#### Battles in Kallisor

```//initiate variables. var herbPower = 10; var herbCost = 25; var numberBattles = 0; var monstersFought = []; var monsters = GetMonsterList(); //Welcome the player to the game var display = "Welcome to Battles in Kallisor."; display += "\r\rIn this simulation, you will battle against a random creature. "; display += "If you win, you get some gold and maybe an item or two. "; display += "If you lose, it's game over."; display += "\r\rHerbs restore about " + herbPower + " Hit Points. You have a limited supply."; display += "\r\rIn this version, there are " + monsters.length + " types of monsters you may battle."; Show(display); var hero = GetHero(); var stillPlaying = true; while (stillPlaying) { //choose a random monster based on hero level var monster; if (hero.level > monsters.length && Math.random() < 0.3) { monster = MakeRandomMonster(hero); } else { var maxRange = Math.min(monsters.length, hero.level + 2) var rand = Math.floor(Math.random() * maxRange); //this creates a copy of the source monster so the original data doesn't get overwritten monster = CloneMonster(monsters[rand]); } //keep a tally of battles and monsters fought //technically numbersBattles will be equal to monstersFought.length //but they're different ideas so we're keeping different variables //in the future, if we change monstersFought to only track which kind of monster instead of each monster, then we'd still want the numberBattles counter anyway numberBattles++; monstersFought.push(monster.Name); //let the player know they've been attacked Show("You are attacked by a " + monster.Name + "!"); //Let the monster have a chance to strike first based on a random factor that's based on the difference between the monster's stats and yours var monsterFirst = false; var monsterRun = false; var monSum = monster.HPMax + monster.attack + monster.defense; var heroSum = hero.HPMax + hero.attack + monster.defense; var statDifference = monSum - heroSum; var chance = Math.floor(Math.random() * 500) if (chance > 0 && chance < statDifference) { monsterFirst = true; Show("The " + monster.Name + " surprises you and attacks first!"); } if (chance < 0 && Math.abs(chance) < statDifference) { monsterRun = true; } //this starts a battle loop //each time through the loop, the player will act, then the monster will act var inBattle = true; while (inBattle) { if (!monsterFirst) { //This starts a loop to get input from the user. We're using a loop here in case the user enters an unexpected value; we can ask again for input until we have a valid response var getCommand = true; while (getCommand) { //This sets up the battle dialogue. If we had this on a web page, we would do this differently. We'd have a stats section, etc. instead of putting it all in like this. display = "You are battling one " + monster.Name; if (hero.sightScope) { display += " (HP: " + monster.HP + ")"; } display += ".\r\r"; display += "Your HP: " + hero.HP + "/" + hero.HPMax; display += "\rYour herbs: " + hero.herbs; display += "\r\rWould you like to:\r"; display += "(f)ight\r"; //This if statement only shows the herb option if you actually have herbs. if (hero.herbs >= 1) { display += "(u)se an herb\r"; } display += "(r)un away\r"; display += "(q)uit\r"; var action = prompt(display); action = action.substring(0, 1).toLowerCase(); if (action === "f" || ((action === "u" || action === "h") && hero.herbs >= 1) || action === "r" || action === "q") { getCommand = false; } } var monsterWillAttack = true; //initiate the fight command if (action === "f") { DoAttack(hero, monster); if (monster.HP <= 0) { monsterWillAttack = false; inBattle = false; AwardPrizes(hero, monster); } } //this allows the player to use herbs with 'u' or 'h' but only if they have herbs else if ((action === "u" || action === "h") && hero.herbs >= 1) { var herbHeal = UseHerb(hero); Show("The herb healed you " + herbHeal + " points. Your HP is now " + hero.HP + "."); } //get ready to try to run else if (action === "r") { Show("You try to run away from the " + monster.Name + "."); if (RunFromBattle(hero)) { Show("You successfully escaped that battle!"); monsterWillAttack = false; inBattle = false; } else { Show("You were not able to run away."); } } //quit the game else if (action === "q") { monsterWillAttack = false; inBattle = false; stillPlaying = false; break; } } monsterFirst = false; //Monster fights back if (monsterWillAttack) { if (monster.HP < (monster.HPMax / 2) && (Math.random() * 1000) < monster.herbs) { UseHerb(monster); Show("The " + monster.Name + " used an herb to heal."); } else if (monsterRun && (Math.random() * 500 < 10)) { Show("The monster ran away!"); inBattle = false; } else { DoAttack(monster, hero); if (hero.HP <= 0) //oh no, you died { inBattle = false; stillPlaying = false; } } } // from MonsterFightsBack } // from (while (inBattle) if (stillPlaying) { BuyHerb(hero); } } // from (while (stillPlaying)) if (hero.HP <= 0) { display = "You have died.\r\r"; } else { display = "You live to battle another day.\r\r"; } display += hero.Name + "'s final stats:\r"; display += "HP: " + hero.HP + "/" + hero.HPMax; display += "\rUnused Herbs: " + hero.herbs; display += "\rTotal experience points: " + hero.exp; display += "\rTotal gold accumulated: " + hero.gold; display += "\rAttack power: " + hero.attack; display += "\rDefense power: " + hero.defense; display += "\r\rNumber of battles fought: " + numberBattles; display += "\rMonsters battled:\r"; display += monstersFought; display += "\r\rBe sure to play again!"; Show(display); //End of Game function AwardPrizes(h, m) { var display = "The " + m.Name + " was defeated.\r\r"; display += h.Name + " earns " + m.exp + " experience points and " + m.gold + " gold.\r\r"; h.exp += m.exp; h.gold += m.gold; //see if you find an herb from the monster if ((Math.random() * 100) < m.herbs) { display += h.Name + " found an herb!"; h.herbs++; } Show(display); //see if you get stronger LevelUp(hero); //let's have after-battle recovery var healUp = Math.floor(Math.random() * (hero.HPMax - hero.HP)); hero.HP += healUp; hero.HP = Math.min(hero.HP, hero.HPMax); if (healUp > 1) { Show("You get some rest after the battle and recover " + healUp + " hit points."); } else if (healUp === 1) { Show("You get a little rest after the battle and recover " + healUp + " hit point."); } } function DoAttack(attacker, defender) { var display = ""; var attName = attacker.Name; var defName = defender.Name; if (attacker.Name === monster.Name) { attName = "The " + attacker.Name; } else { defName = "the " + defender.Name; } display += attName + " attacks! \r\r"; var range = 5; var att = attacker.attack + Math.floor(Math.random() * range) - (Math.floor(range / 2)); var def = defender.defense + Math.floor(Math.random() * range) - (Math.floor(range / 2)); var damage = Math.max(0, (att - def)) if (damage === 0) { damage = Math.floor(Math.random() * 2); } if (damage > 0) { display += attName + " does " + damage + " point"; if (damage > 1) { display += "s"; } display += " of damage to " + defName + "!"; defender.HP -= damage; defender.HP = Math.max(0, defender.HP); } else { display += attName + " misses! No damage is scored." } Show(display); } function BuyHerb(h) { while (h.gold >= herbCost) { display = "An herb costs " + herbCost + " gold. \r\r"; display += "You currently have " + h.herbs + " herb"; if (h.herbs !== 0) { display += "s" } display += " and " + h.gold + " gold pieces.\r\r"; display += "Do you want to buy an herb?"; display += "\r\r(y)es \r\r(n)o "; var getInput = true; while (getInput) { var userInput = prompt(display); userInput = userInput.substring(0,1).toLowerCase(); if (userInput !== "y" && userInput !== "n") { continue; } if (userInput === "n") { getInput = false; return; } if (userInput === "y") { getInput = false; h.gold -= herbCost; h.herbs++; } } } } function UseHerb(h) { var range = 5; var herbHeal = Math.floor(Math.random() * range) - (Math.floor(range / 2)); herbHeal = herbPower + herbHeal; h.HP += herbHeal; h.HP = Math.min(h.HP, h.HPMax); h.herbs--; return herbHeal; } function RunFromBattle(h) { var runChecker = Math.floor(Math.random() * 100); return (runChecker < h.runRate); } function Show(text, alrt = true) { console.log(text) if (alrt) { alert(text); } } function GetHero() { var n = prompt("What is your character's name?", "Dariak"); //var n = "Dariak"; var h = { Name: n, HPMax: 20, herbs: 2, gold: 0, exp: 0, attack: 5, defense: 3, runRate: 25, level: 1, sightScope: false }; h.HP = h.HPMax; return h; } //Decide if the hero levels up! function LevelUp(h) { var text = ""; var levelChanged = true; var HPInc = 0; var attInc = 0; var defInc = 0; var totalAttInc = 0; var totalDefInc = 0; while (levelChanged) { levelChanged = false; //we want the loop to run at least once (instead of using a do/while loop) switch (h.level) { case 1: { if (h.exp > 5) { levelChanged = true; HPInc = 2; attInc = 1; defInc = 1; } break; } case 2: { if (h.exp > 15) { levelChanged = true; HPInc = 4; attInc = 1; defInc = 1; h.sightScope = true; } break; } case 3: { if (h.exp > 30) { levelChanged = true; HPInc = 5; attInc = 2; defInc = 1; } break; } case 4: { if (h.exp > 50) { levelChanged = true; HPInc = 10; attInc = 1; defInc = 2; } break; } default: //keep growing if specific levels are not set { if (h.exp > (15 * h.level)) { levelChanged = true; HPInc = h.level * 3; attInc = (h.level + 1) % 3; defInc = (h.level + 0) % 3; break; } } } //totalAttInc += attInc; //totalDefInc += defInc; if (levelChanged) { h.level++; h.attack += attInc; h.defense += defInc; h.HPMax += HPInc; h.HP += HPInc; //give some HP for levelling up text = "\r\rCongratulations! You leveled up!\r\r"; text += "You're now level " + h.level + ".\r\r"; text += "Your hit points increased by " + HPInc + " and is now " + h.HPMax + ".\r"; text += "Your attack power increased by " + attInc + " and is now " + h.attack + ".\r"; text += "Your defense power increased by " + defInc + " and is now " + h.defense + ".\r"; if (h.sightScope) { text += "\r\rYou've learned a lot about your foes. You can now see their remaining HP."; } Show(text); } } return; } //This creates a copy of the monster so the original monster data is not overwritten function CloneMonster(m) { var cm = { Name: m.Name, HPMax: m.HPMax, HP: m.HPMax, herbs: m.herbs, gold: m.gold, exp: m.exp, attack: m.attack, defense: m.defense } return cm; } function PlusMinusHalf(number) { var newNumber = 0; newNumber = Math.floor(Math.random() * number) - (number / 2); newNumber = number + newNumber; newNumber = Math.floor(newNumber); return newNumber; } function MakeRandomMonster(h) { var monHP = PlusMinusHalf(h.HPMax); var monHerbs = h.level * 5; var monAttack = PlusMinusHalf(h.attack); var monDefense = PlusMinusHalf(h.defense); var monExp = Math.ceil(Math.random() * h.level + PlusMinusHalf(h.level)); var monGold = Math.ceil(Math.random() * h.level + PlusMinusHalf(h.level)); var monName = GenerateRandomName(); var mon = { Name: monName, HPMax: monHP, herbs: monHerbs, gold: monGold, exp: monExp, attack: monAttack, defense: monDefense }; return mon; } function GenerateRandomName() { var makeName = ""; var nameSnippets = ["dra", "con", "us", "mon", "ty", "mer", "lin", "ti", "ger", "max", "bus", "ter", "bud", "dy", "med", "usa"]; var rand = Math.ceil(Math.random() * 4) + 2; var rand2; for (var i = 0; i < rand; i++) { rand2 = Math.floor(Math.random() * nameSnippets.length); makeName += nameSnippets[rand2]; } return makeName; } //This sets the list of monsters with all their stats. function GetMonsterList() { var m = []; var mon = ////to add a monster, copy from this line down... { Name: "squirret", //monster's name HPMax: 5, //monster's Max and starting hit points herbs: 10, //likelihood of monster using an herb gold: 2, //amount of gold won for defeating monster exp: 2, //amount of experience for defeating monster attack: 2, //monster's attack strength defense: 2 //monster's defense rate }; m.push(mon); ////...to here to add a monster mon = { Name: "swallomer", HPMax: 10, herbs: 25, gold: 3, exp: 3, attack: 4, defense: 3 }; m.push(mon); mon = { Name: "gleese", HPMax: 12, herbs: 30, gold: 6, exp: 6, attack: 3, defense: 6 }; m.push(mon); mon = { Name: "rodia", HPMax: 14, herbs: 20, gold: 8, exp: 7, attack: 5, defense: 8 }; m.push(mon); mon = { Name: "eaglon", HPMax: 18, herbs: 50, gold: 10, exp: 8, attack: 5, defense: 8 }; m.push(mon); mon = { Name: "lupino", HPMax: 25, herbs: 50, gold: 15, exp: 11, attack: 8, defense: 9 }; m.push(mon); mon = { Name: "tigroar", HPMax: 28, herbs: 60, gold: 18, exp: 10, attack: 9, defense: 10 }; m.push(mon); //after all the monsters have been added, send them onward return m; } ```