aboutsummaryrefslogtreecommitdiff
path: root/src/game.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game.cpp')
-rw-r--r--src/game.cpp392
1 files changed, 118 insertions, 274 deletions
diff --git a/src/game.cpp b/src/game.cpp
index 5bdbea617..cfa6234ff 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -265,271 +265,6 @@ public:
Client *m_client;
};
-/*
- 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());
-}
-
-static inline void getNeighborConnectingFace(v3s16 p, INodeDefManager *nodedef,
- ClientMap *map, MapNode n, u8 bitmask, u8 *neighbors)
-{
- MapNode n2 = map->getNodeNoEx(p);
- if (nodedef->nodeboxConnects(n, n2, bitmask))
- *neighbors |= bitmask;
-}
-
-static inline u8 getNeighbors(v3s16 p, INodeDefManager *nodedef, ClientMap *map, MapNode n)
-{
- u8 neighbors = 0;
- const ContentFeatures &f = nodedef->get(n);
- // locate possible neighboring nodes to connect to
- if (f.drawtype == NDT_NODEBOX && f.node_box.type == NODEBOX_CONNECTED) {
- v3s16 p2 = p;
-
- p2.Y++;
- getNeighborConnectingFace(p2, nodedef, map, n, 1, &neighbors);
-
- p2 = p;
- p2.Y--;
- getNeighborConnectingFace(p2, nodedef, map, n, 2, &neighbors);
-
- p2 = p;
- p2.Z--;
- getNeighborConnectingFace(p2, nodedef, map, n, 4, &neighbors);
-
- p2 = p;
- p2.X--;
- getNeighborConnectingFace(p2, nodedef, map, n, 8, &neighbors);
-
- p2 = p;
- p2.Z++;
- getNeighborConnectingFace(p2, nodedef, map, n, 16, &neighbors);
-
- p2 = p;
- p2.X++;
- getNeighborConnectingFace(p2, nodedef, map, n, 32, &neighbors);
- }
-
- return neighbors;
-}
-
-/*
- Find what the player is pointing at
-*/
-PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_position,
- const v3f &camera_direction, const v3f &camera_position,
- core::line3d<f32> shootline, f32 d, bool liquids_pointable,
- bool look_for_object, const v3s16 &camera_offset,
- ClientActiveObject *&selected_object)
-{
- PointedThing result;
-
- std::vector<aabb3f> *selectionboxes = hud->getSelectionBoxes();
- selectionboxes->clear();
- static const bool show_entity_selectionbox = g_settings->getBool("show_entity_selectionbox");
-
- selected_object = NULL;
-
- INodeDefManager *nodedef = client->getNodeDefManager();
- ClientMap &map = client->getEnv().getClientMap();
-
- f32 min_distance = BS * 1001;
-
- // 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 (show_entity_selectionbox &&
- 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();
- selectionboxes->push_back(aabb3f(
- selection_box->MinEdge, selection_box->MaxEdge));
- hud->setSelectionPos(pos, camera_offset);
- }
-
- min_distance = (selected_object->getPosition() - camera_position).getLength();
-
- hud->setSelectedFaceNormal(v3f(0.0, 0.0, 0.0));
- result.type = POINTEDTHING_OBJECT;
- result.object_id = selected_object->getId();
- }
- }
-
- // That didn't work, try to find a pointed at node
-
- 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 - (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);
-
- // Prevent signed number overflow
- if (yend == 32767)
- yend = 32766;
-
- if (zend == 32767)
- zend = 32766;
-
- if (xend == 32767)
- xend = 32766;
-
- v3s16 pointed_pos(0, 0, 0);
-
- for (s16 y = ystart; y <= yend; y++) {
- for (s16 z = zstart; z <= zend; z++) {
- for (s16 x = xstart; x <= xend; x++) {
- MapNode n;
- bool is_valid_position;
- v3s16 p(x, y, z);
-
- n = map.getNodeNoEx(p, &is_valid_position);
- if (!is_valid_position) {
- continue;
- }
- if (!isPointableNode(n, client, liquids_pointable)) {
- continue;
- }
-
- std::vector<aabb3f> boxes;
- n.getSelectionBoxes(nodedef, &boxes, getNeighbors(p, nodedef, &map, n));
-
- 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;
-
- v3f centerpoint = box.getCenter();
- f32 distance = (centerpoint - camera_position).getLength();
- if (distance >= min_distance) {
- continue;
- }
- if (!box.intersectsWithLine(shootline)) {
- continue;
- }
- result.type = POINTEDTHING_NODE;
- min_distance = distance;
- pointed_pos = np;
- }
- }
- }
- }
-
- if (result.type == POINTEDTHING_NODE) {
- f32 d = 0.001 * BS;
- MapNode n = map.getNodeNoEx(pointed_pos);
- v3f npf = intToFloat(pointed_pos, BS);
- std::vector<aabb3f> boxes;
- n.getSelectionBoxes(nodedef, &boxes, getNeighbors(pointed_pos, nodedef, &map, n));
- f32 face_min_distance = 1000 * 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;
- 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 >= face_min_distance)
- continue;
- if (!facebox.intersectsWithLine(shootline))
- continue;
- result.node_abovesurface = pointed_pos + facedir;
- hud->setSelectedFaceNormal(v3f(facedir.X, facedir.Y, facedir.Z));
- face_min_distance = distance;
- }
- }
- selectionboxes->clear();
- for (std::vector<aabb3f>::const_iterator
- i = boxes.begin();
- i != boxes.end(); ++i) {
- aabb3f box = *i;
- box.MinEdge += v3f(-d, -d, -d);
- box.MaxEdge += v3f(d, d, d);
- selectionboxes->push_back(box);
- }
- hud->setSelectionPos(intToFloat(pointed_pos, BS), camera_offset);
- result.node_undersurface = pointed_pos;
- }
-
- // Update selection mesh light level and vertex colors
- if (selectionboxes->size() > 0) {
- v3f pf = hud->getSelectionPos();
- v3s16 p = floatToInt(pf, BS);
-
- // Get selection mesh light level
- MapNode n = map.getNodeNoEx(p);
- u16 node_light = getInteriorLight(n, -1, nodedef);
- u16 light_level = node_light;
-
- for (u8 i = 0; i < 6; i++) {
- n = map.getNodeNoEx(p + g_6dirs[i]);
- node_light = getInteriorLight(n, -1, nodedef);
- if (node_light > light_level)
- light_level = node_light;
- }
-
- video::SColor c = MapBlock_LightColor(255, light_level, 0);
- u8 day = c.getRed();
- u8 night = c.getGreen();
- u32 daynight_ratio = client->getEnv().getDayNightRatio();
- finalColorBlend(c, day, night, daynight_ratio);
-
- // Modify final color a bit with time
- u32 timer = porting::getTimeMs() % 5000;
- float timerf = (float)(irr::core::PI * ((timer / 2500.0) - 0.5));
- float sin_r = 0.08 * sin(timerf);
- float sin_g = 0.08 * sin(timerf + irr::core::PI * 0.5);
- float sin_b = 0.08 * sin(timerf + irr::core::PI);
- c.setRed(core::clamp(core::round32(c.getRed() * (0.8 + sin_r)), 0, 255));
- c.setGreen(core::clamp(core::round32(c.getGreen() * (0.8 + sin_g)), 0, 255));
- c.setBlue(core::clamp(core::round32(c.getBlue() * (0.8 + sin_b)), 0, 255));
-
- // Set mesh final color
- hud->setSelectionMeshColor(c);
- }
- return result;
-}
-
/* Profiler display */
void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, FontEngine *fe,
@@ -1668,6 +1403,23 @@ protected:
void updateSound(f32 dtime);
void processPlayerInteraction(GameRunData *runData, f32 dtime, bool show_hud,
bool show_debug);
+ /*!
+ * Returns the object or node the player is pointing at.
+ * Also updates the selected thing in the Hud.
+ *
+ * @param[in] shootline the shootline, starting from
+ * the camera position. This also gives the maximal distance
+ * of the search.
+ * @param[in] liquids_pointable if false, liquids are ignored
+ * @param[in] look_for_object if false, objects are ignored
+ * @param[in] camera_offset offset of the camera
+ * @param[out] selected_object the selected object or
+ * NULL if not found
+ */
+ PointedThing updatePointedThing(
+ const core::line3d<f32> &shootline, bool liquids_pointable,
+ bool look_for_object, const v3s16 &camera_offset,
+ ClientActiveObject *&selected_object);
void handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem);
void handlePointingAtNode(GameRunData *runData,
const PointedThing &pointed, const ItemDefinition &playeritem_def,
@@ -3823,14 +3575,11 @@ void Game::processPlayerInteraction(GameRunData *runData,
core::line3d<f32> shootline;
if (camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT) {
-
shootline = core::line3d<f32>(camera_position,
- camera_position + camera_direction * BS * (d + 1));
-
+ camera_position + camera_direction * BS * d);
} else {
// prevent player pointing anything in front-view
- if (camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT)
- shootline = core::line3d<f32>(0, 0, 0, 0, 0, 0);
+ shootline = core::line3d<f32>(camera_position,camera_position);
}
#ifdef HAVE_TOUCHSCREENGUI
@@ -3843,10 +3592,7 @@ void Game::processPlayerInteraction(GameRunData *runData,
#endif
- PointedThing pointed = getPointedThing(
- // input
- client, hud, player_position, camera_direction,
- camera_position, shootline, d,
+ PointedThing pointed = updatePointedThing(shootline,
playeritem_def.liquids_pointable,
!runData->ldown_for_dig,
camera_offset,
@@ -3940,6 +3686,104 @@ void Game::processPlayerInteraction(GameRunData *runData,
}
+PointedThing Game::updatePointedThing(
+ const core::line3d<f32> &shootline,
+ bool liquids_pointable,
+ bool look_for_object,
+ const v3s16 &camera_offset,
+ ClientActiveObject *&selected_object)
+{
+ std::vector<aabb3f> *selectionboxes = hud->getSelectionBoxes();
+ selectionboxes->clear();
+ static const bool show_entity_selectionbox = g_settings->getBool(
+ "show_entity_selectionbox");
+
+ ClientMap &map = client->getEnv().getClientMap();
+ INodeDefManager *nodedef=client->getNodeDefManager();
+
+ selected_object = NULL;
+
+ PointedThing result=client->getEnv().getPointedThing(
+ shootline, liquids_pointable, look_for_object);
+ if (result.type == POINTEDTHING_OBJECT) {
+ selected_object = client->getEnv().getActiveObject(result.object_id);
+ if (show_entity_selectionbox && 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();
+ selectionboxes->push_back(aabb3f(
+ selection_box->MinEdge, selection_box->MaxEdge));
+ selectionboxes->push_back(
+ aabb3f(selection_box->MinEdge, selection_box->MaxEdge));
+ hud->setSelectionPos(pos, camera_offset);
+ }
+ } else if (result.type == POINTEDTHING_NODE) {
+ // Update selection boxes
+ MapNode n = map.getNodeNoEx(result.node_undersurface);
+ std::vector<aabb3f> boxes;
+ n.getSelectionBoxes(nodedef, &boxes,
+ n.getNeighbors(result.node_undersurface, &map));
+
+ f32 d = 0.002 * BS;
+ for (std::vector<aabb3f>::const_iterator i = boxes.begin();
+ i != boxes.end(); ++i) {
+ aabb3f box = *i;
+ box.MinEdge -= v3f(d, d, d);
+ box.MaxEdge += v3f(d, d, d);
+ selectionboxes->push_back(box);
+ }
+ hud->setSelectionPos(intToFloat(result.node_undersurface, BS),
+ camera_offset);
+ }
+
+ // Update selection mesh light level and vertex colors
+ if (selectionboxes->size() > 0) {
+ v3f pf = hud->getSelectionPos();
+ v3s16 p = floatToInt(pf, BS);
+
+ // Get selection mesh light level
+ MapNode n = map.getNodeNoEx(p);
+ u16 node_light = getInteriorLight(n, -1, nodedef);
+ u16 light_level = node_light;
+
+ for (u8 i = 0; i < 6; i++) {
+ n = map.getNodeNoEx(p + g_6dirs[i]);
+ node_light = getInteriorLight(n, -1, nodedef);
+ if (node_light > light_level)
+ light_level = node_light;
+ }
+
+ video::SColor c = MapBlock_LightColor(255, light_level, 0);
+ u8 day = c.getRed();
+ u8 night = c.getGreen();
+ u32 daynight_ratio = client->getEnv().getDayNightRatio();
+ finalColorBlend(c, day, night, daynight_ratio);
+
+ // Modify final color a bit with time
+ u32 timer = porting::getTimeMs() % 5000;
+ float timerf = (float) (irr::core::PI * ((timer / 2500.0) - 0.5));
+ float sin_r = 0.08 * sin(timerf);
+ float sin_g = 0.08 * sin(timerf + irr::core::PI * 0.5);
+ float sin_b = 0.08 * sin(timerf + irr::core::PI);
+ c.setRed(
+ core::clamp(core::round32(c.getRed() * (0.8 + sin_r)), 0, 255));
+ c.setGreen(
+ core::clamp(core::round32(c.getGreen() * (0.8 + sin_g)), 0, 255));
+ c.setBlue(
+ core::clamp(core::round32(c.getBlue() * (0.8 + sin_b)), 0, 255));
+
+ // Set mesh final color
+ hud->setSelectionMeshColor(c);
+ }
+ return result;
+}
+
+
void Game::handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem)
{
infostream << "Right Clicked in Air" << std::endl;