· 5 years ago · Feb 16, 2020, 07:30 PM
11
22
33
44
55
66
77
88
99
1010
1111
1212
1313
1414
1515
1616
1717
1818
1919
2020
2121
2222
2323
2424
2525
2626
2727
2828
2929
3030
3131
3232
3333
3434
3535
3636
3737
3838
3939
4040
4141
4242
4343
4444
4545
4646
4747
4848
4949
5050
5151
5252
5353
5454
5555
5656
5757
5858
5959
6060
6161
6262
6363
6464
6565
6666
6767
6868
6969
7070
7171
7272
7373
7474
7575
7676
7777
7878
7979
8080
8181
8282
8383
8484
8585
8686
8787
8888
8989
9090
9191
9292
9393
9494
9595
9696
9797
9898
9999
100100
101101
102102
103103
104104
105105
106106
107107
108108
109109
110110
111111
112112
113113
114114
115115
116116
117117
118118
119119
120120
121121
122122
123123
124124
125125
126126
127127
128128
129129
130130
131131
132132
133133
134134
135135
136136
137137
138138
139139
140140
141141
142142
143143
144144
145145
146146
147147
148148
149149
150150
151151
152152
153153
154154
155155
156156
157157
158158
159159
160160
161161
162162
163163
164164
165165
166166
167167
168168
169169
170170
171171
172172
173173
174174
175175
176176
177177
178178
179179
180180
181181
182182
183183
184184
185185
186186
187187
188188
189189
190190
191191
192192
193193
194194
195195
196196
197197
198198
199199
200200
201201
202202
203203
204204
205205
206206
207207
208208
209209
210210
211211
212212
213213
214214
215215
216216
217217
218218
219219
220220
221221
222222
223223
224224
225225
226226
227227
228228
229229
230230
231231
232232
233233
234234
235235
236236
237237
238238
239239
240240
241241
242242
243243
244244
245245
246246
247247
248248
249249
250250
251251
252252
253253
254254
255255
256256
257257
258258
259259
260260
261261
262262
263263
264264
265265
266266
267267
268268
269269
270270
271271
272272
273273
274274
275275
276276
277277
278278
279279
280280
281281
282282
283283
284284
285285
286286
287287
288288
289289
290290
291291
292292
293293
294294
295295
296296
297297
298298
299299
300300
301301
302302
303303
304304
305305
306306
307307
308308
309309
310310
311311
312312
313313
314314
315315
316316
317317
318318
319319
320320
321321
322322
323323
324324
325325
326326
327327
328328
329329
330330
331331
332332
333333
334334
335335
336336
337337
338338
339339
340340
341341
342342
343343
344344
345345
346346
347347
348348
349349
350350
351351
352352
353353
354354
355355
356356
357357
358358
359359
360360
361361
362362
363363
364364
365365
366366
367367
368368
369369
370370
371371
372372
373373
374374
375375
376376
377377
378378
379379
380380
381381
382382
383383
384384
385385
386386
387387
388388
389389
390390
391391
392392
393393
394394
395395
396396
397397
398398
399399
400400
401401
402402
403403
404404
405405
406406
407407
408408
409409
410410
411411
412412
413413
414414
415415
416416
417417
418418
419419
420420
421421
422422
423423
424424
425425
426426
427427
428428
429javascript:
430//mass scavenging by Sophie "Shinko to Kuma"
431//edit by To Infinity For Serenity
432
433//relocate to mass scavenging page
434if (window.location.href.indexOf('screen=place&mode=scavenge_mass') < 0) {
435 //relocate
436 window.location.assign(game_data.link_base_pure + "place&mode=scavenge_mass");
437}
438$("#massScavengeSophie").remove();
439//set global variables
440
441if (typeof troopTypeEnabled == 'undefined') {
442 var troopTypeEnabled = {
443 "spear": true,
444 "sword": true,
445 "axe": true,
446 "archer": true,
447 "scout": true,
448 "light": true,
449 "marcher": true,
450 "heavy": true,
451 "catapult": true,
452 "ram": true
453 };
454}
455var arrayWithData;
456var enabledCategories=[];
457var availableUnits = [];
458var squad_requests = [];
459var scavengeInfo;
460var duration_factor = 0;
461var duration_exponent = 0;
462var duration_initial_seconds = 0;
463var categoryNames= JSON.parse("["+$.find('script:contains("ScavengeMassScreen")')[0].innerHTML.match(/\{.*\:\{.*\:.*\}\}/g)+"]")[0];
464//basic setting, to be safe
465var time = 0;
466
467//colors for UI
468var backgroundColor = "#36393f";
469var borderColor = "#3e4147";
470var headerColor = "#202225";
471var titleColor = "#ffffdf";
472
473$.getAll = function (
474 urls, // array of URLs
475 onLoad, // called when any URL is loaded, params (index, data)
476 onDone, // called when all URLs successfully loaded, no params
477 onError // called when a URL load fails or if onLoad throws an exception, params (error)
478) {
479 var numDone = 0;
480 var lastRequestTime = 0;
481 var minWaitTime = 200; // ms between requests
482 loadNext();
483 function loadNext() {
484 if (numDone == urls.length) {
485 onDone();
486 return;
487 }
488
489 let now = Date.now();
490 let timeElapsed = now - lastRequestTime;
491 if (timeElapsed < minWaitTime) {
492 let timeRemaining = minWaitTime - timeElapsed;
493 setTimeout(loadNext, timeRemaining);
494 return;
495 }
496 console.log('Getting ', urls[numDone]);
497 $("#progress").css("width", `${(numDone + 1) / urls.length * 100}%`);
498 lastRequestTime = now;
499 $.get(urls[numDone])
500 .done((data) => {
501 try {
502 onLoad(numDone, data);
503 ++numDone;
504 loadNext();
505 } catch (e) {
506 onError(e);
507 }
508 })
509 .fail((xhr) => {
510 onError(xhr);
511 })
512 }
513};
514
515//get scavenging data that is in play for this world, every world has different exponent, factor, and initial seconds. Also getting the URLS of each mass scavenging page
516//we can limit the amount of pages we need to call this way, since the mass scavenging pages have all the data that is necessary: troopcounts, which categories per village are unlocked, and if rally point exists.
517function getData() {
518 $("#massScavengeSophie").remove();
519 URLs = [];
520 $.get("game.php?&screen=place&mode=scavenge_mass", function (data) {
521 for (var i = 0; i <= $(".paged-nav-item").length; i++) {
522 //push url that belongs to scavenging page i
523 URLs.push("game.php?&screen=place&mode=scavenge_mass&page=" + i);
524 //get world data
525 tempData = JSON.parse($(data).find('script:contains("ScavengeMassScreen")').html().match(/\{.*\:\{.*\:.*\}\}/g)[0]);
526 duration_exponent = tempData[1].duration_exponent;
527 duration_factor = tempData[1].duration_factor;
528 duration_initial_seconds = tempData[1].duration_initial_seconds;
529 }
530 console.log(URLs);
531
532 })
533 .done(function () {
534 //here we get all the village data and make an array with it, we won't be able to parse unless we add brackets before and after the string
535 arrayWithData = "[";
536 $.getAll(URLs,
537 (i, data) => {
538 thisPageData = $(data).find('script:contains("ScavengeMassScreen")').html().match(/\{.*\:\{.*\:.*\}\}/g)[2];
539 arrayWithData += thisPageData + ",";
540 },
541 () => {
542 //on done
543 arrayWithData = arrayWithData.substring(0, arrayWithData.length - 1);
544 //closing bracket so we can parse the data into a useable array
545 arrayWithData += "]";
546 console.log(arrayWithData);
547 scavengeInfo = JSON.parse(arrayWithData);
548 // count and calculate per village how many troops per category need to be sent.
549 // Once count is finished, make a new UI element, and group all the results per 200.
550 // According to morty, that is the limit at which the server will accept squad pushes.
551 count=0;
552 for (var i = 0; i < scavengeInfo.length; i++) {
553 calculateHaulCategories(scavengeInfo[i]);
554 count++;
555 }
556 if (count == scavengeInfo.length) {
557 //Post here
558 console.log("Done");
559 //need to split all the scavenging runs per 200, server limit according to morty
560 squads = {};
561 per200 = 0;
562 groupNumber = 0;
563 squads[groupNumber] = [];
564 for (var k = 0; k < squad_requests.length; k++) {
565 if (per200 == 200) {
566 groupNumber++;
567 squads[groupNumber] = [];
568 per200 = 0;
569 }
570 per200++;
571 squads[groupNumber].push(squad_requests[k]);
572 }
573
574 //create html send screen with button per launch
575 console.log("Creating launch options");
576 htmlWithLaunchButtons=`<div id="massScavengeFinal" class="ui-widget-content" style="position:fixed;background-color:${backgroundColor};cursor:move;z-index:50;">
577 <table id="massScavengeSophieFinalTable" class="vis" border="1" style="width: 100%;background-color:${backgroundColor};border-color:${borderColor}">
578 <tr>
579 <td colspan="10" id="massScavengeSophieTitle" style="text-align:center; width:auto; background-color:${headerColor}">
580 <h2>
581 <center style="margin:10px"><u>
582 <font color="${titleColor}">Mass scavenging: send per 50 villages</font>
583 </u>
584 </center>
585 </h2>
586 </td>
587 </tr>`;
588 for(var s=0;s<Object.keys(squads).length;s++)
589 {
590 //add row with new button
591 htmlWithLaunchButtons+=`<tr id="sendRow${s}" style="text-align:center; width:auto; background-color:${backgroundColor}"><td style="text-align:center; width:auto; background-color:${backgroundColor}"><center><input type="button" class="btn evt-confirm-btn btn-confirm-yes" id="sendMass" onclick="sendGroup(${s})" value="Launch group ${s+1}"></center></td></tr>`
592 }
593 htmlWithLaunchButtons+="</table></div>"
594 //appending to page
595 console.log("Creating launch UI");
596 $("#contentContainer").eq(0).prepend(htmlWithLaunchButtons);
597 $("#mobileContent").eq(0).prepend(htmlWithLaunchButtons);
598 $("#massScavengeFinal").draggable();
599 }
600 },
601 (error) => {
602 console.error(error);
603 });
604 }
605 )
606}
607//first UI, will always open as soon as you run the script.
608html = `
609<div id="massScavengeSophie" class="ui-widget-content" style="position:fixed;background-color:${backgroundColor};cursor:move;z-index:50;">
610 <table id="massScavengeSophieTable" class="vis" border="1" style="width: 100%;background-color:${backgroundColor};border-color:${borderColor}">
611 <tr>
612 <td colspan="10" id="massScavengeSophieTitle" style="text-align:center; width:auto; background-color:${headerColor}">
613 <h2>
614 <center style="margin:10px"><u>
615 <font color="${titleColor}">Mass scavenging</font>
616 </u>
617 </center>
618 </h2>
619 </td>
620 </tr>
621 <tr style="background-color:${backgroundColor}">
622 <td style="text-align:center;background-color:${headerColor}" colspan="15">
623 <h2>
624 <center style="margin:10px"><u>
625 <font color="${titleColor}">Select unit types to scavenge with</font>
626 </u></center>
627 </h2>
628 </td>
629 </tr>
630 <tr id="imgRow">
631 </tr>
632 <tr id="checkboxRow">
633 </tr>
634 </table>
635 <hr>
636 <table class="vis" border="1" style="width: 100%;background-color:${backgroundColor};border-color:${borderColor}">
637 <tbody>
638 <tr style="background-color:${backgroundColor}">
639 <td style="text-align:center;background-color:${headerColor}" colspan="4">
640 <h2>
641 <center style="margin:10px"><u>
642 <font color="${titleColor}">Select categories to use</font>
643 </u></center>
644 </h2>
645 </td>
646 </tr>
647 <tr id="categories" style="text-align:center; width:auto; background-color:${headerColor}">
648 <td style="text-align:center; width:auto; background-color:${headerColor};padding: 10px;"><font color="${titleColor}">${categoryNames[1].name}</font></td>
649 <td style="text-align:center; width:auto; background-color:${headerColor};padding: 10px;"><font color="${titleColor}">${categoryNames[2].name}</font></td>
650 <td style="text-align:center; width:auto; background-color:${headerColor};padding: 10px;"><font color="${titleColor}">${categoryNames[3].name}</font></td>
651 <td style="text-align:center; width:auto; background-color:${headerColor};padding: 10px;"><font color="${titleColor}">${categoryNames[4].name}</font></td>
652 </tr>
653 <tr>
654 <td style="text-align:center; width:auto; background-color:${backgroundColor}"><center><input type="checkbox" ID="category1" name="cat1" checked="checked"></center></td>
655 <td style="text-align:center; width:auto; background-color:${backgroundColor}"><center><input type="checkbox" ID="category2" name="cat2" checked="checked"></center></td>
656 <td style="text-align:center; width:auto; background-color:${backgroundColor}"><center><input type="checkbox" ID="category3" name="cat3" checked="checked"></center></td>
657 <td style="text-align:center; width:auto; background-color:${backgroundColor}"><center><input type="checkbox" ID="category4" name="cat4" checked="checked"></center></td>
658 </tr>
659 </tbody>
660 </table>
661 <hr>
662 <center>
663 <font color="${titleColor}">How long do you want to send the scavenging runs out for in HOURS? </font>
664 </center>
665 <br>
666 <center><textarea id="runTime" cols="12" style="background-color:${backgroundColor};color:${titleColor};resize:none;" placeholder="Runtime here"></textarea></center>
667 <hr>
668 <center><input type="button" class="btn evt-confirm-btn btn-confirm-yes" id="sendMass" onclick="readyToSend()" value="Calculate runtimes for each page"></center>
669 <hr>
670 /*<center><img class=" tooltip-delayed" title="Sophie -Shinko to Kuma-" src="https://dl.dropboxusercontent.com/s/0do4be4rzef4j30/sophie2.gif" style="cursor:help; position: relative"></center>*/
671 <br>
672 <center>
673 <p>
674 <font color="${titleColor}">Creator: </font><a href="https://forum.tribalwars.net/index.php?members/shinko-to-kuma.121220/" style="text-shadow:-1px -1px 0 ${titleColor},1px -1px 0 ${titleColor},-1px 1px 0 ${titleColor},1px 1px 0 ${titleColor};" title="Sophie profile" target="_blank">Sophie "Shinko to Kuma"</a>
675 </p>
676 </center>
677</div>
678`;
679 $("#contentContainer").eq(0).prepend(html);
680 $("#mobileContent").eq(0).prepend(html);
681 $("#massScavengeSophie").draggable();
682
683//create checkboxes and add them to the UI
684localUnitNames = [];
685worldUnits = game_data.units;
686for (var i = 0; i < worldUnits.length; i++) {
687 if (worldUnits[i] != "militia" && worldUnits[i] != "snob" && worldUnits[i] != "ram" && worldUnits[i] != "catapult" && worldUnits[i] != "spy") {
688 localUnitNames.push(worldUnits[i]);
689 }
690}
691for (var i = 0; i < localUnitNames.length; i++) {
692 $("#imgRow").eq(0).append(`<td style="text-align:center;background-color:${headerColor}" ><a href="#" class="unit_link" data-unit="${localUnitNames[i]}"><img src="https://dsen.innogamescdn.com/asset/cf2959e7/graphic/unit/unit_${localUnitNames[i]}.png" title="${localUnitNames[i]}" alt="" class=""></a></td>
693`);
694 $("#checkboxRow").eq(0).append(`<td align="center" style="background-color:${backgroundColor}"><input type="checkbox" ID="${localUnitNames[i]}" name="${localUnitNames[i]}"></td>
695`);
696enableCorrectTroopTypes();
697}
698
699function readyToSend() {
700 //get trooptypes we wanna use, and runtime
701 worldUnits = game_data.units;
702 for (var i = 0; i < worldUnits.length; i++) {
703 if (worldUnits[i] != "militia" && worldUnits[i] != "snob" && worldUnits[i] != "ram" && worldUnits[i] != "catapult" && worldUnits[i] != "spy") {
704 troopTypeEnabled[worldUnits[i]] = $(`:checkbox#${worldUnits[i]}`).is(":checked");
705 }
706 }
707 enabledCategories.push($("#category1").is(":unchecked"));
708 enabledCategories.push($("#category2").is(":unchecked"));
709 enabledCategories.push($("#category3").is(":unchecked"));
710 enabledCategories.push($("#category4").is(":unchecked"));
711 time=$("#runTime")[0].value;
712 getData();
713}
714
715function sendGroup(groupNr)
716{
717 //Send one group(one page worth of scavenging)
718 TribalWars.post('scavenge_api', { ajaxaction: 'send_squads' }, { "squad_requests": squads[groupNr] })
719 //once group is sent, remove the row from the table
720 $(`#sendRow${groupNr}`).remove();
721}
722
723
724
725function calculateHaulCategories(data) {
726 //check if village has rally point
727 if (data.has_rally_point == true) {
728 console.log("can scavenge");
729 var troopsAllowed = {};
730 for (key in troopTypeEnabled) {
731 if (troopTypeEnabled[key] == true) {
732 troopsAllowed[key] = data.unit_counts_home[key];
733 }
734 }
735
736 totalLoot = 0;
737
738 //check what the max possible loot is
739 for (key in troopsAllowed) {
740 if (key == "spear") totalLoot += troopsAllowed[key] * (data.unit_carry_factor * 25);
741 if (key == "sword") totalLoot += troopsAllowed[key] * (data.unit_carry_factor * 15);
742 if (key == "axe") totalLoot += troopsAllowed[key] * (data.unit_carry_factor * 10);
743 if (key == "archer") totalLoot += troopsAllowed[key] * (data.unit_carry_factor * 10);
744 if (key == "light") totalLoot += troopsAllowed[key] * (data.unit_carry_factor * 80);
745 if (key == "marcher") totalLoot += troopsAllowed[key] * (data.unit_carry_factor * 50);
746 if (key == "heavy") totalLoot += troopsAllowed[key] * (data.unit_carry_factor * 50);
747 if (key == "knight") totalLoot += troopsAllowed[key] * (data.unit_carry_factor * 100);
748 }
749 console.log("Loot possible from this village: " + totalLoot);
750 if (totalLoot == 0) {
751 //can't loot from here, end
752 return;
753 }
754
755 haul = parseInt(((time * 3600) / duration_factor - duration_initial_seconds) ** (1 / (duration_exponent)) / 100) ** (1 / 2);
756 haulCategoryRate = {};
757 //check which categories are enabled
758
759
760 if (data.options[1].is_locked == true) {
761 haulCategoryRate[1] = 0;
762 } else {
763 haulCategoryRate[1] = haul / 0.1;
764 }
765 if (data.options[2].is_locked == true) {
766 haulCategoryRate[2] = 0;
767 } else {
768 haulCategoryRate[2] = haul / 0.25;
769 }
770 if (data.options[3].is_locked == true) {
771 haulCategoryRate[3] = 0;
772 } else {
773 haulCategoryRate[3] = haul / 0.50;
774 }
775 if (data.options[4].is_locked == true) {
776 haulCategoryRate[4] = 0;
777 } else {
778 haulCategoryRate[4] = haul / 0.75;
779 }
780 console.log(haulCategoryRate);
781
782 for(var i=0;i<enabledCategories.length;i++)
783 {
784 if(enabledCategories[i]==false) haulCategoryRate[i+1]=0;
785 }
786
787
788 totalHaul = haulCategoryRate[1] + haulCategoryRate[2] + haulCategoryRate[3] + haulCategoryRate[4];
789
790
791 //calculate HERE :D
792 unitsReadyForSend = {};
793 unitsReadyForSend[0] = {};
794 unitsReadyForSend[1] = {};
795 unitsReadyForSend[2] = {};
796 unitsReadyForSend[3] = {};
797 if (totalLoot > totalHaul) {
798 //not enough units, just fill in everything
799 for (var j = 0; j < 4; j++) {
800 for (key in troopsAllowed) {
801 unitsReadyForSend[j][key] = Math.floor((haulCategoryRate[j+1] * (troopsAllowed[key] / totalLoot)));
802 }
803 }
804
805 }
806 else {
807 //too many units, fill till it reaches time limit predetermined
808 for (var j = 0; j < 4; j++) {
809 for (key in troopsAllowed) {
810 unitsReadyForSend[j][key] = Math.floor((totalLoot / totalHaul * haulCategoryRate[j+1]) * (troopsAllowed[key] / totalLoot));
811 }
812 }
813 }
814 for (var k = 0; k < Object.keys(unitsReadyForSend).length; k++) {
815 candidate_squad = { "unit_counts": unitsReadyForSend[k], "carry_max": 9999999999 };
816 squad_requests.push({ "village_id": data.village_id, "candidate_squad": candidate_squad, "option_id": k + 1, "use_premium": false })
817 }
818 }
819 else {
820 console.log("no rally point");
821 }
822}
823
824function enableCorrectTroopTypes()
825{
826 worldUnits = game_data.units;
827for (var i = 0; i < worldUnits.length; i++) {
828
829 if (worldUnits[i] != "militia" && worldUnits[i] != "snob" && worldUnits[i] != "ram" && worldUnits[i] != "catapult" && worldUnits[i] != "spy") {
830 if(troopTypeEnabled[worldUnits[i]]==true) $(`#${worldUnits[i]}`).prop( "checked", true );
831 }
832}
833}
834
835/* This is some notes just for me so I know what I'm working with data wise
836
837Structure of the array:
838scavengInfo[i].
839
840village_id
841player_id
842village_name
843res :{wood,stone,iron}
844res_rate:{wood,stone,iron}
845storage_max
846unit_counts_home:{spear,sword, etc}
847unit_carry_factor
848has_rally_point (true or false)
849
850options[1]
851base_id: 1
852village_id
853is_locked: (true or false)
854unlock_time: null
855scavenging_squad: null
856*/