diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | data/stick.png | bin | 0 -> 947 bytes | |||
-rw-r--r-- | data/wood.png | bin | 0 -> 1400 bytes | |||
-rw-r--r-- | src/inventory.h | 14 | ||||
-rw-r--r-- | src/main.cpp | 102 | ||||
-rw-r--r-- | src/mapnode.cpp | 2 | ||||
-rw-r--r-- | src/mapnode.h | 45 | ||||
-rw-r--r-- | src/materials.cpp | 75 | ||||
-rw-r--r-- | src/materials.h | 98 | ||||
-rw-r--r-- | src/server.cpp | 471 | ||||
-rw-r--r-- | src/servermain.cpp | 2 | ||||
-rw-r--r-- | src/tile.cpp | 1 | ||||
-rw-r--r-- | src/tile.h | 1 |
13 files changed, 568 insertions, 247 deletions
@@ -1,7 +1,7 @@ # Makefile for Irrlicht Examples
# It's usually sufficient to change just the target name and source file list
# and be sure that CXX is set to a valid compiler
-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
+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
DEBUG_TARGET = debugtest
DEBUG_SOURCES = $(addprefix src/, $(SOURCE_FILES))
@@ -14,7 +14,7 @@ FAST_BUILD_DIR = fastbuild FAST_OBJECTS = $(addprefix $(FAST_BUILD_DIR)/, $(SOURCE_FILES:.cpp=.o))
SERVER_TARGET = server
-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
+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
SERVER_SOURCES = $(addprefix src/, $(SERVER_SOURCE_FILES))
SERVER_BUILD_DIR = serverbuild
SERVER_OBJECTS = $(addprefix $(SERVER_BUILD_DIR)/, $(SERVER_SOURCE_FILES:.cpp=.o))
diff --git a/data/stick.png b/data/stick.png Binary files differnew file mode 100644 index 000000000..7a4663cc3 --- /dev/null +++ b/data/stick.png diff --git a/data/wood.png b/data/wood.png Binary files differnew file mode 100644 index 000000000..57c1d7c12 --- /dev/null +++ b/data/wood.png diff --git a/src/inventory.h b/src/inventory.h index 13bd27d8b..ff0086102 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -390,6 +390,20 @@ public: { 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; diff --git a/src/main.cpp b/src/main.cpp index 1a9379e41..47dcbf70f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -167,6 +167,8 @@ TODO: Better handling of objects and mobs - Make separate classes for client and server
- Client should not discriminate between blocks, server should
- Make other players utilize the same framework
+ - This is also needed for objects that don't get sent to client
+ but are used for triggers etc
TODO: Draw big amounts of torches better (that is, throw them in the
same meshbuffer (can the meshcollector class be used?))
@@ -174,6 +176,9 @@ TODO: Draw big amounts of torches better (that is, throw them in the TODO: Check if the usage of Client::isFetchingBlocks() in
updateViewingRange() actually does something
+TODO: Make an option to the server to disable building and digging near
+ the starting position
+
Doing now:
======================================================================
@@ -239,6 +244,7 @@ TODO: Transferring of the table from server to client #include "guiPauseMenu.h"
#include "guiInventoryMenu.h"
#include "guiTextInputMenu.h"
+#include "materials.h"
IrrlichtWrapper *g_irrlicht;
@@ -1022,6 +1028,22 @@ private: s32 m_selection;
};
+// Chat data
+struct ChatLine
+{
+ ChatLine():
+ age(0.0)
+ {
+ }
+ ChatLine(const std::wstring &a_text):
+ age(0.0),
+ text(a_text)
+ {
+ }
+ float age;
+ std::wstring text;
+};
+
int main(int argc, char *argv[])
{
/*
@@ -1039,6 +1061,8 @@ int main(int argc, char *argv[]) debug_stacks_init();
DSTACK(__FUNCTION_NAME);
+
+ initializeMaterialProperties();
try
{
@@ -1541,8 +1565,7 @@ int main(int argc, char *argv[]) L"Chat here\nOther line\nOther line\nOther line\nOther line",
core::rect<s32>(70, 60, 795, 150),
false, true);
- core::list<std::wstring> chat_lines;
- //chat_lines.push_back(L"Minetest-c55 up and running!");
+ core::list<ChatLine> chat_lines;
/*
Some statistics are collected in these
@@ -2102,34 +2125,38 @@ int main(int argc, char *argv[]) if(g_input->getLeftState())
{
MapNode n = client.getNode(nodepos);
-
- // TODO: Get this from some table that is sent by server
- float dig_time_complete = 0.5;
- if(n.d == CONTENT_STONE || n.d == CONTENT_COALSTONE)
+
+ // Get tool name. Default is "" = bare hands
+ std::string toolname = "";
+ InventoryList *mlist = local_inventory.getList("main");
+ if(mlist != NULL)
{
- dig_time_complete = 10.0;
-
- InventoryList *mlist = local_inventory.getList("main");
- if(mlist != NULL)
+ InventoryItem *item = mlist->getItem(g_selected_item);
+ if(item && (std::string)item->getName() == "ToolItem")
{
- InventoryItem *item = mlist->getItem(g_selected_item);
- if(item && (std::string)item->getName() == "ToolItem")
- {
- ToolItem *titem = (ToolItem*)item;
- if(titem->getToolName() == "WPick")
- {
- dig_time_complete = 1.2;
- }
- else if(titem->getToolName() == "STPick")
- {
- dig_time_complete = 0.6;
- }
- }
+ ToolItem *titem = (ToolItem*)item;
+ toolname = titem->getToolName();
}
}
- else if(n.d == CONTENT_TORCH)
+
+ // Get digging properties for material and tool
+ u8 material = n.d;
+ DiggingProperties prop =
+ getDiggingProperties(material, toolname);
+
+ float dig_time_complete = 0.0;
+
+ if(prop.diggable == false)
+ {
+ /*dstream<<"Material "<<(int)material
+ <<" not diggable with \""
+ <<toolname<<"\""<<std::endl;*/
+ // I guess nobody will wait for this long
+ dig_time_complete = 10000000.0;
+ }
+ else
{
- dig_time_complete = 0.0;
+ dig_time_complete = prop.time;
}
if(dig_time_complete >= 0.001)
@@ -2305,14 +2332,14 @@ int main(int argc, char *argv[]) Get chat messages from client
*/
{
- // Get messages
+ // Get new messages
std::wstring message;
while(client.getChatMessage(message))
{
- chat_lines.push_back(message);
- if(chat_lines.size() > 5)
+ chat_lines.push_back(ChatLine(message));
+ if(chat_lines.size() > 7)
{
- core::list<std::wstring>::Iterator
+ core::list<ChatLine>::Iterator
i = chat_lines.begin();
chat_lines.erase(i);
}
@@ -2320,11 +2347,24 @@ int main(int argc, char *argv[]) // Append them to form the whole static text and throw
// it to the gui element
std::wstring whole;
- for(core::list<std::wstring>::Iterator
+ u16 to_be_removed_count = 0;
+ for(core::list<ChatLine>::Iterator
i = chat_lines.begin();
i != chat_lines.end(); i++)
{
- whole += (*i) + L'\n';
+ (*i).age += dtime;
+ if((*i).age > 30.0)
+ {
+ to_be_removed_count++;
+ continue;
+ }
+ whole += (*i).text + L'\n';
+ }
+ for(u16 i=0; i<to_be_removed_count; i++)
+ {
+ core::list<ChatLine>::Iterator
+ i = chat_lines.begin();
+ chat_lines.erase(i);
}
chat_guitext->setText(whole.c_str());
// Update gui element size and position
diff --git a/src/mapnode.cpp b/src/mapnode.cpp index a8e9f07fc..3dae653ed 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -43,6 +43,7 @@ u16 g_content_tiles[USEFUL_CONTENT_COUNT][6] = {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] = @@ -59,5 +60,6 @@ const char * g_content_inventory_textures[USEFUL_CONTENT_COUNT] = "../data/water.png", "../data/cloud.png", "../data/coalstone.png", + "../data/wood.png", }; diff --git a/src/mapnode.h b/src/mapnode.h index ad85d88e8..659d585b5 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -77,6 +77,7 @@ enum Content CONTENT_OCEAN, CONTENT_CLOUD, CONTENT_COALSTONE, + CONTENT_WOOD, // This is set to the number of the actual values in this enum USEFUL_CONTENT_COUNT @@ -96,6 +97,7 @@ inline bool light_propagates_content(u8 m) /* 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) { @@ -153,14 +155,12 @@ inline bool content_buildable_to(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) @@ -169,12 +169,18 @@ 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. @@ -201,19 +207,6 @@ inline u8 face_contents(u8 m1, u8 m2) 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) */ diff --git a/src/materials.cpp b/src/materials.cpp new file mode 100644 index 000000000..5c1419580 --- /dev/null +++ b/src/materials.cpp @@ -0,0 +1,75 @@ +#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); +} + diff --git a/src/materials.h b/src/materials.h new file mode 100644 index 000000000..ae2deac88 --- /dev/null +++ b/src/materials.h @@ -0,0 +1,98 @@ +/* +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 + diff --git a/src/server.cpp b/src/server.cpp index c0af61b98..e1f7ba739 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "main.h" #include "constants.h" #include "voxel.h" +#include "materials.h" #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0) @@ -1821,9 +1822,47 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) 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); } @@ -2404,138 +2443,6 @@ void Server::peerAdded(con::Peer *peer) 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) @@ -2549,46 +2456,6 @@ 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) @@ -2647,6 +2514,159 @@ void Server::SendPlayerInfos() 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); @@ -2670,31 +2690,96 @@ void Server::SendInventory(u16 peer_id) { 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; + } + } + } /* @@ -2959,6 +3044,16 @@ void Server::handlePeerChange(PeerChange &c) 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); assert(r == NULL); diff --git a/src/servermain.cpp b/src/servermain.cpp index c2d697cfe..b8bc0dc54 100644 --- a/src/servermain.cpp +++ b/src/servermain.cpp @@ -123,6 +123,8 @@ int main(int argc, char *argv[]) DSTACK(__FUNCTION_NAME); + initializeMaterialProperties(); + try { diff --git a/src/tile.cpp b/src/tile.cpp index 25d9c00d0..a9470dc8e 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -36,6 +36,7 @@ const char * g_tile_texture_paths[TILES_COUNT] = "../data/mud_with_grass.png", "../data/cloud.png", "../data/coalstone.png", + "../data/wood.png", }; const char * tile_texture_path_get(u32 i) diff --git a/src/tile.h b/src/tile.h index 9823160c2..c35c27e64 100644 --- a/src/tile.h +++ b/src/tile.h @@ -40,6 +40,7 @@ enum TileID TILE_MUD_WITH_GRASS, TILE_CLOUD, TILE_COALSTONE, + TILE_WOOD, // Count of tile ids TILES_COUNT |