Merge
This commit is contained in:
commit
3505f8982f
|
@ -2337,7 +2337,7 @@ These functions return the leftover itemstack.
|
|||
otherwise returns `nil`.
|
||||
* The returned table contains the functions `fetch`, `fetch_async` and `fetch_async_get`
|
||||
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.
|
||||
* **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN
|
||||
A LOCAL VARIABLE!**
|
||||
|
@ -3698,11 +3698,12 @@ Definition tables
|
|||
-- ^ Minimum and maximum `y` positions these decorations can be generated at.
|
||||
-- ^ This parameter refers to the `y` position of the decoration base, so
|
||||
-- the actual maximum height would be `height_max + size.Y`.
|
||||
flags = "liquid_surface",
|
||||
flags = "liquid_surface, force_placement",
|
||||
-- ^ Flags for all decoration types.
|
||||
-- ^ "liquid_surface": Instead of placement on the highest solid surface
|
||||
-- ^ in a mapchunk column, placement is on the highest 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
|
||||
decoration = "default:grass",
|
||||
|
@ -3746,7 +3747,7 @@ Definition tables
|
|||
},
|
||||
-- ^ See 'Schematic specifier' for details.
|
||||
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'.
|
||||
rotation = "90" -- rotate schematic 90 degrees on placement
|
||||
-- ^ Rotation can be "0", "90", "180", "270", or "random".
|
||||
|
|
72
src/chat.cpp
72
src/chat.cpp
|
@ -390,6 +390,7 @@ ChatPrompt::ChatPrompt(std::wstring prompt, u32 history_limit):
|
|||
m_cols(0),
|
||||
m_view(0),
|
||||
m_cursor(0),
|
||||
m_cursor_len(0),
|
||||
m_nick_completion_start(0),
|
||||
m_nick_completion_end(0)
|
||||
{
|
||||
|
@ -417,20 +418,13 @@ void ChatPrompt::input(const std::wstring &str)
|
|||
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())
|
||||
m_history.push_back(line);
|
||||
if (m_history.size() > m_history_limit)
|
||||
m_history.erase(m_history.begin());
|
||||
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()
|
||||
|
@ -442,13 +436,15 @@ void ChatPrompt::clear()
|
|||
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_view = m_cursor = line.size();
|
||||
clampView();
|
||||
m_nick_completion_start = 0;
|
||||
m_nick_completion_end = 0;
|
||||
return old_line;
|
||||
}
|
||||
|
||||
void ChatPrompt::historyPrev()
|
||||
|
@ -590,14 +586,12 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
|
|||
s32 length = m_line.size();
|
||||
s32 increment = (dir == CURSOROP_DIR_RIGHT) ? 1 : -1;
|
||||
|
||||
if (scope == CURSOROP_SCOPE_CHARACTER)
|
||||
{
|
||||
switch (scope) {
|
||||
case CURSOROP_SCOPE_CHARACTER:
|
||||
new_cursor += increment;
|
||||
}
|
||||
else if (scope == CURSOROP_SCOPE_WORD)
|
||||
{
|
||||
if (increment > 0)
|
||||
{
|
||||
break;
|
||||
case CURSOROP_SCOPE_WORD:
|
||||
if (dir == CURSOROP_DIR_RIGHT) {
|
||||
// skip one word to the right
|
||||
while (new_cursor < length && isspace(m_line[new_cursor]))
|
||||
new_cursor++;
|
||||
|
@ -605,39 +599,47 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
|
|||
new_cursor++;
|
||||
while (new_cursor < length && isspace(m_line[new_cursor]))
|
||||
new_cursor++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// skip one word to the left
|
||||
while (new_cursor >= 1 && isspace(m_line[new_cursor - 1]))
|
||||
new_cursor--;
|
||||
while (new_cursor >= 1 && !isspace(m_line[new_cursor - 1]))
|
||||
new_cursor--;
|
||||
}
|
||||
}
|
||||
else if (scope == CURSOROP_SCOPE_LINE)
|
||||
{
|
||||
break;
|
||||
case CURSOROP_SCOPE_LINE:
|
||||
new_cursor += increment * length;
|
||||
break;
|
||||
case CURSOROP_SCOPE_SELECTION:
|
||||
break;
|
||||
}
|
||||
|
||||
new_cursor = MYMAX(MYMIN(new_cursor, length), 0);
|
||||
|
||||
if (op == CURSOROP_MOVE)
|
||||
{
|
||||
switch (op) {
|
||||
case CURSOROP_MOVE:
|
||||
m_cursor = new_cursor;
|
||||
m_cursor_len = 0;
|
||||
break;
|
||||
case CURSOROP_DELETE:
|
||||
if (m_cursor_len > 0) { // Delete selected text first
|
||||
m_line.erase(m_cursor, m_cursor_len);
|
||||
} else {
|
||||
m_cursor = MYMIN(new_cursor, old_cursor);
|
||||
m_line.erase(m_cursor, abs(new_cursor - old_cursor));
|
||||
}
|
||||
else if (op == CURSOROP_DELETE)
|
||||
{
|
||||
if (new_cursor < old_cursor)
|
||||
{
|
||||
m_line.erase(new_cursor, old_cursor - new_cursor);
|
||||
m_cursor = new_cursor;
|
||||
}
|
||||
else if (new_cursor > old_cursor)
|
||||
{
|
||||
m_line.erase(old_cursor, new_cursor - old_cursor);
|
||||
m_cursor = old_cursor;
|
||||
m_cursor_len = 0;
|
||||
break;
|
||||
case CURSOROP_SELECT:
|
||||
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();
|
||||
|
|
21
src/chat.h
21
src/chat.h
|
@ -146,14 +146,21 @@ public:
|
|||
void input(wchar_t ch);
|
||||
void input(const std::wstring &str);
|
||||
|
||||
// Submit, clear and return current line
|
||||
std::wstring submit();
|
||||
// Add a string to the history
|
||||
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
|
||||
void clear();
|
||||
|
||||
// Replace the current line with the given text
|
||||
void replace(std::wstring line);
|
||||
std::wstring replace(std::wstring line);
|
||||
|
||||
// Select previous command from history
|
||||
void historyPrev();
|
||||
|
@ -169,10 +176,13 @@ public:
|
|||
std::wstring getVisiblePortion() const;
|
||||
// Get cursor position (relative to visible portion). -1 if invalid
|
||||
s32 getVisibleCursorPosition() const;
|
||||
// Get length of cursor selection
|
||||
s32 getCursorLength() const { return m_cursor_len; }
|
||||
|
||||
// Cursor operations
|
||||
enum CursorOp {
|
||||
CURSOROP_MOVE,
|
||||
CURSOROP_SELECT,
|
||||
CURSOROP_DELETE
|
||||
};
|
||||
|
||||
|
@ -186,7 +196,8 @@ public:
|
|||
enum CursorOpScope {
|
||||
CURSOROP_SCOPE_CHARACTER,
|
||||
CURSOROP_SCOPE_WORD,
|
||||
CURSOROP_SCOPE_LINE
|
||||
CURSOROP_SCOPE_LINE,
|
||||
CURSOROP_SCOPE_SELECTION
|
||||
};
|
||||
|
||||
// Cursor operation
|
||||
|
@ -224,6 +235,8 @@ private:
|
|||
s32 m_view;
|
||||
// Cursor (index into m_line)
|
||||
s32 m_cursor;
|
||||
// Cursor length (length of selected portion of line)
|
||||
s32 m_cursor_len;
|
||||
|
||||
// Last nick completion start (index into m_line)
|
||||
s32 m_nick_completion_start;
|
||||
|
|
|
@ -248,9 +248,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
|||
|
||||
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 y = min_y; y <= max_y; y++)
|
||||
for(s16 z = min_z; z <= max_z; z++)
|
||||
{
|
||||
v3s16 p(x,y,z);
|
||||
|
@ -404,17 +403,15 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
|||
Go through every nodebox, find nearest collision
|
||||
*/
|
||||
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)
|
||||
f32 dtime_tmp;
|
||||
int collided = axisAlignedCollision(
|
||||
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)
|
||||
continue;
|
||||
|
||||
|
@ -464,12 +461,10 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
|||
is_collision = false;
|
||||
|
||||
CollisionInfo info;
|
||||
if (is_object[nearest_boxindex]) {
|
||||
if (is_object[nearest_boxindex])
|
||||
info.type = COLLISION_OBJECT;
|
||||
result.standing_on_object = true;
|
||||
} else {
|
||||
else
|
||||
info.type = COLLISION_NODE;
|
||||
}
|
||||
|
||||
info.node_p = node_positions[nearest_boxindex];
|
||||
info.bouncy = bouncy;
|
||||
|
@ -487,13 +482,12 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
|||
speed_f->X = 0;
|
||||
result.collides = true;
|
||||
result.collides_xz = true;
|
||||
} else if(nearest_collided == 1) { // Y
|
||||
if (fabs(speed_f->Y) > BS * 3) {
|
||||
speed_f->Y *= bounce;
|
||||
} else {
|
||||
speed_f->Y = 0;
|
||||
result.touching_ground = true;
|
||||
}
|
||||
else if(nearest_collided == 1) { // Y
|
||||
if (fabs(speed_f->Y) > BS * 3)
|
||||
speed_f->Y *= bounce;
|
||||
else
|
||||
speed_f->Y = 0;
|
||||
result.collides = true;
|
||||
} else if(nearest_collided == 2) { // Z
|
||||
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;
|
||||
}
|
||||
|
|
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") {
|
||||
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
|
||||
#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,
|
||||
InventoryManager *invmgr, IGameDef *gamedef,
|
||||
IWritableTextureSource *tsrc, IrrlichtDevice *device, Client *client)
|
||||
|
@ -1518,7 +1484,7 @@ protected:
|
|||
|
||||
void dropSelectedItem();
|
||||
void openInventory();
|
||||
void openConsole();
|
||||
void openConsole(float height, const wchar_t *line=NULL);
|
||||
void toggleFreeMove(float *statustext_time);
|
||||
void toggleFreeMoveAlt(float *statustext_time, float *jump_timer);
|
||||
void toggleFast(float *statustext_time);
|
||||
|
@ -1578,6 +1544,10 @@ protected:
|
|||
static void settingChangedCallback(const std::string &setting_name, void *data);
|
||||
void readSettings();
|
||||
|
||||
#ifdef __ANDROID__
|
||||
void handleAndroidChatInput();
|
||||
#endif
|
||||
|
||||
private:
|
||||
InputHandler *input;
|
||||
|
||||
|
@ -1664,8 +1634,8 @@ private:
|
|||
|
||||
#ifdef __ANDROID__
|
||||
bool m_cache_hold_aux1;
|
||||
bool m_android_chat_open;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
Game::Game() :
|
||||
|
@ -2179,7 +2149,7 @@ bool Game::initGui()
|
|||
|
||||
// Chat backend and console
|
||||
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
|
||||
-1, chat_backend, client);
|
||||
-1, chat_backend, client, &g_menumgr);
|
||||
if (!gui_chat_console) {
|
||||
*error_message = "Could not allocate memory for chat console";
|
||||
errorstream << *error_message << std::endl;
|
||||
|
@ -2617,10 +2587,10 @@ void Game::processUserInput(VolatileRunFlags *flags,
|
|||
input->step(dtime);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
if (current_formspec != 0)
|
||||
if (current_formspec != NULL)
|
||||
current_formspec->getAndroidUIInput();
|
||||
|
||||
else
|
||||
handleAndroidChatInput();
|
||||
#endif
|
||||
|
||||
// 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])) {
|
||||
openInventory();
|
||||
} else if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) {
|
||||
show_pause_menu(¤t_formspec, client, gamedef, texture_src, device,
|
||||
simple_singleplayer_mode);
|
||||
if (!gui_chat_console->isOpenInhibited()) {
|
||||
show_pause_menu(¤t_formspec, client, gamedef,
|
||||
texture_src, device, simple_singleplayer_mode);
|
||||
}
|
||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CHAT])) {
|
||||
show_chat_menu(¤t_formspec, client, gamedef, texture_src, device,
|
||||
client, "");
|
||||
openConsole(0.2, L"");
|
||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CMD])) {
|
||||
show_chat_menu(¤t_formspec, client, gamedef, texture_src, device,
|
||||
client, "/");
|
||||
openConsole(0.2, L"/");
|
||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CONSOLE])) {
|
||||
openConsole();
|
||||
openConsole(1);
|
||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FREEMOVE])) {
|
||||
toggleFreeMove(statustext_time);
|
||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP])) {
|
||||
|
@ -2700,15 +2670,15 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
|
|||
decreaseViewRange(statustext_time);
|
||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_RANGESELECT])) {
|
||||
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();
|
||||
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_PREV]))
|
||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_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();
|
||||
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_DEC]))
|
||||
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_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
|
||||
dstream << "-----------------------------------------"
|
||||
<< 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()) {
|
||||
// Open up to over half of the screen
|
||||
gui_chat_console->openConsole(0.6);
|
||||
guienv->setFocus(gui_chat_console);
|
||||
#ifdef __ANDROID__
|
||||
porting::showInputDialog(gettext("ok"), "", "", 2);
|
||||
m_android_chat_open = true;
|
||||
#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)
|
||||
|
|
|
@ -46,15 +46,18 @@ GUIChatConsole::GUIChatConsole(
|
|||
gui::IGUIElement* parent,
|
||||
s32 id,
|
||||
ChatBackend* backend,
|
||||
Client* client
|
||||
Client* client,
|
||||
IMenuManager* menumgr
|
||||
):
|
||||
IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
|
||||
core::rect<s32>(0,0,100,100)),
|
||||
m_chat_backend(backend),
|
||||
m_client(client),
|
||||
m_menumgr(menumgr),
|
||||
m_screensize(v2u32(0,0)),
|
||||
m_animate_time_old(0),
|
||||
m_open(false),
|
||||
m_close_on_enter(false),
|
||||
m_height(0),
|
||||
m_desired_height(0),
|
||||
m_desired_height_fraction(0.0),
|
||||
|
@ -119,6 +122,8 @@ void GUIChatConsole::openConsole(f32 height)
|
|||
m_desired_height_fraction = height;
|
||||
m_desired_height = height * m_screensize.Y;
|
||||
reformatConsole();
|
||||
Environment->setFocus(this);
|
||||
m_menumgr->createdMenu(this);
|
||||
}
|
||||
|
||||
bool GUIChatConsole::isOpen() const
|
||||
|
@ -134,11 +139,13 @@ bool GUIChatConsole::isOpenInhibited() const
|
|||
void GUIChatConsole::closeConsole()
|
||||
{
|
||||
m_open = false;
|
||||
Environment->removeFocus(this);
|
||||
m_menumgr->deletingMenu(this);
|
||||
}
|
||||
|
||||
void GUIChatConsole::closeConsoleAtOnce()
|
||||
{
|
||||
m_open = false;
|
||||
closeConsole();
|
||||
m_height = 0;
|
||||
recalculateConsolePosition();
|
||||
}
|
||||
|
@ -148,6 +155,14 @@ f32 GUIChatConsole::getDesiredHeight() const
|
|||
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(
|
||||
bool visible, bool blinking, f32 blink_speed, f32 relative_height)
|
||||
{
|
||||
|
@ -362,13 +377,15 @@ void GUIChatConsole::drawPrompt()
|
|||
s32 cursor_pos = prompt.getVisibleCursorPosition();
|
||||
if (cursor_pos >= 0)
|
||||
{
|
||||
s32 cursor_len = prompt.getCursorLength();
|
||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||
s32 x = (1 + cursor_pos) * m_fontsize.X;
|
||||
core::rect<s32> destrect(
|
||||
x,
|
||||
y + (1.0-m_cursor_height) * m_fontsize.Y,
|
||||
x + m_fontsize.X,
|
||||
y + m_fontsize.Y);
|
||||
y + m_fontsize.Y * (1.0 - m_cursor_height),
|
||||
x + m_fontsize.X * MYMAX(cursor_len, 1),
|
||||
y + m_fontsize.Y * (cursor_len ? m_cursor_height+1 : 1)
|
||||
);
|
||||
video::SColor cursor_color(255,255,255,255);
|
||||
driver->draw2DRectangle(
|
||||
cursor_color,
|
||||
|
@ -381,23 +398,27 @@ void GUIChatConsole::drawPrompt()
|
|||
|
||||
bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||
{
|
||||
|
||||
ChatPrompt &prompt = m_chat_backend->getPrompt();
|
||||
|
||||
if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
|
||||
{
|
||||
// Key input
|
||||
if(KeyPress(event.KeyInput) == getKeySetting("keymap_console"))
|
||||
{
|
||||
closeConsole();
|
||||
Environment->removeFocus(this);
|
||||
|
||||
// inhibit open so the_game doesn't reopen immediately
|
||||
m_open_inhibited = 50;
|
||||
m_close_on_enter = false;
|
||||
return true;
|
||||
}
|
||||
else if(event.KeyInput.Key == KEY_ESCAPE)
|
||||
{
|
||||
closeConsoleAtOnce();
|
||||
Environment->removeFocus(this);
|
||||
// the_game will open the pause menu
|
||||
m_close_on_enter = false;
|
||||
// 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;
|
||||
}
|
||||
else if(event.KeyInput.Key == KEY_PRIOR)
|
||||
|
@ -412,57 +433,50 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
}
|
||||
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);
|
||||
if (m_close_on_enter) {
|
||||
closeConsoleAtOnce();
|
||||
m_close_on_enter = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if(event.KeyInput.Key == KEY_UP)
|
||||
{
|
||||
// Up pressed
|
||||
// Move back in history
|
||||
m_chat_backend->getPrompt().historyPrev();
|
||||
prompt.historyPrev();
|
||||
return true;
|
||||
}
|
||||
else if(event.KeyInput.Key == KEY_DOWN)
|
||||
{
|
||||
// Down pressed
|
||||
// Move forward in history
|
||||
m_chat_backend->getPrompt().historyNext();
|
||||
prompt.historyNext();
|
||||
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
|
||||
// move character / word to the left
|
||||
ChatPrompt::CursorOpScope scope =
|
||||
event.KeyInput.Control ?
|
||||
// Left/right pressed
|
||||
// Move/select character/word to the left depending on control and shift keys
|
||||
ChatPrompt::CursorOp op = event.KeyInput.Shift ?
|
||||
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_CHARACTER;
|
||||
m_chat_backend->getPrompt().cursorOperation(
|
||||
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);
|
||||
prompt.cursorOperation(op, dir, scope);
|
||||
return true;
|
||||
}
|
||||
else if(event.KeyInput.Key == KEY_HOME)
|
||||
{
|
||||
// Home pressed
|
||||
// move to beginning of line
|
||||
m_chat_backend->getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_MOVE,
|
||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||
|
@ -472,7 +486,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
{
|
||||
// End pressed
|
||||
// move to end of line
|
||||
m_chat_backend->getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_MOVE,
|
||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||
|
@ -486,7 +500,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
event.KeyInput.Control ?
|
||||
ChatPrompt::CURSOROP_SCOPE_WORD :
|
||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
||||
m_chat_backend->getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_DELETE,
|
||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||
scope);
|
||||
|
@ -500,30 +514,72 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
event.KeyInput.Control ?
|
||||
ChatPrompt::CURSOROP_SCOPE_WORD :
|
||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
|
||||
m_chat_backend->getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_DELETE,
|
||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||
scope);
|
||||
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)
|
||||
{
|
||||
// Ctrl-V pressed
|
||||
// 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();
|
||||
const c8 *text = os_operator->getTextFromClipboard();
|
||||
if (text)
|
||||
{
|
||||
std::wstring wtext = narrow_to_wide(text);
|
||||
m_chat_backend->getPrompt().input(wtext);
|
||||
if (!text)
|
||||
return true;
|
||||
std::basic_string<unsigned char> str((const unsigned char*)text);
|
||||
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;
|
||||
}
|
||||
else if(event.KeyInput.Key == KEY_KEY_U && event.KeyInput.Control)
|
||||
{
|
||||
// Ctrl-U pressed
|
||||
// kill line to left end
|
||||
m_chat_backend->getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_DELETE,
|
||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||
|
@ -533,7 +589,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
{
|
||||
// Ctrl-K pressed
|
||||
// kill line to right end
|
||||
m_chat_backend->getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_DELETE,
|
||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||
|
@ -545,7 +601,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
// Nick completion
|
||||
std::list<std::string> names = m_client->getConnectedPlayerNames();
|
||||
bool backwards = event.KeyInput.Shift;
|
||||
m_chat_backend->getPrompt().nickCompletion(names, backwards);
|
||||
prompt.nickCompletion(names, backwards);
|
||||
return true;
|
||||
}
|
||||
else if(event.KeyInput.Char != 0 && !event.KeyInput.Control)
|
||||
|
@ -553,9 +609,9 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
#if (defined(linux) || defined(__linux))
|
||||
wchar_t wc = L'_';
|
||||
mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
|
||||
m_chat_backend->getPrompt().input(wc);
|
||||
prompt.input(wc);
|
||||
#else
|
||||
m_chat_backend->getPrompt().input(event.KeyInput.Char);
|
||||
prompt.input(event.KeyInput.Char);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#define GUICHATCONSOLE_HEADER
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "modalMenu.h"
|
||||
#include "chat.h"
|
||||
#include "config.h"
|
||||
|
||||
|
@ -33,7 +34,8 @@ public:
|
|||
gui::IGUIElement* parent,
|
||||
s32 id,
|
||||
ChatBackend* backend,
|
||||
Client* client);
|
||||
Client* client,
|
||||
IMenuManager* menumgr);
|
||||
virtual ~GUIChatConsole();
|
||||
|
||||
// Open the console (height = desired fraction of screen size)
|
||||
|
@ -51,11 +53,16 @@ public:
|
|||
void closeConsole();
|
||||
// Close the console immediately, without animation.
|
||||
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)
|
||||
// Zero if the console is closed or getting closed
|
||||
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
|
||||
void setCursor(
|
||||
bool visible,
|
||||
|
@ -81,11 +88,9 @@ private:
|
|||
void drawPrompt();
|
||||
|
||||
private:
|
||||
// pointer to the chat backend
|
||||
ChatBackend* m_chat_backend;
|
||||
|
||||
// pointer to the client
|
||||
Client* m_client;
|
||||
IMenuManager* m_menumgr;
|
||||
|
||||
// current screen size
|
||||
v2u32 m_screensize;
|
||||
|
@ -95,6 +100,8 @@ private:
|
|||
|
||||
// should the console be opened or closed?
|
||||
bool m_open;
|
||||
// should it close after you press enter?
|
||||
bool m_close_on_enter;
|
||||
// current console height [pixels]
|
||||
s32 m_height;
|
||||
// desired height [pixels]
|
||||
|
|
|
@ -47,9 +47,9 @@ extern gui::IGUIStaticText *guiroot;
|
|||
class MainMenuManager : public IMenuManager
|
||||
{
|
||||
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.end(); ++i)
|
||||
{
|
||||
|
@ -61,13 +61,13 @@ public:
|
|||
m_stack.push_back(menu);
|
||||
}
|
||||
|
||||
virtual void deletingMenu(GUIModalMenu *menu)
|
||||
virtual void deletingMenu(gui::IGUIElement *menu)
|
||||
{
|
||||
// Remove all entries if there are duplicates
|
||||
bool removed_entry;
|
||||
do{
|
||||
removed_entry = false;
|
||||
for(std::list<GUIModalMenu*>::iterator
|
||||
for(std::list<gui::IGUIElement*>::iterator
|
||||
i = m_stack.begin();
|
||||
i != m_stack.end(); ++i)
|
||||
{
|
||||
|
@ -91,10 +91,10 @@ public:
|
|||
// Returns true to prevent further processing
|
||||
virtual bool preprocessEvent(const SEvent& event)
|
||||
{
|
||||
if(!m_stack.empty())
|
||||
return m_stack.back()->preprocessEvent(event);
|
||||
else
|
||||
if (m_stack.empty())
|
||||
return false;
|
||||
GUIModalMenu *mm = dynamic_cast<GUIModalMenu*>(m_stack.back());
|
||||
return mm && mm->preprocessEvent(event);
|
||||
}
|
||||
|
||||
u32 menuCount()
|
||||
|
@ -104,16 +104,17 @@ public:
|
|||
|
||||
bool pausesGame()
|
||||
{
|
||||
for(std::list<GUIModalMenu*>::iterator
|
||||
for(std::list<gui::IGUIElement*>::iterator
|
||||
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 false;
|
||||
}
|
||||
|
||||
std::list<GUIModalMenu*> m_stack;
|
||||
std::list<gui::IGUIElement*> m_stack;
|
||||
};
|
||||
|
||||
extern MainMenuManager g_menumgr;
|
||||
|
|
|
@ -399,8 +399,21 @@ void MapgenValleys::calculateNoise()
|
|||
|
||||
//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++) {
|
||||
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];
|
||||
}
|
||||
|
||||
|
@ -481,9 +494,10 @@ float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
|
|||
}
|
||||
|
||||
// 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.
|
||||
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.
|
||||
*tn->slope = 0.f;
|
||||
|
@ -503,7 +517,7 @@ float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
|
|||
for (s16 y = y_start; y <= y_start + 1000; y++) {
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
@ -522,7 +536,7 @@ int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
|
|||
|
||||
s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
|
||||
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
|
||||
else
|
||||
return level_at_point;
|
||||
|
@ -552,6 +566,15 @@ float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
|
|||
|
||||
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_river_water(c_river_water_source);
|
||||
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 x = node_min.X; x <= node_max.X; x++, index_2d++) {
|
||||
s16 river_y = floor(noise_rivers->result[index_2d]);
|
||||
s16 surface_y = floor(noise_terrain_height->result[index_2d]);
|
||||
float river_y = noise_rivers->result[index_2d];
|
||||
float surface_y = noise_terrain_height->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)
|
||||
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_data = vm->m_area.index(x, node_min.Y - 1, z);
|
||||
|
||||
// Mapgens concern themselves with stone and water.
|
||||
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) {
|
||||
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
|
||||
vm->m_data[index_data] = n_sand;
|
||||
} else if (river && y <= surface_y) {
|
||||
} else if (slope * fill > surface_delta) {
|
||||
// ground
|
||||
vm->m_data[index_data] = n_stone;
|
||||
} else if (river && y < river_y) {
|
||||
// river
|
||||
vm->m_data[index_data] = n_river_water;
|
||||
} else if ((!river) && myround(fill * slope) >= y - surface_y) {
|
||||
// ground
|
||||
vm->m_data[index_data] = n_stone;
|
||||
heightmap[index_2d] = surface_max_y = y;
|
||||
if (y > heightmap[index_2d])
|
||||
heightmap[index_2d] = y;
|
||||
if (y > surface_max_y)
|
||||
surface_max_y = y;
|
||||
} else if (y <= water_level) {
|
||||
// sea
|
||||
vm->m_data[index_data] = n_water;
|
||||
} else if (river) {
|
||||
// river
|
||||
vm->m_data[index_data] = n_river_water;
|
||||
} else {
|
||||
vm->m_data[index_data] = n_air;
|
||||
}
|
||||
|
@ -609,18 +646,51 @@ int MapgenValleys::generateTerrain()
|
|||
index_3d += ystride;
|
||||
}
|
||||
|
||||
// Although the original valleys adjusts humidity by distance
|
||||
// from seawater, this causes problems with the default biomes.
|
||||
// Adjust only by freshwater proximity.
|
||||
const float humidity_offset = 0.8f; // derived by testing
|
||||
if (humid_rivers)
|
||||
noise_humidity->result[index_2d] *= (1 + pow(0.5f, MYMAX((surface_max_y
|
||||
- noise_rivers->result[index_2d]) / 3.f, 0.f))) * humidity_offset;
|
||||
// This happens if we're generating a chunk that doesn't
|
||||
// contain the terrain surface, in which case, we need
|
||||
// to set heightmap to a value outside of the chunk,
|
||||
// to avoid confusing lua mods that use heightmap.
|
||||
if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
|
||||
s16 surface_y_int = myround(surface_y);
|
||||
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 (use_altitude_chill && surface_max_y > 0)
|
||||
noise_heat->result[index_2d] *=
|
||||
pow(0.5f, (surface_max_y - altitude_chill / 3.f) / altitude_chill);
|
||||
if (humid_rivers) {
|
||||
// Use base ground (water table) in a riverbed, to
|
||||
// avoid an unnatural rise in humidity.
|
||||
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;
|
||||
|
@ -645,7 +715,7 @@ MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
|
|||
// generated mapchunk or if not, a node of overgenerated base terrain.
|
||||
content_t c_above = vm->m_data[vi + em.X].getContent();
|
||||
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
|
||||
// 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;
|
||||
} else if (c == c_river_water_source) {
|
||||
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;
|
||||
water_above = true;
|
||||
} 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) ?
|
||||
pr->range(deco_height, deco_height_max) : deco_height;
|
||||
|
||||
bool force_placement = (flags & DECO_FORCE_PLACEMENT);
|
||||
|
||||
v3s16 em = vm->m_area.getExtent();
|
||||
u32 vi = vm->m_area.index(p);
|
||||
for (int i = 0; i < height; i++) {
|
||||
vm->m_area.add_y(em, vi, 1);
|
||||
|
||||
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;
|
||||
|
||||
vm->m_data[vi] = MapNode(c_place);
|
||||
|
|
|
@ -31,8 +31,8 @@ class IMenuManager
|
|||
{
|
||||
public:
|
||||
// A GUIModalMenu calls these when this class is passed as a parameter
|
||||
virtual void createdMenu(GUIModalMenu *menu) = 0;
|
||||
virtual void deletingMenu(GUIModalMenu *menu) = 0;
|
||||
virtual void createdMenu(gui::IGUIElement *menu) = 0;
|
||||
virtual void deletingMenu(gui::IGUIElement *menu) = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -853,7 +853,7 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
|
|||
assert(f->liquid_type == LIQUID_SOURCE);
|
||||
if (opaque_water)
|
||||
f->alpha = 255;
|
||||
f->solidness = 0;
|
||||
f->solidness = 1;
|
||||
is_liquid = true;
|
||||
break;
|
||||
case NDT_FLOWINGLIQUID:
|
||||
|
|
|
@ -116,7 +116,6 @@ void ScriptApiSecurity::initializeSecurity()
|
|||
"upvaluejoin",
|
||||
"sethook",
|
||||
"debug",
|
||||
"getupvalue",
|
||||
"setlocal",
|
||||
};
|
||||
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 "httpfetch.h"
|
||||
#include "settings.h"
|
||||
#include "debug.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -130,11 +131,27 @@ int ModApiHttp::l_request_http_api(lua_State *L)
|
|||
{
|
||||
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
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
|
||||
if (!lua_isstring(L, -1)) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) \
|
||||
if (name.compare(0, 7, "secure.") == 0) {\
|
||||
lua_pushliteral(L, "Attempt to set secure setting.");\
|
||||
lua_error(L);\
|
||||
if (ScriptApiSecurity::isSecure(L) && \
|
||||
name.compare(0, 7, "secure.") == 0) { \
|
||||
lua_pushliteral(L, "Attempt to set secure setting."); \
|
||||
lua_error(L); \
|
||||
}
|
||||
|
||||
// setting_set(name, value)
|
||||
|
|
|
@ -146,6 +146,7 @@ void TerminalChatConsole::typeChatMessage(const std::wstring &msg)
|
|||
|
||||
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
|
||||
/*if (ch != ERR) {
|
||||
m_chat_backend.addMessage(L"",
|
||||
|
@ -177,20 +178,20 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case KEY_ENTER:
|
||||
case '\r':
|
||||
case '\n': {
|
||||
std::wstring text = m_chat_backend.getPrompt().submit();
|
||||
typeChatMessage(text);
|
||||
prompt.addToHistory(prompt.getLine());
|
||||
typeChatMessage(prompt.replace(L""));
|
||||
break;
|
||||
}
|
||||
case KEY_UP:
|
||||
m_chat_backend.getPrompt().historyPrev();
|
||||
prompt.historyPrev();
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
m_chat_backend.getPrompt().historyNext();
|
||||
prompt.historyNext();
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
// Left pressed
|
||||
// move character to the left
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_MOVE,
|
||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
||||
|
@ -198,7 +199,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case 545:
|
||||
// Ctrl-Left pressed
|
||||
// move word to the left
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_MOVE,
|
||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||
ChatPrompt::CURSOROP_SCOPE_WORD);
|
||||
|
@ -206,7 +207,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case KEY_RIGHT:
|
||||
// Right pressed
|
||||
// move character to the right
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_MOVE,
|
||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
||||
|
@ -214,7 +215,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case 560:
|
||||
// Ctrl-Right pressed
|
||||
// move word to the right
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_MOVE,
|
||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||
ChatPrompt::CURSOROP_SCOPE_WORD);
|
||||
|
@ -222,7 +223,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case KEY_HOME:
|
||||
// Home pressed
|
||||
// move to beginning of line
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_MOVE,
|
||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||
|
@ -230,7 +231,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case KEY_END:
|
||||
// End pressed
|
||||
// move to end of line
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_MOVE,
|
||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||
|
@ -240,7 +241,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case 127:
|
||||
// Backspace pressed
|
||||
// delete character to the left
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_DELETE,
|
||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
||||
|
@ -248,7 +249,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case KEY_DC:
|
||||
// Delete pressed
|
||||
// delete character to the right
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_DELETE,
|
||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
|
||||
|
@ -256,7 +257,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case 519:
|
||||
// Ctrl-Delete pressed
|
||||
// delete word to the right
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_DELETE,
|
||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||
ChatPrompt::CURSOROP_SCOPE_WORD);
|
||||
|
@ -264,7 +265,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case 21:
|
||||
// Ctrl-U pressed
|
||||
// kill line to left end
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_DELETE,
|
||||
ChatPrompt::CURSOROP_DIR_LEFT,
|
||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||
|
@ -272,7 +273,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case 11:
|
||||
// Ctrl-K pressed
|
||||
// kill line to right end
|
||||
m_chat_backend.getPrompt().cursorOperation(
|
||||
prompt.cursorOperation(
|
||||
ChatPrompt::CURSOROP_DELETE,
|
||||
ChatPrompt::CURSOROP_DIR_RIGHT,
|
||||
ChatPrompt::CURSOROP_SCOPE_LINE);
|
||||
|
@ -280,7 +281,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
case KEY_TAB:
|
||||
// Tab pressed
|
||||
// Nick completion
|
||||
m_chat_backend.getPrompt().nickCompletion(m_nicks, false);
|
||||
prompt.nickCompletion(m_nicks, false);
|
||||
break;
|
||||
default:
|
||||
// Add character to the prompt,
|
||||
|
@ -296,11 +297,11 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
|
|||
m_pending_utf8_bytes = "";
|
||||
// hopefully only one char in the wstring...
|
||||
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)) {
|
||||
m_chat_backend.getPrompt().input(ch);
|
||||
prompt.input(ch);
|
||||
} else {
|
||||
// Silently ignore characters we don't handle
|
||||
|
||||
|
|
Loading…
Reference in New Issue