사용자:Hsl0/common.js
< 사용자:Hsl0
참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.
- 파이어폭스 / 사파리: Shift 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5 또는 Ctrl-R을 입력 (Mac에서는 ⌘-R)
- 구글 크롬: Ctrl-Shift-R키를 입력 (Mac에서는 ⌘-Shift-R)
- 인터넷 익스플로러 / 엣지: Ctrl 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5를 입력.
- 오페라: Ctrl-F5를 입력.
/* [[틀:JSON수정]] 차단 시작 */
$('.uncy-jsonedit').remove();
delete window.uncy_jsonEdit;
/* [[틀:JSON수정]] 차단 끝 */
var fetchScript = fetch? function fetchScript(url, integrity) {
return fetch(url, {
header: {
Accept: [
'application/javascript',
'application/ecmascript',
'text/javascript',
'application/x-javascript',
'*/*'
]
},
integrity: integrity
}).then(function(res) {
return res.text().then(function(text) {
new Function(text)();
return new $.Deferred().resolve(text, res.statusText, res).promise();
});
});
} : $.getScript;
Promise.all([
mw.loader.using([
'mediawiki.api.options',
'mediawiki.notification',
'oojs-ui-core'
]),
fetchScript('https://cdnjs.cloudflare.com/ajax/libs/punycode/1.4.1/punycode.min.js', 'sha256-I5XOWZu6gbewMSB9UR88y0GmiJi9AsQcCzUpA/MBNnA=')
]).then(function() {
var title = mw.config.get('wgPageName').split('/')[0];
var noti;
/* option key 인코딩
퓨니코드 + url인코딩
% = _
_ = __
*/
function encode(key) {
return encodeURIComponent(punycode.toASCII(key))
.replace(/\./g, '%2E')
.replace(/!/g, '%21')
.replace(/~/g, '%7E')
.replace(/\*/g, '%2A')
.replace(/'/g, '%27')
.replace(/\(/g, '%28')
.replace(/\)/g, '%29')
.replace(/_/g, '__')
.replace(/%/g, '_');
}
function decode(key) {
return punycode.toUnicode(decodeURIComponent(key.replace(/_(?=[a-zA-Z0-9]{2})/g, '%').replace(/__/g, '_')));
}
// hybridStorage 서브셋 생성
window.setStoragePrefix = function(storage, prefix, except) {
var spp = new Proxy(storage, {
get: function(target, prop, receiver) {
function keys() {
return Object.keys(target).filter(function(key) {
return key.startsWith(prefix);
});
}
return Reflect.get(Object.assign({
length: (prop === 'length') && keys().length,
getItem: function getItem(key) {
return target.getItem(prefix + key);
},
key: function key(index) {
return keys()[index].slice(prefix.length);
},
removeItem: function removeItem(key) {
return target.removeItem(prefix + key).then(function() {
return spp;
});
},
setItem: function setItem(key, value) {
return target.setItem(prefix + key, value).then(function() {
return spp;
});
}
}, except), prop, receiver) || target.getItem(prefix + prop);
},
set: function(target, prop, value) {
return target.setItem(prefix + prop, value);
},
deleteProperty: function(target, prop) {
return target.removeItem(prefix + prop);
},
has: function(target, prop) {
Reflect.has(target, prefix + prop);
},
ownKeys: function(target) {
return Reflect.ownKeys(target).filter(function(key) {
return key.startsWith(prefix);
}).map(function(key) {
return key.slice(prefix.length);
});
}
});
return spp;
};
/*
anon = localStorage[*]
user = mw.user.options[userjs-*]
*/
window.hybridStorage = (function() {
var action;
var api = new mw.Api();
var storage, action;
var saveOption = (function() {
var options = {};
var deferred = new $.Deferred();
var timeout = null;
return function saveOption(key, value) {
if(timeout) clearTimeout(timeout);
options[key] = value;
timeout = setTimeout(function() {
deferred.resolve(api.saveOptions(options));
options = {};
timeout = null;
deferred = new $.Deferred();
}, 100);
return deferred.promise();
};
})();
if(mw.user.isAnon()) {
storage = new Proxy(localStorage, {
get: function(target, prop, receiver) {
var value = Reflect.get({
length: target.length,
getItem: target.getItem,
key: target.key,
removeItem: function removeItem(key) {
return Promise.resolve(target.removeItem(key));
},
setItem: function setItem(key, value) {
return Promise.resolve(target.setItem(key, value));
},
refresh: function refresh() {
return Promise.resolve(storage);
},
needRefresh: false
}, prop, receiver) || target.getItem(prop);
return (value === null)? undefined : value;
},
set: function(target, prop, value, receiver) {
return Promise.resolve(target.setItem(prop, value));
},
deleteProperty: function(target, prop) {
return Promise.resolve(target.removeItem(prop));
}
});
} else {
action = {
removeItem: function removeItem(key) {
if(key) return saveOption("userjs-" + key, null).then(action.refresh);
else throw new TypeError("Failed to execute 'removeItem' on 'Storage': 1 argument required, but only 0 present.");
},
setItem: function setItem(key, value) {
if(key) return saveOption("userjs-" + key, value).then(action.refresh);
else throw new TypeError("Failed to execute 'removeItem' on 'Storage': 1 argument required, but only 0 present.");
},
refresh: (function() {
var deferred = new $.Deferred();
var timeout = null;
return function refresh() {
if(timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
setTimeout(function() {
deferred.resolve(api.get({
action: 'query',
meta: 'userinfo',
uiprop: 'options'
}, {
cache: false
}).then(function(response) {
mw.user.options.values = response.query.userinfo.options;
return storage;
}));
timeout = null;
deferred = new $.Deferred();
}, 300);
}, 100);
return deferred.promise();
};
})()
};
storage = new Proxy(mw.user.options, {
get: function(target, prop, receiver) {
function keys() {
return Object.keys(target.values).filter(function(key) {
return key.startsWith('userjs-');
});
}
return Reflect.get({
length: prop === 'length' && keys().length,
getItem: function getItem(key) {
if(key) return target.get("userjs-" + encode(key));
else throw new TypeError("Failed to execute 'getItem' on 'Storage': 1 argument required, but only 0 present.");
},
key: function key(index) {
return decode(keys()[index].slice(7));
},
removeItem: function removeItem(key) {
key = encode(key);
Reflect.deleteProperty(target.values, key);
return action.removeItem(key);
},
setItem: function setItem(key, value) {
key = encode(key);
target.set(key, value);
return action.setItem(key, value);
},
refresh: action.refresh,
needRefresh: true
}, prop, receiver) || Reflect.get(target.values, "userjs-" + encode(prop), receiver);
},
set: function(target, prop, value, receiver) {
prop = encode(prop);
Reflect.set(target.values, prop, value, receiver);
return action.setItem(encode(prop, value));
},
deleteProperty: function(target, prop) {
prop = encode(prop);
Reflect.deleteProperty(target.values, prop);
return action.removeItem(prop);
},
has: function(target, prop) {
return Reflect.has(target.values, "userjs-" + encode(prop));
},
ownKeys: function(target) {
return Reflect.ownKeys(target.values).filter(function(key) {
return key.startsWith("userjs-");
}).map(function(key) {
return decode(key.slice(7));
});
}
});
}
return storage;
})();
// local + global 슈퍼셋 (hybridStorage[gamedb-*])
var rootGameDB = setStoragePrefix(hybridStorage, 'gamedb-', {
refresh: function() {
return hybridStorage.refresh().then(function() {
return rootGameDB;
});
},
needRefresh: hybridStorage.needRefresh
});
// 게임별로 할당되는 영역 (rootGameDB[{게임}/*])
window.localGameDB = setStoragePrefix(rootGameDB, mw.config.get('wgPageName').split('/')[0] + '/', {
refresh: function() {
return rootGameDB.refresh().then(function() {
return localGameDB;
});
},
needRefresh: rootGameDB.needRefresh
});
// 모든 게임이 공유하는 영역 (rootGameDB[#*])
window.globalGameDB = setStoragePrefix(rootGameDB, '#', {
refresh: function() {
return rootGameDB.refresh().then(function() {
return globalGameDB;
});
},
needRefresh: rootGameDB.needRefresh
});
function DataChange(href) {
this.params = geturlSearch(new URL(href, location));
this.local = {};
this.global = {};
this.root = {};
this.refresh = false;
}
DataChange.prototype.control = function control(element) {
var base, key, storage, params;
var data = element.dataset;
/* 저장할 키
local: 키 지정
global: 전역 키 지정
local global: 키 지정
(없음): 기본 키
*/
if('local' in data) {
storage = localGameDB;
base = this.local;
key = data.local;
} else if('global' in data) {
storage = globalGameDB;
base = this.global;
key = data.global;
} else {
storage = rootGameDB;
base = this.root;
key = title;
}
switch(data.action) {
// 호환
case '저장':
case 'save':
/*
reset: DB 덮어쓰기
true: 기존 데이터를 지우고 현재 상태를 그대로 저장
false: 현재 상태를 저장하되, 없는 키는 존치
*/
if(!location.search) base[key] = JSON.stringify('reset' in data? geturlSearch() : Object.assign(JSON.parse(storage.getItem(key)), geturlSearch()));
break;
case '로드':
case 'load':
/*
live: 항상 최신 데이터 사용
true: 링크 누를때 동기화
false: 항상 캐시된 데이터 사용
reset: 파라미터 강제 덮어쓰기
ture: 파라미터가 있어도 강제로 불러와 덮어쓰기
false: 파라미터가 있으면 아무 동작도 하지 않음
*/
if('live' in data) this.refresh = true;
if(!location.search || 'reset' in data) Object.assign(this.params, JSON.parse(storage.getItem(key)));
break;
// 기본
case '호출':
case 'load':
/*
live: 항상 최신 데이터 사용
true: 링크 누를때 동기화
false: 항상 캐시된 데이터 사용
*/
if('live' in data) this.refresh = true;
this.params[data.arg] = storage.getItem(key);
break;
case '수정':
case 'set':
base[key] = data.arg;
break;
case '삭제':
case 'del':
delete base[key];
break;
// JSON
case 'JSON':
case 'json':
/*
live: 항상 최신 데이터 사용
true: 링크 누를때 동기화
false: 항상 캐시된 데이터 사용
reset: 파라미터 덮어쓰기
true: 파라미터를 초기화하고 새로 가져온 값으로 덮어쓰기
false: 변동된 파라미터만 수정하기
*/
if('live' in data) this.refresh = true;
if('reset' in data) this.params = {};
params = this.params;
this.data[key] = JSON.stringify(new CGI2Parser({
get: function(args) {
if(typeof args === 'object') Object.pairs(args).forEach(function(pair) {
params[pair[0]] = this[pair[1]];
});
else Array.from(arguments).forEach(function(key) {
params[key] = this[key];
});
},
set: function(args) {
Object.pairs(args).forEach(function(pair) {
this[pair[0]] = pair[1];
});
},
del: function() {
Array.from(arguments).forEach(function(key) {
delete this[key];
});
},
def: function(args) {
Object.pairs(args).forEach(function(pair) {
if(!(pair[0] in params)) params[pair[0]] = this[pair[1]];
});
},
sav: function(args) {
if(typeof args === 'object') Object.pairs(args).forEach(function(pair) {
this[pair[0]] = params[pair[1]];
});
else Array.from(arguments).forEach(function(key) {
this[key] = params[key];
});
}
}).parse(JSON.parse(base.getItem(key)), data.arg));
Object.assign(this.params, params);
break;
}
};
// TODO: .gameDB-control, .gameDB-container, .gameDB-link click 이벤트 리스너 구현
/**
* DB 저장
* @function
* @param {DataChange} change
*/
function save(change) {
var key;
var promises = [];
if(title in change.root) {
promises.push(rootGameDB.setItem(key, change.root[title]));
}
for(key in change.local) {
promises.push(localGameDB.setItem(key, change.local[key]));
}
for(key in change.global) {
promises.push(globalGameDB.setItem(key, change.global[key]));
}
if(promises.length && !mw.user.isAnon()) noti = mw.notification.notify('데이터를 저장하는 중입니다...', {
autoHide: false,
tag: 'gameDB',
type: 'pending'
});
return Promise.all(promises);
}
function handleError(code, object) {
mw.notification.notify(
code === 'http'?
$('<span />')
.append($('<p />', {class: 'gameDB-noti-errmsg'}).text(object.xhr.responseText))
.append($('<code />', {class: 'gameDB-noti-errcode'}).text('HTTP ' + object.xhr.status)) :
$('<span />')
.append($('<p />', {class: 'gameDB-noti-errmsg'}).text(object.error.info))
.append($('<code />', {class: 'gameDB-noti-errcode'}).text(code)),
{
title: '데이터 저장에 실패하였습니다.',
type: 'error',
tag: 'gameDB'
}
);
}
// 즉시
(function() {
var instant = new DataChange();
$('.gameDB-control').each(function() {
instant.control(this);
});
save(instant).then(function() {
instant.params = searchParamToString(instant.params);
if(instant.params.length > 1) Promise.all(promises).then(function() {
location.search = instant.params;
});
else noti.close();
}, handleError);
})();
// 링크
(function() {
function process(link, controllers, change) {
var href = new URL(link.href, location);
controllers.each(function() {
change.control(this);
});
href.search = searchParamToString(Object.assign(geturlSearch(href), change.params));
link.href = href.href;
}
$('.gameDB-container').not(':has(a, .gameDB-container)').each(function() {
$(this).html($('<a />').text(this.innerText));
});
$('.gameDB-container a').each(function() {
var change = new DataChange(this.href);
var controllers = $($(this).parents('.gameDB-container').get().reverse());
process(this, controllers.not('[data-live]'), change);
$(this).data('change', change);
$(this).addClass('gameDB-link');
});
$('.gameDB-link').on('click', 'gameDB', function(event) {
var link = this;
var parents = $($(this).parents('.gameDB-container[data-live]').get().reverse());
var change = $(this).data('change');
var promise;
if(!('done' in this.dataset)) event.preventDefault();
if(parents.length) {
mw.notification.notify('데이터를 가져오는 중입니다...', {
tag: 'gameDB',
type: 'pending'
});
promise = hybridStorage.refresh().then(function() {
process(link, parents, change);
return save(change);
});
} else promise = save(change);
promise.then(function() {
link.dataset.done = '';
if(link.href) $(link).off('click', 'gameDB').click();
else mw.notification.notify('데이터가 저장되었습니다.', {
tag: 'gameDB'
});
}, handleError);
});
})();
});
/** 플러그인 SimMD5***************************
* 마법의 MD-5 시뮬레이터 게임에 사용되는 스크립트로, 인터페이스와 배틀시스템을 구현합니다.
* 버전 => 1.3.1
* 작성자 : [[사용자:Gustmd7410|Gustmd7410]]
* JSON => SimMD5 = {"name":"SimMD5","descript":"마법의 MD-5 시뮬레이터 게임에 사용되는 스크립트로, 인터페이스와 배틀시스템을 구현합니다.","version":"1.3.1","local":true,"creat":"Gustmd7410","state":"마법의 MD-5 시뮬레이터/플러그인","executable":true};
*/
function plugin_SimMD5(){
if($("[data-name='SimMD5']").length >= 1){
// 이부분에 코드 입력 //
mw.loader.using('oojs-ui-widgets').done(function() {
function prepare() {
function responsible(event) {
var button = $('#input-time .oo-ui-numberInputWidget-plusButton, #input-time .oo-ui-numberInputWidget-minusButton');
if(event.matches) {
button.css('display', 'none');
input.time.$label.css('margin-right', null);
} else {
button.css('display', 'null');
input.time.$label.css('margin-right', '30px');
}
}
function encode(string) {
return string
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/{/g, '{')
.replace(/\|/g, '|')
.replace(/=/g, '=')
.replace(/}/g, '}')
.replace(/\[/g, '[')
.replace(/\]/g, ']')
.replace(/_/g, '_');
}
function cancel(btn) {
if(stat.length) {
battle.done = null;
battle.turn = 0;
battle.attack = null;
battle.sequence = null;
battle.combo = null;
battle.temp = null;
bar = [];
bar[0] = new OO.ui.ProgressBarWidget({
progress: 100
});
bar[1] = new OO.ui.ProgressBarWidget({
progress: 100
});
bar[0].$bar.css({
background: '#3366CC'
});
bar[0].$element.css({
'border-right': 'none',
'border-top-right-radius': 0,
'border-bottom-right-radius': 0
});
bar[1].$bar.css({
background: '#FF5500'
});
bar[1].$element.css({
'border-left': 'none',
'border-top-left-radius': 0,
'border-bottom-left-radius': 0
});
input.start.setLabel('재시작');
input.reset.setLabel('초기화');
$('#stat-turn').text(0);
$('.stat-0.stat-currentHP').data('value', stat[0].HP).text(stat[0].HP.toFixed(2)).css('color', '#3366CC');
$('.stat-1.stat-currentHP').data('value', stat[1].HP).text(stat[1].HP.toFixed(2)).css('color', '#FF5500');
$('.stat-0.stat-HPbar').html(bar[0].$element);
$('.stat-1.stat-HPbar').html(bar[1].$element);
if(btn) $('#log')[0].innerText += '\n다시 시작하려면 재시작 버튼을 눌러주세요.';
}
}
function stop() {
clearInterval(battle.work);
$('#input-stop').hide();
$('#input-start').show();
input.reset.setDisabled(false);
input[0].setDisabled(false);
input[1].setDisabled(false);
input.time.setDisabled(false);
input.swap.setDisabled(false);
}
var input = {};
input[0] = new OO.ui.TextInputWidget({
placeholder: '선',
title: '후',
value: new URLSearchParams(location.search).get('p0') || ''
});
input.start = new OO.ui.ButtonInputWidget({
type: 'submit',
flags: ['primary', 'progressive'],
label: '시작'
});
input.stop = new OO.ui.ButtonInputWidget({
flags: ['primary', 'destructive'],
label: '정지'
});
input[1] = new OO.ui.TextInputWidget({
placeholder: '후',
title: '후',
value: new URLSearchParams(location.search).get('p1') || ''
});
input.time = new OO.ui.NumberInputWidget({
value: 1,
min: 0,
label: '초 간격'
});
input.reset = new OO.ui.ButtonInputWidget({
type: 'reset',
flags: ['destructive'],
label: '초기화'
});
input.swap = new OO.ui.ButtonInputWidget({
label: $('<div />').css({
height: '20px',
width: '20px',
'background-image': 'url("/wiki/Special:Redirect/file/Ambox_move_black.svg")',
'background-size': 'cover'
}),
title: '교체',
framed: false
});
input.table = new OO.ui.ToggleSwitchWidget({
value: true
});
input.icon = new OO.ui.ButtonWidget({
framed: false,
icon: $('#mw-customcollapsible-input-option').hasClass('mw-collapsed')? 'expand' : 'collapse'
});
input.log = new OO.ui.ButtonWidget({
label: '기록 복사'
});
input.url = new OO.ui.ButtonWidget({
label: 'URL 복사'
});
input.box = new OO.ui.MultilineTextInputWidget();
var media = matchMedia('(max-width: 800px)');
var stat = [];
var bar = [];
var battle = {
turn: 0,
attack: null,
done: null,
work: null,
sequence: null,
combo: null,
temp: null
};
$('#input').wrap('<form />');
$('#input-0').html(input[0].$element);
$('#input-start').html(input.start.$element);
$('#input-stop').html(input.stop.$element);
$('#input-1').html(input[1].$element);
$('#input-time').html(input.time.$element);
$('#input-reset').html(input.reset.$element);
$('#input-swap').html(input.swap.$element);
$('#input-table').html(input.table.$element).append(' 스탯');
$('#input-icon').html(input.icon.$element);
$('#stat-load').html(new OO.ui.ProgressBarWidget().$element);
$('#log').text('시작하시려면 상단에 대결할 상대의 이름을 입력해 주세요. (1.3)');
$('#share-log').html(input.log.$element);
$('#share-url').html(input.url.$element);
$('#share-cvbox').html(input.box.$element);
input.box.$input.attr('readonly', '').css('height', '2.5em');
$('#stat-bar').hide();
$('#share').hide();
responsible(media);
media.addListener(responsible);
new MutationObserver(function(mutation) {
input.icon.setIcon($(mutation[0].target).hasClass('mw-collapsed')? 'expand' : 'collapse');
}).observe($('#mw-customcollapsible-input-option')[0], {
attributes: true,
attributeFilter: ['class']
});
input.swap.$element.click(function() {
if(!input.swap.disabled) {
var val = [input[1].value, input[0].value];
input[0].setValue(val[0]);
input[1].setValue(val[1]);
if(stat.length) {
stat = [stat[1], stat[0]];
$('#stat-turn').text(0);
$('.stat-0').each(function() {
if($(this).hasClass('stat-name')) $(this).text(stat[0].name);
else if($(this).hasClass('stat-attack')) $(this).text(stat[0].attack);
else if($(this).hasClass('stat-quick')) $(this).text(stat[0].quick);
else if($(this).hasClass('stat-defense')) $(this).text(stat[0].defense);
else if($(this).hasClass('stat-hit')) $(this).text(stat[0].hit);
else if($(this).hasClass('stat-luck')) $(this).text(stat[0].luck);
else if($(this).hasClass('stat-fullHP')) $(this).text(stat[0].HP);
else if($(this).hasClass('stat-currentHP')) $(this).data('value', stat[0].HP).text(stat[0].HP.toFixed(2));
else if($(this).hasClass('stat-HPbar')) $(this).html(bar[0].$element);
});
$('.stat-1').each(function() {
if($(this).hasClass('stat-name')) $(this).text(stat[1].name);
else if($(this).hasClass('stat-attack')) $(this).text(stat[1].attack);
else if($(this).hasClass('stat-quick')) $(this).text(stat[1].quick);
else if($(this).hasClass('stat-defense')) $(this).text(stat[1].defense);
else if($(this).hasClass('stat-hit')) $(this).text(stat[1].hit);
else if($(this).hasClass('stat-luck')) $(this).text(stat[1].luck);
else if($(this).hasClass('stat-fullHP')) $(this).text(stat[1].HP);
else if($(this).hasClass('stat-currentHP')) $(this).data('value', stat[1].HP).text(stat[1].HP.toFixed(2));
else if($(this).hasClass('stat-HPbar')) $(this).html(bar[1].$element);
});
var url = new URL(location);
url.searchParams.set('p0', input[0].value);
url.searchParams.set('p1', input[1].value);
history.replaceState(null, '', url);
cancel();
input.start.setLabel('시작');
}
}
});
input.table.$element.click(function() {
if(input.table.value) {
if($('#stat-turn').text()) $('#stat-table').show(500);
} else {
$('#stat-table').hide(500);
}
});
input.reset.$button[0].form.addEventListener('reset', function(event) {
event.preventDefault();
if(!input.reset.disabled) {
if(battle.done || battle.done === null) {
var url = new URL(location);
url.searchParams['delete']('p0');
url.searchParams['delete']('p1');
history.replaceState(null, '', url);
stat = [];
input[0].setValue();
input[1].setValue();
input.time.setValue(1);
input.table.setValue(true);
input.start.setLabel('시작');
$('#share').hide();
$('#share-cvbox').hide();
$('#stat-table').hide(500);
$('#stat-bar').hide(500);
$('#stat-turn, .stat-0, .stat-1').text('');
$('#log-time').hide();
$('#log').show();
$('#log').text('시작하시려면 상단에 대결할 상대의 이름을 입력해 주세요.');
$('.stat-HPbar').html('');
} else cancel(true);
}
});
input.start.$button[0].form.addEventListener('submit', function(event) {
function last() {
$('#input-stop').show();
$('#input-start').hide();
input.reset.setLabel('취소');
input[0].setDisabled(true);
input[1].setDisabled(true);
input.time.setDisabled(true);
input.reset.setDisabled(true);
input.swap.setDisabled(true);
input.start.setLabel('재개');
battle.work = start(battle, stat.map(function(obj, index) {
return new Proxy(obj, {
get: function(target, key, receiver) {
if(key === 'HP') return +$('.stat-' + index + '.stat-currentHP').data('value');
else return Reflect.get(target, key, receiver);
},
set: function(target, key, value) {
if(key === 'HP') {
if(value < 0) {
value = 0;
$('.stat-' + index + '.stat-currentHP').css('color', '#000000');
}
$('.stat-' + index + '.stat-currentHP').data('value', value).text(value.toFixed(2));
bar[index].setProgress(value / target.HP * 100);
}
}
});
}), input.time.value * 1000, function(msg) {
$('#log')[0].innerText += msg;
$('#log').scrollTop($('#log')[0].scrollHeight);
if(battle.sequence === 0) {
$('#stat-turn').text(battle.turn);
$('.stat-' + battle.attack + '.stat-name').css({
background: battle.attack? '#FF5500' : '#3366CC',
color: '#FFFFFF'
});
$('.stat-' + (battle.attack ^ 1) + '.stat-name').css({
background: '#EAECF0',
color: battle.attack? '#3366CC' : '#FF5500'
});
}
}, function(msg) {
$('#log')[0].innerText += msg;
$('#log')[0].innerText += '\n\n백괴스러운 MD-5 시뮬레이터 [https://game.uncyclopedia.kr/wiki/마법의_MD-5_시뮬레이터]';
$('#log').scrollTop($('#log')[0].scrollHeight);
$('#share').show();
stop();
battle.done = true;
battle.turn = 0;
battle.attack = null;
battle.sequence = null;
battle.combo = null;
battle.temp = null;
input.start.setLabel('재시작');
input.reset.setLabel('초기화');
});
}
event.preventDefault();
if(!input.start.disabled) {
$('#share').hide();
$('#share-cvbox').hide();
if(input.time.value >= 0) {
$('#log-time').hide();
$('#log').show();
if(!stat.length) $.get({
url: '/w/api.php',
data: {
action: 'parse',
format: 'json',
title: '마법의 MD-5 시뮬레이터',
text: '[{{#invoke:SimMD5|stat|' + encode(input[0].value) + '|AJAX}},{{#invoke:SimMD5|stat|' + encode(input[1].value) + '|AJAX}}]',
prop: 'text',
disablelimitreport: true,
formatversion: 2
},
beforeSend: function() {
if($('#stat-bar').html()) {
$('#stat-bar').hide();
$('#stat-load').show();
} else $('#stat-load').show(500);
$('#log').text('스탯 계산중입니다. 잠시만 기다려 주세요.');
var url = new URL(location);
url.searchParams.set('p0', input[0].value);
url.searchParams.set('p1', input[1].value);
history.replaceState(null, '', url);
},
success: function(callback) {
stat = JSON.parse($(callback.parse.text).text());
bar = [];
bar[0] = new OO.ui.ProgressBarWidget({
progress: 100
});
bar[1] = new OO.ui.ProgressBarWidget({
progress: 100
});
bar[0].$bar.css({
background: '#3366CC'
});
bar[0].$element.css({
'border-right': 'none',
'border-top-right-radius': 0,
'border-bottom-right-radius': 0
});
bar[1].$bar.css({
background: '#FF5500'
});
bar[1].$element.css({
'border-left': 'none',
'border-top-left-radius': 0,
'border-bottom-left-radius': 0
});
$('#stat-turn').text(0);
$('.stat-0').each(function() {
if($(this).hasClass('stat-name')) $(this).text(stat[0].name);
else if($(this).hasClass('stat-attack')) $(this).text(stat[0].attack);
else if($(this).hasClass('stat-quick')) $(this).text(stat[0].quick);
else if($(this).hasClass('stat-defense')) $(this).text(stat[0].defense);
else if($(this).hasClass('stat-hit')) $(this).text(stat[0].hit);
else if($(this).hasClass('stat-luck')) $(this).text(stat[0].luck);
else if($(this).hasClass('stat-fullHP')) $(this).text(stat[0].HP);
else if($(this).hasClass('stat-currentHP')) $(this).data('value', stat[0].HP).text(stat[0].HP.toFixed(2));
else if($(this).hasClass('stat-HPbar')) $(this).html(bar[0].$element);
});
$('.stat-1').each(function() {
if($(this).hasClass('stat-name')) $(this).text(stat[1].name);
else if($(this).hasClass('stat-attack')) $(this).text(stat[1].attack);
else if($(this).hasClass('stat-quick')) $(this).text(stat[1].quick);
else if($(this).hasClass('stat-defense')) $(this).text(stat[1].defense);
else if($(this).hasClass('stat-hit')) $(this).text(stat[1].hit);
else if($(this).hasClass('stat-luck')) $(this).text(stat[1].luck);
else if($(this).hasClass('stat-fullHP')) $(this).text(stat[1].HP);
else if($(this).hasClass('stat-currentHP')) $(this).data('value', stat[1].HP).text(stat[1].HP.toFixed(2));
else if($(this).hasClass('stat-HPbar')) $(this).html(bar[1].$element);
});
$('.stat-0.stat-currentHP').css('color', '#3366CC');
$('.stat-1.stat-currentHP').css('color', '#FF5500');
$('#stat-load').hide();
if(input.table.value) $('#stat-table').show(500);
$('#stat-bar').show();
$('#log').text('');
$('#log')[0].innerText += '[' + stat[0].name + '] 공격력: ' + stat[0].attack + ' / 방어력: ' + stat[0].defense + ' / 민첩: ' + stat[0].quick + ' / 명중: ' + stat[0].quick + ' / 운: ' + stat[0].luck + ' / HP: ' + stat[0].HP + '\n';
$('#log')[0].innerText += '[' + stat[1].name + '] 공격력: ' + stat[1].attack + ' / 방어력: ' + stat[1].defense + ' / 민첩: ' + stat[1].quick + ' / 명중: ' + stat[1].quick + ' / 운: ' + stat[1].luck + ' / HP: ' + stat[1].HP + '\n';
$('#log')[0].innerText += '\n';
battle.turn = 1;
battle.done = false;
battle.attack = 0;
battle.sequence = 0;
battle.combo = [0, 0];
battle.temp = {};
last();
},
error: function(error) {
$('#stat-load').hide(500);
$('#log').text('스탯 계산에 오류가 발생하였습니다. 다시 시도해 주십시오. (' + error.status + ')');
}
});
else if(battle.done || battle.done === null) {
if(battle.done) cancel();
$('#log').text('');
$('#log')[0].innerText += '[' + stat[0].name + '] 공격력: ' + stat[0].attack + ' / 방어력: ' + stat[0].defense + ' / 민첩: ' + stat[0].quick + ' / 명중: ' + stat[0].hit + ' / 운: ' + stat[0].luck + ' / HP: ' + stat[0].HP + '\n';
$('#log')[0].innerText += '[' + stat[1].name + '] 공격력: ' + stat[1].attack + ' / 방어력: ' + stat[1].defense + ' / 민첩: ' + stat[1].quick + ' / 명중: ' + stat[1].hit + ' / 운: ' + stat[1].luck + ' / HP: ' + stat[1].HP + '\n';
$('#log')[0].innerText += '\n';
battle.turn = 1;
battle.done = false;
battle.attack = 0;
battle.sequence = 0;
battle.combo = [0, 0];
battle.temp = {};
last();
} else last();
} else {
$('#log-time').show();
$('#log').hide();
}
}
});
input.stop.$element.click(function() {
if(!input.stop.disabled) stop();
});
input[0].$input.focus(function() {
cancel();
stat = [];
input.start.setLabel('시작');
$(this).select();
});
input[1].$input.focus(function() {
cancel();
stat = [];
input.start.setLabel('시작');
$(this).select();
});
input.log.$button.click(function() {
input.box.setValue($('#log').text());
$('#share-cvbox').show();
input.box.$input.select();
document.execCommand('copy');
});
input.url.$button.click(function() {
var url = new URL('/wiki/마법의_MD-5_시뮬레이터', location);
var search = new URLSearchParams(location.search);
url.searchParams.set('p0', search.get('p0'));
url.searchParams.set('p1', search.get('p1'));
input.box.setValue(url);
$('#share-cvbox').show();
input.box.$input.select();
document.execCommand('copy');
});
input.box.$input.click(function() {
$(this).select();
});
}
function start(battle, stat, time, each, last) {
function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function range(weight) {
var range = [-0.5, -0.25, 0, 0.25, 0.5].map(function(ratio, index) {
return 20 + (weight - 50) * ratio;
});
range.reduce(function(acc, current, index, prob) {
return prob[index] += acc;
});
return range;
}
function rank(range, val) {
return range.findIndex(function(current, index) {
return (index === 0 || range[index - 1] < val) && val <= current;
});
}
function power(stat, rank) {
return stat * (((rank === 0)? 0 : rand(1 + 25 * (rank - 1), 25 * rank)) / 100);
}
function bonus(plus, minus, rank) {
rank -= 2;
if(rank === 0) return 0;
return ((rank > 0)? plus : minus) * (rand(1 + 50 * (rank - 1), 50 * rank) / 100);
}
function josa(text, exist, not, only) {
text = text.normalize('NFD');
var code = text.charCodeAt(text.length - 1);
if(0x1161 <= code && code <= 0x11A7) return ((only)? '' : text) + not;
else if(0x11A8 <= code && code <= 0x11FF) return ((only)? '' : text) + exist;
else return ((only)? '' : text) + exist + '(' + not + ')';
}
return setInterval(function() {
var attacker = battle.attack;
var defender = attacker ^ 1;
if(stat[0].HP > 0 && stat[1].HP > 0) {
switch(battle.sequence) {
case 0:
var scale = range(stat[attacker].luck);
var adv = bonus(stat[attacker].hit, stat[defender].quick, rank(range(50), 50 + ((battle.combo[defender])? 0 : battle.combo[defender]) - ((battle.combo[attacker])? 0: battle.combo[attacker])));
var grade = {
attack: rank(scale, rand(1, 100)),
defense: rank(range(stat[defender].luck), rand(1, 100)),
};
var damage = power(stat[attacker].attack, grade.attack) - power(stat[defender].defense, grade.defense) + adv;
battle.temp = {
rank: rank(scale, damage),
damage: (damage > 0)? damage : 0
};
if(battle.temp.damage > stat[attacker].attack) battle.temp.rank = 5;
if(battle.temp.damage) {
if(!battle.temp.rank) battle.temp.rank = 1;
if(battle.combo[attacker] < 0) battle.combo[attacker] = 0;
battle.combo[attacker]++;
} else {
battle.temp.rank = 0;
if(battle.combo[attacker] > 0) battle.combo[attacker] = 0;
battle.combo[attacker]--;
}
each('[' + stat[attacker].name + ']의 공격 ');
battle.sequence++;
break;
case 1:
var rankText = ['MISS', 'HIT', 'GOOD', 'NICE', 'PERFECT', 'CRITICAL'][battle.temp.rank];
each(rankText + '! ');
battle.sequence++;
break;
case 2:
stat[defender].HP -= battle.temp.damage;
var msg = (battle.temp.rank === 0)? '공격을 피했다. (' : (+battle.temp.damage.toFixed(2)) + '의 대미지를 받았다. (' + ((battle.combo[attacker] > 0)? battle.combo[attacker] : 0) + ' COMBO, ';
each('[' + stat[defender].name + ']' + josa(stat[defender].name, '은', '는', true) + ' ' + msg + '남은 HP: ' + (+stat[defender].HP.toFixed(2)) + ')\n');
if(attacker === 1) battle.turn++;
battle.sequence = 0;
battle.attack = defender;
break;
}
} else last('\n[' + stat[defender].name + '] 승! (' + battle.turn + '턴)');
}, time);
}
$(prepare);
});
// 여기까지 코드 입력 //
}
}
$( plugin_SimMD5 );
/* SimMD5 끝 */