mirror of https://github.com/minetest/minetest.git
Merge celeron55
This commit is contained in:
commit
fcca601e2d
|
@ -12,7 +12,7 @@ set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
||||||
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
|
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
|
||||||
set(VERSION_MAJOR 0)
|
set(VERSION_MAJOR 0)
|
||||||
set(VERSION_MINOR 4)
|
set(VERSION_MINOR 4)
|
||||||
set(VERSION_PATCH 2-rc1)
|
set(VERSION_PATCH 3)
|
||||||
if(VERSION_EXTRA)
|
if(VERSION_EXTRA)
|
||||||
set(VERSION_PATCH ${VERSION_PATCH}-${VERSION_EXTRA})
|
set(VERSION_PATCH ${VERSION_PATCH}-${VERSION_EXTRA})
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -227,10 +227,12 @@ function minetest.item_drop(itemstack, dropper, pos)
|
||||||
local v = dropper:get_look_dir()
|
local v = dropper:get_look_dir()
|
||||||
local p = {x=pos.x+v.x, y=pos.y+1.5+v.y, z=pos.z+v.z}
|
local p = {x=pos.x+v.x, y=pos.y+1.5+v.y, z=pos.z+v.z}
|
||||||
local obj = minetest.env:add_item(p, itemstack)
|
local obj = minetest.env:add_item(p, itemstack)
|
||||||
v.x = v.x*2
|
if obj then
|
||||||
v.y = v.y*2 + 1
|
v.x = v.x*2
|
||||||
v.z = v.z*2
|
v.y = v.y*2 + 1
|
||||||
obj:setvelocity(v)
|
v.z = v.z*2
|
||||||
|
obj:setvelocity(v)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
minetest.env:add_item(pos, itemstack)
|
minetest.env:add_item(pos, itemstack)
|
||||||
end
|
end
|
||||||
|
@ -258,6 +260,16 @@ function minetest.node_punch(pos, node, puncher)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function minetest.handle_node_drops(pos, drops, digger)
|
||||||
|
-- Add dropped items to object's inventory
|
||||||
|
if digger:get_inventory() then
|
||||||
|
local _, dropped_item
|
||||||
|
for _, dropped_item in ipairs(drops) do
|
||||||
|
digger:get_inventory():add_item("main", dropped_item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function minetest.node_dig(pos, node, digger)
|
function minetest.node_dig(pos, node, digger)
|
||||||
minetest.debug("node_dig")
|
minetest.debug("node_dig")
|
||||||
|
|
||||||
|
@ -283,13 +295,8 @@ function minetest.node_dig(pos, node, digger)
|
||||||
wielded:add_wear(dp.wear)
|
wielded:add_wear(dp.wear)
|
||||||
digger:set_wielded_item(wielded)
|
digger:set_wielded_item(wielded)
|
||||||
|
|
||||||
-- Add dropped items to object's inventory
|
-- Handle drops
|
||||||
if digger:get_inventory() then
|
minetest.handle_node_drops(pos, drops, digger)
|
||||||
local _, dropped_item
|
|
||||||
for _, dropped_item in ipairs(drops) do
|
|
||||||
digger:get_inventory():add_item("main", dropped_item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local oldmetadata = nil
|
local oldmetadata = nil
|
||||||
if def.after_dig_node then
|
if def.after_dig_node then
|
||||||
|
|
|
@ -453,6 +453,9 @@ Special groups
|
||||||
- 2: node is removed without tool wear after 0.5 seconds or so
|
- 2: node is removed without tool wear after 0.5 seconds or so
|
||||||
(rail, sign)
|
(rail, sign)
|
||||||
- 3: node is removed without tool wear immediately (torch)
|
- 3: node is removed without tool wear immediately (torch)
|
||||||
|
- disable_jump: Player (and possibly other things) cannot jump from node
|
||||||
|
- fall_damage_add_percent: damage speed = speed * (1 + value/100)
|
||||||
|
- bouncy: value is bounce speed in percent
|
||||||
|
|
||||||
Known damage and digging time defining groups
|
Known damage and digging time defining groups
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
@ -888,6 +891,12 @@ minetest.get_craft_recipe(output) -> input
|
||||||
^ input.items = for example { stack 1, stack 2, stack 3, stack 4,
|
^ input.items = for example { stack 1, stack 2, stack 3, stack 4,
|
||||||
stack 5, stack 6, stack 7, stack 8, stack 9 }
|
stack 5, stack 6, stack 7, stack 8, stack 9 }
|
||||||
^ input.items = nil if no recipe found
|
^ input.items = nil if no recipe found
|
||||||
|
minetest.handle_node_drops(pos, drops, digger)
|
||||||
|
^ drops: list of itemstrings
|
||||||
|
^ Handles drops from nodes after digging: Default action is to put them into
|
||||||
|
digger's inventory
|
||||||
|
^ Can be overridden to get different functionality (eg. dropping items on
|
||||||
|
ground)
|
||||||
|
|
||||||
Rollbacks:
|
Rollbacks:
|
||||||
minetest.rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
|
minetest.rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
|
||||||
|
@ -1118,6 +1127,8 @@ methods:
|
||||||
- is_empty(listname): return true if list is empty
|
- is_empty(listname): return true if list is empty
|
||||||
- get_size(listname): get size of a list
|
- get_size(listname): get size of a list
|
||||||
- set_size(listname, size): set size of a list
|
- set_size(listname, size): set size of a list
|
||||||
|
- get_width(listname): get width of a list
|
||||||
|
- set_width(listname, width): set width of list; currently used for crafting
|
||||||
- get_stack(listname, i): get a copy of stack index i in list
|
- get_stack(listname, i): get a copy of stack index i in list
|
||||||
- set_stack(listname, i, stack): copy stack to index i in list
|
- set_stack(listname, i, stack): copy stack to index i in list
|
||||||
- get_list(listname): return full list
|
- get_list(listname): return full list
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
# https://bitbucket.org/celeron55/minetest/src/tip/src/defaultsettings.cpp
|
# https://bitbucket.org/celeron55/minetest/src/tip/src/defaultsettings.cpp
|
||||||
#
|
#
|
||||||
# A vim command to convert most of defaultsettings.cpp to conf file format:
|
# A vim command to convert most of defaultsettings.cpp to conf file format:
|
||||||
# :'<,'>s/\tg_settings\.setDefault("\([^"]*\)", "\([^"]*\)");.*/#\1 = \2/g
|
# :'<,'>s/\tsettings->setDefault("\([^"]*\)", "\([^"]*\)");.*/#\1 = \2/g
|
||||||
# Note: Some of the settings are implemented in Lua
|
# Note: Some of the settings are implemented in Lua
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -49,8 +49,14 @@
|
||||||
#keymap_freemove = KEY_KEY_K
|
#keymap_freemove = KEY_KEY_K
|
||||||
#keymap_fastmove = KEY_KEY_J
|
#keymap_fastmove = KEY_KEY_J
|
||||||
#keymap_screenshot = KEY_F12
|
#keymap_screenshot = KEY_F12
|
||||||
|
# If true, keymap_special1 instead of keymap_sneak is used for climbing down and descending
|
||||||
|
#aux1_descends = false
|
||||||
# Some (temporary) keys for debugging
|
# Some (temporary) keys for debugging
|
||||||
#keymap_print_debug_stacks = KEY_KEY_P
|
#keymap_print_debug_stacks = KEY_KEY_P
|
||||||
|
#keymap_quicktune_prev = KEY_HOME
|
||||||
|
#keymap_quicktune_next = KEY_END
|
||||||
|
#keymap_quicktune_dec = KEY_NEXT
|
||||||
|
#keymap_quicktune_inc = KEY_PRIOR
|
||||||
|
|
||||||
# Minimum FPS
|
# Minimum FPS
|
||||||
# The amount of rendered stuff is dynamically set according to this
|
# The amount of rendered stuff is dynamically set according to this
|
||||||
|
|
|
@ -157,43 +157,21 @@ static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
void ClientMap::updateDrawList(video::IVideoDriver* driver)
|
||||||
{
|
{
|
||||||
|
ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
|
||||||
|
g_profiler->add("CM::updateDrawList() count", 1);
|
||||||
|
|
||||||
INodeDefManager *nodemgr = m_gamedef->ndef();
|
INodeDefManager *nodemgr = m_gamedef->ndef();
|
||||||
|
|
||||||
//m_dout<<DTIME<<"Rendering map..."<<std::endl;
|
for(core::map<v3s16, MapBlock*>::Iterator
|
||||||
DSTACK(__FUNCTION_NAME);
|
i = m_drawlist.getIterator();
|
||||||
|
i.atEnd() == false; i++)
|
||||||
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
|
|
||||||
|
|
||||||
std::string prefix;
|
|
||||||
if(pass == scene::ESNRP_SOLID)
|
|
||||||
prefix = "CM: solid: ";
|
|
||||||
else
|
|
||||||
prefix = "CM: transparent: ";
|
|
||||||
|
|
||||||
/*
|
|
||||||
This is called two times per frame, reset on the non-transparent one
|
|
||||||
*/
|
|
||||||
if(pass == scene::ESNRP_SOLID)
|
|
||||||
{
|
{
|
||||||
m_last_drawn_sectors.clear();
|
MapBlock *block = i.getNode()->getValue();
|
||||||
|
block->refDrop();
|
||||||
}
|
}
|
||||||
|
m_drawlist.clear();
|
||||||
/*
|
|
||||||
Get time for measuring timeout.
|
|
||||||
|
|
||||||
Measuring time is very useful for long delays when the
|
|
||||||
machine is swapping a lot.
|
|
||||||
*/
|
|
||||||
int time1 = time(0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get animation parameters
|
|
||||||
*/
|
|
||||||
float animation_time = m_client->getAnimationTime();
|
|
||||||
int crack = m_client->getCrackLevel();
|
|
||||||
u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
|
|
||||||
|
|
||||||
m_camera_mutex.Lock();
|
m_camera_mutex.Lock();
|
||||||
v3f camera_position = m_camera_position;
|
v3f camera_position = m_camera_position;
|
||||||
|
@ -201,17 +179,15 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
f32 camera_fov = m_camera_fov;
|
f32 camera_fov = m_camera_fov;
|
||||||
m_camera_mutex.Unlock();
|
m_camera_mutex.Unlock();
|
||||||
|
|
||||||
/*
|
// Use a higher fov to accomodate faster camera movements.
|
||||||
Get all blocks and draw all visible ones
|
// Blocks are cropped better when they are drawn.
|
||||||
*/
|
// Or maybe they aren't? Well whatever.
|
||||||
|
camera_fov *= 1.2;
|
||||||
|
|
||||||
v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
|
v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
|
||||||
|
|
||||||
v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
|
v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
|
||||||
|
|
||||||
v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
|
v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
|
||||||
v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
|
v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
|
||||||
|
|
||||||
// Take a fair amount as we will be dropping more out later
|
// Take a fair amount as we will be dropping more out later
|
||||||
// Umm... these additions are a bit strange but they are needed.
|
// Umm... these additions are a bit strange but they are needed.
|
||||||
v3s16 p_blocks_min(
|
v3s16 p_blocks_min(
|
||||||
|
@ -223,13 +199,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
p_nodes_max.Y / MAP_BLOCKSIZE + 1,
|
p_nodes_max.Y / MAP_BLOCKSIZE + 1,
|
||||||
p_nodes_max.Z / MAP_BLOCKSIZE + 1);
|
p_nodes_max.Z / MAP_BLOCKSIZE + 1);
|
||||||
|
|
||||||
u32 vertex_count = 0;
|
|
||||||
u32 meshbuffer_count = 0;
|
|
||||||
|
|
||||||
// For limiting number of mesh animations per frame
|
|
||||||
u32 mesh_animate_count = 0;
|
|
||||||
u32 mesh_animate_count_far = 0;
|
|
||||||
|
|
||||||
// Number of blocks in rendering range
|
// Number of blocks in rendering range
|
||||||
u32 blocks_in_range = 0;
|
u32 blocks_in_range = 0;
|
||||||
// Number of blocks occlusion culled
|
// Number of blocks occlusion culled
|
||||||
|
@ -242,18 +211,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
// Blocks that were drawn and had a mesh
|
// Blocks that were drawn and had a mesh
|
||||||
u32 blocks_drawn = 0;
|
u32 blocks_drawn = 0;
|
||||||
// Blocks which had a corresponding meshbuffer for this pass
|
// Blocks which had a corresponding meshbuffer for this pass
|
||||||
u32 blocks_had_pass_meshbuf = 0;
|
//u32 blocks_had_pass_meshbuf = 0;
|
||||||
// Blocks from which stuff was actually drawn
|
// Blocks from which stuff was actually drawn
|
||||||
u32 blocks_without_stuff = 0;
|
//u32 blocks_without_stuff = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
Collect a set of blocks for drawing
|
|
||||||
*/
|
|
||||||
|
|
||||||
core::map<v3s16, MapBlock*> drawset;
|
|
||||||
|
|
||||||
{
|
|
||||||
ScopeProfiler sp(g_profiler, prefix+"collecting blocks for drawing", SPT_AVG);
|
|
||||||
|
|
||||||
for(core::map<v2s16, MapSector*>::Iterator
|
for(core::map<v2s16, MapSector*>::Iterator
|
||||||
si = m_sectors.getIterator();
|
si = m_sectors.getIterator();
|
||||||
|
@ -380,35 +340,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
&& d > m_control.wanted_min_range * BS)
|
&& d > m_control.wanted_min_range * BS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Mesh animation
|
|
||||||
{
|
|
||||||
//JMutexAutoLock lock(block->mesh_mutex);
|
|
||||||
MapBlockMesh *mapBlockMesh = block->mesh;
|
|
||||||
// Pretty random but this should work somewhat nicely
|
|
||||||
bool faraway = d >= BS*50;
|
|
||||||
//bool faraway = d >= m_control.wanted_range * BS;
|
|
||||||
if(mapBlockMesh->isAnimationForced() ||
|
|
||||||
!faraway ||
|
|
||||||
mesh_animate_count_far < (m_control.range_all ? 200 : 50))
|
|
||||||
{
|
|
||||||
bool animated = mapBlockMesh->animate(
|
|
||||||
faraway,
|
|
||||||
animation_time,
|
|
||||||
crack,
|
|
||||||
daynight_ratio);
|
|
||||||
if(animated)
|
|
||||||
mesh_animate_count++;
|
|
||||||
if(animated && faraway)
|
|
||||||
mesh_animate_count_far++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mapBlockMesh->decreaseAnimationForceTimer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add to set
|
// Add to set
|
||||||
drawset[block->getPos()] = block;
|
block->refGrab();
|
||||||
|
m_drawlist[block->getPos()] = block;
|
||||||
|
|
||||||
sector_blocks_drawn++;
|
sector_blocks_drawn++;
|
||||||
blocks_drawn++;
|
blocks_drawn++;
|
||||||
|
@ -418,7 +352,126 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
if(sector_blocks_drawn != 0)
|
if(sector_blocks_drawn != 0)
|
||||||
m_last_drawn_sectors[sp] = true;
|
m_last_drawn_sectors[sp] = true;
|
||||||
}
|
}
|
||||||
} // ScopeProfiler
|
|
||||||
|
g_profiler->avg("CM: blocks in range", blocks_in_range);
|
||||||
|
g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
|
||||||
|
if(blocks_in_range != 0)
|
||||||
|
g_profiler->avg("CM: blocks in range without mesh (frac)",
|
||||||
|
(float)blocks_in_range_without_mesh/blocks_in_range);
|
||||||
|
g_profiler->avg("CM: blocks drawn", blocks_drawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MeshBufList
|
||||||
|
{
|
||||||
|
video::SMaterial m;
|
||||||
|
core::list<scene::IMeshBuffer*> bufs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshBufListList
|
||||||
|
{
|
||||||
|
core::list<MeshBufList> lists;
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
lists.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(scene::IMeshBuffer *buf)
|
||||||
|
{
|
||||||
|
for(core::list<MeshBufList>::Iterator i = lists.begin();
|
||||||
|
i != lists.end(); i++){
|
||||||
|
MeshBufList &l = *i;
|
||||||
|
if(l.m == buf->getMaterial()){
|
||||||
|
l.bufs.push_back(buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MeshBufList l;
|
||||||
|
l.m = buf->getMaterial();
|
||||||
|
l.bufs.push_back(buf);
|
||||||
|
lists.push_back(l);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
|
{
|
||||||
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
|
||||||
|
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
|
||||||
|
|
||||||
|
std::string prefix;
|
||||||
|
if(pass == scene::ESNRP_SOLID)
|
||||||
|
prefix = "CM: solid: ";
|
||||||
|
else
|
||||||
|
prefix = "CM: transparent: ";
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is called two times per frame, reset on the non-transparent one
|
||||||
|
*/
|
||||||
|
if(pass == scene::ESNRP_SOLID)
|
||||||
|
{
|
||||||
|
m_last_drawn_sectors.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get time for measuring timeout.
|
||||||
|
|
||||||
|
Measuring time is very useful for long delays when the
|
||||||
|
machine is swapping a lot.
|
||||||
|
*/
|
||||||
|
int time1 = time(0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get animation parameters
|
||||||
|
*/
|
||||||
|
float animation_time = m_client->getAnimationTime();
|
||||||
|
int crack = m_client->getCrackLevel();
|
||||||
|
u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
|
||||||
|
|
||||||
|
m_camera_mutex.Lock();
|
||||||
|
v3f camera_position = m_camera_position;
|
||||||
|
v3f camera_direction = m_camera_direction;
|
||||||
|
f32 camera_fov = m_camera_fov;
|
||||||
|
m_camera_mutex.Unlock();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get all blocks and draw all visible ones
|
||||||
|
*/
|
||||||
|
|
||||||
|
v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
|
||||||
|
|
||||||
|
v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
|
||||||
|
|
||||||
|
v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
|
||||||
|
v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
|
||||||
|
|
||||||
|
// Take a fair amount as we will be dropping more out later
|
||||||
|
// Umm... these additions are a bit strange but they are needed.
|
||||||
|
v3s16 p_blocks_min(
|
||||||
|
p_nodes_min.X / MAP_BLOCKSIZE - 3,
|
||||||
|
p_nodes_min.Y / MAP_BLOCKSIZE - 3,
|
||||||
|
p_nodes_min.Z / MAP_BLOCKSIZE - 3);
|
||||||
|
v3s16 p_blocks_max(
|
||||||
|
p_nodes_max.X / MAP_BLOCKSIZE + 1,
|
||||||
|
p_nodes_max.Y / MAP_BLOCKSIZE + 1,
|
||||||
|
p_nodes_max.Z / MAP_BLOCKSIZE + 1);
|
||||||
|
|
||||||
|
u32 vertex_count = 0;
|
||||||
|
u32 meshbuffer_count = 0;
|
||||||
|
|
||||||
|
// For limiting number of mesh animations per frame
|
||||||
|
u32 mesh_animate_count = 0;
|
||||||
|
u32 mesh_animate_count_far = 0;
|
||||||
|
|
||||||
|
// Blocks that had mesh that would have been drawn according to
|
||||||
|
// rendering range (if max blocks limit didn't kick in)
|
||||||
|
u32 blocks_would_have_drawn = 0;
|
||||||
|
// Blocks that were drawn and had a mesh
|
||||||
|
u32 blocks_drawn = 0;
|
||||||
|
// Blocks which had a corresponding meshbuffer for this pass
|
||||||
|
u32 blocks_had_pass_meshbuf = 0;
|
||||||
|
// Blocks from which stuff was actually drawn
|
||||||
|
u32 blocks_without_stuff = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Draw the selected MapBlocks
|
Draw the selected MapBlocks
|
||||||
|
@ -427,10 +480,90 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
{
|
{
|
||||||
ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG);
|
ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG);
|
||||||
|
|
||||||
int timecheck_counter = 0;
|
MeshBufListList drawbufs;
|
||||||
|
|
||||||
for(core::map<v3s16, MapBlock*>::Iterator
|
for(core::map<v3s16, MapBlock*>::Iterator
|
||||||
i = drawset.getIterator();
|
i = m_drawlist.getIterator();
|
||||||
i.atEnd() == false; i++)
|
i.atEnd() == false; i++)
|
||||||
|
{
|
||||||
|
MapBlock *block = i.getNode()->getValue();
|
||||||
|
|
||||||
|
// If the mesh of the block happened to get deleted, ignore it
|
||||||
|
if(block->mesh == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float d = 0.0;
|
||||||
|
if(isBlockInSight(block->getPos(), camera_position,
|
||||||
|
camera_direction, camera_fov,
|
||||||
|
100000*BS, &d) == false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mesh animation
|
||||||
|
{
|
||||||
|
//JMutexAutoLock lock(block->mesh_mutex);
|
||||||
|
MapBlockMesh *mapBlockMesh = block->mesh;
|
||||||
|
assert(mapBlockMesh);
|
||||||
|
// Pretty random but this should work somewhat nicely
|
||||||
|
bool faraway = d >= BS*50;
|
||||||
|
//bool faraway = d >= m_control.wanted_range * BS;
|
||||||
|
if(mapBlockMesh->isAnimationForced() ||
|
||||||
|
!faraway ||
|
||||||
|
mesh_animate_count_far < (m_control.range_all ? 200 : 50))
|
||||||
|
{
|
||||||
|
bool animated = mapBlockMesh->animate(
|
||||||
|
faraway,
|
||||||
|
animation_time,
|
||||||
|
crack,
|
||||||
|
daynight_ratio);
|
||||||
|
if(animated)
|
||||||
|
mesh_animate_count++;
|
||||||
|
if(animated && faraway)
|
||||||
|
mesh_animate_count_far++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mapBlockMesh->decreaseAnimationForceTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the meshbuffers of the block
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
//JMutexAutoLock lock(block->mesh_mutex);
|
||||||
|
|
||||||
|
MapBlockMesh *mapBlockMesh = block->mesh;
|
||||||
|
assert(mapBlockMesh);
|
||||||
|
|
||||||
|
scene::SMesh *mesh = mapBlockMesh->getMesh();
|
||||||
|
assert(mesh);
|
||||||
|
|
||||||
|
u32 c = mesh->getMeshBufferCount();
|
||||||
|
for(u32 i=0; i<c; i++)
|
||||||
|
{
|
||||||
|
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
||||||
|
const video::SMaterial& material = buf->getMaterial();
|
||||||
|
video::IMaterialRenderer* rnd =
|
||||||
|
driver->getMaterialRenderer(material.MaterialType);
|
||||||
|
bool transparent = (rnd && rnd->isTransparent());
|
||||||
|
if(transparent == is_transparent_pass)
|
||||||
|
{
|
||||||
|
if(buf->getVertexCount() == 0)
|
||||||
|
errorstream<<"Block ["<<analyze_block(block)
|
||||||
|
<<"] contains an empty meshbuf"<<std::endl;
|
||||||
|
drawbufs.add(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core::list<MeshBufList> &lists = drawbufs.lists;
|
||||||
|
|
||||||
|
int timecheck_counter = 0;
|
||||||
|
for(core::list<MeshBufList>::Iterator i = lists.begin();
|
||||||
|
i != lists.end(); i++)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
timecheck_counter++;
|
timecheck_counter++;
|
||||||
|
@ -448,8 +581,19 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MapBlock *block = i.getNode()->getValue();
|
MeshBufList &list = *i;
|
||||||
|
|
||||||
|
driver->setMaterial(list.m);
|
||||||
|
|
||||||
|
for(core::list<scene::IMeshBuffer*>::Iterator j = list.bufs.begin();
|
||||||
|
j != list.bufs.end(); j++)
|
||||||
|
{
|
||||||
|
scene::IMeshBuffer *buf = *j;
|
||||||
|
driver->drawMeshBuffer(buf);
|
||||||
|
vertex_count += buf->getVertexCount();
|
||||||
|
meshbuffer_count++;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
/*
|
/*
|
||||||
Draw the faces of the block
|
Draw the faces of the block
|
||||||
*/
|
*/
|
||||||
|
@ -502,17 +646,12 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||||
else
|
else
|
||||||
blocks_without_stuff++;
|
blocks_without_stuff++;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} // ScopeProfiler
|
} // ScopeProfiler
|
||||||
|
|
||||||
// Log only on solid pass because values are the same
|
// Log only on solid pass because values are the same
|
||||||
if(pass == scene::ESNRP_SOLID){
|
if(pass == scene::ESNRP_SOLID){
|
||||||
g_profiler->avg("CM: blocks in range", blocks_in_range);
|
|
||||||
g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
|
|
||||||
if(blocks_in_range != 0)
|
|
||||||
g_profiler->avg("CM: blocks in range without mesh (frac)",
|
|
||||||
(float)blocks_in_range_without_mesh/blocks_in_range);
|
|
||||||
g_profiler->avg("CM: blocks drawn", blocks_drawn);
|
|
||||||
g_profiler->avg("CM: animated meshes", mesh_animate_count);
|
g_profiler->avg("CM: animated meshes", mesh_animate_count);
|
||||||
g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
|
g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ public:
|
||||||
return m_box;
|
return m_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateDrawList(video::IVideoDriver* driver);
|
||||||
void renderMap(video::IVideoDriver* driver, s32 pass);
|
void renderMap(video::IVideoDriver* driver, s32 pass);
|
||||||
|
|
||||||
int getBackgroundBrightness(float max_d, u32 daylight_factor,
|
int getBackgroundBrightness(float max_d, u32 daylight_factor,
|
||||||
|
@ -142,6 +143,8 @@ private:
|
||||||
f32 m_camera_fov;
|
f32 m_camera_fov;
|
||||||
JMutex m_camera_mutex;
|
JMutex m_camera_mutex;
|
||||||
|
|
||||||
|
core::map<v3s16, MapBlock*> m_drawlist;
|
||||||
|
|
||||||
core::map<v2s16, bool> m_last_drawn_sectors;
|
core::map<v2s16, bool> m_last_drawn_sectors;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -65,9 +65,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
TOSERVER_INVENTORY_FIELDS
|
TOSERVER_INVENTORY_FIELDS
|
||||||
16-bit node ids
|
16-bit node ids
|
||||||
TOCLIENT_DETACHED_INVENTORY
|
TOCLIENT_DETACHED_INVENTORY
|
||||||
|
PROTOCOL_VERSION 13:
|
||||||
|
InventoryList field "Width" (deserialization fails with old versions)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PROTOCOL_VERSION 12
|
#define PROTOCOL_VERSION 13
|
||||||
|
|
||||||
#define PROTOCOL_ID 0x4f457403
|
#define PROTOCOL_ID 0x4f457403
|
||||||
|
|
||||||
|
|
|
@ -211,6 +211,8 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
|
||||||
std::vector<aabb3f> cboxes;
|
std::vector<aabb3f> cboxes;
|
||||||
std::vector<bool> is_unloaded;
|
std::vector<bool> is_unloaded;
|
||||||
std::vector<bool> is_step_up;
|
std::vector<bool> is_step_up;
|
||||||
|
std::vector<int> bouncy_values;
|
||||||
|
std::vector<v3s16> node_positions;
|
||||||
{
|
{
|
||||||
//TimeTaker tt2("collisionMoveSimple collect boxes");
|
//TimeTaker tt2("collisionMoveSimple collect boxes");
|
||||||
ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
|
ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
|
||||||
|
@ -228,11 +230,14 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
|
||||||
for(s16 y = min_y; y <= max_y; y++)
|
for(s16 y = min_y; y <= max_y; y++)
|
||||||
for(s16 z = min_z; z <= max_z; z++)
|
for(s16 z = min_z; z <= max_z; z++)
|
||||||
{
|
{
|
||||||
|
v3s16 p(x,y,z);
|
||||||
try{
|
try{
|
||||||
// Object collides into walkable nodes
|
// Object collides into walkable nodes
|
||||||
MapNode n = map->getNode(v3s16(x,y,z));
|
MapNode n = map->getNode(p);
|
||||||
if(gamedef->getNodeDefManager()->get(n).walkable == false)
|
const ContentFeatures &f = gamedef->getNodeDefManager()->get(n);
|
||||||
|
if(f.walkable == false)
|
||||||
continue;
|
continue;
|
||||||
|
int n_bouncy_value = itemgroup_get(f.groups, "bouncy");
|
||||||
|
|
||||||
std::vector<aabb3f> nodeboxes = n.getNodeBoxes(gamedef->ndef());
|
std::vector<aabb3f> nodeboxes = n.getNodeBoxes(gamedef->ndef());
|
||||||
for(std::vector<aabb3f>::iterator
|
for(std::vector<aabb3f>::iterator
|
||||||
|
@ -245,21 +250,27 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
|
||||||
cboxes.push_back(box);
|
cboxes.push_back(box);
|
||||||
is_unloaded.push_back(false);
|
is_unloaded.push_back(false);
|
||||||
is_step_up.push_back(false);
|
is_step_up.push_back(false);
|
||||||
|
bouncy_values.push_back(n_bouncy_value);
|
||||||
|
node_positions.push_back(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e)
|
catch(InvalidPositionException &e)
|
||||||
{
|
{
|
||||||
// Collide with unloaded nodes
|
// Collide with unloaded nodes
|
||||||
aabb3f box = getNodeBox(v3s16(x,y,z), BS);
|
aabb3f box = getNodeBox(p, BS);
|
||||||
cboxes.push_back(box);
|
cboxes.push_back(box);
|
||||||
is_unloaded.push_back(true);
|
is_unloaded.push_back(true);
|
||||||
is_step_up.push_back(false);
|
is_step_up.push_back(false);
|
||||||
|
bouncy_values.push_back(0);
|
||||||
|
node_positions.push_back(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // tt2
|
} // tt2
|
||||||
|
|
||||||
assert(cboxes.size() == is_unloaded.size());
|
assert(cboxes.size() == is_unloaded.size());
|
||||||
assert(cboxes.size() == is_step_up.size());
|
assert(cboxes.size() == is_step_up.size());
|
||||||
|
assert(cboxes.size() == bouncy_values.size());
|
||||||
|
assert(cboxes.size() == node_positions.size());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collision detection
|
Collision detection
|
||||||
|
@ -342,6 +353,10 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
|
||||||
cbox.MaxEdge.Y - movingbox.MinEdge.Y,
|
cbox.MaxEdge.Y - movingbox.MinEdge.Y,
|
||||||
d));
|
d));
|
||||||
|
|
||||||
|
// Get bounce multiplier
|
||||||
|
bool bouncy = (bouncy_values[nearest_boxindex] >= 1);
|
||||||
|
float bounce = -(float)bouncy_values[nearest_boxindex] / 100.0;
|
||||||
|
|
||||||
// Move to the point of collision and reduce dtime by nearest_dtime
|
// Move to the point of collision and reduce dtime by nearest_dtime
|
||||||
if(nearest_dtime < 0)
|
if(nearest_dtime < 0)
|
||||||
{
|
{
|
||||||
|
@ -362,29 +377,57 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
|
||||||
dtime -= nearest_dtime;
|
dtime -= nearest_dtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_collision = true;
|
||||||
|
if(is_unloaded[nearest_boxindex])
|
||||||
|
is_collision = false;
|
||||||
|
|
||||||
|
CollisionInfo info;
|
||||||
|
info.type = COLLISION_NODE;
|
||||||
|
info.node_p = node_positions[nearest_boxindex];
|
||||||
|
info.bouncy = bouncy;
|
||||||
|
info.old_speed = speed_f;
|
||||||
|
|
||||||
// Set the speed component that caused the collision to zero
|
// Set the speed component that caused the collision to zero
|
||||||
if(step_up)
|
if(step_up)
|
||||||
{
|
{
|
||||||
// Special case: Handle stairs
|
// Special case: Handle stairs
|
||||||
is_step_up[nearest_boxindex] = true;
|
is_step_up[nearest_boxindex] = true;
|
||||||
|
is_collision = false;
|
||||||
}
|
}
|
||||||
else if(nearest_collided == 0) // X
|
else if(nearest_collided == 0) // X
|
||||||
{
|
{
|
||||||
speed_f.X = 0;
|
if(fabs(speed_f.X) > BS*3)
|
||||||
|
speed_f.X *= bounce;
|
||||||
|
else
|
||||||
|
speed_f.X = 0;
|
||||||
result.collides = true;
|
result.collides = true;
|
||||||
result.collides_xz = true;
|
result.collides_xz = true;
|
||||||
}
|
}
|
||||||
else if(nearest_collided == 1) // Y
|
else if(nearest_collided == 1) // Y
|
||||||
{
|
{
|
||||||
speed_f.Y = 0;
|
if(fabs(speed_f.Y) > BS*3)
|
||||||
|
speed_f.Y *= bounce;
|
||||||
|
else
|
||||||
|
speed_f.Y = 0;
|
||||||
result.collides = true;
|
result.collides = true;
|
||||||
}
|
}
|
||||||
else if(nearest_collided == 2) // Z
|
else if(nearest_collided == 2) // Z
|
||||||
{
|
{
|
||||||
speed_f.Z = 0;
|
if(fabs(speed_f.Z) > BS*3)
|
||||||
|
speed_f.Z *= bounce;
|
||||||
|
else
|
||||||
|
speed_f.Z = 0;
|
||||||
result.collides = true;
|
result.collides = true;
|
||||||
result.collides_xz = true;
|
result.collides_xz = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info.new_speed = speed_f;
|
||||||
|
if(info.new_speed.getDistanceFrom(info.old_speed) < 0.1*BS)
|
||||||
|
is_collision = false;
|
||||||
|
|
||||||
|
if(is_collision){
|
||||||
|
result.collisions.push_back(info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,12 +26,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
class Map;
|
class Map;
|
||||||
class IGameDef;
|
class IGameDef;
|
||||||
|
|
||||||
|
enum CollisionType
|
||||||
|
{
|
||||||
|
COLLISION_NODE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CollisionInfo
|
||||||
|
{
|
||||||
|
enum CollisionType type;
|
||||||
|
v3s16 node_p; // COLLISION_NODE
|
||||||
|
bool bouncy;
|
||||||
|
v3f old_speed;
|
||||||
|
v3f new_speed;
|
||||||
|
|
||||||
|
CollisionInfo():
|
||||||
|
type(COLLISION_NODE),
|
||||||
|
node_p(-32768,-32768,-32768),
|
||||||
|
bouncy(false),
|
||||||
|
old_speed(0,0,0),
|
||||||
|
new_speed(0,0,0)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
struct collisionMoveResult
|
struct collisionMoveResult
|
||||||
{
|
{
|
||||||
bool touching_ground;
|
bool touching_ground;
|
||||||
bool collides;
|
bool collides;
|
||||||
bool collides_xz;
|
bool collides_xz;
|
||||||
bool standing_on_unloaded;
|
bool standing_on_unloaded;
|
||||||
|
std::vector<CollisionInfo> collisions;
|
||||||
|
|
||||||
collisionMoveResult():
|
collisionMoveResult():
|
||||||
touching_ground(false),
|
touching_ground(false),
|
||||||
|
@ -72,16 +95,5 @@ bool wouldCollideWithCeiling(
|
||||||
f32 y_increase, f32 d);
|
f32 y_increase, f32 d);
|
||||||
|
|
||||||
|
|
||||||
enum CollisionType
|
|
||||||
{
|
|
||||||
COLLISION_FALL
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CollisionInfo
|
|
||||||
{
|
|
||||||
CollisionType t;
|
|
||||||
f32 speed;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ void set_default_settings(Settings *settings)
|
||||||
settings->setDefault("keymap_toggle_profiler", "KEY_F6");
|
settings->setDefault("keymap_toggle_profiler", "KEY_F6");
|
||||||
settings->setDefault("keymap_increase_viewing_range_min", "+");
|
settings->setDefault("keymap_increase_viewing_range_min", "+");
|
||||||
settings->setDefault("keymap_decrease_viewing_range_min", "-");
|
settings->setDefault("keymap_decrease_viewing_range_min", "-");
|
||||||
|
settings->setDefault("aux1_descends", "false");
|
||||||
// Some (temporary) keys for debugging
|
// Some (temporary) keys for debugging
|
||||||
settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P");
|
settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P");
|
||||||
settings->setDefault("keymap_quicktune_prev", "KEY_HOME");
|
settings->setDefault("keymap_quicktune_prev", "KEY_HOME");
|
||||||
|
|
|
@ -2034,19 +2034,32 @@ void ClientEnvironment::step(float dtime)
|
||||||
i != player_collisions.end(); i++)
|
i != player_collisions.end(); i++)
|
||||||
{
|
{
|
||||||
CollisionInfo &info = *i;
|
CollisionInfo &info = *i;
|
||||||
if(info.t == COLLISION_FALL)
|
v3f speed_diff = info.new_speed - info.old_speed;;
|
||||||
|
// Handle only fall damage
|
||||||
|
// (because otherwise walking against something in fast_move kills you)
|
||||||
|
if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
|
||||||
|
continue;
|
||||||
|
// Get rid of other components
|
||||||
|
speed_diff.X = 0;
|
||||||
|
speed_diff.Z = 0;
|
||||||
|
f32 pre_factor = 1; // 1 hp per node/s
|
||||||
|
f32 tolerance = BS*14; // 5 without damage
|
||||||
|
f32 post_factor = 1; // 1 hp per node/s
|
||||||
|
if(info.type == COLLISION_NODE)
|
||||||
{
|
{
|
||||||
//f32 tolerance = BS*10; // 2 without damage
|
const ContentFeatures &f = m_gamedef->ndef()->
|
||||||
//f32 tolerance = BS*12; // 3 without damage
|
get(m_map->getNodeNoEx(info.node_p));
|
||||||
f32 tolerance = BS*14; // 5 without damage
|
// Determine fall damage multiplier
|
||||||
f32 factor = 1;
|
int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
|
||||||
if(info.speed > tolerance)
|
pre_factor = 1.0 + (float)addp/100.0;
|
||||||
{
|
}
|
||||||
f32 damage_f = (info.speed - tolerance)/BS*factor;
|
float speed = pre_factor * speed_diff.getLength();
|
||||||
u16 damage = (u16)(damage_f+0.5);
|
if(speed > tolerance)
|
||||||
if(damage != 0)
|
{
|
||||||
damageLocalPlayer(damage, true);
|
f32 damage_f = (speed - tolerance)/BS * post_factor;
|
||||||
}
|
u16 damage = (u16)(damage_f+0.5);
|
||||||
|
if(damage != 0)
|
||||||
|
damageLocalPlayer(damage, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
src/game.cpp
15
src/game.cpp
|
@ -1235,6 +1235,9 @@ void the_game(
|
||||||
float object_hit_delay_timer = 0.0;
|
float object_hit_delay_timer = 0.0;
|
||||||
float time_from_last_punch = 10;
|
float time_from_last_punch = 10;
|
||||||
|
|
||||||
|
float update_draw_list_timer = 0.0;
|
||||||
|
v3f update_draw_list_last_cam_dir;
|
||||||
|
|
||||||
bool invert_mouse = g_settings->getBool("invert_mouse");
|
bool invert_mouse = g_settings->getBool("invert_mouse");
|
||||||
|
|
||||||
bool respawn_menu_active = false;
|
bool respawn_menu_active = false;
|
||||||
|
@ -2698,6 +2701,18 @@ void the_game(
|
||||||
camera.wield(item);
|
camera.wield(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Update block draw list every 200ms or when camera direction has
|
||||||
|
changed much
|
||||||
|
*/
|
||||||
|
update_draw_list_timer += dtime;
|
||||||
|
if(update_draw_list_timer >= 0.2 ||
|
||||||
|
update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2){
|
||||||
|
update_draw_list_timer = 0;
|
||||||
|
client.getEnv().getClientMap().updateDrawList(driver);
|
||||||
|
update_draw_list_last_cam_dir = camera_direction;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Drawing begins
|
Drawing begins
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -733,6 +733,54 @@ void GUIFormSpecMenu::drawMenu()
|
||||||
|
|
||||||
void GUIFormSpecMenu::updateSelectedItem()
|
void GUIFormSpecMenu::updateSelectedItem()
|
||||||
{
|
{
|
||||||
|
// WARNING: BLACK MAGIC
|
||||||
|
// See if there is a stack suited for our current guess.
|
||||||
|
// If such stack does not exist, clear the guess.
|
||||||
|
if(m_selected_content_guess.name != "")
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for(u32 i=0; i<m_inventorylists.size() && !found; i++){
|
||||||
|
const ListDrawSpec &s = m_inventorylists[i];
|
||||||
|
Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
|
||||||
|
if(!inv)
|
||||||
|
continue;
|
||||||
|
InventoryList *list = inv->getList(s.listname);
|
||||||
|
if(!list)
|
||||||
|
continue;
|
||||||
|
for(s32 i=0; i<s.geom.X*s.geom.Y && !found; i++){
|
||||||
|
u32 item_i = i + s.start_item_i;
|
||||||
|
if(item_i >= list->getSize())
|
||||||
|
continue;
|
||||||
|
ItemStack stack = list->getItem(item_i);
|
||||||
|
if(stack.name == m_selected_content_guess.name &&
|
||||||
|
stack.count == m_selected_content_guess.count){
|
||||||
|
found = true;
|
||||||
|
if(m_selected_item){
|
||||||
|
// If guessed stack is already selected, all is fine
|
||||||
|
if(m_selected_item->inventoryloc == s.inventoryloc &&
|
||||||
|
m_selected_item->listname == s.listname &&
|
||||||
|
m_selected_item->i == (s32)item_i &&
|
||||||
|
m_selected_amount == stack.count){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delete m_selected_item;
|
||||||
|
m_selected_item = NULL;
|
||||||
|
}
|
||||||
|
infostream<<"Client: Changing selected content guess to "
|
||||||
|
<<s.inventoryloc.dump()<<" "<<s.listname
|
||||||
|
<<" "<<item_i<<std::endl;
|
||||||
|
m_selected_item = new ItemSpec(s.inventoryloc, s.listname, item_i);
|
||||||
|
m_selected_amount = stack.count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found){
|
||||||
|
infostream<<"Client: Discarding selected content guess: "
|
||||||
|
<<m_selected_content_guess.getItemString()<<std::endl;
|
||||||
|
m_selected_content_guess.name = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
// If the selected stack has become empty for some reason, deselect it.
|
// If the selected stack has become empty for some reason, deselect it.
|
||||||
// If the selected stack has become smaller, adjust m_selected_amount.
|
// If the selected stack has become smaller, adjust m_selected_amount.
|
||||||
if(m_selected_item)
|
if(m_selected_item)
|
||||||
|
@ -1054,21 +1102,28 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||||
// Check how many items can be moved
|
// Check how many items can be moved
|
||||||
move_amount = stack_from.count = MYMIN(move_amount, stack_from.count);
|
move_amount = stack_from.count = MYMIN(move_amount, stack_from.count);
|
||||||
ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef());
|
ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef());
|
||||||
if(leftover.count == stack_from.count)
|
// If source stack cannot be added to destination stack at all,
|
||||||
|
// they are swapped
|
||||||
|
if(leftover.count == stack_from.count && leftover.name == stack_from.name)
|
||||||
{
|
{
|
||||||
// Swap the stacks
|
m_selected_amount = stack_to.count;
|
||||||
m_selected_amount -= stack_to.count;
|
// In case the server doesn't directly swap them but instead
|
||||||
|
// moves stack_to somewhere else, set this
|
||||||
|
m_selected_content_guess = stack_to;
|
||||||
|
m_selected_content_guess_inventory = s.inventoryloc;
|
||||||
}
|
}
|
||||||
|
// Source stack goes fully into destination stack
|
||||||
else if(leftover.empty())
|
else if(leftover.empty())
|
||||||
{
|
{
|
||||||
// Item fits
|
|
||||||
m_selected_amount -= move_amount;
|
m_selected_amount -= move_amount;
|
||||||
|
m_selected_content_guess = ItemStack(); // Clear
|
||||||
}
|
}
|
||||||
|
// Source stack goes partly into destination stack
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Item only fits partially
|
|
||||||
move_amount -= leftover.count;
|
move_amount -= leftover.count;
|
||||||
m_selected_amount -= move_amount;
|
m_selected_amount -= move_amount;
|
||||||
|
m_selected_content_guess = ItemStack(); // Clear
|
||||||
}
|
}
|
||||||
|
|
||||||
infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
|
infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
|
||||||
|
@ -1084,6 +1139,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||||
}
|
}
|
||||||
else if(drop_amount > 0)
|
else if(drop_amount > 0)
|
||||||
{
|
{
|
||||||
|
m_selected_content_guess = ItemStack(); // Clear
|
||||||
|
|
||||||
// Send IACTION_DROP
|
// Send IACTION_DROP
|
||||||
|
|
||||||
assert(m_selected_item && m_selected_item->isValid());
|
assert(m_selected_item && m_selected_item->isValid());
|
||||||
|
@ -1107,6 +1164,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||||
}
|
}
|
||||||
else if(craft_amount > 0)
|
else if(craft_amount > 0)
|
||||||
{
|
{
|
||||||
|
m_selected_content_guess = ItemStack(); // Clear
|
||||||
|
|
||||||
// Send IACTION_CRAFT
|
// Send IACTION_CRAFT
|
||||||
|
|
||||||
assert(s.isValid());
|
assert(s.isValid());
|
||||||
|
@ -1126,6 +1185,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||||
m_selected_item = NULL;
|
m_selected_item = NULL;
|
||||||
m_selected_amount = 0;
|
m_selected_amount = 0;
|
||||||
m_selected_dragging = false;
|
m_selected_dragging = false;
|
||||||
|
m_selected_content_guess = ItemStack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(event.EventType==EET_GUI_EVENT)
|
if(event.EventType==EET_GUI_EVENT)
|
||||||
|
|
|
@ -213,6 +213,12 @@ protected:
|
||||||
u32 m_selected_amount;
|
u32 m_selected_amount;
|
||||||
bool m_selected_dragging;
|
bool m_selected_dragging;
|
||||||
|
|
||||||
|
// WARNING: BLACK MAGIC
|
||||||
|
// Used to guess and keep up with some special things the server can do.
|
||||||
|
// If name is "", no guess exists.
|
||||||
|
ItemStack m_selected_content_guess;
|
||||||
|
InventoryLocation m_selected_content_guess_inventory;
|
||||||
|
|
||||||
v2s32 m_pointer;
|
v2s32 m_pointer;
|
||||||
gui::IGUIStaticText *m_tooltip_element;
|
gui::IGUIStaticText *m_tooltip_element;
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,11 +30,14 @@
|
||||||
#include <IGUIStaticText.h>
|
#include <IGUIStaticText.h>
|
||||||
#include <IGUIFont.h>
|
#include <IGUIFont.h>
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#define KMaxButtonPerColumns 12
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
|
GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
|
||||||
//buttons
|
// buttons
|
||||||
GUI_ID_KEY_FORWARD_BUTTON,
|
GUI_ID_KEY_FORWARD_BUTTON,
|
||||||
GUI_ID_KEY_BACKWARD_BUTTON,
|
GUI_ID_KEY_BACKWARD_BUTTON,
|
||||||
GUI_ID_KEY_LEFT_BUTTON,
|
GUI_ID_KEY_LEFT_BUTTON,
|
||||||
|
@ -50,15 +53,21 @@ enum
|
||||||
GUI_ID_KEY_DROP_BUTTON,
|
GUI_ID_KEY_DROP_BUTTON,
|
||||||
GUI_ID_KEY_INVENTORY_BUTTON,
|
GUI_ID_KEY_INVENTORY_BUTTON,
|
||||||
GUI_ID_KEY_DUMP_BUTTON,
|
GUI_ID_KEY_DUMP_BUTTON,
|
||||||
GUI_ID_KEY_RANGE_BUTTON
|
GUI_ID_KEY_RANGE_BUTTON,
|
||||||
|
// other
|
||||||
|
GUI_ID_CB_AUX1_DESCENDS,
|
||||||
};
|
};
|
||||||
|
|
||||||
GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
|
GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
|
||||||
gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) :
|
gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) :
|
||||||
GUIModalMenu(env, parent, id, menumgr)
|
GUIModalMenu(env, parent, id, menumgr)
|
||||||
{
|
{
|
||||||
|
shift_down = false;
|
||||||
activeKey = -1;
|
activeKey = -1;
|
||||||
|
this->key_used_text = NULL;
|
||||||
init_keys();
|
init_keys();
|
||||||
|
for(size_t i=0; i<key_settings.size(); i++)
|
||||||
|
this->key_used.push_back(key_settings.at(i)->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUIKeyChangeMenu::~GUIKeyChangeMenu()
|
GUIKeyChangeMenu::~GUIKeyChangeMenu()
|
||||||
|
@ -71,12 +80,12 @@ void GUIKeyChangeMenu::removeChildren()
|
||||||
const core::list<gui::IGUIElement*> &children = getChildren();
|
const core::list<gui::IGUIElement*> &children = getChildren();
|
||||||
core::list<gui::IGUIElement*> children_copy;
|
core::list<gui::IGUIElement*> children_copy;
|
||||||
for (core::list<gui::IGUIElement*>::ConstIterator i = children.begin(); i
|
for (core::list<gui::IGUIElement*>::ConstIterator i = children.begin(); i
|
||||||
!= children.end(); i++)
|
!= children.end(); i++)
|
||||||
{
|
{
|
||||||
children_copy.push_back(*i);
|
children_copy.push_back(*i);
|
||||||
}
|
}
|
||||||
for (core::list<gui::IGUIElement*>::Iterator i = children_copy.begin(); i
|
for (core::list<gui::IGUIElement*>::Iterator i = children_copy.begin(); i
|
||||||
!= children_copy.end(); i++)
|
!= children_copy.end(); i++)
|
||||||
{
|
{
|
||||||
(*i)->remove();
|
(*i)->remove();
|
||||||
}
|
}
|
||||||
|
@ -84,20 +93,12 @@ void GUIKeyChangeMenu::removeChildren()
|
||||||
|
|
||||||
void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
Remove stuff
|
|
||||||
*/
|
|
||||||
removeChildren();
|
removeChildren();
|
||||||
|
|
||||||
/*
|
|
||||||
Calculate new sizes and positions
|
|
||||||
*/
|
|
||||||
|
|
||||||
v2s32 size(620, 430);
|
v2s32 size(620, 430);
|
||||||
|
|
||||||
core::rect < s32 > rect(screensize.X / 2 - size.X / 2,
|
core::rect < s32 > rect(screensize.X / 2 - size.X / 2,
|
||||||
screensize.Y / 2 - size.Y / 2, screensize.X / 2 + size.X / 2,
|
screensize.Y / 2 - size.Y / 2, screensize.X / 2 + size.X / 2,
|
||||||
screensize.Y / 2 + size.Y / 2);
|
screensize.Y / 2 + size.Y / 2);
|
||||||
|
|
||||||
DesiredRect = rect;
|
DesiredRect = rect;
|
||||||
recalculateAbsolutePosition(false);
|
recalculateAbsolutePosition(false);
|
||||||
|
@ -109,271 +110,60 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
||||||
rect += topleft + v2s32(25, 3);
|
rect += topleft + v2s32(25, 3);
|
||||||
//gui::IGUIStaticText *t =
|
//gui::IGUIStaticText *t =
|
||||||
Environment->addStaticText(wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)"),
|
Environment->addStaticText(wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)"),
|
||||||
rect, false, true, this, -1);
|
rect, false, true, this, -1);
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build buttons
|
||||||
|
|
||||||
v2s32 offset(25, 60);
|
v2s32 offset(25, 60);
|
||||||
// buttons
|
|
||||||
|
|
||||||
|
for(size_t i = 0; i < key_settings.size(); i++)
|
||||||
{
|
{
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
key_setting *k = key_settings.at(i);
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
{
|
||||||
Environment->addStaticText(wgettext("Forward"),
|
core::rect < s32 > rect(0, 0, 100, 20);
|
||||||
rect, false, true, this, -1);
|
rect += topleft + v2s32(offset.X, offset.Y);
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
Environment->addStaticText(k->button_name, rect, false, true, this, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
core::rect < s32 > rect(0, 0, 100, 30);
|
||||||
|
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
||||||
|
k->button = Environment->addButton(rect, this, k->id, wgettext(k->key.name()));
|
||||||
|
}
|
||||||
|
if(i + 1 == KMaxButtonPerColumns)
|
||||||
|
offset = v2s32(250, 60);
|
||||||
|
else
|
||||||
|
offset += v2s32(0, 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
s32 option_x = offset.X + 10;
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
s32 option_y = offset.Y;
|
||||||
this->forward = Environment->addButton(rect, this,
|
u32 option_w = 180;
|
||||||
GUI_ID_KEY_FORWARD_BUTTON,
|
{
|
||||||
wgettext(key_forward.name()));
|
core::rect<s32> rect(0, 0, option_w, 30);
|
||||||
|
rect += topleft + v2s32(option_x, option_y);
|
||||||
|
Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
|
||||||
|
GUI_ID_CB_AUX1_DESCENDS, wgettext("\"Use\" = climb down"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Backward"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->backward = Environment->addButton(rect, this,
|
|
||||||
GUI_ID_KEY_BACKWARD_BUTTON,
|
|
||||||
wgettext(key_backward.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Left"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->left = Environment->addButton(rect, this, GUI_ID_KEY_LEFT_BUTTON,
|
|
||||||
wgettext(key_left.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Right"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->right = Environment->addButton(rect, this,
|
|
||||||
GUI_ID_KEY_RIGHT_BUTTON,
|
|
||||||
wgettext(key_right.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Use"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->use = Environment->addButton(rect, this, GUI_ID_KEY_USE_BUTTON,
|
|
||||||
wgettext(key_use.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Sneak"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->sneak = Environment->addButton(rect, this,
|
|
||||||
GUI_ID_KEY_SNEAK_BUTTON,
|
|
||||||
wgettext(key_sneak.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Jump"), rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->jump = Environment->addButton(rect, this, GUI_ID_KEY_JUMP_BUTTON,
|
|
||||||
wgettext(key_jump.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Drop"), rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->dropbtn = Environment->addButton(rect, this, GUI_ID_KEY_DROP_BUTTON,
|
|
||||||
wgettext(key_drop.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Inventory"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->inventory = Environment->addButton(rect, this,
|
|
||||||
GUI_ID_KEY_INVENTORY_BUTTON,
|
|
||||||
wgettext(key_inventory.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Chat"), rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->chat = Environment->addButton(rect, this, GUI_ID_KEY_CHAT_BUTTON,
|
|
||||||
wgettext(key_chat.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Command"), rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->cmd = Environment->addButton(rect, this, GUI_ID_KEY_CMD_BUTTON,
|
|
||||||
wgettext(key_cmd.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Console"), rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->console = Environment->addButton(rect, this, GUI_ID_KEY_CONSOLE_BUTTON,
|
|
||||||
wgettext(key_console.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
//next col
|
|
||||||
offset = v2s32(250, 60);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Toggle fly"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->fly = Environment->addButton(rect, this, GUI_ID_KEY_FLY_BUTTON,
|
|
||||||
wgettext(key_fly.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Toggle fast"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->fast = Environment->addButton(rect, this, GUI_ID_KEY_FAST_BUTTON,
|
|
||||||
wgettext(key_fast.name()));
|
|
||||||
}
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Range select"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->range = Environment->addButton(rect, this,
|
|
||||||
GUI_ID_KEY_RANGE_BUTTON,
|
|
||||||
wgettext(key_range.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += v2s32(0, 25);
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 20);
|
|
||||||
rect += topleft + v2s32(offset.X, offset.Y);
|
|
||||||
Environment->addStaticText(wgettext("Print stacks"),
|
|
||||||
rect, false, true, this, -1);
|
|
||||||
//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
|
||||||
rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
|
|
||||||
this->dump = Environment->addButton(rect, this, GUI_ID_KEY_DUMP_BUTTON,
|
|
||||||
wgettext(key_dump.name()));
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
core::rect < s32 > rect(0, 0, 100, 30);
|
||||||
rect += topleft + v2s32(size.X - 100 - 20, size.Y - 40);
|
rect += topleft + v2s32(size.X - 100 - 20, size.Y - 40);
|
||||||
Environment->addButton(rect, this, GUI_ID_BACK_BUTTON,
|
Environment->addButton(rect, this, GUI_ID_BACK_BUTTON,
|
||||||
wgettext("Save"));
|
wgettext("Save"));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
core::rect < s32 > rect(0, 0, 100, 30);
|
core::rect < s32 > rect(0, 0, 100, 30);
|
||||||
rect += topleft + v2s32(size.X - 100 - 20 - 100 - 20, size.Y - 40);
|
rect += topleft + v2s32(size.X - 100 - 20 - 100 - 20, size.Y - 40);
|
||||||
Environment->addButton(rect, this, GUI_ID_ABORT_BUTTON,
|
Environment->addButton(rect, this, GUI_ID_ABORT_BUTTON,
|
||||||
wgettext("Cancel"));
|
wgettext("Cancel"));
|
||||||
}
|
}
|
||||||
changeCtype("C");
|
changeCtype("C");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIKeyChangeMenu::drawMenu()
|
void GUIKeyChangeMenu::drawMenu()
|
||||||
|
@ -396,102 +186,32 @@ void GUIKeyChangeMenu::drawMenu()
|
||||||
|
|
||||||
bool GUIKeyChangeMenu::acceptInput()
|
bool GUIKeyChangeMenu::acceptInput()
|
||||||
{
|
{
|
||||||
g_settings->set("keymap_forward", key_forward.sym());
|
for(size_t i = 0; i < key_settings.size(); i++)
|
||||||
g_settings->set("keymap_backward", key_backward.sym());
|
{
|
||||||
g_settings->set("keymap_left", key_left.sym());
|
key_setting *k = key_settings.at(i);
|
||||||
g_settings->set("keymap_right", key_right.sym());
|
g_settings->set(k->setting_name, k->key.sym());
|
||||||
g_settings->set("keymap_jump", key_jump.sym());
|
}
|
||||||
g_settings->set("keymap_sneak", key_sneak.sym());
|
{
|
||||||
g_settings->set("keymap_drop", key_drop.sym());
|
gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS);
|
||||||
g_settings->set("keymap_inventory", key_inventory.sym());
|
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||||
g_settings->set("keymap_chat", key_chat.sym());
|
g_settings->setBool("aux1_descends", ((gui::IGUICheckBox*)e)->isChecked());
|
||||||
g_settings->set("keymap_cmd", key_cmd.sym());
|
}
|
||||||
g_settings->set("keymap_console", key_console.sym());
|
|
||||||
g_settings->set("keymap_rangeselect", key_range.sym());
|
|
||||||
g_settings->set("keymap_freemove", key_fly.sym());
|
|
||||||
g_settings->set("keymap_fastmove", key_fast.sym());
|
|
||||||
g_settings->set("keymap_special1", key_use.sym());
|
|
||||||
g_settings->set("keymap_print_debug_stacks", key_dump.sym());
|
|
||||||
clearKeyCache();
|
clearKeyCache();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void GUIKeyChangeMenu::init_keys()
|
|
||||||
{
|
|
||||||
key_forward = getKeySetting("keymap_forward");
|
|
||||||
key_backward = getKeySetting("keymap_backward");
|
|
||||||
key_left = getKeySetting("keymap_left");
|
|
||||||
key_right = getKeySetting("keymap_right");
|
|
||||||
key_jump = getKeySetting("keymap_jump");
|
|
||||||
key_sneak = getKeySetting("keymap_sneak");
|
|
||||||
key_drop = getKeySetting("keymap_drop");
|
|
||||||
key_inventory = getKeySetting("keymap_inventory");
|
|
||||||
key_chat = getKeySetting("keymap_chat");
|
|
||||||
key_cmd = getKeySetting("keymap_cmd");
|
|
||||||
key_console = getKeySetting("keymap_console");
|
|
||||||
key_range = getKeySetting("keymap_rangeselect");
|
|
||||||
key_fly = getKeySetting("keymap_freemove");
|
|
||||||
key_fast = getKeySetting("keymap_fastmove");
|
|
||||||
key_use = getKeySetting("keymap_special1");
|
|
||||||
key_dump = getKeySetting("keymap_print_debug_stacks");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GUIKeyChangeMenu::resetMenu()
|
bool GUIKeyChangeMenu::resetMenu()
|
||||||
{
|
{
|
||||||
if (activeKey >= 0)
|
if (activeKey >= 0)
|
||||||
{
|
{
|
||||||
switch (activeKey)
|
for(size_t i = 0; i < key_settings.size(); i++)
|
||||||
{
|
{
|
||||||
case GUI_ID_KEY_FORWARD_BUTTON:
|
key_setting *k = key_settings.at(i);
|
||||||
this->forward->setText(
|
if(k->id == activeKey)
|
||||||
wgettext(key_forward.name()));
|
{
|
||||||
break;
|
k->button->setText(wgettext(k->key.name()));
|
||||||
case GUI_ID_KEY_BACKWARD_BUTTON:
|
break;
|
||||||
this->backward->setText(
|
}
|
||||||
wgettext(key_backward.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_LEFT_BUTTON:
|
|
||||||
this->left->setText(wgettext(key_left.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_RIGHT_BUTTON:
|
|
||||||
this->right->setText(wgettext(key_right.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_JUMP_BUTTON:
|
|
||||||
this->jump->setText(wgettext(key_jump.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_SNEAK_BUTTON:
|
|
||||||
this->sneak->setText(wgettext(key_sneak.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_DROP_BUTTON:
|
|
||||||
this->dropbtn->setText(wgettext(key_drop.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_INVENTORY_BUTTON:
|
|
||||||
this->inventory->setText(
|
|
||||||
wgettext(key_inventory.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_CHAT_BUTTON:
|
|
||||||
this->chat->setText(wgettext(key_chat.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_CMD_BUTTON:
|
|
||||||
this->cmd->setText(wgettext(key_cmd.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_CONSOLE_BUTTON:
|
|
||||||
this->console->setText(wgettext(key_console.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_RANGE_BUTTON:
|
|
||||||
this->range->setText(wgettext(key_range.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_FLY_BUTTON:
|
|
||||||
this->fly->setText(wgettext(key_fly.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_FAST_BUTTON:
|
|
||||||
this->fast->setText(wgettext(key_fast.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_USE_BUTTON:
|
|
||||||
this->use->setText(wgettext(key_use.name()));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_DUMP_BUTTON:
|
|
||||||
this->dump->setText(wgettext(key_dump.name()));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
activeKey = -1;
|
activeKey = -1;
|
||||||
return false;
|
return false;
|
||||||
|
@ -501,104 +221,72 @@ bool GUIKeyChangeMenu::resetMenu()
|
||||||
bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
|
bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
|
||||||
{
|
{
|
||||||
if (event.EventType == EET_KEY_INPUT_EVENT && activeKey >= 0
|
if (event.EventType == EET_KEY_INPUT_EVENT && activeKey >= 0
|
||||||
&& event.KeyInput.PressedDown)
|
&& event.KeyInput.PressedDown)
|
||||||
{
|
{
|
||||||
changeCtype("");
|
changeCtype("");
|
||||||
KeyPress kp(event.KeyInput);
|
bool prefer_character = shift_down;
|
||||||
|
KeyPress kp(event.KeyInput, prefer_character);
|
||||||
|
|
||||||
if (activeKey == GUI_ID_KEY_FORWARD_BUTTON)
|
bool shift_went_down = false;
|
||||||
|
if(!shift_down &&
|
||||||
|
(event.KeyInput.Key == irr::KEY_SHIFT ||
|
||||||
|
event.KeyInput.Key == irr::KEY_LSHIFT ||
|
||||||
|
event.KeyInput.Key == irr::KEY_RSHIFT))
|
||||||
|
shift_went_down = true;
|
||||||
|
|
||||||
|
// Remove Key already in use message
|
||||||
|
if(this->key_used_text)
|
||||||
{
|
{
|
||||||
this->forward->setText(wgettext(kp.name()));
|
this->key_used_text->remove();
|
||||||
this->key_forward = kp;
|
this->key_used_text = NULL;
|
||||||
}
|
}
|
||||||
else if (activeKey == GUI_ID_KEY_BACKWARD_BUTTON)
|
// Display Key already in use message
|
||||||
|
if (std::find(this->key_used.begin(), this->key_used.end(), kp) != this->key_used.end())
|
||||||
{
|
{
|
||||||
this->backward->setText(wgettext(kp.name()));
|
core::rect < s32 > rect(0, 0, 600, 40);
|
||||||
this->key_backward = kp;
|
rect += v2s32(0, 0) + v2s32(25, 30);
|
||||||
|
this->key_used_text = Environment->addStaticText(wgettext("Key already in use"),
|
||||||
|
rect, false, true, this, -1);
|
||||||
|
//infostream << "Key already in use" << std::endl;
|
||||||
}
|
}
|
||||||
else if (activeKey == GUI_ID_KEY_LEFT_BUTTON)
|
|
||||||
|
// But go on
|
||||||
{
|
{
|
||||||
this->left->setText(wgettext(kp.name()));
|
key_setting *k=NULL;
|
||||||
this->key_left = kp;
|
for(size_t i = 0; i < key_settings.size(); i++)
|
||||||
|
{
|
||||||
|
if(key_settings.at(i)->id == activeKey)
|
||||||
|
{
|
||||||
|
k = key_settings.at(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(k);
|
||||||
|
k->key = kp;
|
||||||
|
k->button->setText(wgettext(k->key.name()));
|
||||||
|
|
||||||
|
this->key_used.push_back(kp);
|
||||||
|
|
||||||
|
changeCtype("C");
|
||||||
|
// Allow characters made with shift
|
||||||
|
if(shift_went_down){
|
||||||
|
shift_down = true;
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
activeKey = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (activeKey == GUI_ID_KEY_RIGHT_BUTTON)
|
|
||||||
{
|
|
||||||
this->right->setText(wgettext(kp.name()));
|
|
||||||
this->key_right = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_JUMP_BUTTON)
|
|
||||||
{
|
|
||||||
this->jump->setText(wgettext(kp.name()));
|
|
||||||
this->key_jump = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_SNEAK_BUTTON)
|
|
||||||
{
|
|
||||||
this->sneak->setText(wgettext(kp.name()));
|
|
||||||
this->key_sneak = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_DROP_BUTTON)
|
|
||||||
{
|
|
||||||
this->dropbtn->setText(wgettext(kp.name()));
|
|
||||||
this->key_drop = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_INVENTORY_BUTTON)
|
|
||||||
{
|
|
||||||
this->inventory->setText(wgettext(kp.name()));
|
|
||||||
this->key_inventory = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_CHAT_BUTTON)
|
|
||||||
{
|
|
||||||
this->chat->setText(wgettext(kp.name()));
|
|
||||||
this->key_chat = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_CMD_BUTTON)
|
|
||||||
{
|
|
||||||
this->cmd->setText(wgettext(kp.name()));
|
|
||||||
this->key_cmd = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_CONSOLE_BUTTON)
|
|
||||||
{
|
|
||||||
this->console->setText(wgettext(kp.name()));
|
|
||||||
this->key_console = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_RANGE_BUTTON)
|
|
||||||
{
|
|
||||||
this->range->setText(wgettext(kp.name()));
|
|
||||||
this->key_range = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_FLY_BUTTON)
|
|
||||||
{
|
|
||||||
this->fly->setText(wgettext(kp.name()));
|
|
||||||
this->key_fly = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_FAST_BUTTON)
|
|
||||||
{
|
|
||||||
this->fast->setText(wgettext(kp.name()));
|
|
||||||
this->key_fast = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_USE_BUTTON)
|
|
||||||
{
|
|
||||||
this->use->setText(wgettext(kp.name()));
|
|
||||||
this->key_use = kp;
|
|
||||||
}
|
|
||||||
else if (activeKey == GUI_ID_KEY_DUMP_BUTTON)
|
|
||||||
{
|
|
||||||
this->dump->setText(wgettext(kp.name()));
|
|
||||||
this->key_dump = kp;
|
|
||||||
}
|
|
||||||
changeCtype("C");
|
|
||||||
activeKey = -1;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if (event.EventType == EET_GUI_EVENT)
|
if (event.EventType == EET_GUI_EVENT)
|
||||||
{
|
{
|
||||||
if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
|
if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
|
||||||
&& isVisible())
|
&& isVisible())
|
||||||
{
|
{
|
||||||
if (!canTakeFocus(event.GUIEvent.Element))
|
if (!canTakeFocus(event.GUIEvent.Element))
|
||||||
{
|
{
|
||||||
dstream << "GUIMainMenu: Not allowing focus change."
|
dstream << "GUIMainMenu: Not allowing focus change."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
// Returning true disables focus change
|
// Returning true disables focus change
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -606,106 +294,74 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
|
||||||
if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
|
if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
|
||||||
{
|
{
|
||||||
if(event.GUIEvent.Caller->getID() != GUI_ID_BACK_BUTTON &&
|
if(event.GUIEvent.Caller->getID() != GUI_ID_BACK_BUTTON &&
|
||||||
event.GUIEvent.Caller->getID() != GUI_ID_ABORT_BUTTON)
|
event.GUIEvent.Caller->getID() != GUI_ID_ABORT_BUTTON)
|
||||||
{
|
{
|
||||||
changeCtype("");
|
changeCtype("");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (event.GUIEvent.Caller->getID())
|
switch (event.GUIEvent.Caller->getID())
|
||||||
{
|
{
|
||||||
case GUI_ID_BACK_BUTTON: //back
|
case GUI_ID_BACK_BUTTON: //back
|
||||||
acceptInput();
|
acceptInput();
|
||||||
quitMenu();
|
quitMenu();
|
||||||
return true;
|
return true;
|
||||||
case GUI_ID_ABORT_BUTTON: //abort
|
case GUI_ID_ABORT_BUTTON: //abort
|
||||||
quitMenu();
|
quitMenu();
|
||||||
return true;
|
return true;
|
||||||
case GUI_ID_KEY_FORWARD_BUTTON:
|
default:
|
||||||
resetMenu();
|
key_setting *k = NULL;
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
for(size_t i = 0; i < key_settings.size(); i++)
|
||||||
this->forward->setText(wgettext("press Key"));
|
{
|
||||||
break;
|
if(key_settings.at(i)->id == event.GUIEvent.Caller->getID())
|
||||||
case GUI_ID_KEY_BACKWARD_BUTTON:
|
{
|
||||||
resetMenu();
|
k = key_settings.at(i);
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
break;
|
||||||
this->backward->setText(wgettext("press Key"));
|
}
|
||||||
break;
|
}
|
||||||
case GUI_ID_KEY_LEFT_BUTTON:
|
assert(k);
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
resetMenu();
|
||||||
this->left->setText(wgettext("press Key"));
|
shift_down = false;
|
||||||
break;
|
activeKey = event.GUIEvent.Caller->getID();
|
||||||
case GUI_ID_KEY_RIGHT_BUTTON:
|
k->button->setText(wgettext("press key"));
|
||||||
resetMenu();
|
this->key_used.erase(std::remove(this->key_used.begin(),
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
this->key_used.end(), k->key), this->key_used.end());
|
||||||
this->right->setText(wgettext("press Key"));
|
break;
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_USE_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->use->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_FLY_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->fly->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_FAST_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->fast->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_JUMP_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->jump->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_DROP_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->dropbtn->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_CHAT_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->chat->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_CMD_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->cmd->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_CONSOLE_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->console->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_SNEAK_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->sneak->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_INVENTORY_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->inventory->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_DUMP_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->dump->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
case GUI_ID_KEY_RANGE_BUTTON:
|
|
||||||
resetMenu();
|
|
||||||
activeKey = event.GUIEvent.Caller->getID();
|
|
||||||
this->range->setText(wgettext("press Key"));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
Environment->setFocus(this);
|
||||||
//Buttons
|
//Buttons
|
||||||
changeCtype("C");
|
changeCtype("C");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Parent ? Parent->OnEvent(event) : false;
|
return Parent ? Parent->OnEvent(event) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUIKeyChangeMenu::add_key(int id, std::string button_name, std::string setting_name)
|
||||||
|
{
|
||||||
|
key_setting *k = new key_setting;
|
||||||
|
k->id = id;
|
||||||
|
k->button_name = wgettext(button_name.c_str());
|
||||||
|
k->setting_name = setting_name;
|
||||||
|
k->key = getKeySetting(k->setting_name.c_str());
|
||||||
|
key_settings.push_back(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIKeyChangeMenu::init_keys()
|
||||||
|
{
|
||||||
|
this->add_key(GUI_ID_KEY_FORWARD_BUTTON, "Forward", "keymap_forward");
|
||||||
|
this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, "Backward", "keymap_backward");
|
||||||
|
this->add_key(GUI_ID_KEY_LEFT_BUTTON, "Left", "keymap_left");
|
||||||
|
this->add_key(GUI_ID_KEY_RIGHT_BUTTON, "Right", "keymap_right");
|
||||||
|
this->add_key(GUI_ID_KEY_USE_BUTTON, "Use", "keymap_special1");
|
||||||
|
this->add_key(GUI_ID_KEY_JUMP_BUTTON, "Jump", "keymap_jump");
|
||||||
|
this->add_key(GUI_ID_KEY_SNEAK_BUTTON, "Sneak", "keymap_sneak");
|
||||||
|
this->add_key(GUI_ID_KEY_DROP_BUTTON, "Drop", "keymap_drop");
|
||||||
|
this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, "Inventory", "keymap_inventory");
|
||||||
|
this->add_key(GUI_ID_KEY_CHAT_BUTTON, "Chat", "keymap_chat");
|
||||||
|
this->add_key(GUI_ID_KEY_CMD_BUTTON, "Command", "keymap_cmd");
|
||||||
|
this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, "Console", "keymap_console");
|
||||||
|
this->add_key(GUI_ID_KEY_FLY_BUTTON, "Toggle fly", "keymap_freemove");
|
||||||
|
this->add_key(GUI_ID_KEY_FAST_BUTTON, "Toggle fast", "keymap_fastmove");
|
||||||
|
this->add_key(GUI_ID_KEY_RANGE_BUTTON, "Range select", "keymap_rangeselect");
|
||||||
|
this->add_key(GUI_ID_KEY_DUMP_BUTTON, "Print stacks", "keymap_print_debug_stacks");
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,16 @@
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "keycode.h"
|
#include "keycode.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int id;
|
||||||
|
wchar_t *button_name;
|
||||||
|
KeyPress key;
|
||||||
|
std::string setting_name;
|
||||||
|
gui::IGUIButton *button;
|
||||||
|
} key_setting;
|
||||||
|
|
||||||
|
|
||||||
class GUIKeyChangeMenu: public GUIModalMenu
|
class GUIKeyChangeMenu: public GUIModalMenu
|
||||||
{
|
{
|
||||||
|
@ -54,40 +64,15 @@ private:
|
||||||
|
|
||||||
bool resetMenu();
|
bool resetMenu();
|
||||||
|
|
||||||
gui::IGUIButton *forward;
|
void add_key(int id, std::string setting_name, std::string button_name);
|
||||||
gui::IGUIButton *backward;
|
|
||||||
gui::IGUIButton *left;
|
bool shift_down;
|
||||||
gui::IGUIButton *right;
|
|
||||||
gui::IGUIButton *use;
|
|
||||||
gui::IGUIButton *sneak;
|
|
||||||
gui::IGUIButton *jump;
|
|
||||||
gui::IGUIButton *dropbtn;
|
|
||||||
gui::IGUIButton *inventory;
|
|
||||||
gui::IGUIButton *fly;
|
|
||||||
gui::IGUIButton *fast;
|
|
||||||
gui::IGUIButton *range;
|
|
||||||
gui::IGUIButton *dump;
|
|
||||||
gui::IGUIButton *chat;
|
|
||||||
gui::IGUIButton *cmd;
|
|
||||||
gui::IGUIButton *console;
|
|
||||||
|
|
||||||
s32 activeKey;
|
s32 activeKey;
|
||||||
KeyPress key_forward;
|
|
||||||
KeyPress key_backward;
|
std::vector<KeyPress> key_used;
|
||||||
KeyPress key_left;
|
gui::IGUIStaticText *key_used_text;
|
||||||
KeyPress key_right;
|
std::vector<key_setting *> key_settings;
|
||||||
KeyPress key_use;
|
|
||||||
KeyPress key_sneak;
|
|
||||||
KeyPress key_jump;
|
|
||||||
KeyPress key_drop;
|
|
||||||
KeyPress key_inventory;
|
|
||||||
KeyPress key_fly;
|
|
||||||
KeyPress key_fast;
|
|
||||||
KeyPress key_range;
|
|
||||||
KeyPress key_chat;
|
|
||||||
KeyPress key_cmd;
|
|
||||||
KeyPress key_console;
|
|
||||||
KeyPress key_dump;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "tile.h" // getTexturePath
|
#include "tile.h" // getTexturePath
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
#include "subgame.h"
|
||||||
|
|
||||||
struct CreateWorldDestMainMenu : public CreateWorldDest
|
struct CreateWorldDestMainMenu : public CreateWorldDest
|
||||||
{
|
{
|
||||||
|
@ -47,6 +48,22 @@ struct CreateWorldDestMainMenu : public CreateWorldDest
|
||||||
{}
|
{}
|
||||||
void accepted(std::wstring name, std::string gameid)
|
void accepted(std::wstring name, std::string gameid)
|
||||||
{
|
{
|
||||||
|
std::string name_narrow = wide_to_narrow(name);
|
||||||
|
if(!string_allowed_blacklist(name_narrow, WORLDNAME_BLACKLISTED_CHARS))
|
||||||
|
{
|
||||||
|
m_menu->displayMessageMenu(wgettext("Cannot create world: Name contains invalid characters"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<WorldSpec> worlds = getAvailableWorlds();
|
||||||
|
for(std::vector<WorldSpec>::iterator i = worlds.begin();
|
||||||
|
i != worlds.end(); i++)
|
||||||
|
{
|
||||||
|
if((*i).name == name_narrow)
|
||||||
|
{
|
||||||
|
m_menu->displayMessageMenu(wgettext("Cannot create world: A world by this name already exists"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
m_menu->createNewWorld(name, gameid);
|
m_menu->createNewWorld(name, gameid);
|
||||||
}
|
}
|
||||||
GUIMainMenu *m_menu;
|
GUIMainMenu *m_menu;
|
||||||
|
@ -934,3 +951,7 @@ int GUIMainMenu::getTab()
|
||||||
return TAB_SINGLEPLAYER; // Default
|
return TAB_SINGLEPLAYER; // Default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUIMainMenu::displayMessageMenu(std::wstring msg)
|
||||||
|
{
|
||||||
|
(new GUIMessageMenu(env, parent, -1, menumgr, msg))->drop();
|
||||||
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ public:
|
||||||
void createNewWorld(std::wstring name, std::string gameid);
|
void createNewWorld(std::wstring name, std::string gameid);
|
||||||
void deleteWorld(const std::vector<std::string> &paths);
|
void deleteWorld(const std::vector<std::string> &paths);
|
||||||
int getTab();
|
int getTab();
|
||||||
|
void displayMessageMenu(std::wstring msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MainMenuData *m_data;
|
MainMenuData *m_data;
|
||||||
|
|
|
@ -431,6 +431,7 @@ InventoryList::InventoryList(std::string name, u32 size, IItemDefManager *itemde
|
||||||
{
|
{
|
||||||
m_name = name;
|
m_name = name;
|
||||||
m_size = size;
|
m_size = size;
|
||||||
|
m_width = 0;
|
||||||
m_itemdef = itemdef;
|
m_itemdef = itemdef;
|
||||||
clearItems();
|
clearItems();
|
||||||
//m_dirty = false;
|
//m_dirty = false;
|
||||||
|
@ -459,6 +460,11 @@ void InventoryList::setSize(u32 newsize)
|
||||||
m_size = newsize;
|
m_size = newsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InventoryList::setWidth(u32 newwidth)
|
||||||
|
{
|
||||||
|
m_width = newwidth;
|
||||||
|
}
|
||||||
|
|
||||||
void InventoryList::setName(const std::string &name)
|
void InventoryList::setName(const std::string &name)
|
||||||
{
|
{
|
||||||
m_name = name;
|
m_name = name;
|
||||||
|
@ -468,6 +474,8 @@ void InventoryList::serialize(std::ostream &os) const
|
||||||
{
|
{
|
||||||
//os.imbue(std::locale("C"));
|
//os.imbue(std::locale("C"));
|
||||||
|
|
||||||
|
os<<"Width "<<m_width<<"\n";
|
||||||
|
|
||||||
for(u32 i=0; i<m_items.size(); i++)
|
for(u32 i=0; i<m_items.size(); i++)
|
||||||
{
|
{
|
||||||
const ItemStack &item = m_items[i];
|
const ItemStack &item = m_items[i];
|
||||||
|
@ -492,6 +500,7 @@ void InventoryList::deSerialize(std::istream &is)
|
||||||
|
|
||||||
clearItems();
|
clearItems();
|
||||||
u32 item_i = 0;
|
u32 item_i = 0;
|
||||||
|
m_width = 0;
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
|
@ -513,6 +522,12 @@ void InventoryList::deSerialize(std::istream &is)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if(name == "Width")
|
||||||
|
{
|
||||||
|
iss >> m_width;
|
||||||
|
if (iss.fail())
|
||||||
|
throw SerializationError("incorrect width property");
|
||||||
|
}
|
||||||
else if(name == "Item")
|
else if(name == "Item")
|
||||||
{
|
{
|
||||||
if(item_i > getSize() - 1)
|
if(item_i > getSize() - 1)
|
||||||
|
@ -527,10 +542,6 @@ void InventoryList::deSerialize(std::istream &is)
|
||||||
throw SerializationError("too many items");
|
throw SerializationError("too many items");
|
||||||
m_items[item_i++].clear();
|
m_items[item_i++].clear();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
throw SerializationError("Unknown inventory identifier");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,6 +554,7 @@ InventoryList & InventoryList::operator = (const InventoryList &other)
|
||||||
{
|
{
|
||||||
m_items = other.m_items;
|
m_items = other.m_items;
|
||||||
m_size = other.m_size;
|
m_size = other.m_size;
|
||||||
|
m_width = other.m_width;
|
||||||
m_name = other.m_name;
|
m_name = other.m_name;
|
||||||
m_itemdef = other.m_itemdef;
|
m_itemdef = other.m_itemdef;
|
||||||
//setDirty(true);
|
//setDirty(true);
|
||||||
|
@ -560,6 +572,11 @@ u32 InventoryList::getSize() const
|
||||||
return m_items.size();
|
return m_items.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 InventoryList::getWidth() const
|
||||||
|
{
|
||||||
|
return m_width;
|
||||||
|
}
|
||||||
|
|
||||||
u32 InventoryList::getUsedSlots() const
|
u32 InventoryList::getUsedSlots() const
|
||||||
{
|
{
|
||||||
u32 num = 0;
|
u32 num = 0;
|
||||||
|
@ -886,10 +903,6 @@ void Inventory::deSerialize(std::istream &is)
|
||||||
|
|
||||||
m_lists.push_back(list);
|
m_lists.push_back(list);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
throw SerializationError("Unknown inventory identifier");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,7 @@ public:
|
||||||
~InventoryList();
|
~InventoryList();
|
||||||
void clearItems();
|
void clearItems();
|
||||||
void setSize(u32 newsize);
|
void setSize(u32 newsize);
|
||||||
|
void setWidth(u32 newWidth);
|
||||||
void setName(const std::string &name);
|
void setName(const std::string &name);
|
||||||
void serialize(std::ostream &os) const;
|
void serialize(std::ostream &os) const;
|
||||||
void deSerialize(std::istream &is);
|
void deSerialize(std::istream &is);
|
||||||
|
@ -185,6 +186,7 @@ public:
|
||||||
|
|
||||||
const std::string &getName() const;
|
const std::string &getName() const;
|
||||||
u32 getSize() const;
|
u32 getSize() const;
|
||||||
|
u32 getWidth() const;
|
||||||
// Count used slots
|
// Count used slots
|
||||||
u32 getUsedSlots() const;
|
u32 getUsedSlots() const;
|
||||||
u32 getFreeSlots() const;
|
u32 getFreeSlots() const;
|
||||||
|
@ -240,7 +242,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<ItemStack> m_items;
|
std::vector<ItemStack> m_items;
|
||||||
u32 m_size;
|
u32 m_size, m_width;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
IItemDefManager *m_itemdef;
|
IItemDefManager *m_itemdef;
|
||||||
};
|
};
|
||||||
|
|
|
@ -332,6 +332,18 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||||
|
|
||||||
// If source is infinite, reset it's stack
|
// If source is infinite, reset it's stack
|
||||||
if(src_can_take_count == -1){
|
if(src_can_take_count == -1){
|
||||||
|
// If destination stack is of different type and there are leftover
|
||||||
|
// items, attempt to put the leftover items to a different place in the
|
||||||
|
// destination inventory.
|
||||||
|
// The client-side GUI will try to guess if this happens.
|
||||||
|
if(from_stack_was.name != to_stack_was.name){
|
||||||
|
for(u32 i=0; i<list_to->getSize(); i++){
|
||||||
|
if(list_to->getItem(i).empty()){
|
||||||
|
list_to->changeItem(i, to_stack_was);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
list_from->deleteItem(from_i);
|
list_from->deleteItem(from_i);
|
||||||
list_from->addItem(from_i, from_stack_was);
|
list_from->addItem(from_i, from_stack_was);
|
||||||
}
|
}
|
||||||
|
@ -339,6 +351,8 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||||
if(dst_can_put_count == -1){
|
if(dst_can_put_count == -1){
|
||||||
list_to->deleteItem(to_i);
|
list_to->deleteItem(to_i);
|
||||||
list_to->addItem(to_i, to_stack_was);
|
list_to->addItem(to_i, to_stack_was);
|
||||||
|
list_from->deleteItem(from_i);
|
||||||
|
list_from->addItem(from_i, from_stack_was);
|
||||||
list_from->takeItem(from_i, count);
|
list_from->takeItem(from_i, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,18 +783,16 @@ bool getCraftingResult(Inventory *inv, ItemStack& result,
|
||||||
|
|
||||||
result.clear();
|
result.clear();
|
||||||
|
|
||||||
// TODO: Allow different sizes of crafting grids
|
|
||||||
|
|
||||||
// Get the InventoryList in which we will operate
|
// Get the InventoryList in which we will operate
|
||||||
InventoryList *clist = inv->getList("craft");
|
InventoryList *clist = inv->getList("craft");
|
||||||
if(!clist || clist->getSize() != 9)
|
if(!clist)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Mangle crafting grid to an another format
|
// Mangle crafting grid to an another format
|
||||||
CraftInput ci;
|
CraftInput ci;
|
||||||
ci.method = CRAFT_METHOD_NORMAL;
|
ci.method = CRAFT_METHOD_NORMAL;
|
||||||
ci.width = 3;
|
ci.width = clist->getWidth() ? clist->getWidth() : 3;
|
||||||
for(u16 i=0; i<9; i++)
|
for(u16 i=0; i<clist->getSize(); i++)
|
||||||
ci.items.push_back(clist->getItem(i));
|
ci.items.push_back(clist->getItem(i));
|
||||||
|
|
||||||
// Find out what is crafted and add it to result item slot
|
// Find out what is crafted and add it to result item slot
|
||||||
|
@ -793,7 +805,7 @@ bool getCraftingResult(Inventory *inv, ItemStack& result,
|
||||||
if(found && decrementInput)
|
if(found && decrementInput)
|
||||||
{
|
{
|
||||||
// CraftInput has been changed, apply changes in clist
|
// CraftInput has been changed, apply changes in clist
|
||||||
for(u16 i=0; i<9; i++)
|
for(u16 i=0; i<clist->getSize(); i++)
|
||||||
{
|
{
|
||||||
clist->changeItem(i, ci.items[i]);
|
clist->changeItem(i, ci.items[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,29 @@ struct InventoryLocation
|
||||||
name = name_;
|
name = name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const InventoryLocation &other) const
|
||||||
|
{
|
||||||
|
if(type != other.type)
|
||||||
|
return false;
|
||||||
|
switch(type){
|
||||||
|
case UNDEFINED:
|
||||||
|
return false;
|
||||||
|
case CURRENT_PLAYER:
|
||||||
|
return true;
|
||||||
|
case PLAYER:
|
||||||
|
return (name == other.name);
|
||||||
|
case NODEMETA:
|
||||||
|
return (p == other.p);
|
||||||
|
case DETACHED:
|
||||||
|
return (name == other.name);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool operator!=(const InventoryLocation &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
void applyCurrentPlayer(const std::string &name_)
|
void applyCurrentPlayer(const std::string &name_)
|
||||||
{
|
{
|
||||||
if(type == CURRENT_PLAYER)
|
if(type == CURRENT_PLAYER)
|
||||||
|
|
|
@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "main.h" // For g_settings
|
#include "main.h" // For g_settings
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "hex.h"
|
||||||
|
|
||||||
class UnknownKeycode : public BaseException
|
class UnknownKeycode : public BaseException
|
||||||
{
|
{
|
||||||
|
@ -286,16 +288,30 @@ KeyPress::KeyPress(const char *name)
|
||||||
m_name = name[0];
|
m_name = name[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyPress::KeyPress(const irr::SEvent::SKeyInput &in)
|
KeyPress::KeyPress(const irr::SEvent::SKeyInput &in, bool prefer_character)
|
||||||
{
|
{
|
||||||
Key = in.Key;
|
Key = in.Key;
|
||||||
Char = in.Char;
|
Char = in.Char;
|
||||||
|
|
||||||
|
if(prefer_character){
|
||||||
|
m_name.resize(MB_CUR_MAX+1, '\0');
|
||||||
|
int written = wctomb(&m_name[0], Char);
|
||||||
|
if(written > 0){
|
||||||
|
infostream<<"KeyPress: Preferring character for "<<m_name<<std::endl;
|
||||||
|
Key = irr::KEY_KEY_CODES_COUNT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (valid_kcode(Key)) {
|
if (valid_kcode(Key)) {
|
||||||
m_name = KeyNames[Key];
|
m_name = KeyNames[Key];
|
||||||
} else {
|
} else {
|
||||||
m_name.resize(MB_CUR_MAX+1, '\0');
|
m_name.resize(MB_CUR_MAX+1, '\0');
|
||||||
int written = wctomb(&m_name[0], Char);
|
int written = wctomb(&m_name[0], Char);
|
||||||
assert (written >= 0 && "unexpected multibyte character");
|
if(written < 0){
|
||||||
|
std::string hexstr = hex_encode((const char*)&Char, sizeof(Char));
|
||||||
|
errorstream<<"KeyPress: Unexpected multibyte character "<<hexstr<<std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
KeyPress();
|
KeyPress();
|
||||||
KeyPress(const char *name);
|
KeyPress(const char *name);
|
||||||
|
|
||||||
KeyPress(const irr::SEvent::SKeyInput &in);
|
KeyPress(const irr::SEvent::SKeyInput &in, bool prefer_character=false);
|
||||||
|
|
||||||
bool operator==(const KeyPress &o) const
|
bool operator==(const KeyPress &o) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,7 +38,8 @@ LocalPlayer::LocalPlayer(IGameDef *gamedef):
|
||||||
m_sneak_node_exists(false),
|
m_sneak_node_exists(false),
|
||||||
m_old_node_below(32767,32767,32767),
|
m_old_node_below(32767,32767,32767),
|
||||||
m_old_node_below_type("air"),
|
m_old_node_below_type("air"),
|
||||||
m_need_to_get_new_sneak_node(true)
|
m_need_to_get_new_sneak_node(true),
|
||||||
|
m_can_jump(false)
|
||||||
{
|
{
|
||||||
// Initialize hp to 0, so that no hearts will be shown if server
|
// Initialize hp to 0, so that no hearts will be shown if server
|
||||||
// doesn't support health points
|
// doesn't support health points
|
||||||
|
@ -149,13 +150,16 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
|
||||||
position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
|
position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
|
||||||
position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
|
position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
|
||||||
|
|
||||||
f32 min_y = lwn_f.Y + 0.5*BS;
|
if(!is_climbing)
|
||||||
if(position.Y < min_y)
|
|
||||||
{
|
{
|
||||||
position.Y = min_y;
|
f32 min_y = lwn_f.Y + 0.5*BS;
|
||||||
|
if(position.Y < min_y)
|
||||||
|
{
|
||||||
|
position.Y = min_y;
|
||||||
|
|
||||||
if(m_speed.Y < 0)
|
if(m_speed.Y < 0)
|
||||||
m_speed.Y = 0;
|
m_speed.Y = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +192,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
|
||||||
bool touching_ground_was = touching_ground;
|
bool touching_ground_was = touching_ground;
|
||||||
touching_ground = result.touching_ground;
|
touching_ground = result.touching_ground;
|
||||||
|
|
||||||
bool standing_on_unloaded = result.standing_on_unloaded;
|
//bool standing_on_unloaded = result.standing_on_unloaded;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check the nodes under the player to see from which node the
|
Check the nodes under the player to see from which node the
|
||||||
|
@ -281,18 +285,25 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
|
||||||
/*
|
/*
|
||||||
Report collisions
|
Report collisions
|
||||||
*/
|
*/
|
||||||
|
bool bouncy_jump = false;
|
||||||
if(collision_info)
|
if(collision_info)
|
||||||
{
|
{
|
||||||
// Report fall collision
|
for(size_t i=0; i<result.collisions.size(); i++){
|
||||||
if(old_speed.Y < m_speed.Y - 0.1 && !standing_on_unloaded)
|
const CollisionInfo &info = result.collisions[i];
|
||||||
{
|
|
||||||
CollisionInfo info;
|
|
||||||
info.t = COLLISION_FALL;
|
|
||||||
info.speed = m_speed.Y - old_speed.Y;
|
|
||||||
collision_info->push_back(info);
|
collision_info->push_back(info);
|
||||||
|
if(info.new_speed.Y - info.old_speed.Y > 0.1*BS &&
|
||||||
|
info.bouncy)
|
||||||
|
bouncy_jump = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(bouncy_jump && control.jump){
|
||||||
|
m_speed.Y += 6.5*BS;
|
||||||
|
touching_ground = false;
|
||||||
|
MtEvent *e = new SimpleTriggerEvent("PlayerJump");
|
||||||
|
m_gamedef->event()->put(e);
|
||||||
|
}
|
||||||
|
|
||||||
if(!touching_ground_was && touching_ground){
|
if(!touching_ground_was && touching_ground){
|
||||||
MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
|
MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
|
||||||
m_gamedef->event()->put(e);
|
m_gamedef->event()->put(e);
|
||||||
|
@ -314,6 +325,15 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
|
||||||
*/
|
*/
|
||||||
m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
|
m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
|
||||||
m_old_node_below_type = nodemgr->get(map.getNodeNoEx(m_old_node_below)).name;
|
m_old_node_below_type = nodemgr->get(map.getNodeNoEx(m_old_node_below)).name;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check properties of the node on which the player is standing
|
||||||
|
*/
|
||||||
|
const ContentFeatures &f = nodemgr->get(map.getNodeNoEx(getStandingNodePos()));
|
||||||
|
// Determine if jumping is possible
|
||||||
|
m_can_jump = touching_ground;
|
||||||
|
if(itemgroup_get(f.groups, "disable_jump"))
|
||||||
|
m_can_jump = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
|
||||||
|
@ -359,31 +379,70 @@ void LocalPlayer::applyControl(float dtime)
|
||||||
if(free_move && fast_move)
|
if(free_move && fast_move)
|
||||||
superspeed = true;
|
superspeed = true;
|
||||||
|
|
||||||
// Auxiliary button 1 (E)
|
// Old descend control
|
||||||
if(control.aux1)
|
if(g_settings->getBool("aux1_descends"))
|
||||||
{
|
{
|
||||||
if(free_move)
|
// Auxiliary button 1 (E)
|
||||||
|
if(control.aux1)
|
||||||
{
|
{
|
||||||
// In free movement mode, aux1 descends
|
if(free_move)
|
||||||
v3f speed = getSpeed();
|
{
|
||||||
if(fast_move)
|
// In free movement mode, aux1 descends
|
||||||
speed.Y = -20*BS;
|
v3f speed = getSpeed();
|
||||||
|
if(fast_move)
|
||||||
|
speed.Y = -20*BS;
|
||||||
|
else
|
||||||
|
speed.Y = -walkspeed_max;
|
||||||
|
setSpeed(speed);
|
||||||
|
}
|
||||||
|
else if(is_climbing)
|
||||||
|
{
|
||||||
|
v3f speed = getSpeed();
|
||||||
|
speed.Y = -3*BS;
|
||||||
|
setSpeed(speed);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
speed.Y = -walkspeed_max;
|
{
|
||||||
setSpeed(speed);
|
// If not free movement but fast is allowed, aux1 is
|
||||||
|
// "Turbo button"
|
||||||
|
if(fast_move)
|
||||||
|
superspeed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(is_climbing)
|
}
|
||||||
|
// New minecraft-like descend control
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Auxiliary button 1 (E)
|
||||||
|
if(control.aux1)
|
||||||
{
|
{
|
||||||
v3f speed = getSpeed();
|
if(!free_move && !is_climbing)
|
||||||
speed.Y = -3*BS;
|
{
|
||||||
setSpeed(speed);
|
// If not free movement but fast is allowed, aux1 is
|
||||||
|
// "Turbo button"
|
||||||
|
if(fast_move)
|
||||||
|
superspeed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if(control.sneak)
|
||||||
{
|
{
|
||||||
// If not free movement but fast is allowed, aux1 is
|
if(free_move)
|
||||||
// "Turbo button"
|
{
|
||||||
if(fast_move)
|
// In free movement mode, sneak descends
|
||||||
superspeed = true;
|
v3f speed = getSpeed();
|
||||||
|
if(fast_move)
|
||||||
|
speed.Y = -20*BS;
|
||||||
|
else
|
||||||
|
speed.Y = -walkspeed_max;
|
||||||
|
setSpeed(speed);
|
||||||
|
}
|
||||||
|
else if(is_climbing)
|
||||||
|
{
|
||||||
|
v3f speed = getSpeed();
|
||||||
|
speed.Y = -3*BS;
|
||||||
|
setSpeed(speed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +479,7 @@ void LocalPlayer::applyControl(float dtime)
|
||||||
speed.Y = walkspeed_max;
|
speed.Y = walkspeed_max;
|
||||||
setSpeed(speed);
|
setSpeed(speed);
|
||||||
}
|
}
|
||||||
else if(touching_ground)
|
else if(m_can_jump)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
NOTE: The d value in move() affects jump height by
|
NOTE: The d value in move() affects jump height by
|
||||||
|
|
|
@ -101,6 +101,7 @@ private:
|
||||||
std::string m_old_node_below_type;
|
std::string m_old_node_below_type;
|
||||||
// Whether recalculation of the sneak node is needed
|
// Whether recalculation of the sneak node is needed
|
||||||
bool m_need_to_get_new_sneak_node;
|
bool m_need_to_get_new_sneak_node;
|
||||||
|
bool m_can_jump;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1469,7 +1469,7 @@ void Map::timerUpdate(float dtime, float unload_timeout,
|
||||||
|
|
||||||
block->incrementUsageTimer(dtime);
|
block->incrementUsageTimer(dtime);
|
||||||
|
|
||||||
if(block->getUsageTimer() > unload_timeout)
|
if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout)
|
||||||
{
|
{
|
||||||
v3s16 p = block->getPos();
|
v3s16 p = block->getPos();
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,8 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy):
|
||||||
m_generated(false),
|
m_generated(false),
|
||||||
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
|
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
|
||||||
m_disk_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
|
m_disk_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
|
||||||
m_usage_timer(0)
|
m_usage_timer(0),
|
||||||
|
m_refcount(0)
|
||||||
{
|
{
|
||||||
data = NULL;
|
data = NULL;
|
||||||
if(dummy == false)
|
if(dummy == false)
|
||||||
|
|
|
@ -431,6 +431,22 @@ public:
|
||||||
return m_usage_timer;
|
return m_usage_timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
See m_refcount
|
||||||
|
*/
|
||||||
|
void refGrab()
|
||||||
|
{
|
||||||
|
m_refcount++;
|
||||||
|
}
|
||||||
|
void refDrop()
|
||||||
|
{
|
||||||
|
m_refcount--;
|
||||||
|
}
|
||||||
|
int refGet()
|
||||||
|
{
|
||||||
|
return m_refcount;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Node Timers
|
Node Timers
|
||||||
*/
|
*/
|
||||||
|
@ -566,6 +582,12 @@ private:
|
||||||
Map will unload the block when this reaches a timeout.
|
Map will unload the block when this reaches a timeout.
|
||||||
*/
|
*/
|
||||||
float m_usage_timer;
|
float m_usage_timer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reference count; currently used for determining if this block is in
|
||||||
|
the list of blocks to be drawn.
|
||||||
|
*/
|
||||||
|
int m_refcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool blockpos_over_limit(v3s16 p)
|
inline bool blockpos_over_limit(v3s16 p)
|
||||||
|
|
|
@ -1297,7 +1297,9 @@ BiomeType get_biome(u64 seed, v2s16 p2d)
|
||||||
double d = noise2d_perlin(
|
double d = noise2d_perlin(
|
||||||
0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
|
0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
|
||||||
seed+9130, 3, 0.50);
|
seed+9130, 3, 0.50);
|
||||||
if(d > 0.35)
|
if(d > 0.45)
|
||||||
|
return BT_DESERT;
|
||||||
|
if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
|
||||||
return BT_DESERT;
|
return BT_DESERT;
|
||||||
return BT_NORMAL;
|
return BT_NORMAL;
|
||||||
};
|
};
|
||||||
|
@ -1759,8 +1761,9 @@ void make_block(BlockMakeData *data)
|
||||||
vmanip.m_data[i] = airnode;
|
vmanip.m_data[i] = airnode;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Don't replace air or water or lava
|
// Don't replace air or water or lava or ignore
|
||||||
if(vmanip.m_data[i].getContent() == CONTENT_AIR ||
|
if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
|
||||||
|
vmanip.m_data[i].getContent() == CONTENT_AIR ||
|
||||||
vmanip.m_data[i].getContent() == c_water_source ||
|
vmanip.m_data[i].getContent() == c_water_source ||
|
||||||
vmanip.m_data[i].getContent() == c_lava_source)
|
vmanip.m_data[i].getContent() == c_lava_source)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -556,8 +556,6 @@ public:
|
||||||
f->solidness = 0;
|
f->solidness = 0;
|
||||||
} else {
|
} else {
|
||||||
f->solidness = 1;
|
f->solidness = 1;
|
||||||
if(f->alpha == 255)
|
|
||||||
f->solidness = 2;
|
|
||||||
f->backface_culling = false;
|
f->backface_culling = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -45,7 +45,8 @@ Player::Player(IGameDef *gamedef):
|
||||||
updateName("<not set>");
|
updateName("<not set>");
|
||||||
inventory.clear();
|
inventory.clear();
|
||||||
inventory.addList("main", PLAYER_INVENTORY_SIZE);
|
inventory.addList("main", PLAYER_INVENTORY_SIZE);
|
||||||
inventory.addList("craft", 9);
|
InventoryList *craft = inventory.addList("craft", 9);
|
||||||
|
craft->setWidth(3);
|
||||||
inventory.addList("craftpreview", 1);
|
inventory.addList("craftpreview", 1);
|
||||||
inventory.addList("craftresult", 1);
|
inventory.addList("craftresult", 1);
|
||||||
|
|
||||||
|
|
|
@ -1847,6 +1847,20 @@ private:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_width(self, listname)
|
||||||
|
static int l_get_width(lua_State *L)
|
||||||
|
{
|
||||||
|
InvRef *ref = checkobject(L, 1);
|
||||||
|
const char *listname = luaL_checkstring(L, 2);
|
||||||
|
InventoryList *list = getlist(L, ref, listname);
|
||||||
|
if(list){
|
||||||
|
lua_pushinteger(L, list->getWidth());
|
||||||
|
} else {
|
||||||
|
lua_pushinteger(L, 0);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// set_size(self, listname, size)
|
// set_size(self, listname, size)
|
||||||
static int l_set_size(lua_State *L)
|
static int l_set_size(lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -1869,6 +1883,23 @@ private:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set_width(self, listname, size)
|
||||||
|
static int l_set_width(lua_State *L)
|
||||||
|
{
|
||||||
|
InvRef *ref = checkobject(L, 1);
|
||||||
|
const char *listname = luaL_checkstring(L, 2);
|
||||||
|
int newwidth = luaL_checknumber(L, 3);
|
||||||
|
Inventory *inv = getinv(L, ref);
|
||||||
|
InventoryList *list = inv->getList(listname);
|
||||||
|
if(list){
|
||||||
|
list->setWidth(newwidth);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
reportInventoryChange(L, ref);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// get_stack(self, listname, i) -> itemstack
|
// get_stack(self, listname, i) -> itemstack
|
||||||
static int l_get_stack(lua_State *L)
|
static int l_get_stack(lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -2062,6 +2093,8 @@ const luaL_reg InvRef::methods[] = {
|
||||||
method(InvRef, is_empty),
|
method(InvRef, is_empty),
|
||||||
method(InvRef, get_size),
|
method(InvRef, get_size),
|
||||||
method(InvRef, set_size),
|
method(InvRef, set_size),
|
||||||
|
method(InvRef, get_width),
|
||||||
|
method(InvRef, set_width),
|
||||||
method(InvRef, get_stack),
|
method(InvRef, get_stack),
|
||||||
method(InvRef, set_stack),
|
method(InvRef, set_stack),
|
||||||
method(InvRef, get_list),
|
method(InvRef, get_list),
|
||||||
|
|
|
@ -442,9 +442,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||||
m_nearest_unsent_reset_timer += dtime;
|
m_nearest_unsent_reset_timer += dtime;
|
||||||
|
|
||||||
if(m_nothing_to_send_pause_timer >= 0)
|
if(m_nothing_to_send_pause_timer >= 0)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
Player *player = server->m_env->getPlayer(peer_id);
|
||||||
|
// This can happen sometimes; clients and players are not in perfect sync.
|
||||||
|
if(player == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
// Won't send anything if already sending
|
// Won't send anything if already sending
|
||||||
if(m_blocks_sending.size() >= g_settings->getU16
|
if(m_blocks_sending.size() >= g_settings->getU16
|
||||||
|
@ -456,10 +459,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||||
|
|
||||||
//TimeTaker timer("RemoteClient::GetNextBlocks");
|
//TimeTaker timer("RemoteClient::GetNextBlocks");
|
||||||
|
|
||||||
Player *player = server->m_env->getPlayer(peer_id);
|
|
||||||
|
|
||||||
assert(player != NULL);
|
|
||||||
|
|
||||||
v3f playerpos = player->getPosition();
|
v3f playerpos = player->getPosition();
|
||||||
v3f playerspeed = player->getSpeed();
|
v3f playerspeed = player->getSpeed();
|
||||||
v3f playerspeeddir(0,0,0);
|
v3f playerspeeddir(0,0,0);
|
||||||
|
|
|
@ -30,7 +30,7 @@ with this program; ifnot, write to the Free Software Foundation, Inc.,
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#include <OpenAL/al.h>
|
#include <OpenAL/al.h>
|
||||||
#include <OpenAL/alc.h>
|
#include <OpenAL/alc.h>
|
||||||
#include <OpenAL/alext.h>
|
//#include <OpenAL/alext.h>
|
||||||
#else
|
#else
|
||||||
#include <AL/al.h>
|
#include <AL/al.h>
|
||||||
#include <AL/alc.h>
|
#include <AL/alc.h>
|
||||||
|
|
|
@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#define WORLDNAME_BLACKLISTED_CHARS "/\\"
|
||||||
|
|
||||||
struct SubgameSpec
|
struct SubgameSpec
|
||||||
{
|
{
|
||||||
std::string id; // "" = game does not exist
|
std::string id; // "" = game does not exist
|
||||||
|
|
|
@ -698,6 +698,7 @@ struct TestInventory: public TestBase
|
||||||
{
|
{
|
||||||
std::string serialized_inventory =
|
std::string serialized_inventory =
|
||||||
"List 0 32\n"
|
"List 0 32\n"
|
||||||
|
"Width 3\n"
|
||||||
"Empty\n"
|
"Empty\n"
|
||||||
"Empty\n"
|
"Empty\n"
|
||||||
"Empty\n"
|
"Empty\n"
|
||||||
|
@ -735,6 +736,7 @@ struct TestInventory: public TestBase
|
||||||
|
|
||||||
std::string serialized_inventory_2 =
|
std::string serialized_inventory_2 =
|
||||||
"List main 32\n"
|
"List main 32\n"
|
||||||
|
"Width 5\n"
|
||||||
"Empty\n"
|
"Empty\n"
|
||||||
"Empty\n"
|
"Empty\n"
|
||||||
"Empty\n"
|
"Empty\n"
|
||||||
|
@ -778,6 +780,8 @@ struct TestInventory: public TestBase
|
||||||
inv.getList("0")->setName("main");
|
inv.getList("0")->setName("main");
|
||||||
UASSERT(!inv.getList("0"));
|
UASSERT(!inv.getList("0"));
|
||||||
UASSERT(inv.getList("main"));
|
UASSERT(inv.getList("main"));
|
||||||
|
UASSERT(inv.getList("main")->getWidth() == 3);
|
||||||
|
inv.getList("main")->setWidth(5);
|
||||||
std::ostringstream inv_os(std::ios::binary);
|
std::ostringstream inv_os(std::ios::binary);
|
||||||
inv.serialize(inv_os);
|
inv.serialize(inv_os);
|
||||||
UASSERT(inv_os.str() == serialized_inventory_2);
|
UASSERT(inv_os.str() == serialized_inventory_2);
|
||||||
|
|
16
src/tile.cpp
16
src/tile.cpp
|
@ -1216,10 +1216,11 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||||
// Position to copy the blitted from in the blitted image
|
// Position to copy the blitted from in the blitted image
|
||||||
core::position2d<s32> pos_from(0,0);
|
core::position2d<s32> pos_from(0,0);
|
||||||
// Blit
|
// Blit
|
||||||
image->copyToWithAlpha(baseimg, pos_to,
|
/*image->copyToWithAlpha(baseimg, pos_to,
|
||||||
core::rect<s32>(pos_from, dim),
|
core::rect<s32>(pos_from, dim),
|
||||||
video::SColor(255,255,255,255),
|
video::SColor(255,255,255,255),
|
||||||
NULL);
|
NULL);*/
|
||||||
|
blit_with_alpha(image, baseimg, pos_from, pos_to, dim);
|
||||||
// Drop image
|
// Drop image
|
||||||
image->drop();
|
image->drop();
|
||||||
}
|
}
|
||||||
|
@ -1360,7 +1361,11 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||||
u32 h0 = stoi(sf.next(":"));
|
u32 h0 = stoi(sf.next(":"));
|
||||||
infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
|
infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
|
||||||
core::dimension2d<u32> dim(w0,h0);
|
core::dimension2d<u32> dim(w0,h0);
|
||||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
if(baseimg == NULL)
|
||||||
|
{
|
||||||
|
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||||
|
baseimg->fill(video::SColor(0,0,0,0));
|
||||||
|
}
|
||||||
while(sf.atend() == false)
|
while(sf.atend() == false)
|
||||||
{
|
{
|
||||||
u32 x = stoi(sf.next(","));
|
u32 x = stoi(sf.next(","));
|
||||||
|
@ -1380,10 +1385,11 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||||
driver->createImage(video::ECF_A8R8G8B8, dim);
|
driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||||
img->copyTo(img2);
|
img->copyTo(img2);
|
||||||
img->drop();
|
img->drop();
|
||||||
img2->copyToWithAlpha(baseimg, pos_base,
|
/*img2->copyToWithAlpha(baseimg, pos_base,
|
||||||
core::rect<s32>(v2s32(0,0), dim),
|
core::rect<s32>(v2s32(0,0), dim),
|
||||||
video::SColor(255,255,255,255),
|
video::SColor(255,255,255,255),
|
||||||
NULL);
|
NULL);*/
|
||||||
|
blit_with_alpha(img2, baseimg, v2s32(0,0), pos_base, dim);
|
||||||
img2->drop();
|
img2->drop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -242,6 +242,29 @@ inline bool string_allowed(const std::string &s, const std::string &allowed_char
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Checks if a string contains no blacklisted characters (opposite
|
||||||
|
function of string_allowed())
|
||||||
|
*/
|
||||||
|
inline bool string_allowed_blacklist(const std::string & s, const std::string & blacklisted_chars)
|
||||||
|
{
|
||||||
|
for(unsigned int i = 0; i < s.length(); i++)
|
||||||
|
{
|
||||||
|
bool invalid = false;
|
||||||
|
for(unsigned int j = 0; j < blacklisted_chars.length(); j++)
|
||||||
|
{
|
||||||
|
if(s[i] == blacklisted_chars[j])
|
||||||
|
{
|
||||||
|
invalid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(invalid)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Forcefully wraps string into rows using \n
|
Forcefully wraps string into rows using \n
|
||||||
(no word wrap, used for showing paths in gui)
|
(no word wrap, used for showing paths in gui)
|
||||||
|
|
Loading…
Reference in New Issue