diff --git a/data/cobble.png b/data/cobble.png new file mode 100644 index 00000000..7d044741 Binary files /dev/null and b/data/cobble.png differ diff --git a/data/steel_block.png b/data/steel_block.png new file mode 100644 index 00000000..8e202008 Binary files /dev/null and b/data/steel_block.png differ diff --git a/data/steel_ingot.png b/data/steel_ingot.png new file mode 100644 index 00000000..f6c9414e Binary files /dev/null and b/data/steel_ingot.png differ diff --git a/data/stone.png b/data/stone.png index d085cb8d..cad0dbe2 100644 Binary files a/data/stone.png and b/data/stone.png differ diff --git a/data/tool_steelaxe.png b/data/tool_steelaxe.png new file mode 100644 index 00000000..85267ae7 Binary files /dev/null and b/data/tool_steelaxe.png differ diff --git a/data/tool_steelpick.png b/data/tool_steelpick.png new file mode 100644 index 00000000..4bb5f8be Binary files /dev/null and b/data/tool_steelpick.png differ diff --git a/data/tool_steelshovel.png b/data/tool_steelshovel.png new file mode 100644 index 00000000..61d90b12 Binary files /dev/null and b/data/tool_steelshovel.png differ diff --git a/data/tool_stoneaxe.png b/data/tool_stoneaxe.png new file mode 100644 index 00000000..bcb58968 Binary files /dev/null and b/data/tool_stoneaxe.png differ diff --git a/data/tool_stpick.png b/data/tool_stonepick.png similarity index 100% rename from data/tool_stpick.png rename to data/tool_stonepick.png diff --git a/data/tool_stoneshovel.png b/data/tool_stoneshovel.png new file mode 100644 index 00000000..53eb7230 Binary files /dev/null and b/data/tool_stoneshovel.png differ diff --git a/data/tool_woodaxe.png b/data/tool_woodaxe.png new file mode 100644 index 00000000..cb0d95f2 Binary files /dev/null and b/data/tool_woodaxe.png differ diff --git a/data/tool_wpick.png b/data/tool_woodpick.png similarity index 100% rename from data/tool_wpick.png rename to data/tool_woodpick.png diff --git a/data/tool_woodshovel.png b/data/tool_woodshovel.png new file mode 100644 index 00000000..2645952d Binary files /dev/null and b/data/tool_woodshovel.png differ diff --git a/src/inventory.cpp b/src/inventory.cpp index ccd55a79..f9b9107a 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -94,12 +94,51 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is) MaterialItem */ +bool MaterialItem::isCookable() +{ + if(m_content == CONTENT_TREE) + { + return true; + } + else if(m_content == CONTENT_COBBLE) + { + return true; + } + return false; +} + InventoryItem *MaterialItem::createCookResult() { if(m_content == CONTENT_TREE) { return new CraftItem("lump_of_coal", 1); } + else if(m_content == CONTENT_COBBLE) + { + return new MaterialItem(CONTENT_STONE, 1); + } + return NULL; +} + +/* + CraftItem +*/ + +bool CraftItem::isCookable() +{ + if(m_subname == "lump_of_iron") + { + return true; + } + return false; +} + +InventoryItem *CraftItem::createCookResult() +{ + if(m_subname == "lump_of_iron") + { + return new CraftItem("steel_ingot", 1); + } return NULL; } @@ -357,6 +396,9 @@ void InventoryList::deleteItem(u32 i) InventoryItem * InventoryList::addItem(InventoryItem *newitem) { + if(newitem == NULL) + return NULL; + /* First try to find if it could be added to some existing items */ @@ -391,6 +433,9 @@ InventoryItem * InventoryList::addItem(InventoryItem *newitem) InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem) { + if(newitem == NULL) + return NULL; + // If it is an empty position, it's an easy job. InventoryItem *to_item = m_items[i]; if(to_item == NULL) diff --git a/src/inventory.h b/src/inventory.h index d110f92c..761e664a 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -91,6 +91,8 @@ public: /* Other properties */ + // Whether it can be cooked + virtual bool isCookable(){return false;} // Time of cooking virtual float getCookTime(){return 3.0;} // Result of cooking @@ -160,6 +162,7 @@ public: /* Other properties */ + bool isCookable(); InventoryItem *createCookResult(); /* Special methods @@ -272,6 +275,8 @@ public: name = "lump_of_coal.png"; else if(m_subname == "lump_of_iron") name = "lump_of_iron.png"; + else if(m_subname == "steel_ingot") + name = "steel_ingot.png"; else name = "cloud.png"; @@ -301,6 +306,11 @@ public: return 0; return QUANTITY_ITEM_MAX_COUNT - m_count; } + /* + Other properties + */ + bool isCookable(); + InventoryItem *createCookResult(); /* Special methods */ @@ -348,11 +358,25 @@ public: std::string basename; if(m_toolname == "WPick") - basename = "tool_wpick.png"; + basename = "tool_woodpick.png"; else if(m_toolname == "STPick") - basename = "tool_stpick.png"; + basename = "tool_stonepick.png"; + else if(m_toolname == "SteelPick") + basename = "tool_steelpick.png"; else if(m_toolname == "MesePick") basename = "tool_mesepick.png"; + else if(m_toolname == "WShovel") + basename = "tool_woodshovel.png"; + else if(m_toolname == "STShovel") + basename = "tool_stoneshovel.png"; + else if(m_toolname == "SteelShovel") + basename = "tool_steelshovel.png"; + else if(m_toolname == "WAxe") + basename = "tool_woodaxe.png"; + else if(m_toolname == "STAxe") + basename = "tool_stoneaxe.png"; + else if(m_toolname == "SteelAxe") + basename = "tool_steelaxe.png"; else basename = "cloud.png"; diff --git a/src/map.cpp b/src/map.cpp index 40274ae2..49ed2f5f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2252,7 +2252,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, TimeTaker timer_generate("generateChunkRaw() generate"); // Maximum height of the stone surface and obstacles. - // This is used to disable dungeon generation from going too high. + // This is used to disable cave generation from going too high. s16 stone_surface_max_y = 0; /* @@ -2320,12 +2320,12 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, Randomize some parameters */ - s32 stone_obstacle_count = 0; + //s32 stone_obstacle_count = 0; /*s32 stone_obstacle_count = rangelim((1.0+noise2d(m_seed+897, sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/ - s16 stone_obstacle_max_height = 0; + //s16 stone_obstacle_max_height = 0; /*s16 stone_obstacle_max_height = rangelim((1.0+noise2d(m_seed+5902, sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/ @@ -2336,7 +2336,11 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, //for(u32 i_age=0; i_age<1; i_age++) for(u32 i_age=0; i_age<2; i_age++) { // Aging loop + /****************************** + BEGINNING OF AGING LOOP + ******************************/ +#if 0 { // 8ms @cs=8 //TimeTaker timer1("stone obstacles"); @@ -2461,26 +2465,30 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, } }//timer1 +#endif + { // 24ms @cs=8 - //TimeTaker timer1("dungeons"); + //TimeTaker timer1("caves"); /* - Make dungeons + Make caves */ - u32 dungeons_count = relative_volume / 600000; + u32 caves_count = relative_volume / 400000; u32 bruises_count = relative_volume * stone_surface_max_y / 40000000; if(stone_surface_max_y < WATER_LEVEL) bruises_count = 0; - /*u32 dungeons_count = 0; + /*u32 caves_count = 0; u32 bruises_count = 0;*/ - for(u32 jj=0; jj caves_count); if(bruise_surface) { @@ -2494,6 +2502,9 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, tunnel_routepoints = 5; } + else + { + } // Allowed route area size in nodes v3s16 ar( @@ -2521,7 +2532,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, // Allow half a diameter + 7 over stone surface s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7; - /*// If dungeons, don't go through surface too often + /*// If caves, don't go through surface too often if(bruise_surface == false) route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/ @@ -2546,16 +2557,16 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, s16 route_start_y_min = route_y_min; s16 route_start_y_max = route_y_max; - // Start every 2nd dungeon from surface + // Start every 2nd cave from surface bool coming_from_surface = (jj % 2 == 0 && bruise_surface == false); if(coming_from_surface) { - route_start_y_min = -of.Y + stone_surface_max_y + 5; + route_start_y_min = -of.Y + stone_surface_max_y + 10; } route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1); - route_start_y_max = rangelim(route_start_y_max, 0, ar.Y-1); + route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1); // Randomize starting position v3f orp( @@ -2572,6 +2583,16 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, for(u16 j=0; jd = CONTENT_WATERSOURCE; @@ -3119,6 +3142,9 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos, }//timer1 } // Aging loop + /*********************** + END OF AGING LOOP + ************************/ { //TimeTaker timer1("convert mud to sand"); @@ -3953,7 +3979,7 @@ MapBlock * ServerMap::generateBlock( else n.d = CONTENT_AIR; } - // Else it's ground or dungeons (air) + // Else it's ground or caves (air) else { // If it's surface_depth under ground, it's stone @@ -4034,7 +4060,7 @@ MapBlock * ServerMap::generateBlock( //dstream<<"generateBlock(): Done"<getNode(v3s16(x0,y0,z0)); - // Create dungeons + // Create caves if(underground_emptiness[ ued*ued*(z0*ued/MAP_BLOCKSIZE) +ued*(y0*ued/MAP_BLOCKSIZE) @@ -4275,7 +4301,7 @@ continue_generating: if(content_features(n.d).walkable/*is_ground_content(n.d)*/) { // Has now caves - has_dungeons = true; + has_caves = true; // Set air to node n.d = CONTENT_AIR; } @@ -4295,7 +4321,7 @@ continue_generating: Force lighting update if some part of block is partly underground and has caves. */ - /*if(some_part_underground && !completely_underground && has_dungeons) + /*if(some_part_underground && !completely_underground && has_caves) { //dstream<<"Half-ground caves"<getPos()] = block; @@ -4440,11 +4466,11 @@ continue_generating: */ dstream <<"lighting_invalidated_blocks.size()" - <<", has_dungeons" + <<", has_caves" <<", completely_ug" <<", some_part_ug" <<" "<setInventoryTextureCube("stone.png", "stone.png", "stone.png"); f->param_type = CPT_MINERAL; f->is_ground_content = true; - f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + f->dug_item = std::string("MaterialItem ")+itos(CONTENT_COBBLE)+" 1"; i = CONTENT_GRASS; f = &g_content_features[i]; @@ -284,6 +284,7 @@ void init_mapnode() f->setInventoryTexture("torch_on_floor.png"); f->param_type = CPT_LIGHT; f->light_propagates = true; + f->sunlight_propagates = true; f->solidness = 0; // drawn separately, makes no faces f->walkable = false; f->wall_mounted = true; @@ -321,10 +322,28 @@ void init_mapnode() f->setAllTextures("furnace_side.png"); f->setTexture(5, "furnace_front.png"); // Z- f->setInventoryTexture("furnace_front.png"); - f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + //f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + f->dug_item = std::string("MaterialItem ")+itos(CONTENT_COBBLE)+" 6"; if(f->initial_metadata == NULL) f->initial_metadata = new FurnaceNodeMetadata(); + i = CONTENT_COBBLE; + f = &g_content_features[i]; + f->setAllTextures("cobble.png"); + f->setInventoryTextureCube("cobble.png", "cobble.png", "cobble.png"); + f->param_type = CPT_NONE; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + + i = CONTENT_STEEL; + f = &g_content_features[i]; + f->setAllTextures("steel_block.png"); + f->setInventoryTextureCube("steel_block.png", "steel_block.png", + "steel_block.png"); + f->param_type = CPT_NONE; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + } v3s16 facedir_rotate(u8 facedir, v3s16 dir) diff --git a/src/mapnode.h b/src/mapnode.h index 04234830..f359ecbb 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -98,6 +98,8 @@ void init_content_inventory_texture_paths(); #define CONTENT_CHEST 15 #define CONTENT_FURNACE 16 //#define CONTENT_WORKBENCH 17 +#define CONTENT_COBBLE 18 +#define CONTENT_STEEL 19 /* Content feature list diff --git a/src/materials.cpp b/src/materials.cpp index 2e85950e..2e33abeb 100644 --- a/src/materials.cpp +++ b/src/materials.cpp @@ -15,12 +15,40 @@ void setStoneLikeDiggingProperties(u8 material, float toughness) g_material_properties[material].setDiggingProperties("WPick", DiggingProperties(true, 1.3*toughness, 65535./30.*toughness)); g_material_properties[material].setDiggingProperties("STPick", - DiggingProperties(true, 0.65*toughness, 65535./100.*toughness)); + DiggingProperties(true, 0.75*toughness, 65535./100.*toughness)); + g_material_properties[material].setDiggingProperties("SteelPick", + DiggingProperties(true, 0.50*toughness, 65535./333.*toughness)); /*g_material_properties[material].setDiggingProperties("MesePick", DiggingProperties(true, 0.0*toughness, 65535./20.*toughness));*/ } +void setDirtLikeDiggingProperties(u8 material, float toughness) +{ + g_material_properties[material].setDiggingProperties("", + DiggingProperties(true, 0.75*toughness, 0)); + + g_material_properties[material].setDiggingProperties("WShovel", + DiggingProperties(true, 0.4*toughness, 65535./50.*toughness)); + g_material_properties[material].setDiggingProperties("STShovel", + DiggingProperties(true, 0.2*toughness, 65535./150.*toughness)); + g_material_properties[material].setDiggingProperties("SteelShovel", + DiggingProperties(true, 0.15*toughness, 65535./400.*toughness)); +} + +void setWoodLikeDiggingProperties(u8 material, float toughness) +{ + g_material_properties[material].setDiggingProperties("", + DiggingProperties(true, 3.0*toughness, 0)); + + g_material_properties[material].setDiggingProperties("WAxe", + DiggingProperties(true, 1.5*toughness, 65535./30.*toughness)); + g_material_properties[material].setDiggingProperties("STAxe", + DiggingProperties(true, 0.75*toughness, 65535./100.*toughness)); + g_material_properties[material].setDiggingProperties("SteelAxe", + DiggingProperties(true, 0.5*toughness, 65535./333.*toughness)); +} + void initializeMaterialProperties() { /* @@ -29,45 +57,29 @@ void initializeMaterialProperties() Add some digging properties to them. */ - + setStoneLikeDiggingProperties(CONTENT_STONE, 1.0); + setStoneLikeDiggingProperties(CONTENT_MESE, 0.5); + setStoneLikeDiggingProperties(CONTENT_COALSTONE, 1.5); + setStoneLikeDiggingProperties(CONTENT_FURNACE, 3.0); + setStoneLikeDiggingProperties(CONTENT_COBBLE, 1.0); + setStoneLikeDiggingProperties(CONTENT_STEEL, 5.0); - g_material_properties[CONTENT_GRASS].setDiggingProperties("", - DiggingProperties(true, 0.4, 0)); + setDirtLikeDiggingProperties(CONTENT_MUD, 1.0); + setDirtLikeDiggingProperties(CONTENT_GRASS, 1.0); + setDirtLikeDiggingProperties(CONTENT_GRASS_FOOTSTEPS, 1.0); + setDirtLikeDiggingProperties(CONTENT_SAND, 1.0); + + setWoodLikeDiggingProperties(CONTENT_TREE, 1.0); + setWoodLikeDiggingProperties(CONTENT_LEAVES, 0.15); + setWoodLikeDiggingProperties(CONTENT_WOOD, 0.75); + setWoodLikeDiggingProperties(CONTENT_CHEST, 1.0); + g_material_properties[CONTENT_SIGN_WALL].setDiggingProperties("", + DiggingProperties(true, 0.5, 0)); g_material_properties[CONTENT_TORCH].setDiggingProperties("", DiggingProperties(true, 0.0, 0)); - - g_material_properties[CONTENT_TREE].setDiggingProperties("", - DiggingProperties(true, 1.5, 0)); - - g_material_properties[CONTENT_LEAVES].setDiggingProperties("", - DiggingProperties(true, 0.35, 0)); - - g_material_properties[CONTENT_GRASS_FOOTSTEPS].setDiggingProperties("", - DiggingProperties(true, 0.5, 0)); - - setStoneLikeDiggingProperties(CONTENT_MESE, 0.5); - - g_material_properties[CONTENT_MUD].setDiggingProperties("", - DiggingProperties(true, 0.4, 0)); - - setStoneLikeDiggingProperties(CONTENT_COALSTONE, 1.5); - - g_material_properties[CONTENT_WOOD].setDiggingProperties("", - DiggingProperties(true, 1.0, 0)); - g_material_properties[CONTENT_SAND].setDiggingProperties("", - DiggingProperties(true, 0.4, 0)); - - g_material_properties[CONTENT_CHEST].setDiggingProperties("", - DiggingProperties(true, 1.0, 0)); - - setStoneLikeDiggingProperties(CONTENT_FURNACE, 1.0); - - g_material_properties[CONTENT_SIGN_WALL].setDiggingProperties("", - DiggingProperties(true, 0.0, 0)); - /* Add MesePick to everything */ diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp index 21b4ed01..8b21856d 100644 --- a/src/nodemetadata.cpp +++ b/src/nodemetadata.cpp @@ -165,6 +165,18 @@ std::string ChestNodeMetadata::infoText() { return "Chest"; } +bool ChestNodeMetadata::nodeRemovalDisabled() +{ + /* + Disable removal if chest contains something + */ + InventoryList *list = m_inventory->getList("0"); + if(list == NULL) + return true; + if(list->getUsedSlots() == 0) + return true; + return false; +} /* FurnaceNodeMetadata @@ -266,7 +278,7 @@ bool FurnaceNodeMetadata::step(float dtime) // Start only if there are free slots in dst, so that it can // accomodate any result item - if(dst_list->getFreeSlots() > 0) + if(dst_list->getFreeSlots() > 0 && src_item && src_item->isCookable()) { m_src_totaltime = 3; } @@ -281,11 +293,12 @@ bool FurnaceNodeMetadata::step(float dtime) //dstream<<"Furnace is active"<= m_src_totaltime && m_src_totaltime > 0.001) + if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001 + && src_item) { - src_list->decrementMaterials(1); InventoryItem *cookresult = src_item->createCookResult(); dst_list->addItem(cookresult); + src_list->decrementMaterials(1); m_src_time = 0; m_src_totaltime = 0; } diff --git a/src/nodemetadata.h b/src/nodemetadata.h index c38ab131..e56bff17 100644 --- a/src/nodemetadata.h +++ b/src/nodemetadata.h @@ -61,6 +61,7 @@ public: virtual void inventoryModified(){} // A step in time. Returns true if metadata changed. virtual bool step(float dtime) {return false;} + virtual bool nodeRemovalDisabled(){return false;} protected: static void registerType(u16 id, Factory f); @@ -100,6 +101,8 @@ public: virtual std::string infoText(); virtual Inventory* getInventory() {return m_inventory;} + virtual bool nodeRemovalDisabled(); + private: Inventory *m_inventory; }; diff --git a/src/server.cpp b/src/server.cpp index c405af3f..9b3e6e3e 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2033,31 +2033,40 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) u8 material; u8 mineral = MINERAL_NONE; + bool cannot_remove_node = false; + try { MapNode n = m_env.getMap().getNode(p_under); - // Get material at position - material = n.d; - // If it's not diggable, do nothing - if(content_diggable(material) == false) - { - derr_server<<"Server: Not finishing digging: Node not diggable" - <SetBlockNotSent(blockpos); - - return; - } // Get mineral mineral = n.getMineral(); + // Get material at position + material = n.d; + // If not yet cancelled + if(cannot_remove_node == false) + { + // If it's not diggable, do nothing + if(content_diggable(material) == false) + { + derr_server<<"Server: Not finishing digging: " + <<"Node not diggable" + <nodeRemovalDisabled() == true) + { + derr_server<<"Server: Not finishing digging: " + <<"Node metadata disables removal" + <SetBlockNotSent(blockpos); + return; } @@ -3016,9 +3046,9 @@ void Server::SendInventory(u16 peer_id) if(!found) { ItemSpec specs[9]; - specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_STONE); - specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_STONE); - specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_STONE); + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); if(checkItemCombination(items, specs)) @@ -3028,6 +3058,22 @@ void Server::SendInventory(u16 peer_id) } } + // Steel pick + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("SteelPick", 0)); + found = true; + } + } + // Mese pick if(!found) { @@ -3044,7 +3090,97 @@ void Server::SendInventory(u16 peer_id) } } - // Chest1 + // Wooden showel + if(!found) + { + ItemSpec specs[9]; + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("WShovel", 0)); + found = true; + } + } + + // Stone showel + if(!found) + { + ItemSpec specs[9]; + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_STONE); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("STShovel", 0)); + found = true; + } + } + + // Steel showel + if(!found) + { + ItemSpec specs[9]; + specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("SteelShovel", 0)); + found = true; + } + } + + // Wooden axe + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("WAxe", 0)); + found = true; + } + } + + // Stone axe + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("STAxe", 0)); + found = true; + } + } + + // Steel axe + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("SteelAxe", 0)); + found = true; + } + } + + // Chest if(!found) { ItemSpec specs[9]; @@ -3063,6 +3199,45 @@ void Server::SendInventory(u16 peer_id) } } + // Furnace + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new MaterialItem(CONTENT_FURNACE, 1)); + found = true; + } + } + + // Steel block + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new MaterialItem(CONTENT_STEEL, 1)); + found = true; + } + } + } } // if creative_mode == false @@ -3350,6 +3525,7 @@ void setCreativeInventory(Player *player) // CONTENT_IGNORE-terminated list u8 material_items[] = { CONTENT_TORCH, + CONTENT_COBBLE, CONTENT_MUD, CONTENT_STONE, CONTENT_SAND,