diff --git a/assets/common/component_recipe_book.ron b/assets/common/component_recipe_book.ron index f485e9bdac..b45b6840f6 100644 --- a/assets/common/component_recipe_book.ron +++ b/assets/common/component_recipe_book.ron @@ -1,6 +1,7 @@ [ /// MODULAR WEAPONS/HAMMERS/PRIMARY COMPONENTS ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.hammer", @@ -11,6 +12,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.hammer", @@ -21,6 +23,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.hammer", @@ -33,6 +36,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.hammer", @@ -45,6 +49,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.hammer", @@ -57,6 +62,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.hammer", @@ -69,6 +75,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.spikedmace", @@ -79,6 +86,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.spikedmace", @@ -89,6 +97,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.spikedmace", @@ -101,6 +110,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.spikedmace", @@ -113,6 +123,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.spikedmace", @@ -125,6 +136,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.spikedmace", @@ -137,6 +149,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.warhammer", @@ -147,6 +160,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.warhammer", @@ -157,6 +171,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.warhammer", @@ -169,6 +184,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.warhammer", @@ -181,6 +197,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.warhammer", @@ -193,6 +210,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.warhammer", @@ -205,6 +223,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.maul", @@ -215,6 +234,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.maul", @@ -225,6 +245,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.maul", @@ -237,6 +258,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.maul", @@ -249,6 +271,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.maul", @@ -261,6 +284,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.maul", @@ -273,6 +297,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greatmace", @@ -283,6 +308,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greatmace", @@ -293,6 +319,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greatmace", @@ -305,6 +332,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greatmace", @@ -317,6 +345,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greatmace", @@ -329,6 +358,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greatmace", @@ -341,6 +371,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greathammer", @@ -351,6 +382,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greathammer", @@ -361,6 +393,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greathammer", @@ -373,6 +406,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greathammer", @@ -385,6 +419,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greathammer", @@ -397,6 +432,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.greathammer", @@ -409,6 +445,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.ornate", @@ -419,6 +456,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.ornate", @@ -429,6 +467,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.ornate", @@ -441,6 +480,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.ornate", @@ -453,6 +493,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.ornate", @@ -465,6 +506,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Hammer, item: "common.items.modular.weapon.primary.hammer.ornate", @@ -478,6 +520,7 @@ ), /// MODULAR WEAPONS/SWORDS/PRIMARY COMPONENTS ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.longsword", @@ -488,6 +531,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.longsword", @@ -498,6 +542,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.longsword", @@ -510,6 +555,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.longsword", @@ -522,6 +568,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.longsword", @@ -534,6 +581,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.longsword", @@ -546,6 +594,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sawblade", @@ -556,6 +605,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sawblade", @@ -566,6 +616,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sawblade", @@ -578,6 +629,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sawblade", @@ -590,6 +642,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sawblade", @@ -602,6 +655,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sawblade", @@ -614,6 +668,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.katana", @@ -624,6 +679,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.katana", @@ -634,6 +690,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.katana", @@ -646,6 +703,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.katana", @@ -658,6 +716,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.katana", @@ -670,6 +729,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.katana", @@ -682,6 +742,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.zweihander", @@ -692,6 +753,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.zweihander", @@ -702,6 +764,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.zweihander", @@ -714,6 +777,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.zweihander", @@ -726,6 +790,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.zweihander", @@ -738,6 +803,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.zweihander", @@ -750,6 +816,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sabre", @@ -760,6 +827,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sabre", @@ -770,6 +838,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sabre", @@ -782,6 +851,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sabre", @@ -794,6 +864,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sabre", @@ -806,6 +877,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.sabre", @@ -818,6 +890,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.greatsword", @@ -828,6 +901,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.greatsword", @@ -838,6 +912,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.greatsword", @@ -850,6 +925,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.greatsword", @@ -862,6 +938,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.greatsword", @@ -874,6 +951,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.greatsword", @@ -886,6 +964,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.ornate", @@ -896,6 +975,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.ornate", @@ -906,6 +986,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.ornate", @@ -918,6 +999,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.ornate", @@ -930,6 +1012,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.ornate", @@ -942,6 +1025,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Sword, item: "common.items.modular.weapon.primary.sword.ornate", @@ -955,6 +1039,7 @@ ), /// MODULAR WEAPONS/AXES/PRIMARY COMPONENTS ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.axe", @@ -965,6 +1050,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.axe", @@ -975,6 +1061,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.axe", @@ -987,6 +1074,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.axe", @@ -999,6 +1087,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.axe", @@ -1011,6 +1100,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.axe", @@ -1023,6 +1113,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.jagged", @@ -1033,6 +1124,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.jagged", @@ -1043,6 +1135,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.jagged", @@ -1055,6 +1148,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.jagged", @@ -1067,6 +1161,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.jagged", @@ -1079,6 +1174,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.jagged", @@ -1091,6 +1187,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.battleaxe", @@ -1101,6 +1198,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.battleaxe", @@ -1111,6 +1209,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.battleaxe", @@ -1123,6 +1222,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.battleaxe", @@ -1135,6 +1235,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.battleaxe", @@ -1147,6 +1248,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.battleaxe", @@ -1159,6 +1261,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.poleaxe", @@ -1169,6 +1272,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.poleaxe", @@ -1179,6 +1283,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.poleaxe", @@ -1191,6 +1296,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.poleaxe", @@ -1203,6 +1309,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.poleaxe", @@ -1215,6 +1322,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.poleaxe", @@ -1227,6 +1335,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.labrys", @@ -1237,6 +1346,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.labrys", @@ -1247,6 +1357,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.labrys", @@ -1259,6 +1370,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.labrys", @@ -1271,6 +1383,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.labrys", @@ -1283,6 +1396,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.labrys", @@ -1295,6 +1409,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.greataxe", @@ -1305,6 +1420,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.greataxe", @@ -1315,6 +1431,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.greataxe", @@ -1327,6 +1444,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.greataxe", @@ -1339,6 +1457,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.greataxe", @@ -1351,6 +1470,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.greataxe", @@ -1363,6 +1483,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bronze_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.ornate", @@ -1373,6 +1494,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "iron_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.ornate", @@ -1383,6 +1505,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "steel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.ornate", @@ -1395,6 +1518,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "cobalt_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.ornate", @@ -1407,6 +1531,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "bloodsteel_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.ornate", @@ -1419,6 +1544,7 @@ craft_sprite: Some(Anvil), ), ( + recipe_book_key: "orichalcum_weapons", output: ToolPrimaryComponent( toolkind: Axe, item: "common.items.modular.weapon.primary.axe.ornate", @@ -1432,6 +1558,7 @@ ), /// MODULAR WEAPONS/BOWS/PRIMARY COMPONENTS ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.bow", @@ -1443,6 +1570,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.bow", @@ -1454,6 +1582,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.bow", @@ -1465,6 +1594,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.bow", @@ -1476,6 +1606,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.bow", @@ -1487,6 +1618,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.bow", @@ -1498,6 +1630,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.composite", @@ -1509,6 +1642,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.composite", @@ -1520,6 +1654,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.composite", @@ -1531,6 +1666,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.composite", @@ -1542,6 +1678,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.composite", @@ -1553,6 +1690,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.composite", @@ -1564,6 +1702,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.greatbow", @@ -1575,6 +1714,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.greatbow", @@ -1586,6 +1726,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.greatbow", @@ -1597,6 +1738,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.greatbow", @@ -1608,6 +1750,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.greatbow", @@ -1619,6 +1762,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.greatbow", @@ -1630,6 +1774,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.longbow", @@ -1641,6 +1786,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.longbow", @@ -1652,6 +1798,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.longbow", @@ -1663,6 +1810,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.longbow", @@ -1674,6 +1822,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.longbow", @@ -1685,6 +1834,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.longbow", @@ -1696,6 +1846,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.ornate", @@ -1707,6 +1858,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.ornate", @@ -1718,6 +1870,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.ornate", @@ -1729,6 +1882,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.ornate", @@ -1740,6 +1894,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.ornate", @@ -1751,6 +1906,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.ornate", @@ -1762,6 +1918,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.shortbow", @@ -1773,6 +1930,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.shortbow", @@ -1784,6 +1942,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.shortbow", @@ -1795,6 +1954,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.shortbow", @@ -1806,6 +1966,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.shortbow", @@ -1817,6 +1978,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.shortbow", @@ -1828,6 +1990,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.warbow", @@ -1839,6 +2002,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.warbow", @@ -1850,6 +2014,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.warbow", @@ -1861,6 +2026,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.warbow", @@ -1872,6 +2038,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.warbow", @@ -1883,6 +2050,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Bow, item: "common.items.modular.weapon.primary.bow.warbow", @@ -1895,6 +2063,7 @@ ), /// MODULAR WEAPONS/FIRE STAFFS/PRIMARY COMPONENTS ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.brand", @@ -1907,6 +2076,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.brand", @@ -1919,6 +2089,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.brand", @@ -1931,6 +2102,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.brand", @@ -1943,6 +2115,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.brand", @@ -1955,6 +2128,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.brand", @@ -1967,6 +2141,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.grandstaff", @@ -1979,6 +2154,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.grandstaff", @@ -1991,6 +2167,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.grandstaff", @@ -2003,6 +2180,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.grandstaff", @@ -2015,6 +2193,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.grandstaff", @@ -2027,6 +2206,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.grandstaff", @@ -2039,6 +2219,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.longpole", @@ -2051,6 +2232,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.longpole", @@ -2063,6 +2245,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.longpole", @@ -2075,6 +2258,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.longpole", @@ -2087,6 +2271,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.longpole", @@ -2099,6 +2284,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.longpole", @@ -2111,6 +2297,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.ornate", @@ -2123,6 +2310,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.ornate", @@ -2135,6 +2323,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.ornate", @@ -2147,6 +2336,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.ornate", @@ -2159,6 +2349,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.ornate", @@ -2171,6 +2362,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.ornate", @@ -2183,6 +2375,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.pole", @@ -2195,6 +2388,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.pole", @@ -2207,6 +2401,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.pole", @@ -2219,6 +2414,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.pole", @@ -2231,6 +2427,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.pole", @@ -2243,6 +2440,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.pole", @@ -2255,6 +2453,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.rod", @@ -2267,6 +2466,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.rod", @@ -2279,6 +2479,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.rod", @@ -2291,6 +2492,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.rod", @@ -2303,6 +2505,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.rod", @@ -2315,6 +2518,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.rod", @@ -2327,6 +2531,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.staff", @@ -2339,6 +2544,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.staff", @@ -2351,6 +2557,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.staff", @@ -2363,6 +2570,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.staff", @@ -2375,6 +2583,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.staff", @@ -2387,6 +2596,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Staff, item: "common.items.modular.weapon.primary.staff.staff", @@ -2400,6 +2610,7 @@ ), /// MODULAR WEAPONS/NATURE SCEPTRES/PRIMARY COMPONENTS ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.arbor", @@ -2412,6 +2623,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.arbor", @@ -2424,6 +2636,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.arbor", @@ -2436,6 +2649,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.arbor", @@ -2448,6 +2662,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.arbor", @@ -2460,6 +2675,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.arbor", @@ -2472,6 +2688,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.cane", @@ -2484,6 +2701,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.cane", @@ -2496,6 +2714,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.cane", @@ -2508,6 +2727,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.cane", @@ -2520,6 +2740,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.cane", @@ -2532,6 +2753,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.cane", @@ -2544,6 +2766,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crook", @@ -2556,6 +2779,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crook", @@ -2568,6 +2792,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crook", @@ -2580,6 +2805,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crook", @@ -2592,6 +2818,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crook", @@ -2604,6 +2831,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crook", @@ -2616,6 +2844,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crozier", @@ -2628,6 +2857,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crozier", @@ -2640,6 +2870,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crozier", @@ -2652,6 +2883,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crozier", @@ -2664,6 +2896,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crozier", @@ -2676,6 +2909,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.crozier", @@ -2688,6 +2922,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.grandsceptre", @@ -2700,6 +2935,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.grandsceptre", @@ -2712,6 +2948,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.grandsceptre", @@ -2724,6 +2961,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.grandsceptre", @@ -2736,6 +2974,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.grandsceptre", @@ -2748,6 +2987,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.grandsceptre", @@ -2760,6 +3000,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.ornate", @@ -2772,6 +3013,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.ornate", @@ -2784,6 +3026,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.ornate", @@ -2796,6 +3039,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.ornate", @@ -2808,6 +3052,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.ornate", @@ -2820,6 +3065,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.ornate", @@ -2832,6 +3078,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "wood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.sceptre", @@ -2844,6 +3091,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "bamboo_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.sceptre", @@ -2856,6 +3104,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "hardwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.sceptre", @@ -2868,6 +3117,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "ironwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.sceptre", @@ -2880,6 +3130,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "frostwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.sceptre", @@ -2892,6 +3143,7 @@ craft_sprite: Some(CraftingBench), ), ( + recipe_book_key: "eldwood_weapons", output: ToolPrimaryComponent( toolkind: Sceptre, item: "common.items.modular.weapon.primary.sceptre.sceptre", diff --git a/assets/common/economy/trading_goods.ron b/assets/common/economy/trading_goods.ron index 1dd30330f7..59ffe9d682 100644 --- a/assets/common/economy/trading_goods.ron +++ b/assets/common/economy/trading_goods.ron @@ -40,6 +40,9 @@ Ingredients: ( decay_rate: 0.1, // revisit ), + Recipe: ( + decay_rate: 0.1, // revisit + ), Tools: ( // TODO: Separate stone, metal, bone, wood // decay_rate: 0.05, // 14 years half-life @@ -48,4 +51,4 @@ //decay_rate: 0.1, // 6 years half-life //transport_effort: 0.05, // 2kg/40kg ), -} \ No newline at end of file +} diff --git a/assets/common/entity/village/alchemist.ron b/assets/common/entity/village/alchemist.ron index d8c9c53eda..ad3aeea4b6 100644 --- a/assets/common/entity/village/alchemist.ron +++ b/assets/common/entity/village/alchemist.ron @@ -19,6 +19,7 @@ items: [ (10, "common.items.consumable.potion_big"), (10, "common.items.food.sunflower_icetea"), + (1, "common.items.recipes.potions"), ], ), meta: [ diff --git a/assets/common/entity/village/blacksmith.ron b/assets/common/entity/village/blacksmith.ron index 93fb72e5ec..ca4180786f 100644 --- a/assets/common/entity/village/blacksmith.ron +++ b/assets/common/entity/village/blacksmith.ron @@ -18,7 +18,10 @@ )), items: [ (10, "common.items.consumable.potion_big"), - (10, "common.items.food.sunflower_icetea"), + (1, "common.items.recipes.equipment.basic"), + (1, "common.items.recipes.armor.iron"), + (1, "common.items.recipes.weapons.iron"), + (1, "common.items.recipes.utility"), ], ), meta: [ diff --git a/assets/common/entity/village/chef.ron b/assets/common/entity/village/chef.ron index a0e6bbbdae..e8ad5a30d1 100644 --- a/assets/common/entity/village/chef.ron +++ b/assets/common/entity/village/chef.ron @@ -19,6 +19,7 @@ items: [ (10, "common.items.consumable.potion_big"), (10, "common.items.food.sunflower_icetea"), + (1, "common.items.recipes.food"), ], ), meta: [ diff --git a/assets/common/entity/village/herbalist.ron b/assets/common/entity/village/herbalist.ron index fbed25db5b..e4d7fc60a1 100644 --- a/assets/common/entity/village/herbalist.ron +++ b/assets/common/entity/village/herbalist.ron @@ -15,6 +15,8 @@ items: [ (10, "common.items.food.cheese"), (10, "common.items.food.plainsalad"), + (1, "common.items.recipes.food"), + (1, "common.items.recipes.armor.woolen"), ], ), meta: [], diff --git a/assets/common/entity/village/merchant.ron b/assets/common/entity/village/merchant.ron index 64123e4156..ac5bda43c6 100644 --- a/assets/common/entity/village/merchant.ron +++ b/assets/common/entity/village/merchant.ron @@ -14,8 +14,13 @@ (2, ModularWeapon(tool: Staff, material: Ironwood, hands: None)), ]), None)), )), + items: [ + (1, "common.items.recipes.equipment.basic"), + (1, "common.items.recipes.armor.leather"), + (1, "common.items.recipes.weapons.bamboo"), + ], ), meta: [ SkillSetAsset("common.skillset.preset.rank3.fullskill"), ], -) \ No newline at end of file +) diff --git a/assets/common/item_i18n_manifest.ron b/assets/common/item_i18n_manifest.ron index 9d01cfe405..159ee79682 100644 --- a/assets/common/item_i18n_manifest.ron +++ b/assets/common/item_i18n_manifest.ron @@ -7074,5 +7074,48 @@ One, ), ): "weapon-hammer-hammer-cobalt-1h", + Simple("common.items.recipes.armor.bloodsteel"): "recipe-armor-bloodsteel", + Simple("common.items.recipes.armor.brinestone"): "recipe-armor-brinestone", + Simple("common.items.recipes.armor.carapace"): "recipe-armor-carapace", + Simple("common.items.recipes.armor.cobalt"): "recipe-armor-cobalt", + Simple("common.items.recipes.armor.dragonscale"): "recipe-armor-dragonscale", + Simple("common.items.recipes.armor.druid"): "recipe-armor-druid", + Simple("common.items.recipes.armor.iron"): "recipe-armor-iron", + Simple("common.items.recipes.armor.leather"): "recipe-armor-leather", + Simple("common.items.recipes.armor.moonweave"): "recipe-armor-moonweave", + Simple("common.items.recipes.armor.orichalcum"): "recipe-armor-orichalcum", + Simple("common.items.recipes.armor.primal"): "recipe-armor-primal", + Simple("common.items.recipes.armor.scale"): "recipe-armor-scale", + Simple("common.items.recipes.armor.silken"): "recipe-armor-silken", + Simple("common.items.recipes.armor.steel"): "recipe-armor-steel", + Simple("common.items.recipes.armor.sunsilk"): "recipe-armor-sunsilk", + Simple("common.items.recipes.armor.woolen"): "recipe-armor-woolen", + Simple("common.items.recipes.equipment.basic"): "recipe-equipment-basic", + Simple("common.items.recipes.equipment.moderate"): "recipe-equipment-moderate", + Simple("common.items.recipes.equipment.advanced"): "recipe-equipment-advanced", + Simple("common.items.recipes.unique.abyssal_gorget"): "recipe-unique-abyssal_gorget", + Simple("common.items.recipes.unique.mindflayer_spellbag"): "recipe-unique-mindflayer_spellbag", + Simple("common.items.recipes.unique.polaris"): "recipe-unique-polaris", + Simple("common.items.recipes.unique.seashell_necklace"): "recipe-unique-seashell_necklace", + Simple("common.items.recipes.unique.troll_hide_pack"): "recipe-unique-troll_hide_pack", + Simple("common.items.recipes.unique.winged_coronet"): "recipe-unique-winged_coronet", + Simple("common.items.recipes.charms"): "recipe-charms", + Simple("common.items.recipes.explosives"): "recipe-explosives", + Simple("common.items.recipes.food"): "recipe-food", + Simple("common.items.recipes.gliders"): "recipe-gliders", + Simple("common.items.recipes.instruments"): "recipe-instruments", + Simple("common.items.recipes.potions"): "recipe-potions", + Simple("common.items.recipes.utility"): "recipe-utility", + Simple("common.items.recipes.weapons.iron"): "recipe-weapons-iron", + Simple("common.items.recipes.weapons.steel"): "recipe-weapons-steel", + Simple("common.items.recipes.weapons.cobalt"): "recipe-weapons-cobalt", + Simple("common.items.recipes.weapons.bloodsteel"): "recipe-weapons-bloodsteel", + Simple("common.items.recipes.weapons.orichalcum"): "recipe-weapons-orichalcum", + Simple("common.items.recipes.weapons.bamboo"): "recipe-weapons-bamboo", + Simple("common.items.recipes.weapons.hardwood"): "recipe-weapons-hardwood", + Simple("common.items.recipes.weapons.ironwood"): "recipe-weapons-ironwood", + Simple("common.items.recipes.weapons.frostwood"): "recipe-weapons-frostwood", + Simple("common.items.recipes.weapons.eldwood"): "recipe-weapons-eldwood", + Simple("common.items.recipes.default"): "recipe-default", }, ) diff --git a/assets/common/items/armor/pirate/belt.ron b/assets/common/items/armor/pirate/belt.ron index e2258c0f74..2bd3592324 100644 --- a/assets/common/items/armor/pirate/belt.ron +++ b/assets/common/items/armor/pirate/belt.ron @@ -6,6 +6,5 @@ ItemDef( stats: FromSet("Pirate"), )), quality: Epic, - tags: [ - ], + tags: [], ) diff --git a/assets/common/items/recipes/armor/bloodsteel.ron b/assets/common/items/recipes/armor/bloodsteel.ron new file mode 100644 index 0000000000..69e305502d --- /dev/null +++ b/assets/common/items/recipes/armor/bloodsteel.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "bloodsteel_ingot", + "bloodsteel_back", + "bloodsteel_belt", + "bloodsteel_chest", + "bloodsteel_feet", + "bloodsteel_hands", + "bloodsteel_pants", + "bloodsteel_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/brinestone.ron b/assets/common/items/recipes/armor/brinestone.ron new file mode 100644 index 0000000000..093e46b1fc --- /dev/null +++ b/assets/common/items/recipes/armor/brinestone.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "brinestone_back", + "brinestone_belt", + "brinestone_chest", + "brinestone_feet", + "brinestone_hands", + "brinestone_pants", + "brinestone_shoulder", + "brinestone_crown", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/carapace.ron b/assets/common/items/recipes/armor/carapace.ron new file mode 100644 index 0000000000..dcaf19590c --- /dev/null +++ b/assets/common/items/recipes/armor/carapace.ron @@ -0,0 +1,17 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "carapace_back", + "carapace_belt", + "carapace_chest", + "carapace_feet", + "carapace_hands", + "carapace_pants", + "carapace_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/cobalt.ron b/assets/common/items/recipes/armor/cobalt.ron new file mode 100644 index 0000000000..01403bc683 --- /dev/null +++ b/assets/common/items/recipes/armor/cobalt.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "cobalt_ingot", + "cobalt_back", + "cobalt_belt", + "cobalt_chest", + "cobalt_feet", + "cobalt_hands", + "cobalt_pants", + "cobalt_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/dragonscale.ron b/assets/common/items/recipes/armor/dragonscale.ron new file mode 100644 index 0000000000..59df397ca0 --- /dev/null +++ b/assets/common/items/recipes/armor/dragonscale.ron @@ -0,0 +1,17 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "dragonscale_back", + "dragonscale_belt", + "dragonscale_chest", + "dragonscale_feet", + "dragonscale_hands", + "dragonscale_pants", + "dragonscale_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/druid.ron b/assets/common/items/recipes/armor/druid.ron new file mode 100644 index 0000000000..f4db3cacb2 --- /dev/null +++ b/assets/common/items/recipes/armor/druid.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "lifecloth", + "druid_back", + "druid_belt", + "druid_chest", + "druid_feet", + "druid_hands", + "druid_pants", + "druid_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/iron.ron b/assets/common/items/recipes/armor/iron.ron new file mode 100644 index 0000000000..ee20a9d426 --- /dev/null +++ b/assets/common/items/recipes/armor/iron.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "iron_ingot", + "iron_back", + "iron_belt", + "iron_chest", + "iron_feet", + "iron_hands", + "iron_pants", + "iron_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/leather.ron b/assets/common/items/recipes/armor/leather.ron new file mode 100644 index 0000000000..88f05728be --- /dev/null +++ b/assets/common/items/recipes/armor/leather.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "thick_leather", + "leather_back", + "leather_belt", + "leather_chest", + "leather_feet", + "leather_hands", + "leather_pants", + "leather_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/moonweave.ron b/assets/common/items/recipes/armor/moonweave.ron new file mode 100644 index 0000000000..8e363c702d --- /dev/null +++ b/assets/common/items/recipes/armor/moonweave.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "moonweave", + "moonweave_back", + "moonweave_belt", + "moonweave_chest", + "moonweave_feet", + "moonweave_hands", + "moonweave_pants", + "moonweave_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/orichalcum.ron b/assets/common/items/recipes/armor/orichalcum.ron new file mode 100644 index 0000000000..d6b6d04b50 --- /dev/null +++ b/assets/common/items/recipes/armor/orichalcum.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "orichalcum_ingot", + "orichalcum_back", + "orichalcum_belt", + "orichalcum_chest", + "orichalcum_feet", + "orichalcum_hands", + "orichalcum_pants", + "orichalcum_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/primal.ron b/assets/common/items/recipes/armor/primal.ron new file mode 100644 index 0000000000..0050ea3a09 --- /dev/null +++ b/assets/common/items/recipes/armor/primal.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "rigid_leather", + "primal_back", + "primal_belt", + "primal_chest", + "primal_feet", + "primal_hands", + "primal_pants", + "primal_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/scale.ron b/assets/common/items/recipes/armor/scale.ron new file mode 100644 index 0000000000..ab5be20fc1 --- /dev/null +++ b/assets/common/items/recipes/armor/scale.ron @@ -0,0 +1,17 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "scale_back", + "scale_belt", + "scale_chest", + "scale_feet", + "scale_hands", + "scale_pants", + "scale_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/silken.ron b/assets/common/items/recipes/armor/silken.ron new file mode 100644 index 0000000000..a99124da5a --- /dev/null +++ b/assets/common/items/recipes/armor/silken.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "silk", + "silken_back", + "silken_belt", + "silken_chest", + "silken_feet", + "silken_hands", + "silken_pants", + "silken_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/steel.ron b/assets/common/items/recipes/armor/steel.ron new file mode 100644 index 0000000000..378bfccb31 --- /dev/null +++ b/assets/common/items/recipes/armor/steel.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "steel_ingot", + "steel_back", + "steel_belt", + "steel_chest", + "steel_feet", + "steel_hands", + "steel_pants", + "steel_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/sunsilk.ron b/assets/common/items/recipes/armor/sunsilk.ron new file mode 100644 index 0000000000..f133bd2087 --- /dev/null +++ b/assets/common/items/recipes/armor/sunsilk.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "sunsilk", + "sunsilk_back", + "sunsilk_belt", + "sunsilk_chest", + "sunsilk_feet", + "sunsilk_hands", + "sunsilk_pants", + "sunsilk_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/armor/woolen.ron b/assets/common/items/recipes/armor/woolen.ron new file mode 100644 index 0000000000..58b41e3884 --- /dev/null +++ b/assets/common/items/recipes/armor/woolen.ron @@ -0,0 +1,18 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "cotton", + "woolen_back", + "woolen_belt", + "woolen_chest", + "woolen_feet", + "woolen_hands", + "woolen_pants", + "woolen_shoulder", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/charms.ron b/assets/common/items/recipes/charms.ron new file mode 100644 index 0000000000..937ccb3b49 --- /dev/null +++ b/assets/common/items/recipes/charms.ron @@ -0,0 +1,13 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "burning_charm", + "frozen_charm", + "lifesteal_charm", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/default.ron b/assets/common/items/recipes/default.ron new file mode 100644 index 0000000000..0d9dc4d447 --- /dev/null +++ b/assets/common/items/recipes/default.ron @@ -0,0 +1,82 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + // Food + "fish_cooked", + "bird_cooked", + "bird_large_cooked", + "beast_small_cooked", + "beast_large_cooked", + "tough_cooked", + // Armors + "rawhide_back", + "rawhide_belt", + "rawhide_chest", + "rawhide_feet", + "rawhide_hands", + "rawhide_pants", + "rawhide_shoulder", + "linen_back", + "linen_belt", + "linen_chest", + "linen_feet", + "linen_hands", + "linen_pants", + "linen_shoulder", + "bronze_back", + "bronze_belt", + "bronze_chest", + "bronze_feet", + "bronze_hands", + "bronze_pants", + "bronze_shoulder", + // Weapon components + "short_hilt", + "medium_hilt", + "long_hilt", + "short_hammer_haft", + "medium_hammer_haft", + "long_hammer_haft", + "short_axe_haft", + "medium_axe_haft", + "long_axe_haft", + "short_bow_grip", + "medium_bow_grip", + "long_bow_grip", + "light_pyrocore", + "medium_pyrocore", + "heavy_pyrocore", + "light_biocore", + "medium_biocore", + "heavy_biocore", + // Weapons + "burnt_drumstick", + "healing_sceptre", + "bronze_weapons", + "wood_weapons", + // Materials + "tin_ingot", + "copper_ingot", + "bronze_ingot", + "red_cloth", + "twig", + "leather_strips", + "simple_leather", + "linen_flax", + "cloth_strips", + // Tools + "craftsman_hammer", + "mortar_pestle", + "sewing_set", + "tin_pickaxe", + "shovel", + // Bags + "tiny_red_pouch", + "tiny_leather_pouch", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/equipment/advanced.ron b/assets/common/items/recipes/equipment/advanced.ron new file mode 100644 index 0000000000..7cc3352856 --- /dev/null +++ b/assets/common/items/recipes/equipment/advanced.ron @@ -0,0 +1,17 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "diamond_ring", + "diamond_necklace", + "ruby_ring", + "ruby_necklace", + "emerald_ring", + "emerald_necklace", + "merchant_turban", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/equipment/basic.ron b/assets/common/items/recipes/equipment/basic.ron new file mode 100644 index 0000000000..747042a116 --- /dev/null +++ b/assets/common/items/recipes/equipment/basic.ron @@ -0,0 +1,15 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "seashell_necklace", + "knitted_red_pouch", + "steel_pickaxe", + "fang_necklace", + "black_lantern", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/equipment/moderate.ron b/assets/common/items/recipes/equipment/moderate.ron new file mode 100644 index 0000000000..03594b946c --- /dev/null +++ b/assets/common/items/recipes/equipment/moderate.ron @@ -0,0 +1,22 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "sapphire_ring", + "sapphire_necklace", + "topaz_ring", + "topaz_necklace", + "amethyst_ring", + "amethyst_necklace", + "reliable_leather_pack", + "woven_red_bag", + "honeycomb_pendant", + "traveler_backpack", + "sturdy_red_backpack", + "troll_hide_pack", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/explosives.ron b/assets/common/items/recipes/explosives.ron new file mode 100644 index 0000000000..601a66eb85 --- /dev/null +++ b/assets/common/items/recipes/explosives.ron @@ -0,0 +1,17 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "bomb_coconut", + "firework_blue", + "firework_green", + "firework_purple", + "firework_red", + "firework_white", + "firework_yellow", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/food.ron b/assets/common/items/recipes/food.ron new file mode 100644 index 0000000000..ebbabb1268 --- /dev/null +++ b/assets/common/items/recipes/food.ron @@ -0,0 +1,17 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "cactus_colada", + "apple_shroom_curry", + "salad_plain", + "salad_tomato", + "apples_stick", + "mushroom_stick", + "sunflower_icetea", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/gliders.ron b/assets/common/items/recipes/gliders.ron new file mode 100644 index 0000000000..852bb3a56c --- /dev/null +++ b/assets/common/items/recipes/gliders.ron @@ -0,0 +1,20 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "plain_cloth_glider", + "red_cloth_glider", + "cloverleaf_glider", + "leaves_glider", + "sand_raptor_wings", + "snow_raptor_wings", + "wood_raptor_wings", + "moonlit_love_glider", + "horizon_glider", + "winter_wings", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/instruments.ron b/assets/common/items/recipes/instruments.ron new file mode 100644 index 0000000000..c8903d8142 --- /dev/null +++ b/assets/common/items/recipes/instruments.ron @@ -0,0 +1,20 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "double_bass", + "flute", + "guitar", + "lyre", + "kalimba", + "lute", + "melodica", + "washboard", + "sitar", + "icy_talharpa", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/potions.ron b/assets/common/items/recipes/potions.ron new file mode 100644 index 0000000000..ce11966021 --- /dev/null +++ b/assets/common/items/recipes/potions.ron @@ -0,0 +1,14 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "potion_combustion", + "potion_agility", + "potion_minor", + "potion_medium", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/unique/abyssal_gorget.ron b/assets/common/items/recipes/unique/abyssal_gorget.ron new file mode 100644 index 0000000000..caa838f0eb --- /dev/null +++ b/assets/common/items/recipes/unique/abyssal_gorget.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "abyssal_gorget", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/unique/mindflayer_spellbag.ron b/assets/common/items/recipes/unique/mindflayer_spellbag.ron new file mode 100644 index 0000000000..2b6dbc4138 --- /dev/null +++ b/assets/common/items/recipes/unique/mindflayer_spellbag.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "mindflayer_spellbag", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/unique/polaris.ron b/assets/common/items/recipes/unique/polaris.ron new file mode 100644 index 0000000000..acf3baa848 --- /dev/null +++ b/assets/common/items/recipes/unique/polaris.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "polaris", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/unique/seashell_necklace.ron b/assets/common/items/recipes/unique/seashell_necklace.ron new file mode 100644 index 0000000000..25dae4bec3 --- /dev/null +++ b/assets/common/items/recipes/unique/seashell_necklace.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "seashell_necklace", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/unique/troll_hide_pack.ron b/assets/common/items/recipes/unique/troll_hide_pack.ron new file mode 100644 index 0000000000..b4b620229e --- /dev/null +++ b/assets/common/items/recipes/unique/troll_hide_pack.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "troll_hide_pack", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/unique/winged_coronet.ron b/assets/common/items/recipes/unique/winged_coronet.ron new file mode 100644 index 0000000000..5fcbfcaa67 --- /dev/null +++ b/assets/common/items/recipes/unique/winged_coronet.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "winged_coronet", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/utility.ron b/assets/common/items/recipes/utility.ron new file mode 100644 index 0000000000..b98c84a61e --- /dev/null +++ b/assets/common/items/recipes/utility.ron @@ -0,0 +1,15 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "collar_basic", + "velorite_frag", + "lockpick", + "gold_ingot", + "silver_ingot", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/bamboo.ron b/assets/common/items/recipes/weapons/bamboo.ron new file mode 100644 index 0000000000..25fbcaaf6b --- /dev/null +++ b/assets/common/items/recipes/weapons/bamboo.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "bamboo_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/bloodsteel.ron b/assets/common/items/recipes/weapons/bloodsteel.ron new file mode 100644 index 0000000000..889f9688f0 --- /dev/null +++ b/assets/common/items/recipes/weapons/bloodsteel.ron @@ -0,0 +1,12 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "bloodsteel_ingot", + "bloodsteel_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/cobalt.ron b/assets/common/items/recipes/weapons/cobalt.ron new file mode 100644 index 0000000000..e6ba527911 --- /dev/null +++ b/assets/common/items/recipes/weapons/cobalt.ron @@ -0,0 +1,12 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "cobalt_ingot", + "cobalt_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/eldwood.ron b/assets/common/items/recipes/weapons/eldwood.ron new file mode 100644 index 0000000000..09377c5c15 --- /dev/null +++ b/assets/common/items/recipes/weapons/eldwood.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "eldwood_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/frostwood.ron b/assets/common/items/recipes/weapons/frostwood.ron new file mode 100644 index 0000000000..981c965f80 --- /dev/null +++ b/assets/common/items/recipes/weapons/frostwood.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "frostwood_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/hardwood.ron b/assets/common/items/recipes/weapons/hardwood.ron new file mode 100644 index 0000000000..617b9e6a6d --- /dev/null +++ b/assets/common/items/recipes/weapons/hardwood.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "hardwood_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/iron.ron b/assets/common/items/recipes/weapons/iron.ron new file mode 100644 index 0000000000..894afbae67 --- /dev/null +++ b/assets/common/items/recipes/weapons/iron.ron @@ -0,0 +1,12 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "iron_ingot", + "iron_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/ironwood.ron b/assets/common/items/recipes/weapons/ironwood.ron new file mode 100644 index 0000000000..ace59d633d --- /dev/null +++ b/assets/common/items/recipes/weapons/ironwood.ron @@ -0,0 +1,11 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "ironwood_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/orichalcum.ron b/assets/common/items/recipes/weapons/orichalcum.ron new file mode 100644 index 0000000000..00c2bc57a1 --- /dev/null +++ b/assets/common/items/recipes/weapons/orichalcum.ron @@ -0,0 +1,12 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "orichalcum_ingot", + "orichalcum_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/items/recipes/weapons/steel.ron b/assets/common/items/recipes/weapons/steel.ron new file mode 100644 index 0000000000..56bf84e143 --- /dev/null +++ b/assets/common/items/recipes/weapons/steel.ron @@ -0,0 +1,12 @@ +ItemDef( + legacy_name: "", + legacy_description: "", + kind: RecipeGroup( + recipes: [ + "steel_ingot", + "steel_weapons", + ], + ), + quality: Common, + tags: [], +) diff --git a/assets/common/loot_tables/dungeon/adlet/chest.ron b/assets/common/loot_tables/dungeon/adlet/chest.ron index 8aadf90ad5..c7d4d2c27f 100644 --- a/assets/common/loot_tables/dungeon/adlet/chest.ron +++ b/assets/common/loot_tables/dungeon/adlet/chest.ron @@ -14,4 +14,14 @@ (2.0, MultiDrop(Item("common.items.consumable.potion_minor"), 2, 5)), // Food (1.0, MultiDrop(LootTable("common.loot_tables.food.prepared"), 1, 3)), + // Recipes + (0.2, Item("common.items.recipes.explosives")), + (1.0, Item("common.items.recipes.utility")), + (1.0, Item("common.items.recipes.equipment.basic")), + (1.0, Item("common.items.recipes.potions")), + (1.0, Item("common.items.recipes.armor.silken")), + (1.0, Item("common.items.recipes.armor.steel")), + (1.0, Item("common.items.recipes.armor.scale")), + (1.0, Item("common.items.recipes.weapons.steel")), + (1.0, Item("common.items.recipes.weapons.hardwood")), ] diff --git a/assets/common/loot_tables/dungeon/cultist/chest.ron b/assets/common/loot_tables/dungeon/cultist/chest.ron index 6508db2140..a150bbd6ec 100644 --- a/assets/common/loot_tables/dungeon/cultist/chest.ron +++ b/assets/common/loot_tables/dungeon/cultist/chest.ron @@ -4,7 +4,7 @@ // Gear (0.25, LootTable("common.loot_tables.weapons.cultist")), (0.25, LootTable("common.loot_tables.armor.cultist")), - (0.25, LootTable("common.loot_tables.weapons.cave")), + (0.25, LootTable("common.loot_tables.weapons.cave")), // Currency (3.0, MultiDrop(Item("common.items.utility.coins"), 1000, 2000)), // Consumables @@ -12,8 +12,12 @@ (0.1, MultiDrop(Item("common.items.food.spore_corruption"), 1, 3)), // Food (1.0, MultiDrop(LootTable("common.loot_tables.food.prepared"), 3, 6)), - // Ingredients - (0.75, MultiDrop(Item("common.items.crafting_ing.alkahest"), 1, 3)), + // Ingredients + (0.75, MultiDrop(Item("common.items.crafting_ing.alkahest"), 1, 3)), + // Recipe + (1.0, Item("common.items.recipes.unique.abyssal_gorget")), + (1.0, Item("common.items.recipes.unique.mindflayer_spellbag")), + (1.0, Item("common.items.recipes.equipment.advanced")), ]), Lottery([ (0.6, Nothing), diff --git a/assets/common/loot_tables/dungeon/gnarling/chest.ron b/assets/common/loot_tables/dungeon/gnarling/chest.ron index 130b2a5a61..885ad69ab3 100644 --- a/assets/common/loot_tables/dungeon/gnarling/chest.ron +++ b/assets/common/loot_tables/dungeon/gnarling/chest.ron @@ -12,4 +12,12 @@ (2.0, MultiDrop(Item("common.items.consumable.potion_minor"), 2, 5)), // Food (1.0, MultiDrop(LootTable("common.loot_tables.food.prepared"), 1, 2)), + // Recipes + (1.0, Item("common.items.recipes.armor.iron")), + (1.0, Item("common.items.recipes.armor.woolen")), + (1.0, Item("common.items.recipes.armor.leather")), + (1.0, Item("common.items.recipes.weapons.iron")), + (1.0, Item("common.items.recipes.weapons.bamboo")), + (1.0, Item("common.items.recipes.food")), + (1.0, Item("common.items.recipes.utility")), ] diff --git a/assets/common/loot_tables/dungeon/haniwa/chest.ron b/assets/common/loot_tables/dungeon/haniwa/chest.ron index 10df9fafd8..6e6321c0bc 100644 --- a/assets/common/loot_tables/dungeon/haniwa/chest.ron +++ b/assets/common/loot_tables/dungeon/haniwa/chest.ron @@ -11,6 +11,17 @@ (2.0, MultiDrop(Item("common.items.consumable.potion_minor"), 2, 5)), // Food (1.0, MultiDrop(LootTable("common.loot_tables.food.prepared"), 2, 4)), + // Recipe + (0.2, Item("common.items.recipes.explosives")), + (1.0, Item("common.items.recipes.instruments")), + (1.0, Item("common.items.recipes.charms")), + (1.0, Item("common.items.recipes.potions")), + (1.0, Item("common.items.recipes.equipment.moderate")), + (1.0, Item("common.items.recipes.armor.bloodsteel")), + (1.0, Item("common.items.recipes.armor.moonweave")), + (1.0, Item("common.items.recipes.armor.primal")), + (1.0, Item("common.items.recipes.weapons.bloodsteel")), + (1.0, Item("common.items.recipes.weapons.frostwood")), ]), Lottery([ (0.7, Nothing), diff --git a/assets/common/loot_tables/dungeon/myrmidon/chest.ron b/assets/common/loot_tables/dungeon/myrmidon/chest.ron index 76bb691f3a..b5db2d6f55 100644 --- a/assets/common/loot_tables/dungeon/myrmidon/chest.ron +++ b/assets/common/loot_tables/dungeon/myrmidon/chest.ron @@ -12,6 +12,18 @@ (2.0, MultiDrop(Item("common.items.consumable.potion_minor"), 4, 8)), // Food (1.0, MultiDrop(LootTable("common.loot_tables.food.prepared"), 2, 5)), + // Recipes + (0.2, Item("common.items.recipes.explosives")), + (1.0, Item("common.items.recipes.instruments")), + (1.0, Item("common.items.recipes.potions")), + (1.0, Item("common.items.recipes.gliders")), + (0.5, Item("common.items.recipes.equipment.moderate")), + (0.5, Item("common.items.recipes.equipment.advanced")), + (1.0, Item("common.items.recipes.armor.orichalcum")), + (1.0, Item("common.items.recipes.armor.sunsilk")), + (1.0, Item("common.items.recipes.armor.dragonscale")), + (1.0, Item("common.items.recipes.weapons.orichalcum")), + (1.0, Item("common.items.recipes.weapons.eldwood")), ]), Lottery([ (0.6, Nothing), diff --git a/assets/common/loot_tables/dungeon/sahagin/chest.ron b/assets/common/loot_tables/dungeon/sahagin/chest.ron index f3f367e6f2..1469bc1de5 100644 --- a/assets/common/loot_tables/dungeon/sahagin/chest.ron +++ b/assets/common/loot_tables/dungeon/sahagin/chest.ron @@ -11,6 +11,19 @@ (2.0, MultiDrop(Item("common.items.consumable.potion_minor"), 2, 5)), // Food (1.0, MultiDrop(LootTable("common.loot_tables.food.prepared"), 1, 4)), + // Recipes + (0.2, Item("common.items.recipes.explosives")), + (1.0, Item("common.items.recipes.charms")), + (1.0, Item("common.items.recipes.instruments")), + (1.0, Item("common.items.recipes.potions")), + (1.0, Item("common.items.recipes.utility")), + (0.5, Item("common.items.recipes.equipment.basic")), + (0.5, Item("common.items.recipes.equipment.moderate")), + (1.0, Item("common.items.recipes.armor.cobalt")), + (1.0, Item("common.items.recipes.armor.druid")), + (1.0, Item("common.items.recipes.armor.carapace")), + (1.0, Item("common.items.recipes.weapons.cobalt")), + (1.0, Item("common.items.recipes.weapons.ironwood")), ]), Lottery([ (0.8, Nothing), diff --git a/assets/common/loot_tables/dungeon/sea_chapel/chest_coral.ron b/assets/common/loot_tables/dungeon/sea_chapel/chest_coral.ron index 0e56b3018f..a8cb2c2b23 100644 --- a/assets/common/loot_tables/dungeon/sea_chapel/chest_coral.ron +++ b/assets/common/loot_tables/dungeon/sea_chapel/chest_coral.ron @@ -4,6 +4,8 @@ // Ingredients (2.0, Item("common.items.crafting_ing.coral_branch")), (0.5, Item("common.items.crafting_ing.pearl")), + (0.25, Item("common.items.recipes.unique.seashell_necklace")), + (0.25, Item("common.items.recipes.unique.winged_coronet")), ]), Lottery([ (0.6, Nothing), diff --git a/assets/common/loot_tables/dungeon/sea_chapel/sea_bishop.ron b/assets/common/loot_tables/dungeon/sea_chapel/sea_bishop.ron index dc706cc739..fcb6f2a6f6 100644 --- a/assets/common/loot_tables/dungeon/sea_chapel/sea_bishop.ron +++ b/assets/common/loot_tables/dungeon/sea_chapel/sea_bishop.ron @@ -1,4 +1,4 @@ [ (1.0, MultiDrop(Item("common.items.crafting_ing.brinestone"), 3, 6)), (1.0, MultiDrop(Item("common.items.crafting_ing.pearl"), 1, 2)), -] \ No newline at end of file +] diff --git a/assets/common/loot_tables/dungeon/sea_chapel/sea_cleric.ron b/assets/common/loot_tables/dungeon/sea_chapel/sea_cleric.ron index 931cf783c6..51247523b8 100644 --- a/assets/common/loot_tables/dungeon/sea_chapel/sea_cleric.ron +++ b/assets/common/loot_tables/dungeon/sea_chapel/sea_cleric.ron @@ -1,4 +1,3 @@ [ - // Nothing - (1.0, Nothing), -] \ No newline at end of file + (1.0, Item("common.items.recipes.armor.brinestone")), +] diff --git a/assets/common/loot_tables/humanoids/grim_salvager.ron b/assets/common/loot_tables/humanoids/grim_salvager.ron index cd1d959272..92254f507e 100644 --- a/assets/common/loot_tables/humanoids/grim_salvager.ron +++ b/assets/common/loot_tables/humanoids/grim_salvager.ron @@ -14,4 +14,7 @@ (0.4, Item("common.items.armor.misc.head.bandana.red")), (0.4, Item("common.items.armor.misc.head.hood")), (0.4, Item("common.items.armor.misc.head.hood_dark")), -] \ No newline at end of file + // Recipes + (2.0, Item("common.items.recipes.equipment.basic")), + (1.0, Item("common.items.recipes.equipment.moderate")), +] diff --git a/assets/common/loot_tables/humanoids/humanoid.ron b/assets/common/loot_tables/humanoids/humanoid.ron index 97718d5c58..d947631c95 100644 --- a/assets/common/loot_tables/humanoids/humanoid.ron +++ b/assets/common/loot_tables/humanoids/humanoid.ron @@ -14,4 +14,4 @@ // Weapons (1.0, LootTable("common.loot_tables.weapons.starter")), (1.0, LootTable("common.loot_tables.weapons.tier-0")), -] \ No newline at end of file +] diff --git a/assets/common/loot_tables/humanoids/pirate.ron b/assets/common/loot_tables/humanoids/pirate.ron index 3b148a5546..5d7dabfaa1 100644 --- a/assets/common/loot_tables/humanoids/pirate.ron +++ b/assets/common/loot_tables/humanoids/pirate.ron @@ -17,4 +17,8 @@ // Food (1.0, LootTable("common.loot_tables.food.wild_ingredients")), (0.5, Item("common.items.food.meat.fish_raw")), -] \ No newline at end of file + // Recipes + (2.0, Item("common.items.recipes.equipment.basic")), + (1.0, Item("common.items.recipes.equipment.moderate")), + (0.5, Item("common.items.recipes.equipment.advanced")), +] diff --git a/assets/common/loot_tables/humanoids/witch.ron b/assets/common/loot_tables/humanoids/witch.ron index 34b6a8d0df..91db15f01a 100644 --- a/assets/common/loot_tables/humanoids/witch.ron +++ b/assets/common/loot_tables/humanoids/witch.ron @@ -5,4 +5,5 @@ (0.5, LootTable("common.loot_tables.weapons.tier-3")), (0.1, LootTable("common.loot_tables.weapons.tier-4")), (0.05, Item("common.items.armor.witch.hat")), -] \ No newline at end of file + (0.1, Item("common.items.recipes.unique.troll_hide_pack")), +] diff --git a/assets/common/loot_tables/sprite/chest-buried.ron b/assets/common/loot_tables/sprite/chest-buried.ron index d5b7a55c25..def2f90c5b 100644 --- a/assets/common/loot_tables/sprite/chest-buried.ron +++ b/assets/common/loot_tables/sprite/chest-buried.ron @@ -1,4 +1,5 @@ [ (1.0, LootTable("common.loot_tables.weapons.components.tier-1")), (1.0, LootTable("common.loot_tables.armor.cloth")), -] \ No newline at end of file + (0.5, Item("common.items.recipes.explosives")), +] diff --git a/assets/common/loot_tables/sprite/chest.ron b/assets/common/loot_tables/sprite/chest.ron index f44e90a59f..0c1737ad16 100644 --- a/assets/common/loot_tables/sprite/chest.ron +++ b/assets/common/loot_tables/sprite/chest.ron @@ -2,4 +2,12 @@ (1.0, LootTable("common.loot_tables.weapons.components.tier-0")), (1.0, LootTable("common.loot_tables.weapons.components.tier-1")), (1.0, LootTable("common.loot_tables.armor.cloth")), -] \ No newline at end of file + (0.2, Item("common.items.recipes.explosives")), + (0.5, Item("common.items.recipes.instruments")), + (0.2, Item("common.items.recipes.charms")), + (1.0, Item("common.items.recipes.food")), + (0.3, Item("common.items.recipes.gliders")), + (0.5, Item("common.items.recipes.potions")), + (1.0, Item("common.items.recipes.utility")), + (0.5, Item("common.items.recipes.equipment.basic")), +] diff --git a/assets/common/loot_tables/sprite/crate.ron b/assets/common/loot_tables/sprite/crate.ron index 8336ee9b25..35254daf3f 100644 --- a/assets/common/loot_tables/sprite/crate.ron +++ b/assets/common/loot_tables/sprite/crate.ron @@ -2,4 +2,7 @@ (2.0, LootTable("common.loot_tables.materials.common")), (3.0, LootTable("common.loot_tables.food.prepared")), (1.0, Item("common.items.armor.misc.head.straw")), -] \ No newline at end of file + (0.5, Item("common.items.recipes.instruments")), + (1.0, Item("common.items.recipes.food")), + (1.0, Item("common.items.recipes.utility")), +] diff --git a/assets/common/loot_tables/world/world_bosses/gigas_frost/boss.ron b/assets/common/loot_tables/world/world_bosses/gigas_frost/boss.ron index 01dd3a74e7..44a1b0cb0a 100644 --- a/assets/common/loot_tables/world/world_bosses/gigas_frost/boss.ron +++ b/assets/common/loot_tables/world/world_bosses/gigas_frost/boss.ron @@ -1,4 +1,5 @@ [ (1.0, LootTable("common.loot_tables.armor.boreal")), (1.0, Item("common.items.crafting_ing.glacial_crystal")), + (1.0, Item("common.items.recipes.unique.polaris")), ] \ No newline at end of file diff --git a/assets/common/recipe_book.ron b/assets/common/recipe_book_manifest.ron similarity index 99% rename from assets/common/recipe_book.ron rename to assets/common/recipe_book_manifest.ron index 4a07e17a7f..babab7a4ba 100644 --- a/assets/common/recipe_book.ron +++ b/assets/common/recipe_book_manifest.ron @@ -1,5 +1,5 @@ { - "crafting_hammer": ( + "craftsman_hammer": ( output: ("common.items.tool.craftsman_hammer", 1), inputs: [ (Item("common.items.log.wood"), 1, false), @@ -50,7 +50,7 @@ ], craft_sprite: Some(Cauldron), ), - "potion_s": ( + "potion_minor": ( output: ("common.items.consumable.potion_minor", 1), inputs: [ (Item("common.items.crafting_ing.empty_vial"), 1, false), @@ -59,7 +59,7 @@ ], craft_sprite: Some(Cauldron), ), - "potion_m": ( + "potion_medium": ( output: ("common.items.consumable.potion_med", 1), inputs: [ (Item("common.items.consumable.potion_minor"), 2, false), @@ -329,14 +329,6 @@ ], craft_sprite: Some(Forge), ), - /* Only for Christmas event so comment out once done - "diamonds": ( - output: ("common.items.mineral.gem.diamond", 1), - inputs: [ - (Item("common.items.mineral.ore.coal"), 20, false), - ], - craft_sprite: Some(Forge), - ), */ "cotton": ( output: ("common.items.crafting_ing.cloth.cotton", 1), inputs: [ diff --git a/assets/common/trading/item_price_calculation.ron b/assets/common/trading/item_price_calculation.ron index 8397802523..8b1e8d2bdf 100644 --- a/assets/common/trading/item_price_calculation.ron +++ b/assets/common/trading/item_price_calculation.ron @@ -23,6 +23,10 @@ loot_tables: [ // Food Ingredients (20.375, true, "common.trading.food"), + // Recipes + (1.0, true, "common.trading.sellable_recipe"), + (1.0, false, "common.trading.unsellable_recipe"), + // Potions // // crafted from food, no need to duplicate it here. @@ -46,4 +50,5 @@ good_scaling: [ (Armor, 0.025), // common.items.armor.misc.pants.worker_blue (Tools, 0.015487), // common.items.weapons.staff.starter_staff (Ingredients, 0.034626), // common.items.crafting_ing.leather_scraps + (Recipe, 0.01), // common.items.recipes ]) diff --git a/assets/common/trading/sellable_recipe.ron b/assets/common/trading/sellable_recipe.ron new file mode 100644 index 0000000000..5d0f3ad91c --- /dev/null +++ b/assets/common/trading/sellable_recipe.ron @@ -0,0 +1,17 @@ +// Loot table that exists purely for price rationalisation +// +// This loot table should be marked as sellable. +// +// Please keep it sorted by rarity so it's easier to reason about things +[ + // Recipes + (1.0, Item("common.items.recipes.food")), + (1.0, Item("common.items.recipes.utility")), + (1.0, Item("common.items.recipes.equipment.basic")), + (1.0, Item("common.items.recipes.potions")), + (1.0, Item("common.items.recipes.armor.iron")), + (1.0, Item("common.items.recipes.armor.woolen")), + (1.0, Item("common.items.recipes.armor.leather")), + (1.0, Item("common.items.recipes.weapons.iron")), + (1.0, Item("common.items.recipes.weapons.bamboo")), +] diff --git a/assets/common/trading/unsellable_recipe.ron b/assets/common/trading/unsellable_recipe.ron new file mode 100644 index 0000000000..c2966dec8d --- /dev/null +++ b/assets/common/trading/unsellable_recipe.ron @@ -0,0 +1,45 @@ +// Loot table that exists purely for price rationalisation +// +// This loot table should be marked as unsellable. +// +// Please keep it sorted by rarity so it's easier to reason about things +[ + // Recipes + // Misc Groups + (1.0, Item("common.items.recipes.charms")), + (1.0, Item("common.items.recipes.explosives")), + (1.0, Item("common.items.recipes.gliders")), + (1.0, Item("common.items.recipes.instruments")), + // Equipment + (1.0, Item("common.items.recipes.equipment.moderate")), + (0.2, Item("common.items.recipes.equipment.advanced")), + // Armors + (0.7, Item("common.items.recipes.armor.steel")), + (0.7, Item("common.items.recipes.armor.silken")), + (0.7, Item("common.items.recipes.armor.scale")), + (0.7, Item("common.items.recipes.weapons.steel")), + (0.7, Item("common.items.recipes.weapons.hardwood")), + (0.4, Item("common.items.recipes.armor.cobalt")), + (0.4, Item("common.items.recipes.armor.druid")), + (0.4, Item("common.items.recipes.armor.carapace")), + (0.4, Item("common.items.recipes.weapons.cobalt")), + (0.4, Item("common.items.recipes.weapons.ironwood")), + (0.2, Item("common.items.recipes.armor.bloodsteel")), + (0.2, Item("common.items.recipes.armor.moonweave")), + (0.2, Item("common.items.recipes.armor.primal")), + (0.2, Item("common.items.recipes.weapons.bloodsteel")), + (0.2, Item("common.items.recipes.weapons.frostwood")), + (0.1, Item("common.items.recipes.armor.orichalcum")), + (0.1, Item("common.items.recipes.armor.sunsilk")), + (0.1, Item("common.items.recipes.armor.dragonscale")), + (0.1, Item("common.items.recipes.armor.brinestone")), + (0.1, Item("common.items.recipes.weapons.orichalcum")), + (0.1, Item("common.items.recipes.weapons.eldwood")), + // Unique items + (1.0, Item("common.items.recipes.unique.seashell_necklace")), + (0.8, Item("common.items.recipes.unique.winged_coronet")), + (0.5, Item("common.items.recipes.unique.troll_hide_pack")), + (0.3, Item("common.items.recipes.unique.abyssal_gorget")), + (0.1, Item("common.items.recipes.unique.mindflayer_spellbag")), + (0.1, Item("common.items.recipes.unique.polaris")), +] diff --git a/assets/voxygen/i18n/en/common.ftl b/assets/voxygen/i18n/en/common.ftl index 43bee53758..f1e7eb60ec 100644 --- a/assets/voxygen/i18n/en/common.ftl +++ b/assets/voxygen/i18n/en/common.ftl @@ -86,6 +86,7 @@ common-kind-throwable = Can be thrown common-kind-utility = Utility common-kind-ingredient = Ingredient common-kind-lantern = Lantern +common-kind-recipegroup = Recipes common-hands-one = One-Handed common-hands-two = Two-Handed common-rand_appearance = Random appearance diff --git a/assets/voxygen/i18n/en/hud/crafting.ftl b/assets/voxygen/i18n/en/hud/crafting.ftl index 081a0be97b..97cd38586b 100644 --- a/assets/voxygen/i18n/en/hud/crafting.ftl +++ b/assets/voxygen/i18n/en/hud/crafting.ftl @@ -49,3 +49,5 @@ hud-crafting-mod_comp_sec_slot_title = Animal Material hud-crafting-mod_comp_sec_slot_desc = Optionally place an animal crafting ingredient, only certain ingredients can be used to augment weapons. hud-crafting-repair_slot_title = Damaged Item hud-crafting-repair_slot_desc = Place an item here to see the cost of repairing it at its current durability level. +hud-crafting-recipe-uncraftable = Recipe Cannot be Crafted +hud-crafting-recipe-unlearned = You must first learn how to craft this recipe. diff --git a/assets/voxygen/i18n/en/item/recipe.ftl b/assets/voxygen/i18n/en/item/recipe.ftl new file mode 100644 index 0000000000..f31f7d513b --- /dev/null +++ b/assets/voxygen/i18n/en/item/recipe.ftl @@ -0,0 +1,86 @@ +recipe-armor-bloodsteel = Bloodsteel Armor Recipes + .desc = Bloodsteel Armor Recipes +recipe-armor-brinestone = Brinestone Armor Recipes + .desc = Brinestone Armor Recipes +recipe-armor-carapace = Carapace Armor Recipes + .desc = Carapace Armor Recipes +recipe-armor-cobalt = Cobalt Armor Recipes + .desc = Cobalt Armor Recipes +recipe-armor-dragonscale = Dragonscale Armor Recipes + .desc = Dragonscale Armor Recipes +recipe-armor-druid = Druid Armor Recipes + .desc = Druid Armor Recipes +recipe-armor-iron = Iron Armor Recipes + .desc = Iron Armor Recipes +recipe-armor-leather = Leather Armor Recipes + .desc = Leather Armor Recipes +recipe-armor-moonweave = Moonweave Armor Recipes + .desc = Moonweave Armor Recipes +recipe-armor-orichalcum = Orichalcum Armor Recipes + .desc = Orichalcum Armor Recipes +recipe-armor-primal = Primal Armor Recipes + .desc = Primal Armor Recipes +recipe-armor-scale = Scale Armor Recipes + .desc = Scale Armor Recipes +recipe-armor-silken = Silken Armor Recipes + .desc = Silken Armor Recipes +recipe-armor-steel = Steel Armor Recipes + .desc = Steel Armor Recipes +recipe-armor-sunsilk = Sunsilk Armor Recipes + .desc = Sunsilk Armor Recipes +recipe-armor-woolen = Woolen Armor Recipes + .desc = Woolen Armor Recipes +recipe-equipment-basic = Basic Equipment Recipes + .desc = Basic Equipment Recipes +recipe-equipment-moderate = Moderate Equipment Recipes + .desc = Moderate Equipment Recipes +recipe-equipment-advanced = Advanced Equipment Recipes + .desc = Advanced Equipment Recipes +recipe-unique-abyssal_gorget = Abyssal Gorget Recipe + .desc = Abyssal Gorget Recipe +recipe-unique-mindflayer_spellbag = Mindflayer Spellbag Recipe + .desc = Mindflayer Spellbag Recipe +recipe-unique-polaris = Polaris Recipe + .desc = Polaris Recipe +recipe-unique-seashell_necklace = Seashell Necklace Recipe + .desc = Seashell Necklace Recipe +recipe-unique-troll_hide_pack = Troll Hide Pack Recipe + .desc = Troll Hide Pack Recipe +recipe-unique-winged_coronet = Winged Coronet Recipe + .desc = Winged Coronet Recipe +recipe-charms = Charms Recipes + .desc = Charms Recipes +recipe-explosives = Explosives Recipes + .desc = Explosives Recipes +recipe-food = Food Recipes + .desc = Food Recipes +recipe-gliders = Gliders Recipes + .desc = Gliders Recipes +recipe-instruments = Instruments Recipes + .desc = Instruments Recipes +recipe-potions = Potions Recipes + .desc = Potions Recipes +recipe-utility = Utility Recipes + .desc = Utility Recipes +recipe-weapons-iron = Iron Weapon Recipes + .desc = Iron Weapon Recipes +recipe-weapons-steel = Steel Weapon Recipes + .desc = Steel Weapon Recipes +recipe-weapons-cobalt = Cobalt Weapon Recipes + .desc = Cobalt Weapon Recipes +recipe-weapons-bloodsteel = Bloodsteel Weapon Recipes + .desc = Bloodsteel Weapon Recipes +recipe-weapons-orichalcum = Orichalcum Weapon Recipes + .desc = Orichalcum Weapon Recipes +recipe-weapons-bamboo = Bamboo Weapon Recipes + .desc = Bamboo Weapon Recipes +recipe-weapons-hardwood = Hardwood Weapon Recipes + .desc = Hardwood Weapon Recipes +recipe-weapons-ironwood = Ironwood Weapon Recipes + .desc = Ironwood Weapon Recipes +recipe-weapons-frostwood = Frostwood Weapon Recipes + .desc = Frostwood Weapon Recipes +recipe-weapons-eldwood = Eldwood Weapon Recipes + .desc = Eldwood Weapon Recipes +recipe-default = Default Recipes + .desc = Default Recipes \ No newline at end of file diff --git a/assets/voxygen/item_image_manifest.ron b/assets/voxygen/item_image_manifest.ron index f5f9ad62f3..359c50b284 100644 --- a/assets/voxygen/item_image_manifest.ron +++ b/assets/voxygen/item_image_manifest.ron @@ -1708,6 +1708,174 @@ "voxel.object.collar", (0.1, 0.0, 0.0), (-60.0, 20.0, 10.0), 0.9, ), + Simple("common.items.recipes.potions"): VoxTrans( + "voxel.object.recipe_alchemy", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.explosives"): VoxTrans( + "voxel.object.recipe_alchemy", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.charms"): VoxTrans( + "voxel.object.recipe_alchemy", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.iron"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.steel"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.cobalt"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.bloodsteel"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.orichalcum"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.unique.polaris"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.iron"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.steel"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.cobalt"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.bloodsteel"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.orichalcum"): VoxTrans( + "voxel.object.recipe_blacksmithing", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.gliders"): VoxTrans( + "voxel.object.recipe_carpentry", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.instruments"): VoxTrans( + "voxel.object.recipe_carpentry", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.bamboo"): VoxTrans( + "voxel.object.recipe_carpentry", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.hardwood"): VoxTrans( + "voxel.object.recipe_carpentry", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.ironwood"): VoxTrans( + "voxel.object.recipe_carpentry", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.frostwood"): VoxTrans( + "voxel.object.recipe_carpentry", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.weapons.eldwood"): VoxTrans( + "voxel.object.recipe_carpentry", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.food"): VoxTrans( + "voxel.object.recipe_cooking", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.brinestone"): VoxTrans( + "voxel.object.recipe_lapidary", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.unique.abyssal_gorget"): VoxTrans( + "voxel.object.recipe_lapidary", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.unique.seashell_necklace"): VoxTrans( + "voxel.object.recipe_lapidary", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.leather"): VoxTrans( + "voxel.object.recipe_leatherworking", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.scale"): VoxTrans( + "voxel.object.recipe_leatherworking", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.carapace"): VoxTrans( + "voxel.object.recipe_leatherworking", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.primal"): VoxTrans( + "voxel.object.recipe_leatherworking", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.dragonscale"): VoxTrans( + "voxel.object.recipe_leatherworking", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.unique.mindflayer_spellbag"): VoxTrans( + "voxel.object.recipe_leatherworking", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.unique.troll_hide_pack"): VoxTrans( + "voxel.object.recipe_leatherworking", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.unique.winged_coronet"): VoxTrans( + "voxel.object.recipe_leatherworking", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.woolen"): VoxTrans( + "voxel.object.recipe_weaving", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.silken"): VoxTrans( + "voxel.object.recipe_weaving", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.druid"): VoxTrans( + "voxel.object.recipe_weaving", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.moonweave"): VoxTrans( + "voxel.object.recipe_weaving", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.armor.sunsilk"): VoxTrans( + "voxel.object.recipe_weaving", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.utility"): VoxTrans( + "voxel.object.scroll", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.equipment.basic"): VoxTrans( + "voxel.object.scroll", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.equipment.moderate"): VoxTrans( + "voxel.object.scroll", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), + Simple("common.items.recipes.equipment.advanced"): VoxTrans( + "voxel.object.scroll", + (1.0, 0.0, 20.0), (30.0, 45.0, 120.0), 1.0, + ), // Armor // Starter Parts Simple("common.items.armor.misc.foot.sandals"): VoxTrans( diff --git a/assets/voxygen/voxel/item_drop_manifest.ron b/assets/voxygen/voxel/item_drop_manifest.ron index fb843bb54f..3940ef308d 100644 --- a/assets/voxygen/voxel/item_drop_manifest.ron +++ b/assets/voxygen/voxel/item_drop_manifest.ron @@ -418,6 +418,14 @@ // Other Simple("common.items.utility.coins"): "voxel.object.v-coin", Simple("common.items.utility.collar"): "voxel.object.collar", + Recipe("recipe_alchemy"): "voxel.object.recipe_alchemy", + Recipe("recipe_blacksmithing"): "voxel.object.recipe_blacksmithing", + Recipe("recipe_carpentry"): "voxel.object.recipe_carpentry", + Recipe("recipe_cooking"): "voxel.object.recipe_cooking", + Recipe("recipe_lapidary"): "voxel.object.recipe_lapidary", + Recipe("recipe_leatherworking"): "voxel.object.recipe_leatherworking", + Recipe("recipe_weaving"): "voxel.object.recipe_weaving", + Recipe("scroll"): "voxel.object.scroll", // Armor // Starter Parts Simple("common.items.armor.misc.foot.sandals"): "voxel.armor.misc.foot.cloth_sandal", diff --git a/assets/voxygen/voxel/object/recipe_alchemy.vox b/assets/voxygen/voxel/object/recipe_alchemy.vox new file mode 100644 index 0000000000..9e4d828b59 --- /dev/null +++ b/assets/voxygen/voxel/object/recipe_alchemy.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c676f8a806894692fb1dc1e7c352698ea9de968cf9a2ba88aacf901cb5a93b0 +size 2000 diff --git a/assets/voxygen/voxel/object/recipe_blacksmithing.vox b/assets/voxygen/voxel/object/recipe_blacksmithing.vox new file mode 100644 index 0000000000..ee83936e1d --- /dev/null +++ b/assets/voxygen/voxel/object/recipe_blacksmithing.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fcee3d4ef0290a58f9363c0400b50397f4765a9c64044ecce9dccfe2c6f4d5f0 +size 2060 diff --git a/assets/voxygen/voxel/object/recipe_carpentry.vox b/assets/voxygen/voxel/object/recipe_carpentry.vox new file mode 100644 index 0000000000..f00dbd67fb --- /dev/null +++ b/assets/voxygen/voxel/object/recipe_carpentry.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b2a2558b9c4fc0311bdcd93e761b1bc99a9429e91dff47f9e6af34c84ce1308 +size 2000 diff --git a/assets/voxygen/voxel/object/recipe_cooking.vox b/assets/voxygen/voxel/object/recipe_cooking.vox new file mode 100644 index 0000000000..917c63954c --- /dev/null +++ b/assets/voxygen/voxel/object/recipe_cooking.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:72a82fc13cffad0ab785aec4f2dc5dabfb3b1405cf495a6a63fdb91ce49ce5f2 +size 2024 diff --git a/assets/voxygen/voxel/object/recipe_lapidary.vox b/assets/voxygen/voxel/object/recipe_lapidary.vox new file mode 100644 index 0000000000..90577e200c --- /dev/null +++ b/assets/voxygen/voxel/object/recipe_lapidary.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbb1d827b5003f1fd70679a85023402eebe916eb6f622ef8cdddb11485528d56 +size 1992 diff --git a/assets/voxygen/voxel/object/recipe_leatherworking.vox b/assets/voxygen/voxel/object/recipe_leatherworking.vox new file mode 100644 index 0000000000..aeb1b6d1ee --- /dev/null +++ b/assets/voxygen/voxel/object/recipe_leatherworking.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09a0529e44a3a1615444cdf3d94fbb13e784606e5c815cca83a3e4dafd28ee5d +size 2004 diff --git a/assets/voxygen/voxel/object/recipe_weaving.vox b/assets/voxygen/voxel/object/recipe_weaving.vox new file mode 100644 index 0000000000..d6ee164e4f --- /dev/null +++ b/assets/voxygen/voxel/object/recipe_weaving.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b990ad1556bbe473263d88a8ec7eaf18b504ee7222db73b2b0fbabb9c428ac2 +size 1976 diff --git a/assets/voxygen/voxel/object/scroll.vox b/assets/voxygen/voxel/object/scroll.vox new file mode 100644 index 0000000000..7be3b78f8e --- /dev/null +++ b/assets/voxygen/voxel/object/scroll.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb7d54277c8f4d632bdf54513c0f9fb19ff0cb3a110b38d6405e7a88d46172eb +size 23504 diff --git a/assets/voxygen/voxel/object_manifest.ron b/assets/voxygen/voxel/object_manifest.ron index 525e3b8106..347b478a5a 100644 --- a/assets/voxygen/voxel/object_manifest.ron +++ b/assets/voxygen/voxel/object_manifest.ron @@ -1131,4 +1131,14 @@ central: ("armor.empty"), ) ), + Scroll: ( + bone0: ( + offset: (0.0, 0.0, 0.0), + central: ("object.recipe"), + ), + bone1: ( + offset: (0.0, 0.0, 0.0), + central: ("armor.empty"), + ) + ), }) diff --git a/client/src/lib.rs b/client/src/lib.rs index c700e5d61a..cbe8668eb0 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -37,7 +37,7 @@ use common::{ lod, mounting::{Rider, VolumePos, VolumeRider}, outcome::Outcome, - recipe::{ComponentRecipeBook, RecipeBook, RepairRecipeBook}, + recipe::{ComponentRecipeBook, RecipeBookManifest, RepairRecipeBook}, resources::{GameMode, PlayerEntity, Time, TimeOfDay}, shared_server_config::ServerConstants, spiral::Spiral2d, @@ -278,7 +278,6 @@ pub struct Client { possible_starting_sites: Vec, pois: Vec, pub chat_mode: ChatMode, - recipe_book: RecipeBook, component_recipe_book: ComponentRecipeBook, repair_recipe_book: RepairRecipeBook, available_recipes: HashMap>, @@ -692,6 +691,7 @@ impl Client { *state.ecs_mut().write_resource() = PlayerEntity(Some(entity)); state.ecs_mut().insert(material_stats); state.ecs_mut().insert(ability_map); + state.ecs_mut().insert(recipe_book); let map_size = map_size_lg.chunks(); let max_height = world_map.max_height; @@ -953,7 +953,6 @@ impl Client { world_map.sites, world_map.possible_starting_sites, world_map.pois, - recipe_book, component_recipe_book, repair_recipe_book, max_group_size, @@ -972,7 +971,6 @@ impl Client { sites, possible_starting_sites, pois, - recipe_book, component_recipe_book, repair_recipe_book, max_group_size, @@ -1019,7 +1017,6 @@ impl Client { .collect(), possible_starting_sites, pois, - recipe_book, component_recipe_book, repair_recipe_book, available_recipes: HashMap::default(), @@ -1492,8 +1489,6 @@ impl Client { pub fn world_data(&self) -> &WorldData { &self.world_data } - pub fn recipe_book(&self) -> &RecipeBook { &self.recipe_book } - pub fn component_recipe_book(&self) -> &ComponentRecipeBook { &self.component_recipe_book } pub fn repair_recipe_book(&self) -> &RepairRecipeBook { &self.repair_recipe_book } @@ -1508,21 +1503,6 @@ impl Client { /// entity does not have a position. pub fn set_lod_pos_fallback(&mut self, pos: Vec2) { self.lod_pos_fallback = Some(pos); } - /// Returns whether the specified recipe can be crafted and the sprite, if - /// any, that is required to do so. - pub fn can_craft_recipe(&self, recipe: &str, amount: u32) -> (bool, Option) { - self.recipe_book - .get(recipe) - .zip(self.inventories().get(self.entity())) - .map(|(recipe, inv)| { - ( - recipe.inventory_contains_ingredients(inv, amount).is_ok(), - recipe.craft_sprite, - ) - }) - .unwrap_or((false, None)) - } - pub fn craft_recipe( &mut self, recipe: &str, @@ -1530,8 +1510,20 @@ impl Client { craft_sprite: Option<(VolumePos, SpriteKind)>, amount: u32, ) -> bool { - let (can_craft, required_sprite) = self.can_craft_recipe(recipe, amount); - let has_sprite = required_sprite.map_or(true, |s| Some(s) == craft_sprite.map(|(_, s)| s)); + let (can_craft, has_sprite) = if let Some(inventory) = self + .state + .ecs() + .read_storage::() + .get(self.entity()) + { + let rbm = self.state.ecs().read_resource::(); + let (can_craft, required_sprite) = inventory.can_craft_recipe(recipe, 1, &rbm); + let has_sprite = + required_sprite.map_or(true, |s| Some(s) == craft_sprite.map(|(_, s)| s)); + (can_craft, has_sprite) + } else { + (false, false) + }; if can_craft && has_sprite { self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryEvent( InventoryEvent::CraftRecipe { @@ -1680,19 +1672,22 @@ impl Client { } fn update_available_recipes(&mut self) { - self.available_recipes = self - .recipe_book - .iter() - .map(|(name, _)| name.clone()) - .filter_map(|name| { - let (can_craft, required_sprite) = self.can_craft_recipe(&name, 1); - if can_craft { - Some((name, required_sprite)) - } else { - None - } - }) - .collect(); + let rbm = self.state.ecs().read_resource::(); + let inventories = self.state.ecs().read_storage::(); + if let Some(inventory) = inventories.get(self.entity()) { + self.available_recipes = inventory + .recipes_iter() + .cloned() + .filter_map(|name| { + let (can_craft, required_sprite) = inventory.can_craft_recipe(&name, 1, &rbm); + if can_craft { + Some((name, required_sprite)) + } else { + None + } + }) + .collect(); + } } /// Unstable, likely to be removed in a future release @@ -2844,6 +2839,9 @@ impl Client { ServerGeneral::SpectatePosition(pos) => { frontend_events.push(Event::SpectatePosition(pos)); }, + ServerGeneral::UpdateRecipes => { + self.update_available_recipes(); + }, _ => unreachable!("Not a in_game message"), } Ok(()) diff --git a/common/Cargo.toml b/common/Cargo.toml index a75f4aa4a3..9e649bf9ca 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -10,6 +10,7 @@ hot-reloading = ["common-assets/hot-reloading"] simd = ["vek/platform_intrinsics"] bin_csv = ["ron", "csv", "clap"] bin_graphviz = ["petgraph", "clap"] +bin_recipe_gen = ["ron"] bin_cmd_doc_gen = [] bin_asset_migrate = ["ron"] rrt_pathfinding = ["kiddo"] diff --git a/common/net/src/msg/server.rs b/common/net/src/msg/server.rs index 5715a15d85..66d58e2ab1 100644 --- a/common/net/src/msg/server.rs +++ b/common/net/src/msg/server.rs @@ -10,7 +10,7 @@ use common::{ event::{PluginHash, UpdateCharacterMetadata}, lod, outcome::Outcome, - recipe::{ComponentRecipeBook, RecipeBook, RepairRecipeBook}, + recipe::{ComponentRecipeBook, RecipeBookManifest, RepairRecipeBook}, resources::{Time, TimeOfDay, TimeScale}, shared_server_config::ServerConstants, terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, @@ -68,7 +68,7 @@ pub enum ServerInit { max_group_size: u32, client_timeout: Duration, world_map: crate::msg::world_msg::WorldMapMsg, - recipe_book: RecipeBook, + recipe_book: RecipeBookManifest, component_recipe_book: ComponentRecipeBook, repair_recipe_book: RepairRecipeBook, material_stats: MaterialStatManifest, @@ -222,6 +222,9 @@ pub enum ServerGeneral { SpectatePosition(Vec3), /// Plugin data requested from the server PluginData(Vec), + /// Update the list of available recipes. Usually called after a new recipe + /// is acquired + UpdateRecipes, } impl ServerGeneral { @@ -345,7 +348,8 @@ impl ServerMsg { | ServerGeneral::MapMarker(_) | ServerGeneral::WeatherUpdate(_) | ServerGeneral::LocalWindUpdate(_) - | ServerGeneral::SpectatePosition(_) => { + | ServerGeneral::SpectatePosition(_) + | ServerGeneral::UpdateRecipes => { c_type == ClientType::Game && presence.is_some() }, // Always possible diff --git a/common/src/bin/csv_import/main.rs b/common/src/bin/csv_import/main.rs index 83be0d513c..f2ac169592 100644 --- a/common/src/bin/csv_import/main.rs +++ b/common/src/bin/csv_import/main.rs @@ -6,7 +6,7 @@ use clap::Parser; use hashbrown::HashMap; use ron::ser::{to_string_pretty, PrettyConfig}; use serde::Serialize; -use std::{error::Error, fs::File, io::Write}; +use std::{borrow::Cow, error::Error, fs::File, io::Write}; use veloren_common::{ assets::ASSETS_PATH, @@ -79,9 +79,9 @@ fn armor_stats() -> Result<(), Box> { if let Ok(ref record) = record { if item.item_definition_id() - == ItemDefinitionId::Simple( + == ItemDefinitionId::Simple(Cow::Borrowed( record.get(headers["Path"]).expect("No file path in csv?"), - ) + )) { let protection = if let Some(protection_raw) = record.get(headers["Protection"]) { @@ -287,9 +287,9 @@ fn weapon_stats() -> Result<(), Box> { if let ItemKind::Tool(tool) = &*item.kind() { if let Ok(ref record) = record { if item.item_definition_id() - == ItemDefinitionId::Simple( + == ItemDefinitionId::Simple(Cow::Borrowed( record.get(headers["Path"]).expect("No file path in csv?"), - ) + )) { let kind = tool.kind; let equip_time_secs: f32 = record diff --git a/common/src/bin/recipe_graphviz.rs b/common/src/bin/recipe_graphviz.rs index 89ca057d82..09b2c83c95 100644 --- a/common/src/bin/recipe_graphviz.rs +++ b/common/src/bin/recipe_graphviz.rs @@ -5,13 +5,12 @@ use petgraph::{ }; use std::{fs::File, io::Write}; use veloren_common::{ - assets::AssetExt, comp::item::ItemDesc, - recipe::{RecipeBook, RecipeInput}, + recipe::{RecipeBookManifest, RecipeInput}, }; fn main() { - let recipes = RecipeBook::load_expect_cloned("common.recipe_book"); + let recipes = RecipeBookManifest::load().read(); let mut graph = Graph::new(); let mut nodes = HashMap::new(); let mut add_node = |graph: &mut Graph<_, _>, node: &str| { diff --git a/common/src/cmd.rs b/common/src/cmd.rs index 80157817ef..a5b96c135a 100644 --- a/common/src/cmd.rs +++ b/common/src/cmd.rs @@ -6,7 +6,9 @@ use crate::{ AdminRole as Role, Skill, }, generation::try_all_entity_configs, - npc, terrain, + npc, + recipe::RecipeBookManifest, + terrain, }; use hashbrown::HashMap; use lazy_static::lazy_static; @@ -137,6 +139,10 @@ lazy_static! { .iter() .map(|o| o.to_string().to_string()) .collect(); + static ref RECIPES: Vec = { + let rbm = RecipeBookManifest::load().cloned(); + rbm.keys().cloned().collect::>() + }; static ref TIMES: Vec = [ "midnight", "night", "dawn", "morning", "day", "noon", "dusk" ] @@ -378,6 +384,7 @@ pub enum ServerChatCommand { ReloadChunks, RemoveLights, RepairEquipment, + ResetRecipes, Respawn, RevokeBuild, RevokeBuildAll, @@ -734,6 +741,7 @@ impl ServerChatCommand { "Reloads chunks loaded on the server", Some(Admin), ), + ServerChatCommand::ResetRecipes => cmd(vec![], "Resets your recipe book", Some(Admin)), ServerChatCommand::RemoveLights => cmd( vec![Float("radius", 20.0, Optional)], "Removes all lights spawned by players", @@ -1030,6 +1038,7 @@ impl ServerChatCommand { ServerChatCommand::PermitBuild => "permit_build", ServerChatCommand::Players => "players", ServerChatCommand::Portal => "portal", + ServerChatCommand::ResetRecipes => "reset_recipes", ServerChatCommand::Region => "region", ServerChatCommand::ReloadChunks => "reload_chunks", ServerChatCommand::RemoveLights => "remove_lights", diff --git a/common/src/comp/body/object.rs b/common/src/comp/body/object.rs index d9403a46e0..73f6d16687 100644 --- a/common/src/comp/body/object.rs +++ b/common/src/comp/body/object.rs @@ -125,6 +125,7 @@ make_case_elim!( BubbleBomb = 110, IronPikeBomb = 111, Lavathrower = 112, + Scroll = 113, } ); @@ -135,7 +136,7 @@ impl Body { } } -pub const ALL_OBJECTS: [Body; 113] = [ +pub const ALL_OBJECTS: [Body; 114] = [ Body::Arrow, Body::Bomb, Body::Scarecrow, @@ -249,6 +250,7 @@ pub const ALL_OBJECTS: [Body; 113] = [ Body::BubbleBomb, Body::IronPikeBomb, Body::Lavathrower, + Body::Scroll, ]; impl From for super::Body { @@ -371,6 +373,7 @@ impl Body { Body::SurpriseEgg => "surprise_egg", Body::BubbleBomb => "bubble_bomb", Body::IronPikeBomb => "iron_pike_bomb", + Body::Scroll => "recipe", } } @@ -411,6 +414,7 @@ impl Body { Body::TrainingDummy => 2000.0, Body::Snowball => 0.9 * WATER_DENSITY, Body::Pebble => 1000.0, + Body::Scroll => 0.5 * WATER_DENSITY, // let them sink _ => 1.1 * WATER_DENSITY, }; @@ -462,7 +466,7 @@ impl Body { | Body::ChestOpen | Body::ChestSkull | Body::ChestVines => 100.0, - Body::Coins => 1.0, + Body::Coins | Body::Scroll => 1.0, Body::CraftingBench => 100.0, Body::Crate => 50.0, Body::Crossbow => 200.0, diff --git a/common/src/comp/inventory/item/item_key.rs b/common/src/comp/inventory/item/item_key.rs index 6af01d7b43..ac116c60af 100644 --- a/common/src/comp/inventory/item/item_key.rs +++ b/common/src/comp/inventory/item/item_key.rs @@ -5,6 +5,7 @@ use crate::{ use serde::{Deserialize, Serialize}; use std::sync::Arc; +/// ItemKey should only be used for front-end identification purposes #[derive(Clone, Debug, Serialize, Deserialize, Hash, Eq, PartialEq)] pub enum ItemKey { Simple(String), diff --git a/common/src/comp/inventory/item/mod.rs b/common/src/comp/inventory/item/mod.rs index 2e2e170baf..0ece16619d 100644 --- a/common/src/comp/inventory/item/mod.rs +++ b/common/src/comp/inventory/item/mod.rs @@ -366,6 +366,9 @@ pub enum ItemKind { /// through item_ids: Vec, }, + RecipeGroup { + recipes: Vec, + }, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -374,6 +377,7 @@ pub enum ConsumableKind { Food, ComplexFood, Charm, + Recipe, } impl ItemKind { @@ -404,6 +408,7 @@ impl ItemKind { #[allow(deprecated)] ItemKind::Ingredient { descriptor } => format!("Ingredient: {}", descriptor), ItemKind::TagExamples { item_ids } => format!("TagExamples: {:?}", item_ids), + ItemKind::RecipeGroup { .. } => String::from("Recipes:"), } } @@ -418,7 +423,8 @@ impl ItemKind { | ItemKind::Throwable { .. } | ItemKind::Utility { .. } | ItemKind::Ingredient { .. } - | ItemKind::TagExamples { .. } => false, + | ItemKind::TagExamples { .. } + | ItemKind::RecipeGroup { .. } => false, } } } @@ -582,10 +588,7 @@ impl Serialize for ItemBase { where S: Serializer, { - serializer.serialize_str(match self { - ItemBase::Simple(item_def) => &item_def.item_definition_id, - ItemBase::Modular(mod_base) => mod_base.pseudo_item_id(), - }) + serializer.serialize_str(&self.serialization_item_id()) } } @@ -609,13 +612,7 @@ impl<'de> Deserialize<'de> for ItemBase { where E: de::Error, { - Ok( - if serialized_item_base.starts_with(crate::modular_item_id_prefix!()) { - ItemBase::Modular(ModularBase::load_from_pseudo_id(serialized_item_base)) - } else { - ItemBase::Simple(Arc::::load_expect_cloned(serialized_item_base)) - }, - ) + Ok(ItemBase::from_item_id_string(serialized_item_base)) } } @@ -630,6 +627,23 @@ impl ItemBase { ItemBase::Modular(_) => 0, } } + + // Should be kept the same as the persistence_item_id function in Item + // TODO: Maybe use Cow? + fn serialization_item_id(&self) -> String { + match &self { + ItemBase::Simple(item_def) => item_def.item_definition_id.clone(), + ItemBase::Modular(mod_base) => String::from(mod_base.pseudo_item_id()), + } + } + + fn from_item_id_string(item_id_string: &str) -> Self { + if item_id_string.starts_with(crate::modular_item_id_prefix!()) { + ItemBase::Modular(ModularBase::load_from_pseudo_id(item_id_string)) + } else { + ItemBase::Simple(Arc::::load_expect_cloned(item_id_string)) + } + } } // TODO: could this theorectically hold a ref to the actual components and @@ -637,7 +651,7 @@ impl ItemBase { // `Vec`s) #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ItemDefinitionId<'a> { - Simple(&'a str), + Simple(Cow<'a, str>), Modular { pseudo_base: &'a str, components: Vec>, @@ -664,7 +678,7 @@ pub enum ItemDefinitionIdOwned { impl ItemDefinitionIdOwned { pub fn as_ref(&self) -> ItemDefinitionId<'_> { match *self { - Self::Simple(ref id) => ItemDefinitionId::Simple(id), + Self::Simple(ref id) => ItemDefinitionId::Simple(Cow::Borrowed(id)), Self::Modular { ref pseudo_base, ref components, @@ -694,7 +708,7 @@ impl<'a> ItemDefinitionId<'a> { pub fn to_owned(&self) -> ItemDefinitionIdOwned { match self { - Self::Simple(id) => ItemDefinitionIdOwned::Simple(String::from(*id)), + Self::Simple(id) => ItemDefinitionIdOwned::Simple(String::from(&**id)), Self::Modular { pseudo_base, components, @@ -969,7 +983,7 @@ impl Item { ) -> Result { let (base, components) = match item_definition_id { ItemDefinitionId::Simple(spec) => { - let base = ItemBase::Simple(Arc::::load_cloned(spec)?); + let base = ItemBase::Simple(Arc::::load_cloned(&spec)?); (base, Vec::new()) }, ItemDefinitionId::Modular { @@ -1023,11 +1037,7 @@ impl Item { /// Creates a new instance of an `Item from the provided asset identifier if /// it exists pub fn new_from_asset(asset: &str) -> Result { - let inner_item = if asset.starts_with("veloren.core.pseudo_items.modular") { - ItemBase::Modular(ModularBase::load_from_pseudo_id(asset)) - } else { - ItemBase::Simple(Arc::::load_cloned(asset)?) - }; + let inner_item = ItemBase::from_item_id_string(asset); // TODO: Get msm and ability_map less hackily let msm = &MaterialStatManifest::load().read(); let ability_map = &AbilityMap::load().read(); @@ -1206,7 +1216,7 @@ impl Item { match &self.item_base { ItemBase::Simple(item_def) => { if self.components.is_empty() { - ItemDefinitionId::Simple(&item_def.item_definition_id) + ItemDefinitionId::Simple(Cow::Borrowed(&item_def.item_definition_id)) } else { ItemDefinitionId::Compound { simple_base: &item_def.item_definition_id, @@ -1388,10 +1398,10 @@ impl Item { pub fn item_hash(&self) -> u64 { self.hash } - pub fn persistence_item_id(&self) -> &str { + pub fn persistence_item_id(&self) -> String { match &self.item_base { - ItemBase::Simple(item_def) => &item_def.item_definition_id, - ItemBase::Modular(mod_base) => mod_base.pseudo_item_id(), + ItemBase::Simple(item_def) => item_def.item_definition_id.clone(), + ItemBase::Modular(mod_base) => String::from(mod_base.pseudo_item_id()), } } @@ -1545,6 +1555,10 @@ impl Item { Err(other) } } + + // Probably doesn't need to be limited to persistence, but nothing else should + // really need to look at item base + pub fn persistence_item_base(&self) -> &ItemBase { &self.item_base } } impl FrontendItem { @@ -1816,7 +1830,7 @@ impl ItemDesc for ItemDef { fn num_slots(&self) -> u16 { self.slots } fn item_definition_id(&self) -> ItemDefinitionId<'_> { - ItemDefinitionId::Simple(&self.item_definition_id) + ItemDefinitionId::Simple(Cow::Borrowed(&self.item_definition_id)) } fn tags(&self) -> Vec { self.tags.to_vec() } diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index f9984d4763..5c5d8996ec 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -15,13 +15,16 @@ use crate::{ MaterialStatManifest, TagExampleInfo, }, loadout::Loadout, + recipe_book::RecipeBook, slot::{EquipSlot, Slot, SlotError}, }, loot_owner::LootOwnerKind, slot::{InvSlotId, SlotId}, Item, }, + recipe::{Recipe, RecipeBookManifest}, resources::Time, + terrain::SpriteKind, uid::Uid, LoadoutBuilder, }; @@ -31,6 +34,7 @@ use super::FrontendItem; pub mod item; pub mod loadout; pub mod loadout_builder; +pub mod recipe_book; pub mod slot; #[cfg(test)] mod test; #[cfg(test)] mod test_helpers; @@ -52,6 +56,8 @@ pub struct Inventory { /// These slots are "remove-only" meaning that during normal gameplay items /// can only be removed from these slots and never entered. overflow_items: Vec, + /// Recipes that are available for use + recipe_book: RecipeBook, } /// Errors which the methods on `Inventory` produce @@ -131,6 +137,7 @@ impl Inventory { loadout, slots: vec![None; DEFAULT_INVENTORY_SLOTS], overflow_items: Vec::new(), + recipe_book: RecipeBook::default(), } } @@ -140,10 +147,16 @@ impl Inventory { loadout, slots: vec![None; 1], overflow_items: Vec::new(), + recipe_book: RecipeBook::default(), } } - /// Total number of slots in the inventory. + pub fn with_recipe_book(mut self, recipe_book: RecipeBook) -> Inventory { + self.recipe_book = recipe_book; + self + } + + /// Total number of slots in in the inventory. pub fn capacity(&self) -> usize { self.slots().count() } /// An iterator of all inventory slots @@ -1085,6 +1098,57 @@ impl Inventory { pub fn persistence_push_overflow_items>(&mut self, overflow_items: I) { self.overflow_items.extend(overflow_items); } + + pub fn recipes_iter(&self) -> impl ExactSizeIterator { self.recipe_book.iter() } + + pub fn available_recipes_iter<'a>( + &'a self, + rbm: &'a RecipeBookManifest, + ) -> impl Iterator + '_ { + self.recipe_book.get_available_iter(rbm) + } + + pub fn recipe_book_len(&self) -> usize { self.recipe_book.len() } + + pub fn get_recipe<'a>( + &'a self, + recipe_key: &str, + rbm: &'a RecipeBookManifest, + ) -> Option<&Recipe> { + self.recipe_book.get(recipe_key, rbm) + } + + pub fn push_recipe_group(&mut self, recipe_group: Item) -> Result<(), Item> { + self.recipe_book.push_group(recipe_group) + } + + /// Returns whether the specified recipe can be crafted and the sprite, if + /// any, that is required to do so. + pub fn can_craft_recipe( + &self, + recipe_key: &str, + amount: u32, + rbm: &RecipeBookManifest, + ) -> (bool, Option) { + if let Some(recipe) = self.recipe_book.get(recipe_key, rbm) { + ( + recipe.inventory_contains_ingredients(self, amount).is_ok(), + recipe.craft_sprite, + ) + } else { + (false, None) + } + } + + pub fn recipe_is_known(&self, recipe_key: &str) -> bool { + self.recipe_book.is_known(recipe_key) + } + + pub fn reset_recipes(&mut self) { self.recipe_book.reset(); } + + pub fn persistence_recipes_iter_with_index(&self) -> impl Iterator { + self.recipe_book.persistence_recipes_iter_with_index() + } } impl Component for Inventory { diff --git a/common/src/comp/inventory/recipe_book.rs b/common/src/comp/inventory/recipe_book.rs new file mode 100644 index 0000000000..38b72a6a90 --- /dev/null +++ b/common/src/comp/inventory/recipe_book.rs @@ -0,0 +1,116 @@ +use crate::{ + comp::item::{Item, ItemKind}, + recipe::{Recipe, RecipeBookManifest}, +}; +use hashbrown::HashSet; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct RecipeBook { + recipe_groups: Vec, + recipes: HashSet, +} + +impl RecipeBook { + pub(super) fn get<'a>( + &'a self, + recipe_key: &str, + rbm: &'a RecipeBookManifest, + ) -> Option<&Recipe> { + if self.recipes.iter().any(|r| r == recipe_key) { + rbm.get(recipe_key) + } else { + None + } + } + + pub(super) fn len(&self) -> usize { self.recipes.len() } + + pub(super) fn iter(&self) -> impl ExactSizeIterator { self.recipes.iter() } + + pub(super) fn get_available_iter<'a>( + &'a self, + rbm: &'a RecipeBookManifest, + ) -> impl Iterator + '_ { + self.recipes + .iter() + .filter_map(|recipe: &String| rbm.get(recipe).map(|rbm_recipe| (recipe, rbm_recipe))) + } + + pub(super) fn reset(&mut self) { + self.recipe_groups.clear(); + self.recipes.clear(); + } + + /// Pushes a group of recipes to the recipe book. If group already exists + /// return the recipe group. + pub(super) fn push_group(&mut self, group: Item) -> Result<(), Item> { + if self + .recipe_groups + .iter() + .any(|rg| rg.item_definition_id() == group.item_definition_id()) + { + Err(group) + } else { + self.recipe_groups.push(group); + self.update(); + Ok(()) + } + } + + /// Syncs recipes hashset with recipe_groups vec + pub(super) fn update(&mut self) { + self.recipe_groups.iter().for_each(|group| { + if let ItemKind::RecipeGroup { recipes } = &*group.kind() { + self.recipes.extend(recipes.iter().map(String::from)) + } + }) + } + + pub fn recipe_book_from_persistence(recipe_groups: Vec) -> Self { + let mut book = Self { + recipe_groups, + recipes: HashSet::new(), + }; + book.update(); + book + } + + pub fn persistence_recipes_iter_with_index(&self) -> impl Iterator { + self.recipe_groups.iter().enumerate() + } + + pub(super) fn is_known(&self, recipe_key: &str) -> bool { self.recipes.contains(recipe_key) } +} + +#[cfg(test)] +mod tests { + use crate::{ + comp::item::{Item, ItemKind}, + recipe::{complete_recipe_book, default_component_recipe_book}, + }; + + fn valid_recipe(recipe: &str) -> bool { + let recipe_book = complete_recipe_book(); + let component_recipe_book = default_component_recipe_book(); + + recipe_book.read().keys().any(|key| key == recipe) + || component_recipe_book + .read() + .iter() + .any(|(_, cr)| cr.recipe_book_key == recipe) + } + + /// Verify that all recipes in recipe items point to a valid recipe + #[test] + fn validate_recipes() { + let groups = Item::new_from_asset_glob("common.items.recipes.*") + .expect("The directory should exist"); + for group in groups { + let ItemKind::RecipeGroup { recipes } = &*group.kind() else { + panic!("Expected item to be of kind RecipeGroup") + }; + assert!(recipes.iter().all(|r| valid_recipe(r))); + } + } +} diff --git a/common/src/comp/inventory/test.rs b/common/src/comp/inventory/test.rs index 268ea14c84..fcfd1b7e2d 100644 --- a/common/src/comp/inventory/test.rs +++ b/common/src/comp/inventory/test.rs @@ -5,6 +5,7 @@ use crate::comp::{ Item, }; use lazy_static::lazy_static; +use std::borrow::Cow; lazy_static! { static ref TEST_ITEMS: Vec = vec![Item::new_from_asset_expect( "common.items.debug.admin_stick" @@ -24,6 +25,7 @@ fn push_full() { .collect(), loadout: LoadoutBuilder::empty().build(), overflow_items: vec![], + recipe_book: RecipeBook::default(), }; assert_eq!( inv.push(TEST_ITEMS[0].duplicate(ability_map, msm)) @@ -45,6 +47,7 @@ fn push_all_full() { .collect(), loadout: LoadoutBuilder::empty().build(), overflow_items: vec![], + recipe_book: RecipeBook::default(), }; let Error::Full(leftovers) = inv .push_all( @@ -76,6 +79,7 @@ fn push_unique_all_full() { .collect(), loadout: LoadoutBuilder::empty().build(), overflow_items: vec![], + recipe_book: RecipeBook::default(), }; inv.push_all_unique( TEST_ITEMS @@ -96,6 +100,7 @@ fn push_all_empty() { slots: vec![None, None], loadout: LoadoutBuilder::empty().build(), overflow_items: vec![], + recipe_book: RecipeBook::default(), }; inv.push_all( TEST_ITEMS @@ -116,6 +121,7 @@ fn push_all_unique_empty() { slots: vec![None, None], loadout: LoadoutBuilder::empty().build(), overflow_items: vec![], + recipe_book: RecipeBook::default(), }; inv.push_all_unique( TEST_ITEMS @@ -339,7 +345,7 @@ fn equip_equipping_smaller_bag_from_last_slot_of_big_bag() { assert_eq!( inv.get(InvSlotId::new(0, 0)).unwrap().item_definition_id(), - ItemDefinitionId::Simple(LARGE_BAG_ID) + ItemDefinitionId::Simple(Cow::Borrowed(LARGE_BAG_ID)) ); assert!(result.is_empty()); } @@ -369,7 +375,7 @@ fn unequip_unequipping_bag_into_its_own_slot_with_no_other_free_slots_returns_on // by itself, the bag is returned to the caller assert_eq!( result[0].item_definition_id(), - ItemDefinitionId::Simple("common.items.testing.test_bag") + ItemDefinitionId::Simple(Cow::Borrowed("common.items.testing.test_bag")) ); } @@ -517,7 +523,7 @@ fn backpack_crash() { ); assert_eq!(18, returned_items.len()); assert_eq!( - ItemDefinitionId::Simple("common.items.armor.misc.back.backpack"), + ItemDefinitionId::Simple(Cow::Borrowed("common.items.armor.misc.back.backpack")), returned_items[0].item_definition_id() ); } diff --git a/common/src/comp/inventory/trade_pricing.rs b/common/src/comp/inventory/trade_pricing.rs index f7089c805c..e219da3f5d 100644 --- a/common/src/comp/inventory/trade_pricing.rs +++ b/common/src/comp/inventory/trade_pricing.rs @@ -9,7 +9,7 @@ use crate::{ tool::AbilityMap, }, lottery::LootSpec, - recipe::{default_component_recipe_book, default_recipe_book, RecipeInput}, + recipe::{complete_recipe_book, default_component_recipe_book, RecipeInput}, trade::Good, }; use assets::AssetReadGuard; @@ -294,7 +294,7 @@ lazy_static! { // Load recipe book (done to check that material is valid for a particular component) //use crate::recipe::ComponentKey; - let recipes = default_recipe_book().read(); + let recipes = complete_recipe_book().read(); recipes .iter() @@ -463,8 +463,9 @@ impl From)>> for ProbabilityFile { #[derive(Debug, Deserialize)] struct TradingPriceFile { + /// Tuple format: (frequency, can_sell, asset_path) pub loot_tables: Vec<(f32, bool, String)>, - // the amount of Good equivalent to the most common item + /// the amount of Good equivalent to the most common item pub good_scaling: Vec<(Good, f32)>, } @@ -628,17 +629,16 @@ impl TradePricing { ItemDefinitionIdOwned::Simple(name) if name.starts_with("common.items.flowers.") => { Good::Ingredients }, - ItemDefinitionIdOwned::Simple(name) if name.starts_with("common.items.consumable.") => { Good::Potions }, - ItemDefinitionIdOwned::Simple(name) if name.starts_with("common.items.food.") => { Good::Food }, - ItemDefinitionIdOwned::Simple(name) if name.as_str() == Self::COIN_ITEM => Good::Coin, - + ItemDefinitionIdOwned::Simple(name) if name.starts_with("common.items.recipes.") => { + Good::Recipe + }, ItemDefinitionIdOwned::Simple(name) if name.starts_with("common.items.glider.") => { Good::default() }, @@ -809,7 +809,7 @@ impl TradePricing { // Apply recipe book let mut secondaries: HashMap> = HashMap::new(); - let book = default_recipe_book().read(); + let book = complete_recipe_book().read(); let mut ordered_recipes: Vec = Vec::new(); for (_, recipe) in book.iter() { let (ref asset_path, amount) = recipe.output; diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 492d80c216..0a232f425d 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -80,6 +80,7 @@ pub use self::{ tool::{self, AbilityItem}, FrontendItem, Item, ItemConfig, ItemDrops, PickupItem, }, + recipe_book::RecipeBook, slot, CollectFailedReason, Inventory, InventoryUpdate, InventoryUpdateEvent, }, last::Last, diff --git a/common/src/recipe.rs b/common/src/recipe.rs index bb71fb5fa5..1877af0a13 100644 --- a/common/src/recipe.rs +++ b/common/src/recipe.rs @@ -428,15 +428,19 @@ pub fn modular_weapon( } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct RecipeBook { +pub struct RecipeBookManifest { recipes: HashMap, } -impl RecipeBook { +impl RecipeBookManifest { + pub fn load() -> AssetHandle { Self::load_expect("common.recipe_book_manifest") } + pub fn get(&self, recipe: &str) -> Option<&Recipe> { self.recipes.get(recipe) } pub fn iter(&self) -> impl ExactSizeIterator { self.recipes.iter() } + pub fn keys(&self) -> impl ExactSizeIterator { self.recipes.keys() } + pub fn get_available(&self, inv: &Inventory) -> Vec<(String, Recipe)> { self.recipes .iter() @@ -451,8 +455,8 @@ mod tests { use super::*; #[test] - fn default_recipe_valid_key_check() { - let recipe_book = default_recipe_book().read(); + fn complete_recipe_book_valid_key_check() { + let recipe_book = complete_recipe_book().read(); let is_invalid_key = |input: &str| input.chars().any(|c| c.is_uppercase() || c.is_whitespace()); assert!(!recipe_book.iter().any(|(k, _)| is_invalid_key(k))); @@ -517,7 +521,7 @@ impl assets::Asset for ItemList { const EXTENSION: &'static str = "ron"; } -impl assets::Compound for RecipeBook { +impl assets::Compound for RecipeBookManifest { fn load( cache: assets::AnyCache, specifier: &assets::SharedString, @@ -562,7 +566,7 @@ impl assets::Compound for RecipeBook { ) .collect::>()?; - Ok(RecipeBook { recipes }) + Ok(RecipeBookManifest { recipes }) } } @@ -617,6 +621,7 @@ pub struct ComponentKey { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ComponentRecipe { + pub recipe_book_key: String, output: ComponentOutput, material: (RecipeInput, u32), modifier: Option<(RecipeInput, u32)>, @@ -810,6 +815,7 @@ impl<'a> ExactSizeIterator for ComponentRecipeInputsIterator<'a> { #[derive(Clone, Deserialize)] struct RawComponentRecipe { + recipe_book_key: String, output: RawComponentOutput, /// String refers to an item definition id material: (String, u32), @@ -881,7 +887,9 @@ impl assets::Compound for ComponentRecipeBook { .iter() .map(|(input, amount)| input.load_recipe_input().map(|input| (input, *amount))) .collect::, _>>()?; + let recipe_book_key = String::from(&raw_recipe.recipe_book_key); Ok(ComponentRecipe { + recipe_book_key, output, material, modifier, @@ -1112,8 +1120,8 @@ impl assets::Compound for RepairRecipeBook { } } -pub fn default_recipe_book() -> AssetHandle { - RecipeBook::load_expect("common.recipe_book") +pub fn complete_recipe_book() -> AssetHandle { + RecipeBookManifest::load_expect("common.recipe_book_manifest") } pub fn default_component_recipe_book() -> AssetHandle { diff --git a/common/src/states/use_item.rs b/common/src/states/use_item.rs index ac32afde4f..0d851f2e19 100644 --- a/common/src/states/use_item.rs +++ b/common/src/states/use_item.rs @@ -53,7 +53,9 @@ impl CharacterBehavior for Data { let mut update = StateUpdate::from(data); match self.static_data.item_kind { - ItemUseKind::Consumable(ConsumableKind::Drink | ConsumableKind::Charm) => { + ItemUseKind::Consumable( + ConsumableKind::Drink | ConsumableKind::Charm | ConsumableKind::Recipe, + ) => { handle_orientation(data, &mut update, 1.0, None); handle_move(data, &mut update, 1.0); }, @@ -64,9 +66,9 @@ impl CharacterBehavior for Data { } let use_point = match self.static_data.item_kind { - ItemUseKind::Consumable(ConsumableKind::Drink | ConsumableKind::Food) => { - UsePoint::BuildupUse - }, + ItemUseKind::Consumable( + ConsumableKind::Drink | ConsumableKind::Food | ConsumableKind::Recipe, + ) => UsePoint::BuildupUse, ItemUseKind::Consumable(ConsumableKind::ComplexFood | ConsumableKind::Charm) => { UsePoint::UseRecover }, @@ -198,6 +200,11 @@ impl ItemUseKind { Duration::from_secs_f32(0.8), Duration::from_secs_f32(0.1), ), + Self::Consumable(ConsumableKind::Recipe) => ( + Duration::from_secs_f32(0.0), + Duration::from_secs_f32(0.0), + Duration::from_secs_f32(0.0), + ), } } } diff --git a/common/src/terrain/sprite.rs b/common/src/terrain/sprite.rs index 56ea20e17e..7d2db98ba1 100644 --- a/common/src/terrain/sprite.rs +++ b/common/src/terrain/sprite.rs @@ -39,10 +39,7 @@ pub use self::magic::{Attribute, AttributeError}; use crate::{ attributes, - comp::{ - item::{ItemDefinitionId, ItemDefinitionIdOwned}, - tool::ToolKind, - }, + comp::{item::ItemDefinitionIdOwned, tool::ToolKind}, lottery::LootSpec, make_case_elim, sprites, terrain::Block, @@ -805,27 +802,32 @@ impl SpriteKind { pub fn unlock_condition(&self, cfg: Option) -> UnlockKind { cfg.and_then(|cfg| cfg.unlock) .unwrap_or_else(|| match self { - // Example, do not let this merge with twigs requiring cheese to pick up SpriteKind::CommonLockedChest => UnlockKind::Consumes( - ItemDefinitionId::Simple("common.items.utility.lockpick_0").to_owned(), - ), - SpriteKind::BoneKeyhole => UnlockKind::Consumes( - ItemDefinitionId::Simple("common.items.keys.bone_key").to_owned(), - ), - SpriteKind::HaniwaKeyhole => UnlockKind::Consumes( - ItemDefinitionId::Simple("common.items.keys.haniwa_key").to_owned(), - ), - SpriteKind::GlassKeyhole => UnlockKind::Consumes( - ItemDefinitionId::Simple("common.items.keys.glass_key").to_owned(), - ), - SpriteKind::SahaginKeyhole => UnlockKind::Consumes( - ItemDefinitionId::Simple("common.items.keys.sahagin_key").to_owned(), + ItemDefinitionIdOwned::Simple(String::from("common.items.utility.lockpick_0")), ), + SpriteKind::SahaginKeyhole => UnlockKind::Consumes(ItemDefinitionIdOwned::Simple( + String::from("common.items.keys.sahagin_key"), + )), + SpriteKind::BoneKeyhole => UnlockKind::Consumes(ItemDefinitionIdOwned::Simple( + String::from("common.items.keys.bone_key"), + )), + SpriteKind::HaniwaKeyhole => UnlockKind::Consumes(ItemDefinitionIdOwned::Simple( + String::from("common.items.keys.haniwa_key"), + )), + SpriteKind::GlassKeyhole => UnlockKind::Consumes(ItemDefinitionIdOwned::Simple( + String::from("common.items.keys.glass_key"), + )), SpriteKind::TerracottaChest => UnlockKind::Consumes( - ItemDefinitionId::Simple("common.items.keys.terracotta_key_chest").to_owned(), + ItemDefinitionIdOwned::Simple(String::from( + "common.items.keys.terracotta_key_chest", + )) + .to_owned(), ), SpriteKind::TerracottaKeyhole => UnlockKind::Consumes( - ItemDefinitionId::Simple("common.items.keys.terracotta_key_door").to_owned(), + ItemDefinitionIdOwned::Simple(String::from( + "common.items.keys.terracotta_key_door", + )) + .to_owned(), ), _ => UnlockKind::Free, }) @@ -865,11 +867,9 @@ pub enum UnlockKind { Free, /// The sprite requires that the opening character has a given item in their /// inventory - // TODO: use ItemKey here? Requires(ItemDefinitionIdOwned), /// The sprite will consume the given item from the opening character's /// inventory - // TODO: use ItemKey here? Consumes(ItemDefinitionIdOwned), } diff --git a/common/src/trade.rs b/common/src/trade.rs index 3b3ca0f7eb..9c4d9afa5c 100644 --- a/common/src/trade.rs +++ b/common/src/trade.rs @@ -337,6 +337,7 @@ pub enum Good { Potions, Coin, // exchange material across sites RoadSecurity, + Recipe, } impl Default for Good { @@ -351,7 +352,7 @@ impl Good { match self { Good::Tools | Good::Armor => 0.5, Good::Food | Good::Potions | Good::Ingredients => 0.75, - Good::Coin => 1.0, + Good::Coin | Good::Recipe => 1.0, // Certain abstract goods (like Territory) shouldn't be attached to concrete items; // give a sale price of 0 if the player is trying to sell a concrete item that somehow // has one of these categories diff --git a/server/src/character_creator.rs b/server/src/character_creator.rs index 2d24d1ae4f..0a784957ea 100644 --- a/server/src/character_creator.rs +++ b/server/src/character_creator.rs @@ -55,6 +55,7 @@ pub fn create_character( .active_offhand(character_offhand.map(|x| Item::new_from_asset_expect(&x))) .build(); let mut inventory = Inventory::with_loadout_humanoid(loadout); + let stats = Stats::new(character_alias.to_string(), body); let skill_set = SkillSet::default(); // Default items for new characters @@ -66,6 +67,9 @@ pub fn create_character( inventory .push(Item::new_from_asset_expect("common.items.food.cheese")) .expect("Inventory has at least 1 slot left!"); + inventory + .push_recipe_group(Item::new_from_asset_expect("common.items.recipes.default")) + .expect("New inventory should not already have default recipe group."); let map_marker = None; diff --git a/server/src/client.rs b/server/src/client.rs index 6df53d894e..436426fba4 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -193,7 +193,8 @@ impl Client { | ServerGeneral::MapMarker(_) | ServerGeneral::WeatherUpdate(_) | ServerGeneral::LocalWindUpdate(_) - | ServerGeneral::SpectatePosition(_) => { + | ServerGeneral::SpectatePosition(_) + | ServerGeneral::UpdateRecipes => { PreparedMsg::new(2, &g, &self.in_game_stream_params) }, // Terrain diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 00b5fc16cc..5850f34a87 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -184,6 +184,7 @@ fn do_command( ServerChatCommand::PermitBuild => handle_permit_build, ServerChatCommand::Players => handle_players, ServerChatCommand::Portal => handle_spawn_portal, + ServerChatCommand::ResetRecipes => handle_reset_recipes, ServerChatCommand::Region => handle_region, ServerChatCommand::ReloadChunks => handle_reload_chunks, ServerChatCommand::RemoveLights => handle_remove_lights, @@ -3364,6 +3365,27 @@ fn handle_group_promote( } } +fn handle_reset_recipes( + server: &mut Server, + _client: EcsEntity, + target: EcsEntity, + _args: Vec, + action: &ServerChatCommand, +) -> CmdResult<()> { + if let Some(mut inventory) = server + .state + .ecs() + .write_storage::() + .get_mut(target) + { + inventory.reset_recipes(); + server.notify_client(target, ServerGeneral::UpdateRecipes); + Ok(()) + } else { + Err(Content::Plain(action.help_string())) + } +} + fn handle_region( server: &mut Server, client: EcsEntity, diff --git a/server/src/events/inventory_manip.rs b/server/src/events/inventory_manip.rs index 36bf473dd2..0e2a5d2788 100644 --- a/server/src/events/inventory_manip.rs +++ b/server/src/events/inventory_manip.rs @@ -23,9 +23,7 @@ use common::{ }, event_emitters, mounting::VolumePos, - recipe::{ - self, default_component_recipe_book, default_recipe_book, default_repair_recipe_book, - }, + recipe::{self, default_component_recipe_book, default_repair_recipe_book, RecipeBookManifest}, resources::{ProgramTime, Time}, terrain::{Block, SpriteKind}, trade::Trades, @@ -85,6 +83,7 @@ pub struct InventoryManipData<'a> { program_time: ReadExpect<'a, ProgramTime>, ability_map: ReadExpect<'a, AbilityMap>, msm: ReadExpect<'a, MaterialStatManifest>, + rbm: ReadExpect<'a, RecipeBookManifest>, inventories: WriteStorage<'a, comp::Inventory>, items: WriteStorage<'a, comp::PickupItem>, inventory_updates: WriteStorage<'a, comp::InventoryUpdate>, @@ -610,6 +609,25 @@ impl ServerEvent for InventoryManipEvent { Some(InventoryUpdateEvent::Used) }, + ItemKind::RecipeGroup { .. } => { + match inventory.push_recipe_group(item) { + Ok(()) => { + if let Some(client) = data.clients.get(entity) { + client.send_fallible( + ServerGeneral::UpdateRecipes, + ); + } + Some(InventoryUpdateEvent::Used) + }, + Err(item) => { + inventory.insert_or_stack_at(slot, item).expect( + "slot was just vacated of item, so it \ + definitely fits there.", + ); + None + }, + } + }, _ => { inventory.insert_or_stack_at(slot, item).expect( "slot was just vacated of item, so it definitely fits \ @@ -861,7 +879,6 @@ impl ServerEvent for InventoryManipEvent { } => { use comp::controller::CraftEvent; use recipe::ComponentKey; - let recipe_book = default_recipe_book().read(); let get_craft_sprite = |sprite_pos: Option| { sprite_pos @@ -902,32 +919,38 @@ impl ServerEvent for InventoryManipEvent { recipe, slots, amount, - } => recipe_book - .get(&recipe) - .filter(|r| { - if let Some(needed_sprite) = r.craft_sprite { - let sprite = get_craft_sprite(craft_sprite); - Some(needed_sprite) == sprite - } else { - true - } - }) - .and_then(|r| { + } => { + let filtered_recipe = inventory + .get_recipe(&recipe, &data.rbm) + .cloned() + .filter(|r| { + if let Some(needed_sprite) = r.craft_sprite { + let sprite = get_craft_sprite(craft_sprite); + Some(needed_sprite) == sprite + } else { + true + } + }); + if let Some(recipe) = filtered_recipe { let items = (0..amount) .filter_map(|_| { - r.craft_simple( - &mut inventory, - slots.clone(), - &data.ability_map, - &data.msm, - ) - .ok() + recipe + .craft_simple( + &mut inventory, + slots.clone(), + &data.ability_map, + &data.msm, + ) + .ok() }) .flatten() .collect::>(); if items.is_empty() { None } else { Some(items) } - }), + } else { + None + } + }, CraftEvent::Salvage(slot) => { let sprite = get_craft_sprite(craft_sprite); if matches!(sprite, Some(SpriteKind::DismantlingBench)) { @@ -981,12 +1004,14 @@ impl ServerEvent for InventoryManipEvent { modifier: modifier.and_then(item_id), }) .filter(|r| { - if let Some(needed_sprite) = r.craft_sprite { + let sprite = if let Some(needed_sprite) = r.craft_sprite { let sprite = get_craft_sprite(craft_sprite); Some(needed_sprite) == sprite } else { true - } + }; + let known = inventory.recipe_is_known(&r.recipe_book_key); + sprite && known }) .and_then(|r| { r.craft_component( diff --git a/server/src/lib.rs b/server/src/lib.rs index 0788fe3c25..724b0c89f3 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -429,6 +429,9 @@ impl Server { let msm = comp::inventory::item::MaterialStatManifest::load().cloned(); state.ecs_mut().insert(msm); + let rbm = common::recipe::RecipeBookManifest::load().cloned(); + state.ecs_mut().insert(rbm); + state.ecs_mut().insert(CharacterLoader::new( Arc::>::clone(&database_settings), )?); diff --git a/server/src/migrations/V60__recipe_book.sql b/server/src/migrations/V60__recipe_book.sql new file mode 100644 index 0000000000..d34e9364e0 --- /dev/null +++ b/server/src/migrations/V60__recipe_book.sql @@ -0,0 +1,32 @@ +CREATE TEMP TABLE _temp_character_recipe_pairings +( + temp_recipe_book_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + character_id INT NOT NULL, + recipe_book_id INT +); + +INSERT +INTO _temp_character_recipe_pairings +SELECT NULL, + i.item_id, + NULL +FROM item i +WHERE i.item_definition_id = 'veloren.core.pseudo_containers.character'; + +UPDATE _temp_character_recipe_pairings +SET recipe_book_id = ((SELECT MAX(entity_id) FROM entity) + temp_recipe_book_id); + +INSERT +INTO entity +SELECT t.recipe_book_id +FROM _temp_character_recipe_pairings t; + +INSERT +INTO item +SELECT t.recipe_book_id, + t.character_id, + 'veloren.core.pseudo_containers.recipe_book', + 1, + 'recipe_book', + '' +FROM _temp_character_recipe_pairings t; \ No newline at end of file diff --git a/server/src/persistence/character.rs b/server/src/persistence/character.rs index 42ca7c6106..e38c3d5cfe 100644 --- a/server/src/persistence/character.rs +++ b/server/src/persistence/character.rs @@ -15,9 +15,9 @@ use crate::{ convert_body_from_database, convert_body_to_database_json, convert_character_from_database, convert_inventory_from_database_items, convert_items_to_database_items, convert_loadout_from_database_items, - convert_skill_groups_to_database, convert_skill_set_from_database, - convert_stats_from_database, convert_waypoint_from_database_json, - convert_waypoint_to_database_json, + convert_recipe_book_from_database_items, convert_skill_groups_to_database, + convert_skill_set_from_database, convert_stats_from_database, + convert_waypoint_from_database_json, convert_waypoint_to_database_json, }, character_loader::{CharacterCreationResult, CharacterDataResult, CharacterListResult}, character_updater::PetPersistenceData, @@ -48,9 +48,11 @@ const INVENTORY_PSEUDO_CONTAINER_DEF_ID: &str = "veloren.core.pseudo_containers. const LOADOUT_PSEUDO_CONTAINER_DEF_ID: &str = "veloren.core.pseudo_containers.loadout"; const OVERFLOW_ITEMS_PSEUDO_CONTAINER_DEF_ID: &str = "veloren.core.pseudo_containers.overflow_items"; +const RECIPE_BOOK_PSEUDO_CONTAINER_DEF_ID: &str = "veloren.core.pseudo_containers.recipe_book"; const INVENTORY_PSEUDO_CONTAINER_POSITION: &str = "inventory"; const LOADOUT_PSEUDO_CONTAINER_POSITION: &str = "loadout"; const OVERFLOW_ITEMS_PSEUDO_CONTAINER_POSITION: &str = "overflow_items"; +const RECIPE_BOOK_PSEUDO_CONTAINER_POSITION: &str = "recipe_book"; const WORLD_PSEUDO_CONTAINER_ID: EntityId = 1; #[derive(Clone, Copy)] @@ -58,6 +60,7 @@ struct CharacterContainers { inventory_container_id: EntityId, loadout_container_id: EntityId, overflow_items_container_id: EntityId, + recipe_book_container_id: EntityId, } /// Load the inventory/loadout @@ -132,6 +135,7 @@ pub fn load_character_data( let loadout_items = load_items(connection, character_containers.loadout_container_id)?; let overflow_items_items = load_items(connection, character_containers.overflow_items_container_id)?; + let recipe_book_items = load_items(connection, character_containers.recipe_book_container_id)?; let mut stmt = connection.prepare_cached( " @@ -284,6 +288,7 @@ pub fn load_character_data( &loadout_items, character_containers.overflow_items_container_id, &overflow_items_items, + &recipe_book_items, )?, waypoint: char_waypoint, pets, @@ -362,10 +367,21 @@ pub fn load_character_list(player_uuid_: &str, connection: &Connection) -> Chara let loadout = convert_loadout_from_database_items(loadout_container_id, &loadout_items)?; + let recipe_book_container_id = get_pseudo_container_id( + connection, + CharacterId(character_data.character_id), + RECIPE_BOOK_PSEUDO_CONTAINER_POSITION, + )?; + + let recipe_book_items = load_items(connection, recipe_book_container_id)?; + + let recipe_book = convert_recipe_book_from_database_items(&recipe_book_items)?; + Ok(CharacterItem { character: char, body: char_body, - inventory: Inventory::with_loadout(loadout, char_body), + inventory: Inventory::with_loadout(loadout, char_body) + .with_recipe_book(recipe_book), location: character_data.waypoint.as_ref().cloned(), }) }) @@ -391,14 +407,16 @@ pub fn create_character( map_marker, } = persisted_components; - // Fetch new entity IDs for character, inventory, loadout, and overflow items - let mut new_entity_ids = get_new_entity_ids(transaction, |next_id| next_id + 4)?; + // Fetch new entity IDs for character, inventory, loadout, overflow items, and + // recipe book + let mut new_entity_ids = get_new_entity_ids(transaction, |next_id| next_id + 5)?; // Create pseudo-container items for character let character_id = new_entity_ids.next().unwrap(); let inventory_container_id = new_entity_ids.next().unwrap(); let loadout_container_id = new_entity_ids.next().unwrap(); let overflow_items_container_id = new_entity_ids.next().unwrap(); + let recipe_book_container_id = new_entity_ids.next().unwrap(); let pseudo_containers = vec![ Item { @@ -433,6 +451,14 @@ pub fn create_character( position: OVERFLOW_ITEMS_PSEUDO_CONTAINER_POSITION.to_owned(), properties: String::new(), }, + Item { + stack_size: 1, + item_id: recipe_book_container_id, + parent_container_item_id: character_id, + item_definition_id: RECIPE_BOOK_PSEUDO_CONTAINER_DEF_ID.to_owned(), + position: RECIPE_BOOK_PSEUDO_CONTAINER_POSITION.to_owned(), + properties: String::new(), + }, ]; let mut stmt = transaction.prepare_cached( @@ -542,6 +568,7 @@ pub fn create_character( &inventory, inventory_container_id, overflow_items_container_id, + recipe_book_container_id, &mut next_id, ); inserts = inserts_; @@ -830,6 +857,11 @@ fn get_pseudo_containers( character_id, OVERFLOW_ITEMS_PSEUDO_CONTAINER_POSITION, )?, + recipe_book_container_id: get_pseudo_container_id( + connection, + character_id, + RECIPE_BOOK_PSEUDO_CONTAINER_POSITION, + )?, }; Ok(character_containers) @@ -1025,6 +1057,7 @@ pub fn update( &inventory, pseudo_containers.inventory_container_id, pseudo_containers.overflow_items_container_id, + pseudo_containers.recipe_book_container_id, &mut next_id, ); upserts = upserts_; @@ -1037,6 +1070,7 @@ pub fn update( Value::from(pseudo_containers.inventory_container_id), Value::from(pseudo_containers.loadout_container_id), Value::from(pseudo_containers.overflow_items_container_id), + Value::from(pseudo_containers.recipe_book_container_id), ]; for it in load_items(transaction, pseudo_containers.inventory_container_id)? { existing_item_ids.push(Value::from(it.item_id)); @@ -1047,6 +1081,9 @@ pub fn update( for it in load_items(transaction, pseudo_containers.overflow_items_container_id)? { existing_item_ids.push(Value::from(it.item_id)); } + for it in load_items(transaction, pseudo_containers.recipe_book_container_id)? { + existing_item_ids.push(Value::from(it.item_id)); + } let non_upserted_items = upserts .iter() diff --git a/server/src/persistence/character/conversions.rs b/server/src/persistence/character/conversions.rs index e4b4c7acaf..cd78197be3 100644 --- a/server/src/persistence/character/conversions.rs +++ b/server/src/persistence/character/conversions.rs @@ -1,25 +1,26 @@ use crate::persistence::{ character::EntityId, - models::{AbilitySets, Character, Item, SkillGroup}, -}; - -use crate::persistence::{ error::PersistenceError, json_models::{ self, CharacterPosition, DatabaseAbilitySet, DatabaseItemProperties, GenericBody, HumanoidBody, }, + models::{AbilitySets, Character, Item, SkillGroup}, }; use common::{ character::CharacterId, comp::{ + body, inventory::{ item::{tool::AbilityMap, Item as VelorenItem, MaterialStatManifest}, loadout::{Loadout, LoadoutError}, loadout_builder::LoadoutBuilder, + recipe_book::RecipeBook, slot::InvSlotId, }, - skillset, Body as CompBody, Waypoint, *, + item, + skillset::{self, skills::Skill, SkillGroupKind, SkillSet}, + ActiveAbilities, Body as CompBody, Inventory, MapMarker, Stats, Waypoint, }, resources::Time, }; @@ -57,6 +58,7 @@ pub fn convert_items_to_database_items( inventory: &Inventory, inventory_container_id: EntityId, overflow_items_container_id: EntityId, + recipe_book_container_id: EntityId, next_id: &mut i64, ) -> Vec { let loadout = inventory @@ -71,6 +73,16 @@ pub fn convert_items_to_database_items( ) }); + let recipe_book = inventory + .persistence_recipes_iter_with_index() + .map(|(i, item)| { + ( + serde_json::to_string(&i) + .expect("failed to serialize index of recipe from recipe book"), + Some(item), + recipe_book_container_id, + ) + }); // Inventory slots. let inventory = inventory.slots_with_id().map(|(pos, item)| { ( @@ -82,12 +94,17 @@ pub fn convert_items_to_database_items( // Use Breadth-first search to recurse into containers/modular weapons to store // their parts - let mut bfs_queue: VecDeque<_> = inventory.chain(loadout).chain(overflow_items).collect(); + let mut bfs_queue: VecDeque<_> = inventory + .chain(loadout) + .chain(overflow_items) + .chain(recipe_book) + .collect(); let mut upserts = Vec::new(); let mut depth = HashMap::new(); depth.insert(inventory_container_id, 0); depth.insert(loadout_container_id, 0); depth.insert(overflow_items_container_id, 0); + depth.insert(recipe_book_container_id, 0); while let Some((position, item, parent_container_item_id)) = bfs_queue.pop_front() { // Construct new items. if let Some(item) = item { @@ -182,7 +199,7 @@ pub fn convert_items_to_database_items( let upsert = ItemModelPair { model: Item { - item_definition_id: String::from(item.persistence_item_id()), + item_definition_id: item.persistence_item_id(), position, parent_container_item_id, item_id, @@ -210,27 +227,27 @@ pub fn convert_body_to_database_json( comp_body: &CompBody, ) -> Result<(&str, String), PersistenceError> { Ok(match comp_body { - Body::Humanoid(body) => ( + CompBody::Humanoid(body) => ( "humanoid", serde_json::to_string(&HumanoidBody::from(body))?, ), - Body::QuadrupedLow(body) => ( + CompBody::QuadrupedLow(body) => ( "quadruped_low", serde_json::to_string(&GenericBody::from(body))?, ), - Body::QuadrupedMedium(body) => ( + CompBody::QuadrupedMedium(body) => ( "quadruped_medium", serde_json::to_string(&GenericBody::from(body))?, ), - Body::QuadrupedSmall(body) => ( + CompBody::QuadrupedSmall(body) => ( "quadruped_small", serde_json::to_string(&GenericBody::from(body))?, ), - Body::BirdMedium(body) => ( + CompBody::BirdMedium(body) => ( "bird_medium", serde_json::to_string(&GenericBody::from(body))?, ), - Body::Crustacean(body) => ( + CompBody::Crustacean(body) => ( "crustacean", serde_json::to_string(&GenericBody::from(body))?, ), @@ -364,6 +381,7 @@ pub fn convert_inventory_from_database_items( loadout_items: &[Item], overflow_items_container_id: i64, overflow_items: &[Item], + recipe_book_items: &[Item], ) -> Result { // Loadout items must be loaded before inventory items since loadout items // provide inventory slots. Since items stored inside loadout items actually @@ -374,7 +392,8 @@ pub fn convert_inventory_from_database_items( let loadout = convert_loadout_from_database_items(loadout_container_id, loadout_items)?; let overflow_items = convert_overflow_items_from_database_items(overflow_items_container_id, overflow_items)?; - let mut inventory = Inventory::with_loadout_humanoid(loadout); + let recipe_book = convert_recipe_book_from_database_items(recipe_book_items)?; + let mut inventory = Inventory::with_loadout_humanoid(loadout).with_recipe_book(recipe_book); let mut item_indices = HashMap::new(); let mut failed_inserts = HashMap::new(); @@ -681,8 +700,8 @@ pub fn convert_body_from_database( // extra fields on its body struct "humanoid" => { let json_model = serde_json::de::from_str::(body_data)?; - CompBody::Humanoid(humanoid::Body { - species: humanoid::ALL_SPECIES + CompBody::Humanoid(body::humanoid::Body { + species: body::humanoid::ALL_SPECIES .get(json_model.species as usize) .ok_or_else(|| { PersistenceError::ConversionError(format!( @@ -691,7 +710,7 @@ pub fn convert_body_from_database( )) })? .to_owned(), - body_type: humanoid::ALL_BODY_TYPES + body_type: body::humanoid::ALL_BODY_TYPES .get(json_model.body_type as usize) .ok_or_else(|| { PersistenceError::ConversionError(format!( @@ -740,7 +759,7 @@ pub fn convert_character_from_database(character: &Character) -> common::charact } } -pub fn convert_stats_from_database(alias: String, body: Body) -> Stats { +pub fn convert_stats_from_database(alias: String, body: CompBody) -> Stats { let mut new_stats = Stats::empty(body); new_stats.name = alias; new_stats @@ -867,3 +886,25 @@ pub fn convert_active_abilities_from_database(ability_sets: &AbilitySets) -> Act }); json_models::active_abilities_from_db_model(ability_sets) } + +pub fn convert_recipe_book_from_database_items( + database_items: &[Item], +) -> Result { + let mut recipes_groups = Vec::new(); + + for db_item in database_items.iter() { + let item = get_item_from_asset(db_item.item_definition_id.as_str())?; + + // NOTE: item id is currently *unique*, so we can store the ID safely. + let comp = item.get_item_id_for_database(); + comp.store(Some(NonZeroU64::try_from(db_item.item_id as u64).map_err( + |_| PersistenceError::ConversionError("Item with zero item_id".to_owned()), + )?)); + + recipes_groups.push(item); + } + + let recipe_book = RecipeBook::recipe_book_from_persistence(recipes_groups); + + Ok(recipe_book) +} diff --git a/server/src/sys/msg/register.rs b/server/src/sys/msg/register.rs index 024920ef01..446c1d7303 100644 --- a/server/src/sys/msg/register.rs +++ b/server/src/sys/msg/register.rs @@ -8,7 +8,7 @@ use crate::{ use common::{ comp::{self, Admin, Player, Stats}, event::{ClientDisconnectEvent, EventBus, MakeAdminEvent}, - recipe::{default_component_recipe_book, default_recipe_book, default_repair_recipe_book}, + recipe::{default_component_recipe_book, default_repair_recipe_book}, resources::TimeOfDay, shared_server_config::ServerConstants, uid::Uid, @@ -50,6 +50,7 @@ pub struct ReadData<'a> { time_of_day: Read<'a, TimeOfDay>, material_stats: ReadExpect<'a, comp::item::MaterialStatManifest>, ability_map: ReadExpect<'a, comp::item::tool::AbilityMap>, + recipe_book: ReadExpect<'a, common::recipe::RecipeBookManifest>, map: ReadExpect<'a, WorldMapMsg>, trackers: TrackedStorages<'a>, #[allow(dead_code)] @@ -352,7 +353,7 @@ impl<'a> System<'a> for Sys { max_group_size: read_data.settings.max_player_group_size, client_timeout: read_data.settings.client_timeout, world_map: (*read_data.map).clone(), - recipe_book: default_recipe_book().cloned(), + recipe_book: (*read_data.recipe_book).clone(), component_recipe_book: default_component_recipe_book().cloned(), repair_recipe_book: default_repair_recipe_book().cloned(), material_stats: (*read_data.material_stats).clone(), diff --git a/voxygen/src/hud/crafting.rs b/voxygen/src/hud/crafting.rs index a59b472ce5..c418b4d692 100644 --- a/voxygen/src/hud/crafting.rs +++ b/voxygen/src/hud/crafting.rs @@ -26,7 +26,7 @@ use common::{ Inventory, }, mounting::VolumePos, - recipe::{ComponentKey, Recipe, RecipeInput}, + recipe::{ComponentKey, Recipe, RecipeBookManifest, RecipeInput}, terrain::SpriteKind, }; use conrod_core::{ @@ -158,6 +158,7 @@ pub struct Crafting<'a> { slot_manager: &'a mut SlotManager, item_imgs: &'a ItemImgs, inventory: &'a Inventory, + rbm: &'a RecipeBookManifest, msm: &'a MaterialStatManifest, #[conrod(common_builder)] common: widget::CommonBuilder, @@ -166,6 +167,7 @@ pub struct Crafting<'a> { } impl<'a> Crafting<'a> { + #[allow(clippy::too_many_arguments)] pub fn new( client: &'a Client, info: &'a HudInfo, @@ -179,6 +181,7 @@ impl<'a> Crafting<'a> { slot_manager: &'a mut SlotManager, item_imgs: &'a ItemImgs, inventory: &'a Inventory, + rbm: &'a RecipeBookManifest, msm: &'a MaterialStatManifest, tooltip_manager: &'a mut TooltipManager, show: &'a mut Show, @@ -197,6 +200,7 @@ impl<'a> Crafting<'a> { tooltip_manager, item_imgs, inventory, + rbm, msm, show, common: widget::CommonBuilder::default(), @@ -617,9 +621,8 @@ impl<'a> Widget for Crafting<'a> { }) }; let mut ordered_recipes: Vec<_> = self - .client - .recipe_book() - .iter() + .inventory + .available_recipes_iter(self.rbm) .filter(|(_, recipe)| match search_filter { SearchFilter::None => { search(&recipe.output.0) @@ -696,7 +699,7 @@ impl<'a> Widget for Crafting<'a> { }); // Recipe list - let recipe_list_length = self.client.recipe_book().iter().len() + pseudo_entries.len(); + let recipe_list_length = self.inventory.recipe_book_len() + pseudo_entries.len(); if state.ids.recipe_list_btns.len() < recipe_list_length { state.update(|state| { state @@ -869,9 +872,8 @@ impl<'a> Widget for Crafting<'a> { { Some((selected_recipe, *modular_recipe)) } else { - self.client - .recipe_book() - .get(selected_recipe) + self.inventory + .get_recipe(selected_recipe, self.rbm) .map(|r| (selected_recipe, r)) } }, @@ -955,7 +957,7 @@ impl<'a> Widget for Crafting<'a> { }; // Output slot, tags, and modular input slots - let (craft_slot_1, craft_slot_2, can_perform) = match recipe_kind { + let (craft_slot_1, craft_slot_2, can_perform, recipe_known) = match recipe_kind { RecipeKind::ModularWeapon | RecipeKind::Component(_) => { if state.ids.craft_slots.len() < 2 { state.update(|s| { @@ -1182,9 +1184,9 @@ impl<'a> Widget for Crafting<'a> { let ability_map = &AbilityMap::load().read(); let msm = &MaterialStatManifest::load().read(); - let output_item = match recipe_kind { + let (output_item, recipe_known) = match recipe_kind { RecipeKind::ModularWeapon => { - if let Some((primary_comp, toolkind, hand_restriction)) = + let item = if let Some((primary_comp, toolkind, hand_restriction)) = primary_slot.item(self.inventory).and_then(|item| { if let ItemKind::ModularComponent( ModularComponent::ToolPrimaryComponent { @@ -1198,8 +1200,7 @@ impl<'a> Widget for Crafting<'a> { } else { None } - }) - { + }) { secondary_slot .item(self.inventory) .filter(|item| { @@ -1223,7 +1224,8 @@ impl<'a> Widget for Crafting<'a> { }) } else { None - } + }; + (item, true) }, RecipeKind::Component(toolkind) => { if let Some(material) = @@ -1240,16 +1242,22 @@ impl<'a> Widget for Crafting<'a> { }, ), }; - self.client.component_recipe_book().get(&component_key).map( - |component_recipe| { - component_recipe.item_output(ability_map, msm) - }, - ) + self.client + .component_recipe_book() + .get(&component_key) + .map(|component_recipe| { + let item = component_recipe.item_output(ability_map, msm); + let learned = self + .inventory + .recipe_is_known(&component_recipe.recipe_book_key); + (item, learned) + }) + .map_or((None, true), |(item, known)| (Some(item), known)) } else { - None + (None, true) } }, - RecipeKind::Simple | RecipeKind::Repair => None, + RecipeKind::Simple | RecipeKind::Repair => (None, true), }; if let Some(output_item) = output_item { @@ -1281,6 +1289,7 @@ impl<'a> Widget for Crafting<'a> { secondary_slot.slot, self.show.crafting_fields.craft_sprite.map(|(_, s)| s) == recipe.craft_sprite, + recipe_known, ) } else { Text::new(&self.localized_strings.get_msg("hud-crafting-modular_desc")) @@ -1295,7 +1304,7 @@ impl<'a> Widget for Crafting<'a> { .w_h(70.0, 70.0) .graphics_for(state.ids.output_img) .set(state.ids.modular_wep_empty_bg, ui); - (primary_slot.slot, secondary_slot.slot, false) + (primary_slot.slot, secondary_slot.slot, false, recipe_known) } }, RecipeKind::Simple => { @@ -1398,6 +1407,7 @@ impl<'a> Widget for Crafting<'a> { == self.show.crafting_fields.craft_sprite.map(|(_, s)| s) }) }), + true, ) }, RecipeKind::Repair => { @@ -1530,12 +1540,16 @@ impl<'a> Widget for Crafting<'a> { let can_perform = repair_slot.item(self.inventory).map_or(false, can_repair); - (repair_slot.slot, None, can_perform) + (repair_slot.slot, None, can_perform, true) }, }; // Craft button - if Button::image(self.imgs.button) + let label = &match recipe_kind { + RecipeKind::Repair => self.localized_strings.get_msg("hud-crafting-repair"), + _ => self.localized_strings.get_msg("hud-crafting-craft"), + }; + let craft_button_init = Button::image(self.imgs.button) .w_h(105.0, 25.0) .hover_image(if can_perform { self.imgs.button_hover @@ -1547,10 +1561,7 @@ impl<'a> Widget for Crafting<'a> { } else { self.imgs.button }) - .label(&match recipe_kind { - RecipeKind::Repair => self.localized_strings.get_msg("hud-crafting-repair"), - _ => self.localized_strings.get_msg("hud-crafting-craft"), - }) + .label(label) .label_y(conrod_core::position::Relative::Scalar(1.0)) .label_color(if can_perform { TEXT_COLOR @@ -1565,11 +1576,27 @@ impl<'a> Widget for Crafting<'a> { TEXT_GRAY_COLOR }) .bottom_left_with_margins_on(state.ids.align_ing, -31.0, 15.0) - .parent(state.ids.window_frame) - .set(state.ids.btn_craft, ui) - .was_clicked() - && can_perform - { + .parent(state.ids.window_frame); + + let craft_button = if !recipe_known { + craft_button_init + .with_tooltip( + self.tooltip_manager, + &self + .localized_strings + .get_msg("hud-crafting-recipe-uncraftable"), + &self + .localized_strings + .get_msg("hud-crafting-recipe-unlearned"), + &tabs_tooltip, + TEXT_COLOR, + ) + .set(state.ids.btn_craft, ui) + } else { + craft_button_init.set(state.ids.btn_craft, ui) + }; + + if craft_button.was_clicked() && can_perform { match recipe_kind { RecipeKind::ModularWeapon => { if let ( diff --git a/voxygen/src/hud/item_imgs.rs b/voxygen/src/hud/item_imgs.rs index 8bd1ffc061..eb0b4caf96 100644 --- a/voxygen/src/hud/item_imgs.rs +++ b/voxygen/src/hud/item_imgs.rs @@ -1,7 +1,7 @@ use crate::ui::{Graphic, SampleStrat, Transform, Ui}; use common::{ assets::{self, AssetCombined, AssetExt, AssetHandle, Concatenate, DotVoxAsset, ReloadWatcher}, - comp::item::item_key::ItemKey, + comp::item::{item_key::ItemKey, modular}, figure::Segment, }; use conrod_core::image::Id; @@ -17,7 +17,7 @@ pub fn animate_by_pulse(ids: &[Id], pulse: f32) -> Id { ids[animation_frame % ids.len()] } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub enum ImageSpec { Png(String), Vox(String, #[serde(default)] u32), @@ -56,7 +56,7 @@ impl ImageSpec { } #[derive(Serialize, Deserialize)] -pub struct ItemImagesSpec(pub HashMap); +pub struct ItemImagesSpec(pub HashMap); impl assets::Asset for ItemImagesSpec { type Loader = assets::RonLoader; @@ -68,7 +68,7 @@ impl Concatenate for ItemImagesSpec { // TODO: when there are more images don't load them all into memory pub struct ItemImgs { - map: HashMap, + map: HashMap, manifest: AssetHandle, watcher: ReloadWatcher, not_found: Id, @@ -118,11 +118,11 @@ impl ItemImgs { if let ItemKey::TagExamples(keys, _) = item_key { return keys .iter() - .filter_map(|k| self.map.get(k)) + .filter_map(|k| self.map.get(&ItemVisualKey::from(k.clone()))) .cloned() .collect(); }; - match self.map.get(&item_key) { + match self.map.get(&ItemVisualKey::from(item_key.clone())) { Some(id) => vec![*id], // There was no specification in the ron None => { @@ -183,3 +183,25 @@ fn graceful_load_segment_no_skin(specifier: &str, model_index: u32) -> Arc, String), + Recipe(String), + Empty, +} + +impl From for ItemVisualKey { + fn from(item_key: ItemKey) -> Self { + match item_key { + ItemKey::Simple(key) => Self::Simple(key), + ItemKey::ModularWeapon(key) => Self::ModularWeapon(key), + ItemKey::ModularWeaponComponent(key) => Self::ModularWeaponComponent(key), + ItemKey::TagExamples(keys, key) => Self::TagExamples(keys, key), + ItemKey::Empty => Self::Empty, + } + } +} diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 8ebccbff26..62291ba323 100755 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -109,6 +109,7 @@ use common::{ link::Is, mounting::{Mount, Rider, VolumePos}, outcome::Outcome, + recipe::RecipeBookManifest, resources::{ProgramTime, Secs, Time}, slowjob::SlowJobPool, terrain::{SpriteKind, TerrainChunk, UnlockKind}, @@ -3142,6 +3143,7 @@ impl Hud { let entity = info.viewpoint_entity; let healths = ecs.read_storage::(); let inventories = ecs.read_storage::(); + let rbm = ecs.read_resource::(); let energies = ecs.read_storage::(); let skillsets = ecs.read_storage::(); let active_abilities = ecs.read_storage::(); @@ -3381,6 +3383,7 @@ impl Hud { &mut self.slot_manager, &self.item_imgs, inventory, + &rbm, &msm, tooltip_manager, &mut self.show, diff --git a/voxygen/src/hud/util.rs b/voxygen/src/hud/util.rs index 09c3900b1d..41b4a021b9 100644 --- a/voxygen/src/hud/util.rs +++ b/voxygen/src/hud/util.rs @@ -112,6 +112,7 @@ pub fn kind_text<'a>(kind: &ItemKind, i18n: &'a Localization) -> Cow<'a, str> { ItemKind::Ingredient { .. } => i18n.get_msg("common-kind-ingredient"), ItemKind::Lantern { .. } => i18n.get_msg("common-kind-lantern"), ItemKind::TagExamples { .. } => Cow::Borrowed(""), + ItemKind::RecipeGroup { .. } => i18n.get_msg("common-kind-recipegroup"), } } diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs index 549e0c06af..70c76cbffe 100644 --- a/voxygen/src/scene/figure/cache.rs +++ b/voxygen/src/scene/figure/cache.rs @@ -216,11 +216,10 @@ impl CharacterCacheKey { .map(|id| match id { // TODO: Properly handle items with components here. Probably wait until modular // armor? - ItemDefinitionId::Simple(id) => id, - ItemDefinitionId::Compound { simple_base, .. } => simple_base, - ItemDefinitionId::Modular { pseudo_base, .. } => pseudo_base, + ItemDefinitionId::Simple(id) => String::from(id), + ItemDefinitionId::Compound { simple_base, .. } => String::from(simple_base), + ItemDefinitionId::Modular { pseudo_base, .. } => String::from(pseudo_base), }) - .map(String::from) }; // Third person tools are only modeled when the camera is either not first diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index a0e6fe70e7..1db0080b49 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -1,6 +1,7 @@ use super::cache::{ FigureKey, FigureModelEntryFuture, ModelEntryFuture, TerrainModelEntryFuture, ToolKey, }; +use crate::hud::item_imgs::ItemVisualKey; use common::{ assets::{self, AssetExt, AssetHandle, Concatenate, DotVoxAsset, MultiRon, ReloadWatcher}, comp::{ @@ -5609,7 +5610,7 @@ impl<'de> Deserialize<'de> for ModelWithOptionalIndex { } #[derive(Deserialize)] -struct ItemDropCentralSpec(HashMap); +struct ItemDropCentralSpec(HashMap); impl_concatenate_for_wrapper!(ItemDropCentralSpec); make_vox_spec!( @@ -5645,7 +5646,7 @@ impl ItemDropCentralSpec { if let Some(spec) = match item_drop { item_drop::Body::CoinPouch => Some(&coin_pouch), - _ => self.0.get(item_key), + _ => self.0.get(&ItemVisualKey::from(item_key.clone())), } { let full_spec: String = ["voxygen.", spec.0.as_str()].concat(); let segment = match item_drop { diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index 79bd31b06d..0cef377265 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -27,7 +27,7 @@ use common::{ link::Is, mounting::{Mount, VolumePos}, outcome::Outcome, - recipe, + recipe::{self, RecipeBookManifest}, states::utils::can_perform_pet, terrain::{Block, BlockKind}, trade::TradeResult, @@ -1978,13 +1978,24 @@ impl PlayState for SessionState { } => { let slots = { let client = self.client.borrow(); - if let Some(recipe) = client.recipe_book().get(&recipe) { - client.inventories().get(client.entity()).and_then(|inv| { - recipe.inventory_contains_ingredients(inv, 1).ok() - }) + + let s = if let Some(inventory) = client + .state() + .ecs() + .read_storage::() + .get(client.entity()) + { + let rbm = + client.state().ecs().read_resource::(); + if let Some(recipe) = inventory.get_recipe(&recipe, &rbm) { + recipe.inventory_contains_ingredients(inventory, 1).ok() + } else { + None + } } else { None - } + }; + s }; if let Some(slots) = slots { self.client.borrow_mut().craft_recipe( diff --git a/world/src/site/economy/map_types.rs b/world/src/site/economy/map_types.rs index 7e0502514b..9ef120d7df 100644 --- a/world/src/site/economy/map_types.rs +++ b/world/src/site/economy/map_types.rs @@ -20,7 +20,7 @@ pub struct GoodIndex { idx: usize, } -impl GenericIndex for GoodIndex { +impl GenericIndex for GoodIndex { // static list of all Goods traded const VALUES: [Good; GoodIndex::LENGTH] = [ // controlled resources @@ -41,6 +41,7 @@ impl GenericIndex for GoodIndex { Armor, Potions, Transportation, + Recipe, // exchange currency Coin, // uncontrolled resources