forked from EXTERNAL/bareiron
412 lines
14 KiB
C
412 lines
14 KiB
C
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "globals.h"
|
|
#include "registries.h"
|
|
#include "tools.h"
|
|
#include "crafting.h"
|
|
|
|
void getCraftingOutput (PlayerData *player, uint8_t *count, uint16_t *item) {
|
|
|
|
uint8_t i, filled = 0, first = 10, identical = true;
|
|
for (i = 0; i < 9; i ++) {
|
|
if (player->craft_items[i]) {
|
|
filled ++;
|
|
if (first == 10) first = i;
|
|
else if (player->craft_items[i] != player->craft_items[first]) {
|
|
identical = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint16_t first_item = player->craft_items[first];
|
|
uint8_t first_col = first % 3, first_row = first / 3;
|
|
|
|
switch (filled) {
|
|
|
|
case 0:
|
|
*item = 0;
|
|
*count = 0;
|
|
return;
|
|
|
|
case 1:
|
|
switch (first_item) {
|
|
case I_oak_log: *item = I_oak_planks; *count = 4; return;
|
|
case I_oak_planks: *item = I_oak_button; *count = 1; return;
|
|
case I_iron_block: *item = I_iron_ingot; *count = 9; return;
|
|
case I_gold_block: *item = I_gold_ingot; *count = 9; return;
|
|
case I_diamond_block: *item = I_diamond; *count = 9; return;
|
|
case I_redstone_block: *item = I_redstone; *count = 9; return;
|
|
case I_coal_block: *item = I_coal; *count = 9; return;
|
|
case I_copper_block: *item = I_copper_ingot; *count = 9; return;
|
|
|
|
default: break;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
switch (first_item) {
|
|
case I_oak_planks:
|
|
if (first_col != 2 && player->craft_items[first + 1] == I_oak_planks) {
|
|
*item = I_oak_pressure_plate;
|
|
*count = 1;
|
|
return;
|
|
} else if (first_row != 2 && player->craft_items[first + 3] == I_oak_planks) {
|
|
*item = I_stick;
|
|
*count = 4;
|
|
return;
|
|
}
|
|
break;
|
|
case I_charcoal:
|
|
case I_coal:
|
|
if (first_row != 2 && player->craft_items[first + 3] == I_stick) {
|
|
*item = I_torch;
|
|
*count = 4;
|
|
return;
|
|
}
|
|
break;
|
|
case I_iron_ingot:
|
|
if (
|
|
(
|
|
first_row != 2 && first_col != 2 &&
|
|
player->craft_items[first + 4] == I_iron_ingot
|
|
) || (
|
|
first_row != 2 && first_col != 0 &&
|
|
player->craft_items[first + 2] == I_iron_ingot
|
|
)
|
|
) {
|
|
*item = I_shears;
|
|
*count = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
switch (first_item) {
|
|
case I_oak_planks:
|
|
case I_cobblestone:
|
|
case I_stone:
|
|
case I_snow_block:
|
|
// Slab recipes
|
|
if (
|
|
first_col == 0 &&
|
|
player->craft_items[first + 1] == first_item &&
|
|
player->craft_items[first + 2] == first_item
|
|
) {
|
|
if (first_item == I_oak_planks) *item = I_oak_slab;
|
|
else if (first_item == I_cobblestone) *item = I_cobblestone_slab;
|
|
else if (first_item == I_stone) *item = I_stone_slab;
|
|
else if (first_item == I_snow_block) *item = I_snow;
|
|
*count = 6;
|
|
return;
|
|
}
|
|
case I_iron_ingot:
|
|
case I_gold_ingot:
|
|
case I_diamond:
|
|
case I_netherite_ingot:
|
|
// Shovel recipes
|
|
if (
|
|
first_row == 0 &&
|
|
player->craft_items[first + 3] == I_stick &&
|
|
player->craft_items[first + 6] == I_stick
|
|
) {
|
|
if (first_item == I_oak_planks) *item = I_wooden_shovel;
|
|
else if (first_item == I_cobblestone) *item = I_stone_shovel;
|
|
else if (first_item == I_iron_ingot) *item = I_iron_shovel;
|
|
else if (first_item == I_gold_ingot) *item = I_golden_shovel;
|
|
else if (first_item == I_diamond) *item = I_diamond_shovel;
|
|
else if (first_item == I_netherite_ingot) *item = I_netherite_shovel;
|
|
*count = 1;
|
|
return;
|
|
}
|
|
// Sword recipes
|
|
if (
|
|
first_row == 0 &&
|
|
player->craft_items[first + 3] == first_item &&
|
|
player->craft_items[first + 6] == I_stick
|
|
) {
|
|
if (first_item == I_oak_planks) *item = I_wooden_sword;
|
|
else if (first_item == I_cobblestone) *item = I_stone_sword;
|
|
else if (first_item == I_iron_ingot) *item = I_iron_sword;
|
|
else if (first_item == I_gold_ingot) *item = I_golden_sword;
|
|
else if (first_item == I_diamond) *item = I_diamond_sword;
|
|
else if (first_item == I_netherite_ingot) *item = I_netherite_sword;
|
|
*count = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
switch (first_item) {
|
|
case I_oak_planks:
|
|
case I_oak_log:
|
|
case I_snowball:
|
|
// Uniform 2x2 shaped recipes
|
|
if (
|
|
first_col != 2 && first_row != 2 &&
|
|
player->craft_items[first + 1] == first_item &&
|
|
player->craft_items[first + 3] == first_item &&
|
|
player->craft_items[first + 4] == first_item
|
|
) {
|
|
if (first_item == I_oak_planks) { *item = I_crafting_table; *count = 1; }
|
|
else if (first_item == I_oak_log) { *item = I_oak_wood; *count = 3; }
|
|
else if (first_item == I_snowball) { *item = I_snow_block; *count = 3; }
|
|
return;
|
|
}
|
|
break;
|
|
// Boot recipes
|
|
case I_leather:
|
|
case I_iron_ingot:
|
|
case I_gold_ingot:
|
|
case I_diamond:
|
|
case I_netherite_ingot:
|
|
if (
|
|
first_col == 0 && first_row < 2 &&
|
|
player->craft_items[first + 2] == first_item &&
|
|
player->craft_items[first + 3] == first_item &&
|
|
player->craft_items[first + 5] == first_item
|
|
) {
|
|
if (first_item == I_leather) *item = I_leather_boots;
|
|
else if (first_item == I_iron_ingot) *item = I_iron_boots;
|
|
else if (first_item == I_gold_ingot) *item = I_golden_boots;
|
|
else if (first_item == I_diamond) *item = I_diamond_boots;
|
|
else if (first_item == I_netherite_ingot) *item = I_netherite_boots;
|
|
*count = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
switch (first_item) {
|
|
case I_oak_planks:
|
|
case I_cobblestone:
|
|
case I_iron_ingot:
|
|
case I_gold_ingot:
|
|
case I_diamond:
|
|
case I_netherite_ingot:
|
|
// Pickaxe recipes
|
|
if (
|
|
first == 0 &&
|
|
player->craft_items[first + 1] == first_item &&
|
|
player->craft_items[first + 2] == first_item &&
|
|
player->craft_items[first + 4] == I_stick &&
|
|
player->craft_items[first + 7] == I_stick
|
|
) {
|
|
if (first_item == I_oak_planks) *item = I_wooden_pickaxe;
|
|
else if (first_item == I_cobblestone) *item = I_stone_pickaxe;
|
|
else if (first_item == I_iron_ingot) *item = I_iron_pickaxe;
|
|
else if (first_item == I_gold_ingot) *item = I_golden_pickaxe;
|
|
else if (first_item == I_diamond) *item = I_diamond_pickaxe;
|
|
else if (first_item == I_netherite_ingot) *item = I_netherite_pickaxe;
|
|
*count = 1;
|
|
return;
|
|
}
|
|
// Axe recipes
|
|
if (
|
|
first < 2 &&
|
|
player->craft_items[first + 1] == first_item &&
|
|
((
|
|
player->craft_items[first + 3] == first_item &&
|
|
player->craft_items[first + 4] == I_stick &&
|
|
player->craft_items[first + 7] == I_stick
|
|
) || (
|
|
player->craft_items[first + 4] == first_item &&
|
|
player->craft_items[first + 3] == I_stick &&
|
|
player->craft_items[first + 6] == I_stick
|
|
))
|
|
) {
|
|
if (first_item == I_oak_planks) *item = I_wooden_axe;
|
|
else if (first_item == I_cobblestone) *item = I_stone_axe;
|
|
else if (first_item == I_iron_ingot) *item = I_iron_axe;
|
|
else if (first_item == I_gold_ingot) *item = I_golden_axe;
|
|
else if (first_item == I_diamond) *item = I_diamond_axe;
|
|
else if (first_item == I_netherite_ingot) *item = I_netherite_axe;
|
|
*count = 1;
|
|
return;
|
|
}
|
|
if (
|
|
first_item == I_oak_planks ||
|
|
first_item == I_cobblestone
|
|
) break;
|
|
case I_leather:
|
|
// Helmet recipes
|
|
if (
|
|
first_col == 0 && first_row < 2 &&
|
|
player->craft_items[first + 1] == first_item &&
|
|
player->craft_items[first + 2] == first_item &&
|
|
player->craft_items[first + 3] == first_item &&
|
|
player->craft_items[first + 5] == first_item
|
|
) {
|
|
if (first_item == I_leather) *item = I_leather_helmet;
|
|
else if (first_item == I_iron_ingot) *item = I_iron_helmet;
|
|
else if (first_item == I_gold_ingot) *item = I_golden_helmet;
|
|
else if (first_item == I_diamond) *item = I_diamond_helmet;
|
|
else if (first_item == I_netherite_ingot) *item = I_netherite_helmet;
|
|
*count = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
break;
|
|
|
|
case 7:
|
|
// Legging recipes
|
|
if (identical && player->craft_items[4] == 0 && player->craft_items[7] == 0) {
|
|
switch (first_item) {
|
|
case I_leather: *item = I_leather_leggings; *count = 1; return;
|
|
case I_iron_ingot: *item = I_iron_leggings; *count = 1; return;
|
|
case I_gold_ingot: *item = I_golden_leggings; *count = 1; return;
|
|
case I_diamond: *item = I_diamond_leggings; *count = 1; return;
|
|
case I_netherite_ingot: *item = I_netherite_leggings; *count = 1; return;
|
|
default: break;
|
|
}
|
|
}
|
|
switch (first_item) {
|
|
case I_oak_slab:
|
|
if (
|
|
identical &&
|
|
player->craft_items[1] == 0 &&
|
|
player->craft_items[4] == 0
|
|
) {
|
|
*item = I_composter;
|
|
*count = 1;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
if (identical) {
|
|
if (player->craft_items[4] == 0) {
|
|
// Center slot clear
|
|
switch (first_item) {
|
|
case I_cobblestone: *item = I_furnace; *count = 1; return;
|
|
#ifdef ALLOW_CHESTS
|
|
case I_oak_planks: *item = I_chest; *count = 1; return;
|
|
#endif
|
|
default: break;
|
|
}
|
|
} else if (player->craft_items[1] == 0) {
|
|
// Top-middle slot clear (chestplate recipes)
|
|
switch (first_item) {
|
|
case I_leather: *item = I_leather_chestplate; *count = 1; return;
|
|
case I_iron_ingot: *item = I_iron_chestplate; *count = 1; return;
|
|
case I_gold_ingot: *item = I_golden_chestplate; *count = 1; return;
|
|
case I_diamond: *item = I_diamond_chestplate; *count = 1; return;
|
|
case I_netherite_ingot: *item = I_netherite_chestplate; *count = 1; return;
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 9:
|
|
// Uniform 3x3 shaped recipes
|
|
if (identical) switch (first_item) {
|
|
case I_iron_ingot: *item = I_iron_block; *count = 1; return;
|
|
case I_gold_ingot: *item = I_gold_block; *count = 1; return;
|
|
case I_diamond: *item = I_diamond_block; *count = 1; return;
|
|
case I_redstone: *item = I_redstone_block; *count = 1; return;
|
|
case I_coal: *item = I_coal_block; *count = 1; return;
|
|
case I_copper_ingot: *item = I_copper_block; *count = 1; return;
|
|
default: break;
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
*count = 0;
|
|
*item = 0;
|
|
|
|
}
|
|
|
|
#define registerSmeltingRecipe(a, b) \
|
|
if (*material == a && (*output_item == b || *output_item == 0)) *output_item = b
|
|
|
|
void getSmeltingOutput (PlayerData *player) {
|
|
|
|
uint8_t *material_count = &player->craft_count[0];
|
|
uint8_t *fuel_count = &player->craft_count[1];
|
|
|
|
// Don't process if we're missing material or fuel
|
|
if (*material_count == 0 || *fuel_count == 0) return;
|
|
|
|
uint16_t *material = &player->craft_items[0];
|
|
uint16_t *fuel = &player->craft_items[1];
|
|
|
|
// Don't process if we're missing material or fuel
|
|
if (*material == 0 || *fuel == 0) return;
|
|
|
|
// Furnace output is 3rd crafting table slot
|
|
uint8_t *output_count = &player->craft_count[2];
|
|
uint16_t *output_item = &player->craft_items[2];
|
|
|
|
// Determine fuel efficiency based on the type of item
|
|
// Since we can't represent fractions, some items use a random component
|
|
// to represent the fractional part. In some cases (e.g. sticks), this
|
|
// can lead to a fuel_value of 0, which means that the fuel gets consumed
|
|
// without processing any materials.
|
|
uint8_t fuel_value = 0;
|
|
if (*fuel == I_coal) fuel_value = 8;
|
|
else if (*fuel == I_charcoal) fuel_value = 8;
|
|
else if (*fuel == I_coal_block) fuel_value = 80;
|
|
else if (*fuel == I_oak_planks) fuel_value = 1 + (fast_rand() & 1);
|
|
else if (*fuel == I_oak_log) fuel_value = 1 + (fast_rand() & 1);
|
|
else if (*fuel == I_crafting_table) fuel_value = 1 + (fast_rand() & 1);
|
|
else if (*fuel == I_stick) fuel_value = (fast_rand() & 1);
|
|
else if (*fuel == I_oak_sapling) fuel_value = (fast_rand() & 1);
|
|
else if (*fuel == I_wooden_axe) fuel_value = 1;
|
|
else if (*fuel == I_wooden_pickaxe) fuel_value = 1;
|
|
else if (*fuel == I_wooden_shovel) fuel_value = 1;
|
|
else if (*fuel == I_wooden_sword) fuel_value = 1;
|
|
else if (*fuel == I_wooden_hoe) fuel_value = 1;
|
|
else return;
|
|
|
|
uint8_t exchange = *material_count > fuel_value ? fuel_value : *material_count;
|
|
|
|
registerSmeltingRecipe(I_cobblestone, I_stone);
|
|
else registerSmeltingRecipe(I_oak_log, I_charcoal);
|
|
else registerSmeltingRecipe(I_oak_wood, I_charcoal);
|
|
else registerSmeltingRecipe(I_raw_iron, I_iron_ingot);
|
|
else registerSmeltingRecipe(I_raw_gold, I_gold_ingot);
|
|
else registerSmeltingRecipe(I_sand, I_glass);
|
|
else registerSmeltingRecipe(I_chicken, I_cooked_chicken);
|
|
else registerSmeltingRecipe(I_beef, I_cooked_beef);
|
|
else registerSmeltingRecipe(I_porkchop, I_cooked_porkchop);
|
|
else registerSmeltingRecipe(I_mutton, I_cooked_mutton);
|
|
else return;
|
|
|
|
*output_count += exchange;
|
|
*material_count -= exchange;
|
|
|
|
*fuel_count -= 1;
|
|
if (*fuel_count == 0) *fuel = 0;
|
|
|
|
if (*material_count <= 0) {
|
|
*material_count = 0;
|
|
*material = 0;
|
|
} else return getSmeltingOutput(player);
|
|
|
|
return;
|
|
|
|
}
|