# Makefile for Irrlicht Examples\r
# It's usually sufficient to change just the target name and source file list\r
# and be sure that CXX is set to a valid compiler\r
-SOURCE_FILES = guiTextInputMenu.cpp guiInventoryMenu.cpp irrlichtwrapper.cpp guiPauseMenu.cpp defaultsettings.cpp mapnode.cpp tile.cpp voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp\r
+SOURCE_FILES = materials.cpp guiTextInputMenu.cpp guiInventoryMenu.cpp irrlichtwrapper.cpp guiPauseMenu.cpp defaultsettings.cpp mapnode.cpp tile.cpp voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp\r
\r
DEBUG_TARGET = debugtest\r
DEBUG_SOURCES = $(addprefix src/, $(SOURCE_FILES))\r
FAST_OBJECTS = $(addprefix $(FAST_BUILD_DIR)/, $(SOURCE_FILES:.cpp=.o))\r
\r
SERVER_TARGET = server\r
-SERVER_SOURCE_FILES = defaultsettings.cpp mapnode.cpp voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp servermain.cpp test.cpp\r
+SERVER_SOURCE_FILES = materials.cpp defaultsettings.cpp mapnode.cpp voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp servermain.cpp test.cpp\r
SERVER_SOURCES = $(addprefix src/, $(SERVER_SOURCE_FILES))\r
SERVER_BUILD_DIR = serverbuild\r
SERVER_OBJECTS = $(addprefix $(SERVER_BUILD_DIR)/, $(SERVER_SOURCE_FILES:.cpp=.o))\r
{
return m_wear;
}
+ // Returns true if weared out
+ bool addWear(u16 add)
+ {
+ if(m_wear >= 65535 - add)
+ {
+ m_wear = 65535;
+ return true;
+ }
+ else
+ {
+ m_wear += add;
+ return false;
+ }
+ }
private:
std::string m_toolname;
u16 m_wear;
- Make separate classes for client and server\r
- Client should not discriminate between blocks, server should\r
- Make other players utilize the same framework\r
+ - This is also needed for objects that don't get sent to client\r
+ but are used for triggers etc\r
\r
TODO: Draw big amounts of torches better (that is, throw them in the\r
same meshbuffer (can the meshcollector class be used?))\r
TODO: Check if the usage of Client::isFetchingBlocks() in\r
updateViewingRange() actually does something\r
\r
+TODO: Make an option to the server to disable building and digging near\r
+ the starting position\r
+\r
Doing now:\r
======================================================================\r
\r
#include "guiPauseMenu.h"\r
#include "guiInventoryMenu.h"\r
#include "guiTextInputMenu.h"\r
+#include "materials.h"\r
\r
IrrlichtWrapper *g_irrlicht;\r
\r
s32 m_selection;\r
};\r
\r
+// Chat data\r
+struct ChatLine\r
+{\r
+ ChatLine():\r
+ age(0.0)\r
+ {\r
+ }\r
+ ChatLine(const std::wstring &a_text):\r
+ age(0.0),\r
+ text(a_text)\r
+ {\r
+ }\r
+ float age;\r
+ std::wstring text;\r
+};\r
+\r
int main(int argc, char *argv[])\r
{\r
/*\r
debug_stacks_init();\r
\r
DSTACK(__FUNCTION_NAME);\r
+ \r
+ initializeMaterialProperties();\r
\r
try\r
{\r
L"Chat here\nOther line\nOther line\nOther line\nOther line",\r
core::rect<s32>(70, 60, 795, 150),\r
false, true);\r
- core::list<std::wstring> chat_lines;\r
- //chat_lines.push_back(L"Minetest-c55 up and running!");\r
+ core::list<ChatLine> chat_lines;\r
\r
/*\r
Some statistics are collected in these\r
if(g_input->getLeftState())\r
{\r
MapNode n = client.getNode(nodepos);\r
-\r
- // TODO: Get this from some table that is sent by server\r
- float dig_time_complete = 0.5;\r
- if(n.d == CONTENT_STONE || n.d == CONTENT_COALSTONE)\r
+ \r
+ // Get tool name. Default is "" = bare hands\r
+ std::string toolname = "";\r
+ InventoryList *mlist = local_inventory.getList("main");\r
+ if(mlist != NULL)\r
{\r
- dig_time_complete = 10.0;\r
-\r
- InventoryList *mlist = local_inventory.getList("main");\r
- if(mlist != NULL)\r
+ InventoryItem *item = mlist->getItem(g_selected_item);\r
+ if(item && (std::string)item->getName() == "ToolItem")\r
{\r
- InventoryItem *item = mlist->getItem(g_selected_item);\r
- if(item && (std::string)item->getName() == "ToolItem")\r
- {\r
- ToolItem *titem = (ToolItem*)item;\r
- if(titem->getToolName() == "WPick")\r
- {\r
- dig_time_complete = 1.2;\r
- }\r
- else if(titem->getToolName() == "STPick")\r
- {\r
- dig_time_complete = 0.6;\r
- }\r
- }\r
+ ToolItem *titem = (ToolItem*)item;\r
+ toolname = titem->getToolName();\r
}\r
}\r
- else if(n.d == CONTENT_TORCH)\r
+\r
+ // Get digging properties for material and tool\r
+ u8 material = n.d;\r
+ DiggingProperties prop =\r
+ getDiggingProperties(material, toolname);\r
+ \r
+ float dig_time_complete = 0.0;\r
+\r
+ if(prop.diggable == false)\r
+ {\r
+ /*dstream<<"Material "<<(int)material\r
+ <<" not diggable with \""\r
+ <<toolname<<"\""<<std::endl;*/\r
+ // I guess nobody will wait for this long\r
+ dig_time_complete = 10000000.0;\r
+ }\r
+ else\r
{\r
- dig_time_complete = 0.0;\r
+ dig_time_complete = prop.time;\r
}\r
\r
if(dig_time_complete >= 0.001)\r
Get chat messages from client\r
*/\r
{\r
- // Get messages\r
+ // Get new messages\r
std::wstring message;\r
while(client.getChatMessage(message))\r
{\r
- chat_lines.push_back(message);\r
- if(chat_lines.size() > 5)\r
+ chat_lines.push_back(ChatLine(message));\r
+ if(chat_lines.size() > 7)\r
{\r
- core::list<std::wstring>::Iterator\r
+ core::list<ChatLine>::Iterator\r
i = chat_lines.begin();\r
chat_lines.erase(i);\r
}\r
// Append them to form the whole static text and throw\r
// it to the gui element\r
std::wstring whole;\r
- for(core::list<std::wstring>::Iterator\r
+ u16 to_be_removed_count = 0;\r
+ for(core::list<ChatLine>::Iterator\r
i = chat_lines.begin();\r
i != chat_lines.end(); i++)\r
{\r
- whole += (*i) + L'\n';\r
+ (*i).age += dtime;\r
+ if((*i).age > 30.0)\r
+ {\r
+ to_be_removed_count++;\r
+ continue;\r
+ }\r
+ whole += (*i).text + L'\n';\r
+ }\r
+ for(u16 i=0; i<to_be_removed_count; i++)\r
+ {\r
+ core::list<ChatLine>::Iterator\r
+ i = chat_lines.begin();\r
+ chat_lines.erase(i);\r
}\r
chat_guitext->setText(whole.c_str());\r
// Update gui element size and position\r
{TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER},
{TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD},
{TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE},
+ {TILE_WOOD,TILE_WOOD,TILE_WOOD,TILE_WOOD,TILE_WOOD,TILE_WOOD},
};
const char * g_content_inventory_textures[USEFUL_CONTENT_COUNT] =
"../data/water.png",
"../data/cloud.png",
"../data/coalstone.png",
+ "../data/wood.png",
};
CONTENT_OCEAN,
CONTENT_CLOUD,
CONTENT_COALSTONE,
+ CONTENT_WOOD,
// This is set to the number of the actual values in this enum
USEFUL_CONTENT_COUNT
/*
If true, the material allows lossless sunlight propagation.
+ NOTE: It doesn't seem to go through torches regardlessly of this
*/
inline bool sunlight_propagates_content(u8 m)
{
*/
inline bool is_ground_content(u8 m)
{
- return(
- m == CONTENT_STONE ||
- m == CONTENT_GRASS ||
- m == CONTENT_GRASS_FOOTSTEPS ||
- m == CONTENT_MESE ||
- m == CONTENT_MUD ||
- m == CONTENT_COALSTONE
- );
+ return (m != CONTENT_WATER
+ && m != CONTENT_TORCH
+ && m != CONTENT_TREE
+ && m != CONTENT_LEAVES
+ && m != CONTENT_OCEAN
+ && m != CONTENT_CLOUD);
}
inline bool is_mineral(u8 c)
|| c == CONTENT_COALSTONE);
}
-/*inline bool content_has_faces(u8 c)
+inline bool liquid_replaces_content(u8 c)
{
- return (m != CONTENT_IGNORE
- && m != CONTENT_AIR
- && m != CONTENT_TORCH);
-}*/
+ return (c == CONTENT_AIR || c == CONTENT_TORCH);
+}
+
+/*
+ When placing a node, drection info is added to it if this is true
+*/
+inline bool content_directional(u8 c)
+{
+ return (c == CONTENT_TORCH);
+}
/*
Nodes make a face if contents differ and solidness differs.
return 2;
}
-inline bool liquid_replaces_content(u8 c)
-{
- return (c == CONTENT_AIR || c == CONTENT_TORCH);
-}
-
-/*
- When placing a node, drection info is added to it if this is true
-*/
-inline bool content_directional(u8 c)
-{
- return (c == CONTENT_TORCH);
-}
-
/*
Packs directions like (1,0,0), (1,-1,0)
*/
--- /dev/null
+#include "materials.h"
+
+#define MATERIAL_PROPERTIES_COUNT 256
+
+// These correspond to the CONTENT_* constants
+MaterialProperties g_material_properties[MATERIAL_PROPERTIES_COUNT];
+
+bool g_material_properties_initialized = false;
+
+void setStoneLikeDiggingProperties(u8 material, float toughness)
+{
+ g_material_properties[material].setDiggingProperties("",
+ DiggingProperties(true, 15.0*toughness, 0));
+ g_material_properties[material].setDiggingProperties("WPick",
+ DiggingProperties(true, 2.0*toughness, 65535./20.*toughness));
+ g_material_properties[material].setDiggingProperties("STPick",
+ DiggingProperties(true, 1.0*toughness, 65535./50.*toughness));
+}
+
+void initializeMaterialProperties()
+{
+ /*
+ Now, the g_material_properties array is already initialized
+ by the constructors to such that no digging is possible.
+
+ Add some digging properties to them.
+ */
+
+ setStoneLikeDiggingProperties(CONTENT_STONE, 1.0);
+
+ g_material_properties[CONTENT_GRASS].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.5, 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.5, 0));
+
+ setStoneLikeDiggingProperties(CONTENT_COALSTONE, 1.5);
+
+ g_material_properties[CONTENT_WOOD].setDiggingProperties("",
+ DiggingProperties(true, 1.0, 0));
+
+
+ g_material_properties_initialized = true;
+}
+
+MaterialProperties * getMaterialProperties(u8 material)
+{
+ assert(g_material_properties_initialized);
+ return &g_material_properties[material];
+}
+
+DiggingProperties getDiggingProperties(u8 material, const std::string &tool)
+{
+ MaterialProperties *mprop = getMaterialProperties(material);
+ if(mprop == NULL)
+ // Not diggable
+ return DiggingProperties();
+
+ return mprop->getDiggingProperties(tool);
+}
+
--- /dev/null
+/*
+Minetest-c55
+Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef MATERIALS_HEADER
+#define MATERIALS_HEADER
+
+/*
+ Material properties
+*/
+
+#include "common_irrlicht.h"
+#include "inventory.h"
+#include <string>
+
+struct DiggingProperties
+{
+ DiggingProperties():
+ diggable(false),
+ time(0.0),
+ wear(0)
+ {
+ }
+ DiggingProperties(bool a_diggable, float a_time, u16 a_wear):
+ diggable(a_diggable),
+ time(a_time),
+ wear(a_wear)
+ {
+ }
+ bool diggable;
+ // Digging time in seconds
+ float time;
+ // Caused wear
+ u16 wear;
+};
+
+class MaterialProperties
+{
+public:
+ MaterialProperties()
+ {
+ dstream<<__FUNCTION_NAME<<std::endl;
+ }
+
+ void setDiggingProperties(const std::string toolname,
+ const DiggingProperties &prop)
+ {
+ m_digging_properties[toolname] = prop;
+ }
+
+ DiggingProperties getDiggingProperties(const std::string toolname)
+ {
+ core::map<std::string, DiggingProperties>::Node *n;
+ n = m_digging_properties.find(toolname);
+ if(n == NULL)
+ {
+ // Not diggable by this tool, try to get defaults
+ n = m_digging_properties.find("");
+ if(n == NULL)
+ {
+ // Not diggable at all
+ return DiggingProperties();
+ }
+ }
+ // Return found properties
+ return n->getValue();
+ }
+
+private:
+ // toolname="": default properties (digging by hand)
+ // Key is toolname
+ core::map<std::string, DiggingProperties> m_digging_properties;
+};
+
+void initializeMaterialProperties();
+
+// Material correspond to the CONTENT_* constants
+MaterialProperties * getMaterialProperties(u8 material);
+// For getting the default properties, set tool=""
+DiggingProperties getDiggingProperties(u8 material, const std::string &tool);
+
+#endif
+
#include "main.h"
#include "constants.h"
#include "voxel.h"
+#include "materials.h"
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
if(g_settings.getBool("creative_mode") == false)
{
- // Add to inventory and send inventory
+ /*
+ Wear out tool
+ */
+ InventoryList *mlist = player->inventory.getList("main");
+ if(mlist != NULL)
+ {
+ InventoryItem *item = mlist->getItem(item_i);
+ if(item && (std::string)item->getName() == "ToolItem")
+ {
+ ToolItem *titem = (ToolItem*)item;
+ std::string toolname = titem->getToolName();
+
+ // Get digging properties for material and tool
+ DiggingProperties prop =
+ getDiggingProperties(material, toolname);
+
+ if(prop.diggable == false)
+ {
+ derr_server<<"Server: WARNING: Player digged"
+ <<" with impossible material + tool"
+ <<" combination"<<std::endl;
+ }
+
+ bool weared_out = titem->addWear(prop.wear);
+
+ if(weared_out)
+ {
+ mlist->deleteItem(item_i);
+ }
+ }
+ }
+
+ /*
+ Add digged item to inventory
+ */
InventoryItem *item = new MaterialItem(material, 1);
player->inventory.addItem("main", item);
+
+ /*
+ Send inventory
+ */
SendInventory(player->peer_id);
}
c.peer_id = peer->id;
c.timeout = false;
m_peer_change_queue.push_back(c);
-
-#if 0
- // NOTE: Connection is already locked when this is called.
- // NOTE: Environment is already locked when this is called.
-
- // Error check
- core::map<u16, RemoteClient*>::Node *n;
- n = m_clients.find(peer->id);
- // The client shouldn't already exist
- assert(n == NULL);
-
- // Create client
- RemoteClient *client = new RemoteClient();
- client->peer_id = peer->id;
- m_clients.insert(client->peer_id, client);
-
- // Create player
- {
- Player *player = m_env.getPlayer(peer->id);
-
- // The player shouldn't already exist
- assert(player == NULL);
-
- player = new ServerRemotePlayer();
- player->peer_id = peer->id;
-
- /*
- Set player position
- */
-
- // We're going to throw the player to this position
- //v2s16 nodepos(29990,29990);
- //v2s16 nodepos(9990,9990);
- v2s16 nodepos(0,0);
- v2s16 sectorpos = getNodeSectorPos(nodepos);
- // Get zero sector (it could have been unloaded to disk)
- m_env.getMap().emergeSector(sectorpos);
- // Get ground height at origin
- f32 groundheight = m_env.getMap().getGroundHeight(nodepos, true);
- // The sector should have been generated -> groundheight exists
- assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE);
- // Don't go underwater
- if(groundheight < WATER_LEVEL)
- groundheight = WATER_LEVEL;
-
- player->setPosition(intToFloat(v3s16(
- nodepos.X,
- groundheight + 1,
- nodepos.Y
- )));
-
- /*
- Add player to environment
- */
-
- m_env.addPlayer(player);
-
- /*
- Add stuff to inventory
- */
-
- if(g_settings.getBool("creative_mode"))
- {
- // Give a good pick
- {
- InventoryItem *item = new ToolItem("STPick", 32000);
- void* r = player->inventory.addItem("main", item);
- assert(r == NULL);
- }
- // Give all materials
- assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
- for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
- {
- // Skip some materials
- if(i == CONTENT_OCEAN)
- continue;
-
- InventoryItem *item = new MaterialItem(i, 1);
- player->inventory.addItem("main", item);
- }
- // Sign
- {
- InventoryItem *item = new MapBlockObjectItem("Sign Example text");
- void* r = player->inventory.addItem("main", item);
- assert(r == NULL);
- }
- /*// Rat
- {
- InventoryItem *item = new MapBlockObjectItem("Rat");
- bool r = player->inventory.addItem("main", item);
- assert(r == true);
- }*/
- }
- else
- {
- {
- InventoryItem *item = new CraftItem("Stick", 4);
- void* r = player->inventory.addItem("main", item);
- assert(r == NULL);
- }
- {
- InventoryItem *item = new ToolItem("WPick", 32000);
- void* r = player->inventory.addItem("main", item);
- assert(r == NULL);
- }
- {
- InventoryItem *item = new ToolItem("STPick", 32000);
- void* r = player->inventory.addItem("main", item);
- assert(r == NULL);
- }
- /*// Give some lights
- {
- InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999);
- bool r = player->inventory.addItem("main", item);
- assert(r == true);
- }
- // and some signs
- for(u16 i=0; i<4; i++)
- {
- InventoryItem *item = new MapBlockObjectItem("Sign Example text");
- bool r = player->inventory.addItem("main", item);
- assert(r == true);
- }*/
- /*// Give some other stuff
- {
- InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
- bool r = player->inventory.addItem("main", item);
- assert(r == true);
- }*/
- }
- }
-#endif
}
void Server::deletingPeer(con::Peer *peer, bool timeout)
c.peer_id = peer->id;
c.timeout = timeout;
m_peer_change_queue.push_back(c);
-
-#if 0
- // NOTE: Connection is already locked when this is called.
-
- // NOTE: Environment is already locked when this is called.
- // NOTE: Locking environment cannot be moved here because connection
- // is already locked and env has to be locked before
-
- // Error check
- core::map<u16, RemoteClient*>::Node *n;
- n = m_clients.find(peer->id);
- // The client should exist
- assert(n != NULL);
-
- // Send information about leaving in chat
- {
- std::wstring name = L"unknown";
- Player *player = m_env.getPlayer(peer->id);
- if(player != NULL)
- name = narrow_to_wide(player->getName());
-
- std::wstring message;
- message += L"*** ";
- message += name;
- message += L" left game";
- BroadcastChatMessage(message);
- }
-
- // Delete player
- {
- m_env.removePlayer(peer->id);
- }
-
- // Delete client
- delete m_clients[peer->id];
- m_clients.remove(peer->id);
-
- // Send player info to all clients
- SendPlayerInfos();
-#endif
}
void Server::SendObjectData(float dtime)
m_con.SendToAll(0, data, true);
}
+enum ItemSpecType
+{
+ ITEM_NONE,
+ ITEM_MATERIAL,
+ ITEM_CRAFT,
+ ITEM_TOOL,
+ ITEM_MBO
+};
+
+struct ItemSpec
+{
+ ItemSpec():
+ type(ITEM_NONE)
+ {
+ }
+ ItemSpec(enum ItemSpecType a_type, std::string a_name):
+ type(a_type),
+ name(a_name),
+ num(65535)
+ {
+ }
+ ItemSpec(enum ItemSpecType a_type, u16 a_num):
+ type(a_type),
+ name(""),
+ num(a_num)
+ {
+ }
+ enum ItemSpecType type;
+ // Only other one of these is used
+ std::string name;
+ u16 num;
+};
+
+/*
+ items: a pointer to an array of 9 pointers to items
+ specs: a pointer to an array of 9 ItemSpecs
+*/
+bool checkItemCombination(InventoryItem **items, ItemSpec *specs)
+{
+ u16 items_min_x = 100;
+ u16 items_max_x = 100;
+ u16 items_min_y = 100;
+ u16 items_max_y = 100;
+ for(u16 y=0; y<3; y++)
+ for(u16 x=0; x<3; x++)
+ {
+ if(items[y*3 + x] == NULL)
+ continue;
+ if(items_min_x == 100 || x < items_min_x)
+ items_min_x = x;
+ if(items_min_y == 100 || y < items_min_y)
+ items_min_y = y;
+ if(items_max_x == 100 || x > items_max_x)
+ items_max_x = x;
+ if(items_max_y == 100 || y > items_max_y)
+ items_max_y = y;
+ }
+ // No items at all, just return false
+ if(items_min_x == 100)
+ return false;
+
+ u16 items_w = items_max_x - items_min_x + 1;
+ u16 items_h = items_max_y - items_min_y + 1;
+
+ u16 specs_min_x = 100;
+ u16 specs_max_x = 100;
+ u16 specs_min_y = 100;
+ u16 specs_max_y = 100;
+ for(u16 y=0; y<3; y++)
+ for(u16 x=0; x<3; x++)
+ {
+ if(specs[y*3 + x].type == ITEM_NONE)
+ continue;
+ if(specs_min_x == 100 || x < specs_min_x)
+ specs_min_x = x;
+ if(specs_min_y == 100 || y < specs_min_y)
+ specs_min_y = y;
+ if(specs_max_x == 100 || x > specs_max_x)
+ specs_max_x = x;
+ if(specs_max_y == 100 || y > specs_max_y)
+ specs_max_y = y;
+ }
+ // No specs at all, just return false
+ if(specs_min_x == 100)
+ return false;
+
+ u16 specs_w = specs_max_x - specs_min_x + 1;
+ u16 specs_h = specs_max_y - specs_min_y + 1;
+
+ // Different sizes
+ if(items_w != specs_w || items_h != specs_h)
+ return false;
+
+ for(u16 y=0; y<specs_h; y++)
+ for(u16 x=0; x<specs_w; x++)
+ {
+ u16 items_x = items_min_x + x;
+ u16 items_y = items_min_y + y;
+ u16 specs_x = specs_min_x + x;
+ u16 specs_y = specs_min_y + y;
+ InventoryItem *item = items[items_y * 3 + items_x];
+ ItemSpec &spec = specs[specs_y * 3 + specs_x];
+
+ if(spec.type == ITEM_NONE)
+ {
+ // Has to be no item
+ if(item != NULL)
+ return false;
+ continue;
+ }
+
+ // There should be an item
+ if(item == NULL)
+ return false;
+
+ std::string itemname = item->getName();
+
+ if(spec.type == ITEM_MATERIAL)
+ {
+ if(itemname != "MaterialItem")
+ return false;
+ MaterialItem *mitem = (MaterialItem*)item;
+ if(mitem->getMaterial() != spec.num)
+ return false;
+ }
+ else if(spec.type == ITEM_CRAFT)
+ {
+ if(itemname != "CraftItem")
+ return false;
+ CraftItem *mitem = (CraftItem*)item;
+ if(mitem->getSubName() != spec.name)
+ return false;
+ }
+ else if(spec.type == ITEM_TOOL)
+ {
+ // Not supported yet
+ assert(0);
+ }
+ else if(spec.type == ITEM_MBO)
+ {
+ // Not supported yet
+ assert(0);
+ }
+ else
+ {
+ // Not supported yet
+ assert(0);
+ }
+ }
+
+ return true;
+}
+
void Server::SendInventory(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
{
items[i] = clist->getItem(i);
}
+
+ bool found = false;
+
+ // Wood
+ if(!found)
+ {
+ ItemSpec specs[9];
+ specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
+ if(checkItemCombination(items, specs))
+ {
+ rlist->addItem(new MaterialItem(CONTENT_WOOD, 4));
+ found = true;
+ }
+ }
+
+ // Stick
+ if(!found)
+ {
+ ItemSpec specs[9];
+ specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ if(checkItemCombination(items, specs))
+ {
+ rlist->addItem(new CraftItem("Stick", 4));
+ found = true;
+ }
+ }
+
// Sign
- if(clist->getUsedSlots() == 1 && items[0])
+ if(!found)
{
- if((std::string)items[0]->getName() == "MaterialItem")
+ ItemSpec specs[9];
+ specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+ if(checkItemCombination(items, specs))
{
- MaterialItem *mitem = (MaterialItem*)items[0];
- if(mitem->getMaterial() == CONTENT_TREE)
- {
- rlist->addItem(new MapBlockObjectItem("Sign"));
- }
+ rlist->addItem(new MapBlockObjectItem("Sign"));
+ found = true;
}
}
+
// Torch
- if(clist->getUsedSlots() == 2 && items[0] && items[3])
- {
- if(
- (std::string)items[0]->getName() == "MaterialItem"
- && ((MaterialItem*)items[0])->getMaterial() == CONTENT_COALSTONE
- && (std::string)items[3]->getName() == "MaterialItem"
- && ((MaterialItem*)items[3])->getMaterial() == CONTENT_TREE
- )
+ if(!found)
+ {
+ ItemSpec specs[9];
+ specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COALSTONE);
+ specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
+ if(checkItemCombination(items, specs))
{
rlist->addItem(new MaterialItem(CONTENT_TORCH, 4));
+ found = true;
}
}
+
+ // Wooden pick
+ if(!found)
+ {
+ ItemSpec specs[9];
+ specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
+ specs[2] = 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("WPick", 0));
+ found = true;
+ }
+ }
+
+ // Stone pick
+ 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[4] = ItemSpec(ITEM_CRAFT, "Stick");
+ specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
+ if(checkItemCombination(items, specs))
+ {
+ rlist->addItem(new ToolItem("STPick", 0));
+ found = true;
+ }
+ }
+
}
/*
}
else
{
+ {
+ InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
{
InventoryItem *item = new CraftItem("Stick", 4);
void* r = player->inventory.addItem("main", item);
DSTACK(__FUNCTION_NAME);
+ initializeMaterialProperties();
+
try
{
"../data/mud_with_grass.png",
"../data/cloud.png",
"../data/coalstone.png",
+ "../data/wood.png",
};
const char * tile_texture_path_get(u32 i)
TILE_MUD_WITH_GRASS,
TILE_CLOUD,
TILE_COALSTONE,
+ TILE_WOOD,
// Count of tile ids
TILES_COUNT