Merge
This commit is contained in:
commit
3505f8982f
|
@ -2337,7 +2337,7 @@ These functions return the leftover itemstack.
|
||||||
otherwise returns `nil`.
|
otherwise returns `nil`.
|
||||||
* The returned table contains the functions `fetch`, `fetch_async` and `fetch_async_get`
|
* The returned table contains the functions `fetch`, `fetch_async` and `fetch_async_get`
|
||||||
described below.
|
described below.
|
||||||
* Only works at init time.
|
* Only works at init time and must be called from the mod's main scope (not from a function).
|
||||||
* Function only exists if minetest server was built with cURL support.
|
* Function only exists if minetest server was built with cURL support.
|
||||||
* **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN
|
* **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN
|
||||||
A LOCAL VARIABLE!**
|
A LOCAL VARIABLE!**
|
||||||
|
@ -3698,11 +3698,12 @@ Definition tables
|
||||||
-- ^ Minimum and maximum `y` positions these decorations can be generated at.
|
-- ^ Minimum and maximum `y` positions these decorations can be generated at.
|
||||||
-- ^ This parameter refers to the `y` position of the decoration base, so
|
-- ^ This parameter refers to the `y` position of the decoration base, so
|
||||||
-- the actual maximum height would be `height_max + size.Y`.
|
-- the actual maximum height would be `height_max + size.Y`.
|
||||||
flags = "liquid_surface",
|
flags = "liquid_surface, force_placement",
|
||||||
-- ^ Flags for all decoration types.
|
-- ^ Flags for all decoration types.
|
||||||
-- ^ "liquid_surface": Instead of placement on the highest solid surface
|
-- ^ "liquid_surface": Instead of placement on the highest solid surface
|
||||||
-- ^ in a mapchunk column, placement is on the highest liquid surface.
|
-- ^ in a mapchunk column, placement is on the highest liquid surface.
|
||||||
-- ^ Placement is disabled if solid nodes are found above the liquid surface.
|
-- ^ Placement is disabled if solid nodes are found above the liquid surface.
|
||||||
|
-- ^ "force_placement": Nodes other than "air" and "ignore" are replaced by the decoration.
|
||||||
|
|
||||||
----- Simple-type parameters
|
----- Simple-type parameters
|
||||||
decoration = "default:grass",
|
decoration = "default:grass",
|
||||||
|
@ -3746,7 +3747,7 @@ Definition tables
|
||||||
},
|
},
|
||||||
-- ^ See 'Schematic specifier' for details.
|
-- ^ See 'Schematic specifier' for details.
|
||||||
replacements = {["oldname"] = "convert_to", ...},
|
replacements = {["oldname"] = "convert_to", ...},
|
||||||
flags = "place_center_x, place_center_y, place_center_z, force_placement",
|
flags = "place_center_x, place_center_y, place_center_z",
|
||||||
-- ^ Flags for schematic decorations. See 'Schematic attributes'.
|
-- ^ Flags for schematic decorations. See 'Schematic attributes'.
|
||||||
rotation = "90" -- rotate schematic 90 degrees on placement
|
rotation = "90" -- rotate schematic 90 degrees on placement
|
||||||
-- ^ Rotation can be "0", "90", "180", "270", or "random".
|
-- ^ Rotation can be "0", "90", "180", "270", or "random".
|
||||||
|
|
|
@ -316,7 +316,7 @@ if map format version >= 23:
|
||||||
u8[key_len] key
|
u8[key_len] key
|
||||||
u32 val_len
|
u32 val_len
|
||||||
u8[val_len] value
|
u8[val_len] value
|
||||||
serialized inventory
|
serialized inventory
|
||||||
|
|
||||||
- Node timers
|
- Node timers
|
||||||
if map format version == 23:
|
if map format version == 23:
|
||||||
|
|
72
src/chat.cpp
72
src/chat.cpp
|
@ -390,6 +390,7 @@ ChatPrompt::ChatPrompt(std::wstring prompt, u32 history_limit):
|
||||||
m_cols(0),
|
m_cols(0),
|
||||||
m_view(0),
|
m_view(0),
|
||||||
m_cursor(0),
|
m_cursor(0),
|
||||||
|
m_cursor_len(0),
|
||||||
m_nick_completion_start(0),
|
m_nick_completion_start(0),
|
||||||
m_nick_completion_end(0)
|
m_nick_completion_end(0)
|
||||||
{
|
{
|
||||||
|
@ -417,20 +418,13 @@ void ChatPrompt::input(const std::wstring &str)
|
||||||
m_nick_completion_end = 0;
|
m_nick_completion_end = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring ChatPrompt::submit()
|
void ChatPrompt::addToHistory(std::wstring line)
|
||||||
{
|
{
|
||||||
std::wstring line = m_line;
|
|
||||||
m_line.clear();
|
|
||||||
if (!line.empty())
|
if (!line.empty())
|
||||||
m_history.push_back(line);
|
m_history.push_back(line);
|
||||||
if (m_history.size() > m_history_limit)
|
if (m_history.size() > m_history_limit)
|
||||||
m_history.erase(m_history.begin());
|
m_history.erase(m_history.begin());
|
||||||
m_history_index = m_history.size();
|
m_history_index = m_history.size();
|
||||||
m_view = 0;
|
|
||||||
m_cursor = 0;
|
|
||||||
m_nick_completion_start = 0;
|
|
||||||
m_nick_completion_end = 0;
|
|
||||||
return line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPrompt::clear()
|
void ChatPrompt::clear()
|
||||||
|
@ -442,13 +436,15 @@ void ChatPrompt::clear()
|
||||||
m_nick_completion_end = 0;
|
m_nick_completion_end = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPrompt::replace(std::wstring line)
|
std::wstring ChatPrompt::replace(std::wstring line)
|
||||||
{
|
{
|
||||||
|
std::wstring old_line = m_line;
|
||||||
m_line = line;
|
m_line = line;
|
||||||
m_view = m_cursor = line.size();
|
m_view = m_cursor = line.size();
|
||||||
clampView();
|
clampView();
|
||||||
m_nick_completion_start = 0;
|
m_nick_completion_start = 0;
|
||||||
m_nick_completion_end = 0;
|
m_nick_completion_end = 0;
|
||||||
|
return old_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPrompt::historyPrev()
|
void ChatPrompt::historyPrev()
|
||||||
|
@ -590,14 +586,12 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
|
||||||
s32 length = m_line.size();
|
s32 length = m_line.size();
|
||||||
s32 increment = (dir == CURSOROP_DIR_RIGHT) ? 1 : -1;
|
s32 increment = (dir == CURSOROP_DIR_RIGHT) ? 1 : -1;
|
||||||
|
|
||||||
if (scope == CURSOROP_SCOPE_CHARACTER)
|
switch (scope) {
|
||||||
{
|
case CURSOROP_SCOPE_CHARACTER:
|
||||||
new_cursor += increment;
|
new_cursor += increment;
|
||||||
}
|
break;
|
||||||
else if (scope == CURSOROP_SCOPE_WORD)
|
case CURSOROP_SCOPE_WORD:
|
||||||
{
|
if (dir == CURSOROP_DIR_RIGHT) {
|
||||||
if (increment > 0)
|
|
||||||
{
|
|
||||||
// skip one word to the right
|
// skip one word to the right
|
||||||
while (new_cursor < length && isspace(m_line[new_cursor]))
|
while (new_cursor < length && isspace(m_line[new_cursor]))
|
||||||
new_cursor++;
|
new_cursor++;
|
||||||
|
@ -605,39 +599,47 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
|
||||||
new_cursor++;
|
new_cursor++;
|
||||||
while (new_cursor < length && isspace(m_line[new_cursor]))
|
while (new_cursor < length && isspace(m_line[new_cursor]))
|
||||||
new_cursor++;
|
new_cursor++;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// skip one word to the left
|
// skip one word to the left
|
||||||
while (new_cursor >= 1 && isspace(m_line[new_cursor - 1]))
|
while (new_cursor >= 1 && isspace(m_line[new_cursor - 1]))
|
||||||
new_cursor--;
|
new_cursor--;
|
||||||
while (new_cursor >= 1 && !isspace(m_line[new_cursor - 1]))
|
while (new_cursor >= 1 && !isspace(m_line[new_cursor - 1]))
|
||||||
new_cursor--;
|
new_cursor--;
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
else if (scope == CURSOROP_SCOPE_LINE)
|
case CURSOROP_SCOPE_LINE:
|
||||||
{
|
|
||||||
new_cursor += increment * length;
|
new_cursor += increment * length;
|
||||||
|
break;
|
||||||
|
case CURSOROP_SCOPE_SELECTION:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_cursor = MYMAX(MYMIN(new_cursor, length), 0);
|
new_cursor = MYMAX(MYMIN(new_cursor, length), 0);
|
||||||
|
|
||||||
if (op == CURSOROP_MOVE)
|
switch (op) {
|
||||||
{
|
case CURSOROP_MOVE:
|
||||||
m_cursor = new_cursor;
|
m_cursor = new_cursor;
|
||||||
}
|
m_cursor_len = 0;
|
||||||
else if (op == CURSOROP_DELETE)
|
break;
|
||||||
{
|
case CURSOROP_DELETE:
|
||||||
if (new_cursor < old_cursor)
|
if (m_cursor_len > 0) { // Delete selected text first
|
||||||
{
|
m_line.erase(m_cursor, m_cursor_len);
|
||||||
m_line.erase(new_cursor, old_cursor - new_cursor);
|
} else {
|
||||||
m_cursor = new_cursor;
|
m_cursor = MYMIN(new_cursor, old_cursor);
|
||||||
|
m_line.erase(m_cursor, abs(new_cursor - old_cursor));
|
||||||
}
|
}
|
||||||
else if (new_cursor > old_cursor)
|
m_cursor_len = 0;
|
||||||
{
|
break;
|
||||||
m_line.erase(old_cursor, new_cursor - old_cursor);
|
case CURSOROP_SELECT:
|
||||||
m_cursor = old_cursor;
|
if (scope == CURSOROP_SCOPE_LINE) {
|
||||||
|
m_cursor = 0;
|
||||||
|
m_cursor_len = length;
|
||||||
|
} else {
|
||||||
|
m_cursor = MYMIN(new_cursor, old_cursor);
|
||||||
|
m_cursor_len += abs(new_cursor - old_cursor);
|
||||||
|
m_cursor_len = MYMIN(m_cursor_len, length - m_cursor);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
clampView();
|
clampView();
|
||||||
|
|
21
src/chat.h
21
src/chat.h
|
@ -146,14 +146,21 @@ public:
|
||||||
void input(wchar_t ch);
|
void input(wchar_t ch);
|
||||||
void input(const std::wstring &str);
|
void input(const std::wstring &str);
|
||||||
|
|
||||||
// Submit, clear and return current line
|
// Add a string to the history
|
||||||
std::wstring submit();
|
void addToHistory(std::wstring line);
|
||||||
|
|
||||||
|
// Get current line
|
||||||
|
std::wstring getLine() const { return m_line; }
|
||||||
|
|
||||||
|
// Get section of line that is currently selected
|
||||||
|
std::wstring getSelection() const
|
||||||
|
{ return m_line.substr(m_cursor, m_cursor_len); }
|
||||||
|
|
||||||
// Clear the current line
|
// Clear the current line
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
// Replace the current line with the given text
|
// Replace the current line with the given text
|
||||||
void replace(std::wstring line);
|
std::wstring replace(std::wstring line);
|
||||||
|
|
||||||
// Select previous command from history
|
// Select previous command from history
|
||||||
void historyPrev();
|
void historyPrev();
|
||||||
|
@ -169,10 +176,13 @@ public:
|
||||||
std::wstring getVisiblePortion() const;
|
std::wstring getVisiblePortion() const;
|
||||||
// Get cursor position (relative to visible portion). -1 if invalid
|
// Get cursor position (relative to visible portion). -1 if invalid
|
||||||
s32 getVisibleCursorPosition() const;
|
s32 getVisibleCursorPosition() const;
|
||||||
|
// Get length of cursor selection
|
||||||
|
s32 getCursorLength() const { return m_cursor_len; }
|
||||||
|
|
||||||
// Cursor operations
|
// Cursor operations
|
||||||
enum CursorOp {
|
enum CursorOp {
|
||||||
CURSOROP_MOVE,
|
CURSOROP_MOVE,
|
||||||
|
CURSOROP_SELECT,
|
||||||
CURSOROP_DELETE
|
CURSOROP_DELETE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -186,7 +196,8 @@ public:
|
||||||
enum CursorOpScope {
|
enum CursorOpScope {
|
||||||
CURSOROP_SCOPE_CHARACTER,
|
CURSOROP_SCOPE_CHARACTER,
|
||||||
CURSOROP_SCOPE_WORD,
|
CURSOROP_SCOPE_WORD,
|
||||||
CURSOROP_SCOPE_LINE
|
CURSOROP_SCOPE_LINE,
|
||||||
|
CURSOROP_SCOPE_SELECTION
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cursor operation
|
// Cursor operation
|
||||||
|
@ -224,6 +235,8 @@ private:
|
||||||
s32 m_view;
|
s32 m_view;
|
||||||
// Cursor (index into m_line)
|
// Cursor (index into m_line)
|
||||||
s32 m_cursor;
|
s32 m_cursor;
|
||||||
|
// Cursor length (length of selected portion of line)
|
||||||
|
s32 m_cursor_len;
|
||||||
|
|
||||||
// Last nick completion start (index into m_line)
|
// Last nick completion start (index into m_line)
|
||||||
s32 m_nick_completion_start;
|
s32 m_nick_completion_start;
|
||||||
|
|
|
@ -248,9 +248,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
||||||
|
|
||||||
bool any_position_valid = false;
|
bool any_position_valid = false;
|
||||||
|
|
||||||
// The order is important here, must be y first
|
|
||||||
for(s16 y = max_y; y >= min_y; y--)
|
|
||||||
for(s16 x = min_x; x <= max_x; x++)
|
for(s16 x = min_x; x <= max_x; x++)
|
||||||
|
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);
|
v3s16 p(x,y,z);
|
||||||
|
@ -404,17 +403,15 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
||||||
Go through every nodebox, find nearest collision
|
Go through every nodebox, find nearest collision
|
||||||
*/
|
*/
|
||||||
for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) {
|
for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) {
|
||||||
|
// Ignore if already stepped up this nodebox.
|
||||||
|
if(is_step_up[boxindex])
|
||||||
|
continue;
|
||||||
|
|
||||||
// Find nearest collision of the two boxes (raytracing-like)
|
// Find nearest collision of the two boxes (raytracing-like)
|
||||||
f32 dtime_tmp;
|
f32 dtime_tmp;
|
||||||
int collided = axisAlignedCollision(
|
int collided = axisAlignedCollision(
|
||||||
cboxes[boxindex], movingbox, *speed_f, d, &dtime_tmp);
|
cboxes[boxindex], movingbox, *speed_f, d, &dtime_tmp);
|
||||||
|
|
||||||
// Ignore if already stepped up this nodebox.
|
|
||||||
if (is_step_up[boxindex]) {
|
|
||||||
pos_f->Y += (cboxes[boxindex].MaxEdge.Y - movingbox.MinEdge.Y);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collided == -1 || dtime_tmp >= nearest_dtime)
|
if (collided == -1 || dtime_tmp >= nearest_dtime)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -464,12 +461,10 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
||||||
is_collision = false;
|
is_collision = false;
|
||||||
|
|
||||||
CollisionInfo info;
|
CollisionInfo info;
|
||||||
if (is_object[nearest_boxindex]) {
|
if (is_object[nearest_boxindex])
|
||||||
info.type = COLLISION_OBJECT;
|
info.type = COLLISION_OBJECT;
|
||||||
result.standing_on_object = true;
|
else
|
||||||
} else {
|
|
||||||
info.type = COLLISION_NODE;
|
info.type = COLLISION_NODE;
|
||||||
}
|
|
||||||
|
|
||||||
info.node_p = node_positions[nearest_boxindex];
|
info.node_p = node_positions[nearest_boxindex];
|
||||||
info.bouncy = bouncy;
|
info.bouncy = bouncy;
|
||||||
|
@ -487,13 +482,12 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
||||||
speed_f->X = 0;
|
speed_f->X = 0;
|
||||||
result.collides = true;
|
result.collides = true;
|
||||||
result.collides_xz = true;
|
result.collides_xz = true;
|
||||||
} else if(nearest_collided == 1) { // Y
|
}
|
||||||
if (fabs(speed_f->Y) > BS * 3) {
|
else if(nearest_collided == 1) { // Y
|
||||||
|
if (fabs(speed_f->Y) > BS * 3)
|
||||||
speed_f->Y *= bounce;
|
speed_f->Y *= bounce;
|
||||||
} else {
|
else
|
||||||
speed_f->Y = 0;
|
speed_f->Y = 0;
|
||||||
result.touching_ground = true;
|
|
||||||
}
|
|
||||||
result.collides = true;
|
result.collides = true;
|
||||||
} else if(nearest_collided == 2) { // Z
|
} else if(nearest_collided == 2) { // Z
|
||||||
if (fabs(speed_f->Z) > BS * 3)
|
if (fabs(speed_f->Z) > BS * 3)
|
||||||
|
@ -514,5 +508,43 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Final touches: Check if standing on ground, step up stairs.
|
||||||
|
*/
|
||||||
|
aabb3f box = box_0;
|
||||||
|
box.MinEdge += *pos_f;
|
||||||
|
box.MaxEdge += *pos_f;
|
||||||
|
for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) {
|
||||||
|
const aabb3f& cbox = cboxes[boxindex];
|
||||||
|
|
||||||
|
/*
|
||||||
|
See if the object is touching ground.
|
||||||
|
|
||||||
|
Object touches ground if object's minimum Y is near node's
|
||||||
|
maximum Y and object's X-Z-area overlaps with the node's
|
||||||
|
X-Z-area.
|
||||||
|
|
||||||
|
Use 0.15*BS so that it is easier to get on a node.
|
||||||
|
*/
|
||||||
|
if (cbox.MaxEdge.X - d > box.MinEdge.X && cbox.MinEdge.X + d < box.MaxEdge.X &&
|
||||||
|
cbox.MaxEdge.Z - d > box.MinEdge.Z &&
|
||||||
|
cbox.MinEdge.Z + d < box.MaxEdge.Z) {
|
||||||
|
if (is_step_up[boxindex]) {
|
||||||
|
pos_f->Y += (cbox.MaxEdge.Y - box.MinEdge.Y);
|
||||||
|
box = box_0;
|
||||||
|
box.MinEdge += *pos_f;
|
||||||
|
box.MaxEdge += *pos_f;
|
||||||
|
}
|
||||||
|
if (fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.15 * BS) {
|
||||||
|
result.touching_ground = true;
|
||||||
|
|
||||||
|
if (is_object[boxindex])
|
||||||
|
result.standing_on_object = true;
|
||||||
|
if (is_unloaded[boxindex])
|
||||||
|
result.standing_on_unloaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
101
src/game.cpp
101
src/game.cpp
|
@ -176,19 +176,6 @@ struct LocalFormspecHandler : public TextDest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_formname == "MT_CHAT_MENU") {
|
|
||||||
assert(m_client != 0);
|
|
||||||
|
|
||||||
if ((fields.find("btn_send") != fields.end()) ||
|
|
||||||
(fields.find("quit") != fields.end())) {
|
|
||||||
StringMap::const_iterator it = fields.find("f_text");
|
|
||||||
if (it != fields.end())
|
|
||||||
m_client->typeChatMessage(utf8_to_wide(it->second));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_formname == "MT_DEATH_SCREEN") {
|
if (m_formname == "MT_DEATH_SCREEN") {
|
||||||
assert(m_client != 0);
|
assert(m_client != 0);
|
||||||
|
|
||||||
|
@ -1097,27 +1084,6 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec,
|
||||||
#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
|
#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void show_chat_menu(GUIFormSpecMenu **cur_formspec,
|
|
||||||
InventoryManager *invmgr, IGameDef *gamedef,
|
|
||||||
IWritableTextureSource *tsrc, IrrlichtDevice *device,
|
|
||||||
Client *client, std::string text)
|
|
||||||
{
|
|
||||||
std::string formspec =
|
|
||||||
FORMSPEC_VERSION_STRING
|
|
||||||
SIZE_TAG
|
|
||||||
"field[3,2.35;6,0.5;f_text;;" + text + "]"
|
|
||||||
"button_exit[4,3;3,0.5;btn_send;" + strgettext("Proceed") + "]"
|
|
||||||
;
|
|
||||||
|
|
||||||
/* Create menu */
|
|
||||||
/* Note: FormspecFormSource and LocalFormspecHandler
|
|
||||||
* are deleted by guiFormSpecMenu */
|
|
||||||
FormspecFormSource *fs_src = new FormspecFormSource(formspec);
|
|
||||||
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_CHAT_MENU", client);
|
|
||||||
|
|
||||||
create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, fs_src, txt_dst, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void show_deathscreen(GUIFormSpecMenu **cur_formspec,
|
static void show_deathscreen(GUIFormSpecMenu **cur_formspec,
|
||||||
InventoryManager *invmgr, IGameDef *gamedef,
|
InventoryManager *invmgr, IGameDef *gamedef,
|
||||||
IWritableTextureSource *tsrc, IrrlichtDevice *device, Client *client)
|
IWritableTextureSource *tsrc, IrrlichtDevice *device, Client *client)
|
||||||
|
@ -1518,7 +1484,7 @@ protected:
|
||||||
|
|
||||||
void dropSelectedItem();
|
void dropSelectedItem();
|
||||||
void openInventory();
|
void openInventory();
|
||||||
void openConsole();
|
void openConsole(float height, const wchar_t *line=NULL);
|
||||||
void toggleFreeMove(float *statustext_time);
|
void toggleFreeMove(float *statustext_time);
|
||||||
void toggleFreeMoveAlt(float *statustext_time, float *jump_timer);
|
void toggleFreeMoveAlt(float *statustext_time, float *jump_timer);
|
||||||
void toggleFast(float *statustext_time);
|
void toggleFast(float *statustext_time);
|
||||||
|
@ -1578,6 +1544,10 @@ protected:
|
||||||
static void settingChangedCallback(const std::string &setting_name, void *data);
|
static void settingChangedCallback(const std::string &setting_name, void *data);
|
||||||
void readSettings();
|
void readSettings();
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
void handleAndroidChatInput();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InputHandler *input;
|
InputHandler *input;
|
||||||
|
|
||||||
|
@ -1664,8 +1634,8 @@ private:
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
bool m_cache_hold_aux1;
|
bool m_cache_hold_aux1;
|
||||||
|
bool m_android_chat_open;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Game::Game() :
|
Game::Game() :
|
||||||
|
@ -2179,7 +2149,7 @@ bool Game::initGui()
|
||||||
|
|
||||||
// Chat backend and console
|
// Chat backend and console
|
||||||
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
|
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
|
||||||
-1, chat_backend, client);
|
-1, chat_backend, client, &g_menumgr);
|
||||||
if (!gui_chat_console) {
|
if (!gui_chat_console) {
|
||||||
*error_message = "Could not allocate memory for chat console";
|
*error_message = "Could not allocate memory for chat console";
|
||||||
errorstream << *error_message << std::endl;
|
errorstream << *error_message << std::endl;
|
||||||
|
@ -2617,10 +2587,10 @@ void Game::processUserInput(VolatileRunFlags *flags,
|
||||||
input->step(dtime);
|
input->step(dtime);
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
|
if (current_formspec != NULL)
|
||||||
if (current_formspec != 0)
|
|
||||||
current_formspec->getAndroidUIInput();
|
current_formspec->getAndroidUIInput();
|
||||||
|
else
|
||||||
|
handleAndroidChatInput();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Increase timer for double tap of "keymap_jump"
|
// Increase timer for double tap of "keymap_jump"
|
||||||
|
@ -2656,16 +2626,16 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
|
||||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INVENTORY])) {
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INVENTORY])) {
|
||||||
openInventory();
|
openInventory();
|
||||||
} else if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) {
|
} else if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) {
|
||||||
show_pause_menu(¤t_formspec, client, gamedef, texture_src, device,
|
if (!gui_chat_console->isOpenInhibited()) {
|
||||||
simple_singleplayer_mode);
|
show_pause_menu(¤t_formspec, client, gamedef,
|
||||||
|
texture_src, device, simple_singleplayer_mode);
|
||||||
|
}
|
||||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CHAT])) {
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CHAT])) {
|
||||||
show_chat_menu(¤t_formspec, client, gamedef, texture_src, device,
|
openConsole(0.2, L"");
|
||||||
client, "");
|
|
||||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CMD])) {
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CMD])) {
|
||||||
show_chat_menu(¤t_formspec, client, gamedef, texture_src, device,
|
openConsole(0.2, L"/");
|
||||||
client, "/");
|
|
||||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CONSOLE])) {
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CONSOLE])) {
|
||||||
openConsole();
|
openConsole(1);
|
||||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FREEMOVE])) {
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FREEMOVE])) {
|
||||||
toggleFreeMove(statustext_time);
|
toggleFreeMove(statustext_time);
|
||||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP])) {
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP])) {
|
||||||
|
@ -2700,15 +2670,15 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
|
||||||
decreaseViewRange(statustext_time);
|
decreaseViewRange(statustext_time);
|
||||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_RANGESELECT])) {
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_RANGESELECT])) {
|
||||||
toggleFullViewRange(statustext_time);
|
toggleFullViewRange(statustext_time);
|
||||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_NEXT]))
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_NEXT])) {
|
||||||
quicktune->next();
|
quicktune->next();
|
||||||
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_PREV]))
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_PREV])) {
|
||||||
quicktune->prev();
|
quicktune->prev();
|
||||||
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_INC]))
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_INC])) {
|
||||||
quicktune->inc();
|
quicktune->inc();
|
||||||
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_DEC]))
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_DEC])) {
|
||||||
quicktune->dec();
|
quicktune->dec();
|
||||||
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DEBUG_STACKS])) {
|
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DEBUG_STACKS])) {
|
||||||
// Print debug stacks
|
// Print debug stacks
|
||||||
dstream << "-----------------------------------------"
|
dstream << "-----------------------------------------"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
@ -2808,14 +2778,31 @@ void Game::openInventory()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Game::openConsole()
|
void Game::openConsole(float height, const wchar_t *line)
|
||||||
{
|
{
|
||||||
if (!gui_chat_console->isOpenInhibited()) {
|
#ifdef __ANDROID__
|
||||||
// Open up to over half of the screen
|
porting::showInputDialog(gettext("ok"), "", "", 2);
|
||||||
gui_chat_console->openConsole(0.6);
|
m_android_chat_open = true;
|
||||||
guienv->setFocus(gui_chat_console);
|
#else
|
||||||
|
if (gui_chat_console->isOpenInhibited())
|
||||||
|
return;
|
||||||
|
gui_chat_console->openConsole(height);
|
||||||
|
if (line) {
|
||||||
|
gui_chat_console->setCloseOnEnter(true);
|
||||||
|
gui_chat_console->replaceAndAddToHistory(line);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
void Game::handleAndroidChatInput()
|
||||||
|
{
|
||||||
|
if (m_android_chat_open && porting::getInputDialogState() == 0) {
|
||||||
|
std::string text = porting::getInputDialogValue();
|
||||||
|
client->typeChatMessage(utf8_to_wide(text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void Game::toggleFreeMove(float *statustext_time)
|
void Game::toggleFreeMove(float *statustext_time)
|
||||||
|
|
|
@ -46,15 +46,18 @@ GUIChatConsole::GUIChatConsole(
|
||||||
gui::IGUIElement* parent,
|
gui::IGUIElement* parent,
|
||||||
s32 id,
|
s32 id,
|
||||||
ChatBackend* backend,
|
ChatBackend* backend,
|
||||||
Client* client
|
Client* client,
|
||||||
|
IMenuManager* menumgr
|
||||||
):
|
):
|
||||||
IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
|
IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
|
||||||
core::rect<s32>(0,0,100,100)),
|
core::rect<s32>(0,0,100,100)),
|
||||||
m_chat_backend(backend),
|
m_chat_backend(backend),
|
||||||
m_client(client),
|
m_client(client),
|
||||||
|
m_menumgr(menumgr),
|
||||||
m_screensize(v2u32(0,0)),
|
m_screensize(v2u32(0,0)),
|
||||||
m_animate_time_old(0),
|
m_animate_time_old(0),
|
||||||
m_open(false),
|
m_open(false),
|
||||||
|
m_close_on_enter(false),
|
||||||
m_height(0),
|
m_height(0),
|
||||||
m_desired_height(0),
|
m_desired_height(0),
|
||||||
m_desired_height_fraction(0.0),
|
m_desired_height_fraction(0.0),
|
||||||
|
@ -119,6 +122,8 @@ void GUIChatConsole::openConsole(f32 height)
|
||||||
m_desired_height_fraction = height;
|
m_desired_height_fraction = height;
|
||||||
m_desired_height = height * m_screensize.Y;
|
m_desired_height = height * m_screensize.Y;
|
||||||
reformatConsole();
|
reformatConsole();
|
||||||
|
Environment->setFocus(this);
|
||||||
|
m_menumgr->createdMenu(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GUIChatConsole::isOpen() const
|
bool GUIChatConsole::isOpen() const
|
||||||
|
@ -134,11 +139,13 @@ bool GUIChatConsole::isOpenInhibited() const
|
||||||
void GUIChatConsole::closeConsole()
|
void GUIChatConsole::closeConsole()
|
||||||
{
|
{
|
||||||
m_open = false;
|
m_open = false;
|
||||||
|
Environment->removeFocus(this);
|
||||||
|
m_menumgr->deletingMenu(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIChatConsole::closeConsoleAtOnce()
|
void GUIChatConsole::closeConsoleAtOnce()
|
||||||
{
|
{
|
||||||
m_open = false;
|
closeConsole();
|
||||||
m_height = 0;
|
m_height = 0;
|
||||||
recalculateConsolePosition();
|
recalculateConsolePosition();
|
||||||
}
|
}
|
||||||
|
@ -148,6 +155,14 @@ f32 GUIChatConsole::getDesiredHeight() const
|
||||||
return m_desired_height_fraction;
|
return m_desired_height_fraction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUIChatConsole::replaceAndAddToHistory(std::wstring line)
|
||||||
|
{
|
||||||
|
ChatPrompt& prompt = m_chat_backend->getPrompt();
|
||||||
|
prompt.addToHistory(prompt.getLine());
|
||||||
|
prompt.replace(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GUIChatConsole::setCursor(
|
void GUIChatConsole::setCursor(
|
||||||
bool visible, bool blinking, f32 blink_speed, f32 relative_height)
|
bool visible, bool blinking, f32 blink_speed, f32 relative_height)
|
||||||
{
|
{
|
||||||
|
@ -362,13 +377,15 @@ void GUIChatConsole::drawPrompt()
|
||||||
s32 cursor_pos = prompt.getVisibleCursorPosition();
|
s32 cursor_pos = prompt.getVisibleCursorPosition();
|
||||||
if (cursor_pos >= 0)
|
if (cursor_pos >= 0)
|
||||||
{
|
{
|
||||||
|
s32 cursor_len = prompt.getCursorLength();
|
||||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||||
s32 x = (1 + cursor_pos) * m_fontsize.X;
|
s32 x = (1 + cursor_pos) * m_fontsize.X;
|
||||||
core::rect<s32> destrect(
|
core::rect<s32> destrect(
|
||||||
x,
|
x,
|
||||||
y + (1.0-m_cursor_height) * m_fontsize.Y,
|
y + m_fontsize.Y * (1.0 - m_cursor_height),
|
||||||
x + m_fontsize.X,
|
x + m_fontsize.X * MYMAX(cursor_len, 1),
|
||||||
y + m_fontsize.Y);
|
y + m_fontsize.Y * (cursor_len ? m_cursor_height+1 : 1)
|
||||||
|
);
|
||||||
video::SColor cursor_color(255,255,255,255);
|
video::SColor cursor_color(255,255,255,255);
|
||||||
driver->draw2DRectangle(
|
driver->draw2DRectangle(
|
||||||
cursor_color,
|
cursor_color,
|
||||||
|
@ -381,23 +398,27 @@ void GUIChatConsole::drawPrompt()
|
||||||
|
|
||||||
bool GUIChatConsole::OnEvent(const SEvent& event)
|
bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
ChatPrompt &prompt = m_chat_backend->getPrompt();
|
||||||
|
|
||||||
if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
|
if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
|
||||||
{
|
{
|
||||||
// Key input
|
// Key input
|
||||||
if(KeyPress(event.KeyInput) == getKeySetting("keymap_console"))
|
if(KeyPress(event.KeyInput) == getKeySetting("keymap_console"))
|
||||||
{
|
{
|
||||||
closeConsole();
|
closeConsole();
|
||||||
Environment->removeFocus(this);
|
|
||||||
|
|
||||||
// inhibit open so the_game doesn't reopen immediately
|
// inhibit open so the_game doesn't reopen immediately
|
||||||
m_open_inhibited = 50;
|
m_open_inhibited = 50;
|
||||||
|
m_close_on_enter = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_ESCAPE)
|
else if(event.KeyInput.Key == KEY_ESCAPE)
|
||||||
{
|
{
|
||||||
closeConsoleAtOnce();
|
closeConsoleAtOnce();
|
||||||
Environment->removeFocus(this);
|
m_close_on_enter = false;
|
||||||
// the_game will open the pause menu
|
// inhibit open so the_game doesn't reopen immediately
|
||||||
|
m_open_inhibited = 1; // so the ESCAPE button doesn't open the "pause menu"
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_PRIOR)
|
else if(event.KeyInput.Key == KEY_PRIOR)
|
||||||
|
@ -412,57 +433,50 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_RETURN)
|
else if(event.KeyInput.Key == KEY_RETURN)
|
||||||
{
|
{
|
||||||
std::wstring text = m_chat_backend->getPrompt().submit();
|
prompt.addToHistory(prompt.getLine());
|
||||||
|
std::wstring text = prompt.replace(L"");
|
||||||
m_client->typeChatMessage(text);
|
m_client->typeChatMessage(text);
|
||||||
|
if (m_close_on_enter) {
|
||||||
|
closeConsoleAtOnce();
|
||||||
|
m_close_on_enter = false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_UP)
|
else if(event.KeyInput.Key == KEY_UP)
|
||||||
{
|
{
|
||||||
// Up pressed
|
// Up pressed
|
||||||
// Move back in history
|
// Move back in history
|
||||||
m_chat_backend->getPrompt().historyPrev();
|
prompt.historyPrev();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_DOWN)
|
else if(event.KeyInput.Key == KEY_DOWN)
|
||||||
{
|
{
|
||||||
// Down pressed
|
// Down pressed
|
||||||
// Move forward in history
|
// Move forward in history
|
||||||
m_chat_backend->getPrompt().historyNext();
|
prompt.historyNext();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_LEFT)
|
else if(event.KeyInput.Key == KEY_LEFT || event.KeyInput.Key == KEY_RIGHT)
|
||||||
{
|
{
|
||||||
// Left or Ctrl-Left pressed
|
// Left/right pressed
|
||||||
// move character / word to the left
|
// Move/select character/word to the left depending on control and shift keys
|
||||||
ChatPrompt::CursorOpScope scope =
|
ChatPrompt::CursorOp op = event.KeyInput.Shift ?
|
||||||
event.KeyInput.Control ?
|
ChatPrompt::CURSOROP_SELECT :
|
||||||
|
ChatPrompt::CURSOROP_MOVE;
|
||||||
|
ChatPrompt::CursorOpDir dir = event.KeyInput.Key == KEY_LEFT ?
|
||||||
|
ChatPrompt::CURSOROP_DIR_LEFT :
|
||||||
|
ChatPrompt::CURSOROP_DIR_RIGHT;
|
||||||
|
ChatPrompt::CursorOpScope scope = event.KeyInput.Control ?
|
||||||
ChatPrompt::CURSOROP_SCOPE_WORD :
|
ChatPrompt::CURSOROP_SCOPE_WORD :
|
||||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
||||||
m_chat_backend->getPrompt().cursorOperation(
|
prompt.cursorOperation(op, dir, scope);
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
|
||||||
scope);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if(event.KeyInput.Key == KEY_RIGHT)
|
|
||||||
{
|
|
||||||
// Right or Ctrl-Right pressed
|
|
||||||
// move character / word to the right
|
|
||||||
ChatPrompt::CursorOpScope scope =
|
|
||||||
event.KeyInput.Control ?
|
|
||||||
ChatPrompt::CURSOROP_SCOPE_WORD :
|
|
||||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
|
||||||
m_chat_backend->getPrompt().cursorOperation(
|
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
|
||||||
scope);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_HOME)
|
else if(event.KeyInput.Key == KEY_HOME)
|
||||||
{
|
{
|
||||||
// Home pressed
|
// Home pressed
|
||||||
// move to beginning of line
|
// move to beginning of line
|
||||||
m_chat_backend->getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
@ -472,7 +486,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
{
|
{
|
||||||
// End pressed
|
// End pressed
|
||||||
// move to end of line
|
// move to end of line
|
||||||
m_chat_backend->getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
@ -486,7 +500,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
event.KeyInput.Control ?
|
event.KeyInput.Control ?
|
||||||
ChatPrompt::CURSOROP_SCOPE_WORD :
|
ChatPrompt::CURSOROP_SCOPE_WORD :
|
||||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
||||||
m_chat_backend->getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_DELETE,
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||||
scope);
|
scope);
|
||||||
|
@ -500,30 +514,72 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
event.KeyInput.Control ?
|
event.KeyInput.Control ?
|
||||||
ChatPrompt::CURSOROP_SCOPE_WORD :
|
ChatPrompt::CURSOROP_SCOPE_WORD :
|
||||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
||||||
m_chat_backend->getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_DELETE,
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
scope);
|
scope);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if(event.KeyInput.Key == KEY_KEY_A && event.KeyInput.Control)
|
||||||
|
{
|
||||||
|
// Ctrl-A pressed
|
||||||
|
// Select all text
|
||||||
|
prompt.cursorOperation(
|
||||||
|
ChatPrompt::CURSOROP_SELECT,
|
||||||
|
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
|
||||||
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(event.KeyInput.Key == KEY_KEY_C && event.KeyInput.Control)
|
||||||
|
{
|
||||||
|
// Ctrl-C pressed
|
||||||
|
// Copy text to clipboard
|
||||||
|
if (prompt.getCursorLength() <= 0)
|
||||||
|
return true;
|
||||||
|
std::wstring wselected = prompt.getSelection();
|
||||||
|
std::string selected(wselected.begin(), wselected.end());
|
||||||
|
Environment->getOSOperator()->copyToClipboard(selected.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control)
|
else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control)
|
||||||
{
|
{
|
||||||
// Ctrl-V pressed
|
// Ctrl-V pressed
|
||||||
// paste text from clipboard
|
// paste text from clipboard
|
||||||
|
if (prompt.getCursorLength() > 0) {
|
||||||
|
// Delete selected section of text
|
||||||
|
prompt.cursorOperation(
|
||||||
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
|
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
|
||||||
|
ChatPrompt::CURSOROP_SCOPE_SELECTION);
|
||||||
|
}
|
||||||
IOSOperator *os_operator = Environment->getOSOperator();
|
IOSOperator *os_operator = Environment->getOSOperator();
|
||||||
const c8 *text = os_operator->getTextFromClipboard();
|
const c8 *text = os_operator->getTextFromClipboard();
|
||||||
if (text)
|
if (!text)
|
||||||
{
|
return true;
|
||||||
std::wstring wtext = narrow_to_wide(text);
|
std::basic_string<unsigned char> str((const unsigned char*)text);
|
||||||
m_chat_backend->getPrompt().input(wtext);
|
prompt.input(std::wstring(str.begin(), str.end()));
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
else if(event.KeyInput.Key == KEY_KEY_X && event.KeyInput.Control)
|
||||||
|
{
|
||||||
|
// Ctrl-X pressed
|
||||||
|
// Cut text to clipboard
|
||||||
|
if (prompt.getCursorLength() <= 0)
|
||||||
|
return true;
|
||||||
|
std::wstring wselected = prompt.getSelection();
|
||||||
|
std::string selected(wselected.begin(), wselected.end());
|
||||||
|
Environment->getOSOperator()->copyToClipboard(selected.c_str());
|
||||||
|
prompt.cursorOperation(
|
||||||
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
|
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
|
||||||
|
ChatPrompt::CURSOROP_SCOPE_SELECTION);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Key == KEY_KEY_U && event.KeyInput.Control)
|
else if(event.KeyInput.Key == KEY_KEY_U && event.KeyInput.Control)
|
||||||
{
|
{
|
||||||
// Ctrl-U pressed
|
// Ctrl-U pressed
|
||||||
// kill line to left end
|
// kill line to left end
|
||||||
m_chat_backend->getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_DELETE,
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
@ -533,7 +589,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
{
|
{
|
||||||
// Ctrl-K pressed
|
// Ctrl-K pressed
|
||||||
// kill line to right end
|
// kill line to right end
|
||||||
m_chat_backend->getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_DELETE,
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
@ -545,7 +601,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
// Nick completion
|
// Nick completion
|
||||||
std::list<std::string> names = m_client->getConnectedPlayerNames();
|
std::list<std::string> names = m_client->getConnectedPlayerNames();
|
||||||
bool backwards = event.KeyInput.Shift;
|
bool backwards = event.KeyInput.Shift;
|
||||||
m_chat_backend->getPrompt().nickCompletion(names, backwards);
|
prompt.nickCompletion(names, backwards);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(event.KeyInput.Char != 0 && !event.KeyInput.Control)
|
else if(event.KeyInput.Char != 0 && !event.KeyInput.Control)
|
||||||
|
@ -553,9 +609,9 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
#if (defined(linux) || defined(__linux))
|
#if (defined(linux) || defined(__linux))
|
||||||
wchar_t wc = L'_';
|
wchar_t wc = L'_';
|
||||||
mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
|
mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
|
||||||
m_chat_backend->getPrompt().input(wc);
|
prompt.input(wc);
|
||||||
#else
|
#else
|
||||||
m_chat_backend->getPrompt().input(event.KeyInput.Char);
|
prompt.input(event.KeyInput.Char);
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#define GUICHATCONSOLE_HEADER
|
#define GUICHATCONSOLE_HEADER
|
||||||
|
|
||||||
#include "irrlichttypes_extrabloated.h"
|
#include "irrlichttypes_extrabloated.h"
|
||||||
|
#include "modalMenu.h"
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -33,7 +34,8 @@ public:
|
||||||
gui::IGUIElement* parent,
|
gui::IGUIElement* parent,
|
||||||
s32 id,
|
s32 id,
|
||||||
ChatBackend* backend,
|
ChatBackend* backend,
|
||||||
Client* client);
|
Client* client,
|
||||||
|
IMenuManager* menumgr);
|
||||||
virtual ~GUIChatConsole();
|
virtual ~GUIChatConsole();
|
||||||
|
|
||||||
// Open the console (height = desired fraction of screen size)
|
// Open the console (height = desired fraction of screen size)
|
||||||
|
@ -51,11 +53,16 @@ public:
|
||||||
void closeConsole();
|
void closeConsole();
|
||||||
// Close the console immediately, without animation.
|
// Close the console immediately, without animation.
|
||||||
void closeConsoleAtOnce();
|
void closeConsoleAtOnce();
|
||||||
|
// Set whether to close the console after the user presses enter.
|
||||||
|
void setCloseOnEnter(bool close) { m_close_on_enter = close; }
|
||||||
|
|
||||||
// Return the desired height (fraction of screen size)
|
// Return the desired height (fraction of screen size)
|
||||||
// Zero if the console is closed or getting closed
|
// Zero if the console is closed or getting closed
|
||||||
f32 getDesiredHeight() const;
|
f32 getDesiredHeight() const;
|
||||||
|
|
||||||
|
// Replace actual line when adding the actual to the history (if there is any)
|
||||||
|
void replaceAndAddToHistory(std::wstring line);
|
||||||
|
|
||||||
// Change how the cursor looks
|
// Change how the cursor looks
|
||||||
void setCursor(
|
void setCursor(
|
||||||
bool visible,
|
bool visible,
|
||||||
|
@ -81,11 +88,9 @@ private:
|
||||||
void drawPrompt();
|
void drawPrompt();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// pointer to the chat backend
|
|
||||||
ChatBackend* m_chat_backend;
|
ChatBackend* m_chat_backend;
|
||||||
|
|
||||||
// pointer to the client
|
|
||||||
Client* m_client;
|
Client* m_client;
|
||||||
|
IMenuManager* m_menumgr;
|
||||||
|
|
||||||
// current screen size
|
// current screen size
|
||||||
v2u32 m_screensize;
|
v2u32 m_screensize;
|
||||||
|
@ -95,6 +100,8 @@ private:
|
||||||
|
|
||||||
// should the console be opened or closed?
|
// should the console be opened or closed?
|
||||||
bool m_open;
|
bool m_open;
|
||||||
|
// should it close after you press enter?
|
||||||
|
bool m_close_on_enter;
|
||||||
// current console height [pixels]
|
// current console height [pixels]
|
||||||
s32 m_height;
|
s32 m_height;
|
||||||
// desired height [pixels]
|
// desired height [pixels]
|
||||||
|
|
|
@ -47,9 +47,9 @@ extern gui::IGUIStaticText *guiroot;
|
||||||
class MainMenuManager : public IMenuManager
|
class MainMenuManager : public IMenuManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void createdMenu(GUIModalMenu *menu)
|
virtual void createdMenu(gui::IGUIElement *menu)
|
||||||
{
|
{
|
||||||
for(std::list<GUIModalMenu*>::iterator
|
for(std::list<gui::IGUIElement*>::iterator
|
||||||
i = m_stack.begin();
|
i = m_stack.begin();
|
||||||
i != m_stack.end(); ++i)
|
i != m_stack.end(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -61,13 +61,13 @@ public:
|
||||||
m_stack.push_back(menu);
|
m_stack.push_back(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void deletingMenu(GUIModalMenu *menu)
|
virtual void deletingMenu(gui::IGUIElement *menu)
|
||||||
{
|
{
|
||||||
// Remove all entries if there are duplicates
|
// Remove all entries if there are duplicates
|
||||||
bool removed_entry;
|
bool removed_entry;
|
||||||
do{
|
do{
|
||||||
removed_entry = false;
|
removed_entry = false;
|
||||||
for(std::list<GUIModalMenu*>::iterator
|
for(std::list<gui::IGUIElement*>::iterator
|
||||||
i = m_stack.begin();
|
i = m_stack.begin();
|
||||||
i != m_stack.end(); ++i)
|
i != m_stack.end(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -91,10 +91,10 @@ public:
|
||||||
// Returns true to prevent further processing
|
// Returns true to prevent further processing
|
||||||
virtual bool preprocessEvent(const SEvent& event)
|
virtual bool preprocessEvent(const SEvent& event)
|
||||||
{
|
{
|
||||||
if(!m_stack.empty())
|
if (m_stack.empty())
|
||||||
return m_stack.back()->preprocessEvent(event);
|
|
||||||
else
|
|
||||||
return false;
|
return false;
|
||||||
|
GUIModalMenu *mm = dynamic_cast<GUIModalMenu*>(m_stack.back());
|
||||||
|
return mm && mm->preprocessEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 menuCount()
|
u32 menuCount()
|
||||||
|
@ -104,16 +104,17 @@ public:
|
||||||
|
|
||||||
bool pausesGame()
|
bool pausesGame()
|
||||||
{
|
{
|
||||||
for(std::list<GUIModalMenu*>::iterator
|
for(std::list<gui::IGUIElement*>::iterator
|
||||||
i = m_stack.begin(); i != m_stack.end(); ++i)
|
i = m_stack.begin(); i != m_stack.end(); ++i)
|
||||||
{
|
{
|
||||||
if((*i)->pausesGame())
|
GUIModalMenu *mm = dynamic_cast<GUIModalMenu*>(*i);
|
||||||
|
if (mm && mm->pausesGame())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<GUIModalMenu*> m_stack;
|
std::list<gui::IGUIElement*> m_stack;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MainMenuManager g_menumgr;
|
extern MainMenuManager g_menumgr;
|
||||||
|
|
|
@ -399,8 +399,21 @@ void MapgenValleys::calculateNoise()
|
||||||
|
|
||||||
//mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
|
//mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
|
||||||
|
|
||||||
|
float heat_offset = 0.f;
|
||||||
|
float humidity_scale = 1.f;
|
||||||
|
|
||||||
|
// Altitude chill tends to reduce the average heat.
|
||||||
|
if (use_altitude_chill)
|
||||||
|
heat_offset = 5.f;
|
||||||
|
|
||||||
|
// River humidity tends to increase the humidity range.
|
||||||
|
if (humid_rivers) {
|
||||||
|
humidity_scale = 0.8f;
|
||||||
|
}
|
||||||
|
|
||||||
for (s32 index = 0; index < csize.X * csize.Z; index++) {
|
for (s32 index = 0; index < csize.X * csize.Z; index++) {
|
||||||
noise_heat->result[index] += noise_heat_blend->result[index];
|
noise_heat->result[index] += noise_heat_blend->result[index] + heat_offset;
|
||||||
|
noise_humidity->result[index] *= humidity_scale;
|
||||||
noise_humidity->result[index] += noise_humidity_blend->result[index];
|
noise_humidity->result[index] += noise_humidity_blend->result[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,9 +494,10 @@ float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// base - depth : height of the bottom of the river
|
// base - depth : height of the bottom of the river
|
||||||
// water_level - 6 : don't make rivers below 6 nodes under the surface
|
// water_level - 3 : don't make rivers below 3 nodes under the surface
|
||||||
|
// We use three because that's as low as the swamp biomes go.
|
||||||
// There is no logical equivalent to this using rangelim.
|
// There is no logical equivalent to this using rangelim.
|
||||||
mount = MYMIN(MYMAX(base - depth, (float) (water_level - 6)), mount);
|
mount = MYMIN(MYMAX(base - depth, (float)(water_level - 3)), mount);
|
||||||
|
|
||||||
// Slope has no influence on rivers.
|
// Slope has no influence on rivers.
|
||||||
*tn->slope = 0.f;
|
*tn->slope = 0.f;
|
||||||
|
@ -503,7 +517,7 @@ float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
|
||||||
for (s16 y = y_start; y <= y_start + 1000; y++) {
|
for (s16 y = y_start; y <= y_start + 1000; y++) {
|
||||||
float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
|
float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
|
||||||
|
|
||||||
if (fill * *tn->slope <= y - mount) {
|
if (fill * *tn->slope < y - mount) {
|
||||||
mount = MYMAX(y - 1, mount);
|
mount = MYMAX(y - 1, mount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -522,7 +536,7 @@ int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
|
||||||
|
|
||||||
s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
|
s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
|
||||||
if (level_at_point <= water_level ||
|
if (level_at_point <= water_level ||
|
||||||
level_at_point > water_level + 16)
|
level_at_point > water_level + 32)
|
||||||
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
|
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
|
||||||
else
|
else
|
||||||
return level_at_point;
|
return level_at_point;
|
||||||
|
@ -552,6 +566,15 @@ float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
|
||||||
|
|
||||||
int MapgenValleys::generateTerrain()
|
int MapgenValleys::generateTerrain()
|
||||||
{
|
{
|
||||||
|
// Raising this reduces the rate of evaporation.
|
||||||
|
static const float evaporation = 300.f;
|
||||||
|
// from the lua
|
||||||
|
static const float humidity_dropoff = 4.f;
|
||||||
|
// constant to convert altitude chill (compatible with lua) to heat
|
||||||
|
static const float alt_to_heat = 20.f;
|
||||||
|
// humidity reduction by altitude
|
||||||
|
static const float alt_to_humid = 10.f;
|
||||||
|
|
||||||
MapNode n_air(CONTENT_AIR);
|
MapNode n_air(CONTENT_AIR);
|
||||||
MapNode n_river_water(c_river_water_source);
|
MapNode n_river_water(c_river_water_source);
|
||||||
MapNode n_sand(c_sand);
|
MapNode n_sand(c_sand);
|
||||||
|
@ -564,42 +587,56 @@ int MapgenValleys::generateTerrain()
|
||||||
|
|
||||||
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
for (s16 z = node_min.Z; z <= node_max.Z; z++)
|
||||||
for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
|
for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
|
||||||
s16 river_y = floor(noise_rivers->result[index_2d]);
|
float river_y = noise_rivers->result[index_2d];
|
||||||
s16 surface_y = floor(noise_terrain_height->result[index_2d]);
|
float surface_y = noise_terrain_height->result[index_2d];
|
||||||
float slope = noise_inter_valley_slope->result[index_2d];
|
float slope = noise_inter_valley_slope->result[index_2d];
|
||||||
|
float t_heat = noise_heat->result[index_2d];
|
||||||
|
|
||||||
heightmap[index_2d] = surface_y;
|
heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
|
||||||
|
|
||||||
if (surface_y > surface_max_y)
|
if (surface_y > surface_max_y)
|
||||||
surface_max_y = surface_y;
|
surface_max_y = ceil(surface_y);
|
||||||
|
|
||||||
|
if (humid_rivers) {
|
||||||
|
// Derive heat from (base) altitude. This will be most correct
|
||||||
|
// at rivers, since other surface heights may vary below.
|
||||||
|
if (use_altitude_chill && (surface_y > 0.f || river_y > 0.f))
|
||||||
|
t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
|
||||||
|
|
||||||
|
// If humidity is low or heat is high, lower the water table.
|
||||||
|
float delta = noise_humidity->result[index_2d] - 50.f;
|
||||||
|
if (delta < 0.f) {
|
||||||
|
float t_evap = (t_heat - 32.f) / evaporation;
|
||||||
|
river_y += delta * MYMAX(t_evap, 0.08f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u32 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
|
u32 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
|
||||||
u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
|
u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
|
||||||
|
|
||||||
// Mapgens concern themselves with stone and water.
|
// Mapgens concern themselves with stone and water.
|
||||||
for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
|
for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
|
||||||
float fill = 0.f;
|
|
||||||
fill = noise_inter_valley_fill->result[index_3d];
|
|
||||||
|
|
||||||
if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
|
if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
|
||||||
bool river = (river_y > surface_y);
|
float fill = noise_inter_valley_fill->result[index_3d];
|
||||||
|
float surface_delta = (float)y - surface_y;
|
||||||
|
bool river = y + 1 < river_y;
|
||||||
|
|
||||||
if (river && y == surface_y) {
|
if (fabs(surface_delta) <= 0.5f && y > water_level && river) {
|
||||||
// river bottom
|
// river bottom
|
||||||
vm->m_data[index_data] = n_sand;
|
vm->m_data[index_data] = n_sand;
|
||||||
} else if (river && y <= surface_y) {
|
} else if (slope * fill > surface_delta) {
|
||||||
// ground
|
// ground
|
||||||
vm->m_data[index_data] = n_stone;
|
vm->m_data[index_data] = n_stone;
|
||||||
} else if (river && y < river_y) {
|
if (y > heightmap[index_2d])
|
||||||
// river
|
heightmap[index_2d] = y;
|
||||||
vm->m_data[index_data] = n_river_water;
|
if (y > surface_max_y)
|
||||||
} else if ((!river) && myround(fill * slope) >= y - surface_y) {
|
surface_max_y = y;
|
||||||
// ground
|
|
||||||
vm->m_data[index_data] = n_stone;
|
|
||||||
heightmap[index_2d] = surface_max_y = y;
|
|
||||||
} else if (y <= water_level) {
|
} else if (y <= water_level) {
|
||||||
// sea
|
// sea
|
||||||
vm->m_data[index_data] = n_water;
|
vm->m_data[index_data] = n_water;
|
||||||
|
} else if (river) {
|
||||||
|
// river
|
||||||
|
vm->m_data[index_data] = n_river_water;
|
||||||
} else {
|
} else {
|
||||||
vm->m_data[index_data] = n_air;
|
vm->m_data[index_data] = n_air;
|
||||||
}
|
}
|
||||||
|
@ -609,18 +646,51 @@ int MapgenValleys::generateTerrain()
|
||||||
index_3d += ystride;
|
index_3d += ystride;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Although the original valleys adjusts humidity by distance
|
// This happens if we're generating a chunk that doesn't
|
||||||
// from seawater, this causes problems with the default biomes.
|
// contain the terrain surface, in which case, we need
|
||||||
// Adjust only by freshwater proximity.
|
// to set heightmap to a value outside of the chunk,
|
||||||
const float humidity_offset = 0.8f; // derived by testing
|
// to avoid confusing lua mods that use heightmap.
|
||||||
if (humid_rivers)
|
if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
|
||||||
noise_humidity->result[index_2d] *= (1 + pow(0.5f, MYMAX((surface_max_y
|
s16 surface_y_int = myround(surface_y);
|
||||||
- noise_rivers->result[index_2d]) / 3.f, 0.f))) * humidity_offset;
|
if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
|
||||||
|
// If surface_y is outside the chunk, it's good enough.
|
||||||
|
heightmap[index_2d] = surface_y_int;
|
||||||
|
} else {
|
||||||
|
// If the ground is outside of this chunk, but surface_y
|
||||||
|
// is within the chunk, give a value outside.
|
||||||
|
heightmap[index_2d] = node_min.Y - 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Assign the heat adjusted by altitude.
|
if (humid_rivers) {
|
||||||
if (use_altitude_chill && surface_max_y > 0)
|
// Use base ground (water table) in a riverbed, to
|
||||||
noise_heat->result[index_2d] *=
|
// avoid an unnatural rise in humidity.
|
||||||
pow(0.5f, (surface_max_y - altitude_chill / 3.f) / altitude_chill);
|
float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
|
||||||
|
float humid = noise_humidity->result[index_2d];
|
||||||
|
float water_depth = (t_alt - river_y) / humidity_dropoff;
|
||||||
|
humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f));
|
||||||
|
|
||||||
|
// Reduce humidity with altitude (ignoring riverbeds).
|
||||||
|
// This is similar to the lua version's seawater adjustment,
|
||||||
|
// but doesn't increase the base humidity, which causes
|
||||||
|
// problems with the default biomes.
|
||||||
|
if (t_alt > 0.f)
|
||||||
|
humid -= alt_to_humid * t_alt / altitude_chill;
|
||||||
|
|
||||||
|
noise_humidity->result[index_2d] = humid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign the heat adjusted by any changed altitudes.
|
||||||
|
// The altitude will change about half the time.
|
||||||
|
if (use_altitude_chill) {
|
||||||
|
// ground height ignoring riverbeds
|
||||||
|
float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
|
||||||
|
if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
|
||||||
|
// The altitude hasn't changed. Use the first result.
|
||||||
|
noise_heat->result[index_2d] = t_heat;
|
||||||
|
else if (t_alt > 0.f)
|
||||||
|
noise_heat->result[index_2d] -= alt_to_heat * t_alt / altitude_chill;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return surface_max_y;
|
return surface_max_y;
|
||||||
|
@ -645,7 +715,7 @@ MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
|
||||||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
// generated mapchunk or if not, a node of overgenerated base terrain.
|
||||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
content_t c_above = vm->m_data[vi + em.X].getContent();
|
||||||
bool air_above = c_above == CONTENT_AIR;
|
bool air_above = c_above == CONTENT_AIR;
|
||||||
bool water_above = (c_above == c_water_source);
|
bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
|
||||||
|
|
||||||
// If there is air or water above enable top/filler placement, otherwise force
|
// If there is air or water above enable top/filler placement, otherwise force
|
||||||
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
// nplaced to stone level by setting a number exceeding any possible filler depth.
|
||||||
|
@ -714,7 +784,7 @@ MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
|
||||||
water_above = true;
|
water_above = true;
|
||||||
} else if (c == c_river_water_source) {
|
} else if (c == c_river_water_source) {
|
||||||
vm->m_data[vi] = MapNode(biome->c_river_water);
|
vm->m_data[vi] = MapNode(biome->c_river_water);
|
||||||
nplaced = U16_MAX; // Sand was already placed under rivers.
|
nplaced = depth_top; // Enable filler placement for next surface
|
||||||
air_above = false;
|
air_above = false;
|
||||||
water_above = true;
|
water_above = true;
|
||||||
} else if (c == CONTENT_AIR) {
|
} else if (c == CONTENT_AIR) {
|
||||||
|
|
|
@ -304,13 +304,16 @@ size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p)
|
||||||
s16 height = (deco_height_max > 0) ?
|
s16 height = (deco_height_max > 0) ?
|
||||||
pr->range(deco_height, deco_height_max) : deco_height;
|
pr->range(deco_height, deco_height_max) : deco_height;
|
||||||
|
|
||||||
|
bool force_placement = (flags & DECO_FORCE_PLACEMENT);
|
||||||
|
|
||||||
v3s16 em = vm->m_area.getExtent();
|
v3s16 em = vm->m_area.getExtent();
|
||||||
u32 vi = vm->m_area.index(p);
|
u32 vi = vm->m_area.index(p);
|
||||||
for (int i = 0; i < height; i++) {
|
for (int i = 0; i < height; i++) {
|
||||||
vm->m_area.add_y(em, vi, 1);
|
vm->m_area.add_y(em, vi, 1);
|
||||||
|
|
||||||
content_t c = vm->m_data[vi].getContent();
|
content_t c = vm->m_data[vi].getContent();
|
||||||
if (c != CONTENT_AIR && c != CONTENT_IGNORE)
|
if (c != CONTENT_AIR && c != CONTENT_IGNORE &&
|
||||||
|
!force_placement)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
vm->m_data[vi] = MapNode(c_place);
|
vm->m_data[vi] = MapNode(c_place);
|
||||||
|
|
|
@ -31,8 +31,8 @@ class IMenuManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// A GUIModalMenu calls these when this class is passed as a parameter
|
// A GUIModalMenu calls these when this class is passed as a parameter
|
||||||
virtual void createdMenu(GUIModalMenu *menu) = 0;
|
virtual void createdMenu(gui::IGUIElement *menu) = 0;
|
||||||
virtual void deletingMenu(GUIModalMenu *menu) = 0;
|
virtual void deletingMenu(gui::IGUIElement *menu) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -853,7 +853,7 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
|
||||||
assert(f->liquid_type == LIQUID_SOURCE);
|
assert(f->liquid_type == LIQUID_SOURCE);
|
||||||
if (opaque_water)
|
if (opaque_water)
|
||||||
f->alpha = 255;
|
f->alpha = 255;
|
||||||
f->solidness = 0;
|
f->solidness = 1;
|
||||||
is_liquid = true;
|
is_liquid = true;
|
||||||
break;
|
break;
|
||||||
case NDT_FLOWINGLIQUID:
|
case NDT_FLOWINGLIQUID:
|
||||||
|
|
|
@ -116,7 +116,6 @@ void ScriptApiSecurity::initializeSecurity()
|
||||||
"upvaluejoin",
|
"upvaluejoin",
|
||||||
"sethook",
|
"sethook",
|
||||||
"debug",
|
"debug",
|
||||||
"getupvalue",
|
|
||||||
"setlocal",
|
"setlocal",
|
||||||
};
|
};
|
||||||
static const char *package_whitelist[] = {
|
static const char *package_whitelist[] = {
|
||||||
|
|
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "lua_api/l_http.h"
|
#include "lua_api/l_http.h"
|
||||||
#include "httpfetch.h"
|
#include "httpfetch.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -130,11 +131,27 @@ int ModApiHttp::l_request_http_api(lua_State *L)
|
||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
|
// We have to make sure that this function is being called directly by
|
||||||
|
// a mod, otherwise a malicious mod could override this function and
|
||||||
|
// steal its return value.
|
||||||
|
lua_Debug info;
|
||||||
|
|
||||||
|
// Make sure there's only one item below this function on the stack...
|
||||||
|
if (lua_getstack(L, 2, &info)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
|
||||||
|
FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
|
||||||
|
|
||||||
|
// ...and that that item is the main file scope.
|
||||||
|
if (strcmp(info.what, "main") != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Mod must be listed in secure.http_mods or secure.trusted_mods
|
// Mod must be listed in secure.http_mods or secure.trusted_mods
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
|
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
|
||||||
if (!lua_isstring(L, -1)) {
|
if (!lua_isstring(L, -1)) {
|
||||||
lua_pushnil(L);
|
return 0;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mod_name = lua_tostring(L, -1);
|
const char *mod_name = lua_tostring(L, -1);
|
||||||
|
|
|
@ -75,9 +75,10 @@ int ModApiUtil::l_get_us_time(lua_State *L)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_SECURE_SETTING(L, name) \
|
#define CHECK_SECURE_SETTING(L, name) \
|
||||||
if (name.compare(0, 7, "secure.") == 0) {\
|
if (ScriptApiSecurity::isSecure(L) && \
|
||||||
lua_pushliteral(L, "Attempt to set secure setting.");\
|
name.compare(0, 7, "secure.") == 0) { \
|
||||||
lua_error(L);\
|
lua_pushliteral(L, "Attempt to set secure setting."); \
|
||||||
|
lua_error(L); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// setting_set(name, value)
|
// setting_set(name, value)
|
||||||
|
|
|
@ -146,6 +146,7 @@ void TerminalChatConsole::typeChatMessage(const std::wstring &msg)
|
||||||
|
|
||||||
void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
{
|
{
|
||||||
|
ChatPrompt &prompt = m_chat_backend.getPrompt();
|
||||||
// Helpful if you want to collect key codes that aren't documented
|
// Helpful if you want to collect key codes that aren't documented
|
||||||
/*if (ch != ERR) {
|
/*if (ch != ERR) {
|
||||||
m_chat_backend.addMessage(L"",
|
m_chat_backend.addMessage(L"",
|
||||||
|
@ -177,20 +178,20 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case KEY_ENTER:
|
case KEY_ENTER:
|
||||||
case '\r':
|
case '\r':
|
||||||
case '\n': {
|
case '\n': {
|
||||||
std::wstring text = m_chat_backend.getPrompt().submit();
|
prompt.addToHistory(prompt.getLine());
|
||||||
typeChatMessage(text);
|
typeChatMessage(prompt.replace(L""));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KEY_UP:
|
case KEY_UP:
|
||||||
m_chat_backend.getPrompt().historyPrev();
|
prompt.historyPrev();
|
||||||
break;
|
break;
|
||||||
case KEY_DOWN:
|
case KEY_DOWN:
|
||||||
m_chat_backend.getPrompt().historyNext();
|
prompt.historyNext();
|
||||||
break;
|
break;
|
||||||
case KEY_LEFT:
|
case KEY_LEFT:
|
||||||
// Left pressed
|
// Left pressed
|
||||||
// move character to the left
|
// move character to the left
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
||||||
|
@ -198,7 +199,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case 545:
|
case 545:
|
||||||
// Ctrl-Left pressed
|
// Ctrl-Left pressed
|
||||||
// move word to the left
|
// move word to the left
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_WORD);
|
ChatPrompt::CURSOROP_SCOPE_WORD);
|
||||||
|
@ -206,7 +207,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case KEY_RIGHT:
|
case KEY_RIGHT:
|
||||||
// Right pressed
|
// Right pressed
|
||||||
// move character to the right
|
// move character to the right
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
||||||
|
@ -214,7 +215,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case 560:
|
case 560:
|
||||||
// Ctrl-Right pressed
|
// Ctrl-Right pressed
|
||||||
// move word to the right
|
// move word to the right
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_WORD);
|
ChatPrompt::CURSOROP_SCOPE_WORD);
|
||||||
|
@ -222,7 +223,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case KEY_HOME:
|
case KEY_HOME:
|
||||||
// Home pressed
|
// Home pressed
|
||||||
// move to beginning of line
|
// move to beginning of line
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
@ -230,7 +231,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case KEY_END:
|
case KEY_END:
|
||||||
// End pressed
|
// End pressed
|
||||||
// move to end of line
|
// move to end of line
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_MOVE,
|
ChatPrompt::CURSOROP_MOVE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
@ -240,7 +241,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case 127:
|
case 127:
|
||||||
// Backspace pressed
|
// Backspace pressed
|
||||||
// delete character to the left
|
// delete character to the left
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_DELETE,
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
||||||
|
@ -248,7 +249,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case KEY_DC:
|
case KEY_DC:
|
||||||
// Delete pressed
|
// Delete pressed
|
||||||
// delete character to the right
|
// delete character to the right
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_DELETE,
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
||||||
|
@ -256,7 +257,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case 519:
|
case 519:
|
||||||
// Ctrl-Delete pressed
|
// Ctrl-Delete pressed
|
||||||
// delete word to the right
|
// delete word to the right
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_DELETE,
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_WORD);
|
ChatPrompt::CURSOROP_SCOPE_WORD);
|
||||||
|
@ -264,7 +265,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case 21:
|
case 21:
|
||||||
// Ctrl-U pressed
|
// Ctrl-U pressed
|
||||||
// kill line to left end
|
// kill line to left end
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_DELETE,
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
@ -272,7 +273,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case 11:
|
case 11:
|
||||||
// Ctrl-K pressed
|
// Ctrl-K pressed
|
||||||
// kill line to right end
|
// kill line to right end
|
||||||
m_chat_backend.getPrompt().cursorOperation(
|
prompt.cursorOperation(
|
||||||
ChatPrompt::CURSOROP_DELETE,
|
ChatPrompt::CURSOROP_DELETE,
|
||||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||||
|
@ -280,7 +281,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
case KEY_TAB:
|
case KEY_TAB:
|
||||||
// Tab pressed
|
// Tab pressed
|
||||||
// Nick completion
|
// Nick completion
|
||||||
m_chat_backend.getPrompt().nickCompletion(m_nicks, false);
|
prompt.nickCompletion(m_nicks, false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Add character to the prompt,
|
// Add character to the prompt,
|
||||||
|
@ -296,11 +297,11 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
||||||
m_pending_utf8_bytes = "";
|
m_pending_utf8_bytes = "";
|
||||||
// hopefully only one char in the wstring...
|
// hopefully only one char in the wstring...
|
||||||
for (size_t i = 0; i < w.size(); i++) {
|
for (size_t i = 0; i < w.size(); i++) {
|
||||||
m_chat_backend.getPrompt().input(w.c_str()[i]);
|
prompt.input(w.c_str()[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (IS_ASCII_PRINTABLE_CHAR(ch)) {
|
} else if (IS_ASCII_PRINTABLE_CHAR(ch)) {
|
||||||
m_chat_backend.getPrompt().input(ch);
|
prompt.input(ch);
|
||||||
} else {
|
} else {
|
||||||
// Silently ignore characters we don't handle
|
// Silently ignore characters we don't handle
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue