MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
Tag: Undo |
No edit summary |
||
| (3 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
/* TimeRO MediaWiki:Common.js | /* TimeRO MediaWiki:Common.js - MERGED REVISED | ||
Combines Cards + Collection network-safe loader with the existing Common.js apps. | |||
Original header: | |||
TimeRO MediaWiki:Common.js | |||
Fixes Card Database and Beginner Leveling Guide loaders. | Fixes Card Database and Beginner Leveling Guide loaders. | ||
ES5-safe: no const, let, arrow functions, template literals or nullish coalescing. */ | ES5-safe: no const, let, arrow functions, template literals or nullish coalescing. */ | ||
| Line 17: | Line 21: | ||
'.tl-root{margin:-1em -1.5em;min-height:100vh;background:radial-gradient(circle at 18% 0%,rgba(88,215,255,.09),transparent 34%),radial-gradient(circle at 88% 24%,rgba(176,108,255,.08),transparent 30%),linear-gradient(135deg,#050914,#02050e);overflow:hidden}.tl-inner{max-width:1280px;margin:0 auto;padding:44px 28px 60px}.tl-hero{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid rgba(88,215,255,.18);border-radius:18px;padding:34px;margin-bottom:18px}.tl-hero h1{font-size:clamp(2.2rem,5vw,4rem);line-height:.96;font-weight:900;color:#fff;letter-spacing:-.035em;margin:0 0 16px}.tl-hero h1 span{background:linear-gradient(90deg,#00ff88,#58d7ff,#f9a826);-webkit-background-clip:text;background-clip:text;color:transparent}.tl-stats,.tl-grid,.tl-checks,.tl-related{display:grid;gap:12px}.tl-stats{grid-template-columns:repeat(5,1fr);margin:18px 0}.tl-stat{background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:14px;text-align:center}.tl-stat strong{display:block;font-size:1.35rem;color:#58d7ff;font-weight:900}.tl-stat span{font-size:.72rem;color:rgba(122,144,176,.72);letter-spacing:.12em;text-transform:uppercase;font-weight:800}.tl-panel{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid rgba(255,255,255,.08);border-radius:18px;padding:16px;margin-bottom:18px}.tl-label{color:#7a90b0;font-weight:900;letter-spacing:.11em;text-transform:uppercase;font-size:.72rem;margin-bottom:10px}.tl-flex{display:flex;gap:9px;flex-wrap:wrap}.tl-track{height:12px;border-radius:999px;background:rgba(255,255,255,.05);overflow:hidden;display:grid;grid-template-columns:24.5fr 24.5fr 20fr 15fr 16fr;margin-bottom:14px}.tl-track span:nth-child(1){background:#00ff88}.tl-track span:nth-child(2){background:#00d4ff}.tl-track span:nth-child(3){background:#f9a826}.tl-track span:nth-child(4){background:#b06cff}.tl-track span:nth-child(5){background:#ff3d5a}.tl-phase{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid var(--line);border-radius:18px;padding:24px;margin-bottom:22px}.tl-head{display:flex;gap:18px;margin-bottom:22px}.tl-icon{width:64px;height:64px;border-radius:18px;display:flex;align-items:center;justify-content:center;flex:0 0 64px;font-size:1.8rem;background:var(--soft);border:1px solid var(--line)}.tl-chip{display:inline-flex;margin:0 8px 8px 0;padding:3px 10px;border-radius:999px;background:var(--soft);border:1px solid var(--line);color:var(--color);font-size:.65rem;letter-spacing:.13em;text-transform:uppercase;font-weight:900}.tl-phase h2{color:#fff;margin:0 0 8px;font-size:clamp(1.35rem,2.5vw,2rem);border:0}.tl-phase p{color:rgba(176,192,224,.75);line-height:1.7;margin:0}.tl-grid{grid-template-columns:1fr 1fr;margin-bottom:18px}.tl-box{border-radius:16px;overflow:hidden;background:rgba(0,0,0,.24);border:1px solid var(--line)}.tl-box-head{padding:13px 16px;background:var(--soft);border-bottom:1px solid var(--line);color:var(--color);font-weight:900;letter-spacing:.08em;text-transform:uppercase;font-size:.78rem}.tl-box-body{padding:15px;display:flex;flex-direction:column;gap:10px}.tl-card{border-radius:12px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);padding:12px 14px}.tl-map{display:flex;justify-content:space-between;gap:14px}.tl-name{color:#fff;font-size:.95rem;font-weight:900}.tl-muted{color:rgba(122,144,176,.72);font-size:.76rem;margin-top:3px}.tl-level{color:var(--color);font-size:.78rem;font-weight:900;white-space:nowrap;text-align:right}.tl-mob{cursor:pointer}.tl-mob-main{display:flex;align-items:center;gap:12px}.tl-mob-icon{width:42px;height:42px;border-radius:10px;display:flex;align-items:center;justify-content:center;background:var(--soft);border:1px solid var(--line);font-size:1.2rem}.tl-mob-info{flex:1}.tl-detail{display:none;padding:10px 0 0 54px;color:rgba(180,205,230,.78);font-size:.82rem;line-height:1.6}.tl-mob.open .tl-detail{display:block}.tl-checks{grid-template-columns:1fr 1fr}.tl-check{display:flex;align-items:center;gap:10px;cursor:pointer}.tl-mark{width:18px;height:18px;border-radius:5px;border:1px solid var(--line);background:var(--soft);display:flex;align-items:center;justify-content:center;color:var(--color);font-weight:900}.tl-check.checked .tl-text{text-decoration:line-through;opacity:.55}.tl-note{display:none;margin-top:14px;border-radius:12px;padding:14px 16px;color:rgba(220,235,255,.78);line-height:1.65;font-size:.88rem}.tl-note strong{display:block;margin-bottom:5px;letter-spacing:.09em;text-transform:uppercase;font-size:.75rem}.tl-footer{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-top:20px}.tl-related{grid-template-columns:repeat(4,1fr);margin-top:24px}.tl-related .tl-panel{text-align:center;margin:0}@media(max-width:980px){.tl-stats,.tl-grid,.tl-checks,.tl-related{grid-template-columns:1fr}.tl-inner{padding:26px 14px 44px}.tl-hero,.tl-phase{padding:20px}.tl-head{flex-direction:column}.tl-map{flex-direction:column}.tl-level{text-align:left}}');} | '.tl-root{margin:-1em -1.5em;min-height:100vh;background:radial-gradient(circle at 18% 0%,rgba(88,215,255,.09),transparent 34%),radial-gradient(circle at 88% 24%,rgba(176,108,255,.08),transparent 30%),linear-gradient(135deg,#050914,#02050e);overflow:hidden}.tl-inner{max-width:1280px;margin:0 auto;padding:44px 28px 60px}.tl-hero{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid rgba(88,215,255,.18);border-radius:18px;padding:34px;margin-bottom:18px}.tl-hero h1{font-size:clamp(2.2rem,5vw,4rem);line-height:.96;font-weight:900;color:#fff;letter-spacing:-.035em;margin:0 0 16px}.tl-hero h1 span{background:linear-gradient(90deg,#00ff88,#58d7ff,#f9a826);-webkit-background-clip:text;background-clip:text;color:transparent}.tl-stats,.tl-grid,.tl-checks,.tl-related{display:grid;gap:12px}.tl-stats{grid-template-columns:repeat(5,1fr);margin:18px 0}.tl-stat{background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:14px;text-align:center}.tl-stat strong{display:block;font-size:1.35rem;color:#58d7ff;font-weight:900}.tl-stat span{font-size:.72rem;color:rgba(122,144,176,.72);letter-spacing:.12em;text-transform:uppercase;font-weight:800}.tl-panel{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid rgba(255,255,255,.08);border-radius:18px;padding:16px;margin-bottom:18px}.tl-label{color:#7a90b0;font-weight:900;letter-spacing:.11em;text-transform:uppercase;font-size:.72rem;margin-bottom:10px}.tl-flex{display:flex;gap:9px;flex-wrap:wrap}.tl-track{height:12px;border-radius:999px;background:rgba(255,255,255,.05);overflow:hidden;display:grid;grid-template-columns:24.5fr 24.5fr 20fr 15fr 16fr;margin-bottom:14px}.tl-track span:nth-child(1){background:#00ff88}.tl-track span:nth-child(2){background:#00d4ff}.tl-track span:nth-child(3){background:#f9a826}.tl-track span:nth-child(4){background:#b06cff}.tl-track span:nth-child(5){background:#ff3d5a}.tl-phase{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid var(--line);border-radius:18px;padding:24px;margin-bottom:22px}.tl-head{display:flex;gap:18px;margin-bottom:22px}.tl-icon{width:64px;height:64px;border-radius:18px;display:flex;align-items:center;justify-content:center;flex:0 0 64px;font-size:1.8rem;background:var(--soft);border:1px solid var(--line)}.tl-chip{display:inline-flex;margin:0 8px 8px 0;padding:3px 10px;border-radius:999px;background:var(--soft);border:1px solid var(--line);color:var(--color);font-size:.65rem;letter-spacing:.13em;text-transform:uppercase;font-weight:900}.tl-phase h2{color:#fff;margin:0 0 8px;font-size:clamp(1.35rem,2.5vw,2rem);border:0}.tl-phase p{color:rgba(176,192,224,.75);line-height:1.7;margin:0}.tl-grid{grid-template-columns:1fr 1fr;margin-bottom:18px}.tl-box{border-radius:16px;overflow:hidden;background:rgba(0,0,0,.24);border:1px solid var(--line)}.tl-box-head{padding:13px 16px;background:var(--soft);border-bottom:1px solid var(--line);color:var(--color);font-weight:900;letter-spacing:.08em;text-transform:uppercase;font-size:.78rem}.tl-box-body{padding:15px;display:flex;flex-direction:column;gap:10px}.tl-card{border-radius:12px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);padding:12px 14px}.tl-map{display:flex;justify-content:space-between;gap:14px}.tl-name{color:#fff;font-size:.95rem;font-weight:900}.tl-muted{color:rgba(122,144,176,.72);font-size:.76rem;margin-top:3px}.tl-level{color:var(--color);font-size:.78rem;font-weight:900;white-space:nowrap;text-align:right}.tl-mob{cursor:pointer}.tl-mob-main{display:flex;align-items:center;gap:12px}.tl-mob-icon{width:42px;height:42px;border-radius:10px;display:flex;align-items:center;justify-content:center;background:var(--soft);border:1px solid var(--line);font-size:1.2rem}.tl-mob-info{flex:1}.tl-detail{display:none;padding:10px 0 0 54px;color:rgba(180,205,230,.78);font-size:.82rem;line-height:1.6}.tl-mob.open .tl-detail{display:block}.tl-checks{grid-template-columns:1fr 1fr}.tl-check{display:flex;align-items:center;gap:10px;cursor:pointer}.tl-mark{width:18px;height:18px;border-radius:5px;border:1px solid var(--line);background:var(--soft);display:flex;align-items:center;justify-content:center;color:var(--color);font-weight:900}.tl-check.checked .tl-text{text-decoration:line-through;opacity:.55}.tl-note{display:none;margin-top:14px;border-radius:12px;padding:14px 16px;color:rgba(220,235,255,.78);line-height:1.65;font-size:.88rem}.tl-note strong{display:block;margin-bottom:5px;letter-spacing:.09em;text-transform:uppercase;font-size:.75rem}.tl-footer{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-top:20px}.tl-related{grid-template-columns:repeat(4,1fr);margin-top:24px}.tl-related .tl-panel{text-align:center;margin:0}@media(max-width:980px){.tl-stats,.tl-grid,.tl-checks,.tl-related{grid-template-columns:1fr}.tl-inner{padding:26px 14px 44px}.tl-hero,.tl-phase{padding:20px}.tl-head{flex-direction:column}.tl-map{flex-direction:column}.tl-level{text-align:left}}');} | ||
/* Card app */ | /* Card app - merged Cards + Collection renderer */ | ||
function initCards(){var root=document.getElementById('timero-card-db-app');if(!root||root.getAttribute('data-ready')==='1')return;root.setAttribute('data-ready','1'); | function initCards(){ | ||
var root=document.getElementById('timero-card-db-app'); | |||
if(!root||root.getAttribute('data-ready')==='1'||root.getAttribute('data-timero-mounted')==='1')return; | |||
root.setAttribute('data-ready','1'); | |||
root.setAttribute('data-timero-mounted','1'); | |||
injectSharedCss(); | |||
var state={ | |||
api:root.getAttribute('data-api')||'https://timero.com.br/pt/api/wiki_cards.php', | |||
q:'', | |||
cat:'all', | |||
slot:'', | |||
group:'', | |||
changed:false, | |||
sort:'card_name', | |||
dir:'asc', | |||
cards:[], | |||
groups:[], | |||
filters:{slots:[],categories:[]}, | |||
total:0, | |||
err:'', | |||
errDetails:'', | |||
load:false | |||
}; | |||
var cats=[ | |||
['all','Todas','◆','#7c6aff'], | |||
['weapon','Armas','⚔️','#ff6b7a'], | |||
['armor','Armaduras','🛡','#00d4ff'], | |||
['accessory','Acessórios','💎','#f9a826'], | |||
['headgear','Headgear','🎩','#b06cff'], | |||
['shield','Escudos','🛡️','#70b8ff'], | |||
['garment','Capas','🧥','#60d090'], | |||
['shoes','Sapatos','👢','#f0c840'] | |||
]; | |||
function categoryValue(card){return String(card.category||card.card_category||card.type||'').toLowerCase();} | |||
function slotValue(card){return String(card.slot||card.slot_type||card.equip_slot||'');} | |||
function groupName(card){return card.group_name||card.collection_group_name||card.groupName||'';} | |||
function groupIcon(card){return card.group_icon||card.collection_group_icon||'📚';} | |||
function groupColor(card){return card.group_color||card.collection_group_color||'#b06cff';} | |||
function oldEffect(card){return card.old_effect||card.original_effect||card.vanilla_effect||'—';} | |||
function newEffect(card){return card.new_effect||card.reworked_effect||card.effect_new||card.effect||'—';} | |||
function collectionEffect(card){return card.collection_effect||card.group_effect||card.effect||'';} | |||
function collectionScript(card){return card.bonus_script||card.collection_script||card.script||'';} | |||
function collectionPoints(card){return card.collection_points||card.points||0;} | |||
function cardChanged(card){return String(card.changed)==='1'||String(oldEffect(card))!==String(newEffect(card));} | |||
function meta(id){ | |||
id=String(id||'all').toLowerCase(); | |||
for(var i=0;i<cats.length;i++)if(cats[i][0]===id)return cats[i]; | |||
return cats[0]; | |||
} | |||
function readScript(s){ | |||
return String(s||'') | |||
.replace(/bonus\s+/gi,'') | |||
.replace(/;/g,'; ') | |||
.replace(/bAllStats/gi,'All Stats') | |||
.replace(/bMaxHP/gi,'Max HP') | |||
.replace(/bMaxSP/gi,'Max SP') | |||
.replace(/bBaseAtk/gi,'ATK') | |||
.replace(/bMatk/gi,'MATK') | |||
.replace(/bStr/gi,'STR') | |||
.replace(/bAgi/gi,'AGI') | |||
.replace(/bVit/gi,'VIT') | |||
.replace(/bInt/gi,'INT') | |||
.replace(/bDex/gi,'DEX') | |||
.replace(/bLuk/gi,'LUK')||'—'; | |||
} | |||
function buildUrl(){ | |||
var url=state.api; | |||
var join=url.indexOf('?')===-1?'?':'&'; | |||
var params=[]; | |||
params.push('q='+encodeURIComponent(state.q)); | |||
if(state.cat&&state.cat!=='all')params.push('category='+encodeURIComponent(state.cat)); | |||
if(state.slot)params.push('slot='+encodeURIComponent(state.slot)); | |||
if(state.group)params.push('group='+encodeURIComponent(state.group)); | |||
params.push('changed='+(state.changed?'1':'0')); | |||
params.push('sort='+encodeURIComponent(state.sort)); | |||
params.push('dir='+encodeURIComponent(state.dir)); | |||
params.push('limit=250'); | |||
params.push('_='+String(new Date().getTime())); | |||
return url+join+params.join('&'); | |||
} | |||
function shell(){ | |||
root.className+=' tr-app'; | |||
root.innerHTML= | |||
'<div class="tr-shell">'+ | |||
'<div class="tr-head">'+ | |||
'<div class="tr-kicker">◇ Banco de Dados</div>'+ | |||
'<h2 class="tr-title">Cartas Balanceadas + Coleção</h2>'+ | |||
'<div class="tr-sub">Pesquise por nome da carta, ID, monstro, slot, efeito antigo, efeito novo, bônus de coleção ou script de coleção. Este loader une a lógica antiga do Common.js com o endpoint novo <strong>wiki_cards.php</strong>.</div>'+ | |||
'</div>'+ | |||
'<div class="tc-toolbar">'+ | |||
'<div class="tc-top">'+ | |||
'<div class="tc-search-wrap"><span>🔍</span><input id="tc-search" class="tc-search" placeholder="Buscar carta, ID, monstro, efeito ou coleção..."></div>'+ | |||
'<label class="tc-toggle"><input id="tc-changed" type="checkbox"> ⚡ Apenas alteradas</label>'+ | |||
'<div id="tc-count" class="tr-pill">— cartas</div>'+ | |||
'</div>'+ | |||
'<div id="tc-tabs" class="tc-tabs"></div>'+ | |||
'<div id="tc-extra-filters" class="tc-tabs"></div>'+ | |||
'</div>'+ | |||
'<div class="tc-table">'+ | |||
'<div class="tc-head-row">'+ | |||
'<div class="tc-th" data-sort="id">ID ↕</div>'+ | |||
'<div class="tc-th" data-sort="name">Carta / Monstro ↕</div>'+ | |||
'<div class="tc-th" data-sort="slot">Slot ↕</div>'+ | |||
'<div class="tc-th" data-sort="category">Grupo ↕</div>'+ | |||
'<div class="tc-th">Status</div>'+ | |||
'</div>'+ | |||
'<div id="tc-body"><div class="tc-msg">Carregando cartas...</div></div>'+ | |||
'</div>'+ | |||
'<div class="tc-groups">'+ | |||
'<div class="tr-head" style="margin-top:26px">'+ | |||
'<div class="tr-kicker">◇ Grupos de Coleção</div>'+ | |||
'<h2 class="tr-title" style="font-size:1.35rem">Bônus permanentes por grupo</h2>'+ | |||
'<div class="tr-sub">Dados carregados da tabela <strong>wiki_card_groups</strong> e enriquecidos por <strong>collection_card_meta</strong> quando disponível.</div>'+ | |||
'</div>'+ | |||
'<div id="tc-groups"></div>'+ | |||
'</div>'+ | |||
'</div>'; | |||
} | |||
function bindStatic(){ | |||
var search=root.querySelector('#tc-search'); | |||
var changed=root.querySelector('#tc-changed'); | |||
var heads=root.querySelectorAll('.tc-th[data-sort]'); | |||
var debounced=debounce(function(){state.q=search.value;fetchCards();},220); | |||
search.oninput=debounced; | |||
changed.onchange=function(){state.changed=this.checked;fetchCards();}; | |||
for(var i=0;i<heads.length;i++){ | |||
heads[i].onclick=function(){ | |||
var s=this.getAttribute('data-sort'); | |||
if(state.sort===s)state.dir=state.dir==='asc'?'desc':'asc'; | |||
else{state.sort=s;state.dir='asc';} | |||
fetchCards(); | |||
}; | |||
} | |||
} | |||
function renderTabs(){ | |||
var tabs=root.querySelector('#tc-tabs'); | |||
if(!tabs)return; | |||
tabs.innerHTML=''; | |||
for(var i=0;i<cats.length;i++){ | |||
(function(c){ | |||
var b=document.createElement('button'); | |||
b.className='tr-btn'+(c[0]===state.cat?' active':''); | |||
b.innerHTML=esc(c[2])+' '+esc(c[1]); | |||
b.onclick=function(){state.cat=c[0];fetchCards();}; | |||
tabs.appendChild(b); | |||
})(cats[i]); | |||
} | |||
} | |||
function renderExtraFilters(){ | |||
var wrap=root.querySelector('#tc-extra-filters'); | |||
if(!wrap)return; | |||
var slotValues=(state.filters&&state.filters.slots)||[]; | |||
var groupValues=state.groups||[]; | |||
var html=''; | |||
html+='<select id="tc-slot-filter" class="tr-btn" style="background:#050914;border-radius:999px;max-width:220px"><option value="">Todos os slots</option>'; | |||
for(var i=0;i<slotValues.length;i++){ | |||
html+='<option value="'+esc(slotValues[i])+'"'+(state.slot===slotValues[i]?' selected':'')+'>'+esc(slotValues[i])+'</option>'; | |||
} | |||
html+='</select>'; | |||
html+='<select id="tc-group-filter" class="tr-btn" style="background:#050914;border-radius:999px;max-width:260px"><option value="">Todos os grupos</option>'; | |||
for(i=0;i<groupValues.length;i++){ | |||
var g=groupValues[i]; | |||
var gid=g.id||g.group_id||g.group_key||g.name||g.group_name||''; | |||
var gname=g.name||g.group_name||g.group_key||('Grupo '+gid); | |||
html+='<option value="'+esc(gid)+'"'+(String(state.group)===String(gid)?' selected':'')+'>'+esc(g.icon||'📚')+' '+esc(gname)+'</option>'; | |||
} | |||
html+='</select>'; | |||
html+='<button id="tc-clear-filters" class="tr-btn">Limpar filtros</button>'; | |||
wrap.innerHTML=html; | |||
var slot=root.querySelector('#tc-slot-filter'); | |||
var group=root.querySelector('#tc-group-filter'); | |||
var clear=root.querySelector('#tc-clear-filters'); | |||
if(slot)slot.onchange=function(){state.slot=this.value;fetchCards();}; | |||
if(group)group.onchange=function(){state.group=this.value;fetchCards();}; | |||
if(clear)clear.onclick=function(){ | |||
state.q=''; | |||
state.cat='all'; | |||
state.slot=''; | |||
state.group=''; | |||
state.changed=false; | |||
var search=root.querySelector('#tc-search'); | |||
var changed=root.querySelector('#tc-changed'); | |||
if(search)search.value=''; | |||
if(changed)changed.checked=false; | |||
fetchCards(); | |||
}; | |||
} | |||
function renderError(){ | |||
var body=root.querySelector('#tc-body'); | |||
var count=root.querySelector('#tc-count'); | |||
if(count)count.innerHTML='Erro'; | |||
if(!body)return; | |||
body.innerHTML= | |||
'<div class="tc-msg tc-error" style="text-align:left">'+ | |||
'<div style="font-weight:900;letter-spacing:.08em;text-transform:uppercase;color:#ff7070;margin-bottom:8px">Erro na rede</div>'+ | |||
'<div style="line-height:1.65;margin-bottom:12px;color:#ffb8b8">A wiki não conseguiu carregar <strong>Cards + Collection</strong> pelo endpoint JSON.</div>'+ | |||
'<div style="background:rgba(0,0,0,.32);border:1px solid rgba(255,255,255,.08);border-radius:10px;padding:12px;font-family:Consolas,monospace;font-size:12px;white-space:pre-wrap;color:#ffd0d0">'+esc(state.err||'Erro desconhecido')+'</div>'+ | |||
(state.errDetails?'<div style="margin-top:10px;background:rgba(0,0,0,.22);border:1px solid rgba(255,255,255,.06);border-radius:10px;padding:12px;font-family:Consolas,monospace;font-size:12px;white-space:pre-wrap;color:#d8ecff">'+esc(state.errDetails)+'</div>':'')+ | |||
'<div style="margin-top:14px;color:rgba(255,210,210,.78);line-height:1.6;font-size:.9em">Verifique se <code>/pt/api/wiki_cards.php</code> existe, se o PHP retorna JSON válido e se o header CORS permite <code>wiki.timero.com.br</code>.</div>'+ | |||
'</div>'; | |||
} | |||
function cardIcon(id){ | |||
id=Number(id)||0; | |||
return '<div class="tc-icon"><img src="https://timero.com.br/images/item/icons/'+esc(id)+'.png" onerror="this.onerror=null;this.src=\'https://timero.com.br/images/item/'+esc(id)+'.png\';this.onerror=function(){this.parentNode.innerHTML=\\\'🃏\\\';};"></div>'; | |||
} | |||
function itemAnchor(id,name){ | |||
id=Number(id)||0; | |||
return '<a href="https://timero.com.br/pt/item?id='+id+'" target="_blank" rel="noopener" style="color:#58d7ff;text-decoration:none;font-weight:900">'+esc(name||('Carta #'+id))+'</a>'; | |||
} | |||
function monsterAnchor(id,name){ | |||
id=Number(id)||0; | |||
if(!id)return esc(name||'—'); | |||
return '<a href="https://timero.com.br/pt/monster?id='+id+'" target="_blank" rel="noopener" style="color:#c0a0ff;text-decoration:none;font-weight:800">'+esc(name||('Monstro #'+id))+'</a>'; | |||
} | |||
function renderCards(){ | |||
var body=root.querySelector('#tc-body'); | |||
var count=root.querySelector('#tc-count'); | |||
var cards=state.cards||[]; | |||
if(count)count.innerHTML=(state.total||cards.length)+' carta'+((state.total||cards.length)===1?'':'s'); | |||
if(state.load){ | |||
body.innerHTML='<div class="tc-msg">Carregando cartas...</div>'; | |||
return; | |||
} | |||
if(state.err){ | |||
renderError(); | |||
return; | |||
} | |||
if(!cards.length){ | |||
body.innerHTML='<div class="tc-msg">Nenhuma carta encontrada.</div>'; | |||
renderGroups(); | |||
return; | |||
} | |||
body.innerHTML=''; | |||
for(var i=0;i<cards.length;i++){ | |||
(function(card){ | |||
var id=card.item_id||card.card_id||card.id; | |||
var cname=card.card_name||card.name||('Carta #'+id); | |||
var m=meta(categoryValue(card)); | |||
var changed=cardChanged(card); | |||
var row=document.createElement('div'); | |||
var det=document.createElement('div'); | |||
var gname=groupName(card); | |||
var gicon=groupIcon(card); | |||
var gcolor=groupColor(card); | |||
row.className='tc-row'; | |||
row.innerHTML= | |||
'<div class="tc-cell tc-id">#'+esc(id)+'</div>'+ | |||
'<div class="tc-cell"><div class="tc-name">'+cardIcon(id)+'<div><div class="tc-card-title">'+itemAnchor(id,cname)+'</div>'+(card.monster_name?'<div class="tc-small">'+monsterAnchor(card.monster_id,card.monster_name)+'</div>':'')+'</div></div></div>'+ | |||
'<div class="tc-cell"><span class="tr-pill">'+esc(slotValue(card)||'Unknown')+'</span></div>'+ | |||
'<div class="tc-cell"><span class="tr-pill" style="color:'+esc(gcolor||m[3])+';border-color:'+esc(gcolor||m[3])+'44">'+esc(gicon||m[2])+' '+esc(gname||categoryValue(card)||'—')+'</span></div>'+ | |||
'<div class="tc-cell">'+(changed?'<span class="tc-status tc-changed">Alterada</span>':'<span class="tc-status tc-original">Original</span>')+'</div>'; | |||
det.className='tc-detail'; | |||
det.innerHTML= | |||
'<div class="tc-detail-grid">'+ | |||
'<div class="tc-box"><h4>Efeito Antigo</h4><div>'+esc(oldEffect(card)||'—')+'</div></div>'+ | |||
'<div class="tc-box"><h4>Efeito TimeRO</h4><div>'+esc(newEffect(card)||'—')+'</div></div>'+ | |||
'<div class="tc-box"><h4>Coleção</h4><div>'+ | |||
'<b style="color:#f0c840">Grupo:</b> '+esc(gname||'—')+'<br>'+ | |||
'<b style="color:#f0c840">Pontos:</b> '+esc(collectionPoints(card)||0)+'<br>'+ | |||
'<b style="color:#f0c840">Efeito:</b> '+esc(collectionEffect(card)||'—')+'<br>'+ | |||
'<b style="color:#f0c840">Script:</b> '+esc(readScript(collectionScript(card)))+ | |||
'</div></div>'+ | |||
'</div>'; | |||
row.onclick=function(){ | |||
var open=det.className.indexOf('open')>-1; | |||
var ds=body.querySelectorAll('.tc-detail.open'); | |||
var rs=body.querySelectorAll('.tc-row.open'); | |||
for(var a=0;a<ds.length;a++)ds[a].className='tc-detail'; | |||
for(var r=0;r<rs.length;r++)rs[r].className='tc-row'; | |||
if(!open){det.className='tc-detail open';row.className='tc-row open';} | |||
}; | |||
body.appendChild(row); | |||
body.appendChild(det); | |||
})(cards[i]); | |||
} | |||
renderGroups(); | |||
} | |||
function renderGroups(){ | |||
var gw=root.querySelector('#tc-groups'); | |||
if(!gw)return; | |||
var groups=state.groups||[]; | |||
gw.innerHTML=''; | |||
if(!groups.length){ | |||
gw.innerHTML='<div class="tc-msg">Nenhum grupo de coleção cadastrado.</div>'; | |||
return; | |||
} | |||
for(var i=0;i<groups.length;i++){ | |||
var g=groups[i]; | |||
var c=g.color||'#7c6aff'; | |||
var key=g.group_key||g.key||g.id||g.group_id||'—'; | |||
var name=g.name||g.group_name||g.title||('Grupo '+key); | |||
var cardCount=g.card_count||g.cards||0; | |||
var min=g.min_cards||g.required_count||g.minimum_count||1; | |||
var effect=g.collection_effect||g.effect||g.bonus||'—'; | |||
var el=document.createElement('div'); | |||
el.className='tc-group'; | |||
el.style.borderColor=c+'33'; | |||
el.innerHTML= | |||
'<div class="tc-group-main">'+ | |||
'<div class="tc-group-icon" style="background:'+c+'14;border:1px solid '+c+'44">'+esc(g.icon||'🃏')+'</div>'+ | |||
'<div><div class="tc-group-key" style="color:'+c+'">Grupo · '+esc(key)+'</div><div class="tc-group-name">'+esc(name)+'</div></div>'+ | |||
'<div class="tr-pill" style="color:'+c+';border-color:'+c+'33">'+esc(cardCount)+' cartas · Min '+esc(min)+'</div>'+ | |||
'</div>'+ | |||
'<div class="tc-group-bonus"><b style="color:'+c+'">Bônus:</b> '+esc(effect)+'</div>'; | |||
gw.appendChild(el); | |||
} | |||
} | |||
function normalizeData(d){ | |||
d=d||{}; | |||
state.cards=d.cards||[]; | |||
state.groups=d.groups||[]; | |||
state.filters=d.filters||{slots:[],categories:[]}; | |||
state.total=d.total||state.cards.length; | |||
// API-side filtering is preferred. This client-side pass preserves old Common.js logic | |||
// when the endpoint ignores changed/category/slot/group parameters. | |||
var q=String(state.q||'').toLowerCase(); | |||
var cat=String(state.cat||'all').toLowerCase(); | |||
var slot=String(state.slot||''); | |||
var group=String(state.group||''); | |||
state.cards=state.cards.filter(function(card){ | |||
if(cat!=='all'&&categoryValue(card)!==cat)return false; | |||
if(slot&&slotValue(card)!==slot)return false; | |||
if(group){ | |||
var gid=String(card.group_id||card.collection_group_id||''); | |||
var gname=String(groupName(card)||''); | |||
if(gid!==group&&gname!==group)return false; | |||
} | |||
if(state.changed&&!cardChanged(card))return false; | |||
if(q){ | |||
var blob=[ | |||
card.item_id,card.card_id,card.id,card.card_name,card.name,card.monster_name, | |||
slotValue(card),categoryValue(card),groupName(card),oldEffect(card),newEffect(card), | |||
collectionEffect(card),collectionScript(card) | |||
].join(' ').toLowerCase(); | |||
if(blob.indexOf(q)<0)return false; | |||
} | |||
return true; | |||
}); | |||
state.total=state.cards.length; | |||
} | |||
function fetchCards(){ | |||
state.load=true; | |||
state.err=''; | |||
state.errDetails=''; | |||
renderTabs(); | |||
renderCards(); | |||
var url=buildUrl(); | |||
ajax(url,function(d){ | |||
state.load=false; | |||
if(!d||!d.ok){ | |||
state.err=(d&&d.error)||'Erro desconhecido'; | |||
state.errDetails='URL usada:\n'+url; | |||
state.cards=[]; | |||
state.groups=[]; | |||
}else{ | |||
normalizeData(d); | |||
} | |||
renderTabs(); | |||
renderExtraFilters(); | |||
renderCards(); | |||
},function(e){ | |||
state.load=false; | |||
state.err=e; | |||
state.errDetails='URL usada:\n'+url; | |||
state.cards=[]; | |||
state.groups=[]; | |||
renderTabs(); | |||
renderExtraFilters(); | |||
renderCards(); | |||
}); | |||
} | |||
shell(); | |||
bindStatic(); | |||
renderTabs(); | |||
renderExtraFilters(); | |||
fetchCards(); | |||
} | |||
/* Leveling app */ | /* Leveling app */ | ||
| Line 68: | Line 494: | ||
function calc(){var k=Number((byId('tz-kills')||{}).value)||0,v=Number((byId('tz-value')||{}).value)||0,d=Number((byId('tz-drop')||{}).value)||0,c=Number((byId('tz-cost')||{}).value)||0,res=(k*v*(d/100))-c;var out=byId('tz-result');if(out)out.innerHTML='Lucro estimado: '+money(res)+' / hora';} | function calc(){var k=Number((byId('tz-kills')||{}).value)||0,v=Number((byId('tz-value')||{}).value)||0,d=Number((byId('tz-drop')||{}).value)||0,c=Number((byId('tz-cost')||{}).value)||0,res=(k*v*(d/100))-c;var out=byId('tz-result');if(out)out.innerHTML='Lucro estimado: '+money(res)+' / hora';} | ||
function bind(root){var bs=root.querySelectorAll('[data-tz-method]'),i;for(i=0;i<bs.length;i++)bs[i].onclick=function(){setMethod(root,this.getAttribute('data-tz-method'));};var ins=root.querySelectorAll('.tz-field input');for(i=0;i<ins.length;i++)ins[i].oninput=calc;} | function bind(root){var bs=root.querySelectorAll('[data-tz-method]'),i;for(i=0;i<bs.length;i++)bs[i].onclick=function(){setMethod(root,this.getAttribute('data-tz-method'));};var ins=root.querySelectorAll('.tz-field input');for(i=0;i<ins.length;i++)ins[i].oninput=calc;} | ||
function init(){var root=byId('timero-zeny-guide-app | function init(){var root=byId('timero-zeny-guide-app');if(!root||root.getAttribute('data-timero-zeny-ready')==='1')return;root.setAttribute('data-timero-zeny-ready','1');render(root);} | ||
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init(); | if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init(); | ||
if(window.mw&&mw.hook)mw.hook('wikipage.content').add(init); | if(window.mw&&mw.hook)mw.hook('wikipage.content').add(init); | ||
| Line 111: | Line 537: | ||
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init(); | if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init(); | ||
if(window.mw&&mw.hook)mw.hook('wikipage.content').add(init); | if(window.mw&&mw.hook)mw.hook('wikipage.content').add(init); | ||
})(); | |||
/* ========================================================= | |||
TIMERO FARMING GUIDE — MERCHANT LEDGER FIX | |||
Source-compatible with the original page using #farming-guide-root. | |||
This keeps the original wiki page intact and restores interactions | |||
without inline <script>, <input>, <button>, or onclick handlers. | |||
========================================================= */ | |||
(function () { | |||
'use strict'; | |||
function $(sel, root) { return (root || document).querySelector(sel); } | |||
function $all(sel, root) { return Array.prototype.slice.call((root || document).querySelectorAll(sel)); } | |||
function byId(id) { return document.getElementById(id); } | |||
function injectStyle() { | |||
if (byId('timero-farming-merchant-ledger-css')) return; | |||
var s = document.createElement('style'); | |||
s.id = 'timero-farming-merchant-ledger-css'; | |||
s.textContent = '' + | |||
'@keyframes ticker-scroll{0%{transform:translateX(0)}100%{transform:translateX(-50%)}}' + | |||
'@keyframes route-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}' + | |||
'#farming-guide-root .method-tab:hover,#farming-guide-root .route-pill:hover,#farming-guide-root .loadout-item:hover,#farming-guide-root [data-calc-adjust]:hover,#farming-guide-root .calc-method-option:hover,#farming-guide-root .loadout-clear:hover{filter:brightness(1.16);transform:translateY(-1px)}' + | |||
'#farming-guide-root .loadout-item.is-selected{background:rgba(176,108,255,0.12)!important;border-color:rgba(176,108,255,0.34)!important;box-shadow:0 0 18px rgba(176,108,255,0.08)}' + | |||
'#farming-guide-root .route-pill.is-active{box-shadow:0 0 18px rgba(249,197,0,0.12),inset 0 0 12px rgba(255,255,255,0.04)!important}' + | |||
'@media(max-width:900px){#farming-guide-root [style*="grid-template-columns:repeat(5"],#farming-guide-root [style*="grid-template-columns:repeat(4"],#farming-guide-root [style*="grid-template-columns:repeat(3"],#farming-guide-root [style*="grid-template-columns:1fr 1fr"]{grid-template-columns:1fr!important}#farming-guide-root [style*="padding:56px 64px"],#farming-guide-root [style*="padding:52px 64px"]{padding:36px 18px!important}}'; | |||
document.head.appendChild(s); | |||
} | |||
var methodColors = { | |||
grind: { color: '#f9c500', bg: 'linear-gradient(135deg,rgba(249,197,0,0.18),rgba(249,197,0,0.07))' }, | |||
market: { color: '#00d4ff', bg: 'linear-gradient(135deg,rgba(0,212,255,0.18),rgba(0,212,255,0.07))' }, | |||
passive:{ color: '#b06cff', bg: 'linear-gradient(135deg,rgba(176,108,255,0.18),rgba(176,108,255,0.07))' } | |||
}; | |||
function setMethod(root, method) { | |||
method = method || 'grind'; | |||
root.setAttribute('data-open-method', method); | |||
$all('.method-panel', root).forEach(function (panel) { | |||
var active = panel.id === 'method-' + method; | |||
panel.style.display = active ? 'grid' : 'none'; | |||
}); | |||
$all('.method-tab', root).forEach(function (tab) { | |||
var id = tab.getAttribute('data-method'); | |||
var active = id === method; | |||
var meta = methodColors[id] || methodColors.grind; | |||
tab.style.background = active ? meta.bg : 'transparent'; | |||
tab.style.color = active ? meta.color : meta.color.replace(')', ',0.60)').replace('rgb', 'rgba'); | |||
tab.style.fontWeight = active ? '900' : '700'; | |||
tab.style.boxShadow = active ? 'inset 0 -2px 0 ' + meta.color : 'none'; | |||
}); | |||
} | |||
function setRoute(root, routeId) { | |||
var currentlyOpen = root.getAttribute('data-open-route') || ''; | |||
var shouldClose = currentlyOpen === routeId; | |||
var next = shouldClose ? '' : routeId; | |||
root.setAttribute('data-open-route', next); | |||
$all('.route-detail', root).forEach(function (panel) { | |||
panel.style.display = panel.id === next ? 'block' : 'none'; | |||
}); | |||
$all('.route-pill', root).forEach(function (pill) { | |||
var active = pill.getAttribute('data-route') === next; | |||
pill.classList.toggle('is-active', active); | |||
pill.style.opacity = next && !active ? '0.56' : '1'; | |||
}); | |||
if (next) { | |||
var target = byId(next); | |||
if (target) setTimeout(function () { target.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }, 60); | |||
} | |||
} | |||
function fmtMillions(v) { | |||
v = Math.max(0, Math.round(v)); | |||
if (v >= 1000) { | |||
var b = v / 1000; | |||
return (Math.round(b * 10) / 10).toLocaleString('pt-BR') + 'B z'; | |||
} | |||
return v.toLocaleString('pt-BR') + 'M z'; | |||
} | |||
function getCalcState(root) { | |||
var hoursEl = byId('calc-hours'); | |||
var labelEl = byId('calc-method-label'); | |||
var rate = Number(root.getAttribute('data-calc-rate') || '70'); | |||
var hours = Number(root.getAttribute('data-calc-hours') || (hoursEl ? hoursEl.textContent : '2') || '2'); | |||
var booster = Number(root.getAttribute('data-calc-booster') || '0'); | |||
var label = root.getAttribute('data-calc-label') || (labelEl ? labelEl.textContent : 'Rota Mid-Game (70M/hr)'); | |||
return { hours: hours, rate: rate, booster: booster, label: label }; | |||
} | |||
function calc(root) { | |||
var st = getCalcState(root); | |||
var mult = st.booster ? 1.5 : 1; | |||
var session = st.hours * st.rate * mult; | |||
var day = session; | |||
var week = day * 7; | |||
var weeklyTarget = 12000; | |||
var pct = Math.min(100, Math.round((week / weeklyTarget) * 100)); | |||
var hoursEl = byId('calc-hours'); | |||
var labelEl = byId('calc-method-label'); | |||
var sessionEl = byId('result-session'); | |||
var dayEl = byId('result-day'); | |||
var weekEl = byId('result-week'); | |||
var pctEl = byId('result-pct'); | |||
var barEl = byId('result-bar'); | |||
if (hoursEl) hoursEl.textContent = String(st.hours).replace('.', ','); | |||
if (labelEl) labelEl.textContent = st.label; | |||
if (sessionEl) sessionEl.textContent = fmtMillions(session); | |||
if (dayEl) dayEl.textContent = fmtMillions(day); | |||
if (weekEl) weekEl.textContent = fmtMillions(week); | |||
if (pctEl) pctEl.textContent = pct + '%'; | |||
if (barEl) barEl.style.width = pct + '%'; | |||
var yes = byId('boost-yes'); | |||
var no = byId('boost-no'); | |||
if (yes && no) { | |||
yes.style.background = st.booster ? 'rgba(0,255,136,0.14)' : 'rgba(255,255,255,0.04)'; | |||
yes.style.borderColor = st.booster ? 'rgba(0,255,136,0.30)' : 'rgba(255,255,255,0.09)'; | |||
yes.style.color = st.booster ? '#00ff88' : 'rgba(122,144,176,0.60)'; | |||
yes.style.fontWeight = st.booster ? '800' : '700'; | |||
no.style.background = st.booster ? 'rgba(255,255,255,0.04)' : 'rgba(255,61,90,0.15)'; | |||
no.style.borderColor = st.booster ? 'rgba(255,255,255,0.09)' : 'rgba(255,61,90,0.30)'; | |||
no.style.color = st.booster ? 'rgba(122,144,176,0.60)' : '#ff3d5a'; | |||
no.style.fontWeight = st.booster ? '700' : '800'; | |||
} | |||
} | |||
function updateLoadout(root) { | |||
var total = 0; | |||
var count = 0; | |||
$all('.loadout-item.is-selected', root).forEach(function (item) { | |||
total += Number(item.getAttribute('data-cost') || '0'); | |||
count++; | |||
}); | |||
var totalEl = byId('loadout-total'); | |||
var countEl = byId('loadout-count'); | |||
if (totalEl) totalEl.textContent = total.toLocaleString('pt-BR') + 'k z'; | |||
if (countEl) countEl.textContent = String(count); | |||
} | |||
function bind(root) { | |||
$all('.method-tab', root).forEach(function (tab) { | |||
tab.addEventListener('click', function () { setMethod(root, tab.getAttribute('data-method')); }); | |||
}); | |||
$all('.route-pill', root).forEach(function (pill) { | |||
pill.addEventListener('click', function () { setRoute(root, pill.getAttribute('data-route')); }); | |||
}); | |||
$all('.route-close', root).forEach(function (btn) { | |||
btn.addEventListener('click', function (e) { e.stopPropagation(); setRoute(root, btn.getAttribute('data-route')); }); | |||
}); | |||
$all('[data-calc-adjust]', root).forEach(function (btn) { | |||
btn.addEventListener('click', function () { | |||
var st = getCalcState(root); | |||
var delta = Number(btn.getAttribute('data-delta') || '0'); | |||
var next = Math.max(0.5, Math.min(24, st.hours + delta)); | |||
root.setAttribute('data-calc-hours', String(next)); | |||
calc(root); | |||
}); | |||
}); | |||
var display = byId('calc-method-display'); | |||
var menu = byId('calc-method-menu'); | |||
var calcSection = byId('calculator-section'); | |||
if (display && menu) { | |||
display.addEventListener('click', function (e) { | |||
e.stopPropagation(); | |||
var open = menu.style.display === 'block'; | |||
menu.style.display = open ? 'none' : 'block'; | |||
if (calcSection) calcSection.setAttribute('data-method-menu-open', open ? '0' : '1'); | |||
}); | |||
document.addEventListener('click', function () { menu.style.display = 'none'; if (calcSection) calcSection.setAttribute('data-method-menu-open', '0'); }); | |||
} | |||
$all('.calc-method-option', root).forEach(function (opt) { | |||
opt.addEventListener('click', function (e) { | |||
e.stopPropagation(); | |||
root.setAttribute('data-calc-rate', opt.getAttribute('data-rate') || '70'); | |||
root.setAttribute('data-calc-label', opt.getAttribute('data-label') || opt.textContent.trim()); | |||
if (menu) menu.style.display = 'none'; | |||
calc(root); | |||
}); | |||
}); | |||
['boost-no', 'boost-yes'].forEach(function (id) { | |||
var el = byId(id); | |||
if (el) el.addEventListener('click', function () { root.setAttribute('data-calc-booster', el.getAttribute('data-booster') || '0'); calc(root); }); | |||
}); | |||
$all('.loadout-item', root).forEach(function (item) { | |||
item.addEventListener('click', function () { | |||
item.classList.toggle('is-selected'); | |||
var check = $('.li-check', item); | |||
if (check) check.textContent = item.classList.contains('is-selected') ? '✓' : ''; | |||
updateLoadout(root); | |||
}); | |||
}); | |||
var clear = $('.loadout-clear', root); | |||
if (clear) clear.addEventListener('click', function () { | |||
$all('.loadout-item', root).forEach(function (item) { | |||
item.classList.remove('is-selected'); | |||
var check = $('.li-check', item); | |||
if (check) check.textContent = ''; | |||
}); | |||
updateLoadout(root); | |||
}); | |||
setMethod(root, root.getAttribute('data-open-method') || 'grind'); | |||
calc(root); | |||
updateLoadout(root); | |||
} | |||
function init() { | |||
var root = byId('farming-guide-root'); | |||
if (!root || root.getAttribute('data-timero-farming-v6-ready') === '1') return; | |||
root.setAttribute('data-timero-farming-v6-ready', '1'); | |||
injectStyle(); | |||
bind(root); | |||
} | |||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init); | |||
else init(); | |||
if (window.mw && mw.hook) mw.hook('wikipage.content').add(init); | |||
})(); | })(); | ||
Latest revision as of 18:53, 6 June 2026
/* TimeRO MediaWiki:Common.js - MERGED REVISED
Combines Cards + Collection network-safe loader with the existing Common.js apps.
Original header:
TimeRO MediaWiki:Common.js
Fixes Card Database and Beginner Leveling Guide loaders.
ES5-safe: no const, let, arrow functions, template literals or nullish coalescing. */
(function () {
'use strict';
function esc(v){return String(v==null?'':v).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,''');}
function style(id,css){if(document.getElementById(id))return;var s=document.createElement('style');s.id=id;s.appendChild(document.createTextNode(css));document.head.appendChild(s);}
function ajax(url,ok,fail){var x=new XMLHttpRequest();x.open('GET',url,true);x.setRequestHeader('Accept','application/json');x.onreadystatechange=function(){if(x.readyState!==4)return;if(x.status<200||x.status>=300){fail('HTTP '+x.status+': '+x.responseText.substr(0,240));return;}try{ok(JSON.parse(x.responseText));}catch(e){fail('JSON inválido: '+x.responseText.substr(0,240));}};x.onerror=function(){fail('Falha de rede.');};x.send(null);}
function debounce(fn,ms){var t;return function(){var a=arguments,self=this;clearTimeout(t);t=setTimeout(function(){fn.apply(self,a);},ms);};}
function rgba(hex,a){var h=String(hex||'#58d7ff').replace('#',''),n=parseInt(h,16);return 'rgba('+((n>>16)&255)+','+((n>>8)&255)+','+(n&255)+','+a+')';}
function injectSharedCss(){style('timero-apps-fixed-css',
'.tr-app,.tr-app *{box-sizing:border-box}.tr-app{font-family:Segoe UI,system-ui,sans-serif;color:#d8ecff}.tr-shell{background:radial-gradient(circle at 18% 0%,rgba(74,144,217,.10),transparent 34%),radial-gradient(circle at 88% 24%,rgba(92,70,180,.08),transparent 30%),linear-gradient(135deg,rgba(5,10,22,.98),rgba(2,5,14,.99));border:1px solid rgba(80,170,255,.18);border-radius:18px;padding:24px;margin:0 0 34px;box-shadow:0 0 30px rgba(0,0,0,.35),inset 0 0 28px rgba(80,160,255,.025)}'+
'.tr-head{background:linear-gradient(90deg,rgba(74,144,217,.14),rgba(74,144,217,.04),transparent);border:1px solid rgba(74,144,217,.18);border-left:5px solid #4a90d9;border-radius:12px;padding:16px 18px;margin:0 0 18px}.tr-kicker{color:#58d7ff;font-weight:900;letter-spacing:.10em;text-transform:uppercase;font-size:.78rem;margin-bottom:8px}.tr-title{color:#fff;font-size:clamp(1.4rem,2.6vw,2rem);font-weight:900;margin:0 0 6px;line-height:1.1}.tr-sub{color:rgba(180,205,230,.72);font-size:.92rem;line-height:1.65}.tr-btn{border:1px solid rgba(255,255,255,.08);background:rgba(255,255,255,.04);color:rgba(180,205,230,.72);border-radius:999px;padding:8px 13px;cursor:pointer;font-family:inherit;font-weight:800;font-size:.78rem}.tr-btn.active{background:linear-gradient(135deg,rgba(74,144,217,.22),rgba(74,144,217,.08));border-color:rgba(88,215,255,.30);color:#58d7ff}.tr-pill{display:inline-flex;align-items:center;justify-content:center;padding:6px 10px;border-radius:999px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);font-weight:800;font-size:.76rem;white-space:nowrap}'+
'.tc-toolbar{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:16px;margin:0 0 16px}.tc-top{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.tc-search-wrap{flex:1;min-width:260px;position:relative}.tc-search-wrap span{position:absolute;left:13px;top:50%;transform:translateY(-50%);opacity:.55}.tc-search{width:100%;padding:11px 12px 11px 40px;border-radius:11px;background:rgba(0,0,0,.34);border:1px solid rgba(255,255,255,.09);color:#e8eef8;font-size:.92rem;outline:none}.tc-toggle{display:inline-flex;gap:9px;align-items:center;cursor:pointer;padding:10px 14px;border-radius:11px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);font-weight:800}.tc-tabs{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}.tc-table{border:1px solid rgba(255,255,255,.08);border-radius:14px;overflow:hidden;background:rgba(3,6,14,.96)}.tc-head-row,.tc-row{display:grid;grid-template-columns:88px 1.35fr 150px 145px 120px;align-items:center}.tc-head-row{background:rgba(0,0,0,.42);border-bottom:1px solid rgba(255,255,255,.06)}.tc-th{padding:12px 14px;color:#6070a0;font-weight:900;letter-spacing:.08em;text-transform:uppercase;font-size:.68rem;border-right:1px solid rgba(255,255,255,.045);cursor:pointer}.tc-row{border-bottom:1px solid rgba(255,255,255,.045);cursor:pointer}.tc-row:hover{background:rgba(74,144,217,.06)}.tc-cell{padding:13px 14px;border-right:1px solid rgba(255,255,255,.035)}.tc-id{font-family:Courier New,monospace;color:#f0c840;font-weight:900}.tc-name{display:flex;align-items:center;gap:12px}.tc-icon{width:42px;height:42px;border-radius:10px;background:rgba(0,0,0,.28);border:1px solid rgba(255,255,255,.08);display:flex;align-items:center;justify-content:center;overflow:hidden;flex:0 0 42px}.tc-icon img{max-width:36px;max-height:36px}.tc-card-title{color:#58d7ff;font-weight:900}.tc-small{color:rgba(180,205,230,.58);font-size:.76rem;margin-top:3px}.tc-status{display:inline-flex;padding:6px 10px;border-radius:999px;font-size:.72rem;font-weight:900}.tc-changed{background:rgba(112,216,144,.10);border:1px solid rgba(112,216,144,.24);color:#70d890}.tc-original{background:rgba(255,255,255,.035);border:1px solid rgba(255,255,255,.08);color:rgba(180,205,230,.55)}.tc-detail{display:none;background:rgba(0,0,0,.18);border-bottom:1px solid rgba(255,255,255,.055)}.tc-detail.open{display:block}.tc-detail-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;padding:16px}.tc-box{border-radius:12px;padding:14px;background:linear-gradient(135deg,rgba(8,14,26,.96),rgba(4,8,18,.99));border:1px solid rgba(255,255,255,.08);min-height:112px}.tc-box h4{color:#6070a0;font-weight:900;letter-spacing:.08em;text-transform:uppercase;font-size:.68rem;margin:0 0 8px}.tc-box div{color:rgba(220,235,255,.78);font-size:.84rem;line-height:1.65;white-space:pre-wrap}.tc-msg{padding:34px;text-align:center;color:rgba(180,205,230,.58);font-weight:700}.tc-error{color:#ff8a8a}.tc-groups{margin-top:26px}.tc-group{border-radius:14px;border:1px solid rgba(255,255,255,.08);background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));overflow:hidden;margin-bottom:10px}.tc-group-main{padding:15px 18px;display:grid;grid-template-columns:auto 1fr auto;gap:13px;align-items:center}.tc-group-icon{width:42px;height:42px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:1.25rem}.tc-group-key{font-size:.64rem;font-weight:900;letter-spacing:.11em;text-transform:uppercase;margin-bottom:2px}.tc-group-name{color:#fff;font-weight:900}.tc-group-bonus{padding:11px 18px;border-top:1px solid rgba(255,255,255,.055);color:rgba(220,235,255,.74);line-height:1.55;font-size:.84rem}'+
'.tl-root{margin:-1em -1.5em;min-height:100vh;background:radial-gradient(circle at 18% 0%,rgba(88,215,255,.09),transparent 34%),radial-gradient(circle at 88% 24%,rgba(176,108,255,.08),transparent 30%),linear-gradient(135deg,#050914,#02050e);overflow:hidden}.tl-inner{max-width:1280px;margin:0 auto;padding:44px 28px 60px}.tl-hero{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid rgba(88,215,255,.18);border-radius:18px;padding:34px;margin-bottom:18px}.tl-hero h1{font-size:clamp(2.2rem,5vw,4rem);line-height:.96;font-weight:900;color:#fff;letter-spacing:-.035em;margin:0 0 16px}.tl-hero h1 span{background:linear-gradient(90deg,#00ff88,#58d7ff,#f9a826);-webkit-background-clip:text;background-clip:text;color:transparent}.tl-stats,.tl-grid,.tl-checks,.tl-related{display:grid;gap:12px}.tl-stats{grid-template-columns:repeat(5,1fr);margin:18px 0}.tl-stat{background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:14px;text-align:center}.tl-stat strong{display:block;font-size:1.35rem;color:#58d7ff;font-weight:900}.tl-stat span{font-size:.72rem;color:rgba(122,144,176,.72);letter-spacing:.12em;text-transform:uppercase;font-weight:800}.tl-panel{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid rgba(255,255,255,.08);border-radius:18px;padding:16px;margin-bottom:18px}.tl-label{color:#7a90b0;font-weight:900;letter-spacing:.11em;text-transform:uppercase;font-size:.72rem;margin-bottom:10px}.tl-flex{display:flex;gap:9px;flex-wrap:wrap}.tl-track{height:12px;border-radius:999px;background:rgba(255,255,255,.05);overflow:hidden;display:grid;grid-template-columns:24.5fr 24.5fr 20fr 15fr 16fr;margin-bottom:14px}.tl-track span:nth-child(1){background:#00ff88}.tl-track span:nth-child(2){background:#00d4ff}.tl-track span:nth-child(3){background:#f9a826}.tl-track span:nth-child(4){background:#b06cff}.tl-track span:nth-child(5){background:#ff3d5a}.tl-phase{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid var(--line);border-radius:18px;padding:24px;margin-bottom:22px}.tl-head{display:flex;gap:18px;margin-bottom:22px}.tl-icon{width:64px;height:64px;border-radius:18px;display:flex;align-items:center;justify-content:center;flex:0 0 64px;font-size:1.8rem;background:var(--soft);border:1px solid var(--line)}.tl-chip{display:inline-flex;margin:0 8px 8px 0;padding:3px 10px;border-radius:999px;background:var(--soft);border:1px solid var(--line);color:var(--color);font-size:.65rem;letter-spacing:.13em;text-transform:uppercase;font-weight:900}.tl-phase h2{color:#fff;margin:0 0 8px;font-size:clamp(1.35rem,2.5vw,2rem);border:0}.tl-phase p{color:rgba(176,192,224,.75);line-height:1.7;margin:0}.tl-grid{grid-template-columns:1fr 1fr;margin-bottom:18px}.tl-box{border-radius:16px;overflow:hidden;background:rgba(0,0,0,.24);border:1px solid var(--line)}.tl-box-head{padding:13px 16px;background:var(--soft);border-bottom:1px solid var(--line);color:var(--color);font-weight:900;letter-spacing:.08em;text-transform:uppercase;font-size:.78rem}.tl-box-body{padding:15px;display:flex;flex-direction:column;gap:10px}.tl-card{border-radius:12px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);padding:12px 14px}.tl-map{display:flex;justify-content:space-between;gap:14px}.tl-name{color:#fff;font-size:.95rem;font-weight:900}.tl-muted{color:rgba(122,144,176,.72);font-size:.76rem;margin-top:3px}.tl-level{color:var(--color);font-size:.78rem;font-weight:900;white-space:nowrap;text-align:right}.tl-mob{cursor:pointer}.tl-mob-main{display:flex;align-items:center;gap:12px}.tl-mob-icon{width:42px;height:42px;border-radius:10px;display:flex;align-items:center;justify-content:center;background:var(--soft);border:1px solid var(--line);font-size:1.2rem}.tl-mob-info{flex:1}.tl-detail{display:none;padding:10px 0 0 54px;color:rgba(180,205,230,.78);font-size:.82rem;line-height:1.6}.tl-mob.open .tl-detail{display:block}.tl-checks{grid-template-columns:1fr 1fr}.tl-check{display:flex;align-items:center;gap:10px;cursor:pointer}.tl-mark{width:18px;height:18px;border-radius:5px;border:1px solid var(--line);background:var(--soft);display:flex;align-items:center;justify-content:center;color:var(--color);font-weight:900}.tl-check.checked .tl-text{text-decoration:line-through;opacity:.55}.tl-note{display:none;margin-top:14px;border-radius:12px;padding:14px 16px;color:rgba(220,235,255,.78);line-height:1.65;font-size:.88rem}.tl-note strong{display:block;margin-bottom:5px;letter-spacing:.09em;text-transform:uppercase;font-size:.75rem}.tl-footer{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-top:20px}.tl-related{grid-template-columns:repeat(4,1fr);margin-top:24px}.tl-related .tl-panel{text-align:center;margin:0}@media(max-width:980px){.tl-stats,.tl-grid,.tl-checks,.tl-related{grid-template-columns:1fr}.tl-inner{padding:26px 14px 44px}.tl-hero,.tl-phase{padding:20px}.tl-head{flex-direction:column}.tl-map{flex-direction:column}.tl-level{text-align:left}}');}
/* Card app - merged Cards + Collection renderer */
function initCards(){
var root=document.getElementById('timero-card-db-app');
if(!root||root.getAttribute('data-ready')==='1'||root.getAttribute('data-timero-mounted')==='1')return;
root.setAttribute('data-ready','1');
root.setAttribute('data-timero-mounted','1');
injectSharedCss();
var state={
api:root.getAttribute('data-api')||'https://timero.com.br/pt/api/wiki_cards.php',
q:'',
cat:'all',
slot:'',
group:'',
changed:false,
sort:'card_name',
dir:'asc',
cards:[],
groups:[],
filters:{slots:[],categories:[]},
total:0,
err:'',
errDetails:'',
load:false
};
var cats=[
['all','Todas','◆','#7c6aff'],
['weapon','Armas','⚔️','#ff6b7a'],
['armor','Armaduras','🛡','#00d4ff'],
['accessory','Acessórios','💎','#f9a826'],
['headgear','Headgear','🎩','#b06cff'],
['shield','Escudos','🛡️','#70b8ff'],
['garment','Capas','🧥','#60d090'],
['shoes','Sapatos','👢','#f0c840']
];
function categoryValue(card){return String(card.category||card.card_category||card.type||'').toLowerCase();}
function slotValue(card){return String(card.slot||card.slot_type||card.equip_slot||'');}
function groupName(card){return card.group_name||card.collection_group_name||card.groupName||'';}
function groupIcon(card){return card.group_icon||card.collection_group_icon||'📚';}
function groupColor(card){return card.group_color||card.collection_group_color||'#b06cff';}
function oldEffect(card){return card.old_effect||card.original_effect||card.vanilla_effect||'—';}
function newEffect(card){return card.new_effect||card.reworked_effect||card.effect_new||card.effect||'—';}
function collectionEffect(card){return card.collection_effect||card.group_effect||card.effect||'';}
function collectionScript(card){return card.bonus_script||card.collection_script||card.script||'';}
function collectionPoints(card){return card.collection_points||card.points||0;}
function cardChanged(card){return String(card.changed)==='1'||String(oldEffect(card))!==String(newEffect(card));}
function meta(id){
id=String(id||'all').toLowerCase();
for(var i=0;i<cats.length;i++)if(cats[i][0]===id)return cats[i];
return cats[0];
}
function readScript(s){
return String(s||'')
.replace(/bonus\s+/gi,'')
.replace(/;/g,'; ')
.replace(/bAllStats/gi,'All Stats')
.replace(/bMaxHP/gi,'Max HP')
.replace(/bMaxSP/gi,'Max SP')
.replace(/bBaseAtk/gi,'ATK')
.replace(/bMatk/gi,'MATK')
.replace(/bStr/gi,'STR')
.replace(/bAgi/gi,'AGI')
.replace(/bVit/gi,'VIT')
.replace(/bInt/gi,'INT')
.replace(/bDex/gi,'DEX')
.replace(/bLuk/gi,'LUK')||'—';
}
function buildUrl(){
var url=state.api;
var join=url.indexOf('?')===-1?'?':'&';
var params=[];
params.push('q='+encodeURIComponent(state.q));
if(state.cat&&state.cat!=='all')params.push('category='+encodeURIComponent(state.cat));
if(state.slot)params.push('slot='+encodeURIComponent(state.slot));
if(state.group)params.push('group='+encodeURIComponent(state.group));
params.push('changed='+(state.changed?'1':'0'));
params.push('sort='+encodeURIComponent(state.sort));
params.push('dir='+encodeURIComponent(state.dir));
params.push('limit=250');
params.push('_='+String(new Date().getTime()));
return url+join+params.join('&');
}
function shell(){
root.className+=' tr-app';
root.innerHTML=
'<div class="tr-shell">'+
'<div class="tr-head">'+
'<div class="tr-kicker">◇ Banco de Dados</div>'+
'<h2 class="tr-title">Cartas Balanceadas + Coleção</h2>'+
'<div class="tr-sub">Pesquise por nome da carta, ID, monstro, slot, efeito antigo, efeito novo, bônus de coleção ou script de coleção. Este loader une a lógica antiga do Common.js com o endpoint novo <strong>wiki_cards.php</strong>.</div>'+
'</div>'+
'<div class="tc-toolbar">'+
'<div class="tc-top">'+
'<div class="tc-search-wrap"><span>🔍</span><input id="tc-search" class="tc-search" placeholder="Buscar carta, ID, monstro, efeito ou coleção..."></div>'+
'<label class="tc-toggle"><input id="tc-changed" type="checkbox"> ⚡ Apenas alteradas</label>'+
'<div id="tc-count" class="tr-pill">— cartas</div>'+
'</div>'+
'<div id="tc-tabs" class="tc-tabs"></div>'+
'<div id="tc-extra-filters" class="tc-tabs"></div>'+
'</div>'+
'<div class="tc-table">'+
'<div class="tc-head-row">'+
'<div class="tc-th" data-sort="id">ID ↕</div>'+
'<div class="tc-th" data-sort="name">Carta / Monstro ↕</div>'+
'<div class="tc-th" data-sort="slot">Slot ↕</div>'+
'<div class="tc-th" data-sort="category">Grupo ↕</div>'+
'<div class="tc-th">Status</div>'+
'</div>'+
'<div id="tc-body"><div class="tc-msg">Carregando cartas...</div></div>'+
'</div>'+
'<div class="tc-groups">'+
'<div class="tr-head" style="margin-top:26px">'+
'<div class="tr-kicker">◇ Grupos de Coleção</div>'+
'<h2 class="tr-title" style="font-size:1.35rem">Bônus permanentes por grupo</h2>'+
'<div class="tr-sub">Dados carregados da tabela <strong>wiki_card_groups</strong> e enriquecidos por <strong>collection_card_meta</strong> quando disponível.</div>'+
'</div>'+
'<div id="tc-groups"></div>'+
'</div>'+
'</div>';
}
function bindStatic(){
var search=root.querySelector('#tc-search');
var changed=root.querySelector('#tc-changed');
var heads=root.querySelectorAll('.tc-th[data-sort]');
var debounced=debounce(function(){state.q=search.value;fetchCards();},220);
search.oninput=debounced;
changed.onchange=function(){state.changed=this.checked;fetchCards();};
for(var i=0;i<heads.length;i++){
heads[i].onclick=function(){
var s=this.getAttribute('data-sort');
if(state.sort===s)state.dir=state.dir==='asc'?'desc':'asc';
else{state.sort=s;state.dir='asc';}
fetchCards();
};
}
}
function renderTabs(){
var tabs=root.querySelector('#tc-tabs');
if(!tabs)return;
tabs.innerHTML='';
for(var i=0;i<cats.length;i++){
(function(c){
var b=document.createElement('button');
b.className='tr-btn'+(c[0]===state.cat?' active':'');
b.innerHTML=esc(c[2])+' '+esc(c[1]);
b.onclick=function(){state.cat=c[0];fetchCards();};
tabs.appendChild(b);
})(cats[i]);
}
}
function renderExtraFilters(){
var wrap=root.querySelector('#tc-extra-filters');
if(!wrap)return;
var slotValues=(state.filters&&state.filters.slots)||[];
var groupValues=state.groups||[];
var html='';
html+='<select id="tc-slot-filter" class="tr-btn" style="background:#050914;border-radius:999px;max-width:220px"><option value="">Todos os slots</option>';
for(var i=0;i<slotValues.length;i++){
html+='<option value="'+esc(slotValues[i])+'"'+(state.slot===slotValues[i]?' selected':'')+'>'+esc(slotValues[i])+'</option>';
}
html+='</select>';
html+='<select id="tc-group-filter" class="tr-btn" style="background:#050914;border-radius:999px;max-width:260px"><option value="">Todos os grupos</option>';
for(i=0;i<groupValues.length;i++){
var g=groupValues[i];
var gid=g.id||g.group_id||g.group_key||g.name||g.group_name||'';
var gname=g.name||g.group_name||g.group_key||('Grupo '+gid);
html+='<option value="'+esc(gid)+'"'+(String(state.group)===String(gid)?' selected':'')+'>'+esc(g.icon||'📚')+' '+esc(gname)+'</option>';
}
html+='</select>';
html+='<button id="tc-clear-filters" class="tr-btn">Limpar filtros</button>';
wrap.innerHTML=html;
var slot=root.querySelector('#tc-slot-filter');
var group=root.querySelector('#tc-group-filter');
var clear=root.querySelector('#tc-clear-filters');
if(slot)slot.onchange=function(){state.slot=this.value;fetchCards();};
if(group)group.onchange=function(){state.group=this.value;fetchCards();};
if(clear)clear.onclick=function(){
state.q='';
state.cat='all';
state.slot='';
state.group='';
state.changed=false;
var search=root.querySelector('#tc-search');
var changed=root.querySelector('#tc-changed');
if(search)search.value='';
if(changed)changed.checked=false;
fetchCards();
};
}
function renderError(){
var body=root.querySelector('#tc-body');
var count=root.querySelector('#tc-count');
if(count)count.innerHTML='Erro';
if(!body)return;
body.innerHTML=
'<div class="tc-msg tc-error" style="text-align:left">'+
'<div style="font-weight:900;letter-spacing:.08em;text-transform:uppercase;color:#ff7070;margin-bottom:8px">Erro na rede</div>'+
'<div style="line-height:1.65;margin-bottom:12px;color:#ffb8b8">A wiki não conseguiu carregar <strong>Cards + Collection</strong> pelo endpoint JSON.</div>'+
'<div style="background:rgba(0,0,0,.32);border:1px solid rgba(255,255,255,.08);border-radius:10px;padding:12px;font-family:Consolas,monospace;font-size:12px;white-space:pre-wrap;color:#ffd0d0">'+esc(state.err||'Erro desconhecido')+'</div>'+
(state.errDetails?'<div style="margin-top:10px;background:rgba(0,0,0,.22);border:1px solid rgba(255,255,255,.06);border-radius:10px;padding:12px;font-family:Consolas,monospace;font-size:12px;white-space:pre-wrap;color:#d8ecff">'+esc(state.errDetails)+'</div>':'')+
'<div style="margin-top:14px;color:rgba(255,210,210,.78);line-height:1.6;font-size:.9em">Verifique se <code>/pt/api/wiki_cards.php</code> existe, se o PHP retorna JSON válido e se o header CORS permite <code>wiki.timero.com.br</code>.</div>'+
'</div>';
}
function cardIcon(id){
id=Number(id)||0;
return '<div class="tc-icon"><img src="https://timero.com.br/images/item/icons/'+esc(id)+'.png" onerror="this.onerror=null;this.src=\'https://timero.com.br/images/item/'+esc(id)+'.png\';this.onerror=function(){this.parentNode.innerHTML=\\\'🃏\\\';};"></div>';
}
function itemAnchor(id,name){
id=Number(id)||0;
return '<a href="https://timero.com.br/pt/item?id='+id+'" target="_blank" rel="noopener" style="color:#58d7ff;text-decoration:none;font-weight:900">'+esc(name||('Carta #'+id))+'</a>';
}
function monsterAnchor(id,name){
id=Number(id)||0;
if(!id)return esc(name||'—');
return '<a href="https://timero.com.br/pt/monster?id='+id+'" target="_blank" rel="noopener" style="color:#c0a0ff;text-decoration:none;font-weight:800">'+esc(name||('Monstro #'+id))+'</a>';
}
function renderCards(){
var body=root.querySelector('#tc-body');
var count=root.querySelector('#tc-count');
var cards=state.cards||[];
if(count)count.innerHTML=(state.total||cards.length)+' carta'+((state.total||cards.length)===1?'':'s');
if(state.load){
body.innerHTML='<div class="tc-msg">Carregando cartas...</div>';
return;
}
if(state.err){
renderError();
return;
}
if(!cards.length){
body.innerHTML='<div class="tc-msg">Nenhuma carta encontrada.</div>';
renderGroups();
return;
}
body.innerHTML='';
for(var i=0;i<cards.length;i++){
(function(card){
var id=card.item_id||card.card_id||card.id;
var cname=card.card_name||card.name||('Carta #'+id);
var m=meta(categoryValue(card));
var changed=cardChanged(card);
var row=document.createElement('div');
var det=document.createElement('div');
var gname=groupName(card);
var gicon=groupIcon(card);
var gcolor=groupColor(card);
row.className='tc-row';
row.innerHTML=
'<div class="tc-cell tc-id">#'+esc(id)+'</div>'+
'<div class="tc-cell"><div class="tc-name">'+cardIcon(id)+'<div><div class="tc-card-title">'+itemAnchor(id,cname)+'</div>'+(card.monster_name?'<div class="tc-small">'+monsterAnchor(card.monster_id,card.monster_name)+'</div>':'')+'</div></div></div>'+
'<div class="tc-cell"><span class="tr-pill">'+esc(slotValue(card)||'Unknown')+'</span></div>'+
'<div class="tc-cell"><span class="tr-pill" style="color:'+esc(gcolor||m[3])+';border-color:'+esc(gcolor||m[3])+'44">'+esc(gicon||m[2])+' '+esc(gname||categoryValue(card)||'—')+'</span></div>'+
'<div class="tc-cell">'+(changed?'<span class="tc-status tc-changed">Alterada</span>':'<span class="tc-status tc-original">Original</span>')+'</div>';
det.className='tc-detail';
det.innerHTML=
'<div class="tc-detail-grid">'+
'<div class="tc-box"><h4>Efeito Antigo</h4><div>'+esc(oldEffect(card)||'—')+'</div></div>'+
'<div class="tc-box"><h4>Efeito TimeRO</h4><div>'+esc(newEffect(card)||'—')+'</div></div>'+
'<div class="tc-box"><h4>Coleção</h4><div>'+
'<b style="color:#f0c840">Grupo:</b> '+esc(gname||'—')+'<br>'+
'<b style="color:#f0c840">Pontos:</b> '+esc(collectionPoints(card)||0)+'<br>'+
'<b style="color:#f0c840">Efeito:</b> '+esc(collectionEffect(card)||'—')+'<br>'+
'<b style="color:#f0c840">Script:</b> '+esc(readScript(collectionScript(card)))+
'</div></div>'+
'</div>';
row.onclick=function(){
var open=det.className.indexOf('open')>-1;
var ds=body.querySelectorAll('.tc-detail.open');
var rs=body.querySelectorAll('.tc-row.open');
for(var a=0;a<ds.length;a++)ds[a].className='tc-detail';
for(var r=0;r<rs.length;r++)rs[r].className='tc-row';
if(!open){det.className='tc-detail open';row.className='tc-row open';}
};
body.appendChild(row);
body.appendChild(det);
})(cards[i]);
}
renderGroups();
}
function renderGroups(){
var gw=root.querySelector('#tc-groups');
if(!gw)return;
var groups=state.groups||[];
gw.innerHTML='';
if(!groups.length){
gw.innerHTML='<div class="tc-msg">Nenhum grupo de coleção cadastrado.</div>';
return;
}
for(var i=0;i<groups.length;i++){
var g=groups[i];
var c=g.color||'#7c6aff';
var key=g.group_key||g.key||g.id||g.group_id||'—';
var name=g.name||g.group_name||g.title||('Grupo '+key);
var cardCount=g.card_count||g.cards||0;
var min=g.min_cards||g.required_count||g.minimum_count||1;
var effect=g.collection_effect||g.effect||g.bonus||'—';
var el=document.createElement('div');
el.className='tc-group';
el.style.borderColor=c+'33';
el.innerHTML=
'<div class="tc-group-main">'+
'<div class="tc-group-icon" style="background:'+c+'14;border:1px solid '+c+'44">'+esc(g.icon||'🃏')+'</div>'+
'<div><div class="tc-group-key" style="color:'+c+'">Grupo · '+esc(key)+'</div><div class="tc-group-name">'+esc(name)+'</div></div>'+
'<div class="tr-pill" style="color:'+c+';border-color:'+c+'33">'+esc(cardCount)+' cartas · Min '+esc(min)+'</div>'+
'</div>'+
'<div class="tc-group-bonus"><b style="color:'+c+'">Bônus:</b> '+esc(effect)+'</div>';
gw.appendChild(el);
}
}
function normalizeData(d){
d=d||{};
state.cards=d.cards||[];
state.groups=d.groups||[];
state.filters=d.filters||{slots:[],categories:[]};
state.total=d.total||state.cards.length;
// API-side filtering is preferred. This client-side pass preserves old Common.js logic
// when the endpoint ignores changed/category/slot/group parameters.
var q=String(state.q||'').toLowerCase();
var cat=String(state.cat||'all').toLowerCase();
var slot=String(state.slot||'');
var group=String(state.group||'');
state.cards=state.cards.filter(function(card){
if(cat!=='all'&&categoryValue(card)!==cat)return false;
if(slot&&slotValue(card)!==slot)return false;
if(group){
var gid=String(card.group_id||card.collection_group_id||'');
var gname=String(groupName(card)||'');
if(gid!==group&&gname!==group)return false;
}
if(state.changed&&!cardChanged(card))return false;
if(q){
var blob=[
card.item_id,card.card_id,card.id,card.card_name,card.name,card.monster_name,
slotValue(card),categoryValue(card),groupName(card),oldEffect(card),newEffect(card),
collectionEffect(card),collectionScript(card)
].join(' ').toLowerCase();
if(blob.indexOf(q)<0)return false;
}
return true;
});
state.total=state.cards.length;
}
function fetchCards(){
state.load=true;
state.err='';
state.errDetails='';
renderTabs();
renderCards();
var url=buildUrl();
ajax(url,function(d){
state.load=false;
if(!d||!d.ok){
state.err=(d&&d.error)||'Erro desconhecido';
state.errDetails='URL usada:\n'+url;
state.cards=[];
state.groups=[];
}else{
normalizeData(d);
}
renderTabs();
renderExtraFilters();
renderCards();
},function(e){
state.load=false;
state.err=e;
state.errDetails='URL usada:\n'+url;
state.cards=[];
state.groups=[];
renderTabs();
renderExtraFilters();
renderCards();
});
}
shell();
bindStatic();
renderTabs();
renderExtraFilters();
fetchCards();
}
/* Leveling app */
function initLeveling(){var root=document.getElementById('timero-leveling-guide-app');if(!root||root.getAttribute('data-ready')==='1')return;root.setAttribute('data-ready','1');injectSharedCss();var cls=[['all','Todas','◆','#58d7ff'],['swordsman','Espadachim','⚔️','#ff6b7a'],['mage','Mago','🔮','#b06cff'],['archer','Arqueiro','🏹','#00ff88'],['acolyte','Acolyte','✨','#f9a826'],['thief','Ladrão','🗡️','#7a90b0']],notes={swordsman:['⚔️','Dica: Espadachim','Priorize sobrevivência e dano consistente.'],mage:['🔮','Dica: Mago','Controle distância, elemento e consumo de SP.'],archer:['🏹','Dica: Arqueiro','Use vantagem de alcance e kite.'],acolyte:['✨','Dica: Acolyte','Heal contra Undead pode ser muito eficiente.'],thief:['🗡️','Dica: Ladrão','AGI e evasão tornam a progressão mais segura.']},ph=[['phase-1','FASE 1','Nível 1 → 25','~XX–YY minutos','🌿','#00ff88','Primeiros Passos — Poring Island & Prontera Field'],['phase-2','FASE 2','Nível 25 → 50','~XX–YY horas','⚡','#00d4ff','Construindo Momentum — Mapas Intermediários'],['phase-3','FASE 3','Nível 50 → 70','~XX–YY horas','🔥','#f9a826','Mid-Game Eficiente — Zonas de Farming'],['phase-4','FASE 4','Nível 70 → 85','~XX–YY horas','⚔️','#b06cff','Pré-Endgame — Transições e Dungeons'],['phase-5','FASE FINAL','Nível 85 → 99','~XX–YY horas','🏁','#ff3d5a','Reta Final — Caminho ao 99']];function phase(p,i){var c=p[5],maps='',mobs='',checks='',j;for(j=0;j<(i<2?3:2);j++)maps+='<div class="tl-card tl-map"><div><div class="tl-name">Mapa Fase '+(i+1)+' · '+(j+1)+'</div><div class="tl-muted">mapa_code</div></div><div><div class="tl-level">Nv. '+(i*20+1)+'–'+(i*20+20)+'</div><div class="tl-muted">Rota recomendada</div></div></div>';for(j=0;j<(i===0?2:1);j++)mobs+='<div class="tl-card tl-mob"><div class="tl-mob-main"><div class="tl-mob-icon">'+p[4]+'</div><div class="tl-mob-info"><div class="tl-name">Monstro Fase '+(i+1)+' · '+String.fromCharCode(65+j)+'</div><div class="tl-muted">Substitua pelo monstro real</div></div><div class="tl-level">EXP: ???</div><div>▼</div></div><div class="tl-detail">HP: ??? · Drops: Item 1, Item 2<br><span style="color:'+c+'">Dica:</span> Adicione dicas de combate aqui.</div></div>';var list=['Confirmar rota de leveling','Comprar consumíveis necessários','Atualizar equipamentos principais','Avançar para a próxima fase'];for(j=0;j<list.length;j++)checks+='<div class="tl-card tl-check"><div class="tl-mark"></div><div class="tl-text">'+list[j]+'</div></div>';return '<section id="'+p[0]+'" class="tl-phase" style="--color:'+c+';--soft:'+rgba(c,.08)+';--line:'+rgba(c,.22)+'"><div class="tl-head"><div class="tl-icon">'+p[4]+'</div><div><span class="tl-chip">'+p[1]+'</span><span class="tl-chip">'+p[2]+'</span><span class="tl-chip">⏱ '+p[3]+'</span><h2>'+p[6]+'</h2><p>Substitua com a descrição real da fase, mapas ideais, monstros principais, consumíveis e momento correto de troca de classe.</p></div></div><div class="tl-grid"><div class="tl-box"><div class="tl-box-head">🗺️ Mapas Recomendados</div><div class="tl-box-body">'+maps+'</div></div><div class="tl-box"><div class="tl-box-head">🐉 Monstros-Alvo</div><div class="tl-box-body">'+mobs+'</div></div></div><div class="tl-box"><div class="tl-box-head">✅ Checklist da '+p[1]+'</div><div class="tl-box-body"><div class="tl-checks">'+checks+'</div></div></div><div class="tl-note"></div><div class="tl-footer">'+(i>0?'<button class="tr-btn" data-scroll="'+ph[i-1][0]+'">← '+ph[i-1][1]+'</button>':'<span></span>')+(i<ph.length-1?'<button class="tr-btn active" data-scroll="'+ph[i+1][0]+'">Próxima Fase: '+ph[i+1][2]+' →</button>':'<button class="tr-btn active" data-scroll="timero-leveling-guide-app">Voltar ao topo ↑</button>')+'</div></section>';}
root.className+=' tr-app';var filters='',nav='',blocks='',i;for(i=0;i<cls.length;i++)filters+='<button class="tr-btn'+(i===0?' active':'')+'" data-class="'+cls[i][0]+'">'+cls[i][2]+' '+cls[i][1]+'</button>';for(i=0;i<ph.length;i++){nav+='<button class="tr-btn'+(i===0?' active':'')+'" data-scroll="'+ph[i][0]+'">'+ph[i][1]+' · '+ph[i][2]+'</button>';blocks+=phase(ph[i],i);}root.innerHTML='<div class="tl-root"><div class="tl-inner"><header class="tl-hero"><div class="tr-kicker">// Guia de Progressão</div><h1>Guia de Leveling<br><span>para Iniciantes</span></h1><p class="tr-sub">Do nível 1 ao 99 — rotas otimizadas, mapas ideais por fase, dicas de consumíveis e estratégias para cada etapa da progressão no TimeRO.</p></header><div class="tl-stats"><div class="tl-stat"><strong>5</strong><span>Fases</span></div><div class="tl-stat"><strong>10+</strong><span>Mapas</span></div><div class="tl-stat"><strong>98</strong><span>Níveis</span></div><div class="tl-stat"><strong>Solo</strong><span>Estilo</span></div><div class="tl-stat"><strong>Pre-R</strong><span>Modalidade</span></div></div><div class="tl-panel"><div class="tl-label">Filtrar por classe</div><div class="tl-flex">'+filters+'</div></div><div class="tl-panel"><div class="tl-label">Progressão de Níveis</div><div class="tl-track"><span></span><span></span><span></span><span></span><span></span></div><div class="tl-flex">'+nav+'</div></div>'+blocks+'<div class="tl-related"><div class="tl-panel">🧰<b>Random Options</b></div><div class="tl-panel">🏰<b>Instances</b></div><div class="tl-panel">🔥<b>Fever System</b></div><div class="tl-panel">⏱️<b>MVP Timer</b></div></div></div></div>';var sc=root.querySelectorAll('[data-scroll]');for(i=0;i<sc.length;i++)sc[i].onclick=function(){var t=document.getElementById(this.getAttribute('data-scroll'));if(t)t.scrollIntoView({behavior:'smooth',block:'start'});};var mb=root.querySelectorAll('.tl-mob');for(i=0;i<mb.length;i++)mb[i].onclick=function(){this.className=this.className.indexOf('open')<0?this.className+' open':this.className.replace(' open','');};var ch=root.querySelectorAll('.tl-check');for(i=0;i<ch.length;i++)ch[i].onclick=function(){var on=this.className.indexOf('checked')<0,m=this.querySelector('.tl-mark');this.className=on?this.className+' checked':this.className.replace(' checked','');if(m)m.innerHTML=on?'✓':'';};var cb=root.querySelectorAll('[data-class]');for(i=0;i<cb.length;i++)cb[i].onclick=function(){var v=this.getAttribute('data-class'),j;for(j=0;j<cb.length;j++){cb[j].className='tr-btn'+(cb[j]===this?' active':'');cb[j].style.opacity=(v!=='all'&&cb[j]!==this)?.45:1;}var nt=root.querySelectorAll('.tl-note');for(j=0;j<nt.length;j++){if(v==='all'||!notes[v]){nt[j].style.display='none';nt[j].innerHTML='';}else{var n=notes[v],color='#58d7ff';for(var k=0;k<cls.length;k++)if(cls[k][0]===v)color=cls[k][3];nt[j].style.display='block';nt[j].style.border='1px solid '+rgba(color,.24);nt[j].style.background=rgba(color,.07);nt[j].innerHTML='<strong style="color:'+color+'">'+n[0]+' '+n[1]+'</strong>'+esc(n[2]);}}};}
function boot(){initCards();initLeveling();}
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot);else boot();
if(window.mw&&mw.hook)mw.hook('wikipage.content').add(boot);
})();
/* =========================================================
TIMERO WIKI ZENY FARMING GUIDE
Safe renderer: fixes raw <input>/<button>/<script> text on MediaWiki.
Mount points supported:
- #timero-zeny-guide-app
- #farming-guide-root (legacy page root)
========================================================= */
(function(){
'use strict';
function esc(v){return String(v==null?'':v).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,''');}
function byId(id){return document.getElementById(id);}
function money(n){n=Number(n)||0;if(n>=1000000)return (n/1000000).toFixed(2)+'M z';if(n>=1000)return (n/1000).toFixed(1)+'k z';return Math.round(n)+' z';}
function addStyle(id,css){if(byId(id))return;var s=document.createElement('style');s.id=id;s.appendChild(document.createTextNode(css));document.head.appendChild(s);}
var methods=[
{id:'grind',icon:'⚔️',name:'Grind Ativo',color:'#f9a826',desc:'Matar monstros, coletar drops e vender no mercado. É o método mais direto e consistente para jogadores em progressão.',pros:['Lucro imediato','Ganha EXP junto','Começa com pouco capital'],cons:['Requer atenção ativa','Consome poções','Varia conforme drops']},
{id:'market',icon:'🏪',name:'Mercado',color:'#00d4ff',desc:'Comprar itens subvalorizados e revender com margem. Depende de leitura de preço, timing e paciência.',pros:['Escala com capital','Pode ser semi-passivo','Lucro alto em oportunidades'],cons:['Precisa conhecer preços','Risco de encalhe','Requer capital inicial']},
{id:'passive',icon:'💤',name:'Renda Passiva',color:'#b06cff',desc:'Lojas, produção, itens de quest e rotinas repetíveis. Ideal para complementar o grind sem precisar lutar o tempo todo.',pros:['Combina com alt chars','Baixo estresse','Bom para rotina diária'],cons:['Lucro mais lento','Depende da demanda','Exige organização']}
];
var routes=[
{id:'payon',method:'grind',name:'Payon Cave',range:'Lv. 25–45',profit:'Baixo → Médio',risk:'Baixo',items:'Drops simples, cartas iniciais, consumíveis',note:'Rota segura para começar a juntar Zeny enquanto evolui.'},
{id:'orc',method:'grind',name:'Orc Dungeon / Orc Field',range:'Lv. 45–70',profit:'Médio',risk:'Médio',items:'Oridecon, Elunium, itens de NPC, cartas úteis',note:'Bom equilíbrio entre EXP, mob density e venda para NPC/market.'},
{id:'geffenia',method:'grind',name:'Geffênia',range:'Lv. 80+',profit:'Alto',risk:'Alto',items:'Equipamentos, cartas, drops valiosos e loot de alta procura',note:'Uma das rotas clássicas de farming quando o personagem já tem gear.'},
{id:'magma',method:'grind',name:'Magma Dungeon',range:'Lv. 85+',profit:'Alto',risk:'Médio-Alto',items:'Itens de NPC, drops em volume, materiais',note:'Boa para classes com dano em área e sustain.'},
{id:'buy-low',method:'market',name:'Compra Subvalorizada',range:'Qualquer',profit:'Variável',risk:'Médio',items:'Cartas, minérios, consumíveis, itens de quest',note:'Procure vendedores com preço abaixo da média e revenda com margem.'},
{id:'quest-items',method:'market',name:'Itens de Quest',range:'Qualquer',profit:'Médio-Alto',risk:'Baixo-Médio',items:'Materiais de quests, crafting e equipamentos',note:'Alta demanda quando novos jogadores começam progressão.'},
{id:'vendor',method:'passive',name:'Loja de Revenda',range:'Qualquer',profit:'Médio',risk:'Baixo',items:'Consumíveis, flechas, materiais, itens populares',note:'Mantenha loja aberta em pontos de alto tráfego.'},
{id:'production',method:'passive',name:'Produção e Rotina',range:'Qualquer',profit:'Médio',risk:'Baixo',items:'Itens craftados, materiais convertidos, pacotes',note:'Ideal para jogadores que gostam de estabilidade.'}
];
function css(){addStyle('timero-zeny-guide-css',
'.tz-root,.tz-root *{box-sizing:border-box}.tz-root{margin:-1em -1.5em;min-height:100vh;background:radial-gradient(circle at 18% 0%,rgba(249,168,38,.09),transparent 34%),radial-gradient(circle at 88% 24%,rgba(0,212,255,.07),transparent 30%),linear-gradient(135deg,#050914,#02050e);font-family:Segoe UI,system-ui,sans-serif;color:#e8eef8}.tz-shell{max-width:1280px;margin:0 auto;padding:44px 28px 60px}.tz-hero,.tz-panel,.tz-card{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid rgba(249,168,38,.18);border-radius:18px;box-shadow:0 0 30px rgba(0,0,0,.34),inset 0 0 24px rgba(249,168,38,.025)}.tz-hero{position:relative;overflow:hidden;padding:34px;margin-bottom:18px}.tz-kicker{display:inline-flex;padding:5px 14px;border-radius:999px;background:rgba(249,168,38,.10);border:1px solid rgba(249,168,38,.25);color:#f9a826;font-weight:900;letter-spacing:.16em;text-transform:uppercase;font-size:.72rem;margin-bottom:16px}.tz-title{font-size:clamp(2.2rem,5vw,4rem);line-height:.96;font-weight:900;color:#fff;letter-spacing:-.035em;margin:0 0 16px}.tz-title span{background:linear-gradient(90deg,#f9c500,#f9a826,#00d4ff);-webkit-background-clip:text;background-clip:text;color:transparent}.tz-sub{max-width:850px;color:rgba(180,205,230,.76);line-height:1.72;font-size:1rem}.tz-stats{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin:18px 0}.tz-stat{background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:14px;text-align:center}.tz-stat strong{display:block;font-size:1.35rem;color:#f9a826;font-weight:900}.tz-stat span{font-size:.72rem;color:rgba(122,144,176,.72);letter-spacing:.12em;text-transform:uppercase;font-weight:800}.tz-panel{padding:18px;margin-bottom:18px}.tz-label{color:#7a90b0;font-weight:900;letter-spacing:.11em;text-transform:uppercase;font-size:.72rem;margin-bottom:10px}.tz-tabs{display:flex;gap:9px;flex-wrap:wrap}.tz-btn{border:1px solid rgba(255,255,255,.08);background:rgba(255,255,255,.04);color:rgba(180,205,230,.72);border-radius:999px;padding:9px 14px;cursor:pointer;font-family:inherit;font-weight:900;font-size:.78rem;letter-spacing:.04em}.tz-btn.active{background:linear-gradient(135deg,rgba(249,168,38,.20),rgba(249,168,38,.07));border-color:rgba(249,168,38,.34);color:#f9a826}.tz-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:18px}.tz-card{padding:20px;margin-bottom:18px}.tz-card-head{display:flex;align-items:center;gap:12px;margin-bottom:14px}.tz-icon{width:48px;height:48px;border-radius:14px;display:flex;align-items:center;justify-content:center;font-size:1.35rem;border:1px solid var(--c-line);background:var(--c-soft)}.tz-card h2{margin:0;color:#fff;border:0;font-size:1.25rem}.tz-card p{color:rgba(180,205,230,.74);line-height:1.7;margin:0 0 12px}.tz-two{display:grid;grid-template-columns:1fr 1fr;gap:10px}.tz-mini{background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.07);border-radius:12px;padding:12px}.tz-mini b{display:block;color:var(--c);letter-spacing:.10em;text-transform:uppercase;font-size:.68rem;margin-bottom:7px}.tz-mini ul{margin:0;padding-left:16px;color:rgba(180,205,230,.75);font-size:.82rem;line-height:1.7}.tz-routes{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}.tz-route{background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:15px;cursor:pointer}.tz-route:hover{border-color:rgba(249,168,38,.32)}.tz-route-name{color:#fff;font-weight:900;margin-bottom:4px}.tz-route-meta{color:#f9a826;font-size:.78rem;font-weight:900;margin-bottom:5px}.tz-muted{color:rgba(122,144,176,.72);font-size:.82rem;line-height:1.55}.tz-calc{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}.tz-field label{display:block;color:#7a90b0;font-size:.68rem;font-weight:900;letter-spacing:.10em;text-transform:uppercase;margin-bottom:6px}.tz-field input{width:100%;padding:10px 11px;border-radius:10px;background:rgba(0,0,0,.32);border:1px solid rgba(255,255,255,.10);color:#e8eef8;font-family:inherit}.tz-result{margin-top:12px;padding:15px;border-radius:12px;background:rgba(249,168,38,.08);border:1px solid rgba(249,168,38,.20);color:#f9a826;font-weight:900;text-align:center;font-size:1.1rem}.tz-related{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.tz-related a,.tz-related div{display:block;text-decoration:none;background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:16px;text-align:center;color:rgba(180,205,230,.72)}@media(max-width:900px){.tz-grid,.tz-two,.tz-routes,.tz-calc,.tz-stats,.tz-related{grid-template-columns:1fr}.tz-shell{padding:26px 14px 44px}.tz-hero{padding:22px}}'
);}
function render(root){css();root.className='tz-root';var tabs='',i;for(i=0;i<methods.length;i++)tabs+='<button class="tz-btn'+(i===0?' active':'')+'" data-tz-method="'+methods[i].id+'">'+methods[i].icon+' '+esc(methods[i].name)+'</button>';root.innerHTML='<div class="tz-shell"><header class="tz-hero"><div class="tz-kicker">// Economia TimeRO</div><h1 class="tz-title">Guia de Farming<br><span>de Zeny</span></h1><div class="tz-sub">Métodos, rotas, calculadora de lucro e estratégias práticas para acumular Zeny sem depender de tentativa e erro. O conteúdo antigo foi convertido para um renderer seguro em Common.js, sem botões crus quebrando no MediaWiki.</div></header><div class="tz-stats"><div class="tz-stat"><strong>3</strong><span>Métodos</span></div><div class="tz-stat"><strong>8</strong><span>Rotas Base</span></div><div class="tz-stat"><strong>Calc</strong><span>Lucro/Hora</span></div><div class="tz-stat"><strong>Market</strong><span>Trading</span></div><div class="tz-stat"><strong>Pre-R</strong><span>Economia</span></div></div><section class="tz-panel"><div class="tz-label">Escolha sua abordagem</div><div class="tz-tabs">'+tabs+'</div></section><section class="tz-grid"><div id="tz-method-panel"></div><div><div class="tz-card"><div class="tz-label">Calculadora rápida</div><div class="tz-calc"><div class="tz-field"><label>Kills / hora</label><input id="tz-kills" type="number" value="700" min="0"></div><div class="tz-field"><label>Valor item</label><input id="tz-value" type="number" value="2500" min="0"></div><div class="tz-field"><label>Drop %</label><input id="tz-drop" type="number" value="25" min="0" max="100"></div><div class="tz-field"><label>Custo/h</label><input id="tz-cost" type="number" value="150000" min="0"></div></div><div class="tz-result" id="tz-result">—</div></div><div class="tz-card"><div class="tz-label">Rotas recomendadas</div><div class="tz-routes" id="tz-routes"></div></div></div></section><section class="tz-panel"><div class="tz-label">Guias relacionados</div><div class="tz-related"><a href="/wiki/Beginner_Leveling_Guide">🌿<br><b>Leveling</b></a><a href="/wiki/MVP_Hunting_Guide">💀<br><b>Caça a MVPs</b></a><a href="/wiki/Market">🏪<br><b>Mercado</b></a><a href="/wiki/Random_Options">🧰<br><b>Random Options</b></a></div></section></div>';bind(root);setMethod(root,'grind');calc(root);}
function methodById(id){for(var i=0;i<methods.length;i++)if(methods[i].id===id)return methods[i];return methods[0];}
function setMethod(root,id){var m=methodById(id),panel=byId('tz-method-panel'),html='',i;var style='--c:'+m.color+';--c-soft:'+m.color+'16;--c-line:'+m.color+'44';html+='<div class="tz-card" style="'+style+'"><div class="tz-card-head"><div class="tz-icon">'+m.icon+'</div><div><h2>'+esc(m.name)+'</h2><div class="tz-muted">Método selecionado</div></div></div><p>'+esc(m.desc)+'</p><div class="tz-two"><div class="tz-mini"><b>Vantagens</b><ul>';for(i=0;i<m.pros.length;i++)html+='<li>'+esc(m.pros[i])+'</li>';html+='</ul></div><div class="tz-mini"><b>Cuidados</b><ul>';for(i=0;i<m.cons.length;i++)html+='<li>'+esc(m.cons[i])+'</li>';html+='</ul></div></div></div>';panel.innerHTML=html;var buttons=root.querySelectorAll('[data-tz-method]');for(i=0;i<buttons.length;i++)buttons[i].className='tz-btn'+(buttons[i].getAttribute('data-tz-method')===id?' active':'');renderRoutes(id);}
function renderRoutes(method){var wrap=byId('tz-routes'),html='',i,r;if(!wrap)return;for(i=0;i<routes.length;i++){r=routes[i];if(r.method!==method)continue;html+='<div class="tz-route"><div class="tz-route-name">'+esc(r.name)+'</div><div class="tz-route-meta">'+esc(r.range)+' · '+esc(r.profit)+'</div><div class="tz-muted"><b>Risco:</b> '+esc(r.risk)+'<br><b>Itens:</b> '+esc(r.items)+'<br>'+esc(r.note)+'</div></div>';}wrap.innerHTML=html||'<div class="tz-muted">Nenhuma rota para este método.</div>';}
function calc(){var k=Number((byId('tz-kills')||{}).value)||0,v=Number((byId('tz-value')||{}).value)||0,d=Number((byId('tz-drop')||{}).value)||0,c=Number((byId('tz-cost')||{}).value)||0,res=(k*v*(d/100))-c;var out=byId('tz-result');if(out)out.innerHTML='Lucro estimado: '+money(res)+' / hora';}
function bind(root){var bs=root.querySelectorAll('[data-tz-method]'),i;for(i=0;i<bs.length;i++)bs[i].onclick=function(){setMethod(root,this.getAttribute('data-tz-method'));};var ins=root.querySelectorAll('.tz-field input');for(i=0;i<ins.length;i++)ins[i].oninput=calc;}
function init(){var root=byId('timero-zeny-guide-app');if(!root||root.getAttribute('data-timero-zeny-ready')==='1')return;root.setAttribute('data-timero-zeny-ready','1');render(root);}
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init();
if(window.mw&&mw.hook)mw.hook('wikipage.content').add(init);
})();
/* =========================================================
TIMERO WIKI MVP HUNTING GUIDE
Safe renderer: fixes inline onclick/filter/timer JavaScript on MediaWiki.
Mount points supported:
- #timero-mvp-guide-app
- #mvp-guide-root (legacy page root)
========================================================= */
(function(){
'use strict';
function esc(v){return String(v==null?'':v).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,''');}
function byId(id){return document.getElementById(id);}
function addStyle(id,css){if(byId(id))return;var s=document.createElement('style');s.id=id;s.appendChild(document.createTextNode(css));document.head.appendChild(s);}
function now(){return new Date().getTime();}
function pad(n){n=Math.floor(n);return n<10?'0'+n:String(n);}
var bosses=[
{id:1511,name:'Amon Ra',tier:'S',danger:10,exp:9000000,respawn:60,hp:'1.2M',map:'moc_pryd06',element:'Earth 3',race:'Demi-Human',size:'Large',party:'Party',drops:'Amon Ra Card, Safety Ring, Yggdrasil Berry',tips:'Use fire damage, Pneuma support and avoid standing stacked.'},
{id:1039,name:'Baphomet',tier:'S',danger:9,exp:8500000,respawn:120,hp:'668k',map:'prt_maze03',element:'Dark 3',race:'Demon',size:'Large',party:'Party',drops:'Baphomet Card, Crescent Scythe, Oridecon',tips:'Bring Shadow resistance, Safety Wall/Pneuma rotation and burst windows.'},
{id:1086,name:'Golden Thief Bug',tier:'A',danger:8,exp:5200000,respawn:60,hp:'126k',map:'prt_sewb4',element:'Fire 2',race:'Insect',size:'Large',party:'Solo/Party',drops:'GTB Card, Golden Gear, Gold',tips:'Magic immunity card makes it extremely valuable. Track timer carefully.'},
{id:1150,name:'Moonlight Flower',tier:'A',danger:7,exp:4600000,respawn:60,hp:'120k',map:'pay_dun04',element:'Fire 3',race:'Demon',size:'Medium',party:'Solo+',drops:'Moonlight Flower Card, Long Mace, Fox Tail',tips:'Good early MVP target. Watch clones and keep consumables ready.'},
{id:1115,name:'Eddga',tier:'B',danger:6,exp:3500000,respawn:120,hp:'152k',map:'pay_fild11',element:'Fire 1',race:'Brute',size:'Large',party:'Solo+',drops:'Eddga Card, Tiger Footskin, Fireblend',tips:'Accessible starter MVP. Water damage and fire armor help.'},
{id:1087,name:'Orc Hero',tier:'B',danger:6,exp:3300000,respawn:60,hp:'295k',map:'gef_fild03',element:'Earth 2',race:'Demi-Human',size:'Large',party:'Solo+',drops:'Orc Hero Card, Orcish Voucher, Shield',tips:'Solid target for geared players. Bring demi-human reduction.'}
];
var state={tier:'all',sort:'danger'};
function css(){addStyle('timero-mvp-guide-css',
'.tm-root,.tm-root *{box-sizing:border-box}.tm-root{margin:-1em -1.5em;min-height:100vh;background:radial-gradient(circle at 18% 0%,rgba(255,61,90,.09),transparent 34%),radial-gradient(circle at 88% 24%,rgba(255,107,0,.07),transparent 30%),linear-gradient(135deg,#050914,#02050e);font-family:Segoe UI,system-ui,sans-serif;color:#e8eef8}.tm-shell{max-width:1280px;margin:0 auto;padding:44px 28px 60px}.tm-hero,.tm-panel,.tm-card{background:linear-gradient(135deg,rgba(8,14,26,.94),rgba(4,8,18,.99));border:1px solid rgba(255,61,90,.20);border-radius:18px;box-shadow:0 0 30px rgba(0,0,0,.34),inset 0 0 24px rgba(255,61,90,.025)}.tm-hero{position:relative;overflow:hidden;padding:34px;margin-bottom:18px}.tm-tape{height:6px;background:repeating-linear-gradient(90deg,#ff3d5a 0,#ff3d5a 32px,#ff6b00 32px,#ff6b00 64px,transparent 64px,transparent 80px);opacity:.75;border-radius:999px;margin-bottom:22px}.tm-kicker{display:inline-flex;padding:5px 14px;border-radius:999px;background:rgba(255,61,90,.10);border:1px solid rgba(255,61,90,.25);color:#ff3d5a;font-weight:900;letter-spacing:.16em;text-transform:uppercase;font-size:.72rem;margin-bottom:16px}.tm-title{font-size:clamp(2.2rem,5vw,4rem);line-height:.96;font-weight:900;color:#fff;letter-spacing:-.035em;margin:0 0 16px}.tm-title span{background:linear-gradient(90deg,#ff3d5a,#ff6b00,#f9c500);-webkit-background-clip:text;background-clip:text;color:transparent}.tm-sub{max-width:850px;color:rgba(180,205,230,.76);line-height:1.72;font-size:1rem}.tm-stats{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin:18px 0}.tm-stat{background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:14px;text-align:center}.tm-stat strong{display:block;font-size:1.35rem;color:#ff3d5a;font-weight:900}.tm-stat span{font-size:.72rem;color:rgba(122,144,176,.72);letter-spacing:.12em;text-transform:uppercase;font-weight:800}.tm-panel{padding:18px;margin-bottom:18px}.tm-label{color:#7a90b0;font-weight:900;letter-spacing:.11em;text-transform:uppercase;font-size:.72rem;margin-bottom:10px}.tm-flex{display:flex;gap:9px;flex-wrap:wrap;align-items:center}.tm-btn{border:1px solid rgba(255,255,255,.08);background:rgba(255,255,255,.04);color:rgba(180,205,230,.72);border-radius:999px;padding:9px 14px;cursor:pointer;font-family:inherit;font-weight:900;font-size:.78rem;letter-spacing:.04em}.tm-btn.active{background:linear-gradient(135deg,rgba(255,61,90,.20),rgba(255,61,90,.07));border-color:rgba(255,61,90,.34);color:#ff3d5a}.tm-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px}.tm-card{overflow:hidden;border-color:var(--line)}.tm-card-head{padding:18px 20px;display:grid;grid-template-columns:60px 1fr auto;gap:14px;align-items:center;cursor:pointer}.tm-avatar{width:60px;height:60px;border-radius:14px;background:var(--soft);border:1px solid var(--line);display:flex;align-items:center;justify-content:center;font-size:1.7rem}.tm-tier{display:inline-flex;padding:2px 8px;border-radius:5px;background:var(--color);color:#fff;font-size:.60rem;font-weight:900;letter-spacing:.12em;margin-bottom:6px}.tm-name{font-size:1.08rem;font-weight:900;color:#fff}.tm-meta{font-size:.70rem;color:rgba(122,144,176,.72);margin-top:4px}.tm-stars{color:var(--color);white-space:nowrap}.tm-strip{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid rgba(255,255,255,.06);border-bottom:1px solid rgba(255,255,255,.06)}.tm-strip div{padding:10px;text-align:center;border-right:1px solid rgba(255,255,255,.05)}.tm-strip b{display:block;color:var(--color);font-size:.82rem}.tm-strip span{font-size:.58rem;letter-spacing:.10em;text-transform:uppercase;color:rgba(122,144,176,.58)}.tm-dossier{display:none;padding:18px 20px;border-top:1px solid rgba(255,255,255,.06)}.tm-card.open .tm-dossier{display:block}.tm-dossier-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}.tm-box{background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:12px;color:rgba(180,205,230,.78);font-size:.84rem;line-height:1.6}.tm-box b{color:var(--color)}.tm-add{margin-top:12px;width:100%;border-radius:10px;border:1px solid var(--line);background:var(--soft);color:var(--color);font-weight:900;font-family:inherit;padding:10px;cursor:pointer}.tm-timers{display:grid;grid-template-columns:1fr 1fr;gap:14px}.tm-form{display:grid;grid-template-columns:1fr 150px auto auto;gap:10px}.tm-form label{display:block;color:#7a90b0;font-size:.68rem;font-weight:900;letter-spacing:.10em;text-transform:uppercase;margin-bottom:6px}.tm-form input{width:100%;padding:10px 11px;border-radius:10px;background:rgba(0,0,0,.32);border:1px solid rgba(255,255,255,.10);color:#e8eef8;font-family:inherit}.tm-timer-list{display:flex;flex-direction:column;gap:10px}.tm-timer{display:flex;align-items:center;justify-content:space-between;gap:12px;background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:12px;padding:12px}.tm-timer b{color:#fff}.tm-time{color:#00d4ff;font-weight:900;font-family:Courier New,monospace}.tm-ready .tm-time{color:#00ff88}.tm-related{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.tm-related a{display:block;text-decoration:none;background:rgba(0,0,0,.24);border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:16px;text-align:center;color:rgba(180,205,230,.72)}@media(max-width:980px){.tm-grid,.tm-timers,.tm-form,.tm-stats,.tm-related,.tm-dossier-grid{grid-template-columns:1fr}.tm-shell{padding:26px 14px 44px}.tm-card-head{grid-template-columns:52px 1fr}.tm-stars{grid-column:1/-1;text-align:left}.tm-strip{grid-template-columns:1fr 1fr}}'
);}
function color(t){return t==='S'?'#ff3d5a':(t==='A'?'#ff6b00':'#00d4ff');}
function saveTimers(list){try{localStorage.setItem('timero-mvp-guide-timers',JSON.stringify(list));}catch(e){}}
function loadTimers(){try{var v=JSON.parse(localStorage.getItem('timero-mvp-guide-timers')||'[]');return v&&v.length?v:[];}catch(e){return [];}}
function render(root){css();root.className='tm-root';root.innerHTML='<div class="tm-shell"><header class="tm-hero"><div class="tm-tape"></div><div class="tm-kicker">// Hunter Dossier</div><h1 class="tm-title">Guia de Caça<br><span>a MVPs</span></h1><div class="tm-sub">Encontre, filtre, ordene e rastreie bosses do TimeRO. Esta versão remove o JavaScript inline quebrado e reconstrói filtros, dossiês e timers diretamente pelo Common.js.</div></header><div class="tm-stats"><div class="tm-stat"><strong>S/A/B</strong><span>Tiers</span></div><div class="tm-stat"><strong>'+bosses.length+'</strong><span>MVPs Base</span></div><div class="tm-stat"><strong>Drops</strong><span>Loot Raro</span></div><div class="tm-stat"><strong>Timer</strong><span>Respawn</span></div><div class="tm-stat"><strong>Builds</strong><span>Classes</span></div></div><section class="tm-panel"><div class="tm-label">Filtrar e ordenar</div><div class="tm-flex"><button class="tm-btn active" data-tier="all">Todos</button><button class="tm-btn" data-tier="S">💀 S-Tier</button><button class="tm-btn" data-tier="A">🔥 A-Tier</button><button class="tm-btn" data-tier="B">⚡ B-Tier</button><span style="width:1px;height:28px;background:rgba(255,255,255,.08)"></span><button class="tm-btn active" data-sort="danger">Dificuldade</button><button class="tm-btn" data-sort="exp">EXP</button><button class="tm-btn" data-sort="respawn">Respawn</button><div id="tm-count" style="margin-left:auto;color:#7a90b0;font-size:.78rem;font-weight:800"></div></div></section><section class="tm-grid" id="tm-boss-grid"></section><section class="tm-panel"><div class="tm-label">Adicionar MVP manualmente</div><div class="tm-form"><div><label>Nome do MVP</label><input id="tm-manual-name" type="text" placeholder="Ex: Eddga"></div><div><label>Respawn (min)</label><input id="tm-manual-respawn" type="number" placeholder="60" min="1"></div><button class="tm-btn active" id="tm-add-manual" type="button">+ Adicionar</button><button class="tm-btn" id="tm-clear" type="button">Limpar Todos</button></div></section><section class="tm-panel"><div class="tm-label">Timers salvos neste navegador</div><div class="tm-timer-list" id="tm-timer-list"></div></section><section class="tm-panel"><div class="tm-label">Guias relacionados</div><div class="tm-related"><a href="/wiki/Beginner_Leveling_Guide">🌿<br><b>Leveling</b></a><a href="/wiki/Farming_Guide">💰<br><b>Farming</b></a><a href="/wiki/PvP">⚔️<br><b>PvP</b></a><a href="/wiki/MVP_Timer">⏱️<br><b>MVP Timer</b></a></div></section></div>';bind(root);renderBosses(root);renderTimers();if(!window.__timeroMvpGuideTimer)window.__timeroMvpGuideTimer=setInterval(renderTimers,1000);}
function renderBosses(root){var grid=byId('tm-boss-grid'),list=[],i;for(i=0;i<bosses.length;i++)if(state.tier==='all'||bosses[i].tier===state.tier)list.push(bosses[i]);list.sort(function(a,b){if(state.sort==='exp')return b.exp-a.exp;if(state.sort==='respawn')return a.respawn-b.respawn;return b.danger-a.danger;});var html='',b,c,stars,j;for(i=0;i<list.length;i++){b=list[i];c=color(b.tier);stars='';for(j=0;j<5;j++)stars+=j<Math.ceil(b.danger/2)?'★':'☆';html+='<article class="tm-card" data-boss-id="'+b.id+'" style="--color:'+c+';--soft:'+c+'14;--line:'+c+'44"><div class="tm-card-head"><div class="tm-avatar">💀</div><div><div class="tm-tier">'+b.tier+'-TIER</div><div class="tm-name">'+esc(b.name)+'</div><div class="tm-meta">ID #'+b.id+' · '+esc(b.element)+' · '+esc(b.race)+' · '+esc(b.size)+'</div></div><div class="tm-stars">'+stars+'<br><span style="font-size:.68rem;color:#7a90b0">▼ Dossiê</span></div></div><div class="tm-strip"><div><b>'+esc(b.hp)+'</b><span>HP</span></div><div><b>'+esc(Math.round(b.exp/1000))+'k</b><span>Base EXP</span></div><div><b>'+b.respawn+'min</b><span>Respawn</span></div><div><b>'+esc(b.party)+'</b><span>Recomendado</span></div></div><div class="tm-dossier"><div class="tm-dossier-grid"><div class="tm-box"><b>Localização:</b> '+esc(b.map)+'<br><b>Drops:</b> '+esc(b.drops)+'</div><div class="tm-box"><b>Dica:</b> '+esc(b.tips)+'</div></div><button class="tm-add" data-add-boss="'+b.id+'" type="button">+ Adicionar ao timer ('+b.respawn+'min)</button></div></article>';}
grid.innerHTML=html||'<div class="tm-panel">Nenhum MVP encontrado.</div>';var count=byId('tm-count');if(count)count.innerHTML='Exibindo '+list.length+' MVP(s)';var cards=grid.querySelectorAll('.tm-card-head');for(i=0;i<cards.length;i++)cards[i].onclick=function(){var card=this.parentNode;card.className=card.className.indexOf('open')<0?card.className+' open':card.className.replace(' open','');};var adds=grid.querySelectorAll('[data-add-boss]');for(i=0;i<adds.length;i++)adds[i].onclick=function(e){e.stopPropagation();var id=this.getAttribute('data-add-boss');for(var k=0;k<bosses.length;k++)if(String(bosses[k].id)===String(id)){addTimer(bosses[k].name,bosses[k].respawn);break;}};}
function addTimer(name,respawn){name=String(name||'').replace(/^\s+|\s+$/g,'');respawn=Number(respawn)||0;if(!name||respawn<=0)return;var list=loadTimers();list.push({name:name,respawn:respawn,deadAt:now(),readyAt:now()+respawn*60000});saveTimers(list);renderTimers();}
function renderTimers(){var wrap=byId('tm-timer-list');if(!wrap)return;var list=loadTimers(),html='',i,t,remain,h,m,s,ready;if(!list.length){wrap.innerHTML='<div class="tm-box">Nenhum timer ativo. Adicione um MVP pelo dossiê ou pelo formulário manual.</div>';return;}for(i=0;i<list.length;i++){t=list[i];remain=Math.max(0,t.readyAt-now());ready=remain<=0;h=Math.floor(remain/3600000);m=Math.floor((remain%3600000)/60000);s=Math.floor((remain%60000)/1000);html+='<div class="tm-timer'+(ready?' tm-ready':'')+'"><div><b>'+esc(t.name)+'</b><div class="tm-muted">Respawn: '+esc(t.respawn)+'min</div></div><div class="tm-time">'+(ready?'READY':(h>0?pad(h)+':':'')+pad(m)+':'+pad(s))+'</div><button class="tm-btn" data-remove-timer="'+i+'" type="button">Remover</button></div>';}wrap.innerHTML=html;var rm=wrap.querySelectorAll('[data-remove-timer]');for(i=0;i<rm.length;i++)rm[i].onclick=function(){var idx=Number(this.getAttribute('data-remove-timer')),l=loadTimers();l.splice(idx,1);saveTimers(l);renderTimers();};}
function bind(root){var i,tb=root.querySelectorAll('[data-tier]');for(i=0;i<tb.length;i++)tb[i].onclick=function(){state.tier=this.getAttribute('data-tier');var all=root.querySelectorAll('[data-tier]');for(var j=0;j<all.length;j++)all[j].className='tm-btn'+(all[j]===this?' active':'');renderBosses(root);};var sb=root.querySelectorAll('[data-sort]');for(i=0;i<sb.length;i++)sb[i].onclick=function(){state.sort=this.getAttribute('data-sort');var all=root.querySelectorAll('[data-sort]');for(var j=0;j<all.length;j++)all[j].className='tm-btn'+(all[j]===this?' active':'');renderBosses(root);};byId('tm-add-manual').onclick=function(){addTimer((byId('tm-manual-name')||{}).value,(byId('tm-manual-respawn')||{}).value);};byId('tm-clear').onclick=function(){saveTimers([]);renderTimers();};}
function init(){var root=byId('timero-mvp-guide-app')||byId('mvp-guide-root');if(!root||root.getAttribute('data-timero-mvp-ready')==='1')return;root.setAttribute('data-timero-mvp-ready','1');render(root);}
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init();
if(window.mw&&mw.hook)mw.hook('wikipage.content').add(init);
})();
/* =========================================================
TIMERO FARMING GUIDE — MERCHANT LEDGER FIX
Source-compatible with the original page using #farming-guide-root.
This keeps the original wiki page intact and restores interactions
without inline <script>, <input>, <button>, or onclick handlers.
========================================================= */
(function () {
'use strict';
function $(sel, root) { return (root || document).querySelector(sel); }
function $all(sel, root) { return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }
function byId(id) { return document.getElementById(id); }
function injectStyle() {
if (byId('timero-farming-merchant-ledger-css')) return;
var s = document.createElement('style');
s.id = 'timero-farming-merchant-ledger-css';
s.textContent = '' +
'@keyframes ticker-scroll{0%{transform:translateX(0)}100%{transform:translateX(-50%)}}' +
'@keyframes route-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}' +
'#farming-guide-root .method-tab:hover,#farming-guide-root .route-pill:hover,#farming-guide-root .loadout-item:hover,#farming-guide-root [data-calc-adjust]:hover,#farming-guide-root .calc-method-option:hover,#farming-guide-root .loadout-clear:hover{filter:brightness(1.16);transform:translateY(-1px)}' +
'#farming-guide-root .loadout-item.is-selected{background:rgba(176,108,255,0.12)!important;border-color:rgba(176,108,255,0.34)!important;box-shadow:0 0 18px rgba(176,108,255,0.08)}' +
'#farming-guide-root .route-pill.is-active{box-shadow:0 0 18px rgba(249,197,0,0.12),inset 0 0 12px rgba(255,255,255,0.04)!important}' +
'@media(max-width:900px){#farming-guide-root [style*="grid-template-columns:repeat(5"],#farming-guide-root [style*="grid-template-columns:repeat(4"],#farming-guide-root [style*="grid-template-columns:repeat(3"],#farming-guide-root [style*="grid-template-columns:1fr 1fr"]{grid-template-columns:1fr!important}#farming-guide-root [style*="padding:56px 64px"],#farming-guide-root [style*="padding:52px 64px"]{padding:36px 18px!important}}';
document.head.appendChild(s);
}
var methodColors = {
grind: { color: '#f9c500', bg: 'linear-gradient(135deg,rgba(249,197,0,0.18),rgba(249,197,0,0.07))' },
market: { color: '#00d4ff', bg: 'linear-gradient(135deg,rgba(0,212,255,0.18),rgba(0,212,255,0.07))' },
passive:{ color: '#b06cff', bg: 'linear-gradient(135deg,rgba(176,108,255,0.18),rgba(176,108,255,0.07))' }
};
function setMethod(root, method) {
method = method || 'grind';
root.setAttribute('data-open-method', method);
$all('.method-panel', root).forEach(function (panel) {
var active = panel.id === 'method-' + method;
panel.style.display = active ? 'grid' : 'none';
});
$all('.method-tab', root).forEach(function (tab) {
var id = tab.getAttribute('data-method');
var active = id === method;
var meta = methodColors[id] || methodColors.grind;
tab.style.background = active ? meta.bg : 'transparent';
tab.style.color = active ? meta.color : meta.color.replace(')', ',0.60)').replace('rgb', 'rgba');
tab.style.fontWeight = active ? '900' : '700';
tab.style.boxShadow = active ? 'inset 0 -2px 0 ' + meta.color : 'none';
});
}
function setRoute(root, routeId) {
var currentlyOpen = root.getAttribute('data-open-route') || '';
var shouldClose = currentlyOpen === routeId;
var next = shouldClose ? '' : routeId;
root.setAttribute('data-open-route', next);
$all('.route-detail', root).forEach(function (panel) {
panel.style.display = panel.id === next ? 'block' : 'none';
});
$all('.route-pill', root).forEach(function (pill) {
var active = pill.getAttribute('data-route') === next;
pill.classList.toggle('is-active', active);
pill.style.opacity = next && !active ? '0.56' : '1';
});
if (next) {
var target = byId(next);
if (target) setTimeout(function () { target.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }, 60);
}
}
function fmtMillions(v) {
v = Math.max(0, Math.round(v));
if (v >= 1000) {
var b = v / 1000;
return (Math.round(b * 10) / 10).toLocaleString('pt-BR') + 'B z';
}
return v.toLocaleString('pt-BR') + 'M z';
}
function getCalcState(root) {
var hoursEl = byId('calc-hours');
var labelEl = byId('calc-method-label');
var rate = Number(root.getAttribute('data-calc-rate') || '70');
var hours = Number(root.getAttribute('data-calc-hours') || (hoursEl ? hoursEl.textContent : '2') || '2');
var booster = Number(root.getAttribute('data-calc-booster') || '0');
var label = root.getAttribute('data-calc-label') || (labelEl ? labelEl.textContent : 'Rota Mid-Game (70M/hr)');
return { hours: hours, rate: rate, booster: booster, label: label };
}
function calc(root) {
var st = getCalcState(root);
var mult = st.booster ? 1.5 : 1;
var session = st.hours * st.rate * mult;
var day = session;
var week = day * 7;
var weeklyTarget = 12000;
var pct = Math.min(100, Math.round((week / weeklyTarget) * 100));
var hoursEl = byId('calc-hours');
var labelEl = byId('calc-method-label');
var sessionEl = byId('result-session');
var dayEl = byId('result-day');
var weekEl = byId('result-week');
var pctEl = byId('result-pct');
var barEl = byId('result-bar');
if (hoursEl) hoursEl.textContent = String(st.hours).replace('.', ',');
if (labelEl) labelEl.textContent = st.label;
if (sessionEl) sessionEl.textContent = fmtMillions(session);
if (dayEl) dayEl.textContent = fmtMillions(day);
if (weekEl) weekEl.textContent = fmtMillions(week);
if (pctEl) pctEl.textContent = pct + '%';
if (barEl) barEl.style.width = pct + '%';
var yes = byId('boost-yes');
var no = byId('boost-no');
if (yes && no) {
yes.style.background = st.booster ? 'rgba(0,255,136,0.14)' : 'rgba(255,255,255,0.04)';
yes.style.borderColor = st.booster ? 'rgba(0,255,136,0.30)' : 'rgba(255,255,255,0.09)';
yes.style.color = st.booster ? '#00ff88' : 'rgba(122,144,176,0.60)';
yes.style.fontWeight = st.booster ? '800' : '700';
no.style.background = st.booster ? 'rgba(255,255,255,0.04)' : 'rgba(255,61,90,0.15)';
no.style.borderColor = st.booster ? 'rgba(255,255,255,0.09)' : 'rgba(255,61,90,0.30)';
no.style.color = st.booster ? 'rgba(122,144,176,0.60)' : '#ff3d5a';
no.style.fontWeight = st.booster ? '700' : '800';
}
}
function updateLoadout(root) {
var total = 0;
var count = 0;
$all('.loadout-item.is-selected', root).forEach(function (item) {
total += Number(item.getAttribute('data-cost') || '0');
count++;
});
var totalEl = byId('loadout-total');
var countEl = byId('loadout-count');
if (totalEl) totalEl.textContent = total.toLocaleString('pt-BR') + 'k z';
if (countEl) countEl.textContent = String(count);
}
function bind(root) {
$all('.method-tab', root).forEach(function (tab) {
tab.addEventListener('click', function () { setMethod(root, tab.getAttribute('data-method')); });
});
$all('.route-pill', root).forEach(function (pill) {
pill.addEventListener('click', function () { setRoute(root, pill.getAttribute('data-route')); });
});
$all('.route-close', root).forEach(function (btn) {
btn.addEventListener('click', function (e) { e.stopPropagation(); setRoute(root, btn.getAttribute('data-route')); });
});
$all('[data-calc-adjust]', root).forEach(function (btn) {
btn.addEventListener('click', function () {
var st = getCalcState(root);
var delta = Number(btn.getAttribute('data-delta') || '0');
var next = Math.max(0.5, Math.min(24, st.hours + delta));
root.setAttribute('data-calc-hours', String(next));
calc(root);
});
});
var display = byId('calc-method-display');
var menu = byId('calc-method-menu');
var calcSection = byId('calculator-section');
if (display && menu) {
display.addEventListener('click', function (e) {
e.stopPropagation();
var open = menu.style.display === 'block';
menu.style.display = open ? 'none' : 'block';
if (calcSection) calcSection.setAttribute('data-method-menu-open', open ? '0' : '1');
});
document.addEventListener('click', function () { menu.style.display = 'none'; if (calcSection) calcSection.setAttribute('data-method-menu-open', '0'); });
}
$all('.calc-method-option', root).forEach(function (opt) {
opt.addEventListener('click', function (e) {
e.stopPropagation();
root.setAttribute('data-calc-rate', opt.getAttribute('data-rate') || '70');
root.setAttribute('data-calc-label', opt.getAttribute('data-label') || opt.textContent.trim());
if (menu) menu.style.display = 'none';
calc(root);
});
});
['boost-no', 'boost-yes'].forEach(function (id) {
var el = byId(id);
if (el) el.addEventListener('click', function () { root.setAttribute('data-calc-booster', el.getAttribute('data-booster') || '0'); calc(root); });
});
$all('.loadout-item', root).forEach(function (item) {
item.addEventListener('click', function () {
item.classList.toggle('is-selected');
var check = $('.li-check', item);
if (check) check.textContent = item.classList.contains('is-selected') ? '✓' : '';
updateLoadout(root);
});
});
var clear = $('.loadout-clear', root);
if (clear) clear.addEventListener('click', function () {
$all('.loadout-item', root).forEach(function (item) {
item.classList.remove('is-selected');
var check = $('.li-check', item);
if (check) check.textContent = '';
});
updateLoadout(root);
});
setMethod(root, root.getAttribute('data-open-method') || 'grind');
calc(root);
updateLoadout(root);
}
function init() {
var root = byId('farming-guide-root');
if (!root || root.getAttribute('data-timero-farming-v6-ready') === '1') return;
root.setAttribute('data-timero-farming-v6-ready', '1');
injectStyle();
bind(root);
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
if (window.mw && mw.hook) mw.hook('wikipage.content').add(init);
})();