Skip to content

Commit

Permalink
make magic reports work
Browse files Browse the repository at this point in the history
  • Loading branch information
seiyria committed Aug 29, 2024
1 parent 9b9af62 commit 0e78d07
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 8 deletions.
7 changes: 7 additions & 0 deletions src/app/analysis/analysis.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ export class AnalysisComponent {
break;
}

case AnalysisReportType.SpellPotency: {
report = this.analysisService.generateSpellReport(
$event.data.spellName ?? ''
);
break;
}

case AnalysisReportType.TraitUsage: {
report = this.analysisService.generateTraitReport();
break;
Expand Down
93 changes: 93 additions & 0 deletions src/app/services/analysis.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
StatType,
WeaponClass,
} from '../../interfaces';
import { ISTEM } from '../../interfaces/stem';
import { ModService } from './mod.service';

@Injectable({
Expand Down Expand Up @@ -801,4 +802,96 @@ export class AnalysisService {
entries: [weaponReport, armorReport],
};
}

/**
* diceRoll(rolls: number, sides: number, minSidesDivisor = 2): number {
const min = sides / minSidesDivisor;
const max = sides;
return rolls * (min + Math.floor(Math.random() * (max - min + 1)));
}
*/

// 5,20 -> [20, 20, 20, 20, 20]
private calculateSpellDamage(
spell: ISTEM['spell'],
skill: number,
stat: number
): { min: number; max: number } {
const calcSkill = skill + 1;
const maxMult = spell.skillMultiplierChanges
.filter((m) => m[0] <= skill)
.reverse()[0][1];

const isStatic = spell.spellMeta.staticPotency;
const potencyMultiplier = spell.potencyMultiplier ?? 1;

if (spell.spellMeta.useSkillAsPotency)
return {
min: calcSkill * potencyMultiplier,
max: calcSkill * potencyMultiplier,
};

const bonusRollsMin = isStatic ? 0 : spell.bonusRollsMin ?? 0;
const bonusRollsMax = isStatic ? 0 : spell.bonusRollsMax ?? 0;

// base rolls
const baseRollsMin = calcSkill + bonusRollsMin;
const baseRollsMax = calcSkill + bonusRollsMax;

// sides = stat
const basePotencyMin = baseRollsMin * (stat / 2);
const basePotencyMax = baseRollsMax * (stat / 2 + (stat - stat / 2 + 1));

const retPotencyMin = basePotencyMin * maxMult * potencyMultiplier;
const retPotencyMax = basePotencyMax * maxMult * potencyMultiplier;

return {
min: retPotencyMin,
max: retPotencyMax,
};
}

public generateSpellReport(spellName: string): AnalysisReport {
const spellData = this.modService
.mod()
.stems.find((s) => s._gameId === spellName);
if (!spellData) return { entries: [] };

const allReports: AnalysisReportDisplay[] = [];

for (let skill = 1; skill <= 30; skill++) {
const spellReport: AnalysisReportDisplay = {
type: AnalysisDisplayType.Table,
table: {
title: `Spell Damage Calculations (Skill ${skill})`,
headers: [
'Skill Level',
'Primary Stat',
'Minimum Expected Potency',
'Maximum Expected Potency',
],
rows: [],
},
};

for (let stat = 10; stat <= 50; stat += 5) {
const damage = this.calculateSpellDamage(spellData.spell, skill, stat);

spellReport.table.rows.push([
{ pretext: skill.toString() },
{ pretext: stat.toString() },
{ pretext: damage.min.toFixed(0) },
{ pretext: damage.max.toFixed(0) },
]);
}

allReports.push(spellReport);
}

return {
entries: [...allReports],
};
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="relative">
<ng-select class="form-control" [items]="values()" [bindValue]="'value'" groupBy="category" [(ngModel)]="report"
placeholder="Select report..." (change)="change.emit($event)" [searchFn]="search">
placeholder="Select report..." (change)="change.emit($event)" [searchFn]="search" [virtualScroll]="true">

<ng-template ng-label-tmp let-item="item">
<div class="text-white">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Component, computed, input, model, output } from '@angular/core';
import {
Component,
computed,
inject,
input,
model,
output,
} from '@angular/core';
import { sortBy } from 'lodash';
import {
AnalysisReportType,
Expand All @@ -10,11 +17,12 @@ import {
WeaponClass,
} from '../../../../interfaces';
import { armorClasses, weaponClasses } from '../../../helpers';
import { ModService } from '../../../services/mod.service';

export type ReportModel = {
category: string;
type: AnalysisReportType;
data: { itemClasses?: ItemClassType[] };
data: { itemClasses?: ItemClassType[]; spellName?: string };
value: string;
};

Expand All @@ -24,29 +32,47 @@ export type ReportModel = {
styleUrl: './input-analysis-report.component.scss',
})
export class InputAnalysisReportComponent {
private modService = inject(ModService);

public report = model.required<ReportModel | undefined>();
public label = input<string>('Report');
public change = output<ReportModel | undefined>();

private allCalculableSpells = computed(() => {
return this.modService
.mod()
.stems.filter(
(s) => s._hasSpell && s.spell.skillMultiplierChanges?.length > 0
);
});

public values = computed(() => {
const allSpells = this.allCalculableSpells();
return sortBy(
[
...allSpells.map((spell) => ({
category: 'Potency Estimator (Spell)',
value: spell._gameId,
type: AnalysisReportType.SpellPotency,
data: { spellName: spell._gameId },
desc: `Level/skill varied damage calculator.`,
})),
...Object.values(WeaponClass).map((iClass) => ({
category: 'Item Progression',
category: 'Item Progression (Singular)',
value: iClass,
type: AnalysisReportType.Progression,
data: { itemClasses: [iClass] },
desc: `Level-by-level progression report.`,
})),
...Object.values(ArmorClass).map((iClass) => ({
category: 'Item Progression',
category: 'Item Progression (Singular)',
value: iClass,
type: AnalysisReportType.Progression,
data: { itemClasses: [iClass] },
desc: `Level-by-level progression report.`,
})),
{
category: 'Aggregate Item Progression',
category: 'Item Progression (Aggregate)',
value: 'Shield',
type: AnalysisReportType.Progression,
data: {
Expand All @@ -55,7 +81,7 @@ export class InputAnalysisReportComponent {
desc: `Level-by-level progression report (includes every Shield-adjacent item).`,
},
{
category: 'Aggregate Item Progression',
category: 'Item Progression (Aggregate)',
value: 'Armor',
type: AnalysisReportType.Progression,
data: {
Expand All @@ -64,7 +90,7 @@ export class InputAnalysisReportComponent {
desc: `Level-by-level progression report (includes every Armor-adjacent item).`,
},
{
category: 'Aggregate Item Progression',
category: 'Item Progression (Aggregate)',
value: 'Robe',
type: AnalysisReportType.Progression,
data: {
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export enum AnalysisReportType {
WeaponAverage = 'weaponaverage', // average weapon information by item class
TraitUsage = 'traitusage', // a list of all traits that are used and unused
StatUtilization = 'statutilization', // a list of all stats by utilization
SpellPotency = 'spellpotency', // a list of all skill/stat combos for spell damage estimation
}

export enum AnalysisDisplayType {
Expand Down

0 comments on commit 0e78d07

Please sign in to comment.