Fogest revisó este gist . Ir a la revisión
1 file changed, 486 insertions
batch balance (fixed) (archivo creado)
| @@ -0,0 +1,486 @@ | |||
| 1 | + | // ==UserScript== | |
| 2 | + | // @name Batch Balance | |
| 3 | + | // @namespace https://github.com/tobytorn | |
| 4 | + | // @description Distribute money or change balances for multiple faction members (Not supported on mobile) | |
| 5 | + | // @author tobytorn [1617955] | |
| 6 | + | // @match https://www.torn.com/factions.php?step=your* | |
| 7 | + | // @version 2.0.2 | |
| 8 | + | // @grant GM_getValue | |
| 9 | + | // @grant GM_setValue | |
| 10 | + | // @grant GM_addStyle | |
| 11 | + | // @supportURL https://github.com/tobytorn/batch-balance | |
| 12 | + | // @license MIT | |
| 13 | + | // @require https://unpkg.com/[email protected]/dist/jquery.min.js | |
| 14 | + | // @downloadURL https://update.greasyfork.org/scripts/536376/Batch%20Balance.user.js | |
| 15 | + | // @updateURL https://update.greasyfork.org/scripts/536376/Batch%20Balance.meta.js | |
| 16 | + | // ==/UserScript== | |
| 17 | + | ||
| 18 | + | // Usage: | |
| 19 | + | // Add the following parameters to the URL of the control page (https://www.torn.com/factions.php?step=your#/tab=controls) to enable this script | |
| 20 | + | // batbal_uids Comma-separated user IDs | |
| 21 | + | // batbal_amounts Comma-separated amounts | |
| 22 | + | // batbal_action [Optional] "add" for adding to balance (default), or "give" for giving money | |
| 23 | + | // batbal_asset [Optional] "money" (default) or "points" | |
| 24 | + | // | |
| 25 | + | // Example: The following URL will add 120 to Leslie, subtract 250 from tobytorn, and add 1.5k to Duke | |
| 26 | + | // https://www.torn.com/factions.php?step=your#/tab=controls&batbal_uids=15,1617955,4&batbal_amounts=120,-250,1500 | |
| 27 | + | ||
| 28 | + | 'use strict'; | |
| 29 | + | ||
| 30 | + | function batchBalanceWrapper() { | |
| 31 | + | console.log('Batch Balance starts'); | |
| 32 | + | ||
| 33 | + | const ACTION_INTERVAL_MS = 1000; | |
| 34 | + | const GM_VALUE_KEY = 'batbal-action'; | |
| 35 | + | const PROFILE_HREF_PREFIX = 'profiles.php?XID='; | |
| 36 | + | const ACTION_SPECS = { | |
| 37 | + | give: { | |
| 38 | + | summary: 'Give', | |
| 39 | + | text: 'Give', | |
| 40 | + | waitingText: 'Giving', | |
| 41 | + | bodyParam: 'giveMoney', | |
| 42 | + | }, | |
| 43 | + | add: { | |
| 44 | + | summary: 'Add to balance', | |
| 45 | + | text: 'Add', | |
| 46 | + | waitingText: 'Adding', | |
| 47 | + | bodyParam: 'addToBalance', | |
| 48 | + | }, | |
| 49 | + | }; | |
| 50 | + | ||
| 51 | + | const $ = window.jQuery; | |
| 52 | + | ||
| 53 | + | const LOCAL_STORAGE_PREFIX = 'BATCH_BALANCE_'; | |
| 54 | + | ||
| 55 | + | function getLocalStorage(key, defaultValue) { | |
| 56 | + | const value = window.localStorage.getItem(LOCAL_STORAGE_PREFIX + key); | |
| 57 | + | try { | |
| 58 | + | return JSON.parse(value) ?? defaultValue; | |
| 59 | + | } catch (err) { | |
| 60 | + | return defaultValue; | |
| 61 | + | } | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | function setLocalStorage(key, value) { | |
| 65 | + | window.localStorage.setItem(LOCAL_STORAGE_PREFIX + key, JSON.stringify(value)); | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | const isPda = window.GM_info?.scriptHandler?.toLowerCase().includes('tornpda'); | |
| 69 | + | const [getValue, setValue] = | |
| 70 | + | isPda || typeof window.GM_getValue !== 'function' || typeof window.GM_setValue !== 'function' | |
| 71 | + | ? [getLocalStorage, setLocalStorage] | |
| 72 | + | : [window.GM_getValue, window.GM_setValue]; | |
| 73 | + | ||
| 74 | + | const STYLE = ` | |
| 75 | + | .batbal-overlay { | |
| 76 | + | position: relative; | |
| 77 | + | } | |
| 78 | + | .batbal-overlay:after { | |
| 79 | + | content: ''; | |
| 80 | + | position: absolute; | |
| 81 | + | background: repeating-linear-gradient(135deg, #2228, #2228 70px, #0008 70px, #0008 80px); | |
| 82 | + | top: 0; | |
| 83 | + | left: 0; | |
| 84 | + | width: 100%; | |
| 85 | + | height: 100%; | |
| 86 | + | z-index: 900000; | |
| 87 | + | } | |
| 88 | + | #batbal-ctrl { | |
| 89 | + | margin: 10px 0; | |
| 90 | + | padding: 10px; | |
| 91 | + | border-radius: 5px; | |
| 92 | + | background-color: var(--default-bg-panel-color); | |
| 93 | + | text-align: center; | |
| 94 | + | line-height: 16px; | |
| 95 | + | } | |
| 96 | + | #batbal-ctrl-detail > :not(:first-child), | |
| 97 | + | #batbal-ctrl > :not(:first-child) { | |
| 98 | + | margin-top: 10px; | |
| 99 | + | } | |
| 100 | + | #batbal-ctrl-title { | |
| 101 | + | font-size: large; | |
| 102 | + | font-weight: bold; | |
| 103 | + | } | |
| 104 | + | #batbal-ctrl-status { | |
| 105 | + | font-weight: bold; | |
| 106 | + | } | |
| 107 | + | #batbal-ctrl button { | |
| 108 | + | margin: 0 4px; | |
| 109 | + | } | |
| 110 | + | #batbal-ctrl table { | |
| 111 | + | margin: 0 auto; | |
| 112 | + | } | |
| 113 | + | #batbal-ctrl th { | |
| 114 | + | font-weight: bold; | |
| 115 | + | } | |
| 116 | + | #batbal-ctrl th, | |
| 117 | + | #batbal-ctrl td { | |
| 118 | + | color: inherit; | |
| 119 | + | padding: 5px; | |
| 120 | + | border: 1px solid #ccc; | |
| 121 | + | } | |
| 122 | + | #batbal-ctrl td:last-child { | |
| 123 | + | text-align: right; | |
| 124 | + | } | |
| 125 | + | #batbal-ctrl-detail tr.batbal-done:after { | |
| 126 | + | content: '\u2713'; | |
| 127 | + | color: green; | |
| 128 | + | padding-left: 6px; | |
| 129 | + | } | |
| 130 | + | `; | |
| 131 | + | ||
| 132 | + | const CONTROLLER_HTML = ` | |
| 133 | + | <div id="batbal-ctrl"> | |
| 134 | + | <div id="batbal-ctrl-title">Batch Balance</div> | |
| 135 | + | <div> | |
| 136 | + | <table> | |
| 137 | + | <thead> | |
| 138 | + | <tr> | |
| 139 | + | <th colspan="2">Summary</th> | |
| 140 | + | </tr> | |
| 141 | + | </thead> | |
| 142 | + | <tbody> | |
| 143 | + | <tr> | |
| 144 | + | <th>Action</th> | |
| 145 | + | <td id="batbal-ctrl-summary-action-type">-</td> | |
| 146 | + | </tr> | |
| 147 | + | <tr> | |
| 148 | + | <th>Asset Type</th> | |
| 149 | + | <td id="batbal-ctrl-summary-asset-type">-</td> | |
| 150 | + | </tr> | |
| 151 | + | <tr> | |
| 152 | + | <th>Player Count</th> | |
| 153 | + | <td id="batbal-ctrl-summary-player-count">-</td> | |
| 154 | + | </tr> | |
| 155 | + | <tr> | |
| 156 | + | <th>Player Not in Faction</th> | |
| 157 | + | <td><span id="batbal-ctrl-summary-player-not-in-faction">-</span></td> | |
| 158 | + | </tr> | |
| 159 | + | <tr> | |
| 160 | + | <th>Total Amount</th> | |
| 161 | + | <td><span id="batbal-ctrl-summary-total-amount">-</span></td> | |
| 162 | + | </tr> | |
| 163 | + | </tbody> | |
| 164 | + | </table> | |
| 165 | + | </div> | |
| 166 | + | <div> | |
| 167 | + | <button id="batbal-ctrl-start" class="torn-btn" disabled>Start</button> | |
| 168 | + | <button id="batbal-ctrl-show-detail" class="torn-btn">Show details</button> | |
| 169 | + | <button id="batbal-ctrl-hide-detail" class="torn-btn" style="display: none">Hide details</button> | |
| 170 | + | <button id="batbal-ctrl-clear-data" class="torn-btn" disabled>Clear data</button> | |
| 171 | + | </div> | |
| 172 | + | <button id="batbal-ctrl-submit" class="torn-btn" style="display: none" disabled></button> | |
| 173 | + | <div>Status: <span id="batbal-ctrl-status"></span></div> | |
| 174 | + | <div id="batbal-ctrl-detail" style="display: none"> | |
| 175 | + | <table> | |
| 176 | + | <thead> | |
| 177 | + | <tr> | |
| 178 | + | <th>ID</th> | |
| 179 | + | <th>Name</th> | |
| 180 | + | <th>Amount</th> | |
| 181 | + | <th>Note</th> | |
| 182 | + | </tr> | |
| 183 | + | </thead> | |
| 184 | + | <tbody></tbody> | |
| 185 | + | </table> | |
| 186 | + | </div> | |
| 187 | + | </div>`; | |
| 188 | + | ||
| 189 | + | function formatAmount(v) { | |
| 190 | + | return (v >= 0 ? '+' : '') + v.toString().replace(/\d{1,3}(?=(\d{3})+$)/g, (s) => s + ','); | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | async function sleep(t) { | |
| 194 | + | await new Promise((r) => setTimeout(r, t)); | |
| 195 | + | } | |
| 196 | + | ||
| 197 | + | // Copied from https://stackoverflow.com/a/25490531 | |
| 198 | + | function getCookie(name) { | |
| 199 | + | return document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)')?.pop() || ''; | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | function getParams() { | |
| 203 | + | const params = new URLSearchParams(location.hash.slice(1)); | |
| 204 | + | return params.get('/tab') === 'controls' ? params : null; | |
| 205 | + | } | |
| 206 | + | ||
| 207 | + | function storeAction(action) { | |
| 208 | + | setValue(GM_VALUE_KEY, action); | |
| 209 | + | } | |
| 210 | + | ||
| 211 | + | function parseAction() { | |
| 212 | + | const params = getParams(); | |
| 213 | + | if (!params) { | |
| 214 | + | return null; | |
| 215 | + | } | |
| 216 | + | const paramUids = params.get('batbal_uids'); | |
| 217 | + | const paramAmounts = params.get('batbal_amounts'); | |
| 218 | + | if (paramUids === null || paramAmounts === null) { | |
| 219 | + | return null; | |
| 220 | + | } | |
| 221 | + | const uids = paramUids.split(','); | |
| 222 | + | const amounts = paramAmounts.split(','); | |
| 223 | + | if (amounts.length !== uids.length) { | |
| 224 | + | return { error: 'Param "batbal_uids" and "batbal_amounts" have different lengths' }; | |
| 225 | + | } | |
| 226 | + | if (uids.length === 0 || uids.some((x) => !x.match(/^\d+$/))) { | |
| 227 | + | return { error: 'Param "batbal_uids" is invalid' }; | |
| 228 | + | } | |
| 229 | + | if (amounts.length === 0 || amounts.some((x) => !x.match(/^[+-]?\d{1,11}$/))) { | |
| 230 | + | return { error: 'Param "batbal_amounts" is invalid' }; | |
| 231 | + | } | |
| 232 | + | const actionType = params.get('batbal_action') ?? 'add'; | |
| 233 | + | if (!['give', 'add'].includes(actionType)) { | |
| 234 | + | return { error: 'Param "batbal_action" is invalid' }; | |
| 235 | + | } | |
| 236 | + | const assetType = params.get('batbal_asset') ?? 'money'; | |
| 237 | + | if (!['money', 'points'].includes(assetType)) { | |
| 238 | + | return { error: 'Param "batbal_asset" is invalid' }; | |
| 239 | + | } | |
| 240 | + | return { | |
| 241 | + | uidAmounts: uids.map((uid, i) => [uid, parseInt(amounts[i])]).filter(([, amount]) => amount !== 0), | |
| 242 | + | next: 0, | |
| 243 | + | actionType, | |
| 244 | + | assetType, | |
| 245 | + | }; | |
| 246 | + | } | |
| 247 | + | ||
| 248 | + | function checkAction(parsedAction, storedAction) { | |
| 249 | + | if (parsedAction && storedAction) { | |
| 250 | + | if ( | |
| 251 | + | JSON.stringify(parsedAction.uidAmounts) !== JSON.stringify(storedAction.uidAmounts) || | |
| 252 | + | parsedAction.actionType !== storedAction.actionType || | |
| 253 | + | parsedAction.assetType !== storedAction.assetType | |
| 254 | + | ) { | |
| 255 | + | throw new Error( | |
| 256 | + | "An unfinished Batch Balance operation was found that doesn't match the URL parameters. " + | |
| 257 | + | 'Click "Show details" to view the pending operation. ' + | |
| 258 | + | 'To resume it, clear the URL parameters and refresh the page.' + | |
| 259 | + | 'To discard it, click "Clear data" and refresh the page.', | |
| 260 | + | ); | |
| 261 | + | } | |
| 262 | + | } | |
| 263 | + | return storedAction ?? parsedAction; | |
| 264 | + | } | |
| 265 | + | ||
| 266 | + | /** @returns Promise<Record<string, { name: string, isInFaction: boolean }>> */ | |
| 267 | + | async function getUidMap() { | |
| 268 | + | return new Promise((resolve) => { | |
| 269 | + | const interval = setInterval(function () { | |
| 270 | + | const $depositors = $('.money___DbkSX .userListWrap___AndUA .userInfoWrap___k2sjQ'); | |
| 271 | + | if ($depositors.length === 0) { | |
| 272 | + | return; | |
| 273 | + | } | |
| 274 | + | const map = {}; | |
| 275 | + | $depositors.each(function () { | |
| 276 | + | const $name = $(this).find(`a[href*="${PROFILE_HREF_PREFIX}"]`).first(); | |
| 277 | + | if ($name.length > 0) { | |
| 278 | + | const uid = ($name.attr('href') || '').split(PROFILE_HREF_PREFIX)[1]; | |
| 279 | + | map[uid] = { | |
| 280 | + | name: $name.text().trim(), | |
| 281 | + | isInFaction: !$(this).hasClass('inactive___Hd0EQ'), | |
| 282 | + | }; | |
| 283 | + | } | |
| 284 | + | }); | |
| 285 | + | clearInterval(interval); | |
| 286 | + | resolve(map); | |
| 287 | + | }, 200); | |
| 288 | + | }); | |
| 289 | + | } | |
| 290 | + | ||
| 291 | + | function renderController() { | |
| 292 | + | GM_addStyle(STYLE); | |
| 293 | + | const $controlsWrap = $('.faction-controls-wrap'); | |
| 294 | + | $controlsWrap.addClass('batbal-overlay'); | |
| 295 | + | $controlsWrap.before(CONTROLLER_HTML); | |
| 296 | + | $('#batbal-ctrl-show-detail').on('click', function () { | |
| 297 | + | $('#batbal-ctrl-detail').show(); | |
| 298 | + | $('#batbal-ctrl-hide-detail').show(); | |
| 299 | + | $(this).hide(); | |
| 300 | + | }); | |
| 301 | + | $('#batbal-ctrl-hide-detail').on('click', function () { | |
| 302 | + | $('#batbal-ctrl-detail').hide(); | |
| 303 | + | $('#batbal-ctrl-show-detail').show(); | |
| 304 | + | $(this).hide(); | |
| 305 | + | }); | |
| 306 | + | $('#batbal-ctrl-clear-data').on('click', function () { | |
| 307 | + | if ( | |
| 308 | + | confirm( | |
| 309 | + | 'Are you sure you want to delete the saved Batch Balance data? ' + | |
| 310 | + | 'This will remove any unfinished operations and cannot be undone.', | |
| 311 | + | ) | |
| 312 | + | ) { | |
| 313 | + | storeAction(null); | |
| 314 | + | $('#batbal-ctrl').hide(); | |
| 315 | + | alert('Saved data has been deleted, please refresh the page'); | |
| 316 | + | } | |
| 317 | + | }); | |
| 318 | + | } | |
| 319 | + | ||
| 320 | + | function updateStatus(s) { | |
| 321 | + | $('#batbal-ctrl-status').text(String(s)); | |
| 322 | + | if (s instanceof Error) { | |
| 323 | + | $('#batbal-ctrl-status').css('color', 'red'); | |
| 324 | + | } | |
| 325 | + | } | |
| 326 | + | ||
| 327 | + | function renderDetails(action, uidMap) { | |
| 328 | + | const $tbody = $('#batbal-ctrl-detail tbody'); | |
| 329 | + | $tbody.empty(); | |
| 330 | + | let outsideCount = 0; | |
| 331 | + | action.uidAmounts.forEach(([uid, amount], i) => { | |
| 332 | + | const amountClass = amount >= 0 ? 't-green' : 't-red'; | |
| 333 | + | const trClass = i < action.next ? 'batbal-done' : ''; | |
| 334 | + | const uidInfo = uidMap[uid] || {}; | |
| 335 | + | const name = uidInfo.name || ''; | |
| 336 | + | const isInFaction = uidInfo.isInFaction || false; | |
| 337 | + | if (!isInFaction) { | |
| 338 | + | outsideCount++; | |
| 339 | + | } | |
| 340 | + | $tbody.append(`<tr class="${trClass}"> | |
| 341 | + | <td>${uid}</td> | |
| 342 | + | <td>${name}</td> | |
| 343 | + | <td><span class="${amountClass}">${formatAmount(amount)}</span></td> | |
| 344 | + | <td><span class="${!isInFaction ? 't-red' : ''}">${!isInFaction ? 'Not in faction' : ''}</span></td> | |
| 345 | + | </tr>`); | |
| 346 | + | }); | |
| 347 | + | const total = action.uidAmounts.reduce((v, [, amount]) => v + amount, 0); | |
| 348 | + | const totalClass = total >= 0 ? 't-green' : 't-red'; | |
| 349 | + | const actionSpec = ACTION_SPECS[action.actionType]; | |
| 350 | + | $('#batbal-ctrl-summary-action-type').text(actionSpec.summary); | |
| 351 | + | $('#batbal-ctrl-summary-asset-type').text(action.assetType); | |
| 352 | + | $('#batbal-ctrl-summary-player-count').text(action.uidAmounts.length); | |
| 353 | + | $('#batbal-ctrl-summary-player-not-in-faction') | |
| 354 | + | .text(outsideCount) | |
| 355 | + | .toggleClass('t-red', outsideCount > 0); | |
| 356 | + | $('#batbal-ctrl-summary-total-amount').text(formatAmount(total)).addClass(totalClass); | |
| 357 | + | updateStatus(`Progress: ${action.next} / ${action.uidAmounts.length} done`); | |
| 358 | + | } | |
| 359 | + | ||
| 360 | + | async function addMoney({ uid, name, amount, actionType, assetType }) { | |
| 361 | + | const $submit = $('#batbal-ctrl-submit'); | |
| 362 | + | $submit.show(); | |
| 363 | + | const actionSpec = ACTION_SPECS[actionType]; | |
| 364 | + | const textSuffix = ` ${assetType}: ${name} [${uid}] ${formatAmount(amount)}`; | |
| 365 | + | const queryParam = { | |
| 366 | + | money: 'factionsGiveMoney', | |
| 367 | + | points: 'factionsGivePoints', | |
| 368 | + | }[assetType]; | |
| 369 | + | $submit.text(`${actionSpec.text} ${textSuffix}`); | |
| 370 | + | $submit.prop('disabled', false); | |
| 371 | + | return new Promise((resolve, reject) => { | |
| 372 | + | $submit.on('click', async () => { | |
| 373 | + | try { | |
| 374 | + | $submit.off('click'); | |
| 375 | + | $submit.text(`${actionSpec.waitingText} ${textSuffix}`); | |
| 376 | + | $submit.prop('disabled', true); | |
| 377 | + | const rfcv = getCookie('rfc_v'); | |
| 378 | + | const rsp = await fetch(`/page.php?sid=${queryParam}&rfcv=${rfcv}`, { | |
| 379 | + | method: 'POST', | |
| 380 | + | headers: { | |
| 381 | + | 'Content-Type': 'application/json', | |
| 382 | + | 'x-requested-with': 'XMLHttpRequest', | |
| 383 | + | }, | |
| 384 | + | body: JSON.stringify({ | |
| 385 | + | option: actionSpec.bodyParam, | |
| 386 | + | receiver: parseInt(uid), | |
| 387 | + | amount, | |
| 388 | + | }), | |
| 389 | + | }); | |
| 390 | + | const rawData = await rsp.text(); | |
| 391 | + | if (!rsp.ok) { | |
| 392 | + | throw new Error(`Network error: ${rsp.status} ${rawData}`); | |
| 393 | + | } | |
| 394 | + | const data = JSON.parse(rawData); | |
| 395 | + | if (data.success === true) { | |
| 396 | + | resolve(); | |
| 397 | + | } else { | |
| 398 | + | reject(new Error(`Unexpected server response: ${rawData}`)); | |
| 399 | + | } | |
| 400 | + | } catch (err) { | |
| 401 | + | reject(err); | |
| 402 | + | } | |
| 403 | + | }); | |
| 404 | + | }); | |
| 405 | + | } | |
| 406 | + | ||
| 407 | + | async function start(action, uidMap) { | |
| 408 | + | storeAction(action); | |
| 409 | + | $('#batbal-ctrl-start').prop('disabled', true); | |
| 410 | + | $('#batbal-ctrl-clear-data').prop('disabled', true); | |
| 411 | + | ||
| 412 | + | try { | |
| 413 | + | while (action.next < action.uidAmounts.length) { | |
| 414 | + | updateStatus(`Current progress: ${action.next} / ${action.uidAmounts.length} done`); | |
| 415 | + | const now = Date.now(); | |
| 416 | + | const [uid, amount] = action.uidAmounts[action.next]; | |
| 417 | + | const uidInfo = uidMap[uid] || {}; | |
| 418 | + | const name = uidInfo.name || 'Unknown player'; | |
| 419 | + | await addMoney({ uid, name, amount, actionType: action.actionType, assetType: action.assetType }); | |
| 420 | + | action.next++; | |
| 421 | + | storeAction(action); | |
| 422 | + | renderDetails(action, uidMap); | |
| 423 | + | const elapsed = Date.now() - now; | |
| 424 | + | if (elapsed < ACTION_INTERVAL_MS) { | |
| 425 | + | await sleep(ACTION_INTERVAL_MS - elapsed); | |
| 426 | + | } | |
| 427 | + | } | |
| 428 | + | storeAction(null); | |
| 429 | + | updateStatus('All done!'); | |
| 430 | + | } catch (err) { | |
| 431 | + | updateStatus(err); | |
| 432 | + | } | |
| 433 | + | } | |
| 434 | + | ||
| 435 | + | async function main() { | |
| 436 | + | try { | |
| 437 | + | const parsedAction = parseAction(); | |
| 438 | + | const storedAction = getValue(GM_VALUE_KEY, null); | |
| 439 | + | if (storedAction === null && parsedAction === null) { | |
| 440 | + | return; | |
| 441 | + | } | |
| 442 | + | ||
| 443 | + | const uidMap = await getUidMap(); | |
| 444 | + | renderController(); | |
| 445 | + | if (storedAction) { | |
| 446 | + | renderDetails(storedAction, uidMap); | |
| 447 | + | $('#batbal-ctrl-clear-data').prop('disabled', false); | |
| 448 | + | } | |
| 449 | + | if (parsedAction.error) { | |
| 450 | + | throw new Error(parsedAction.error); | |
| 451 | + | } | |
| 452 | + | ||
| 453 | + | const action = checkAction(parsedAction, storedAction); | |
| 454 | + | if (!storedAction) { | |
| 455 | + | renderDetails(action, uidMap); | |
| 456 | + | } | |
| 457 | + | if (action.actionType === 'give') { | |
| 458 | + | if (action.uidAmounts.some(([uid]) => !uidMap[uid]?.isInFaction)) { | |
| 459 | + | throw new Error('Some players are not in the faction'); | |
| 460 | + | } | |
| 461 | + | if (action.uidAmounts.some(([, amount]) => amount <= 0)) { | |
| 462 | + | throw new Error('Amounts to give must be positive'); | |
| 463 | + | } | |
| 464 | + | } | |
| 465 | + | ||
| 466 | + | $('#batbal-ctrl-start').prop('disabled', false); | |
| 467 | + | $('#batbal-ctrl-start').on('click', () => start(action, uidMap)); | |
| 468 | + | } catch (err) { | |
| 469 | + | updateStatus(err); | |
| 470 | + | console.log('Unhandled exception from Batch Balance:', err); | |
| 471 | + | } | |
| 472 | + | } | |
| 473 | + | ||
| 474 | + | main(); | |
| 475 | + | console.log('Batch Balance ends'); | |
| 476 | + | } | |
| 477 | + | ||
| 478 | + | if (document.readyState === 'loading') { | |
| 479 | + | document.addEventListener('readystatechange', () => { | |
| 480 | + | if (document.readyState === 'interactive') { | |
| 481 | + | batchBalanceWrapper(); | |
| 482 | + | } | |
| 483 | + | }); | |
| 484 | + | } else { | |
| 485 | + | batchBalanceWrapper(); | |
| 486 | + | } | |
Siguiente
Anterior