diff --git a/database/actions.json b/database/actions.json index 708bcf4..0746f43 100644 --- a/database/actions.json +++ b/database/actions.json @@ -48,18 +48,15 @@ "utility": [ { "id": 7, - "title": "Haste", - "description": "Greatly increase your agility for a short duration.", - "effectDuration": 5, - "statType": "agi", - "statBoost": 5 + "title": "Berserker's Strength", + "description": "Greatly increase your strength for a short duration.", + "appliedEffect": 1 }, { "id": 8, "title": "Clarity", "description": "Temporarily boost the rate of your mana regeration.", - "effectDuration": 3, - "manaAmount": 1 + "appliedEffect": 2 } ] } diff --git a/database/effects.json b/database/effects.json new file mode 100644 index 0000000..ae3278a --- /dev/null +++ b/database/effects.json @@ -0,0 +1,29 @@ +[ + { + "id": 1, + "type": "buff", + "name": "Berserker's Strength", + "attribute": "str", + "value": 5, + "duration": 1, + "isBuff": true + }, + { + "id": 2, + "type": "buff", + "name": "Clarity", + "attribute": "mana", + "value": 2, + "duration": 60, + "isBuff": true + }, + { + "id": 3, + "type": "debuff", + "name": "Poison", + "attribute": "health", + "value": -1, + "duration": 5, + "isBuff": false + } +] diff --git a/dist/bundle.js b/dist/bundle.js index 430cbc2..fbca103 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1 +1 @@ -(()=>{"use strict";class t{name;constructor(t){this.name=t}enter(){}exit(){}update(){}}const e={attack:function(t,e,s){let a=t.damage*e.getStat("damage")-s.getStat("sta")/2;a=function(t,e,n){let s=t*(1-n.armor/100);return console.log(s),s}(a,0,s),n(s,a)},defensive:function(t,e){let n=t.defenseValue;e.armor+=n},heal:function(t,e){let n=t.healAmount*(e.getStat("wis")/2);e.health+=n},utility:function(t,e,n){console.log(t,e,n)}};function n(t,e){let n=e;return t.health-n<=0&&0==t.isDead?(t.health=0,t.isDead=!0,console.log("You died.")):0==t.isDead&&(t.health-=n,t.monsterImage&&(t.monsterImage.classList.add("shrink"),setTimeout((()=>{t.monsterImage.classList.remove("shrink")}),150))),n}class s extends t{constructor(){super("PlayerTurn")}enter(){super.enter()}exit(){super.exit()}update(t,n,s){super.update(),s.actionQueue.length>0&&function(t,n,s){const a=e[t.category];a?a(t,n,s):console.error(`Unexpected action category: ${t.category}`)}(s.returnNextAction(),n,t)}}class a extends t{constructor(){super("EnemyTurn")}enter(){super.enter()}exit(){super.exit()}update(t,e){super.update(),n(e,t.getStat("damage"))}}class i extends t{constructor(t,e,n){super("Battle"),this.enemy=t,this.player=e,this.currentTurn=new s,this.battleTimer=0,this.actionQueue=n}enter(){super.enter(),this.currentTurn.enter()}exit(){this.currentTurn.exit(),super.exit(),window.clearInterval(this.battleInterval)}update(t){this.battleTimer+=t,this.battleTimer>=1&&(this.battleTimer=0,super.update(),this.currentTurn.update(this.enemy,this.player,this.actionQueue),this.nextTurn())}isBattleOver(){return this.player.isDead||this.enemy.isDead}resetForNewBattle(t,e){this.enemy=e,this.player=t,this.currentTurn=new s}nextTurn(){this.currentTurn instanceof s?(this.currentTurn.exit(),this.currentTurn=new a,this.currentTurn.enter()):(this.currentTurn.exit(),this.currentTurn=new s,this.currentTurn.enter())}}class r extends t{constructor(){super("Idle")}enter(){super.enter()}exit(){super.exit()}update(){super.update()}}class o extends t{constructor(){super("Death")}enter(){super.enter()}exit(){super.exit()}update(){super.update()}}const c=new Map,d=t=>{const e=c.get(t);if(e)return e;const n=document.getElementById(t);if(!n)throw new TypeError(`Nothing with "${t}" was found.`);return c.set(t,n),n};let l=performance.now();async function h(t){try{const e=await fetch(t);return await e.json()}catch(t){console.error("Error loading JSON file:",t)}}function u(t,e){var n,s,a;for(s=document.getElementsByClassName("tabcontent"),n=0;n{const n=document.createElement("div");n.classList.add("inventory-item-card");const s=document.createElement("h4");if(s.textContent=e.name,n.appendChild(s),e.image){const t=document.createElement("img");t.src=e.image,t.classList.add("inventory-item-image"),n.appendChild(t)}const a=document.createElement("p");a.textContent=e.description,n.appendChild(a);const i=document.createElement("p"),r=Object.entries(e.stats).map((([t,e])=>`${t}: ${e}`));i.textContent=r.join(", "),n.appendChild(i),n.addEventListener("click",(()=>{const t=document.querySelector(".inventory-item-card-selected");t&&t.classList.remove("inventory-item-card-selected"),n.classList.add("inventory-item-card-selected")})),t.appendChild(n)}))}calculateTotalStats(){let t={str:0,sta:0,agi:0,dex:0,wis:0,int:0,cha:0,health:0,damage:0};return this.items.forEach((e=>{Object.keys(e.stats).forEach((n=>{t[n]+=e.stats[n]}))})),t}}window.openTab=u;const f=d("changeState"),x=d("monster"),v=d("player-health-bar"),b=d("enemy-health-bar"),C=d("player-armor-bar"),L=d("enemy-armor-bar"),S=d("player-mana-bar"),T=d("enemy-mana-bar"),E={battle:()=>new i(A,w,N),idle:()=>new r(A,w,N),death:()=>new o(A,w,N)};let w=new class{constructor(){this.maxHP=100,this.maxAP=100,this.maxMP=100,this.health=100,this.isDead=!1,this.armor=10,this.mana=10,this.coins=1e3,this.coinGens=0,this.kills=0,this.inventory=new g(this),this.inventoryStats={},this.healthBar=d("player-health-bar"),h("database/player.json").then((t=>{this.baseStats=t,this.cachedStats={...this.baseStats}})),this.modifiers=[]}getStat(t){return this.cachedStats[t]}recalculateCachedStats(t){for(const e in t)this.cachedStats[e]=this.baseStats[e]+this.inventoryStats[e]}removeCoins(t){return this.coins>=t&&(this.coins-=t,!0)}addCoins(t){this.coins+=t}addItemToInventory(t){this.inventory.addItem(t),this.inventory.populateGrid(),this.inventoryStats=this.inventory.calculateTotalStats(),function(t){const e=d("statsBody");for(;e.firstChild;)e.firstChild.remove();const n=t;for(let[t,s]of Object.entries(n)){const n=document.createElement("tr"),a=document.createElement("td");a.textContent=t,n.appendChild(a);const i=document.createElement("td");i.textContent=s,n.appendChild(i),e.appendChild(n)}}(this.inventoryStats),this.recalculateCachedStats(this.inventoryStats)}},A=new class{constructor(t,e){this.maxHP=0,this.maxAP=100,this.maxMP=100,this.isDead=!1,this.type=t,this.player=e,this.armor=50,this.mana=100,this.monsterImage=d("monster"),this.healthBar=d("enemy-health-bar"),this.baseStats=[],h("database/goblinbrawler.json").then((n=>{this.baseStats=n,this.cachedStats={...this.baseStats},this.health=this.calcHP(t,e)})),d("resetMob").addEventListener("click",(()=>this.resetMob()))}getStat(t){return this.cachedStats[t]}resetMob(){0!=this.isDead&&this.health<=0&&(this.isDead=!1),this.health=this.calcHP(this.type,this.player),this.monsterImage.classList.remove("mirrored"),this.monsterImage.classList.remove("flashing"),this.healthBar.style.backgroundColor="green"}calcHP(t,e){let n=Math.ceil(10*Math.pow(1.02,this.baseStats.health*e.kills));return this.maxHP=n,n}}(50,w);new class{constructor(t){this.items=[],this.player=t;const e=d("buyButton");fetch("database/items.json").then((t=>t.json())).then((t=>{this.items=t,this.populateGrid()})).catch((t=>console.error("Error:",t))),e.addEventListener("click",(()=>{const t=document.querySelector(".shop-item-card-selected"),e=d("shopMessage");if(t){const n=t.getAttribute("data-id"),s=this.buyItem(this.player,n);e.textContent=s}else e.textContent="No item selected."}))}buyItem(t,e){let n=this.items.find((t=>t.id==e));return n?t.removeCoins(n.cost)?(t.addItemToInventory(n),`You bought ${n.name}!`):`You do not have enough coins. This item costs ${n.cost} and you only have ${t.coins} coins.`:"Item does not exist."}populateGrid(){const t=d("itemsGrid");this.items.forEach((e=>{const n=document.createElement("div");n.classList.add("shop-item-card"),n.setAttribute("data-id",e.id);const s=document.createElement("h4");if(s.textContent=e.name,n.appendChild(s),e.image){const t=document.createElement("img");t.src=e.image,t.classList.add("shop-item-image"),n.appendChild(t)}const a=document.createElement("p");a.textContent="Cost: "+e.cost,n.appendChild(a);const i=document.createElement("p");i.textContent=e.description,n.appendChild(i);const r=document.createElement("p"),o=Object.entries(e.stats).map((([t,e])=>`${t}: ${e}`));r.textContent=o.join(", "),n.appendChild(r),n.addEventListener("click",(()=>{const t=document.querySelector(".shop-item-card-selected");t&&t.classList.remove("shop-item-card-selected"),n.classList.add("shop-item-card-selected")})),t.appendChild(n)}))}addItemToShop(t){this.items.push(t)}}(w);const N=new class{constructor(){this.currentActionIndex=0,this.actionQueue=[]}populateActionCards(){let t;fetch("database/actions.json").then((t=>t.json())).then((t=>{for(let e in t)for(let n of t[e]){let t=document.createElement("div");t.className="actionCard",t.draggable=!0,n.category=e,t.dataset.actionObject=JSON.stringify(n);let s=document.createElement("h2");s.textContent=n.title,t.appendChild(s),d("playerActionList").appendChild(t)}})),document.addEventListener("dragstart",(function(e){t=e.target,t.style.opacity=.5}),!1),document.addEventListener("dragend",(function(t){t.target.style.opacity=""}),!1),document.querySelector("#playerActionList").addEventListener("dragover",(t=>{t.preventDefault()}),!1),document.querySelector("#playerActionList").addEventListener("drop",(e=>{"playerActionQueue"!==t.parentNode.id&&"playerActionList"!==t.parentNode.id||(e.preventDefault(),t.cloneNode(!0).style.opacity="","playerActionList"===e.target.id&&"playerActionQueue"===t.parentNode.id&&t.parentNode.removeChild(t))}),!1),document.querySelector("#playerActionQueue").addEventListener("dragover",(t=>{t.preventDefault()}),!1),document.querySelector("#playerActionQueue").addEventListener("drop",(e=>{if("playerActionQueue"===t.parentNode.id||"playerActionList"===t.parentNode.id){e.preventDefault();const n=t.cloneNode(!0);n.style.opacity="";let s=e.target;for(;"playerActionQueue"!==s.id&&!s.classList.contains("actionCard")&&!s.classList.contains("queuedCard");)s=s.parentNode;"playerActionQueue"===s.id?(n.classList.replace("actionCard","queuedCard"),s.appendChild(n)):"playerActionQueue"===t.parentNode.id?(n.classList.replace("actionCard","queuedCard"),s.parentNode.insertBefore(n,s),s.parentNode.insertBefore(s,t)):(n.classList.replace("actionCard","queuedCard"),s.parentNode.insertBefore(n,s.nextSibling)),"playerActionQueue"===t.parentNode.id&&t.parentNode.removeChild(t),this.updateActionQueue(),this.currentActionIndex=0}}),!1)}returnNextAction(){if(this.actionQueue.length>0){const t=this.actionQueue[this.currentActionIndex];return this.currentActionIndex=(this.currentActionIndex+1)%this.actionQueue.length,console.log({currentAction:t}),t}}updateActionQueue(){this.actionQueue=Array.from(d("playerActionQueue").children).filter((t=>"DIV"===t.tagName)).map((t=>JSON.parse(t.dataset.actionObject))),console.log(this.actionQueue)}},I=new class{constructor(t={},e){this.empty={update:function(){},enter:function(){},exit:function(){}},this.states=t,this.current=this.empty,this.buttonText=e}change(t,e){if(!this.states[t])throw new Error(`State ${t} does not exist`);this.current.exit(),this.current=this.states[t](),this.current.enter(e),this.buttonText.textContent=this.current.name}update(t){this.current instanceof i&&this.current.isBattleOver()?this.change("death"):this.current.update(t)}nextTurn(){this.current instanceof i&&(this.current.nextTurn(),this.buttonText.textContent=this.current.currentTurn.name)}}(E,f);(t=>{d("tabButtonFight").addEventListener("click",(t=>u(t,"Fight"))),d("tabButtonStrategy").addEventListener("click",(t=>u(t,"Strategy"))),d("tabButtonInventory").addEventListener("click",(t=>u(t,"Inventory"))),d("tabButtonShop").addEventListener("click",(t=>u(t,"Shop"))),d("tabButtonStats").addEventListener("click",(t=>u(t,"Stats"))),d("buyCoinGen").addEventListener("click",(()=>function(t){let e=Math.floor(10*Math.pow(1.1,t.coinGens));t.coins>=e&&(t.coinGens++,t.coins=t.coins-e)}(t))),d("tabButtonFight").click()})(w),N.populateActionCards(),f.addEventListener("click",(()=>{I.change("battle")})),function t(){const e=function(){const t=performance.now(),e=(t-l)/1e3;return l=t,e}();((t,e)=>{d("coins").innerHTML=t.coins,d("coinGens").innerHTML=t.coinGens,d("enemyHP").innerHTML=e.health,d("playerHP").innerHTML=t.health,d("enemyAP").innerHTML=e.armor,d("playerAP").innerHTML=t.armor,d("enemyMP").innerHTML=e.mana,d("playerMP").innerHTML=t.mana,d("totalKills").innerHTML=t.kills;let n=Math.floor(10*Math.pow(1.1,t.coinGens));d("coinGenCost").innerHTML=n})(w,A),m(w,v),p(w,C),y(w,S),m(A,b,x),p(A,L),y(A,T),I.update(e),requestAnimationFrame(t)}()})(); \ No newline at end of file +(()=>{"use strict";class t{name;constructor(t){this.name=t}enter(){}exit(){}update(){}}const e={attack:function(t,e,s){let a=t.damage*e.getStat("damage")-s.getStat("sta")/2;a=function(t,e,n){let s=t*(1-n.armor/100);return console.log(s),s}(a,0,s),n(s,a)},defensive:function(t,e){let n=t.defenseValue;e.armor+=n},heal:function(t,e){let n=t.healAmount*(e.getStat("wis")/2);e.health+=n},utility:function(t,e,n){console.log(t,e,n)}};function n(t,e){let n=e;return t.health-n<=0&&0==t.isDead?(t.health=0,t.isDead=!0,console.log("You died.")):0==t.isDead&&(t.health-=n,t.monsterImage&&(t.monsterImage.classList.add("shrink"),setTimeout((()=>{t.monsterImage.classList.remove("shrink")}),150))),n}class s extends t{constructor(){super("PlayerTurn")}enter(){super.enter()}exit(){super.exit()}update(t,n,s){super.update(),s.actionQueue.length>0&&function(t,n,s){const a=e[t.category];a?a(t,n,s):console.error(`Unexpected action category: ${t.category}`)}(s.returnNextAction(),n,t)}}class a extends t{constructor(){super("EnemyTurn")}enter(){super.enter()}exit(){super.exit()}update(t,e){super.update(),n(e,t.getStat("damage"))}}class i extends t{constructor(t,e,n){super("Battle"),this.enemy=t,this.player=e,this.currentTurn=new s,this.battleTimer=0,this.actionQueue=n}enter(){super.enter(),this.currentTurn.enter()}exit(){this.currentTurn.exit(),super.exit(),window.clearInterval(this.battleInterval)}update(t){this.battleTimer+=t,this.battleTimer>=1&&(this.battleTimer=0,super.update(),this.currentTurn.update(this.enemy,this.player,this.actionQueue),this.nextTurn())}isBattleOver(){return this.player.isDead||this.enemy.isDead}resetForNewBattle(t,e){this.enemy=e,this.player=t,this.currentTurn=new s}nextTurn(){this.currentTurn instanceof s?(this.currentTurn.exit(),this.currentTurn=new a,this.currentTurn.enter()):(this.currentTurn.exit(),this.currentTurn=new s,this.currentTurn.enter())}}class r extends t{constructor(){super("Idle")}enter(){super.enter()}exit(){super.exit()}update(){super.update()}}class o extends t{constructor(){super("Death")}enter(){super.enter()}exit(){super.exit()}update(){super.update()}}const c=new Map,d=t=>{const e=c.get(t);if(e)return e;const n=document.getElementById(t);if(!n)throw new TypeError(`Nothing with "${t}" was found.`);return c.set(t,n),n};let l=performance.now();async function h(t){try{const e=await fetch(t);return await e.json()}catch(t){console.error("Error loading JSON file:",t)}}function u(t,e){var n,s,a;for(s=document.getElementsByClassName("tabcontent"),n=0;n{const n=document.createElement("div");n.classList.add("inventory-item-card");const s=document.createElement("h4");if(s.textContent=e.name,n.appendChild(s),e.image){const t=document.createElement("img");t.src=e.image,t.classList.add("inventory-item-image"),n.appendChild(t)}const a=document.createElement("p");a.textContent=e.description,n.appendChild(a);const i=document.createElement("p"),r=Object.entries(e.stats).map((([t,e])=>`${t}: ${e}`));i.textContent=r.join(", "),n.appendChild(i),n.addEventListener("click",(()=>{const t=document.querySelector(".inventory-item-card-selected");t&&t.classList.remove("inventory-item-card-selected"),n.classList.add("inventory-item-card-selected")})),t.appendChild(n)}))}calculateTotalStats(){let t={str:0,sta:0,agi:0,dex:0,wis:0,int:0,cha:0,health:0,damage:0};return this.items.forEach((e=>{Object.keys(e.stats).forEach((n=>{t[n]+=e.stats[n]}))})),t}}class g{constructor(t,e,n,s,a,i,r){this.id=t,this.type=e,this.name=n,this.attribute=s,this.value=a,this.duration=i,this.isBuff=r}}window.openTab=u;const v=d("changeState"),x=d("monster"),b=d("player-health-bar"),C=d("enemy-health-bar"),E=d("player-armor-bar"),L=d("enemy-armor-bar"),S=d("player-mana-bar"),T=d("enemy-mana-bar"),w={battle:()=>new i(N,A,I),idle:()=>new r(N,A,I),death:()=>new o(N,A,I)};!function(){const t=[];fetch("database/effects.json").then((t=>t.json())).then((e=>(e.forEach((e=>{const{id:n,type:s,name:a,attribute:i,value:r,duration:o,isBuff:c}=e,d=new g(n,s,a,i,r,o,c);t.push(d)})),console.log(t),t)))}();let A=new class{constructor(){this.maxHP=100,this.maxAP=100,this.maxMP=100,this.health=100,this.isDead=!1,this.armor=10,this.mana=10,this.coins=1e3,this.coinGens=0,this.kills=0,this.inventory=new f(this),this.inventoryStats={},this.healthBar=d("player-health-bar"),h("database/player.json").then((t=>{this.baseStats=t,this.cachedStats={...this.baseStats}})),this.activeEffects=[]}applyEffect(t){this.activeEffects.push({effect:t,remainingDuration:t.duration})}updateEffects(){for(let t=this.activeEffects.length-1;t>=0;t--){const e=this.activeEffects[t];e.remainingDuration--,e.remainingDuration<=0&&this.activeEffects.splice(t,1)}}getStat(t){return this.cachedStats[t]}recalculateCachedStats(t){for(const e in t)this.cachedStats[e]=this.baseStats[e]+this.inventoryStats[e]}removeCoins(t){return this.coins>=t&&(this.coins-=t,!0)}addCoins(t){this.coins+=t}addItemToInventory(t){this.inventory.addItem(t),this.inventory.populateGrid(),this.inventoryStats=this.inventory.calculateTotalStats(),function(t){const e=d("statsBody");for(;e.firstChild;)e.firstChild.remove();const n=t;for(let[t,s]of Object.entries(n)){const n=document.createElement("tr"),a=document.createElement("td");a.textContent=t,n.appendChild(a);const i=document.createElement("td");i.textContent=s,n.appendChild(i),e.appendChild(n)}}(this.inventoryStats),this.recalculateCachedStats(this.inventoryStats)}},N=new class{constructor(t,e){this.maxHP=0,this.maxAP=100,this.maxMP=100,this.isDead=!1,this.type=t,this.player=e,this.armor=50,this.mana=100,this.monsterImage=d("monster"),this.healthBar=d("enemy-health-bar"),this.baseStats=[],h("database/goblinbrawler.json").then((n=>{this.baseStats=n,this.cachedStats={...this.baseStats},this.health=this.calcHP(t,e)})),d("resetMob").addEventListener("click",(()=>this.resetMob()))}getStat(t){return this.cachedStats[t]}resetMob(){0!=this.isDead&&this.health<=0&&(this.isDead=!1),this.health=this.calcHP(this.type,this.player),this.monsterImage.classList.remove("mirrored"),this.monsterImage.classList.remove("flashing"),this.healthBar.style.backgroundColor="green"}calcHP(t,e){let n=Math.ceil(10*Math.pow(1.02,this.baseStats.health*e.kills));return this.maxHP=n,n}}(50,A);new class{constructor(t){this.items=[],this.player=t;const e=d("buyButton");fetch("database/items.json").then((t=>t.json())).then((t=>{this.items=t,this.populateGrid()})).catch((t=>console.error("Error:",t))),e.addEventListener("click",(()=>{const t=document.querySelector(".shop-item-card-selected"),e=d("shopMessage");if(t){const n=t.getAttribute("data-id"),s=this.buyItem(this.player,n);e.textContent=s}else e.textContent="No item selected."}))}buyItem(t,e){let n=this.items.find((t=>t.id==e));return n?t.removeCoins(n.cost)?(t.addItemToInventory(n),`You bought ${n.name}!`):`You do not have enough coins. This item costs ${n.cost} and you only have ${t.coins} coins.`:"Item does not exist."}populateGrid(){const t=d("itemsGrid");this.items.forEach((e=>{const n=document.createElement("div");n.classList.add("shop-item-card"),n.setAttribute("data-id",e.id);const s=document.createElement("h4");if(s.textContent=e.name,n.appendChild(s),e.image){const t=document.createElement("img");t.src=e.image,t.classList.add("shop-item-image"),n.appendChild(t)}const a=document.createElement("p");a.textContent="Cost: "+e.cost,n.appendChild(a);const i=document.createElement("p");i.textContent=e.description,n.appendChild(i);const r=document.createElement("p"),o=Object.entries(e.stats).map((([t,e])=>`${t}: ${e}`));r.textContent=o.join(", "),n.appendChild(r),n.addEventListener("click",(()=>{const t=document.querySelector(".shop-item-card-selected");t&&t.classList.remove("shop-item-card-selected"),n.classList.add("shop-item-card-selected")})),t.appendChild(n)}))}addItemToShop(t){this.items.push(t)}}(A);const I=new class{constructor(){this.currentActionIndex=0,this.actionQueue=[]}populateActionCards(){let t;fetch("database/actions.json").then((t=>t.json())).then((t=>{for(let e in t)for(let n of t[e]){let t=document.createElement("div");t.className="actionCard",t.draggable=!0,n.category=e,t.dataset.actionObject=JSON.stringify(n);let s=document.createElement("h2");s.textContent=n.title,t.appendChild(s),d("playerActionList").appendChild(t)}})),document.addEventListener("dragstart",(function(e){t=e.target,t.style.opacity=.5}),!1),document.addEventListener("dragend",(function(t){t.target.style.opacity=""}),!1),document.querySelector("#playerActionList").addEventListener("dragover",(t=>{t.preventDefault()}),!1),document.querySelector("#playerActionList").addEventListener("drop",(e=>{"playerActionQueue"!==t.parentNode.id&&"playerActionList"!==t.parentNode.id||(e.preventDefault(),t.cloneNode(!0).style.opacity="","playerActionList"===e.target.id&&"playerActionQueue"===t.parentNode.id&&t.parentNode.removeChild(t))}),!1),document.querySelector("#playerActionQueue").addEventListener("dragover",(t=>{t.preventDefault()}),!1),document.querySelector("#playerActionQueue").addEventListener("drop",(e=>{if("playerActionQueue"===t.parentNode.id||"playerActionList"===t.parentNode.id){e.preventDefault();const n=t.cloneNode(!0);n.style.opacity="";let s=e.target;for(;"playerActionQueue"!==s.id&&!s.classList.contains("actionCard")&&!s.classList.contains("queuedCard");)s=s.parentNode;"playerActionQueue"===s.id?(n.classList.replace("actionCard","queuedCard"),s.appendChild(n)):"playerActionQueue"===t.parentNode.id?(n.classList.replace("actionCard","queuedCard"),s.parentNode.insertBefore(n,s),s.parentNode.insertBefore(s,t)):(n.classList.replace("actionCard","queuedCard"),s.parentNode.insertBefore(n,s.nextSibling)),"playerActionQueue"===t.parentNode.id&&t.parentNode.removeChild(t),this.updateActionQueue(),this.currentActionIndex=0}}),!1)}returnNextAction(){if(this.actionQueue.length>0){const t=this.actionQueue[this.currentActionIndex];return this.currentActionIndex=(this.currentActionIndex+1)%this.actionQueue.length,console.log({currentAction:t}),t}}updateActionQueue(){this.actionQueue=Array.from(d("playerActionQueue").children).filter((t=>"DIV"===t.tagName)).map((t=>JSON.parse(t.dataset.actionObject))),console.log(this.actionQueue)}},M=new class{constructor(t={},e){this.empty={update:function(){},enter:function(){},exit:function(){}},this.states=t,this.current=this.empty,this.buttonText=e}change(t,e){if(!this.states[t])throw new Error(`State ${t} does not exist`);this.current.exit(),this.current=this.states[t](),this.current.enter(e),this.buttonText.textContent=this.current.name}update(t){this.current instanceof i&&this.current.isBattleOver()?this.change("death"):this.current.update(t)}nextTurn(){this.current instanceof i&&(this.current.nextTurn(),this.buttonText.textContent=this.current.currentTurn.name)}}(w,v);(t=>{d("tabButtonFight").addEventListener("click",(t=>u(t,"Fight"))),d("tabButtonStrategy").addEventListener("click",(t=>u(t,"Strategy"))),d("tabButtonInventory").addEventListener("click",(t=>u(t,"Inventory"))),d("tabButtonShop").addEventListener("click",(t=>u(t,"Shop"))),d("tabButtonStats").addEventListener("click",(t=>u(t,"Stats"))),d("buyCoinGen").addEventListener("click",(()=>function(t){let e=Math.floor(10*Math.pow(1.1,t.coinGens));t.coins>=e&&(t.coinGens++,t.coins=t.coins-e)}(t))),d("tabButtonFight").click()})(A),I.populateActionCards(),v.addEventListener("click",(()=>{M.change("battle")})),function t(){const e=function(){const t=performance.now(),e=(t-l)/1e3;return l=t,e}();((t,e)=>{d("coins").innerHTML=t.coins,d("coinGens").innerHTML=t.coinGens,d("enemyHP").innerHTML=e.health,d("playerHP").innerHTML=t.health,d("enemyAP").innerHTML=e.armor,d("playerAP").innerHTML=t.armor,d("enemyMP").innerHTML=e.mana,d("playerMP").innerHTML=t.mana,d("totalKills").innerHTML=t.kills;let n=Math.floor(10*Math.pow(1.1,t.coinGens));d("coinGenCost").innerHTML=n})(A,N),p(A,b),m(A,E),y(A,S),p(N,C,x),m(N,L),y(N,T),M.update(e),requestAnimationFrame(t)}()})(); \ No newline at end of file diff --git a/src/combat.js b/src/combat.js index 49313a4..73865c7 100644 --- a/src/combat.js +++ b/src/combat.js @@ -50,7 +50,7 @@ export function calculateMitigation(damage, source, target){ } //deprecating this asap and moving to processAction once enemy abilities are implemented -export function calculateAttackDMG(source, target) { +export function calculateAttackDMG(source) { let dmgAMT = source.getStat('damage'); return dmgAMT; } diff --git a/src/effects.js b/src/effects.js new file mode 100644 index 0000000..d40bec1 --- /dev/null +++ b/src/effects.js @@ -0,0 +1,27 @@ +export class Effect { + constructor(id, type, name, attribute, value, duration, isBuff) { + this.id = id; + this.type = type; + this.name = name; + this.attribute = attribute; + this.value = value; + this.duration = duration; + this.isBuff = isBuff; + } +} + +export function loadEffectsFromJSON () { + const effects = []; + + fetch('database/effects.json') + .then(response => response.json()) + .then(effectsArray => { + effectsArray.forEach(effectData => { + const { id, type, name, attribute, value, duration, isBuff } = effectData; + const effect = new Effect(id, type, name, attribute, value, duration, isBuff); + effects.push(effect); + }); + console.log(effects); + return effects; + }); +} \ No newline at end of file diff --git a/src/main.js b/src/main.js index 6ed0b48..8b854e4 100644 --- a/src/main.js +++ b/src/main.js @@ -13,6 +13,7 @@ import { Player } from "./player.js"; import { Shop } from './shop.js'; import { populateDOMEventCache, updateAllOfTheThings } from "./events.js"; import { ActionQueueManager } from './actions.js'; +import { loadEffectsFromJSON } from "./effects.js"; // references necessary for function calls from modules window.openTab = openTab; @@ -35,6 +36,8 @@ const states = { death: () => new DeathState(enemy, player, actionQueueManager) }; +const CombatEffects = loadEffectsFromJSON(); + // initialize game objects let player = new Player(); let enemy = new Enemy(50, player); @@ -42,6 +45,7 @@ let shop = new Shop(player); const actionQueueManager = new ActionQueueManager(); const stateMachine = new StateMachine(states, changeStateButton); + // run initialization events populateDOMEventCache(player); actionQueueManager.populateActionCards(); diff --git a/src/player.js b/src/player.js index ac39bb3..f4f92d9 100644 --- a/src/player.js +++ b/src/player.js @@ -16,6 +16,7 @@ export class Player { this.coins = 1000; this.coinGens = 0; this.kills = 0; + this.inventory = new Inventory(this); this.inventoryStats = {}; @@ -26,39 +27,34 @@ export class Player { this.cachedStats = { ...this.baseStats }; }); - this.modifiers = []; + this.activeEffects = []; } - // addModifier(modifier) { - // this.modifiers.push(modifier); - // this.recalculateCachedStats(Object.keys(modifier.statsAffected)); - // } + //undecided on how to structure effects, going with a record+int approach for now + applyEffect(effect) { + this.activeEffects.push({ + effect: effect, + remainingDuration: effect.duration + }); + } - // removeModifier(modifierId) { - // const index = this.modifiers.findIndex(mod => mod.id === modifierId); - // if (index !== -1) { - // const [removedModifier] = this.modifiers.splice(index, 1); - // this.recalculateCachedStats(Object.keys(removedModifier.statsAffected)); - // } - // } + updateEffects() { + for (let i = this.activeEffects.length - 1; i >= 0; i--) { + const activeEffect = this.activeEffects[i]; + activeEffect.remainingDuration--; + + if (activeEffect.remainingDuration <= 0) { + //remove effect here, but does this cancel it midway in the current tick? + //this might remove it and steal the benefit/penalty of the final tick - TBD + this.activeEffects.splice(i, 1); + } + } + } getStat(statName) { return this.cachedStats[statName]; } - // recalculateCachedStats(statsAffectedArray) { - // for (let stat of statsAffectedArray) { - // this.cachedStats[stat] = this.baseStats[stat]; - - // for (let modifier of this.modifiers) { - // if (modifier.statsAffected[stat] && (!modifier.condition || modifier.condition())) { - // this.cachedStats[stat] += modifier.statsAffected[stat]; - // } - // } - // } - // } - - recalculateCachedStats(statsArray) { for (const stat in statsArray) { this.cachedStats[stat] = this.baseStats[stat] + this.inventoryStats[stat];