**test** [[pizza]] <% story.passage("twine-functionality").render() %> <% story.passage("interface_scripts").render() %> <% story.passage("combat-object").render() %><% story.passage("stats").render() %> <% story.passage("abilities").render() %> <% story.passage("combat_functions").render() %> <% story.passage("apply-effect").render() %> <% story.passage("enemy-behavior").render() %> <% story.passage("miscCombat").render() %> <% story.passage("damage-calculations").render() %> <% story.passage("status-box").render() %> <% player = new monsters.Goblin() %> <% player.EXP = 0 %> Health is <%= player.health %>, race is <%= player.race %>. <% enemy = new monsters.Rabbit() %> [[setFight]]<!-- Set up parties of ally and enemy combatants --> <% player2 = new monsters.Succubus(); enemy2 = new monsters.Skeleton() %> <% allies = [player, player2] %> <% enemies = [enemy, enemy2] %> <% //turnOrder = arrangeTurns(allies, enemies); %> <% currentFight = new initiateCombat(allies, enemies); %> <% gameOverScreen = "start"; print(startFight(allies, enemies, "Hub")); %>/% UI that always shows %/ <br> You have <%= player.EXP %> experience<br> <% // if player has enough experience, show upgrade screen if (player.EXP >= 10){ print("You can tier up!<br>"); if (player.upgrades == null){ print("No known upgrade path<br>"); } else{ print("[[UpgradeScreen]]"); } } // otherwise start the next fight else{ print("Select an enemy<br>" + setterLink('fight a rabbit', 'setFight', 'enemy = new monsters.Rabbit()') + "<br>" + setterLink('fight a goblin', 'setFight', 'enemy = new monsters.Goblin()') + "<br>" + setterLink('fight a hobgoblin', 'setFight', 'enemy = new monsters.Hobgoblin()')); } %><% // create setter link for each upgrade option of current race for(i = 0; i<player.upgrades.length; i++){ print(setterLink("Upgrade to " + player.upgrades[i] + "<br>", "Hub", "player = new monsters." + player.upgrades[i] + "(); player.EXP = 0")) } %><% Monster = function(){ this.abilities = [combatAbilities.attack]; this.magic = 0; } monsters = {}; monsters.Rabbit = function(){ Monster.call(this); this.race = "rabbit"; this.abilities.push(combatAbilities.heal); this.health = 10; this.maxHP = 10; this.attack = 2; this.magic = 2; this.XP = 5; } monsters.Rabbit.prototype = Object.create(Monster.prototype); monsters.RatSwarm = function(){ Monster.call(this); this.race = "rat swarm"; this.health = 15; this.maxHP = 15; this.attack = 2; this.XP = 10; this.resistance = ["slashing"]; } monsters.RatSwarm.prototype = Object.create(Monster.prototype); monsters.GiantSpider = function(){ Monster.call(this); this.abilities.push(combatAbilities.poison); this.race = "giant spider"; this.health = 20; this.maxHP = 20; this.attack = 4; this.XP = 10; } monsters.GiantSpider.prototype = Object.create(Monster.prototype); monsters.Goblin = function(){ Monster.call(this); this.abilities.push(combatAbilities.poison); this.abilities.push(combatAbilities.paralyze); this.race = "goblin"; this.health = 20; this.maxHP = 20; this.attack = 4; this.XP = 10; this.upgrades = ["Hobgoblin"]; } monsters.Goblin.prototype = Object.create(Monster.prototype); monsters.Hobgoblin = function(){ Monster.call(this); this.race = "hobgoblin"; this.abilities.push(combatAbilities.Rabbit_Slaying_Sword); this.health = 30; this.maxHP = 30; this.attack = 7; this.XP = 15; this.upgrades = ["Ogre", "Ghoul"]; } monsters.Hobgoblin.prototype = Object.create(Monster.prototype); monsters.Ogre = function(){ Monster.call(this); this.race = "ogre"; this.health = 40; this.maxHP = 40; this.attack = 10; this.XP = 20; } monsters.Ogre.prototype = Object.create(Monster.prototype); monsters.Ghoul = function(){ Monster.call(this); this.race = "ghoul"; this.health = 35; this.maxHP = 35; this.attack = 12; this.XP = 20; } monsters.Ghoul.prototype = Object.create(Monster.prototype); monsters.Skeleton = function(){ Monster.call(this); this.race = "skeleton"; this.health = 15; this.maxHP = 15; this.attack = 3; this.XP = 7; this.resistance = ["slashing"]; this.immune = ["poison"]; } monsters.Skeleton.prototype = Object.create(Monster.prototype); monsters.Succubus = function(){ Monster.call(this); this.race = "succubus"; this.health = 15; this.maxHP = 15; this.attack = 2; this.XP = 15; this.abilities.push(combatAbilities.charm); } monsters.Succubus.prototype = Object.create(Monster.prototype); monsters.AnimateCandle = function(){ Monster.call(this); this.race = "Animate Candle"; this.health = 10; this.maxHP = 10; this.attack = 2; this.XP = 5; this.abilities.push(combatAbilities.flame); this.absorbs = ["fire"]; } monsters.AnimateCandle.prototype = Object.create(Monster.prototype); monsters.DireWolf = function(){ Monster.call(this); this.race = "dire wolf"; this.health = 50; this.maxHP = 50; this.attack = 10; this.XP = 20; this.abilities.push(combatAbilities.roar); } monsters.DireWolf.prototype = Object.create(Monster.prototype); %><% combatAbilities = {}; // returns a soft link for an ability combatAbilities.getName = function(ability){ return "combatAbilities." + ability.name; }; // basic attack combatAbilities.attack = { name: "attack", damage: 0, targetType: "single" } // poison attack combatAbilities.poison = { name: "poison", poison: 4, targetType: "single" } // charm an enemy to fight for you combatAbilities.charm = { name: "charm", charm: 50 } // heal someone combatAbilities.heal = { name: "heal", heal: 2, beneficial: 1 } // paralyze someone combatAbilities.paralyze = { name: "paralyze", paralyze: 2 } combatAbilities.roar = { name: "roar", paralyze: 2, targetType: "AoE" } // generic weak fire attack combatAbilities.flame = { name: "flame", damage: 0, damageType: ["fire"] } //Goblin-slaying sword combatAbilities.Rabbit_Slaying_Sword = { name: "Rabbit_Slaying_Sword", damage: 0, damageType: "slashing", condition: function(attacker, target){ return target.race == "rabbit"; }, conditionEffect: { name: "extra damage to rabbits", damage: 5, damageType: ["slashing"] } } // AoE charms rats, no one else. combatAbilities.SewerSong = { name: "SewerSong", targetType: "AoE", condition: function(attacker, target){ return (target.race == "giant rat" || target.race == "rat swarm"); }, conditionEffect: { name: "ratWhisperer", charm: 100 } } %><% // create a setter link setterLink = function(display, target, script){ script = script.replace(/'/g, "\""); return "<a onclick='" +script + "' href='javascript:void(0)' data-passage=" + target + ">" + display + "</a>" } %><!-- select who to attack [[combat]] --> <% print("" + currentFight.currentActor().race + " will use " + chosenAbility.name + " on which target?<br>"); currentFight.targetScreen.selectTarget(currentFight.enemies, currentFight.allies, chosenAbility); print(currentFight.targetScreen.displayScreen()); %><!-- Anything in this section is just for debugging purposes --> <!-- check status effects before updating UI --> <% if (currentFight.actorIsPC() && !partyDefeated(enemies) && !currentFight.currentActor().needsTarget){ messageBoxes.messageScreen.addMessage("It's " + currentFight.currentActor().race + "'s turn."); currentFight.currentActor().checkStatusEffects(); } %> <!-- A UI informing the player of combatant status --> <% print(messageBoxes.statusScreenEnemies.printEnemyStatus(currentFight.enemies)); print(messageBoxes.statusScreenAllies.printAllyStatus(currentFight.allies)); %> <!-- A UI explaining what has happened since the last time you selected an option --> <% print("<div class='message-box' style='height:400px; overflow:scroll'>" + messageBoxes.messageScreen.displayScreen() + "</div>") %> --- <!-- Stuff that happens upon victory or defeat --> <% if(partyDefeated(allies)){ print(setterLink("You lost.", gameOverScreen, "$(document.body).removeClass('widen');")); } else if (partyDefeated(enemies)){ awardXP(allies, currentFight.xpAward); xpAward = 0; currentFight.allies[0].partyFullHeal(currentFight.allies); print(setterLink("You won!", returnFromCombat, "$(document.body).removeClass('widen');")); } <!-- Actions you can take this combat round --> else if (!currentFight.currentActor().needsTarget){ currentFight.takeAction(); // currentFight.currentActor().hasTarget = 1; print(currentFight.abilityScreen.displayScreen()); } <!-- Targets you can select from --> else{ print("" + currentFight.currentActor().race + " will use " + chosenAbility.name + " on which target?<br>"); currentFight.targetScreen.selectTarget(currentFight.enemies, currentFight.allies, chosenAbility); print(currentFight.targetScreen.displayScreen()); currentFight.currentActor().needsTarget = 0; } %><% // enemy takes an action Monster.prototype.autoAction = function(team, targets){ var chosenAbility = this.abilities[Math.floor(Math.random()*this.abilities.length)]; //if the ability is beneficial, use it on an ally instead of an enemy if(chosenAbility.beneficial){ var temp = team; team = targets; targets = temp; } //check that attacker is able to attack and has a potential target if(!this.fightPossible(team, targets) || this.paralyze){ return; } if(this.charm) { var targets = this.autoSelectTarget(chosenAbility, team); } else {var targets = this.autoSelectTarget(chosenAbility, targets);} this.applyEffect(chosenAbility, targets); } // check that attacker is alive and has potential targets Monster.prototype.fightPossible = function(team, targets){ if (partyDefeated(team) || partyDefeated(targets)){ return 0; } if (isDead(this)){ return 0; } else{ return 1; } } //enemy selects target Monster.prototype.autoSelectTarget = function(ability, targets){ var validTargets = []; for(var i=0; i<targets.length; i++){ if(!isDead(targets[i]) && !(targets[i].charm > 0)){ validTargets.push(targets[i]); } } if(ability.targetType == "AoE"){ return targets; } else { return [validTargets[Math.floor(Math.random()*validTargets.length)]]; } } %><% messageBoxes = {}; messageBoxes.MessageBox = function(){ this.title = ""; this.toDisplay = ""; } messageBoxes.messageScreen = new messageBoxes.MessageBox(); messageBoxes.statusScreenAllies = new messageBoxes.MessageBox(); messageBoxes.statusScreenEnemies = new messageBoxes.MessageBox(); // add a message to a message screen messageBoxes.MessageBox.prototype.addMessage = function(message){ this.toDisplay += message + "<br>"; } // display and empty a status screen messageBoxes.MessageBox.prototype.displayScreen = function(){ var display = this.toDisplay; this.toDisplay = ""; return display; } // add an ability setter-link to a message box (will need to change "select-target" to "combat" later) messageBoxes.MessageBox.prototype.addAbility = function(ability){ var setLink = setterLink(ability.name, "combat", "chosenAbility = " + combatAbilities.getName(ability)); this.addMessage(setLink); } // add all a character's abilities to a message box messageBoxes.MessageBox.prototype.addAbilities = function(attacker){ for(var i=0;i<attacker.abilities.length; i++){ this.addAbility(attacker.abilities[i]); } } // add a target to the target screen messageBoxes.MessageBox.prototype.addTarget = function(targets, enemyIndex, targetsName, ability){ var display = targets[enemyIndex].race + "'s health is " + targets[enemyIndex].health; var setLink = setterLink(display, "combat", "currentFight.currentActor().applyEffect(" + combatAbilities.getName(ability) + ", [currentFight." + targetsName + "[" + enemyIndex + "]]); currentFight.nextTurn()"); this.addMessage(setLink); } // add an array of targets individually to the target screen messageBoxes.MessageBox.prototype.addTargets = function(targets, targetsName, ability){ for(var i=0; i<targets.length; i++){ if(!isDead(targets[i])){ this.addTarget(targets, i, targetsName, ability); } } } // add a message to attack an entire party with an AoE. messageBoxes.MessageBox.prototype.addAoE = function(targets, ability){ var setLink = setterLink("attack entire party", "combat", "currentFight.currentActor().applyEffect(" + combatAbilities.getName(ability) + ", currentFight." + targets + "); currentFight.nextTurn()"); this.addMessage(setLink); } // given a certain ability, add a target selection screen to a message box. messageBoxes.MessageBox.prototype.selectTarget = function(enemies, allies, ability){ if (ability.targetType == "AoE"){ this.addMessage("<br>Target allies:"); this.addAoE("allies", ability); this.addMessage("<br>Target enemies:"); this.addAoE("enemies", ability); } else{ this.addMessage("<br>Target an ally:"); this.addTargets(allies, "allies", ability); this.addMessage("<br>Target an enemy:"); this.addTargets(enemies, "enemies", ability); } } %><% initiateCombat = function(allies, enemies){ this.allies = allies; this.enemies = enemies; this.turnOrder = allies.concat(enemies); this.currentTurn = 0; this.xpAward = this.addXP(enemies); this.abilityScreen = new messageBoxes.MessageBox(); this.targetScreen = new messageBoxes.MessageBox(); }; // create a setter-link to start combat startFight = function(allies, enemies, victoryPassage){ var setVictoryPassage = "returnFromCombat = '" + victoryPassage + "';"; var widen = "$(document.body).addClass('widen');"; // var setUpFight = "currentFight = new initiateCombat(allies, enemies);"; return setterLink("Fight!", "combat", setVictoryPassage + widen); } // not currently used for anything. initiateCombat.prototype.setTurnOrder = function(){ // var turnOrder = this.allies.concat(this.enemies); return ""; }; // figure out whose turn it is initiateCombat.prototype.currentActor = function(){ return this.turnOrder[this.currentTurn]; }; // determine if the current character is a PC initiateCombat.prototype.actorIsPC = function(){ if (this.allies.indexOf(this.currentActor()) > -1){ return 1; } else { return 0; } }; // advance to the next person's turn initiateCombat.prototype.nextTurn = function(){ this.currentTurn = (this.currentTurn + 1) % this.turnOrder.length; while(isDead(this.currentActor()) && !isDefeated(this.allies) && !isDefeated(this.enemies)){ this.currentTurn = (this.currentTurn + 1) % this.turnOrder.length; } }; // automatically perform actions until the next active PC's turn initiateCombat.prototype.autoConsecAction = function(){ while((!this.actorIsPC() || this.currentActor().charm || this.currentActor().paralyze > 1) && !partyDefeated(this.allies)){ this.currentActor().checkStatusEffects(); if(!this.actorIsPC()){ this.currentActor().autoAction(this.enemies, this.allies); } else if (this.currentActor().charm || isDead(this.currentActor()) || this.currentActor().paralyze){ this.currentActor().autoAction(this.allies, this.enemies); } this.nextTurn(); } }; // whoever's turn it is, make them act initiateCombat.prototype.takeAction = function(){ var actor = this.turnOrder[this.currentTurn]; if(this.actorIsPC()){ // this.currentActor().checkStatusEffects(); if(!isDefeated(actor) && !actor.paralyze){ this.currentActor().needsTarget = 1; this.abilityScreen.addAbilities(actor); } else if(isDead(actor)){ this.abilityScreen.addMessage("[[" + actor.race + " is dead|combat]]"); this.nextTurn(); } else if(actor.paralyze){ this.nextTurn(); this.abilityScreen.addMessage("[[" + actor.race + " is paralyzed|combat]]"); } } else{ var setLink = setterLink("enemies attack", "combat", "currentFight.autoConsecAction()"); this.abilityScreen.addMessage(setLink); } }; %><% Monster.prototype.applyEffectSingle = function(ability, target){ // if target is dead, skip if(isDead(target)) { return; } // if conditional effect applies, do it instead if(ability.condition && ability.condition(this, target)){ this.applyEffectSingle(ability.conditionEffect, target); return; } if(ability.damage != null){ this.applyDamage(ability, target); } if(ability.poison != null){ this.applyPoison(ability, target); } if(ability.charm != null){ this.applyCharm(ability, target); } if(ability.paralyze != null){ target.paralyze = ability.paralyze; messageBoxes.messageScreen.addMessage("<font color='yellow'>" + target.race + " is stunned.</font>"); } if(ability.heal != null){ this.applyHealing(ability, target); } if (isDead(target)) { messageBoxes.messageScreen.addMessage("This was enough to defeat the target."); } } // apply the effects of an ability Monster.prototype.applyEffect = function(ability, targets){ messageBoxes.messageScreen.addMessage(this.race + " uses " + ability.name + "."); for(var i=0; i < targets.length; i++){ this.applyEffectSingle(ability, targets[i]); } } // check if target is resistant to attack checkResistance = function(ability, target){ if(commonElement(ability.damageType, target.resistance)){ messageBoxes.messageScreen.addMessage(target.race + " is resistant to " + ability.damageType + " attacks."); return 1; } return 0; } // check if target is vulnerable to attack checkVulnerable = function(ability, target){ if(commonElement(ability.damageType, target.vulnerability)){ messageBoxes.messageScreen.addMessage(target.race + " is vulnerable to " + ability.damageType + " attacks."); return 1; } return 0; } // check if target absorbs damage type checkAbsorbs = function(ability, target){ if(commonElement(ability.damageType, target.absorbs)){ messageBoxes.messageScreen.addMessage(target.race + " absorbs " + ability.damageType + " attacks."); return 1; } return 0; } // check if target is immune to damage type checkImmune = function(ability, target){ if(commonElement(ability.damageType, target.immune)){ messageBoxes.messageScreen.addMessage(target.race + " is immune to " + ability.damageType + " attacks."); return 1; } return 0; } // check that two arrays exist, then check if they share at least one common element commonElement = function(array1, array2){ if(array1 && array2){ for (var i=0; i<array2.length; i++){ if(array1.indexOf(array2[i]) > -1){ return 1 } } } return 0; } // apply poison Monster.prototype.applyPoison = function(ability, target){ if(target.immune && target.immune.indexOf("poison") > -1){ messageBoxes.messageScreen.addMessage(target.race + " is immune to poison."); return } target.poison = 1; messageBoxes.messageScreen.addMessage("<font color='purple'>" + target.race + " is poisoned.</font>"); } // apply charm Monster.prototype.applyCharm = function(ability, target){ if(target.immune && target.immune.indexOf("charm") > -1){ messageBoxes.messageScreen.addMessage(target.race + " is immune to charm."); return; } if(Math.random()*100 < ability.charm){ target.charm = 1; messageBoxes.messageScreen.addMessage("<font color='#E0A2B9'>" + target.race + " is charmed.</font>"); } else { messageBoxes.messageScreen.addMessage("charm failed."); } } %>You died. How did you die? [[I was walking home from work when a bum stabbed me. He looked familiar...|weaponSelect]] [[I was taking a walk reflecting on my wasted life, when I saw a kid about to be run over by a truck. I pushed the kid out the way, but got hit myself|weaponSelect]] [[I ran into my stalker. She pulled something out of her pocket... and I don't remember anything after that|weaponSelect]] <% story.passage("twine-functionality").render() %> <% story.passage("interface_scripts").render() %> <% story.passage("combat-object").render() %>You're surrounded by darkness. In the midst of that darkness is a light shining on four objects: a swords, a bow, a spear, and a shield. [[reach for the sword|adventureBegins]] [[reach for the bow|adventureBegins]] [[reach for the spear|adventureBegins]] [[reach for the shield|adventureBegins]] <% story.passage("stats").render() %> <% story.passage("abilities").render() %> <% story.passage("combat_functions").render() %> <% story.passage("apply-effect").render() %> <% story.passage("enemy-behavior").render() %> <% story.passage("miscCombat").render() %> <% story.passage("damage-calculations").render() %> <% story.passage("status-box").render() %>As you ponder your choice, four arms reach out of the darkness and each grab one of the items in front of you. When the arms and their prizes disappear, you begin to fall away from the light empty-handed. Something hits you in the chest, but the light is now too distant to make out what it is. You grab hold of it just before hitting the ground softly. You open your eyes without realizing they had been closed, and find yourself on a dirt road in the middle of a bustling crowd, looking up at a man in plate armour. "Watch where you're going, kid." "What?" You have no idea what's going on. As you lift yourself up, you notice a pan flute in your hand. "A kid who doesn't know manners, huh? When you bump into someone, you're supposed to apologize. That way they don't get mad at you." The man in armour shoves you back down as he says this. You're still looking around in confusion. Your exchange is attracting the attention of passers-by, and you notice they look awfully strange. Their clothes appear pre-industrial, and some of them look... inhuman. They don't seem to approve of the way Armour is treating you, but none of them intervene. Something clangs in front of you. A sword. "If you're going to insult me, then you better be prepared to back it up. Pick that up." Armour takes a couple of steps back before drawing another sword from his belt. "If you can avoid embarrassing yourself, I'll even let you keep the sword." Confused and unsure what to do, you reach out for the sword... "Aah!" You receive a shock and quickly withdraw your hand. Armour looks at you. "Fine. Fists it is." <% //returnFromCombat = "pitifulDefeat" %> <% gameOverScreen = "pitifulDefeat" %> <!-- [[pitifulDefeat]] --> <% combatAbilities.sword = { name: "sword", damage: 3, damageType: "slashing" } combatAbilities.punch = { name: "punch", damage: 0 } introArmour = new Monster(); introArmour.race = "Armour"; introArmour.maxHP = 30; introArmour.health = 30; introArmour.attack = 10; introArmour.abilities = [combatAbilities.punch]; introArmour.XP = 5; Pat = new Monster(); Pat.race = "Pat"; Pat.maxHP = 20; Pat.health = 20; Pat.attack = 2; Pat.abilities = [combatAbilities.punch]; Pat.EXP = 0; %> <% allies = [Pat] %> <% enemies = [introArmour] %> <% currentFight = new initiateCombat(allies, enemies); %> <% //xpAward = addXP(enemies) %> <% print(startFight(allies, enemies, "pitifulDefeat")) %><% Pat.fullHeal() %> "Ugh!" For the third time, you find yourself in the dirt. "Wouldn't it have been easier to just apologize like a civilized person?" Armour calls down at you as he turns and walks off. What the hell is going on? There's singing coming from a sewer pipe. [[investigate the voice in the sewer pipe|enterSewers]]<% // fully heals a combatant Monster.prototype.fullHeal = function(){ this.health = this.maxHP; this.poison = 0; this.charm = 0; this.paralyze = 0; } // fully heals an array of combatants Monster.prototype.partyFullHeal = function(party){ for(var i=0; i<party.length; i++){ party[i].fullHeal(); } } %>Meet sewer bum. She tells you sewer people all sing this song. Supposed to ward off sewer creatures, doesn't really work. Might as well sit down and learn how to play this pan flute. She teaches you the song. Whoa, there's a swarm of rats on either side of you. You stop playing in surprise. They attack. <% print(startFight(allies, enemies, "firstVictory")); %> <% Pat.abilities.push(combatAbilities.SewerSong); sewerBum = new Monster(); sewerBum.race = "Sewer Bum"; sewerBum.maxHP = 25; sewerBum.health = 25; sewerBum.attack = 5; sewerBum.abilities = [combatAbilities.sword]; sewerBum.EXP = 0; %> <% //returnFromCombat = "firstVictory" %> <% //gameOverScreen = "firstVictory" %> <!-- [[firstVictory]] --> <% enemy1 = new monsters.RatSwarm(); enemy2 = new monsters.RatSwarm(); %> <% allies = [sewerBum, Pat] %> <% enemies = [enemy1, enemy2] %> <% currentFight = new initiateCombat(allies, enemies); %> <% //xpAward = addXP(enemies) %>Oh, the song charms rats. Why does it only do that when you play the song? Sewer bum leads you through the sewers. She'll take you outside the city for some reason. You probably got on someone's shitlist earlier. Oh no, you are attacked again. <% print(startFight(allies, enemies, "secondVictory")); %> <% //returnFromCombat = "secondVictory" %> <% //gameOverScreen = "secondVictory" %> <!-- [[secondVictory]] --> <% enemy1 = new monsters.RatSwarm(); enemy2 = new monsters.GiantSpider(); enemy3 = new monsters.GiantSpider(); enemy4 = new monsters.RatSwarm(); %> <% allies = [sewerBum, Pat] %> <% enemies = [enemy1, enemy2, enemy3, enemy4] %> <% currentFight = new initiateCombat(allies, enemies); %> <% //xpAward = addXP(enemies) %>Hurray, you won again. You're almost out. Bum says you'll exit next to a forest. Oh, wouldn't you know you're attacked again right at the exit. <% print(startFight(allies, enemies, "finishIntro")); %> <% //returnFromCombat = "finishIntro" %> <% //gameOverScreen = "finishIntro" %> <!-- [[finishIntro]] --> <% enemy1 = new monsters.RatSwarm(); enemy2 = new monsters.RatSwarm(); enemy3 = new monsters.DireWolf(); enemy4 = new monsters.RatSwarm(); enemy5 = new monsters.RatSwarm(); %> <% allies = [sewerBum, Pat] %> <% enemies = [enemy1, enemy2, enemy3, enemy4, enemy5] %> <% currentFight = new initiateCombat(allies, enemies); %> <% //xpAward = addXP(enemies) %>You step out of the sewers into a plain overlooking a forest.<% // apply damage Monster.prototype.applyDamage = function(ability, target){ var damage = this.randomize(ability.damage, this.attack); damage += Math.floor(damage/4*checkVulnerable(ability, target)) - Math.floor(damage/4*checkResistance(ability, target)); if(checkAbsorbs(ability, target)){ target.healHP(damage); return; } if(checkImmune(ability, target)){ return; } target.health -= damage; messageBoxes.messageScreen.addMessage("attack did " + damage + " damage to " + target.race + "."); if(target.charm){ target.charm = 0; messageBoxes.messageScreen.addMessage("<font color='#E0A2B9'>" + target.race + " is no longer charmed.</font>"); } } // add two numbers together and randomize by 20% Monster.prototype.randomize = function(bonus, stat){ var randomizer = (2 * Math.random()-1) * (stat + bonus) /5; var magnitude = stat + bonus + Math.floor(randomizer); return magnitude; } // apply healing from an ability. Placeholder, will need to add calculation and stat-dependance later. Monster.prototype.applyHealing = function(ability, target){ var magnitude = this.randomize(ability.heal, this.magic); target.healHP(magnitude); } // heal HP Monster.prototype.healHP = function(magnitude){ this.health += magnitude; if(this.health >= this.maxHP){ this.health = this.maxHP; messageBoxes.messageScreen.addMessage(this.race + " fully healed."); } else { messageBoxes.messageScreen.addMessage(this.race + " healed " + magnitude + " damage."); } } %><% //distribute XP awardXP = function(party, XP){ XP = Math.floor(XP/party.length); for (var i=0; i<party.length; i++){ party[i].EXP += XP; } } //add up a party's XP initiateCombat.prototype.addXP = function(party){ var xpAward = 0; for (var i=0; i<party.length; i++){ xpAward += party[i].XP; } return xpAward; } // check if someone is dead. isDead = function(target){ if (target.health <= 0){ target.health = 0; target.poison = 0; target.paralyze = 0; return 1; } else { return 0; } } // check if character is defeated isDefeated = function(target){ if (isDead(target) || (target.charm > 0)) {return 1;} else {return 0;} } // check if a party is defeated partyDefeated = function(party){ for (var i=0; i<party.length; i++){ if (!isDefeated(party[i])) { return 0; } } return 1; } // check and status effect and apply their consequence Monster.prototype.checkStatusEffects = function(){ // if they're already dead, skip if(isDead(this)) {return;} if(this.poison > 0){ this.health -= 4; messageBoxes.messageScreen.addMessage("<font color='purple'>" + this.race + " took poison damage.</font>"); } if(this.paralyze >0){ this.paralyze--; if(this.paralyze == 0){ messageBoxes.messageScreen.addMessage("<font color='yellow'>" + this.race + " is no longer stunned.</font>"); } else{ messageBoxes.messageScreen.addMessage("<font color='yellow'>" + this.race + " is stunned.</font>"); } } //check if a status effect caused death if(isDead(this)) { messageBoxes.messageScreen.addMessage(this.race + " fell from poison."); // currentFight.nextTurn(); }; } %><% // alternative method returns hp bar for monster. Not currently used. May use later to add animation Monster.prototype.hpBar1 = function(){ var currentHP = Math.floor(this.health/this.maxHP*100); return "HP:<canvas id='player1HP' width='" + currentHP + "' height='15' style='background:red;'></canvas>"; } // returns hp bar for monster. Monster.prototype.hpBar = function(){ var currentHP = Math.floor(this.health/this.maxHP*100); var hpOutline = "<span class='box' style='width:100px; border:solid black'><span class='box hpBar' style='width:" + currentHP + "px'>"+this.health+"/"+this.maxHP+"</span></span>"; return "HP:" + hpOutline; } // returns status box for monster Monster.prototype.statusBox = function(){ var status = "<div class='box' style='border:solid black'>" + this.race + "<br>" + this.hpBar() + "</div>"; return status; } // push a status box to a messagebox messageBoxes.MessageBox.prototype.addStatus = function(combatant){ var statusBox = combatant.statusBox(); this.addMessage(statusBox); } // add an array of monsters' stats to a message box messageBoxes.MessageBox.prototype.addStatusArr = function(party){ // this.addMessage("Allies:") for (var i=0; i<party.length; i++){ this.addStatus(party[i]); } } // display enemy and ally status boxes. Should probably make this one function, maybe taking the turn-order array as input. messageBoxes.MessageBox.prototype.printAllyStatus = function(allies){ this.addStatusArr(allies); var output = "<div class='message-box ally'><span style='position:relative; top:0; left:0'>Allies</span><br>" + this.displayScreen() + "</div>"; return output; } messageBoxes.MessageBox.prototype.printEnemyStatus = function(enemies){ this.addStatusArr(currentFight.enemies); var output = "<div class='message-box enemy'><span style='position:relative; top:0; left:0'>Enemies</span><br>" + this.displayScreen() + "</div>"; return output; } %>