Skip to content

Commit

Permalink
update dialogs and item validation
Browse files Browse the repository at this point in the history
  • Loading branch information
seiyria committed Aug 17, 2024
1 parent e42d539 commit 6a25a93
Show file tree
Hide file tree
Showing 14 changed files with 118 additions and 91 deletions.
3 changes: 3 additions & 0 deletions src/app/helpers/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export const defaultNPCScript: () => INPCScript = () => ({
},
otherStats: {},
usableSkills: [],
maxWanderRandomlyDistance: 0,
noLeash: false,
items: {
equipment: {
rightHand: undefined as unknown as string,
Expand All @@ -44,5 +46,6 @@ export const defaultNPCScript: () => INPCScript = () => ({
dialog: {
keyword: {},
},
baseEffects: [],
behaviors: [],
});
18 changes: 10 additions & 8 deletions src/app/helpers/export/npc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,16 @@ export function formatNPCs(npcs: INPCDefinition[]): INPCDefinition[] {

npc.repMod = npc.repMod.filter((rep: any) => rep.delta !== 0);

if (npc.drops.length === 0) delete npc.drops;
if (npc.copyDrops.length === 0) delete npc.copyDrops;
if (npc.dropPool.items.length === 0) delete npc.dropPool;

Object.values(ItemSlot).forEach((slot) => {
if (npc.items.equipment[slot]?.length > 0) return;
delete npc.items.equipment[slot];
});
if (!npc.drops || npc.drops.length === 0) delete npc.drops;
if (!npc.copyDrops || npc.copyDrops.length === 0) delete npc.copyDrops;
if (!npc.dropPool || npc.dropPool.items.length === 0) delete npc.dropPool;

if (npc.items?.equipment) {
Object.values(ItemSlot).forEach((slot) => {
if (npc.items.equipment[slot]?.length > 0) return;
delete npc.items.equipment[slot];
});
}

['leash', 'spawn', 'combat'].forEach((triggerType) => {
if (!npc.triggers?.[triggerType]?.messages) return;
Expand Down
29 changes: 14 additions & 15 deletions src/app/helpers/schemas/_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import {
Stat,
} from '../../../interfaces';

const itemSlots = [
'weapon',
'armor',
'shield',
'ring',
'robe',
...Object.values(ItemSlot),
] as ItemSlot[];

export function isArrayOf(validator: SchemaValidator): SchemaValidator {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return (val: any) => val.every(validator);
Expand Down Expand Up @@ -49,7 +58,7 @@ export function isObjectWithFailure(keys: string[]): SchemaValidatorMessage {
export function isObjectWithSome(keys: string[]): SchemaValidator {
return (val: any) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
return Object.keys(val).every((k) => keys.includes(k));
return Object.keys(val ?? {}).every((k) => keys.includes(k));
};
}

Expand All @@ -68,7 +77,7 @@ export function isObjectWithSomeFailure(
export function isPartialObjectOf<T>(possibleVals: T[]): SchemaValidator {
return (val: any) =>
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
Object.keys(val).every((k) => possibleVals.includes(k as T));
Object.keys(val ?? {}).every((k) => possibleVals.includes(k as T));
}

export function isPartialObjectOfFailure<T>(
Expand All @@ -94,17 +103,9 @@ export const isPartialSkillObjectFailure = isPartialObjectOfFailure<Skill>(
Object.values(Skill)
);

export const isPartialEquipmentObject = isPartialObjectOf<ItemSlot>([
'weapon',
'armor',
...Object.values(ItemSlot),
] as ItemSlot[]);
export const isPartialEquipmentObject = isPartialObjectOf<ItemSlot>(itemSlots);
export const isPartialEquipmentObjectFailure =
isPartialObjectOfFailure<ItemSlot>([
'weapon',
'armor',
...Object.values(ItemSlot),
] as ItemSlot[]);
isPartialObjectOfFailure<ItemSlot>(itemSlots);

export const isPartialReputationObject = isPartialObjectOf<Allegiance>(
Object.values(Allegiance)
Expand All @@ -113,9 +114,7 @@ export const isPartialReputationObjectFailure =
isPartialObjectOfFailure<Allegiance>(Object.values(Allegiance));

export function isItemSlot(val: any): boolean {
return (
['weapon', 'armor', ...Object.values(ItemSlot)] as ItemSlot[]
).includes(val as ItemSlot);
return itemSlots.includes(val as ItemSlot);
}

export function isTraitObject(val: any): boolean {
Expand Down
8 changes: 7 additions & 1 deletion src/app/helpers/schemas/dialog.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { isNumber, isObject, isString } from 'lodash';
import { isBoolean, isNumber, isObject, isString } from 'lodash';
import { Schema } from '../../../interfaces';
import {
isArrayOf,
isNPCEffect,
isObjectWith,
isPartialEquipmentObject,
isPartialEquipmentObjectFailure,
Expand All @@ -15,13 +16,17 @@ export const dialogSchema: Schema = [

['name', false, isString],
['affiliation', false, isString],
['forceAI', false, isString],
['allegiance', false, isString],
['alignment', false, isString],
['hostility', false, isString],
['level', false, isNumber],
['hp', false, isRandomNumber],
['mp', false, isRandomNumber],

['noLeash', false, isBoolean],
['maxWanderRandomlyDistance', false, isNumber],

['otherStats', false, isPartialStatObject, isPartialStatObjectFailure],
['usableSkills', false, isArrayOf(isString)],
['items', false, isObjectWith(['equipment'])],
Expand All @@ -33,4 +38,5 @@ export const dialogSchema: Schema = [
],
['dialog', false, isObjectWith(['keyword'])],
['behaviors', false, isArrayOf(isObject)],
['baseEffects', false, isArrayOf(isNPCEffect)],
];
16 changes: 8 additions & 8 deletions src/app/helpers/validators/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ export function checkItemUses(mod: IModKit): ValidationMessageGroup {
});

mod.npcs.forEach((npc) => {
npc.items.sack.forEach((item) => {
npc.items?.sack?.forEach((item) => {
addItemCount(item.result);
});

Object.keys(npc.items.equipment || {}).forEach((slot) => {
Object.keys(npc.items?.equipment ?? {}).forEach((slot) => {
(npc.items.equipment[slot as ItemSlotType] || []).forEach((item) => {
addItemCount(item.result);
});
Expand All @@ -87,11 +87,11 @@ export function checkItemUses(mod: IModKit): ValidationMessageGroup {
addItemCount(npc.tansFor);
}

npc.drops.forEach((item) => {
npc.drops?.forEach((item) => {
addItemCount(item.result);
});

npc.dropPool.items.forEach((item) => {
npc.dropPool?.items.forEach((item) => {
addItemCount(item.result);
});
});
Expand Down Expand Up @@ -153,7 +153,7 @@ export function nonexistentItems(mod: IModKit): ValidationMessageGroup {
});

mod.npcs.forEach((npc) => {
npc.items.sack.forEach((checkRollable) => {
npc.items?.sack?.forEach((checkRollable) => {
if (allItemNames[checkRollable.result]) return;

itemValidations.messages.push({
Expand All @@ -162,7 +162,7 @@ export function nonexistentItems(mod: IModKit): ValidationMessageGroup {
});
});

Object.keys(npc.items.equipment).forEach((itemslot) => {
Object.keys(npc.items?.equipment ?? {}).forEach((itemslot) => {
npc.items.equipment[itemslot as ItemSlotType]?.forEach(
(checkRollable) => {
if (allItemNames[checkRollable.result]) return;
Expand All @@ -175,7 +175,7 @@ export function nonexistentItems(mod: IModKit): ValidationMessageGroup {
);
});

npc.drops.forEach((checkRollable) => {
npc.drops?.forEach((checkRollable) => {
if (allItemNames[checkRollable.result]) return;

itemValidations.messages.push({
Expand All @@ -184,7 +184,7 @@ export function nonexistentItems(mod: IModKit): ValidationMessageGroup {
});
});

npc.dropPool.items.forEach((checkRollable) => {
npc.dropPool?.items?.forEach((checkRollable) => {
if (allItemNames[checkRollable.result]) return;

itemValidations.messages.push({
Expand Down
4 changes: 2 additions & 2 deletions src/app/helpers/validators/npc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function checkNPCUsages(mod: IModKit) {
});

mod.quests.forEach((quest) => {
quest.requirements.npcIds.forEach((npcId) => {
quest.requirements.npcIds?.forEach((npcId) => {
addItemCount(npcId);
});
});
Expand Down Expand Up @@ -131,7 +131,7 @@ export function nonexistentNPCs(mod: IModKit): ValidationMessageGroup {
});

mod.quests.forEach((quest) => {
quest.requirements.npcIds.forEach((npcId) => {
quest.requirements.npcIds?.forEach((npcId) => {
if (allNPCIds[npcId]) return;

itemValidations.messages.push({
Expand Down
2 changes: 1 addition & 1 deletion src/app/helpers/validators/spawner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function checkSpawners(mod: IModKit): ValidationMessageGroup {
});
}

if (!spawner.npcAISettings.includes('default')) {
if (!spawner.npcAISettings?.includes('default')) {
itemValidations.messages.push({
type: 'warning',
message: `Spawner ${spawner.tag} does not have the default AI setting.`,
Expand Down
5 changes: 3 additions & 2 deletions src/app/services/electron.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ export class ElectronService {
});

// the mod has no backup, which means it was a clean export. it might need some reformatting to get it back in
window.api.receive('loadmod', () => {
// this.modService.updateMod(mod);
window.api.receive('loadmod', (mod: IModKit) => {
const importedMod = importMod(mod);
this.modService.updateMod(importedMod);
});

// import the mod raw from the backup.
Expand Down
3 changes: 3 additions & 0 deletions src/app/shared/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { SpriteWithInlineNameComponent } from './components/sprite-with-inline-n
import { SpriteComponent } from './components/sprite/sprite.component';
import { TestViewComponent } from './components/test-view/test-view.component';
import { WebviewDirective } from './directives/';
import { EditBaseeffectComponent } from './components/edit-baseeffect/edit-baseeffect.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -93,6 +94,7 @@ import { WebviewDirective } from './directives/';
InputQuestComponent,
InputItemslotEncrustComponent,
TestViewComponent,
EditBaseeffectComponent,
],
imports: [
CommonModule,
Expand Down Expand Up @@ -146,6 +148,7 @@ import { WebviewDirective } from './directives/';
InputQuestComponent,
InputItemslotEncrustComponent,
TestViewComponent,
EditBaseeffectComponent,
],
})
export class SharedModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,29 @@
<div class="form-row">
<app-input-allegiance [(allegiance)]="editingData.allegiance"></app-input-allegiance>
</div>

<div class="form-row">
<app-input-floating-label>Max Randomly Wander Distance</app-input-floating-label>
<input [(ngModel)]="editingData.maxWanderRandomlyDistance" min="0" type="number" class="form-input" />
</div>

<div class="form-row pl-1">
<label class="label cursor-pointer"
floatUi="Whether or not this NPC should wander and never leash. Makes the NPC hard to find.">
<input type="checkbox" [(ngModel)]="editingData.noLeash" class="checkbox" />
<span class="label-text">No Leash</span>
</label>
</div>

<div class="form-row">
<button class="btn btn-accent btn-sm w-full" (click)="addBaseEffect()">
Add Base Effect
</button>
</div>

@for(baseEffect of editingData.baseEffects; track $index) {
<app-edit-baseeffect [baseEffect]="baseEffect" (remove)="removeBaseEffect($index)"></app-edit-baseeffect>
}
</div>

<div class="form-column">
Expand Down Expand Up @@ -195,4 +218,4 @@

<app-debug-view>
{{ editingData | json }}
</app-debug-view>
</app-debug-view>
28 changes: 25 additions & 3 deletions src/app/tabs/dialogs/dialogs-editor/dialogs-editor.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class DialogsEditorComponent

public statsInOrder = computed(() => {
const npc = this.editing();
return Object.keys(npc.otherStats).sort() as StatType[];
return Object.keys(npc.otherStats ?? {}).sort() as StatType[];
});

public behaviorError = computed(() => {
Expand All @@ -80,19 +80,21 @@ export class DialogsEditorComponent
ngOnInit(): void {
const npc = this.editing();

if (npc.behaviors.length > 0) {
if (npc.behaviors?.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
this.behaviorText.set(yaml.dump(npc.behaviors));
this.behaviorModel.value = this.behaviorText();
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (Object.keys(npc.dialog.keyword ?? {}).length > 0) {
if (Object.keys(npc.dialog?.keyword ?? {}).length > 0) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
this.dialogText.set(yaml.dump(npc.dialog));
this.dialogModel.value = this.dialogText();
}

npc.baseEffects ??= [];

super.ngOnInit();
}

Expand Down Expand Up @@ -138,6 +140,26 @@ export class DialogsEditorComponent
this.dialogText.set(dialogText);
}

public addBaseEffect() {
const npc = this.editing();
npc.baseEffects.push({
endsAt: -1,
name: undefined as unknown as string,
extra: {
potency: 1,
damageType: undefined,
enrageTimer: undefined,
},
});
this.editing.set(npc);
}

public removeBaseEffect(index: number) {
const npc = this.editing();
npc.baseEffects.splice(index, 1);
this.editing.set(npc);
}

doSave() {
const npc = this.editing();
npc.usableSkills = npc.usableSkills.filter(Boolean);
Expand Down
Loading

0 comments on commit 6a25a93

Please sign in to comment.