Tip of the Day
Long pressing an item opens multi-selection options in the inventory.
MediaWiki:Gadget-DryCalc.js
From Walkscape Walkthrough
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* global mw, $ */
(function () {
'use strict';
function clampNumber(n, min, max) {
if (!isFinite(n)) return NaN;
return Math.min(Math.max(n, min), max);
}
function formatPercent(x) {
if (!isFinite(x)) return '—';
return (x * 100).toFixed(2) + '%';
}
function formatNumber(x, decimals) {
if (!isFinite(x)) return '—';
var d = (typeof decimals === 'number') ? decimals : 2;
return x.toFixed(d);
}
function calc(p, t) {
// p: probability per trial, t: trials
var q = 1 - p;
var p0 = Math.pow(q, t); // P(0 drops)
var pge1 = 1 - p0; // P(>=1)
var mu = t * p; // expected drops
return { p0: p0, pge1: pge1, mu: mu };
}
function trialsForConfidence(p, c) {
// smallest t such that P(>=1) >= c
// 1 - (1-p)^t >= c => (1-p)^t <= 1-c
// t >= ln(1-c)/ln(1-p)
if (!(p > 0 && p < 1)) return NaN;
if (!(c > 0 && c < 1)) return NaN;
var t = Math.log(1 - c) / Math.log(1 - p);
return Math.ceil(t);
}
function buildUI($host) {
var defaultMode = ($host.data('default-mode') || 'actions').toString().toLowerCase();
if (defaultMode !== 'steps') defaultMode = 'actions';
var $wrap = $('<div>').addClass('ws-drycalc-card');
var $title = $('<div>').addClass('ws-drycalc-title').text('Drop Chance Calculator');
var $modeRow = $('<div>').addClass('ws-drycalc-row');
var $modeLabel = $('<label>').addClass('ws-drycalc-label').text('Mode');
var $mode = $('<select>').addClass('ws-drycalc-input')
.append($('<option>').val('actions').text('Actions'))
.append($('<option>').val('steps').text('Steps'))
.val(defaultMode);
$modeRow.append($modeLabel, $mode);
var $rateRow = $('<div>').addClass('ws-drycalc-row');
var $rateLabel = $('<label>').addClass('ws-drycalc-label').text('Drop rate');
var $ratePrefix = $('<span>').addClass('ws-drycalc-inline').text('1 in');
var $rateN = $('<input>')
.addClass('ws-drycalc-input')
.attr({ type: 'number', min: '1', step: '1', value: '128' });
$rateRow.append($rateLabel, $('<div>').addClass('ws-drycalc-inlinewrap').append($ratePrefix, $rateN));
var $countRow = $('<div>').addClass('ws-drycalc-row');
var $countLabel = $('<label>').addClass('ws-drycalc-label');
var $count = $('<input>')
.addClass('ws-drycalc-input')
.attr({ type: 'number', min: '0', step: '1', value: '0' });
$countRow.append($countLabel, $count);
var $out = $('<div>').addClass('ws-drycalc-out');
function render() {
var mode = $mode.val();
var n = parseFloat($rateN.val());
var t = parseFloat($count.val());
n = clampNumber(n, 1, 1e12);
t = clampNumber(t, 0, 1e15);
var unit = (mode === 'steps') ? 'steps' : 'actions';
$countLabel.text('Completed (' + unit + ')');
if (!(n >= 1) || !(t >= 0)) {
$out.empty().append(
$('<div>').addClass('ws-drycalc-warn').text('Please enter a valid drop rate and count.')
);
return;
}
var p = 1 / n;
var r = calc(p, t);
// confidence milestones
var t50 = trialsForConfidence(p, 0.50);
var t90 = trialsForConfidence(p, 0.90);
var t95 = trialsForConfidence(p, 0.95);
$out.empty().append(
$('<div>').addClass('ws-drycalc-metric')
.append($('<div>').addClass('ws-drycalc-k').text('Expected ' + unit + ' per drop'))
.append($('<div>').addClass('ws-drycalc-v').text(formatNumber(n, 0))),
$('<div>').addClass('ws-drycalc-metric')
.append($('<div>').addClass('ws-drycalc-k').text('Expected drops so far'))
.append($('<div>').addClass('ws-drycalc-v').text(formatNumber(r.mu, 2))),
$('<div>').addClass('ws-drycalc-metric')
.append($('<div>').addClass('ws-drycalc-k').text('Chance of at least 1 drop by now'))
.append($('<div>').addClass('ws-drycalc-v').text(formatPercent(r.pge1))),
$('<div>').addClass('ws-drycalc-metric')
.append($('<div>').addClass('ws-drycalc-k').text('Chance you would be dry (0 drops)'))
.append($('<div>').addClass('ws-drycalc-v').text(formatPercent(r.p0))),
$('<div>').addClass('ws-drycalc-subtitle').text('Milestones (chance of ≥1 drop)'),
$('<div>').addClass('ws-drycalc-milestones').append(
$('<div>').addClass('ws-drycalc-chip').text('50%: ' + (isFinite(t50) ? t50 : '—') + ' ' + unit),
$('<div>').addClass('ws-drycalc-chip').text('90%: ' + (isFinite(t90) ? t90 : '—') + ' ' + unit),
$('<div>').addClass('ws-drycalc-chip').text('95%: ' + (isFinite(t95) ? t95 : '—') + ' ' + unit)
)
);
}
$mode.on('change', render);
$rateN.on('input', render);
$count.on('input', render);
$wrap.append($title, $modeRow, $rateRow, $countRow, $out);
$host.empty().append($wrap);
render();
}
function init($content) {
$content.find('.ws-drycalc').each(function () {
buildUI($(this));
});
}
mw.hook('wikipage.content').add(init);
})();
