Skip to content

Commit

Permalink
Feat/recipe creation (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
misterpotts authored Jan 2, 2023
1 parent e6add81 commit 85cbb28
Show file tree
Hide file tree
Showing 60 changed files with 3,486 additions and 2,090 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
/package-lock.json
/.nyc_output/
/coverage/
/dist
/dist
/.idea/watcherTasks.xml
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fabricate",
"version": "0.7.1",
"version": "0.7.2",
"description": "A system-agnostic, flexible crafting module for FoundryVT",
"main": "index.js",
"scripts": {
Expand Down
46 changes: 44 additions & 2 deletions src/lang/en.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,46 @@
{
"fabricate": {
"EditComponentDialog": {
"title": "Fabricate | Component"
"ComponentManagerApp": {
"title": "Fabricate | Component",
"essences": {
"title": "Essences",
"instructions": "The component is imbued with these essences. Left click on an essence to increase its potency. Shift click while doing so to decrease it."
},
"salvage": {
"title": "Salvage",
"instructions": "These components will be reclaimed when the item is salvaged. Left click on a component to increase its salvage value. Shift click while doing so to decrease it."
}
},
"RecipeManagerApp": {
"title": "Fabricate | Recipe",
"summary": {
"title": "Summary",
"instructions": "This Recipe has the following features. Use the left navigation menu to edit each aspect of the Recipe respectively. "
},
"essences": {
"title": "Essences",
"instructions": "The recipe requires these essences in addition to any named ingredients and catalysts. Left click on an essence to increase the required amount. Shift click while doing so to decrease it.",
"notAvailable": "This crafting system has no Essences specified."
},
"search": "Search available components",
"ingredients": {
"title": "Ingredients",
"instructions": "The recipe requires these ingredients in addition to any essences and catalysts. A recipe can have more than one combination of ingredients to choose from. Drag and drop a component onto an empty result combination option to create a new one, or drop a component into an existing combination. Left click on a component to increase the number required in each option. Shift click while doing so to decrease it. ",
"addCombinationOption": "Drag and drop a component here to create a new option for Recipe ingredients. ",
"noneSet": "This Recipe has no named ingredients. "
},
"results": {
"title": "Results",
"instructions": "The recipe produces these components when successfully crafted. A recipe can have more than one combination of results to choose from. Drag and drop a component onto an empty result combination option to create a new one, or drop a component into an existing combination. Left click on a component to increase the number produced in each option. Shift click while doing so to decrease it. ",
"addCombinationOption": "Drag and drop a component here to create a new option for the Recipe results. ",
"noneSet": "This Recipe has no results. You might want to add some. "
},
"catalysts": {
"title": "Catalysts",
"instructions": "The recipe requires these catalysts to be present in order to be crafted. Catalysts are not consumed by crafting.",
"add": "Left click a component below to add it as a catalyst for this Recipe. You can left click existing catalysts to increase the required number, or shift click while doing so to decrease it. ",
"noneSet": "This recipe has no catalysts. "
}
},
"EditEssenceDialog": {
"title": "Fabricate | Essence",
Expand Down Expand Up @@ -90,6 +129,9 @@
"content": "{errorMessage}. \n You can reset Fabricate to resolve the error, but this will delete all except the bundled crafting systems!"
},
"tabs": {
"recipes": {
"optionTooltip": "{size} Components"
},
"essences": {
"description": "Essences are a quality of a component. They define something that the component has, not something that it is. Components might have multiple Essences in different quantities, all of which you can define for your system. Not every crafting system needs essences. However, if you do want to add them to components, you'll need to define them here first.",
"create": "Add a new Essence",
Expand Down
2 changes: 1 addition & 1 deletion src/module.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "fabricate",
"title": "Fabricate",
"version": "0.7.1",
"version": "0.7.2",
"description": "A system-agnostic, flexible crafting module for FoundryVTT",
"authors": [
{
Expand Down
9 changes: 5 additions & 4 deletions src/scripts/Properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ const Properties = {
id: "fabricate",
label: "Fabricate",
templates: {
recipeTab: "modules/fabricate/templates/recipe-tab.hbs",
itemSheetCraftingTab: "modules/fabricate/templates/item-sheet-crafting-tab.hbs",
craftingTab: "modules/fabricate/templates/crafting-tab.hbs",
craftingMessage: "modules/fabricate/templates/chat-message.hbs",
craftingSystemManagementApp: "modules/fabricate/templates/crafting-system-manager.hbs",
ComponentManagerApp: "modules/fabricate/templates/edit-component-dialog.hbs",
EssenceManagerApp: "modules/fabricate/templates/edit-essence-details.hbs",
EditCraftingSystemDetailDialog: "modules/fabricate/templates/edit-crafting-system-detail.hbs",
componentManagerApp: "modules/fabricate/templates/component-manager.hbs",
recipeManagerApp: "modules/fabricate/templates/recipe-manager.hbs",
editEssenceDialog: "modules/fabricate/templates/edit-essence-details.hbs",
editCraftingSystemDetailDialog: "modules/fabricate/templates/edit-crafting-system-detail.hbs",
partials: {
editableSystem: "modules/fabricate/templates/partials/editable-crafting-system.hbs",
readOnlySystem: "modules/fabricate/templates/partials/readonly-crafting-system.hbs",
Expand Down
26 changes: 13 additions & 13 deletions src/scripts/actor/ComponentCombinationGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ComponentCombinationNode} from "./ComponentCombinationNode";
import {Combination, Unit} from "../common/Combination";
import {Essence} from "../common/Essence";
import {CraftingComponent} from "../common/CraftingComponent";
import {Essence} from "../common/Essence";

export class ComponentCombinationGenerator {

Expand All @@ -11,32 +11,32 @@ export class ComponentCombinationGenerator {
constructor(availableComponents: Combination<CraftingComponent>, requiredEssences: Combination<Essence>) {
this._requiredEssences = requiredEssences;
this._roots = availableComponents.members
.map((component: CraftingComponent) => Combination.ofUnit(new Unit<CraftingComponent>(component, 1)))
.map((combination: Combination<CraftingComponent>) => new ComponentCombinationNode(requiredEssences, combination, availableComponents.subtract(combination)));
.map((component) => Combination.ofUnit(new Unit(component, 1)))
.map((combination) => new ComponentCombinationNode(requiredEssences, combination, availableComponents.subtract(combination)));
}

private allCombinations(baseNodes: ComponentCombinationNode[]): ComponentCombinationNode[] {
const generatedCombinations: ComponentCombinationNode[] = [];
let treeLevel: ComponentCombinationNode[] = baseNodes;
let treeLevel = baseNodes;
while (treeLevel.length > 0) {
treeLevel.forEach((node: ComponentCombinationNode) => {
generatedCombinations.push(node);
});
treeLevel = treeLevel.filter((node: ComponentCombinationNode) => node.hasChildren())
.map((node: ComponentCombinationNode) => node.children)
.reduce((left: ComponentCombinationNode[], right: ComponentCombinationNode[]) => left.concat(right), []);
treeLevel = treeLevel.filter((node) => node.hasChildren())
.map((node) => node.children)
.reduce((left, right) => left.concat(right), []);
}
return generatedCombinations;
}

private excludeInsufficient(allCombinations: ComponentCombinationNode[], requiredEssences: Combination<Essence>): ComponentCombinationNode[] {
return allCombinations.filter((node: ComponentCombinationNode) => node.essenceCombination.size() >= requiredEssences.size()
return allCombinations.filter((node) => node.essenceCombination.size() >= requiredEssences.size()
&& requiredEssences.isIn(node.essenceCombination));
}

private excludeDuplicates(sufficientCombinations: ComponentCombinationNode[]): [Combination<CraftingComponent>, Combination<Essence>][] {
const suitableCombinationsBySize: Map<number, [Combination<CraftingComponent>, Combination<Essence>][]> = new Map();
sufficientCombinations.forEach((node: ComponentCombinationNode) => {
sufficientCombinations.forEach((node) => {
if (!suitableCombinationsBySize.has(node.componentCombination.size())) {
suitableCombinationsBySize.set(node.componentCombination.size(), [[node.componentCombination, node.essenceCombination]]);
} else {
Expand All @@ -53,14 +53,14 @@ export class ComponentCombinationGenerator {
}
}
});
return Array.from(suitableCombinationsBySize.values(), (combinations: [Combination<CraftingComponent>, Combination<Essence>][]) => combinations)
.reduce((left: [Combination<CraftingComponent>, Combination<Essence>][], right: [Combination<CraftingComponent>, Combination<Essence>][]) => left.concat(right), []);
return Array.from(suitableCombinationsBySize.values(), (combinations) => combinations)
.reduce((left, right) => left.concat(right), []);
}

public generate(): [Combination<CraftingComponent>, Combination<Essence>][] {
this._roots.forEach((node: ComponentCombinationNode) => node.populate());
const generatedCombinations: ComponentCombinationNode[] = this.allCombinations(this._roots);
const suitableCombinations: ComponentCombinationNode[] = this.excludeInsufficient(generatedCombinations, this._requiredEssences);
const generatedCombinations = this.allCombinations(this._roots);
const suitableCombinations = this.excludeInsufficient(generatedCombinations, this._requiredEssences);
return this.excludeDuplicates(suitableCombinations);
}

Expand Down
2 changes: 1 addition & 1 deletion src/scripts/actor/ComponentCombinationNode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Combination, Unit} from "../common/Combination";
import {Essence} from "../common/Essence";
import {CraftingComponent} from "../common/CraftingComponent";
import {Essence} from "../common/Essence";

export class ComponentCombinationNode {
private readonly _requiredEssences: Combination<Essence>;
Expand Down
8 changes: 0 additions & 8 deletions src/scripts/actor/ComponentSearch.ts

This file was deleted.

30 changes: 0 additions & 30 deletions src/scripts/actor/EssenceSearch.ts

This file was deleted.

10 changes: 5 additions & 5 deletions src/scripts/actor/EssenceSelection.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Combination} from "../common/Combination";
import {Essence} from "../common/Essence";
import {CraftingComponent} from "../common/CraftingComponent";
import {ComponentCombinationGenerator} from "./ComponentCombinationGenerator";
import {Essence} from "../common/Essence";

export class EssenceSelection {

Expand All @@ -15,7 +15,7 @@ export class EssenceSelection {
if (this._essences.isEmpty()) {
return Combination.EMPTY();
}
let availableComponents: Combination<CraftingComponent> = contents.clone();
let availableComponents = contents.clone();
contents.members.forEach(((thisComponent: CraftingComponent) => {
if (thisComponent.essences.isEmpty() || !thisComponent.essences.intersects(this._essences)) {
availableComponents = availableComponents.subtract(availableComponents.just(thisComponent));
Expand All @@ -28,15 +28,15 @@ export class EssenceSelection {
if (combinations.length === 0) {
return Combination.EMPTY();
}
const sortedCombinations: [Combination<CraftingComponent>, Combination<Essence>][] = combinations
.sort((left: [Combination<CraftingComponent>, Combination<Essence>], right: [Combination<CraftingComponent>, Combination<Essence>]) => {
const sortedCombinations = combinations
.sort((left, right) => {
return left[1].size() - right[1].size();
});
return sortedCombinations[0][0];
}

private matchingCombinationsFor(availableComponents: Combination<CraftingComponent>, requiredEssences: Combination<Essence>): [Combination<CraftingComponent>, Combination<Essence>][] {
const combinationGenerator: ComponentCombinationGenerator = new ComponentCombinationGenerator(availableComponents, requiredEssences);
const combinationGenerator = new ComponentCombinationGenerator(availableComponents, requiredEssences);
return combinationGenerator.generate();
}

Expand Down
17 changes: 0 additions & 17 deletions src/scripts/actor/IngredientSearch.ts

This file was deleted.

Loading

0 comments on commit 85cbb28

Please sign in to comment.