diff --git a/src/app/helpers/stem.ts b/src/app/helpers/stem.ts index b060ae6..37ba5fb 100644 --- a/src/app/helpers/stem.ts +++ b/src/app/helpers/stem.ts @@ -61,9 +61,18 @@ export const defaultSTEM: () => ISTEM = () => { spellName: '', maxSkillForGain: 0, mpCost: 0, - skillMultiplierChanges: [], + castTime: 0, + cooldown: 0, + potencyMultiplier: 1, + bonusRollsMin: 0, + bonusRollsMax: 0, + willSaveThreshold: 0, + willSavePercent: 0, + skillMultiplierChanges: [[0, 1]], spellMeta: { - spellRef: '', + bonusAgro: 0, + creatureSummoned: [], + fizzledBy: [], }, }, diff --git a/src/app/shared/components/input-effect/input-effect.component.ts b/src/app/shared/components/input-effect/input-effect.component.ts index c86890d..04ecf93 100644 --- a/src/app/shared/components/input-effect/input-effect.component.ts +++ b/src/app/shared/components/input-effect/input-effect.component.ts @@ -7,7 +7,6 @@ import { model, output, } from '@angular/core'; -import { ElectronService } from '../../../services/electron.service'; import { ModService } from '../../../services/mod.service'; @Component({ @@ -16,10 +15,9 @@ import { ModService } from '../../../services/mod.service'; styleUrl: './input-effect.component.scss', }) export class InputEffectComponent { - private electronService = inject(ElectronService); private modService = inject(ModService); - public effect = model(); + public effect = model<{ value: string } | undefined>(); public label = input('Effect'); public defaultValue = input(); public change = output(); @@ -58,7 +56,7 @@ export class InputEffectComponent { const defaultItem = this.defaultValue(); if (defaultItem) { const foundItem = this.values().find((i) => i.value === defaultItem); - this.effect.set(foundItem as unknown as string); + this.effect.set(foundItem as unknown as { value: string }); } }, { allowSignalWrites: true } diff --git a/src/app/tabs/stems/stems-editor/stems-editor.component.html b/src/app/tabs/stems/stems-editor/stems-editor.component.html index e780488..c069361 100644 --- a/src/app/tabs/stems/stems-editor/stems-editor.component.html +++ b/src/app/tabs/stems/stems-editor/stems-editor.component.html @@ -128,16 +128,418 @@ @case (1) { + +
-
+
+ Spell Name + +
+ + +
+
+
+ Max Skill For Gains + +
+
+ +
+
+ Bonus Agro On Cast + +
+
+
+ + +
+
+
+ MP Cost + +
+
+ +
+
+ Cast Time + +
+
+ +
+
+ Cooldown + +
+
+
+ +
+ +
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+ Potency Multiplier + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+ Bonus Rolls Min + +
+
+ +
+
+ Bonus Rolls Max + +
+
+
+ +
+ +
+
+
+ +
+
+ +
+ @if(editingData.spell.spellMeta.aoe) { +
+ +
+ } +
+
+ + @if(editingData.spell.spellMeta.aoe) { +
+
+
+ AoE Range + +
+
+ +
+
+ +
+
+
+ } + + @if(editingData.spell.spellMeta.doesAttack || editingData.spell.spellMeta.doesOvertime) { +
+
+
+ Will Save Threshold + +
+
+ +
+
+ Will Save % + +
+
+
+ } + +
+
+
+ +
+
+ +
+ @if(editingData.spell.spellMeta.canBeResisted) { +
+ +
+ } +
+
+ + @if(editingData.spell.spellMeta.doesAttack) { +
+ +
+ } +
+
+
+ Caster Message + +
+ +
+ Caster Attack Message + +
+ +
+ +
+ +
+ Target Message + +
+ +
+ Target Attack Message + +
+ +
+ +
+
+
+ +
+ + @for(item of editingData.spell.skillMultiplierChanges; track item) { +
+
+
+ Caster Skill + +
+
+ +
+
+ Potency + +
+
+ +
+
+ +
+
+
+ } + +
+ +
+
+ +
+
+ +
+
+ +
+
+
+ + @for(npc of sortSpellSummonNPCs(editingData.spell.spellMeta.creatureSummoned); track $index) { +
+
+
+ +
+
+ +
+
+ +
+
+
+ } + +
+
+
+ +
+
+ +
+
+ +
+
+
+ + @for(effect of sortSpellFizzleEffects(editingData.spell.spellMeta.fizzledBy); track $index) { +
+
+
+ {{ effect }} +
+
+ +
+
+ +
+
+
+ }
} @@ -430,11 +832,13 @@
- +
- +
diff --git a/src/app/tabs/stems/stems-editor/stems-editor.component.ts b/src/app/tabs/stems/stems-editor/stems-editor.component.ts index 91cbf38..d79ee89 100644 --- a/src/app/tabs/stems/stems-editor/stems-editor.component.ts +++ b/src/app/tabs/stems/stems-editor/stems-editor.component.ts @@ -1,6 +1,6 @@ import { Component, computed, OnInit, signal } from '@angular/core'; import { isBoolean, isString } from 'lodash'; -import { StatType } from '../../../../interfaces'; +import { INPCDefinition, StatType } from '../../../../interfaces'; import { ISTEM } from '../../../../interfaces/stem'; import { EditorBaseComponent } from '../../../shared/components/editor-base/editor-base.component'; @@ -70,6 +70,10 @@ export class StemsEditorComponent public currentItem = signal(undefined); public currentTraitStat = signal('agi'); + public currentSpellNPC = signal(undefined); + public currentSpellFizzleEffect = signal<{ value: string } | undefined>( + undefined + ); public canSave = computed(() => { const data = this.editing(); @@ -164,6 +168,114 @@ export class StemsEditorComponent }); } + setSpellAttack($event: boolean) { + if (!$event) return; + + const editing = this.editing(); + editing.spell = { + ...editing.spell, + spellMeta: { + ...editing.spell.spellMeta, + doesOvertime: false, + doesHeal: false, + }, + }; + + this.editing.set(editing); + } + + setSpellHeal($event: boolean) { + if (!$event) return; + + const editing = this.editing(); + editing.spell = { + ...editing.spell, + spellMeta: { + ...editing.spell.spellMeta, + doesOvertime: false, + doesAttack: false, + noHostileTarget: true, + noReflect: true, + }, + }; + + this.editing.set(editing); + } + + setSpellOvertime($event: boolean) { + if (!$event) return; + + const editing = this.editing(); + editing.spell = { + ...editing.spell, + spellMeta: { + ...editing.spell.spellMeta, + doesAttack: false, + doesHeal: false, + }, + }; + + this.editing.set(editing); + } + + addSpellPotencyMultiplier() { + const editing = this.editing(); + editing.spell.skillMultiplierChanges.push([]); + this.editing.set(editing); + } + + removeSpellPotencyMultiplier(index: number) { + const editing = this.editing(); + editing.spell.skillMultiplierChanges.splice(index, 1); + this.editing.set(editing); + } + + addSpellSummonNPC(npc: INPCDefinition | undefined) { + if (!npc) return; + + const editing = this.editing(); + editing.spell.spellMeta.creatureSummoned.push(npc.npcId); + this.editing.set(editing); + } + + removeSpellSummonNPC(index: number) { + const editing = this.editing(); + editing.spell.spellMeta.creatureSummoned.splice(index, 1); + this.editing.set(editing); + } + + hasSpellSummonNPC(npc: INPCDefinition | undefined): boolean { + if (!npc) return false; + return this.editing().spell.spellMeta.creatureSummoned.includes(npc.npcId); + } + + sortSpellSummonNPCs(npcs: string[]): string[] { + return npcs.sort(); + } + + addSpellFizzleEffect(effect: string | undefined) { + if (!effect) return; + + const editing = this.editing(); + editing.spell.spellMeta.fizzledBy.push(effect); + this.editing.set(editing); + } + + removeSpellFizzleEffect(index: number) { + const editing = this.editing(); + editing.spell.spellMeta.fizzledBy.splice(index, 1); + this.editing.set(editing); + } + + hasSpellFizzleEffect(effect: string | undefined): boolean { + if (!effect) return false; + return this.editing().spell.spellMeta.fizzledBy.includes(effect); + } + + sortSpellFizzleEffects(effects: string[]): string[] { + return effects.sort(); + } + doSave() { const core = this.editing(); diff --git a/src/interfaces/spell.ts b/src/interfaces/spell.ts index 491c1fd..f36309b 100644 --- a/src/interfaces/spell.ts +++ b/src/interfaces/spell.ts @@ -13,7 +13,7 @@ export interface ISpell { potencyMultiplier?: number; // the overall multiplier to the potency of the skill bonusRollsMin?: number; // the number of bonus rolls this spell will roll at minimum (default 0) bonusRollsMax?: number; // the number of bonus rolls this spell will roll at maximum (default 0) - skillMultiplierChanges?: number[][]; // the skill multiplier buffs when you reach a certain skill threshold + skillMultiplierChanges: number[][]; // the skill multiplier buffs when you reach a certain skill threshold spellMeta: { aoe?: boolean; // whether or not this spell is an aoe @@ -23,7 +23,7 @@ export interface ISpell { canBeResisted?: boolean; // whether or not the spell can be resisted outright noReflect?: boolean; // whether or not the spell can NOT be reflected (useful for cures, etc) staticPotency?: boolean; // whether or not the potency for this spell should be static (buffs should be consistent) - creatureSummoned?: string[]; // if this spell summons a creature, this is the npc id + creatureSummoned: string[]; // if this spell summons a creature, this is the npc id doesHeal?: boolean; // if the spell does a heal (inverse attack), it calls this first doesAttack?: boolean; // if the spell does an attack, it calls this first doesOvertime?: boolean; // if the spell has an over-time component, it is applied automatically @@ -38,8 +38,7 @@ export interface ISpell { targetsParty?: boolean; // if the spell targets the entire casters party (aka, powerwords) range?: number; // if the spell is an aoe, this is the default range from the center it targets (default 0) resistLowerTrait?: string; // if the spell canBeResisted, this trait will improve the chance of the spell cast going through - spellRef: string; // the reference to the spell for casting purposes useSkillAsPotency?: boolean; // if true, the spell will use only the casters skill as the potency (unless there is already a potency set) - fizzledBy?: string[]; // if set, the spell will not take hold on any target if they contain an effect listed in this array + fizzledBy: string[]; // if set, the spell will not take hold on any target if they contain an effect listed in this array }; }