Skip to content

Commit

Permalink
add filter by items
Browse files Browse the repository at this point in the history
  • Loading branch information
AngryBeaver committed Oct 13, 2022
1 parent 209475f commit feba4ac
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 140 deletions.
71 changes: 69 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,72 @@
![Foundry System](https://img.shields.io/endpoint?url=https%3A%2F%2Ffoundryshields.com%2Fsystem%3FnameType%3Draw%26showVersion%3D1%26style%3Dflat%26url%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2FAngryBeaver%2Fbeavers-crafting%2Fmain%2Fmodule.json)
![Download Count](https://img.shields.io/github/downloads/AngryBeaver/beavers-crafting/total?color=bright-green)

# Credits
Copy organizational structur from midi-qol (gulpfile,package.json,my.conf.js,tsconcig.json)
## Work in progress
! Carefull structure will probably change until i finalize this module,
so do not start creating tones of recipes already ! The future upgrades might break them.

## Features
### Loot subtype Recipe
![img.png](pictures/newItem.png)

For this to work you must go to your settings and enter the name of the create Item Dialog.
Default is "Create New Item" obviously you need to adapt if you have a different language.

### Configure subtype Recipe
![img.png](pictures/configure.png)

- cost: you may add costs to the crafting process
- ingredients: you add items that will get consumed while crafting
- skill: you may add a skill that is required in the crafting process
- your may check that all costs are payed in the crafting process no matter of success or fail.
- results: you may add items as a result of a successfull crafting process of this recipe.

### Crafting
![img.png](pictures/crafting.png)

You can start a crafting process by clicking on a recipe in your inventar
or throu recipe compendium
- list all recipes that you have permission to see for all items in your world (not compendium)
- filter available: only those that you have at least one ingredient of any quantity of.
- filter useable: only those that you have all ingredients in required quantity of.
- filter by item: only those recipes that uses all items in the filter regardless of quantity.
- you can display details for a Recipe:
- it will display you an uneditable recipe and shows you which ingredients are missing.
- you can hit the craft button to start a craft process.
- a craft process will ask for the given skill if any and returns with an result
### Result
![img.png](pictures/result.png)

You will see a chat message with your result

## Upcoming Changes
### "any" of ingredient
I want to create recipes with "any" weapon or mushroom therefor i may need some new fields in recipe or a new subtype ingredient
### results should include rollTables
I want to create a random potion with random ingredients.
### macro
I want to be able to add macros to recipes.
giving them more flexibility e.g. get damage on certain recipes where you failed your check.
### ingredients/potions/recipes package
The identity of ingredients works best when the item originates from compendium
- I want a compendium package with lots of garbage items (mushrooms etc. that you can drop as loot)
- I want a compendium package with various potions (dnd5e is so borring here)
- I want a compendium package with recipes using the above two as a starter package for other creators.
### hooks for the crafting process
Once the process is stabilized
- I want to create hooks to make live easier for other
developer that invent recipe packages that needed a little special extra
- or developers that might extend specials to this module


## Notes
### Currency reorder
When adding costs to your recipe your currency will get exchanged to highest values.
### Items reorder
Actor Items will get merged to stacks in the crafting process.
(only those that match ingredients or results)



## Credits
Copy organizational structur from midi-qol (gulpfile,package.json,tsconcig.json)
38 changes: 37 additions & 1 deletion css/crafting.css
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@
border-left: 2px groove #FFF;
}

.beaversCrafting.crafting-app{
min-width:560px;
}

.beavers-crafting .crafting-app.header{
height:40px;
line-height:40px;
Expand Down Expand Up @@ -159,4 +163,36 @@
}
.beavers-crafting .dialog-button {
flex:0;
}
}

.beavers-crafting .crafting-app .drop-area .item{
/* Center the content */
width:20px;
margin:2px;
}
.beavers-crafting .crafting-app .drop-area .item img{
/* Center the content */
border:0px;
}

.beavers-crafting .crafting-app.header .filter{
/* Center the content */
height: 40px;
line-height: 40px;
text-align: right;
color: grey;
}
.beavers-crafting .crafting-app.header .drop-area {
/* Center the content */
align-items: center;
display: flex;
justify-content: center;
height:30px;
margin:4px;

/* Border */
border: 1px dashed #ffffff;
border-radius: 0.25rem;
}


2 changes: 1 addition & 1 deletion module.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"title": "Beaver's Crafting System",
"description": "A Crafting Module for DnD",
"id": "beavers-crafting",
"version": "0.0.10",
"version": "0.1.0",
"authors": [
{
"name": "angryBeaver",
Expand Down
70 changes: 0 additions & 70 deletions my.conf.js

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "beavers-crafting",
"title": "Beaver's Crafting",
"version": "0.0.10",
"version": "0.1.0",
"description": "Crafting",
"devDir": "C:\\Users\\User\\AppData\\Local\\FoundryVTT\\Data\\modules",
"main": "src/main.js",
Expand Down
Binary file added pictures/configure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pictures/crafting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pictures/newItem.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pictures/result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/Recipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ interface Trash {
results:{};
}

class DefaultComponent implements Component {
export class DefaultComponent implements Component {
id: string;
img: string;
name: string;
Expand Down
63 changes: 37 additions & 26 deletions src/RecipeCompendium.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,58 @@ import {Settings} from "./Settings.js";

export class RecipeCompendium {

static getAll(): Recipe[]{
static getAll(): Recipe[] {
// @ts-ignore
return game.items.directory.documents
.filter(item=>RecipeCompendium.isRecipe(item))
.map(item=>new Recipe(item));
.filter(item => RecipeCompendium.isRecipe(item))
.map(item => new Recipe(item));
}

filterForItem(recipes,item){

static filterForItems(recipes: Recipe[], items) {
return recipes.filter(recipe => {
const recipeItemsInItemList = items.filter(
item => {
for (const [k, component] of Object.entries(recipe.ingredients)) {
if (this.isSame(item, component)) {
return true;
}
}
return false;
})
return recipeItemsInItemList.length === items.length;
});
}

static filterForActor(actor,filter){
static filterForActor(actor, filter) {
return RecipeCompendium.getAll()
.filter(recipe=>{
if(filter == FilterType.all){
.filter(recipe => {
if (filter == FilterType.all) {
return true;
}
const result = RecipeCompendium.validateRecipeToItemList(recipe,actor.items);
return ((filter==FilterType.usable && !result.hasErrors)
|| (filter==FilterType.available && result.isAvailable));
const result = RecipeCompendium.validateRecipeToItemList(recipe, actor.items);
return ((filter == FilterType.usable && !result.hasErrors)
|| (filter == FilterType.available && result.isAvailable));
});

}

static validateRecipeToItemList(recipe:Recipe,listOfItems,result?:Result):Result {
static validateRecipeToItemList(recipe: Recipe, listOfItems, result?: Result): Result {
if (!result) result = new DefaultResult();
result.isAvailable=recipe.ingredients.size===0;
result.isAvailable = recipe.ingredients.size === 0;
for (const [k, component] of Object.entries(recipe.ingredients)) {
const itemChange = RecipeCompendium.findComponentInList(listOfItems,component);
const itemChange = RecipeCompendium.findComponentInList(listOfItems, component);
const remainingQuantity = itemChange.toUpdate["system.quantity"] - component.quantity;
const isAvailAble = itemChange.toUpdate["system.quantity"]>0;
const isAvailAble = itemChange.toUpdate["system.quantity"] > 0;
result.ingredients[k] = {
component:component,
component: component,
isAvailable: isAvailAble,
difference: remainingQuantity,
};
if(isAvailAble){
if (isAvailAble) {
result.isAvailable = isAvailAble;
}
if (remainingQuantity < 0) {
result.hasErrors=true;
result.hasErrors = true;
} else {
if (remainingQuantity == 0) {
result.changes.items.toDelete.push(itemChange.toUpdate._id);
Expand All @@ -58,7 +69,7 @@ export class RecipeCompendium {
return result;
}

static findComponentInList(listOfItems, component:Component):ItemChange {
static findComponentInList(listOfItems, component: Component): ItemChange {
const itemChange = new DefaultItemChange();
listOfItems.forEach((i) => {
if (this.isSame(i, component)) {
Expand All @@ -73,22 +84,22 @@ export class RecipeCompendium {
return itemChange;
}

static isSame(item, component:Component) {
static isSame(item, component: Component) {
const isSameName = (item, component) => item.name === component.name;
const isFromSource = (item, component) => item.flags?.core?.sourceId == component.uuid;
const hasSameSource = (item, component) => item.flags?.core?.sourceId == component.sourceId;
return isSameName(item, component) && (isFromSource(item, component) || hasSameSource(item, component));
}

static isRecipe(item){
static isRecipe(item) {
// @ts-ignore
return (item?.type === 'loot' && item?.system?.source === game.settings.get(Settings.NAMESPACE,Settings.RECIPE_SOURCE_NAME));
return (item?.type === 'loot' && item?.system?.source === game.settings.get(Settings.NAMESPACE, Settings.RECIPE_SOURCE_NAME));
}

}

export enum FilterType {
usable,available,all
usable, available, all
}

class DefaultItemChange implements ItemChange {
Expand All @@ -99,9 +110,9 @@ class DefaultItemChange implements ItemChange {
};
}

export class DefaultResult implements Result{
ingredients= {};
currencies=true;
export class DefaultResult implements Result {
ingredients = {};
currencies = true;
changes = {
items: {
toUpdate: [],
Expand Down
11 changes: 3 additions & 8 deletions src/RecipeSheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {Recipe} from "./Recipe.js";
import {Settings} from "./Settings.js";
import {getCurrencies, getSkills} from "./systems/dnd5e.js"
import {RecipeCompendium} from "./RecipeCompendium.js";
import {getDataFrom} from "./apps/CraftingApp.js";

const recipeSheets = [];

Expand Down Expand Up @@ -98,14 +99,8 @@ export class RecipeSheet {
if(!isIngredient && !isResult){
return;
}
let data;
try {
data = JSON.parse(e.dataTransfer.getData('text/plain'));
}
catch (err) {
return false;
}
if(data.type !== "Item") return;
const data = getDataFrom(e);
if(!data || data.type !== "Item") return;
const entity = await fromUuid(data.uuid);
if(entity) {
if(isIngredient){
Expand Down
Loading

0 comments on commit feba4ac

Please sign in to comment.