diff --git a/data/item_ladder.png b/data/item_ladder.png new file mode 100644 index 000000000..f35978ff9 Binary files /dev/null and b/data/item_ladder.png differ diff --git a/data/ladder.png b/data/ladder.png new file mode 100644 index 000000000..dbbd680ec Binary files /dev/null and b/data/ladder.png differ diff --git a/src/content_craft.cpp b/src/content_craft.cpp index b5a1dc776..481ea1a63 100644 --- a/src/content_craft.cpp +++ b/src/content_craft.cpp @@ -413,6 +413,22 @@ InventoryItem *craft_get_result(InventoryItem **items) } } + // Ladder + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[2] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[3] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[5] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[6] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[8] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_LADDER, 1); + } + } + return NULL; } diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 3044c8b35..ceb673606 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -1134,6 +1134,53 @@ void mapblock_mesh_generate_special(MeshMakeData *data, u16 indices[] = {0,1,2,2,3,0}; collector.append(material_rail, vertices, 4, indices, 6); } + else if (n.d == CONTENT_LADDER) { + u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); + video::SColor c(255,l,l,l); + + float d = (float)BS/16; + + // Assume wall is at X+ + video::S3DVertex vertices[4] = + { + video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1), + video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1), + video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0), + video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0), + }; + + v3s16 dir = unpackDir(n.dir); + + for(s32 i=0; i<4; i++) + { + if(dir == v3s16(1,0,0)) + vertices[i].Pos.rotateXZBy(0); + if(dir == v3s16(-1,0,0)) + vertices[i].Pos.rotateXZBy(180); + if(dir == v3s16(0,0,1)) + vertices[i].Pos.rotateXZBy(90); + if(dir == v3s16(0,0,-1)) + vertices[i].Pos.rotateXZBy(-90); + if(dir == v3s16(0,-1,0)) + vertices[i].Pos.rotateXYBy(-90); + if(dir == v3s16(0,1,0)) + vertices[i].Pos.rotateXYBy(90); + + vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + } + + video::SMaterial material_ladder; + material_ladder.setFlag(video::EMF_LIGHTING, false); + material_ladder.setFlag(video::EMF_BACK_FACE_CULLING, false); + material_ladder.setFlag(video::EMF_BILINEAR_FILTER, false); + material_ladder.setFlag(video::EMF_FOG_ENABLE, true); + material_ladder.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + material_ladder.setTexture(0, g_texturesource->getTextureRaw("ladder.png")); + + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + collector.append(material_ladder, vertices, 4, indices, 6); + } } } #endif diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp index 7589f06ed..e3235778a 100644 --- a/src/content_mapnode.cpp +++ b/src/content_mapnode.cpp @@ -303,6 +303,19 @@ void content_mapnode_init() f->walkable = false; setDirtLikeDiggingProperties(f->digging_properties, 0.75); + i = CONTENT_LADDER; + f = &content_features(i); + f->setInventoryTexture("item_ladder.png"); + f->light_propagates = true; + f->param_type = CPT_LIGHT; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + f->wall_mounted = true; + f->solidness = 0; + f->air_equivalent = true; + f->walkable = false; + setWoodLikeDiggingProperties(f->digging_properties, 0.5); + // Deprecated i = CONTENT_COALSTONE; f = &content_features(i); diff --git a/src/content_mapnode.h b/src/content_mapnode.h index 609df0a95..8f44126cf 100644 --- a/src/content_mapnode.h +++ b/src/content_mapnode.h @@ -46,6 +46,7 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version); #define CONTENT_FURNACE 16 #define CONTENT_FENCE 21 #define CONTENT_RAIL 30 +#define CONTENT_LADDER 31 // 0x800...0xfff (2048...4095): higher 4 bytes of param2 are not usable #define CONTENT_GRASS 0x800 //1 diff --git a/src/game.cpp b/src/game.cpp index 6c0474ee7..d8ea45fb1 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -538,6 +538,56 @@ void getPointedNode(Client *client, v3f player_position, } } } + + else if(n.getContent() == CONTENT_LADDER) + { + v3s16 dir = unpackDir(n.dir); + v3f dir_f = v3f(dir.X, dir.Y, dir.Z); + dir_f *= BS/2 - BS/6 - BS/20; + v3f cpf = npf + dir_f; + f32 distance = (cpf - camera_position).getLength(); + + v3f vertices[4] = + { + v3f(BS*0.42,-BS/2,-BS/2), + v3f(BS*0.49, BS/2, BS/2), + }; + + for(s32 i=0; i<2; i++) + { + if(dir == v3s16(1,0,0)) + vertices[i].rotateXZBy(0); + if(dir == v3s16(-1,0,0)) + vertices[i].rotateXZBy(180); + if(dir == v3s16(0,0,1)) + vertices[i].rotateXZBy(90); + if(dir == v3s16(0,0,-1)) + vertices[i].rotateXZBy(-90); + if(dir == v3s16(0,-1,0)) + vertices[i].rotateXYBy(-90); + if(dir == v3s16(0,1,0)) + vertices[i].rotateXYBy(90); + + vertices[i] += npf; + } + + core::aabbox3d box; + + box = core::aabbox3d(vertices[0]); + box.addInternalPoint(vertices[1]); + + if(distance < mindistance) + { + if(box.intersectsWithLine(shootline)) + { + nodefound = true; + nodepos = np; + neighbourpos = np; + mindistance = distance; + nodehilightbox = box; + } + } + } else if(n.getContent() == CONTENT_RAIL) { v3s16 dir = unpackDir(n.param0);