Best JavaScript code snippet using storybook-test-runner
dragon-battle.service.ts
Source:dragon-battle.service.ts
1import { Injectable } from "@nestjs/common";2import { InjectRepository } from "@nestjs/typeorm";3import { MathService } from "src/common/services/math.service";4import { Repository } from "typeorm";5import { ExpeditionDto } from "../../dragon-action/model/dto/expedition.dto";6import { MagicArrow } from "../../dragon-skills/model/data/skills-common";7import { AirVector, DeepWounds, EnchantedBarrier, FireBolt, IceBolt, LeafCut, RockBlast, Thunderbolt } from "../../dragon-skills/model/data/skills-exclusive";8import { BattleDragonDto, BattleResultExperience, BattleResultType, TurnResult } from "../model/definitions/dragon-battle";9import { Dragon } from "../model/dragon.entity";10import { BattleResultDto } from "../model/dto/battle-result.dto";11import { DragonDto } from "../model/dto/dragon.dto";12import { BattleHelperService } from "./dragon-helper.service";13@Injectable()14export class DragonBattleService {15 constructor (16 @InjectRepository(Dragon)17 private dragonRepository: Repository<Dragon>,18 private battleHelperService: BattleHelperService,19 private mathService: MathService,20 ) {}21 async executeBattle(ownedDragon: DragonDto, enemyDragon: Partial<DragonDto>): Promise<Partial<BattleResultDto>> {22 let owned = this.battleHelperService.calculateBattleStats(ownedDragon);23 let enemy = this.battleHelperService.calculateBattleStats(enemyDragon);24 const logs = [];25 let result = '';26 while (owned.health > 0 && enemy.health > 0 && logs.length <= 100) {27 let turnResult: TurnResult;28 if (owned.initiative > enemy.initiative) {29 turnResult = this.performMovement(owned, enemy, true, logs.length);30 owned = turnResult.attacker;31 enemy = turnResult.defender;32 } else {33 turnResult = this.performMovement(enemy, owned, false, logs.length);34 owned = turnResult.defender;35 enemy = turnResult.attacker;36 }37 logs.push(turnResult.log);38 }39 if (logs.length >= 100) {40 const resultExperience = await this.saveBattleResults(BattleResultType.Draw, owned, enemy, logs.length);41 result =`<div class="neither">The battle did not found a winner. 42 Both participants gained ${resultExperience.ownedExperience} experience.</div>`;43 } else if (owned.health > enemy.health) {44 const resultExperience = await this.saveBattleResults(BattleResultType.Win, owned, enemy, logs.length);45 result = `<div class="owned">${owned.name} won and gained ${resultExperience.ownedExperience} experience.<br>46 ${enemy.name} lost ${resultExperience.enemyExperience} experience.</div>`;47 } else {48 const resultExperience = await this.saveBattleResults(BattleResultType.Loss, owned, enemy, logs.length);49 result = `<div class="enemy">${enemy.name} won and gained ${resultExperience.enemyExperience} experience.<br>50 ${owned.name} lost ${resultExperience.ownedExperience} experience.</div>`;51 }52 return {53 ownedDragon: { id: owned.id, name: owned.name, level: owned.level, stamina: owned.stamina, },54 enemyDragon: { id: enemy.id, name: enemy.name, level: enemy.level, },55 logs: logs,56 result: result,57 };58 }59 async executeGuardianBattle(ownedDragon: DragonDto, expedition: ExpeditionDto): Promise<Partial<BattleResultDto>> {60 let enemyDragon = this.battleHelperService.createDragonFromGuardian(expedition.guardian);61 62 let owned = this.battleHelperService.calculateBattleStats(ownedDragon);63 let enemy = this.battleHelperService.calculateBattleStats(enemyDragon);64 const logs = [];65 let result = '';66 while (owned.health > 0 && enemy.health > 0 && logs.length <= 100) {67 let turnResult: TurnResult;68 if (owned.initiative > enemy.initiative) {69 turnResult = this.performMovement(owned, enemy, true, logs.length);70 owned = turnResult.attacker;71 enemy = turnResult.defender;72 } else {73 turnResult = this.performMovement(enemy, owned, false, logs.length);74 owned = turnResult.defender;75 enemy = turnResult.attacker;76 }77 logs.push(turnResult.log);78 }79 if (logs.length >= 100) {80 await this.saveBattleGuardianResults(BattleResultType.Draw, owned, expedition, logs.length);81 result =`<div class="neither">The battle did not found a winner</div>`;82 } else if (owned.health > enemy.health) {83 await this.saveBattleGuardianResults(BattleResultType.Win, owned, expedition, logs.length);84 result = `<div class="owned">${owned.name} won and gained access to new areas in ${expedition.name}.</div>`;85 } else {86 await this.saveBattleGuardianResults(BattleResultType.Loss, owned, expedition, logs.length);87 result = `<div class="enemy">${owned.name} failed ${enemyDragon.name}'s challenge.</div>`;88 }89 return {90 ownedDragon: { id: owned.id, name: owned.name, level: owned.level, stamina: owned.stamina, },91 enemyDragon: { id: enemy.id, name: enemy.name, level: enemy.level, },92 logs: logs,93 result: result,94 };95 }96 private performMovement(attacker: BattleDragonDto, defender: BattleDragonDto, ownedTurn: boolean, turn: number): TurnResult {97 let cssClasses = ownedTurn ? 'item-log log-owned' : 'item-log log-enemy';98 let turnResult: TurnResult = { attacker: attacker, defender: defender, log: '', cssClasses: cssClasses };99 /**100 * Preamptive restore effects101 */102 turnResult.defender.mana += defender.manaRegen;103 turnResult.defender.initiative += defender.speed;104 /**105 * Special attacks106 */107 turnResult = this.executeSpecialAttacks(turnResult);108 /**109 * Dodge chance110 */111 const dodgeChance = turnResult.defender.dodgeChance * (1 - attacker.skills.thoughtfulStrike / 70);112 if (!turnResult.skip && dodgeChance > Math.random()) {113 turnResult.log = `114 <div class="item-log log-miss">115 ${turnResult.attacker.name} (${turnResult.attacker.health.toFixed(1)}) 116 missess.117 </div>`;118 turnResult.skip = true;119 }120 /**121 * Regular turn122 */123 if (!turnResult.skip) {124 turnResult = this.executeRegularTurn(turnResult);125 }126 /**127 * Post-movement effects128 */129 turnResult = this.executePostTurnEffects(turnResult, turn);130 return turnResult;131 }132 private executeSpecialAttacks(turnResult: TurnResult): TurnResult {133 let attacker = turnResult.attacker;134 let defender = turnResult.defender;135 let log = turnResult.log;136 let extraLogs = [];137 let cssClasses = turnResult.cssClasses;138 let blockedHit = 0;139 /**140 * Pre-spell effects141 */142 if (defender.skills.block > 0) {143 const blockChance = 0.05 + defender.skills.block / 100;144 if (blockChance > Math.random()) {145 blockedHit = this.mathService.randRange(0.95, 1.05) * (40 + defender.skills.block) / 120;146 extraLogs.push(`<div class="log-extra">- blocked ${(100*blockedHit).toFixed(1)}% damage</div>`);147 }148 }149 if (attacker.skills.magicArrow > 0) {150 const castCost = MagicArrow.castMana * (1 + attacker.skills.magicArrow / 10);151 if (attacker.mana > castCost && Math.random() < MagicArrow.castChance) {152 let skillHit = (1 + attacker.skills.magicArrow / 10) * (1.1 * attacker.magicalAttack) - defender.resistance;153 skillHit = this.mathService.randRange(0.9, 1.1) * this.mathService.limit(attacker.level / 5, skillHit, skillHit);154 skillHit *= (1 - blockedHit);155 defender.health -= skillHit;156 attacker.mana -= castCost;157 158 let brokenResistance = 0;159 if (defender.resistance > 0) {160 brokenResistance = this.mathService.randRange(0.9, 1.1) * (3 + 0.05 * defender.resistance * attacker.skills.magicArrow);161 defender.resistance -= brokenResistance;162 extraLogs.push(`<div class="log-extra">+ broken ${brokenResistance.toFixed(1)} resistance</div>`);163 }164 cssClasses += ' log-skill';165 log = `166 <div class="${cssClasses}">167 ${attacker.name} (${attacker.health.toFixed(1)}) uses <b>Magic Arrow</b> and strikes ${defender.name} (${defender.health.toFixed(1)}) 168 for ${skillHit.toFixed(1)} damage.`169 extraLogs.forEach(extraLog => log += extraLog);170 log += `</div>`;171 return { attacker: attacker, defender: defender, skip: true, log: log };172 }173 }174 if (attacker.skills.fireBolt > 0) {175 const castCost = FireBolt.castMana * (1 + attacker.skills.fireBolt / 8);176 if (attacker.mana > castCost && Math.random() < FireBolt.castChance) {177 let skillHit = (1 + attacker.skills.fireBolt / 10) * (1.5 * attacker.magicalAttack) - defender.resistance;178 skillHit = this.mathService.randRange(0.9, 1.1) * this.mathService.limit(attacker.level / 5, skillHit, skillHit);179 skillHit *= (1 - blockedHit);180 defender.health -= skillHit;181 attacker.mana -= castCost;182 183 const extraCritPower = attacker.skills.fireBolt;184 attacker.critPower += extraCritPower / 100;185 extraLogs.push(`<div class="log-extra">+ critical power boost (${extraCritPower.toFixed(1)} %)</div>`);186 cssClasses += ' log-skill';187 log = `188 <div class="${cssClasses}">189 ${attacker.name} (${attacker.health.toFixed(1)}) uses <b>Fire bolt</b> and strikes ${defender.name} (${defender.health.toFixed(1)}) 190 for ${skillHit.toFixed(1)} damage.`191 extraLogs.forEach(extraLog => log += extraLog);192 log += `</div>`;193 return { attacker: attacker, defender: defender, log: log, skip: true, cssClasses: cssClasses };194 }195 }196 if (attacker.skills.iceBolt > 0) {197 const castCost = IceBolt.castMana * (1 + attacker.skills.iceBolt / 8);198 if (attacker.mana > castCost && Math.random() < IceBolt.castChance) {199 let skillHit = (1 + attacker.skills.iceBolt / 10) * (1.4 * attacker.magicalAttack) - defender.resistance;200 skillHit = this.mathService.randRange(0.9, 1.1) * this.mathService.limit(attacker.level / 5, skillHit, skillHit);201 skillHit *= (1 - blockedHit);202 defender.health -= skillHit;203 attacker.mana -= castCost;204 const skillSlow = this.mathService.randRange(0.9, 1.1) * (5 + 0.075 * defender.speed * attacker.skills.iceBolt);205 defender.initiative -= skillSlow;206 extraLogs.push(`<div class="log-extra">+ slow (${skillSlow.toFixed(1)} initiative)</div>`);207 cssClasses += ' log-skill';208 log = `209 <div class="${cssClasses}">210 ${attacker.name} (${attacker.health.toFixed(1)}) uses <b>Ice Bolt</b> and strikes ${defender.name} (${defender.health.toFixed(1)}) 211 for ${skillHit.toFixed(1)} damage.`212 extraLogs.forEach(extraLog => log += extraLog);213 log += `</div>`;214 return { attacker: attacker, defender: defender, log: log, skip: true, cssClasses: cssClasses };215 }216 }217 if (attacker.skills.airVector > 0) {218 const castCost = AirVector.castMana * (1 + attacker.skills.airVector / 8);219 if (attacker.mana > castCost && Math.random() < AirVector.castChance) {220 let skillHit = (1 + attacker.skills.airVector / 10) * (1.3 * attacker.magicalAttack) - defender.resistance;221 skillHit = this.mathService.randRange(0.9, 1.1) * this.mathService.limit(attacker.level / 5, skillHit, skillHit);222 skillHit *= (1 - blockedHit);223 defender.health -= skillHit;224 attacker.mana -= castCost;225 226 const skillHaste = this.mathService.randRange(0.9, 1.1) * (5 + 0.09 * attacker.speed * attacker.skills.airVector);227 attacker.initiative += skillHaste;228 extraLogs.push(`<div class="log-extra">+ haste (${skillHaste.toFixed(1)} initiative)</div>`);229 cssClasses += ' log-skill';230 log = `231 <div class="${cssClasses}">232 ${attacker.name} (${attacker.health.toFixed(1)}) uses <b>Air Vector</b> and strikes ${defender.name} (${defender.health.toFixed(1)}) 233 for ${skillHit.toFixed(1)} damage;`234 extraLogs.forEach(extraLog => log += extraLog);235 log += `</div>`;236 return { attacker: attacker, defender: defender, log: log, skip: true };237 }238 }239 if (attacker.skills.rockBlast > 0) {240 const castCost = RockBlast.castMana * (1 + attacker.skills.rockBlast / 8);241 if (attacker.mana > castCost && Math.random() < RockBlast.castChance) {242 let skillHit = (1 + attacker.skills.rockBlast / 10) * (1.5 * attacker.magicalAttack) - defender.resistance;243 skillHit = this.mathService.randRange(0.9, 1.1) * this.mathService.limit(attacker.level / 5, skillHit, skillHit);244 skillHit *= (1 - blockedHit);245 defender.health -= skillHit;246 attacker.mana -= castCost;247 248 const stunChance = 0.1 + attacker.skills.rockBlast / 75;249 if (stunChance > Math.random()) {250 defender.initiative -= defender.speed;251 extraLogs.push(`<div class="log-extra">+ stun</div>`);252 }253 cssClasses += ' log-skill';254 log = `255 <div class="${cssClasses}">256 ${attacker.name} (${attacker.health.toFixed(1)}) uses <b>Rock Blast</b> and strikes ${defender.name} (${defender.health.toFixed(1)}) 257 for ${skillHit.toFixed(1)} damage.`;258 extraLogs.forEach(extraLog => log += extraLog);259 log += `</div>`;260 return { attacker: attacker, defender: defender, log: log, skip: true, cssClasses: cssClasses };261 }262 }263 if (attacker.skills.thunderbolt > 0) {264 const castCost = Thunderbolt.castMana * (1 + attacker.skills.thunderbolt / 9);265 if (attacker.mana > castCost && Math.random() < Thunderbolt.castChance) {266 let skillHit = (1 + attacker.skills.thunderbolt / 10) * (1.9 * attacker.magicalAttack) - defender.resistance;267 skillHit = this.mathService.randRange(0.6, 2.1) * this.mathService.limit(attacker.level / 5, skillHit, skillHit);268 skillHit *= (1 - blockedHit);269 defender.health -= skillHit;270 attacker.mana -= castCost;271 const paralysisChance = 0.125 + attacker.skills.thunderbolt / 75;272 if (paralysisChance > Math.random()) {273 defender.speed -= 0.1 * defender.speed;274 defender.initiative -= 0.25 * defender.speed;275 extraLogs.push(`<div class="log-extra">+ paralysis</div>`);276 }277 cssClasses += ' log-skill';278 log = `279 <div class="${cssClasses}">280 ${attacker.name} (${attacker.health.toFixed(1)}) uses <b>Thunderbolt</b> and strikes ${defender.name} (${defender.health.toFixed(1)}) 281 for ${skillHit.toFixed(1)} damage.`;282 extraLogs.forEach(extraLog => log += extraLog);283 log += `</div>`;284 return { attacker: attacker, defender: defender, log: log, skip: true, cssClasses: cssClasses };285 }286 }287 return { attacker: attacker, defender: defender, log: log, cssClasses: cssClasses, skip: false };288 }289 private executeRegularTurn(turnResult: TurnResult): TurnResult {290 let attacker = turnResult.attacker;291 let defender = turnResult.defender;292 let log = turnResult.log;293 let extraLogs = [];294 let cssClasses = turnResult.cssClasses;295 296 let isCrit = false;297 let critFactor = 1;298 let isArmorPenetrated = false;299 let rageFactor = 1;300 let blockedHit = 0;301 let lethalFactor = 1;302 /**303 * Pre-offensive effects304 */305 if (attacker.skills.armorPenetration) {306 const penetrationChance = 0.05 + attacker.skills.armorPenetration / 75;307 if (penetrationChance > Math.random()) {308 isArmorPenetrated = true;309 extraLogs.push(`<div class="log-extra">+ armor penetration</div>`);310 }311 }312 if (attacker.skills.rage) {313 if (attacker.health < 0.5 * attacker.maxHealth) {314 rageFactor = 1 + attacker.skills.rage / 75;315 extraLogs.push(`<div class="log-extra">+ rage</div>`);316 }317 }318 /**319 * Pre-defensive skills320 */321 if (defender.skills.block) {322 const blockChance = 0.05 + defender.skills.block / 100;323 if (blockChance > Math.random()) {324 blockedHit = this.mathService.randRange(0.95, 1.05) * (50 + defender.skills.block) / 100;325 extraLogs.push(`<div class="log-extra">- blocked ${(100*blockedHit).toFixed(1)}% damage</div>`);326 }327 }328 if (defender.skills.enchantedBarrier) {329 const barrierCost = EnchantedBarrier.castMana + defender.skills.enchantedBarrier / 8;330 if (defender.mana >= barrierCost) {331 defender.mana -= barrierCost;332 let absorbedHit = (10 + defender.skills.enchantedBarrier / 3) / 100;333 blockedHit += absorbedHit;334 extraLogs.push(`<div class="log-extra">- absorbed ${(100*absorbedHit).toFixed(1)}% damage</div>`);335 }336 }337 /**338 * Critical chance339 */340 if (attacker.critChance > Math.random()) {341 isCrit = true;342 critFactor = attacker.critPower;343 cssClasses += ' log-crit';344 }345 /**346 * Lethal blow347 */348 if (attacker.skills.lethalBlow) {349 const lethalHitChance = attacker.skills.lethalBlow / 300;350 if (lethalHitChance > Math.random()) {351 lethalFactor = 10;352 cssClasses += ' log-crit';353 extraLogs.push(`<div class="log-extra">+ lethal blow</div>`);354 }355 }356 /**357 * Freeze358 */359 if (attacker.skills.freeze) {360 const freezeChance = 0.03 + attacker.skills.freeze / 125;361 if (freezeChance > Math.random()) {362 defender.initiative -= defender.speed;363 extraLogs.push(`<div class="log-extra">+ freeze</div>`);364 }365 }366 /**367 * Super Charge368 */369 if (attacker.skills.superCharge) {370 const chargeChance = attacker.skills.superCharge / 250;371 if (chargeChance > Math.random()) {372 const chargedHealth = 0.2 * attacker.maxHealth * (1 + attacker.skills.superCharge / 100);373 attacker.health += chargedHealth;374 extraLogs.push(`<div class="log-extra">+ Thunder God's blessing (gained ${chargedHealth.toFixed(1)} health)</div>`);375 }376 }377 /**378 * Terrible omen379 */380 if (attacker.skills.terribleOmen) {381 const omenChance = attacker.skills.terribleOmen / 150;382 if (omenChance > Math.random() && attacker.dodgeChance < 0.8) {383 const extraDodge = 0.13;384 attacker.dodgeChance += extraDodge;385 attacker.dodgeChance = Math.min(attacker.dodgeChance, 0.8);386 extraLogs.push(`<div class="log-extra">+ terrible omen</div>`);387 }388 }389 /**390 * Regular hit391 */392 let baseHit = critFactor * rageFactor * attacker.physicalAttack * lethalFactor;393 baseHit = isArmorPenetrated ? baseHit : baseHit - defender.armor;394 baseHit *= (1 - blockedHit);395 baseHit = this.mathService.randRange(0.9, 1.1) * this.mathService.limit(1 + attacker.level / 10, baseHit, baseHit);396 defender.health -= baseHit;397 /**398 * Post-offensive effects399 */400 if (isCrit) {401 if (attacker.skills.criticalDrain) {402 const drainedHealth = baseHit * (0.15 + attacker.skills.criticalDrain / 60);403 attacker.health += drainedHealth;404 defender.health -= drainedHealth;405 const drainedMana = baseHit * (0.075 + attacker.skills.criticalDrain / 80);406 attacker.mana += drainedMana;407 defender.mana -= drainedMana;408 extraLogs.push(`<div class="log-extra">+ drained ${drainedHealth.toFixed(1)} health, ${drainedMana.toFixed(1)} mana</div>`);409 }410 if (attacker.skills.zeal) {411 const acceleration = attacker.speed * (attacker.skills.zeal / 50);412 attacker.initiative += acceleration;413 extraLogs.push(`<div class="log-extra">+ critical acceleration (${acceleration.toFixed(1)}) initiative</div>`);414 }415 }416 if (attacker.skills.lifeLink) {417 const drainedHealth = baseHit * (0.04 + attacker.skills.lifeLink / 80);418 attacker.health += drainedHealth;419 defender.health -= drainedHealth;420 extraLogs.push(`<div class="log-extra">+ drained ${drainedHealth.toFixed(1)} health</div>`);421 }422 if (attacker.skills.fireBreath) {423 const baseFireComponent = Math.log(2 + attacker.skills.fireBreath) * (0.4 * attacker.magicalAttack);424 let fireHit = critFactor * rageFactor * baseFireComponent - defender.resistance;425 fireHit *= (1 - blockedHit);426 fireHit = this.mathService.randRange(0.9, 1.1) * this.mathService.limit(1 + attacker.level / 10, fireHit, fireHit);427 defender.health -= fireHit;428 extraLogs.push(`<div class="log-extra">+ ${fireHit.toFixed(1)} fire damage</div>`);429 }430 if (attacker.skills.staticStrike) {431 const baseStaticComponent = Math.log(2 + attacker.skills.staticStrike) * (0.3 * attacker.magicalAttack);432 let staticHit = critFactor * rageFactor * baseStaticComponent - defender.resistance;433 staticHit *= (1 - blockedHit);434 staticHit = this.mathService.randRange(0.5, 1.9) * this.mathService.limit(1 + attacker.level / 9, staticHit, staticHit);435 defender.health -= staticHit;436 extraLogs.push(`<div class="log-extra">+ ${staticHit.toFixed(1)} electric damage</div>`);437 if (defender.armor > 0) {438 const armorBreak = 0.5 + 0.1 * defender.armor * attacker.skills.staticStrike / 50;439 defender.armor -= armorBreak;440 extraLogs.push(`<div class="log-extra">+ broken ${armorBreak.toFixed(1)} armor</div>`);441 }442 }443 let leafCutCost = LeafCut.castMana * (1 + attacker.skills.leafCut / 50);444 if (attacker.skills.leafCut > 0 && attacker.mana > leafCutCost) {445 const baseLeafComponent = Math.log(2 + attacker.skills.leafCut) * (0.6 * attacker.magicalAttack);446 let leafHit = critFactor * rageFactor * baseLeafComponent - defender.resistance;447 leafHit *= (1 - blockedHit);448 leafHit = this.mathService.randRange(0.9, 1.1) * this.mathService.limit(1 + attacker.level / 8, leafHit, leafHit);449 defender.health -= leafHit;450 attacker.mana -= leafCutCost;451 extraLogs.push(`<div class="log-extra">+ leaf cut ${leafHit.toFixed(1)} damage</div>`);452 }453 454 if (attacker.skills.pugnaciousStrike && defender.armor > 0) {455 const armorBreak = 0.5 + 0.1 * defender.armor * attacker.skills.pugnaciousStrike / 40;456 defender.armor -= armorBreak;457 extraLogs.push(`<div class="log-extra">+ broken ${armorBreak.toFixed(1)} armor</div>`);458 }459 if (attacker.skills.deepWounds) {460 const woundChance = 0.1 + attacker.skills.deepWounds / 75;461 if (woundChance > Math.random()) {462 const newWound = defender.maxHealth * (attacker.skills.deepWounds / 150);463 defender.deepWounds += newWound;464 extraLogs.push(`<div class="log-extra">+ deep wound ${newWound.toFixed(1)} damage</div>`);465 }466 }467 468 /**469 * Post-defensive skills470 */471 if (defender.skills.roughSkin) {472 const reflectedHit = baseHit * defender.skills.roughSkin / 50;473 attacker.health -= reflectedHit;474 extraLogs.push(`<div class="log-extra">- ${defender.name} reflected ${reflectedHit.toFixed(1)} damage</div>`);475 }476 log += `477 <div class="${cssClasses}">478 ${attacker.name} (${attacker.health.toFixed(1)}) 479 ${isCrit ? 'critically strikes' : 'strikes'}480 ${defender.name} (${defender.health.toFixed(1)}) 481 for ${baseHit.toFixed(1)}`;482 extraLogs.forEach(extraLog => log += extraLog);483 log += `</div>`;484 return { attacker: attacker, defender: defender, log: log, cssClasses: cssClasses, skip: false };485 }486 private executePostTurnEffects(turnResult: TurnResult, turn: number): TurnResult {487 let attacker = turnResult.attacker;488 let defender = turnResult.defender;489 let log = turnResult.log;490 let independentLogs = [];491 let cssClasses = turnResult.cssClasses;492 if ((defender.skills.soundBody > 0 || defender.healthRegen > 0) && defender.health < defender.maxHealth && defender.health > 0) {493 let restoredHealth = (0.05 * defender.maxHealth * (1 + defender.skills.soundBody / 20) + defender.healthRegen)494 / (1 + turn / 15);495 if (restoredHealth > 0) {496 defender.health += restoredHealth;497 if (defender.health > defender.maxHealth) defender.health = defender.maxHealth;498 independentLogs.push(`<div class="item-log log-status">${defender.name} regenerated ${restoredHealth.toFixed(1)} health.</div>`);499 } 500 }501 if (defender.skills.poison > 0) {502 let poisonDamage = (1 + attacker.maxHealth / 100) * (1 + turn / 33) * Math.log(2 + 2 * defender.skills.poison);503 attacker.health -= poisonDamage;504 independentLogs.push(`<div class="item-log log-status">${attacker.name} took ${poisonDamage.toFixed(1)} poison damage.</div>`);505 }506 507 if (attacker.deepWounds > 0) {508 attacker.health -= attacker.deepWounds;509 attacker.deepWounds *= 0.82;510 independentLogs.push(`<div class="item-log log-status">${attacker.name} suffered ${attacker.deepWounds.toFixed(1)} internal damage.</div>`);511 }512 independentLogs.forEach(independentLog => log += independentLog);513 return { attacker: attacker, defender: defender, log: log, cssClasses: cssClasses, skip: false };514 }515 private async saveBattleResults(result: BattleResultType, owned: BattleDragonDto, enemy: BattleDragonDto, battleLength: number): Promise<BattleResultExperience> {516 let resultExperience: BattleResultExperience = { ownedExperience: 0, enemyExperience: 0 };517 switch (result) {518 case BattleResultType.Win: {519 let gainedExperience = 6 * Math.log(10 + Math.max(-8, 1.5 * (enemy.level - owned.level)));520 gainedExperience = Math.round(this.mathService.randRange(0.8, 1.2) * this.mathService.limit(1, gainedExperience, 50));521 let lostExperience = gainedExperience / 3;522 lostExperience = Math.round(this.mathService.randRange(0.8, 1.2) * this.mathService.limit(1, lostExperience, 10));523 owned.experience += gainedExperience;524 enemy.experience -= lostExperience;525 resultExperience = { ownedExperience: gainedExperience, enemyExperience: lostExperience };526 break;527 }528 case BattleResultType.Loss: {529 let gainedExperience = 3 * Math.log(10 + Math.max(-8, 1.5 * (owned.level - enemy.level)));530 gainedExperience = Math.round(this.mathService.randRange(0.8, 1.2) * this.mathService.limit(1, gainedExperience, 50));531 let lostExperience = gainedExperience / 2;532 lostExperience = Math.round(this.mathService.randRange(0.8, 1.2) * this.mathService.limit(1, lostExperience, 10));533 owned.experience -= lostExperience;534 enemy.experience += gainedExperience;535 resultExperience = { ownedExperience: lostExperience, enemyExperience: gainedExperience };536 break;537 }538 case BattleResultType.Draw: {539 let gainedExperience = 3 * Math.log(10 + Math.max(-8, 1.5 * (enemy.level - owned.level)));540 gainedExperience = Math.round(this.mathService.randRange(0.8, 1.2) * this.mathService.limit(1, gainedExperience, 50));541 owned.experience += gainedExperience;542 enemy.experience += gainedExperience;543 resultExperience = { ownedExperience: gainedExperience, enemyExperience: gainedExperience };544 break;545 }546 }547 owned.stamina -= 3 + Math.floor(battleLength / 25);548 if (owned.stamina < 0) owned.stamina = 0;549 owned.battledWith.push(enemy.id);550 if (owned.experience < 0) owned.experience = 0;551 if (enemy.experience < 0) enemy.experience = 0;552 await this.dragonRepository.update(553 owned.id, 554 { experience: owned.experience, stamina: owned.stamina, battledWith: owned.battledWith },555 );556 await this.dragonRepository.update(557 enemy.id,558 { experience: enemy.experience },559 );560 return resultExperience;561 }562 private async saveBattleGuardianResults(result: BattleResultType, owned: BattleDragonDto, expedition: ExpeditionDto, battleLength: number): Promise<void> {563 owned.stamina -= 3 + Math.floor(battleLength / 25);564 if (owned.stamina < 0) owned.stamina = 0;565 if (result === BattleResultType.Win && owned.unlockedExpeditions.indexOf(expedition.uid) === -1) {566 owned.unlockedExpeditions.push(expedition.uid);567 }568 await this.dragonRepository.update(569 owned.id, 570 { stamina: owned.stamina, unlockedExpeditions: owned.unlockedExpeditions },571 );572 }...
index.js
Source:index.js
1// Third Party Packages2const { v4: uuidv4 } = require("uuid");3const dateformat = require("dateformat");4const moment = require("moment");5const fs = require("fs");6const useragent = require("express-useragent");7// Custom Packages8const crypt = require("../crypt");9const dbutils = require("../db/utils");10const utils = require("./utils");11const constants = require("../constants");12const caller = require("./caller");13// Models14const Logs = require("../db/models").Logs;15// Functions16const NewAdditionalLogger = (ua, ip, host, frameno) => {17 let e = new Error();18 let callerDetails = caller.FetchCallerDetails(e, frameno);19 let log = {20 ...callerDetails,21 browser: ua.browser,22 platform: ua.platform,23 host: host,24 os: ua.os,25 ip: ip,26 };27 return log;28};29const NewAPILogger = async (req, extraLogs) => {30 let now = new Date();31 let startDate = dateformat(now, "mmmm dS, yyyy, hh:MM:ss:l");32 let log = {33 traceid: uuidv4(),34 method: req.method,35 url: req.originalUrl,36 headers: crypt.ObjectEncrypt(req.headers),37 params: crypt.ObjectEncrypt(req.params),38 status: 100,39 error: "",40 startDate: startDate,41 endDate: startDate,42 duration: 0,43 extraLogs: extraLogs,44 };45 await logAPI(log);46 return log;47};48const UpdateAPILogger = async (req, respData) => {49 let extraLogs = PrepareExtraLogs(req, 3);50 let startMoment = moment(51 req.APILogger.startDate,52 "MMMM Do, YYYY, HH:mm:ss:SSS"53 );54 let now = new Date();55 let endDate = dateformat(now, "mmmm dS, yyyy, hh:MM:ss:l");56 let endMoment = moment(endDate, "MMMM Do, YYYY, HH:mm:ss:SSS");57 req.APILogger.extraLogs = extraLogs;58 req.APILogger.endDate = endDate;59 req.APILogger.status = respData.code;60 req.APILogger.error = respData.error;61 req.APILogger.duration = startMoment.diff(endMoment, "milliseconds");62 await logAPI(req.APILogger);63};64const InitAPILogger = async (req) => {65 let extraLogs = PrepareExtraLogs(req, 3);66 let apilog = await NewAPILogger(req, extraLogs);67 req.APILogger = apilog;68};69const PrepareExtraLogs = (req, frameno) => {70 let source = req.headers["user-agent"];71 let ua = useragent.parse(source);72 let ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress;73 let extraLogs = NewAdditionalLogger(ua, ip, req.hostname, frameno);74 return extraLogs;75};76const LogMessage = (req, type, message) => {77 let e = new Error();78 let functionName = req ? req.method + " " + req.originalUrl + " Handler" : "";79 let callerDetails = caller.FetchCallerDetails(e, 1);80 let filePath = callerDetails.filePath;81 let lineNumber = callerDetails.lineNumber;82 let traceid = req ? req.APILogger.traceid : 0;83 let source = req ? req.headers["user-agent"] : "";84 let ua = req ? useragent.parse(source) : {};85 let ip = req ? utils.FetchIP(req) : "";86 let host = req ? req.hostname : "";87 let now = new Date();88 let date = dateformat(now, "mmmm dS, yyyy, hh:MM:ss:l");89 let extraLogs = {90 line: lineNumber,91 funcName: functionName,92 filePath: filePath,93 browser: ua.browser,94 platform: ua.platform,95 host: host,96 os: ua.os,97 ip: ip,98 };99 let log = { traceid, timestamp: date, type, message, extraLogs };100 if (log.type == constants.LOG_ERROR || log.type == constants.LOG_DEBUG) {101 var stack = new Error().stack;102 log.stack = stack;103 }104 // Log to Console105 console.log(log);106 // Log to File107 fileName = dateformat("yyyymmdd") + ".log";108 if (!fs.existsSync(constants.LOG_FOLDER_PATH)) {109 fs.mkdirSync(constants.LOG_FOLDER_PATH, {});110 }111 fs.writeFile(112 constants.LOG_FOLDER_PATH + fileName,113 JSON.stringify(log) + "\n",114 { flag: "a+" },115 (err) => {}116 );117};118const logAPI = async (log) => {119 //Log DB120 await dbutils.insert(Logs, log);121 let newLog = {122 traceid: log.traceid,123 timestamp: log.endDate,124 type: "",125 status: log.status,126 message: "HTTP Request: " + log.method + " " + log.url,127 error: log.error,128 extra: log.extraLogs,129 };130 if (log.error !== "") {131 newLog.type = constants.LOG_ERROR;132 var stack = new Error().stack;133 newLog.stack = stack;134 } else {135 newLog.type = "info";136 }137 // Log to Console138 console.log(newLog);139 // Log to File140 fileName = dateformat("yyyymmdd") + ".log";141 if (!fs.existsSync(constants.LOG_FOLDER_PATH)) {142 fs.mkdirSync(constants.LOG_FOLDER_PATH, {});143 }144 fs.writeFile(145 constants.LOG_FOLDER_PATH + fileName,146 JSON.stringify(newLog) + "\n",147 { flag: "a+" },148 (err) => {}149 );150};...
index.ts
Source:index.ts
1import fs from 'fs';2import path from 'path';3import SendGrid from '@sendgrid/mail';4// https://github.com/sendgrid/sendgrid-nodejs5const fsPromises = fs.promises;6let fromEmail: string;7let presetDirectory: string;8let extraLogs: boolean = false;9export type EmailConfig = {10 sendgridAPIKey: string,11 fromEmail: string;12 presetDirectory: string;13 extraLogs: boolean; // if true, we will log who we are sending emails to14};15export type PresetTemplate = {16 presetName: string;17 replaceThese: { [key: string]: string }[];18};19export async function config(config: EmailConfig): Promise<void> {20 if (!config.sendgridAPIKey) throw new Error('@lawlzer/email - config - sendgridAPIKey is required');21 if (typeof config.sendgridAPIKey !== 'string') throw new Error('@lawlzer/email - config - sendgridAPIKey must be a string');22 if (!config.fromEmail) throw new Error('@lawlzer/email - config - fromEmail is required');23 if (typeof config.fromEmail !== 'string') throw new Error('@lawlzer/email - config - fromEmail must be a string');24 if (!config.presetDirectory) throw new Error('@lawlzer/email - config - presetDirectory is required');25 if (typeof config.presetDirectory !== 'string') throw new Error('@lawlzer/email - config - presetDirectory must be a string');26 if (typeof config.extraLogs === 'boolean') extraLogs = config.extraLogs;27 SendGrid.setApiKey(config.sendgridAPIKey);28 fromEmail = config.fromEmail;29 presetDirectory = config.presetDirectory;30};31async function getPreset(presetName: string): Promise<string> {32 if (!presetDirectory) throw new Error('@lawlzer/email - getPreset - presetDirectory is not set. Please call "config()" first.');33 const presetFilePath = path.resolve(presetDirectory, `${presetName}.html`);34 try {35 await fsPromises.access(presetFilePath); // throws if file does not exist, so we just catch it and return our own error 36 } catch (e) { throw new Error(`@lawlzer/email - getPreset - preset file "${presetFilePath}" does not exist.`); }37 const preset = await fsPromises.readFile(presetFilePath);38 return String(preset);39};40export async function sendEmail({ to, subject, presets }: { to: string, subject: string, presets: PresetTemplate[] }): Promise<void> {41 let html = '';42 for await (const preset of presets) {43 const { presetName, replaceThese } = preset;44 let presetHTML = await getPreset(presetName);45 for (const replaceThis of replaceThese) {46 for (const key in replaceThis) {47 const value = replaceThis[key];48 presetHTML = presetHTML.replaceAll(key, value);49 }50 };51 html += presetHTML;52 };53 const msg = {54 to: to,55 from: fromEmail,56 subject: subject,57 html: html,58 };59 try {60 await SendGrid.send(msg);61 if (extraLogs) console.log('@lawlzer/email - sendEmail - Email automatically sent to:', to);62 } catch (e) {63 throw new Error('@lawlzer/email - sendEmail - Sending email error: \n' + e);64 };...
Using AI Code Generation
1require('storybook-test-runner').extraLogs();2var storybookTestRunner = require('storybook-test-runner');3storybookTestRunner.extraLogs();4var storybookTestRunner = require('storybook-test-runner');5storybookTestRunner.extraLogs();6var storybookTestRunner = require('storybook-test-runner');7storybookTestRunner.extraLogs();8var storybookTestRunner = require('storybook-test-runner');9storybookTestRunner.extraLogs();10var storybookTestRunner = require('storybook-test-runner');11storybookTestRunner.extraLogs();12var storybookTestRunner = require('storybook-test-runner');13storybookTestRunner.extraLogs();14var storybookTestRunner = require('storybook-test-runner');15storybookTestRunner.extraLogs();16var storybookTestRunner = require('storybook-test-runner');17storybookTestRunner.extraLogs();18var storybookTestRunner = require('storybook-test-runner');19storybookTestRunner.extraLogs();20var storybookTestRunner = require('
Using AI Code Generation
1import { extraLogs } from 'storybook-test-runner';2import { storiesOf } from '@storybook/react';3storiesOf('Button', module)4 .add('with text', () => {5 extraLogs('some extra logs');6 return <Button>Click me</Button>;7 });
Using AI Code Generation
1import { extraLogs } from 'storybook-test-runner';2const storybookTestRunner = require('storybook-test-runner');3import { extraLogs } from 'storybook-test-runner';4const storybookTestRunner = require('storybook-test-runner');5import { extraLogs } from 'storybook-test-runner';6const storybookTestRunner = require('storybook-test-runner');7import { extraLogs } from 'storybook-test-runner';8const storybookTestRunner = require('storybook-test-runner');9import { extraLogs } from 'storybook-test-runner';10const storybookTestRunner = require('storybook-test-runner');11import { extraLogs } from 'storybook-test-runner';12const storybookTestRunner = require('storybook-test-runner');13import { extraLogs } from 'storybook-test-runner';14const storybookTestRunner = require('storybook-test-runner');15import { extraLogs } from 'storybook-test-runner';
Using AI Code Generation
1const { extraLogs } = require('storybook-test-runner');2describe('my test suite', () => {3 extraLogs();4 it('my test', () => {5 });6});7describe('my test suite', () => {8 extraLogs();9 it('my test', () => {10 });11});12describe('my test suite', () => {13 extraLogs();14 it('my test', () => {15 });16});17describe('my test suite', () => {18 extraLogs();19 it('my test', () => {20 });21});22describe('my test suite', () => {23 extraLogs();24 it('my test', () => {25 });26});27describe('my test suite', () => {28 extraLogs();29 it('my test', () => {30 });31});32describe('my test suite', () => {33 extraLogs();34 it('my test', () => {35 });36});37describe('my test suite', () => {38 extraLogs();39 it('my test', () => {40 });41});42describe('my test suite', () => {43 extraLogs();44 it('my test', () => {45 });46});47describe('my test suite', () => {48 extraLogs();49 it('my test', () => {50 });51});52describe('my test suite', () => {53 extraLogs();54 it('my test', () => {55 });56});
Using AI Code Generation
1import { extraLogs } from 'storybook-test-runner';2describe('test', () => {3 it('should log', () => {4 extraLogs();5 expect(1).toBe(1);6 });7});8import { configure, addDecorator } from '@storybook/react';9import { extraLogs } from 'storybook-test-runner';10addDecorator(extraLogs);11configure(require.context('../src', true, /\.stories\.js$/), module);12const path = require('path');13module.exports = async ({ config, mode }) => {14 config.module.rules.push({15 {16 loader: require.resolve('@storybook/source-loader'),17 options: {18 prettierConfig: {19 },20 },21 },22 });23 config.module.rules.push({24 test: /\.(ts|tsx)$/,25 {26 loader: require.resolve('awesome-typescript-loader'),27 options: {28 configFileName: path.resolve(__dirname, '../tsconfig.json'),29 },30 },31 {32 loader: require.resolve('react-docgen-typescript-loader'),33 },34 });35 config.resolve.extensions.push('.ts', '.tsx');36 return config;37};38import '@storybook/addon-actions/register';39import '@storybook/addon-knobs/register';40import '@storybook/addon-links/register';41import { setConsoleOptions } from '@storybook/addon-console';42setConsoleOptions({43});44import React from 'react';45import { addDecorator } from '@storybook/react';46import { withConsole } from '@storybook/addon-console';47import { withInfo } from '@storybook/addon-info';48import { withA11y } from '@storybook/addon-a11y';49import { withKnobs } from '@storybook/addon-knobs';50import { withTests } from '@storybook/addon-jest';51import { withOptions } from '@storybook/addon-options';52import { withContexts }
Using AI Code Generation
1const { extraLogs } = require('storybook-test-runner');2const { expect } = require('chai');3describe('test', () => {4 it('test', async () => {5 const { browser, page } = await extraLogs();6 await page.waitForSelector('button');7 await page.click('button');8 const text = await page.$eval('div', (el) => el.innerText);9 expect(text).to.equal('Hello World!');10 await browser.close();11 });12});13import { addParameters, configure } from '@storybook/html';14import { setConsoleOptions } from '@storybook/addon-console';15import { withConsole } from '@storybook/addon-console';16setConsoleOptions({17});18addParameters({19 console: {20 },21});22addDecorator((storyFn, context) => withConsole()(storyFn)(context));23const req = require.context('../stories', true, /.stories.js$/);24function loadStories() {25 req.keys().forEach((filename) => req(filename));26}27configure(loadStories, module);28const path = require('path');29module.exports = async ({ config, mode }) => {30 config.module.rules.push({31 loaders: [require.resolve('@storybook/source-loader')],32 });33 config.module.rules.push({34 options: {35 },36 });37 config.resolve = {38 alias: {39 '@': path.resolve(__dirname, '../src'),40 },41 };42 return config;43};44import '@storybook/addon-console';45import '@storybook/addon-actions/register';46import '@storybook/addon-links/register';47import '@storybook/addon-viewport/register';48import '@storybook/addon-notes/register-panel';49import { addDecorator, addParameters } from '@storybook/html';50import { withConsole } from '@storybook/addon-console';51addDecorator((storyFn, context) => withConsole()(storyFn)(context));52addParameters({53 options: {54 },55});
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!