Skip to content

Commit

Permalink
Add support for item allowing to cast spell on superior level
Browse files Browse the repository at this point in the history
  • Loading branch information
Socolin committed Jul 29, 2024
1 parent 0bdce9f commit fe5936c
Show file tree
Hide file tree
Showing 28 changed files with 376 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/app/actor/character-sheet-equipment.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from '../data-accessor/selectors/character-selectors';
import {Lvl0Item, Lvl0ItemAmmunition, Lvl0ItemPotions, Lvl0ItemWeapon} from '../data-accessor/models/lvl0-item';
import {UnionKeys} from '../../utils/util';
import {AmmunitionType, ItemModifierInfo} from '../../models/item';
import {AmmunitionType} from '../../models/item';
import {SkillDefinition} from '../../repositories';
import {ItemUpdaterService} from '../data-accessor/item-updater.service';
import {ActorUpdaterService} from '../data-accessor/actor-updater.service';
Expand Down
2 changes: 2 additions & 0 deletions src/app/data-accessor/models/lvl0-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
WandItemProperties,
WeaponItemProperties
} from '../../../models/item';
import {ItemPropertiesUniqueCapabilities} from '../../../models/item/properties/item-properties-unique-capabilities';

export type BaseLvl0Item = {
id: string;
Expand Down Expand Up @@ -72,5 +73,6 @@ export type Lvl0Item =
| Lvl0ItemWeapon;

export type Lvl0ItemWithModifiers = Lvl0Item & { system: ItemPropertiesTemplateStatModifiers };
export type Lvl0ItemWithUniqueCapabilities = BaseLvl0Item & { system: ItemPropertiesUniqueCapabilities };
export type Lvl0ItemWitExtraSkills = Lvl0Item & { system: ItemPropertiesTemplateExtraSkills };

Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,39 @@ import {SystemDataDatabaseService} from '../../system-data/system-data-database.
import {selectCharacterJobDefinition} from './character-job-definition-selector';
import {selectCharacterJobSpecializations} from './character-job-specializations-selector';
import _ from 'lodash';
import {
selectSuperiorArcaneCapability, SuperiorArcaneCapability
} from './character-superior-arcane-capability-selector';


export type CharacterSuperiorArcaneCapability = {
sourceType: 'item';
sourceId: string;
label: string;
levelDiff: number;
cost: number;
damage: number;
}

export type CharacterAvailableSpell = {
spellDefinition: SpellDefinition,
superiorArcaneCapability?: CharacterSuperiorArcaneCapability
}

export class CharacterAvailableSpellsSelector {
static listAvailableSpells(
systemDataDatabaseService: SystemDataDatabaseService,
arcaneLevel: number,
jobDefinition: JobDefinition | undefined,
jobSpecializations: string[],
manaValue: number
): SpellDefinition[] {
manaValue: number,
superiorArcaneCapabilities: SuperiorArcaneCapability[]
): CharacterAvailableSpell[] {
if (!jobDefinition)
return [];
if (!jobDefinition.spellClass)
return [];
let spells: SpellDefinition[] = [];
let spells: CharacterAvailableSpell[] = [];
for (let specialization of jobSpecializations) {
let specializationSpellsByLevels = systemDataDatabaseService.spellRepository.getSpellsByLevels(
jobDefinition.spellClass,
Expand All @@ -33,12 +52,43 @@ export class CharacterAvailableSpellsSelector {
}

for (let [level, spellDefinitions] of Object.entries(specializationSpellsByLevels)) {
if (+level > arcaneLevel)
let spellLevel = +level;
if (spellLevel > arcaneLevel) {
for (let superiorArcaneCapability of superiorArcaneCapabilities) {
if (spellLevel > (superiorArcaneCapability.maximumArcaneLevel || 20)) {
continue;
}
let levelDiff = spellLevel - arcaneLevel;
let manaCost = spellLevel;
if (superiorArcaneCapability.manaMultiplierPerLevel) {
manaCost = (superiorArcaneCapability.manaMultiplierPerLevel * levelDiff) * manaCost;
}
let damage = 0;
if (superiorArcaneCapability.damagePerLevel) {
damage = superiorArcaneCapability.damagePerLevel * levelDiff;
}
if (manaCost > manaValue)
continue;
for (let spellDefinition of spellDefinitions) {
spells.push({
spellDefinition: spellDefinition,
superiorArcaneCapability: {
sourceType: superiorArcaneCapability.sourceType,
sourceId: superiorArcaneCapability.sourceId,
label: superiorArcaneCapability.label,
levelDiff: levelDiff,
cost: manaCost,
damage: damage,
}
});
}
}
continue;
if (+level > manaValue)
}
if (spellLevel > manaValue)
continue;
for (let spellDefinition of spellDefinitions) {
spells.push(spellDefinition);
spells.push({spellDefinition: spellDefinition});
}
}
}
Expand All @@ -47,21 +97,23 @@ export class CharacterAvailableSpellsSelector {
}

export function selectAvailableSpells(systemDataDatabaseService: SystemDataDatabaseService) {
return function (source: Observable<Lvl0Character>): Observable<SpellDefinition[]> {
return new Observable<SpellDefinition[]>(subscriber => {
return function (source: Observable<Lvl0Character>): Observable<CharacterAvailableSpell[]> {
return new Observable<CharacterAvailableSpell[]>(subscriber => {
return combineLatest([
source.pipe(selectCharacterArcaneLevel(systemDataDatabaseService)),
source.pipe(selectCharacterJobDefinition(systemDataDatabaseService)),
source.pipe(selectCharacterJobSpecializations(systemDataDatabaseService)),
source.pipe(selectCharacterMana()),
source.pipe(selectSuperiorArcaneCapability()),
]).subscribe({
next([arcaneLevel, jobDefinition, jobSpecializations, mana]: [number, JobDefinition, string[], number]) {
next([arcaneLevel, jobDefinition, jobSpecializations, mana, superiorArcaneCapabilities]: [number, JobDefinition, string[], number, SuperiorArcaneCapability[]]) {
subscriber.next(CharacterAvailableSpellsSelector.listAvailableSpells(
systemDataDatabaseService,
arcaneLevel,
jobDefinition,
jobSpecializations,
mana
mana,
superiorArcaneCapabilities
));
},
error(error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class CharacterMaxManaSelector {

for (let levelData of levelUpData) {
if (levelData.level <= level.value) {
maxMana += levelData.mana;
maxMana += levelData.mana ?? 0;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {Lvl0Character} from '../models/lvl0-character';
import {combineLatest, distinctUntilChanged, Observable, shareReplay} from 'rxjs';
import _ from 'lodash';
import {Lvl0Item} from '../models/lvl0-item';
import {selectCharacterEquipedItems} from './character-equiped-items-selector';

export type SuperiorArcaneCapability = {
sourceType: 'item';
sourceId: string;
label: string;
manaMultiplierPerLevel?: number;
damagePerLevel?: number;
usageCountPerSessions?: number;
maximumArcaneLevel?: number;
}

export class CharacterSuperiorArcaneCapabilitySelector {
static selectSuperiorArcaneCapabilitySelector(
equipedItems: Lvl0Item[],
): SuperiorArcaneCapability[] {
let result: SuperiorArcaneCapability[] = [];
for (let equipedItem of equipedItems) {
if (!('superiorArcane' in equipedItem.system)) {
continue;
}
if (!equipedItem.system.superiorArcane?.active) {
continue;
}

result.push({
label: equipedItem.name,
sourceId: equipedItem.id,
sourceType: 'item',
...equipedItem.system.superiorArcane
} as SuperiorArcaneCapability)
}
return result;
}
}

export function selectSuperiorArcaneCapability() {
return function (source: Observable<Lvl0Character>): Observable<SuperiorArcaneCapability[]> {
return new Observable<SuperiorArcaneCapability[]>(subscriber => {
return combineLatest([
source.pipe(selectCharacterEquipedItems()),
]).subscribe({
next([equipedItems]: [Lvl0Item[]]) {
subscriber.next(CharacterSuperiorArcaneCapabilitySelector.selectSuperiorArcaneCapabilitySelector(
equipedItems,
));
},
error(error) {
subscriber.error(error);
},
complete() {
subscriber.complete();
}
})
}).pipe(
distinctUntilChanged((a, b) => _.isEqual(a, b)),
shareReplay(1)
);
};
}
Loading

0 comments on commit fe5936c

Please sign in to comment.