/*
-Minetest-c55
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
+#include <IMaterialRendererServices.h>
#include "client.h"
#include "server.h"
#include "guiPauseMenu.h"
#include "guiPasswordChange.h"
+#include "guiVolumeChange.h"
#include "guiFormSpecMenu.h"
#include "guiTextInputMenu.h"
#include "guiDeathScreen.h"
#include "guiChatConsole.h"
#include "config.h"
#include "clouds.h"
+#include "particles.h"
#include "camera.h"
#include "farmesh.h"
#include "mapblock.h"
#include "main.h" // For g_settings
#include "itemdef.h"
#include "tile.h" // For TextureSource
+#include "shader.h" // For ShaderSource
#include "logoutputbuffer.h"
#include "subgame.h"
#include "quicktune_shortcutter.h"
TextDestPlayerInventory(Client *client)
{
m_client = client;
+ m_formname = "";
+ }
+ TextDestPlayerInventory(Client *client, std::string formname)
+ {
+ m_client = client;
+ m_formname = formname;
}
void gotText(std::map<std::string, std::string> fields)
{
- m_client->sendInventoryFields("", fields);
+ m_client->sendInventoryFields(m_formname, fields);
}
Client *m_client;
+ std::string m_formname;
};
/* Respawn menu callback */
Client *m_client;
};
+class FormspecFormSource: public IFormSource
+{
+public:
+ FormspecFormSource(std::string formspec,FormspecFormSource** game_formspec)
+ {
+ m_formspec = formspec;
+ m_game_formspec = game_formspec;
+ }
+
+ ~FormspecFormSource()
+ {
+ *m_game_formspec = 0;
+ }
+
+ void setForm(std::string formspec) {
+ m_formspec = formspec;
+ }
+
+ std::string getForm()
+ {
+ return m_formspec;
+ }
+
+ std::string m_formspec;
+ FormspecFormSource** m_game_formspec;
+};
/*
Hotbar draw routine
*/
}
};
+class GameGlobalShaderConstantSetter : public IShaderConstantSetter
+{
+ Sky *m_sky;
+ bool *m_force_fog_off;
+ f32 *m_fog_range;
+ Client *m_client;
+
+public:
+ GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
+ f32 *fog_range, Client *client):
+ m_sky(sky),
+ m_force_fog_off(force_fog_off),
+ m_fog_range(fog_range),
+ m_client(client)
+ {}
+ ~GameGlobalShaderConstantSetter() {}
+
+ virtual void onSetConstants(video::IMaterialRendererServices *services,
+ bool is_highlevel)
+ {
+ if(!is_highlevel)
+ return;
+
+ // Background color
+ video::SColor bgcolor = m_sky->getBgColor();
+ video::SColorf bgcolorf(bgcolor);
+ float bgcolorfa[4] = {
+ bgcolorf.r,
+ bgcolorf.g,
+ bgcolorf.b,
+ bgcolorf.a,
+ };
+ services->setPixelShaderConstant("skyBgColor", bgcolorfa, 4);
+
+ // Fog distance
+ float fog_distance = *m_fog_range;
+ if(*m_force_fog_off)
+ fog_distance = 10000*BS;
+ services->setPixelShaderConstant("fogDistance", &fog_distance, 1);
+
+ // Day-night ratio
+ u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
+ float daynight_ratio_f = (float)daynight_ratio / 1000.0;
+ services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1);
+ }
+};
+
void the_game(
bool &kill,
bool random_input,
bool simple_singleplayer_mode
)
{
+ FormspecFormSource* current_formspec = 0;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
// Create texture source
IWritableTextureSource *tsrc = createTextureSource(device);
+ // Create shader source
+ IWritableShaderSource *shsrc = createShaderSource(device);
+
// These will be filled by data received from the server
// Create item definition manager
IWritableItemDefManager *itemdef = createItemDefManager();
MapDrawControl draw_control;
Client client(device, playername.c_str(), password, draw_control,
- tsrc, itemdef, nodedef, sound, &eventmgr);
+ tsrc, shsrc, itemdef, nodedef, sound, &eventmgr);
// Client acts as our GameDef
IGameDef *gamedef = &client;
// First line of debug text
gui::IGUIStaticText *guitext = guienv->addStaticText(
- L"Minetest-c55",
+ L"Minetest",
core::rect<s32>(5, 5, 795, 5+text_height),
false, false);
// Second line of debug text
gui::IGUIStaticText *guitext_info = guienv->addStaticText(
L"",
core::rect<s32>(0,0,400,text_height*5+5) + v2s32(100,200),
- false, false);
+ false, true);
// Status text (displays info when showing and hiding GUI stuff, etc.)
gui::IGUIStaticText *guitext_status = guienv->addStaticText(
bool digging = false;
bool ldown_for_dig = false;
- float damage_flash_timer = 0;
+ float damage_flash = 0;
s16 farmesh_range = 20*MAP_BLOCKSIZE;
+ float jump_timer = 0;
+ bool reset_jump_timer = false;
+
const float object_hit_delay = 0.2;
float object_hit_delay_timer = 0.0;
float time_from_last_punch = 10;
+ float update_draw_list_timer = 0.0;
+ v3f update_draw_list_last_cam_dir;
+
bool invert_mouse = g_settings->getBool("invert_mouse");
bool respawn_menu_active = false;
bool show_hud = true;
bool show_chat = true;
bool force_fog_off = false;
+ f32 fog_range = 100*BS;
bool disable_camera_update = false;
bool show_debug = g_settings->getBool("show_debug");
bool show_profiler_graph = false;
float time_of_day = 0;
float time_of_day_smooth = 0;
+ float repeat_rightclick_timer = 0;
+
+ /*
+ Shader constants
+ */
+ shsrc->addGlobalConstantSetter(new GameGlobalShaderConstantSetter(
+ sky, &force_fog_off, &fog_range, &client));
+
/*
Main loop
*/
// NOTE: So we have to use getTime() and call run()s between them
u32 lasttime = device->getTimer()->getTime();
+ LocalPlayer* player = client.getEnv().getLocalPlayer();
+ player->hurt_tilt_timer = 0;
+ player->hurt_tilt_strength = 0;
+
for(;;)
{
if(device->run() == false || kill == true)
g_gamecallback->changepassword_requested = false;
}
+ if(g_gamecallback->changevolume_requested)
+ {
+ (new GUIVolumeChange(guienv, guiroot, -1,
+ &g_menumgr, &client))->drop();
+ g_gamecallback->changevolume_requested = false;
+ }
+
+ /* Process TextureSource's queue */
+ tsrc->processQueue();
+
+ /* Process ItemDefManager's queue */
+ itemdef->processQueue(gamedef);
+
/*
- Process TextureSource's queue
+ Process ShaderSource's queue
*/
- tsrc->processQueue();
+ shsrc->processQueue();
/*
Random calculations
// Input handler step() (used by the random input generator)
input->step(dtime);
+ // Increase timer for doubleclick of "jump"
+ if(g_settings->getBool("doubletap_jump") && jump_timer <= 0.2)
+ jump_timer += dtime;
+
/*
Launch menus and trigger stuff according to keys
*/
<<"Launching inventory"<<std::endl;
GUIFormSpecMenu *menu =
- new GUIFormSpecMenu(guienv, guiroot, -1,
+ new GUIFormSpecMenu(device, guiroot, -1,
&g_menumgr,
&client, gamedef);
statustext += L" (note: no 'fly' privilege)";
}
}
+ else if(input->wasKeyDown(getKeySetting("keymap_jump")))
+ {
+ if(g_settings->getBool("doubletap_jump") && jump_timer < 0.2)
+ {
+ if(g_settings->getBool("free_move"))
+ {
+ g_settings->set("free_move","false");
+ statustext = L"free_move disabled";
+ statustext_time = 0;
+ }
+ else
+ {
+ g_settings->set("free_move","true");
+ statustext = L"free_move enabled";
+ statustext_time = 0;
+ if(!client.checkPrivilege("fly"))
+ statustext += L" (note: no 'fly' privilege)";
+ }
+ }
+ reset_jump_timer = true;
+ }
else if(input->wasKeyDown(getKeySetting("keymap_fastmove")))
{
if(g_settings->getBool("fast_move"))
statustext += L" (note: no 'fast' privilege)";
}
}
+ else if(input->wasKeyDown(getKeySetting("keymap_noclip")))
+ {
+ if(g_settings->getBool("noclip"))
+ {
+ g_settings->set("noclip","false");
+ statustext = L"noclip disabled";
+ statustext_time = 0;
+ }
+ else
+ {
+ g_settings->set("noclip","true");
+ statustext = L"noclip enabled";
+ statustext_time = 0;
+ if(!client.checkPrivilege("noclip"))
+ statustext += L" (note: no 'noclip' privilege)";
+ }
+ }
else if(input->wasKeyDown(getKeySetting("keymap_screenshot")))
{
irr::video::IImage* const image = driver->createScreenShot();
statustext_time = 0;
}
+ // Reset jump_timer
+ if(!input->isKeyDown(getKeySetting("keymap_jump")) && reset_jump_timer)
+ {
+ reset_jump_timer = false;
+ jump_timer = 0.0;
+ }
+
// Handle QuicktuneShortcutter
if(input->wasKeyDown(getKeySetting("keymap_quicktune_next")))
quicktune.next();
bool a_jump,
bool a_superspeed,
bool a_sneak,
+ bool a_LMB,
+ bool a_RMB,
float a_pitch,
float a_yaw*/
PlayerControl control(
input->isKeyDown(getKeySetting("keymap_jump")),
input->isKeyDown(getKeySetting("keymap_special1")),
input->isKeyDown(getKeySetting("keymap_sneak")),
+ input->getLeftState(),
+ input->getRightState(),
camera_pitch,
camera_yaw
);
client.setPlayerControl(control);
+ u32 keyPressed=
+ 1*(int)input->isKeyDown(getKeySetting("keymap_forward"))+
+ 2*(int)input->isKeyDown(getKeySetting("keymap_backward"))+
+ 4*(int)input->isKeyDown(getKeySetting("keymap_left"))+
+ 8*(int)input->isKeyDown(getKeySetting("keymap_right"))+
+ 16*(int)input->isKeyDown(getKeySetting("keymap_jump"))+
+ 32*(int)input->isKeyDown(getKeySetting("keymap_special1"))+
+ 64*(int)input->isKeyDown(getKeySetting("keymap_sneak"))+
+ 128*(int)input->getLeftState()+
+ 256*(int)input->getRightState();
+ LocalPlayer* player = client.getEnv().getLocalPlayer();
+ player->keyPressed=keyPressed;
}
/*
{
break;
}
- else if(event.type == CE_PLAYER_DAMAGE)
+ else if(event.type == CE_PLAYER_DAMAGE &&
+ client.getHP() != 0)
{
//u16 damage = event.player_damage.amount;
//infostream<<"Player damage: "<<damage<<std::endl;
- damage_flash_timer = 0.05;
- if(event.player_damage.amount >= 2){
- damage_flash_timer += 0.05 * event.player_damage.amount;
- }
+
+ damage_flash += 100.0;
+ damage_flash += 8.0 * event.player_damage.amount;
+
+ player->hurt_tilt_timer = 1.5;
+ player->hurt_tilt_strength = event.player_damage.amount/2;
+ player->hurt_tilt_strength = rangelim(player->hurt_tilt_strength, 2.0, 10.0);
}
else if(event.type == CE_PLAYER_FORCE_MOVE)
{
/* Handle visualization */
- damage_flash_timer = 0;
+ damage_flash = 0;
+
+ LocalPlayer* player = client.getEnv().getLocalPlayer();
+ player->hurt_tilt_timer = 0;
+ player->hurt_tilt_strength = 0;
/*LocalPlayer* player = client.getLocalPlayer();
player->setPosition(player->getPosition() + v3f(0,-BS,0));
camera.update(player, busytime, screensize);*/
}
+ else if (event.type == CE_SHOW_FORMSPEC)
+ {
+ if (current_formspec == 0)
+ {
+ /* Create menu */
+ current_formspec = new FormspecFormSource(*(event.show_formspec.formspec),¤t_formspec);
+
+ GUIFormSpecMenu *menu =
+ new GUIFormSpecMenu(device, guiroot, -1,
+ &g_menumgr,
+ &client, gamedef);
+ menu->setFormSource(current_formspec);
+ menu->setTextDest(new TextDestPlayerInventory(&client,*(event.show_formspec.formname)));
+ menu->drop();
+ }
+ else
+ {
+ /* update menu */
+ current_formspec->setForm(*(event.show_formspec.formspec));
+ }
+ delete(event.show_formspec.formspec);
+ delete(event.show_formspec.formname);
+ }
else if(event.type == CE_TEXTURES_UPDATED)
{
update_wielded_item_trigger = true;
bool left_punch = false;
soundmaker.m_player_leftpunch_sound.name = "";
+ if(input->getRightState())
+ repeat_rightclick_timer += dtime;
+ else
+ repeat_rightclick_timer = 0;
+
if(playeritem_usable && input->getLeftState())
{
if(input->getLeftClicked())
else
{
dig_time_complete = params.time;
+ if (g_settings->getBool("enable_particles"))
+ {
+ const ContentFeatures &features =
+ client.getNodeDefManager()->get(n);
+ addPunchingParticles
+ (gamedef, smgr, player, nodepos, features.tiles);
+ }
}
if(dig_time_complete >= 0.001)
MapNode wasnode = map.getNode(nodepos);
client.removeNode(nodepos);
+ if (g_settings->getBool("enable_particles"))
+ {
+ const ContentFeatures &features =
+ client.getNodeDefManager()->get(wasnode);
+ addDiggingParticles
+ (gamedef, smgr, player, nodepos, features.tiles);
+ }
+
dig_time = 0;
digging = false;
camera.setDigging(0); // left click animation
}
- if(input->getRightClicked())
+ if(input->getRightClicked() ||
+ repeat_rightclick_timer >= g_settings->getFloat("repeat_rightclick_time"))
{
+ repeat_rightclick_timer = 0;
infostream<<"Ground right-clicked"<<std::endl;
// Sign special case, at least until formspec is properly implemented.
// Deprecated?
- if(meta && meta->getString("formspec") == "hack:sign_text_input" && !random_input)
+ if(meta && meta->getString("formspec") == "hack:sign_text_input"
+ && !random_input
+ && !input->isKeyDown(getKeySetting("keymap_sneak")))
{
infostream<<"Launching metadata text input"<<std::endl;
wtext))->drop();
}
// If metadata provides an inventory view, activate it
- else if(meta && meta->getString("formspec") != "" && !random_input)
+ else if(meta && meta->getString("formspec") != "" && !random_input
+ && !input->isKeyDown(getKeySetting("keymap_sneak")))
{
infostream<<"Launching custom inventory view"<<std::endl;
/* Create menu */
GUIFormSpecMenu *menu =
- new GUIFormSpecMenu(guienv, guiroot, -1,
+ new GUIFormSpecMenu(device, guiroot, -1,
&g_menumgr,
&client, gamedef);
menu->setFormSpec(meta->getString("formspec"),
// make that happen
const ItemDefinition &def =
playeritem.getDefinition(itemdef);
- if(def.node_placement_prediction != "")
+ if(def.node_placement_prediction != ""
+ && !nodedef->get(map.getNode(nodepos)).rightclickable)
do{ // breakable
verbosestream<<"Node placement prediction for "
<<playeritem.name<<" is "
Fog range
*/
- f32 fog_range;
if(farmesh)
{
fog_range = BS*farmesh_range;
Calculate general brightness
*/
u32 daynight_ratio = client.getEnv().getDayNightRatio();
- float time_brightness = (float)decode_light(
- (daynight_ratio * LIGHT_SUN) / 1000) / 255.0;
+ float time_brightness = decode_light_f((float)daynight_ratio/1000.0);
float direct_brightness = 0;
bool sunlight_seen = false;
if(g_settings->getBool("free_move")){
farmesh->update(v2f(player_position.X, player_position.Z),
brightness, farmesh_range);
}
+
+ /*
+ Update particles
+ */
+
+ allparticles_step(dtime, client.getEnv());
/*
Fog
//TimeTaker guiupdatetimer("Gui updating");
const char program_name_and_version[] =
- "Minetest-c55 " VERSION_STRING;
+ "Minetest " VERSION_STRING;
if(show_debug)
{
item = mlist->getItem(client.getPlayerItem());
camera.wield(item);
}
-
+
+ /*
+ Update block draw list every 200ms or when camera direction has
+ changed much
+ */
+ update_draw_list_timer += dtime;
+ if(update_draw_list_timer >= 0.2 ||
+ update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2){
+ update_draw_list_timer = 0;
+ client.getEnv().getClientMap().updateDrawList(driver);
+ update_draw_list_last_cam_dir = camera_direction;
+ }
+
/*
Drawing begins
*/
{
TimeTaker timer("smgr");
smgr->drawAll();
+
+ if(g_settings->getBool("anaglyph"))
+ {
+ irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
+ irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
+
+ irr::core::matrix4 startMatrix = camera.getCameraNode()->getAbsoluteTransformation();
+
+ irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget() -
+ camera.getCameraNode()->getAbsolutePosition()).setLength(1) +
+ camera.getCameraNode()->getAbsolutePosition() ;
+
+ //Left eye...
+ irr::core::vector3df leftEye;
+ irr::core::matrix4 leftMove;
+
+ leftMove.setTranslation( irr::core::vector3df(-g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
+ leftEye=(startMatrix*leftMove).getTranslation();
+
+ //clear the depth buffer, and color
+ driver->beginScene( true, true, irr::video::SColor(0,200,200,255) );
+
+ driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_RED;
+ driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
+ driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
+ irr::scene::ESNRP_SOLID +
+ irr::scene::ESNRP_TRANSPARENT +
+ irr::scene::ESNRP_TRANSPARENT_EFFECT +
+ irr::scene::ESNRP_SHADOW;
+
+ camera.getCameraNode()->setPosition( leftEye );
+ camera.getCameraNode()->setTarget( focusPoint );
+
+ smgr->drawAll(); // 'smgr->drawAll();' may go here
+
+
+ //Right eye...
+ irr::core::vector3df rightEye;
+ irr::core::matrix4 rightMove;
+
+ rightMove.setTranslation( irr::core::vector3df(g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
+ rightEye=(startMatrix*rightMove).getTranslation();
+
+ //clear the depth buffer
+ driver->clearZBuffer();
+
+ driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_GREEN + irr::video::ECP_BLUE;
+ driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
+ driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
+ irr::scene::ESNRP_SOLID +
+ irr::scene::ESNRP_TRANSPARENT +
+ irr::scene::ESNRP_TRANSPARENT_EFFECT +
+ irr::scene::ESNRP_SHADOW;
+
+ camera.getCameraNode()->setPosition( rightEye );
+ camera.getCameraNode()->setTarget( focusPoint );
+
+ smgr->drawAll(); // 'smgr->drawAll();' may go here
+
+
+ //driver->endScene();
+
+ driver->getOverrideMaterial().Material.ColorMask=irr::video::ECP_ALL;
+ driver->getOverrideMaterial().EnableFlags=0;
+ driver->getOverrideMaterial().EnablePasses=0;
+
+ camera.getCameraNode()->setPosition( oldPosition );
+ camera.getCameraNode()->setTarget( oldTarget );
+ }
+
scenetime = timer.stop(true);
}
if(show_hud)
{
+ v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
+ u32 selectionbox_color_r = rangelim(myround(selectionbox_color.X), 0, 255);
+ u32 selectionbox_color_g = rangelim(myround(selectionbox_color.Y), 0, 255);
+ u32 selectionbox_color_b = rangelim(myround(selectionbox_color.Z), 0, 255);
+
for(std::vector<aabb3f>::const_iterator
i = hilightboxes.begin();
i != hilightboxes.end(); i++)
<<" max="
<<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"
<<std::endl;*/
- driver->draw3DBox(*i, video::SColor(255,0,0,0));
+ driver->draw3DBox(*i, video::SColor(255,selectionbox_color_r,selectionbox_color_g,selectionbox_color_b));
}
}
*/
if(show_hud)
{
+ v3f crosshair_color = g_settings->getV3F("crosshair_color");
+ u32 crosshair_color_r = rangelim(myround(crosshair_color.X), 0, 255);
+ u32 crosshair_color_g = rangelim(myround(crosshair_color.Y), 0, 255);
+ u32 crosshair_color_b = rangelim(myround(crosshair_color.Z), 0, 255);
+ u32 crosshair_alpha = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
+
driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
displaycenter + core::vector2d<s32>(10,0),
- video::SColor(255,255,255,255));
+ video::SColor(crosshair_alpha,crosshair_color_r,crosshair_color_g,crosshair_color_b));
driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
displaycenter + core::vector2d<s32>(0,10),
- video::SColor(255,255,255,255));
+ video::SColor(crosshair_alpha,crosshair_color_r,crosshair_color_g,crosshair_color_b));
}
} // timer
//timer10.stop();
//TimeTaker //timer11("//timer11");
- /*
- Draw gui
- */
- // 0-1ms
- guienv->drawAll();
/*
Draw hotbar
/*
Damage flash
*/
- if(damage_flash_timer > 0.0)
+ if(damage_flash > 0.0)
{
- damage_flash_timer -= dtime;
-
- video::SColor color(128,255,0,0);
+ video::SColor color(std::min(damage_flash, 180.0f),180,0,0);
driver->draw2DRectangle(color,
core::rect<s32>(0,0,screensize.X,screensize.Y),
NULL);
+
+ damage_flash -= 100.0*dtime;
}
+ /*
+ Damage camera tilt
+ */
+ if(player->hurt_tilt_timer > 0.0)
+ {
+ player->hurt_tilt_timer -= dtime*5;
+ if(player->hurt_tilt_timer < 0)
+ player->hurt_tilt_strength = 0;
+ }
+
+ /*
+ Draw gui
+ */
+ // 0-1ms
+ guienv->drawAll();
+
/*
End scene
*/
if(!sound_is_dummy)
delete sound;
+
+ delete tsrc;
+ delete shsrc;
delete nodedef;
delete itemdef;
- delete tsrc;
}