/*
Minetest-c55
Copyright (C) 2010-2011 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 Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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.
*/
#include "game.h"
#include "irrlichttypes_extrabloated.h"
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "client.h"
#include "server.h"
#include "guiPauseMenu.h"
#include "guiPasswordChange.h"
#include "guiInventoryMenu.h"
#include "guiTextInputMenu.h"
#include "guiDeathScreen.h"
#include "tool.h"
#include "guiChatConsole.h"
#include "config.h"
#include "clouds.h"
#include "camera.h"
#include "farmesh.h"
#include "mapblock.h"
#include "settings.h"
#include "profiler.h"
#include "mainmenumanager.h"
#include "gettext.h"
#include "log.h"
#include "filesys.h"
// Needed for determining pointing to nodes
#include "nodedef.h"
#include "nodemetadata.h"
#include "main.h" // For g_settings
#include "itemdef.h"
#include "tile.h" // For TextureSource
#include "logoutputbuffer.h"
#include "subgame.h"
#include "quicktune_shortcutter.h"
#include "clientmap.h"
#include "sky.h"
#include "sound.h"
#if USE_SOUND
#include "sound_openal.h"
#endif
#include "event_manager.h"
#include <list>
#include "util/directiontables.h"
/*
Text input system
*/
struct TextDestChat : public TextDest
{
TextDestChat(Client *client)
{
m_client = client;
}
void gotText(std::wstring text)
{
m_client->typeChatMessage(text);
}
Client *m_client;
};
struct TextDestNodeMetadata : public TextDest
{
TextDestNodeMetadata(v3s16 p, Client *client)
{
m_p = p;
m_client = client;
}
void gotText(std::wstring text)
{
std::string ntext = wide_to_narrow(text);
infostream<<"Changing text of a sign node: "
<<ntext<<std::endl;
std::map<std::string, std::string> fields;
fields["text"] = ntext;
m_client->sendNodemetaFields(m_p, "", fields);
}
v3s16 m_p;
Client *m_client;
};
/* Respawn menu callback */
class MainRespawnInitiator: public IRespawnInitiator
{
public:
MainRespawnInitiator(bool *active, Client *client):
m_active(active), m_client(client)
{
*m_active = true;
}
void respawn()
{
*m_active = false;
m_client->sendRespawn();
}
private:
bool *m_active;
Client *m_client;
};
/* Form update callback */
class NodeMetadataFormSource: public IFormSource
{
public:
NodeMetadataFormSource(ClientMap *map, v3s16 p):
m_map(map),
m_p(p)
{
}
std::string getForm()
{
NodeMetadata *meta = m_map->getNodeMetadata(m_p);
if(!meta)
return "";
return meta->getString("formspec");
}
ClientMap *m_map;
v3s16 m_p;
};
class PlayerInventoryFormSource: public IFormSource
{
public:
PlayerInventoryFormSource(Client *client):
m_client(client)
{
}
std::string getForm()
{
LocalPlayer* player = m_client->getEnv().getLocalPlayer();
return player->inventory_formspec;
}
Client *m_client;
};
/*
Hotbar draw routine
*/
void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
IGameDef *gamedef,
v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
Inventory *inventory, s32 halfheartcount, u16 playeritem)
{
InventoryList *mainlist = inventory->getList("main");
if(mainlist == NULL)
{
errorstream<<"draw_hotbar(): mainlist == NULL"<<std::endl;
return;
}
s32 padding = imgsize/12;
//s32 height = imgsize + padding*2;
s32 width = itemcount*(imgsize+padding*2);
// Position of upper left corner of bar
v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);
// Draw background color
/*core::rect<s32> barrect(0,0,width,height);
barrect += pos;
video::SColor bgcolor(255,128,128,128);
driver->draw2DRectangle(bgcolor, barrect, NULL);*/
core::rect<s32> imgrect(0,0,imgsize,imgsize);
for(s32 i=0; i<itemcount; i++)
{
const ItemStack &item = mainlist->getItem(i);
core::rect<s32> rect = imgrect + pos
+ v2s32(padding+i*(imgsize+padding*2), padding);
if(playeritem == i)
{
video::SColor c_outside(255,255,0,0);
//video::SColor c_outside(255,0,0,0);
//video::SColor c_inside(255,192,192,192);
s32 x1 = rect.UpperLeftCorner.X;
s32 y1 = rect.UpperLeftCorner.Y;
s32 x2 = rect.LowerRightCorner.X;
s32 y2 = rect.LowerRightCorner.Y;
// Black base borders
driver->draw2DRectangle(c_outside,
core::rect<s32>(
v2s32(x1 - padding, y1 - padding),
v2s32(x2 + padding, y1)
), NULL);
driver->draw2DRectangle(c_outside,
core::rect<s32>(
v2s32(x1 - padding, y2),
v2s32(x2 + padding, y2 + padding)
), NULL);
driver->draw2DRectangle(c_outside,
core::rect<s32>(
v2s32(x1 - padding, y1),
v2s32(x1, y2)
), NULL);
driver->draw2DRectangle(c_outside,
core::rect<s32>(
v2s32(x2, y1),
v2s32(x2 + padding, y2)
), NULL);
/*// Light inside borders
driver->draw2DRectangle(c_inside,
core::rect<s32>(
v2s32(x1 - padding/2, y1 - padding/2),
v2s32(x2 + padding/2, y1)
), NULL);
driver->draw2DRectangle(c_inside,
core::rect<s32>(
v2s32(x1 - padding/2, y2),
v2s32(x2 + padding/2, y2 + padding/2)
), NULL);
driver->draw2DRectangle(c_inside,
core::rect<s32>(
v2s32(x1 - padding/2, y1),
v2s32(x1, y2)
), NULL);
driver->draw2DRectangle(c_inside,
core::rect<s32>(
v2s32(x2, y1),
v2s32(x2 + padding/2, y2)
), NULL);
*/
}
video::SColor bgcolor2(128,0,0,0);
driver->draw2DRectangle(bgcolor2, rect, NULL);
drawItemStack(driver, font, item, rect, NULL, gamedef);
}
/*
Draw hearts
*/
video::ITexture *heart_texture =
gamedef->getTextureSource()->getTextureRaw("heart.png");
if(heart_texture)
{
v2s32 p = pos + v2s32(0, -20);
for(s32 i=0; i<halfheartcount/2; i++)
{
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
core::rect<s32> rect(0,0,16,16);
rect += p;
driver->draw2DImage(heart_texture, rect,
core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(heart_texture->getOriginalSize())),
NULL, colors, true);
p += v2s32(16,0);
}
if(halfheartcount % 2 == 1)
{
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
core::rect<s32> rect(0,0,16/2,16);
rect += p;
core::dimension2di srcd(heart_texture->getOriginalSize());
srcd.Width /= 2;
driver->draw2DImage(heart_texture, rect,
core::rect<s32>(core::position2d<s32>(0,0), srcd),
NULL, colors, true);
p += v2s32(16,0);
}
}
}
/*
Check if a node is pointable
*/
inline bool isPointableNode(const MapNode& n,
Client *client, bool liquids_pointable)
{
const ContentFeatures &features = client->getNodeDefManager()->get(n);
return features.pointable ||
(liquids_pointable && features.isLiquid());
}
/*
Find what the player is pointing at
*/
PointedThing getPointedThing(Client *client, v3f player_position,
v3f camera_direction, v3f camera_position,
core::line3d<f32> shootline, f32 d,
bool liquids_pointable,
bool look_for_object,
std::vector<aabb3f> &hilightboxes,
ClientActiveObject *&selected_object)
{
PointedThing result;
hilightboxes.clear();
selected_object = NULL;
INodeDefManager *nodedef = client->getNodeDefManager();
ClientMap &map = client->getEnv().getClientMap();
// First try to find a pointed at active object
if(look_for_object)
{
selected_object = client->getSelectedActiveObject(d*BS,
camera_position, shootline);
if(selected_object != NULL)
{
if(selected_object->doShowSelectionBox())
{
aabb3f *selection_box = selected_object->getSelectionBox();
// Box should exist because object was
// returned in the first place
assert(selection_box);
v3f pos = selected_object->getPosition();
hilightboxes.push_back(aabb3f(
selection_box->MinEdge + pos,
selection_box->MaxEdge + pos));
}
result.type = POINTEDTHING_OBJECT;
result.object_id = selected_object->getId();
return result;
}
}
// That didn't work, try to find a pointed at node
f32 mindistance = BS * 1001;
v3s16 pos_i = floatToInt(player_position, BS);
/*infostream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
<<std::endl;*/
s16 a = d;
s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
for(s16 y = ystart; y <= yend; y++)
for(s16 z = zstart; z <= zend; z++)
for(s16 x = xstart; x <= xend; x++)
{
MapNode n;
try
{
n = map.getNode(v3s16(x,y,z));
}
catch(InvalidPositionException &e)
{
continue;
}
if(!isPointableNode(n, client, liquids_pointable))
continue;
std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
v3s16 np(x,y,z);
v3f npf = intToFloat(np, BS);
for(std::vector<aabb3f>::const_iterator
i = boxes.begin();
i != boxes.end(); i++)
{
aabb3f box = *i;
box.MinEdge += npf;
box.MaxEdge += npf;
for(u16 j=0; j<6; j++)
{
v3s16 facedir = g_6dirs[j];
aabb3f facebox = box;
f32 d = 0.001*BS;
if(facedir.X > 0)
facebox.MinEdge.X = facebox.MaxEdge.X-d;
else if(facedir.X < 0)
facebox.MaxEdge.X = facebox.MinEdge.X+d;
else if(facedir.Y > 0)
facebox.MinEdge.Y = facebox.MaxEdge.Y-d;
else if(facedir.Y < 0)
facebox.MaxEdge.Y = facebox.MinEdge.Y+d;
else if(facedir.Z > 0)
facebox.MinEdge.Z = facebox.MaxEdge.Z-d;
else if(facedir.Z < 0)
facebox.MaxEdge.Z = facebox.MinEdge.Z+d;
v3f centerpoint = facebox.getCenter();
f32 distance = (centerpoint - camera_position).getLength();
if(distance >= mindistance)
continue;
if(!facebox.intersectsWithLine(shootline))
continue;
v3s16 np_above = np + facedir;
result.type = POINTEDTHING_NODE;
result.node_undersurface = np;
result.node_abovesurface = np_above;
mindistance = distance;
hilightboxes.clear();
for(std::vector<aabb3f>::const_iterator
i2 = boxes.begin();
i2 != boxes.end(); i2++)
{
aabb3f box = *i2;
box.MinEdge += npf + v3f(-d,-d,-d);
box.MaxEdge += npf + v3f(d,d,d);
hilightboxes.push_back(box);
}
}
}
} // for coords
return result;
}
/*
Draws a screen with a single text on it.
Text will be removed when the screen is drawn the next time.
*/
/*gui::IGUIStaticText **/
void draw_load_screen(const std::wstring &text,
video::IVideoDriver* driver, gui::IGUIFont* font)
|