Skip to content

Commit

Permalink
better validation setup. closes #24
Browse files Browse the repository at this point in the history
  • Loading branch information
seiyria committed Aug 15, 2024
1 parent 68c5359 commit b106e43
Show file tree
Hide file tree
Showing 12 changed files with 535 additions and 488 deletions.
504 changes: 36 additions & 468 deletions src/app/helpers/validate.ts

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/app/helpers/validators/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * from './item';
export * from './map';
export * from './npc';
export * from './quest';
export * from './recipe';
export * from './spawner';
116 changes: 116 additions & 0 deletions src/app/helpers/validators/item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { get } from 'lodash';
import {
IModKit,
ItemSlotType,
ValidationMessageGroup,
} from '../../../interfaces';

export function checkItemStats(mod: IModKit): ValidationMessageGroup {
const itemValidations: ValidationMessageGroup = {
header: 'Awkward Item Stats & Settings',
messages: [],
};

mod.items.forEach((item) => {
const modsActionSpeed =
get(item, 'randomStats.actionSpeed') || get(item, 'stats.actionSpeed');
if (modsActionSpeed) {
itemValidations.messages.push({
type: 'warning',
message: `${item.name} modifies actionSpeed.`,
});
}

const destroysOnDrop = get(item, 'destroyOnDrop');
if (destroysOnDrop) {
itemValidations.messages.push({
type: 'warning',
message: `${item.name} destroys on drop.`,
});
}
});

if (itemValidations.messages.length === 0) {
itemValidations.messages.push({
type: 'good',
message: 'No abnormalities!',
});
}

return itemValidations;
}

export function checkItemUses(mod: IModKit): ValidationMessageGroup {
const itemValidations: ValidationMessageGroup = {
header: 'Unused Items',
messages: [],
};

// item count tracker
const itemCounts: Record<string, number> = {};

const addItemCount = (itemName: string) => {
if (itemCounts[itemName] >= 0) {
itemCounts[itemName]++;
}
};

mod.items.forEach((item) => {
itemCounts[item.name] = 0;
});

// count item usages by type
mod.drops.forEach((droptable) => {
addItemCount(droptable.result);
});

mod.recipes.forEach((recipe) => {
addItemCount(recipe.item);

(recipe.ingredients || []).forEach((ing) => {
addItemCount(ing);
});
});

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

Object.keys(npc.items.equipment || {}).forEach((slot) => {
(npc.items.equipment[slot as ItemSlotType] || []).forEach((item) => {
addItemCount(item.result);
});
});

if (npc.tansFor) {
addItemCount(npc.tansFor);
}

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

npc.dropPool.items.forEach((item) => {
addItemCount(item.result);
});
});

Object.keys(itemCounts).forEach((item) => {
if (itemCounts[item] > 0) return;

itemValidations.messages.push({
type: 'warning',
message: `${item} is unused.`,
});
});

if (itemValidations.messages.length === 0) {
itemValidations.messages.push({
type: 'good',
message: 'No abnormalities!',
});
}

return itemValidations;
}
143 changes: 143 additions & 0 deletions src/app/helpers/validators/map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { IModKit, ValidationMessageGroup } from '../../../interfaces';

export function checkMapProperties(mod: IModKit): ValidationMessageGroup[] {
const groups: ValidationMessageGroup[] = [];

mod.maps.forEach((map) => {
const mapValidations: ValidationMessageGroup = {
header: `Map Properties (${map.name})`,
messages: [],
};

[
'itemExpirationHours',
'itemGarbageCollection',
'maxCreatures',
'maxLevel',
'maxSkill',
'region',
'respawnX',
'respawnY',
].forEach((prop) => {
if (map.map.properties[prop]) return;

mapValidations.messages.push({
type: 'error',
message: `${map.name} map does not have a ${prop} property.`,
});
});

groups.push(mapValidations);
});

return groups;
}

export function checkMapSpawners(mod: IModKit): ValidationMessageGroup[] {
const groups: ValidationMessageGroup[] = [];

const bosses: string[] = [];
const modSpawnerTags: Record<string, number> = {};
const usedSpawnerTags: Record<string, number> = {};

const addModSpawnerCount = (item: string) => {
if (modSpawnerTags[item] >= 0) {
modSpawnerTags[item]++;
}
};

const addUsedSpawnerCount = (item: string) => {
usedSpawnerTags[item] = usedSpawnerTags[item] || 0;
usedSpawnerTags[item]++;
};

mod.spawners.forEach((item) => {
modSpawnerTags[item.tag] = 0;
});

mod.maps.forEach((map) => {
map.map.layers[10].objects.forEach((spawner: any) => {
addModSpawnerCount(spawner.properties.tag as string);
addUsedSpawnerCount(spawner.properties.tag as string);

if (spawner.properties.lairName) {
bosses.push(spawner.properties.lairName as string);
}
});
});

// calculate unused spawners
const modSpawnerValidations: ValidationMessageGroup = {
header: `Unused Spawners`,
messages: [],
};

Object.keys(modSpawnerTags).forEach((item) => {
if (modSpawnerTags[item] > 0) return;

modSpawnerValidations.messages.push({
type: 'warning',
message: `${item} is unused.`,
});
});

if (modSpawnerValidations.messages.length === 0) {
modSpawnerValidations.messages.push({
type: 'good',
message: 'No abnormalities!',
});
}

groups.push(modSpawnerValidations);

// calculate map spawners
const mapSpawnerValidations: ValidationMessageGroup = {
header: `Map Spawners`,
messages: [],
};

Object.keys(usedSpawnerTags).forEach((item) => {
if (item === 'Global Lair') return;
if (usedSpawnerTags[item] > 0 && modSpawnerTags[item] > 0) return;

mapSpawnerValidations.messages.push({
type: 'error',
message: `${item} is not a valid spawner tag.`,
});
});

if (mapSpawnerValidations.messages.length === 0) {
mapSpawnerValidations.messages.push({
type: 'good',
message: 'No abnormalities!',
});
}

groups.push(mapSpawnerValidations);

// calculate boss validations
const mapLairValidations: ValidationMessageGroup = {
header: `Lairs`,
messages: [],
};

bosses.forEach((boss) => {
if (mod.npcs.some((npc) => npc.npcId === boss)) return;

mapLairValidations.messages.push({
type: 'error',
message: `${boss} is not a valid lair.`,
});
});

if (mapLairValidations.messages.length === 0) {
mapLairValidations.messages.push({
type: 'good',
message: 'No abnormalities!',
});
}

groups.push(mapLairValidations);

return groups;
}
98 changes: 98 additions & 0 deletions src/app/helpers/validators/npc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { IModKit, ValidationMessageGroup } from '../../../interfaces';

export function checkMapNPCDialogs(mod: IModKit): ValidationMessageGroup {
// check npc dialog refs, make sure they exist
const mapDialogValidations: ValidationMessageGroup = {
header: `Unused NPC Scripts`,
messages: [],
};

const foundDialogs: Record<string, number> = {};

const addDialogCount = (item: string) => {
foundDialogs[item] ??= 0;
foundDialogs[item]++;
};

mod.maps.forEach((map) => {
map.map.layers[9].objects.forEach((npc: any) => {
addDialogCount(npc.properties.tag as string);
});
});

mod.dialogs.forEach((dia) => {
if (foundDialogs[dia.tag]) return;

mapDialogValidations.messages.push({
type: 'warning',
message: `${dia.tag} is unused.`,
});
});

if (mapDialogValidations.messages.length === 0) {
mapDialogValidations.messages.push({
type: 'good',
message: 'No abnormalities!',
});
}

return mapDialogValidations;
}

export function checkNPCUsages(mod: IModKit) {
const npcValidations: ValidationMessageGroup = {
header: `Unused NPCs`,
messages: [],
};

// item count tracker
const itemCounts: Record<string, number> = {};

const addItemCount = (itemName: string) => {
if (itemCounts[itemName] >= 0) {
itemCounts[itemName]++;
}
};

mod.npcs.forEach((item) => {
itemCounts[item.npcId] = 0;
});

mod.spawners.forEach((spawner) => {
spawner.npcIds.forEach((npcId) => {
addItemCount(npcId.result);
});
});

mod.quests.forEach((quest) => {
quest.requirements.npcIds.forEach((npcId) => {
addItemCount(npcId);
});
});

mod.maps.forEach((map) => {
map.map.layers[10].objects.forEach((spawner: any) => {
if (spawner.properties.lairName) {
addItemCount(spawner.properties.lairName as string);
}
});
});

Object.keys(itemCounts).forEach((item) => {
if (itemCounts[item] > 0) return;

npcValidations.messages.push({
type: 'warning',
message: `${item} is unused.`,
});
});

if (npcValidations.messages.length === 0) {
npcValidations.messages.push({
type: 'good',
message: 'No abnormalities!',
});
}

return npcValidations;
}
26 changes: 26 additions & 0 deletions src/app/helpers/validators/quest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { IModKit, ValidationMessageGroup } from '../../../interfaces';

export function checkQuests(mod: IModKit): ValidationMessageGroup {
const itemValidations: ValidationMessageGroup = {
header: `Quests`,
messages: [],
};

mod.quests.forEach((quest) => {
if (quest.rewards.length === 0) {
itemValidations.messages.push({
type: 'warning',
message: `Quest ${quest.name} does not have any rewards.`,
});
}
});

if (itemValidations.messages.length === 0) {
itemValidations.messages.push({
type: 'good',
message: 'No abnormalities!',
});
}

return itemValidations;
}
Loading

0 comments on commit b106e43

Please sign in to comment.