function updateRewards(){ const btn=document.getElementByI
by FrozenOtter31499 lines19.5 KB
function updateRewards(){
const btn=document.getElementById('rewardsBtn');
const hasNew=REWARD_DEFS.some((r,i)=>!GS.rewardsClaimed.includes(i)&&GS.trophies>=getTrophyFloor()+r.offset);
if(hasNew)btn.classList.add('has-new');else btn.classList.remove('has-new');
}
function savePlayerName(){
const v=document.getElementById('playerNameInput').value.trim();
if(v){GS.playerName=v;saveGS();toast('השם נשמר!');}
}
// ==================== DECK ====================
let tempDeck=[];
function goDeck(){tempDeck=[...GS.deck];renderDeck();showScreen('deckScreen');}
function renderDeck(){
document.getElementById('dCount').textContent=tempDeck.length;
document.getElementById('dNext').disabled=tempDeck.length!==10;
const selRow=document.getElementById('selRow');
selRow.innerHTML='';
for(let i=0;i<10;i++){
const d=document.createElement('div');d.className='sel-slot '+(i<tempDeck.length?'':'empty');
if(i<tempDeck.length){const c=CHARS.find(x=>x.id===tempDeck[i]);d.textContent=c.icon;}
selRow.appendChild(d);
}
const grid=document.getElementById('charGrid');
grid.innerHTML='';
CHARS.forEach(c=>{
const el=document.createElement('div');
const picked=tempDeck.includes(c.id);
const locked=!isUnl(c.id);
el.className='char-cell '+(picked?'picked':'')+(locked?' locked':'');
el.innerHTML=`<div class="c-lvl">Lv.${getLvl(c.id)}</div>${locked?'<div class="c-lock">נעול</div>':''}<div class="c-icon">${c.icon}</div><div class="c-name">${c.name}</div><div class="c-info">❤️${c.hp} ⚔️${c.dmg}<br>💧${c.cost} ${c.special}</div>`;
if(!locked)el.onclick=()=>toggleChar(c.id);
grid.appendChild(el);
});
}
function toggleChar(id){
if(tempDeck.includes(id)){tempDeck=tempDeck.filter(x=>x!==id);}
else if(tempDeck.length<10){tempDeck.push(id);}
renderDeck();
}
function goMaps(){if(tempDeck.length!==10)return;GS.deck=[...tempDeck];saveGS();renderMaps();showScreen('mapScreen');}
// ==================== MAPS ====================
let selMap=0;
function renderMaps(){
const g=document.getElementById('mapGrid');
g.innerHTML='';
MAPS.forEach(m=>{
const el=document.createElement('div');
el.className='map-cell '+(selMap===m.id?'chosen':'');
el.style.background=m.bg;
el.innerHTML=`<div class="m-emoji">${m.emoji}</div><div class="m-name">${m.name}</div>`;
el.onclick=()=>{selMap=m.id;renderMaps();document.getElementById('mStart').disabled=false;};
g.appendChild(el);
});
}
// ==================== GAME ====================
let active=false,paused=false,tmr,loop,manaTmr,botTmr;
let units=[],projectiles=[];
let elixir=5,botElixir=5;
let timeLeft=180;
let hand=[],botHand=[],deckQueue=[],botQueue=[];
let botLvl=1,botDeck=[];
let mapData=null;
let trainMode=false,trainDiff='medium';
let towers={};
function startGame(){trainMode=false;initGame();}
function startTrain(diff){trainMode=true;trainDiff=diff;initGame();}
function initGame(){
active=true;paused=false;units=[];projectiles=[];elixir=5;botElixir=5;timeLeft=180;
mapData=MAPS[selMap];
botLvl=trainMode?(diffToBotLvl(trainDiff)):getBotLvl();
botDeck=trainMode?buildBotDeck(botLvl):buildBotDeck(botLvl);
deckQueue=shuffle([...GS.deck]);botQueue=shuffle([...botDeck]);
hand=drawHand(deckQueue,4);botHand=drawHand(botQueue,4);
towers={p:[2400,2400,4000],b:[2400,2400,4000],pActive:[true,true,false],bActive:[true,true,false]};
updateTowers();
document.getElementById('arena').style.background=mapData.bg;
renderScenery();
showScreen('gameScreen');
renderHand();
updateHUD();
if(tmr)clearInterval(tmr);tmr=setInterval(()=>{if(!active||paused)return;timeLeft--;if(timeLeft<=0)endGame();updateHUD();},1000);
if(loop)clearInterval(loop);loop=setInterval(gameTick,50);
if(manaTmr)clearInterval(manaTmr);manaTmr=setInterval(()=>{if(!active||paused)return;elixir=Math.min(10,elixir+0.15);botElixir=Math.min(10,botElixir+getBotElixirRate());updateElixir();},200);
if(botTmr)clearInterval(botTmr);botTmr=setInterval(botTick,1200);
document.getElementById('arena').onclick=arenaClick;
}
function diffToBotLvl(d){return d==='easy'?1:d==='medium'?3:d==='hard'?6:10;}
function buildBotDeck(lvl){
const pool=CHARS.filter((_,i)=>i<10+(lvl*2)).map(c=>c.id);
const d=[];while(d.length<10){const r=pool[Math.floor(Math.random()*pool.length)];if(!d.includes(r))d.push(r);}
return d;
}
function shuffle(a){const n=[...a];for(let i=n.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[n[i],n[j]]=[n[j],n[i]];}return n;}
function drawHand(queue,n){const h=[];while(h.length<n&&queue.length>0)h.push(queue.shift());return h;}
function renderScenery(){
const arena=document.getElementById('arena');
arena.querySelectorAll('.scenery').forEach(e=>e.remove());
if(mapData.scenery)mapData.scenery.forEach(s=>{
const e=document.createElement('div');e.className='scenery';e.textContent=s.icon;
e.style.left=s.x+'%';e.style.top=s.y+'%';e.style.fontSize=s.s+'rem';e.style.opacity=s.o;
arena.appendChild(e);
});
}
function updateHUD(){
document.getElementById('hTimer').textContent=fmtTime(timeLeft);
document.getElementById('hPlayer').textContent=towers.pActive.filter(Boolean).length;
document.getElementById('hBot').textContent=towers.bActive.filter(Boolean).length;
}
function fmtTime(s){const m=Math.floor(s/60);const r=s%60;return m+':'+(r<10?'0':'')+r;}
function updateElixir(){
document.getElementById('eText').textContent='אליקסיר: '+Math.floor(elixir)+'/10';
document.getElementById('eFill').style.width=(elixir*10)+'%';
renderHand();
}
function renderHand(){
const bar=document.getElementById('handBar');
bar.innerHTML='';
hand.forEach((id,idx)=>{
const c=CHARS.find(x=>x.id===id);
const el=document.createElement('div');
const can=elixir>=c.cost;
el.className='hand-card '+(selCard===idx?'selected ':'')+(can?'':'disabled');
el.innerHTML=`<div class="hc-cost">${c.cost}</div><div class="hc-icon">${c.icon}</div><div class="hc-name">${c.name}</div>`;
el.onclick=(e)=>{e.stopPropagation();selectCard(idx);};
bar.appendChild(el);
});
}
let selCard=-1;
function selectCard(idx){
if(idx>=hand.length)return;
const c=CHARS.find(x=>x.id===hand[idx]);
if(elixir<c.cost)return;
selCard=selCard===idx?-1:idx;
renderHand();
const ghost=document.getElementById('ghost');
if(selCard>=0){ghost.style.display='block';}else{ghost.style.display='none';}
}
function arenaClick(e){
if(selCard<0||!active||paused)return;
const c=CHARS.find(x=>x.id===hand[selCard]);
if(elixir<c.cost)return;
const arena=document.getElementById('arena');
const rect=arena.getBoundingClientRect();
const x=e.clientX-rect.left;const y=e.clientY-rect.top;
if(y>rect.height*0.55||y<rect.height*0.25)return;
elixir-=c.cost;
spawnUnit(hand[selCard],'player',x,y);
hand[selCard]=deckQueue.length>0?deckQueue.shift():hand[selCard];
selCard=-1;document.getElementById('ghost').style.display='none';
updateElixir();renderHand();
}
function spawnUnit(charId,side,x,y){
const s=getStats(charId);
const arena=document.getElementById('arena');
const el=document.createElement('div');
el.className='unit '+side;
el.style.left=(x-21)+'px';el.style.top=(y-21)+'px';
el.innerHTML=s.icon+`<div class="unit-hp-bg"><div class="unit-hp-fg" style="width:100%"></div></div>`;
arena.appendChild(el);
const unit={id:Date.now()+Math.random(),charId,char:s,side,el,x,y,hp:s.hp,maxHp:s.hp,lastAtk:0,state:'walk',target:null};
units.push(unit);
}
function gameTick(){
if(!active||paused)return;
const arena=document.getElementById('arena');
const w=arena.offsetWidth,h=arena.offsetHeight;
// Update units
units.forEach(u=>{
if(u.hp<=0)return;
// Find target
let nearest=null,nd=Infinity;
// Enemy units
units.forEach(o=>{
if(o.hp<=0||o.side===u.side)return;
const d=dist(u,o);
if(d<nd){nd=d;nearest=o;}
});
// Towers
[0,1,2].forEach(ti=>{
const isBot=u.side==='player';
const tSide=isBot?'b':'p';
if(!towers[tSide+'Active'][ti])return;
const tx=getTowerX(ti,w);const ty=isBot?h*0.11:h*0.89;
const d=Math.hypot(u.x-tx,u.y-ty);
if(d<nd){nd=d;nearest={x:tx,y:ty,tower:true,side:tSide,index:ti};}
});
if(nearest&&nd<=u.char.range){
u.state='attack';
if(Date.now()-u.lastAtk>1000/u.char.speed){
u.lastAtk=Date.now();
if(nearest.tower){
dmgTower(nearest.side,nearest.index,u.char.dmg);
}else{
dmgUnit(nearest,u.char.dmg);
}
}
}else{
u.state='walk';
const ty=u.side==='player'?0:h;
const tx=w/2;
const angle=Math.atan2(ty-u.y,tx-u.x);
const spd=u.char.speed*1.5;
u.x+=Math.cos(angle)*spd;u.y+=Math.sin(angle)*spd;
u.el.style.left=(u.x-21)+'px';u.el.style.top=(u.y-21)+'px';
}
});
// Tower shooting
[0,1,2].forEach(ti=>{
['p','b'].forEach(ts=>{
if(!towers[ts+'Active'][ti])return;
const isBot=ts==='b';
const tx=getTowerX(ti,w);const ty=isBot?h*0.11:h*0.89;
let nearest=null,nd=TOWER_RANGE;
units.forEach(u=>{
if(u.hp<=0||u.side===(isBot?'bot':'player'))return;
const d=Math.hypot(u.x-tx,u.y-ty);
if(d<nd){nd=d;nearest=u;}
});
if(nearest){
const key=ts+ti;
if(!towers[key])towers[key]=0;
if(Date.now()-towers[key]>TOWER_ATK_SPEED){
towers[key]=Date.now();
fireShot(tx,ty,nearest,TOWER_DMG);
}
}
});
});
// Projectiles
projectiles.forEach(p=>{
if(p.done)return;
const dx=p.target.x-p.x;const dy=p.target.y-p.y;
const d=Math.hypot(dx,dy);
if(d<10){
p.done=true;p.el.remove();
if(p.target.tower){
dmgTower(p.target.side,p.target.index,p.dmg);
}else if(units.includes(p.target)){
dmgUnit(p.target,p.dmg);
}
}else{
p.x+=dx/d*12;p.y+=dy/d*12;
p.el.style.left=(p.x-5)+'px';p.el.style.top=(p.y-5)+'px';
}
});
projectiles=projectiles.filter(p=>!p.done);
// Cleanup dead
units.forEach(u=>{
if(u.hp<=0&&u.el.parentNode){u.el.remove();}
});
units=units.filter(u=>u.hp>0);
// Check end
if(towers.pActive[2]===false||towers.bActive[2]===false)endGame();
}
function getTowerX(i,w){return i===0?w*0.05:i===1?w*0.95:w*0.5;}
function dist(a,b){return Math.hypot(a.x-b.x,a.y-b.y);}
function dmgUnit(u,dmg){
u.hp-=dmg;
const pct=Math.max(0,u.hp/u.maxHp*100);
u.el.querySelector('.unit-hp-fg').style.width=pct+'%';
showDmg(u.x,u.y-25,dmg);
if(u.hp<=0){u.el.style.opacity='0';setTimeout(()=>u.el&&u.el.remove(),300);}
}
function dmgTower(side,idx,dmg){
const key=side==='b'?'b':'p';
towers[key][idx]-=dmg;
const el=document.getElementById('hp'+(side==='b'?'B':'P')+idx);
if(el)el.textContent=Math.max(0,Math.floor(towers[key][idx]));
showDmg(getTowerX(idx,document.getElementById('arena').offsetWidth),side==='b'?40:document.getElementById('arena').offsetHeight-40,dmg);
if(towers[key][idx]<=0){
towers[key][idx]=0;
towers[key+'Active'][idx]=false;
const tel=document.getElementById('t'+(side==='b'?'B':'P')+idx);
if(tel){tel.classList.add('destroyed');if(idx===2)tel.classList.remove('inactive');}
if(idx<2){
const king=document.getElementById('t'+(side==='b'?'B':'P')+2);
if(king)king.classList.remove('inactive');
towers[key+'Active'][2]=true;
}
}
}
function showDmg(x,y,dmg){
const el=document.createElement('div');el.className='dmg-pop';el.textContent='-'+Math.floor(dmg);
el.style.left=(x-15)+'px';el.style.top=y+'px';
document.getElementById('arena').appendChild(el);
setTimeout(()=>el.remove(),800);
}
function fireShot(x,y,target,dmg){
const arena=document.getElementById('arena');
const el=document.createElement('div');el.className='tower-shot';
el.style.left=(x-5)+'px';el.style.top=(y-5)+'px';
el.style.background=target.side==='b'?'#4CAF50':'#f44336';
arena.appendChild(el);
projectiles.push({el,x,y,target,dmg,done:false});
}
function getBotElixirRate(){
if(trainMode){
return trainDiff==='easy'?0.05:trainDiff==='medium'?0.12:trainDiff==='hard'?0.2:0.35;
}
return 0.1+Math.min(0.15,(botLvl-1)*0.02);
}
function botTick(){
if(!active||paused)return;
const arena=document.getElementById('arena');
const w=arena.offsetWidth,h=arena.offsetHeight;
// Simple AI: play random affordable card in random position
const affordable=botHand.map((id,idx)=>({id,idx,c:CHARS.find(x=>x.id===id)})).filter(o=>botElixir>=o.c.cost);
if(affordable.length===0)return;
const pick=affordable[Math.floor(Math.random()*affordable.length)];
botElixir-=pick.c.cost;
const x=w*0.2+Math.random()*w*0.6;
const y=h*0.08+Math.random()*h*0.15;
spawnUnit(pick.id,'bot',x,y);
botHand[pick.idx]=botQueue.length>0?botQueue.shift():botHand[pick.idx];
}
function updateTowers(){
[0,1,2].forEach(i=>{
['P','B'].forEach(s=>{
const el=document.getElementById('t'+s+i);
const side=s==='B'?'b':'p';
if(towers[side+'Active'][i])el.classList.remove('inactive','destroyed');
else if(towers[side][i]<=0)el.classList.add('destroyed');
});
});
}
function endGame(){
if(!active)return;active=false;
clearInterval(tmr);clearInterval(loop);clearInterval(manaTmr);clearInterval(botTmr);
const pCount=towers.pActive.filter(Boolean).length;
const bCount=towers.bActive.filter(Boolean).length;
let result,title,coins=0,trophies=0;
if(pCount>bCount||towers.bActive[2]===false){result='win';title='ניצחון! 🎉';coins=30+Math.floor(Math.random()*20);trophies=30;}
else if(bCount>pCount||towers.pActive[2]===false){result='lose';title='הפסד...';coins=5;trophies=-getLossAmount();}
else{result='draw';title='תיקו 🤝';coins=10;trophies=0;}
if(result==='win')GS.wins++;else if(result==='lose')GS.losses++;
GS.coins=Math.max(0,GS.coins+coins);
GS.trophies=Math.max(0,GS.trophies+trophies);
updateLeaderboard();saveGS();
document.getElementById('rTitle').textContent=title;
document.getElementById('rTitle').className='rtitle '+result;
document.getElementById('rRewards').innerHTML=`<div class="r-reward">💰 <b>+${coins}</b> מטבעות</div>`+(trophies!==0?`<div class="r-reward">🏆 <b>${trophies>0?'+':''}${trophies}</b> גביעים</div>`:'');
document.getElementById('resultOverlay').classList.add('on');
}
// ==================== COLLECTION ====================
function goCollection(){renderUpgrades();showScreen('collectionScreen');}
function renderUpgrades(){
document.getElementById('cCoins').textContent=GS.coins;
const g=document.getElementById('upGrid');
g.innerHTML='';
CHARS.forEach(c=>{
if(!isUnl(c.id))return;
const lvl=getLvl(c.id);
const max=getMaxLvl();
const el=document.createElement('div');el.className='up-card';
const s=getStats(c.id);
const cost=getCost(lvl);
const can=lvl<max&&GS.coins>=cost;
el.innerHTML=`<div class="c-lvl" style="position:static;display:inline-block;margin-bottom:4px;">Lv.${lvl}</div><div class="up-icon">${c.icon}</div><div class="up-name">${c.name}</div><div class="up-stat">❤️${s.hp} ⚔️${s.dmg}<br>💰 שדרוג: ${lvl>=max?'מקסימום':cost}</div>`+(lvl>=max?'<div class="up-max">מקסימום ⭐</div>':`<button class="up-btn" ${can?'':'disabled'} onclick="doUpgrade(${c.id})">שדרג</button>`);
g.appendChild(el);
});
}
function doUpgrade(id){
const lvl=getLvl(id);
const cost=getCost(lvl);
if(GS.coins<cost||lvl>=getMaxLvl())return;
GS.coins-=cost;GS.levels[id]=lvl+1;saveGS();toast('שודרג לרמה '+(lvl+1)+'!');renderUpgrades();updateMenu();
}
// ==================== LEADERBOARD ====================
function goLeaderboard(){renderLB();showScreen('leaderboardScreen');}
function renderLB(){
const tbody=document.getElementById('lbBody');
tbody.innerHTML='';
const list=getTop5();
list.forEach((p,i)=>{
const tr=document.createElement('tr');
tr.innerHTML=`<td>${i+1}</td><td>${p.name}</td><td>${p.trophies}</td>`;
tbody.appendChild(tr);
});
if(list.length===0){tbody.innerHTML='<tr><td colspan="3">אין נתונים עדיין</td></tr>';}
}
// ==================== REWARDS ====================
function goRewards(){renderRewards();showScreen('rewardsScreen');}
function renderRewards(){
const g=document.getElementById('rewardsGrid');
g.innerHTML='';
const floor=getTrophyFloor();
REWARD_DEFS.forEach((r,i)=>{
const el=document.createElement('div');
const claimed=GS.rewardsClaimed.includes(i);
const available=GS.trophies>=floor+r.offset;
el.className='reward-item '+(claimed?'claimed':available?'available':'locked');
el.innerHTML=`<div class="reward-icon">${r.icon}</div><div class="reward-info"><div class="reward-title">${r.title}</div><div class="reward-desc">${r.desc}</div><div class="reward-trophy">נדרש: ${floor+r.offset} גביעים</div></div>${claimed?'<div class="reward-check">✓</div>':''}`;
if(available&&!claimed)el.onclick=()=>claimReward(i);
g.appendChild(el);
});
}
function claimReward(idx){
if(GS.rewardsClaimed.includes(idx))return;
const r=REWARD_DEFS[idx];
GS.rewardsClaimed.push(idx);
if(r.type==='coins'){GS.coins+=r.amount;toast('קיבלת '+r.amount+' מטבעות!');}
else if(r.type==='coinChest'){openCoinChest();}
else if(r.type==='charChest'){openCharChestReward();}
saveGS();renderRewards();updateMenu();
}
// ==================== CHESTS ====================
let pendingCoinReward=0;
function openCoinChest(){
pendingCoinReward=50+Math.floor(Math.random()*100);
document.getElementById('chestOverlay').classList.add('on');
document.getElementById('chestVisual').classList.remove('opened');
document.getElementById('chestReward').textContent='';
document.getElementById('chestContinue').style.display='none';
}
function openChest(){
const v=document.getElementById('chestVisual');
if(v.classList.contains('opened'))return;
v.classList.add('opened');
document.getElementById('chestReward').textContent='💰 '+pendingCoinReward+' מטבעות!';
document.getElementById('chestContinue').style.display='inline-block';
GS.coins+=pendingCoinReward;saveGS();updateMenu();
}
function closeChest(){document.getElementById('chestOverlay').classList.remove('on');}
let pendingCharId=null;
function openCharChestReward(){
const locked=CHARS.filter(c=>!isUnl(c.id)&&canUnl(c.id));
if(locked.length===0){toast('אין דמויות חדשות לפתיחה!');GS.coins+=200;return;}
pendingCharId=locked[Math.floor(Math.random()*locked.length)].id;
document.getElementById('charChestOverlay').classList.add('on');
document.getElementById('charChestVisual').classList.remove('opened');
document.getElementById('charChestReward').textContent='';
document.getElementById('charChestContinue').style.display='none';
}
function openCharChest(){
const v=document.getElementById('charChestVisual');
if(v.classList.contains('opened'))return;
v.classList.add('opened');
const c=CHARS.find(x=>x.id===pendingCharId);
document.getElementById('charChestReward').innerHTML=c.icon+'<br><span style="font-size:1.2rem">'+c.name+'</span>';
document.getElementById('charChestContinue').style.display='inline-block';
if(!GS.unlocked.includes(pendingCharId))GS.unlocked.push(pendingCharId);
saveGS();updateMenu();
}
function closeCharChest(){document.getElementById('charChestOverlay').classList.remove('on');}
// Mouse follow ghost
document.addEventListener('mousemove',e=>{
const ghost=document.getElementById('ghost');
if(selCard<0||!ghost)return;
const arena=document.getElementById('arena');
const rect=arena.getBoundingClientRect();
const x=e.clientX-rect.left;const y=e.clientY-rect.top;
if(x>0&&x<rect.width&&y>0&&y<rect.height){
ghost.style.left=(x-20)+'px';ghost.style.top=(y-20)+'px';ghost.style.display='block';
}else{ghost.style.display='none';}
});
// Init
updateMenu();
updateRewards();Game Source: function updateRewards(){ const btn=document.getElementByI
Creator: FrozenOtter31
Libraries: none
Complexity: complex (499 lines, 19.5 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: function-updaterewards-const-btn-documen-frozenotter31" to link back to the original. Then publish at arcadelab.ai/publish.