diff options
Diffstat (limited to '')
-rw-r--r-- | MCServer/Plugins/APIDump/APIDesc.lua | 28 | ||||
-rw-r--r-- | MCServer/Plugins/APIDump/main_APIDump.lua | 138 | ||||
-rw-r--r-- | Tools/ProtoProxy/Globals.h | 6 | ||||
-rw-r--r-- | src/Bindings/LuaState.cpp | 15 | ||||
-rw-r--r-- | src/Bindings/LuaState.h | 6 | ||||
-rw-r--r-- | src/BlockID.h | 14 | ||||
-rw-r--r-- | src/ChunkMap.cpp | 37 | ||||
-rw-r--r-- | src/Entities/Entity.cpp | 381 | ||||
-rw-r--r-- | src/Entities/Entity.h | 1 | ||||
-rw-r--r-- | src/Entities/FallingBlock.cpp | 19 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 37 | ||||
-rw-r--r-- | src/Entities/Player.h | 164 | ||||
-rw-r--r-- | src/Items/ItemLighter.h | 2 | ||||
-rw-r--r-- | src/Protocol/Protocol16x.cpp | 4 | ||||
-rw-r--r-- | src/Protocol/Protocol17x.cpp | 10 | ||||
-rw-r--r-- | src/Simulator/IncrementalRedstoneSimulator.cpp | 2 | ||||
-rw-r--r-- | src/World.cpp | 59 | ||||
-rw-r--r-- | src/World.h | 8 |
18 files changed, 576 insertions, 355 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index c5599b212..74e7bf860 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1666,25 +1666,26 @@ a_Player:OpenWindow(Window); GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." }, GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player (based on the first group). Prefix player messages with this code." }, GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" }, - GetEffectiveGameMode = { Params = "", Return = "{{eGameMode|GameMode}}", Notes = "Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions." }, + GetEffectiveGameMode = { Params = "", Return = "{{Globals#GameMode|GameMode}}", Notes = "(OBSOLETE) Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions. Note that this function is the same as GetGameMode(), use that function instead." }, GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." }, GetEyeHeight = { Return = "number", Notes = "Returns the height of the player's eyes, in absolute coords" }, GetEyePosition = { Return = "{{Vector3d|EyePositionVector}}", Notes = "Returns the position of the player's eyes, as a {{Vector3d}}" }, GetFloaterID = { Params = "", Return = "number", Notes = "Returns the Entity ID of the fishing hook floater that belongs to the player. Returns -1 if no floater is associated with the player. FIXME: Undefined behavior when the player has used multiple fishing rods simultanously." }, + GetFlyingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the maximum flying speed, relative to the default game flying speed. Defaults to 1, but plugins may modify it for faster or slower flying." }, GetFoodExhaustionLevel = { Params = "", Return = "number", Notes = "Returns the food exhaustion level" }, GetFoodLevel = { Params = "", Return = "number", Notes = "Returns the food level (number of half-drumsticks on-screen)" }, GetFoodPoisonedTicksRemaining = { Params = "", Return = "", Notes = "Returns the number of ticks left for the food posoning effect" }, GetFoodSaturationLevel = { Params = "", Return = "number", Notes = "Returns the food saturation (overcharge of the food level, is depleted before food level)" }, GetFoodTickTimer = { Params = "", Return = "", Notes = "Returns the number of ticks past the last food-based heal or damage action; when this timer reaches 80, a new heal / damage is applied." }, - GetGameMode = { Return = "{{eGameMode|GameMode}}", Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.<br /> <b>NOTE:</b> Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically."}, + GetGameMode = { Return = "{{Globals#GameMode|GameMode}}", Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.<br /> <b>NOTE:</b> Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically."}, GetGroups = { Return = "array-table of {{cGroup}}", Notes = "Returns all the groups that this player is member of, as a table. The groups are stored in the array part of the table, beginning with index 1."}, GetIP = { Return = "string", Notes = "Returns the IP address of the player, if available. Returns an empty string if there's no IP to report."}, GetInventory = { Return = "{{cInventory|Inventory}}", Notes = "Returns the player's inventory"}, - GetMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's current maximum speed (as reported by the 1.6.1+ protocols)" }, + GetMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's current maximum speed, relative to the game default speed. Takes into account the sprinting / flying status." }, GetName = { Return = "string", Notes = "Returns the player's name" }, - GetNormalMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum walking speed (as reported by the 1.6.1+ protocols)" }, + GetNormalMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum walking speed, relative to the game default speed. Defaults to 1, but plugins may modify it for faster or slower walking." }, GetResolvedPermissions = { Return = "array-table of string", Notes = "Returns all the player's permissions, as a table. The permissions are stored in the array part of the table, beginning with index 1." }, - GetSprintingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum sprinting speed (as reported by the 1.6.1+ protocols)" }, + GetSprintingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum sprinting speed, relative to the game default speed. Defaults to 1.3, but plugins may modify it for faster or slower sprinting." }, GetStance = { Return = "number", Notes = "Returns the player's stance (Y-pos of player's eyes)" }, GetThrowSpeed = { Params = "SpeedCoeff", Return = "{{Vector3d}}", Notes = "Returns the speed vector for an object thrown with the specified speed coeff. Basically returns the normalized look vector multiplied by the coeff, with a slight random variation." }, GetThrowStartPos = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the position where the projectiles should start when thrown by this player." }, @@ -1721,17 +1722,18 @@ a_Player:OpenWindow(Window); SetCrouch = { Params = "IsCrouched", Return = "", Notes = "Sets the crouch state, broadcasts the change to other players." }, SetCurrentExperience = { Params = "XPAmount", Return = "", Notes = "Sets the current amount of experience (and indirectly, the XP level)." }, SetFlying = { Params = "IsFlying", Notes = "Sets if the player is flying or not." }, + SetFlyingMaxSpeed = { Params = "FlyingMaxSpeed", Return = "", Notes = "Sets the flying maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client." }, SetFoodExhaustionLevel = { Params = "ExhaustionLevel", Return = "", Notes = "Sets the food exhaustion to the specified level." }, SetFoodLevel = { Params = "FoodLevel", Return = "", Notes = "Sets the food level (number of half-drumsticks on-screen)" }, SetFoodPoisonedTicksRemaining = { Params = "FoodPoisonedTicksRemaining", Return = "", Notes = "Sets the number of ticks remaining for food poisoning. Doesn't send foodpoisoning effect to the client, use FoodPoison() for that." }, SetFoodSaturationLevel = { Params = "FoodSaturationLevel", Return = "", Notes = "Sets the food saturation (overcharge of the food level)." }, SetFoodTickTimer = { Params = "FoodTickTimer", Return = "", Notes = "Sets the number of ticks past the last food-based heal or damage action; when this timer reaches 80, a new heal / damage is applied." }, - SetGameMode = { Params = "{{eGameMode|NewGameMode}}", Return = "", Notes = "Sets the gamemode for the player. The new gamemode overrides the world's default gamemode, unless it is set to gmInherit." }, + SetGameMode = { Params = "{{Globals#GameMode|NewGameMode}}", Return = "", Notes = "Sets the gamemode for the player. The new gamemode overrides the world's default gamemode, unless it is set to gmInherit." }, SetIsFishing = { Params = "IsFishing, [FloaterEntityID]", Return = "", Notes = "Sets the 'IsFishing' flag for the player. The floater entity ID is expected for the true variant, it can be omitted when IsFishing is false. FIXME: Undefined behavior when multiple fishing rods are used simultanously" }, SetName = { Params = "Name", Return = "", Notes = "Sets the player name. This rename will NOT be visible to any players already in the server who are close enough to see this player." }, - SetNormalMaxSpeed = { Params = "NormalMaxSpeed", Return = "", Notes = "Sets the normal (walking) maximum speed (as reported by the 1.6.1+ protocols)" }, + SetNormalMaxSpeed = { Params = "NormalMaxSpeed", Return = "", Notes = "Sets the normal (walking) maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client, if appropriate." }, SetSprint = { Params = "IsSprinting", Return = "", Notes = "Sets whether the player is sprinting or not." }, - SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed (as reported by the 1.6.1+ protocols)" }, + SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed, relative to the game default speed. The default value is 1.3. Sends the updated speed to the client, if appropriate." }, SetVisible = { Params = "IsVisible", Return = "", Notes = "Sets the player visibility to other players" }, XpForLevel = { Params = "XPLevel", Return = "number", Notes = "(STATIC) Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." }, }, @@ -2792,11 +2794,11 @@ end "Globals.xpcall", "Globals.decoda_output", -- When running under Decoda, this function gets added to the global namespace "sqlite3.__newindex", - "%a+\.__%a+", -- AnyClass.__Anything - "%a+\.\.collector", -- AnyClass..collector - "%a+\.new", -- AnyClass.new - "%a+.new_local", -- AnyClass.new_local - "%a+.delete", -- AnyClass.delete + "%a+%.__%a+", -- AnyClass.__Anything + "%a+%.%.collector", -- AnyClass..collector + "%a+%.new", -- AnyClass.new + "%a+%.new_local", -- AnyClass.new_local + "%a+%.delete", -- AnyClass.delete -- Functions global in the APIDump plugin: "CreateAPITables", diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index 6d4a6ebc5..7455c3cd2 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -1231,10 +1231,6 @@ local function DumpAPIHtml(a_API) return (Hook1.Name < Hook2.Name); end ); - - -- Read in the descriptions: - LOG("Reading descriptions..."); - ReadDescriptions(a_API); ReadHooks(Hooks); -- Create a "class index" file, write each class as a link to that file, @@ -1329,6 +1325,126 @@ end +--- Returns the string with extra tabs and CR/LFs removed +local function CleanUpDescription(a_Desc) + -- Get rid of indent and newlines, normalize whitespace: + local res = a_Desc:gsub("[\n\t]", "") + res = a_Desc:gsub("%s%s+", " ") + + -- Replace paragraph marks with newlines: + res = res:gsub("<p>", "\n") + res = res:gsub("</p>", "") + + -- Replace list items with dashes: + res = res:gsub("</?ul>", "") + res = res:gsub("<li>", "\n - ") + res = res:gsub("</li>", "") + + return res +end + + + + + +--- Writes a list of methods into the specified file in ZBS format +local function WriteZBSMethods(f, a_Methods) + for _, func in ipairs(a_Methods or {}) do + f:write("\t\t\t[\"", func.Name, "\"] =\n") + f:write("\t\t\t{\n") + f:write("\t\t\t\ttype = \"method\",\n") + if ((func.Notes ~= nil) and (func.Notes ~= "")) then + f:write("\t\t\t\tdescription = [[", CleanUpDescription(func.Notes or ""), " ]],\n") + end + f:write("\t\t\t},\n") + end +end + + + + + +--- Writes a list of constants into the specified file in ZBS format +local function WriteZBSConstants(f, a_Constants) + for _, cons in ipairs(a_Constants or {}) do + f:write("\t\t\t[\"", cons.Name, "\"] =\n") + f:write("\t\t\t{\n") + f:write("\t\t\t\ttype = \"value\",\n") + if ((cons.Desc ~= nil) and (cons.Desc ~= "")) then + f:write("\t\t\t\tdescription = [[", CleanUpDescription(cons.Desc or ""), " ]],\n") + end + f:write("\t\t\t},\n") + end +end + + + + + +--- Writes one MCS class definition into the specified file in ZBS format +local function WriteZBSClass(f, a_Class) + assert(type(a_Class) == "table") + + -- Write class header: + f:write("\t", a_Class.Name, " =\n\t{\n") + f:write("\t\ttype = \"class\",\n") + f:write("\t\tdescription = [[", CleanUpDescription(a_Class.Desc or ""), " ]],\n") + f:write("\t\tchilds =\n") + f:write("\t\t{\n") + + -- Export methods and constants: + WriteZBSMethods(f, a_Class.Functions) + WriteZBSConstants(f, a_Class.Constants) + + -- Finish the class definition: + f:write("\t\t},\n") + f:write("\t},\n\n") +end + + + + + +--- Dumps the entire API table into a file in the ZBS format +local function DumpAPIZBS(a_API) + LOG("Dumping ZBS API description...") + local f, err = io.open("mcserver.lua", "w") + if (f == nil) then + LOG("Cannot open mcserver.lua for writing, ZBS API will not be dumped. " .. err) + return + end + + -- Write the file header: + f:write("-- This is a MCServer API file automatically generated by the APIDump plugin\n") + f:write("-- Note that any manual changes will be overwritten by the next dump\n\n") + f:write("return {\n") + + -- Export each class except Globals, store those aside: + local Globals + for _, cls in ipairs(a_API) do + if (cls.Name ~= "Globals") then + WriteZBSClass(f, cls) + else + Globals = cls + end + end + + -- Export the globals: + if (Globals) then + WriteZBSMethods(f, Globals.Functions) + WriteZBSConstants(f, Globals.Constants) + end + + -- Finish the file: + f:write("}\n") + f:close() + LOG("ZBS API dumped...") +end + + + + + local function DumpApi() LOG("Dumping the API...") @@ -1377,9 +1493,16 @@ local function DumpApi() Globals.Name = "Globals"; table.insert(API, Globals); - -- Dump all available API object in HTML format into a subfolder: + -- Read in the descriptions: + LOG("Reading descriptions..."); + ReadDescriptions(API); + + -- Dump all available API objects in HTML format into a subfolder: DumpAPIHtml(API); + -- Dump all available API objects in format used by ZeroBraneStudio API descriptions: + DumpAPIZBS(API) + LOG("APIDump finished"); return true end @@ -1418,9 +1541,12 @@ function Initialize(Plugin) LOG("Initialising " .. Plugin:GetName() .. " v." .. Plugin:GetVersion()) + -- Bind a console command to dump the API: cPluginManager:BindConsoleCommand("api", HandleCmdApi, "Dumps the Lua API docs into the API/ subfolder") + + -- Add a WebAdmin tab that has a Dump button g_Plugin:AddWebTab("APIDump", HandleWebAdminDump) - -- TODO: Add a WebAdmin tab that has a Dump button + return true end diff --git a/Tools/ProtoProxy/Globals.h b/Tools/ProtoProxy/Globals.h index 0724d3a52..e2f5aa860 100644 --- a/Tools/ProtoProxy/Globals.h +++ b/Tools/ProtoProxy/Globals.h @@ -22,6 +22,8 @@ #define ALIGN_8 #define ALIGN_16 + #define FORMATSTRING(formatIndex, va_argsIndex) + #elif defined(__GNUC__) // TODO: Can GCC explicitly mark classes as abstract (no instances can be created)? @@ -38,7 +40,7 @@ // Some portability macros :) #define stricmp strcasecmp - #define FORMATSTRING(formatIndex,va_argsIndex) + #define FORMATSTRING(formatIndex, va_argsIndex) #else @@ -61,7 +63,7 @@ #define ALIGN_16 */ - #define FORMATSTRING(formatIndex,va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex))) + #define FORMATSTRING(formatIndex, va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex))) #endif diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index f24e15c3b..47380b8a7 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -689,9 +689,10 @@ void cLuaState::Push(void * a_Ptr) ASSERT(IsValid()); // Investigate the cause of this - what is the callstack? - LOGWARNING("Lua engine encountered an error - attempting to push a plain pointer"); + // One code path leading here is the OnHookExploding / OnHookExploded with exotic parameters. Need to decide what to do with them + LOGWARNING("Lua engine: attempting to push a plain pointer, pushing nil instead."); + LOGWARNING("This indicates an unimplemented part of MCS bindings"); LogStackTrace(); - ASSERT(!"A plain pointer should never be pushed on Lua stack"); lua_pushnil(m_LuaState); m_NumCurrentFunctionArgs += 1; @@ -1080,20 +1081,20 @@ bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status) -void cLuaState::LogStackTrace(void) +void cLuaState::LogStackTrace(int a_StartingDepth) { - LogStackTrace(m_LuaState); + LogStackTrace(m_LuaState, a_StartingDepth); } -void cLuaState::LogStackTrace(lua_State * a_LuaState) +void cLuaState::LogStackTrace(lua_State * a_LuaState, int a_StartingDepth) { LOGWARNING("Stack trace:"); lua_Debug entry; - int depth = 0; + int depth = a_StartingDepth; while (lua_getstack(a_LuaState, depth, &entry)) { lua_getinfo(a_LuaState, "Sln", &entry); @@ -1312,7 +1313,7 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header) int cLuaState::ReportFnCallErrors(lua_State * a_LuaState) { LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1)); - LogStackTrace(a_LuaState); + LogStackTrace(a_LuaState, 1); return 1; // We left the error message on the stack as the return value } diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index f5cb8379d..f0047b362 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -200,7 +200,7 @@ public: void Push(const HTTPTemplateRequest * a_Request); void Push(cTNTEntity * a_TNTEntity); void Push(Vector3i * a_Vector); - NORETURNDEBUG void Push(void * a_Ptr); + void Push(void * a_Ptr); void Push(cHopperEntity * a_Hopper); void Push(cBlockEntity * a_BlockEntity); @@ -868,10 +868,10 @@ public: static bool ReportErrors(lua_State * a_LuaState, int status); /** Logs all items in the current stack trace to the server console */ - void LogStackTrace(void); + void LogStackTrace(int a_StartingDepth = 0); /** Logs all items in the current stack trace to the server console */ - static void LogStackTrace(lua_State * a_LuaState); + static void LogStackTrace(lua_State * a_LuaState, int a_StartingDepth = 0); /** Returns the type of the item on the specified position in the stack */ AString GetTypeText(int a_StackPos); diff --git a/src/BlockID.h b/src/BlockID.h index 1c454cd23..8adefcfba 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -853,9 +853,17 @@ enum eExplosionSource esWitherSkullBlue, esWitherBirth, esPlugin, - - // Obsolete constants, kept for compatibility, will be removed after some time: - esCreeper = esMonster, +} ; + + + + + +enum eShrapnelLevel +{ + slNone, + slGravityAffectedOnly, + slAll } ; // tolua_end diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index ffba52d54..e695f0ab2 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1834,8 +1834,23 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc. m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z); } + else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around + { + if (!cBlockInfo::FullyOccupiesVoxel(Block)) + { + break; + } + else if ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block != E_BLOCK_SAND) && (Block != E_BLOCK_GRAVEL))) + { + break; + } + m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); + } + area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); + break; + } } // switch (BlockType) } // for z @@ -1848,11 +1863,10 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ public cEntityCallback { public: - cTNTDamageCallback(cBoundingBox & a_bbTNT, Vector3d a_ExplosionPos, int a_ExplosionSize, int a_ExplosionSizeSq) : + cTNTDamageCallback(cBoundingBox & a_bbTNT, Vector3d a_ExplosionPos, int a_ExplosionSize) : m_bbTNT(a_bbTNT), m_ExplosionPos(a_ExplosionPos), - m_ExplosionSize(a_ExplosionSize), - m_ExplosionSizeSq(a_ExplosionSizeSq) + m_ExplosionSize(a_ExplosionSize) { } @@ -1875,14 +1889,16 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ } Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z)); - Vector3d MaxExplosionBoundary(m_ExplosionSizeSq, m_ExplosionSizeSq, m_ExplosionSizeSq); // Work out how far we are from the edge of the TNT's explosive effect AbsoluteEntityPos -= m_ExplosionPos; - AbsoluteEntityPos = MaxExplosionBoundary - AbsoluteEntityPos; - double FinalDamage = ((AbsoluteEntityPos.x + AbsoluteEntityPos.y + AbsoluteEntityPos.z) / 3) * m_ExplosionSize; - FinalDamage = a_Entity->GetMaxHealth() - abs(FinalDamage); + // All to positive + AbsoluteEntityPos.x = abs(AbsoluteEntityPos.x); + AbsoluteEntityPos.y = abs(AbsoluteEntityPos.y); + AbsoluteEntityPos.z = abs(AbsoluteEntityPos.z); + + double FinalDamage = (((1 / AbsoluteEntityPos.x) + (1 / AbsoluteEntityPos.y) + (1 / AbsoluteEntityPos.z)) * 2) * m_ExplosionSize; // Clip damage values if (FinalDamage > a_Entity->GetMaxHealth()) @@ -1890,7 +1906,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ else if (FinalDamage < 0) FinalDamage = 0; - if (!a_Entity->IsTNT()) // Don't apply damage to other TNT entities, they should be invincible + if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible { a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0); } @@ -1900,7 +1916,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ if (distance_explosion.SqrLength() < 4096.0) { distance_explosion.Normalize(); - distance_explosion *= m_ExplosionSizeSq; + distance_explosion *= m_ExplosionSize * m_ExplosionSize; a_Entity->AddSpeed(distance_explosion); } @@ -1912,14 +1928,13 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ cBoundingBox & m_bbTNT; Vector3d m_ExplosionPos; int m_ExplosionSize; - int m_ExplosionSizeSq; }; cBoundingBox bbTNT(Vector3d(a_BlockX, a_BlockY, a_BlockZ), 0.5, 1); bbTNT.Expand(ExplosionSizeInt * 2, ExplosionSizeInt * 2, ExplosionSizeInt * 2); - cTNTDamageCallback TNTDamageCallback(bbTNT, Vector3d(a_BlockX, a_BlockY, a_BlockZ), ExplosionSizeInt, ExplosionSizeSq); + cTNTDamageCallback TNTDamageCallback(bbTNT, Vector3d(a_BlockX, a_BlockY, a_BlockZ), ExplosionSizeInt); ForEachEntity(TNTDamageCallback); // Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391): diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 0750ae05e..221cbbea7 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -521,27 +521,35 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) { if (a_Chunk.IsValid()) { - HandlePhysics(a_Dt, a_Chunk); - } - } - if (a_Chunk.IsValid()) - { - TickBurning(a_Chunk); - } - if ((a_Chunk.IsValid()) && (GetPosY() < -46)) - { - TickInVoid(a_Chunk); - } - else - m_TicksSinceLastVoidDamage = 0; + cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT); - if (IsMob() || IsPlayer()) - { - // Set swimming state - SetSwimState(a_Chunk); + if ((NextChunk == NULL) || !NextChunk->IsValid()) + { + return; + } + + TickBurning(*NextChunk); + + if (GetPosY() < VOID_BOUNDARY) + { + TickInVoid(*NextChunk); + } + else + { + m_TicksSinceLastVoidDamage = 0; + } + + if (IsMob() || IsPlayer()) + { + // Set swimming state + SetSwimState(*NextChunk); - // Handle drowning - HandleAir(); + // Handle drowning + HandleAir(); + } + + HandlePhysics(a_Dt, *NextChunk); + } } } @@ -562,7 +570,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) if ((BlockY >= cChunkDef::Height) || (BlockY < 0)) { // Outside of the world - + cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); // See if we can commit our changes. If not, we will discard them. if (NextChunk != NULL) @@ -571,210 +579,205 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) NextPos += (NextSpeed * a_Dt); SetPosition(NextPos); } + return; } - // Make sure we got the correct chunk and a valid one. No one ever knows... - cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); - if (NextChunk != NULL) + int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width); + int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width); + BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ ); + BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; + if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block { - int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width); - int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width); - BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ ); - BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; - if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block + if (m_bOnGround) // check if it's still on the ground { - if (m_bOnGround) // check if it's still on the ground + if (!cBlockInfo::IsSolid(BlockBelow)) // Check if block below is air or water. { - if (!cBlockInfo::IsSolid(BlockBelow)) // Check if block below is air or water. - { - m_bOnGround = false; - } + m_bOnGround = false; } } - else - { - // Push out entity. - BLOCKTYPE GotBlock; + } + else + { + // Push out entity. + BLOCKTYPE GotBlock; - static const struct - { - int x, y, z; - } gCrossCoords[] = - { - { 1, 0, 0}, - {-1, 0, 0}, - { 0, 0, 1}, - { 0, 0, -1}, - } ; - - bool IsNoAirSurrounding = true; - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + static const struct + { + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + } ; + + bool IsNoAirSurrounding = true; + for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + if (!a_Chunk.UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock)) { - if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock)) - { - // The pickup is too close to an unloaded chunk, bail out of any physics handling - return; - } - if (!cBlockInfo::IsSolid(GotBlock)) - { - NextPos.x += gCrossCoords[i].x; - NextPos.z += gCrossCoords[i].z; - IsNoAirSurrounding = false; - break; - } - } // for i - gCrossCoords[] - - if (IsNoAirSurrounding) + // The pickup is too close to an unloaded chunk, bail out of any physics handling + return; + } + if (!cBlockInfo::IsSolid(GotBlock)) { - NextPos.y += 0.5; + NextPos.x += gCrossCoords[i].x; + NextPos.z += gCrossCoords[i].z; + IsNoAirSurrounding = false; + break; } + } // for i - gCrossCoords[] + + if (IsNoAirSurrounding) + { + NextPos.y += 0.5; + } - m_bOnGround = true; + m_bOnGround = true; - /* - // DEBUG: - LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}", - m_UniqueID, GetClass(), BlockX, BlockY, BlockZ - ); - */ - } + /* + // DEBUG: + LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}", + m_UniqueID, GetClass(), BlockX, BlockY, BlockZ + ); + */ + } - if (!m_bOnGround) + if (!m_bOnGround) + { + float fallspeed; + if (IsBlockWater(BlockIn)) { - float fallspeed; - if (IsBlockWater(BlockIn)) - { - fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water. - } - else if (BlockIn == E_BLOCK_COBWEB) - { - NextSpeed.y *= 0.05; // Reduce overall falling speed - fallspeed = 0; // No falling. - } - else - { - // Normal gravity - fallspeed = m_Gravity * a_Dt; - } - NextSpeed.y += fallspeed; + fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water. + } + else if (BlockIn == E_BLOCK_COBWEB) + { + NextSpeed.y *= 0.05; // Reduce overall falling speed + fallspeed = 0; // No falling. } else { - // Friction - if (NextSpeed.SqrLength() > 0.0004f) + // Normal gravity + fallspeed = m_Gravity * a_Dt; + } + NextSpeed.y += fallspeed; + } + else + { + // Friction + if (NextSpeed.SqrLength() > 0.0004f) + { + NextSpeed.x *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.x) < 0.05) { - NextSpeed.x *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.x) < 0.05) - { - NextSpeed.x = 0; - } - NextSpeed.z *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.z) < 0.05) - { - NextSpeed.z = 0; - } + NextSpeed.x = 0; + } + NextSpeed.z *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.z) < 0.05) + { + NextSpeed.z = 0; } } + } - // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we - // might have different speed modifiers according to terrain. - if (BlockIn == E_BLOCK_COBWEB) - { - NextSpeed.x *= 0.25; - NextSpeed.z *= 0.25; - } + // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we + // might have different speed modifiers according to terrain. + if (BlockIn == E_BLOCK_COBWEB) + { + NextSpeed.x *= 0.25; + NextSpeed.z *= 0.25; + } - //Get water direction - Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ); + //Get water direction + Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ); - m_WaterSpeed *= 0.9f; //Reduce speed each tick + m_WaterSpeed *= 0.9f; //Reduce speed each tick - switch(WaterDir) - { - case X_PLUS: - m_WaterSpeed.x = 0.2f; - m_bOnGround = false; - break; - case X_MINUS: - m_WaterSpeed.x = -0.2f; - m_bOnGround = false; - break; - case Z_PLUS: - m_WaterSpeed.z = 0.2f; - m_bOnGround = false; - break; - case Z_MINUS: - m_WaterSpeed.z = -0.2f; - m_bOnGround = false; - break; - - default: + switch(WaterDir) + { + case X_PLUS: + m_WaterSpeed.x = 0.2f; + m_bOnGround = false; break; - } + case X_MINUS: + m_WaterSpeed.x = -0.2f; + m_bOnGround = false; + break; + case Z_PLUS: + m_WaterSpeed.z = 0.2f; + m_bOnGround = false; + break; + case Z_MINUS: + m_WaterSpeed.z = -0.2f; + m_bOnGround = false; + break; + + default: + break; + } - if (fabs(m_WaterSpeed.x) < 0.05) - { - m_WaterSpeed.x = 0; - } + if (fabs(m_WaterSpeed.x) < 0.05) + { + m_WaterSpeed.x = 0; + } - if (fabs(m_WaterSpeed.z) < 0.05) - { - m_WaterSpeed.z = 0; - } + if (fabs(m_WaterSpeed.z) < 0.05) + { + m_WaterSpeed.z = 0; + } - NextSpeed += m_WaterSpeed; + NextSpeed += m_WaterSpeed; - if( NextSpeed.SqrLength() > 0.f ) + if( NextSpeed.SqrLength() > 0.f ) + { + cTracer Tracer( GetWorld() ); + bool HasHit = Tracer.Trace( NextPos, NextSpeed, 2 ); + if (HasHit) // Oh noez! we hit something { - cTracer Tracer( GetWorld() ); - int Ret = Tracer.Trace( NextPos, NextSpeed, 2 ); - if( Ret ) // Oh noez! we hit something + // Set to hit position + if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * a_Dt).SqrLength()) { - // Set to hit position - if( (Tracer.RealHit - NextPos).SqrLength() <= ( NextSpeed * a_Dt ).SqrLength() ) - { - if( Ret == 1 ) - { - if( Tracer.HitNormal.x != 0.f ) NextSpeed.x = 0.f; - if( Tracer.HitNormal.y != 0.f ) NextSpeed.y = 0.f; - if( Tracer.HitNormal.z != 0.f ) NextSpeed.z = 0.f; - - if( Tracer.HitNormal.y > 0 ) // means on ground - { - m_bOnGround = true; - } - } - NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z); - NextPos.x += Tracer.HitNormal.x * 0.3f; - NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot - NextPos.z += Tracer.HitNormal.z * 0.3f; - } - else + if (Tracer.HitNormal.x != 0.f) NextSpeed.x = 0.f; + if (Tracer.HitNormal.y != 0.f) NextSpeed.y = 0.f; + if (Tracer.HitNormal.z != 0.f) NextSpeed.z = 0.f; + + if (Tracer.HitNormal.y > 0) // means on ground { - NextPos += (NextSpeed * a_Dt); + m_bOnGround = true; } + NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z); + NextPos.x += Tracer.HitNormal.x * 0.3f; + NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot + NextPos.z += Tracer.HitNormal.z * 0.3f; } else { - // We didn't hit anything, so move =] NextPos += (NextSpeed * a_Dt); } } - BlockX = (int) floor(NextPos.x); - BlockZ = (int) floor(NextPos.z); - NextChunk = NextChunk->GetNeighborChunk(BlockX,BlockZ); - // See if we can commit our changes. If not, we will discard them. - if (NextChunk != NULL) + else { - if (NextPos.x != GetPosX()) SetPosX(NextPos.x); - if (NextPos.y != GetPosY()) SetPosY(NextPos.y); - if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z); - if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x); - if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y); - if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z); + // We didn't hit anything, so move =] + NextPos += (NextSpeed * a_Dt); } } + + BlockX = (int) floor(NextPos.x); + BlockZ = (int) floor(NextPos.z); + + cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); + // See if we can commit our changes. If not, we will discard them. + if (NextChunk != NULL) + { + if (NextPos.x != GetPosX()) SetPosX(NextPos.x); + if (NextPos.y != GetPosY()) SetPosY(NextPos.y); + if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z); + if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x); + if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y); + if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z); + } } @@ -815,14 +818,13 @@ void cEntity::TickBurning(cChunk & a_Chunk) { int RelX = x; int RelZ = z; - cChunk * CurChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelX, RelZ); - if (CurChunk == NULL) - { - continue; - } + for (int y = MinY; y <= MaxY; y++) { - switch (CurChunk->GetBlock(RelX, y, RelZ)) + BLOCKTYPE Block; + a_Chunk.UnboundedRelGetBlockType(RelX, y, RelZ, Block); + + switch (Block) { case E_BLOCK_FIRE: { @@ -922,7 +924,7 @@ void cEntity::TickInVoid(cChunk & a_Chunk) void cEntity::SetSwimState(cChunk & a_Chunk) { - int RelY = (int)floor(m_LastPosY + 0.1); + int RelY = (int)floor(GetPosY() + 0.1); if ((RelY < 0) || (RelY >= cChunkDef::Height - 1)) { m_IsSwimming = false; @@ -931,11 +933,10 @@ void cEntity::SetSwimState(cChunk & a_Chunk) } BLOCKTYPE BlockIn; - int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width; - int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width; + int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; + int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; // Check if the player is swimming: - // Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn)) { // This sometimes happens on Linux machines diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index a73565de7..df80093e5 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -117,6 +117,7 @@ public: BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have DROWNING_TICKS = 20, ///< Number of ticks per heart of damage + VOID_BOUNDARY = -46 ///< At what position Y to begin applying void damage } ; cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp index 9fcd9ac80..a66c7e4ae 100644 --- a/src/Entities/FallingBlock.cpp +++ b/src/Entities/FallingBlock.cpp @@ -33,20 +33,16 @@ void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle) void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) { - float MilliDt = a_Dt * 0.001f; - AddSpeedY(MilliDt * -9.8f); - AddPosY(GetSpeedY() * MilliDt); - // GetWorld()->BroadcastTeleportEntity(*this); // Test position - int BlockX = m_OriginalPosition.x; + int BlockX = POSX_TOINT; int BlockY = (int)(GetPosY() - 0.5); - int BlockZ = m_OriginalPosition.z; + int BlockZ = POSZ_TOINT; if (BlockY < 0) { // Fallen out of this world, just continue falling until out of sight, then destroy: - if (BlockY < 100) + if (BlockY < VOID_BOUNDARY) { Destroy(true); } @@ -86,6 +82,15 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) Destroy(true); return; } + + float MilliDt = a_Dt * 0.001f; + AddSpeedY(MilliDt * -9.8f); + AddPosition(GetSpeed() * MilliDt); + + if ((GetSpeedX() != 0) || (GetSpeedZ() != 0)) + { + BroadcastMovementUpdate(); + } } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 440d30595..863aaa799 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -43,8 +43,9 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_GameMode(eGameMode_NotSet) , m_IP("") , m_ClientHandle(a_Client) - , m_NormalMaxSpeed(0.1) - , m_SprintingMaxSpeed(0.13) + , m_NormalMaxSpeed(1.0) + , m_SprintingMaxSpeed(1.3) + , m_FlyingMaxSpeed(1.0) , m_IsCrouched(false) , m_IsSprinting(false) , m_IsFlying(false) @@ -684,7 +685,21 @@ const cSlotNums & cPlayer::GetInventoryPaintSlots(void) const double cPlayer::GetMaxSpeed(void) const { - return m_IsSprinting ? m_SprintingMaxSpeed : m_NormalMaxSpeed; + if (m_IsFlying) + { + return m_FlyingMaxSpeed; + } + else + { + if (m_IsSprinting) + { + return m_SprintingMaxSpeed; + } + else + { + return m_NormalMaxSpeed; + } + } } @@ -694,7 +709,7 @@ double cPlayer::GetMaxSpeed(void) const void cPlayer::SetNormalMaxSpeed(double a_Speed) { m_NormalMaxSpeed = a_Speed; - if (!m_IsSprinting) + if (!m_IsSprinting && !m_IsFlying) { m_ClientHandle->SendPlayerMaxSpeed(); } @@ -707,7 +722,7 @@ void cPlayer::SetNormalMaxSpeed(double a_Speed) void cPlayer::SetSprintingMaxSpeed(double a_Speed) { m_SprintingMaxSpeed = a_Speed; - if (m_IsSprinting) + if (m_IsSprinting && !m_IsFlying) { m_ClientHandle->SendPlayerMaxSpeed(); } @@ -717,6 +732,18 @@ void cPlayer::SetSprintingMaxSpeed(double a_Speed) +void cPlayer::SetFlyingMaxSpeed(double a_Speed) +{ + m_FlyingMaxSpeed = a_Speed; + + // Update the flying speed, always: + m_ClientHandle->SendPlayerAbilities(); +} + + + + + void cPlayer::SetCrouch(bool a_IsCrouched) { // Set the crouch status, broadcast to all visible players diff --git a/src/Entities/Player.h b/src/Entities/Player.h index c25053c21..ea32dbfb9 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -47,19 +47,19 @@ public: virtual void HandlePhysics(float a_Dt, cChunk &) override { UNUSED(a_Dt); }; - /// Returns the curently equipped weapon; empty item if none + /** Returns the curently equipped weapon; empty item if none */ virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); } - /// Returns the currently equipped helmet; empty item if none + /** Returns the currently equipped helmet; empty item if none */ virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); } - /// Returns the currently equipped chestplate; empty item if none + /** Returns the currently equipped chestplate; empty item if none */ virtual cItem GetEquippedChestplate(void) const override { return m_Inventory.GetEquippedChestplate(); } - /// Returns the currently equipped leggings; empty item if none + /** Returns the currently equipped leggings; empty item if none */ virtual cItem GetEquippedLeggings(void) const override { return m_Inventory.GetEquippedLeggings(); } - /// Returns the currently equipped boots; empty item if none + /** Returns the currently equipped boots; empty item if none */ virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); } @@ -77,36 +77,41 @@ public: */ short DeltaExperience(short a_Xp_delta); - /// Gets the experience total - XpTotal for score on death + /** Gets the experience total - XpTotal for score on death */ inline short GetXpLifetimeTotal(void) { return m_LifetimeTotalXp; } - /// Gets the currrent experience + /** Gets the currrent experience */ inline short GetCurrentXp(void) { return m_CurrentXp; } - /// Gets the current level - XpLevel + /** Gets the current level - XpLevel */ short GetXpLevel(void); - /// Gets the experience bar percentage - XpP + /** Gets the experience bar percentage - XpP */ float GetXpPercentage(void); - /// Caculates the amount of XP needed for a given level, ref: http://minecraft.gamepedia.com/XP + /** Caculates the amount of XP needed for a given level + Ref: http://minecraft.gamepedia.com/XP + */ static short XpForLevel(short int a_Level); - /// inverse of XpForLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations + /** Inverse of XpForLevel + Ref: http://minecraft.gamepedia.com/XP + values are as per this with pre-calculations + */ static short CalcLevelFromXp(short int a_CurrentXp); // tolua_end - /// Starts charging the equipped bow + /** Starts charging the equipped bow */ void StartChargingBow(void); - /// Finishes charging the current bow. Returns the number of ticks for which the bow has been charged + /** Finishes charging the current bow. Returns the number of ticks for which the bow has been charged */ int FinishChargingBow(void); - /// Cancels the current bow charging + /** Cancels the current bow charging */ void CancelChargingBow(void); - /// Returns true if the player is currently charging the bow + /** Returns true if the player is currently charging the bow */ bool IsChargingBow(void) const { return m_IsChargingBow; } void SetTouchGround( bool a_bTouchGround ); @@ -124,16 +129,16 @@ public: // tolua_begin - /// Returns the position where projectiles thrown by this player should start, player eye position + adjustment + /** Returns the position where projectiles thrown by this player should start, player eye position + adjustment */ Vector3d GetThrowStartPos(void) const; - /// Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff. + /** Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff. */ Vector3d GetThrowSpeed(double a_SpeedCoeff) const; - /// Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable + /** Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable */ eGameMode GetGameMode(void) const { return m_GameMode; } - /// Returns the current effective gamemode (inherited gamemode is resolved before returning) + /** Returns the current effective gamemode (inherited gamemode is resolved before returning) */ eGameMode GetEffectiveGameMode(void) const { return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode; } /** Sets the gamemode for the player. @@ -142,24 +147,24 @@ public: */ void SetGameMode(eGameMode a_GameMode); - /// Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world + /** Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world */ bool IsGameModeCreative(void) const; - /// Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world + /** Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world */ bool IsGameModeSurvival(void) const; - /// Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world + /** Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world */ bool IsGameModeAdventure(void) const; AString GetIP(void) const { return m_IP; } // tolua_export - /// Returns the associated team, NULL if none + /** Returns the associated team, NULL if none */ cTeam * GetTeam(void) { return m_Team; } // tolua_export - /// Sets the player team, NULL if none + /** Sets the player team, NULL if none */ void SetTeam(cTeam * a_Team); - /// Forces the player to query the scoreboard for his team + /** Forces the player to query the scoreboard for his team */ cTeam * UpdateTeam(void); // tolua_end @@ -169,24 +174,24 @@ public: // Sets the current gamemode, doesn't check validity, doesn't send update packets to client void LoginSetGameMode(eGameMode a_GameMode); - /// Forces the player to move in the given direction. + /** Forces the player to move in the given direction. */ void ForceSetSpeed(Vector3d a_Direction); // tolua_export - /// Tries to move to a new position, with attachment-related checks (y == -999) + /** Tries to move to a new position, with attachment-related checks (y == -999) */ void MoveTo(const Vector3d & a_NewPos); // tolua_export cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export const cWindow * GetWindow(void) const { return m_CurrentWindow; } - /// Opens the specified window; closes the current one first using CloseWindow() + /** Opens the specified window; closes the current one first using CloseWindow() */ void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp // tolua_begin - /// Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true + /** Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true */ void CloseWindow(bool a_CanRefuse = true); - /// Closes the current window if it matches the specified ID, resets current window to m_InventoryWindow + /** Closes the current window if it matches the specified ID, resets current window to m_InventoryWindow */ void CloseWindowIfID(char a_WindowID, bool a_CanRefuse = true); cClientHandle * GetClientHandle(void) const { return m_ClientHandle; } @@ -208,10 +213,10 @@ public: typedef std::list< cGroup* > GroupList; typedef std::list< std::string > StringList; - /// Adds a player to existing group or creates a new group when it doesn't exist + /** Adds a player to existing group or creates a new group when it doesn't exist */ void AddToGroup( const AString & a_GroupName ); // tolua_export - /// Removes a player from the group, resolves permissions and group inheritance (case sensitive) + /** Removes a player from the group, resolves permissions and group inheritance (case sensitive) */ void RemoveFromGroup( const AString & a_GroupName ); // tolua_export bool HasPermission( const AString & a_Permission ); // tolua_export @@ -234,7 +239,7 @@ public: /** tosses a pickup newly created from a_Item */ void TossPickup(const cItem & a_Item); - /// Heals the player by the specified amount of HPs (positive only); sends health update + /** Heals the player by the specified amount of HPs (positive only); sends health update */ void Heal(int a_Health); int GetFoodLevel (void) const { return m_FoodLevel; } @@ -243,7 +248,7 @@ public: double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; } int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; } - /// Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore + /** Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore */ bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); } void SetFoodLevel (int a_FoodLevel); @@ -252,28 +257,28 @@ public: void SetFoodExhaustionLevel (double a_FoodExhaustionLevel); void SetFoodPoisonedTicksRemaining(int a_FoodPoisonedTicksRemaining); - /// Adds to FoodLevel and FoodSaturationLevel, returns true if any food has been consumed, false if player "full" + /** Adds to FoodLevel and FoodSaturationLevel, returns true if any food has been consumed, false if player "full" */ bool Feed(int a_Food, double a_Saturation); - /// Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values. + /** Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values. */ void AddFoodExhaustion(double a_Exhaustion) { m_FoodExhaustionLevel += a_Exhaustion; } - /// Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two + /** Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two */ void FoodPoison(int a_NumTicks); - /// Returns true if the player is currently in the process of eating the currently equipped item + /** Returns true if the player is currently in the process of eating the currently equipped item */ bool IsEating(void) const { return (m_EatingFinishTick >= 0); } - /// Returns true if the player is currently flying. + /** Returns true if the player is currently flying. */ bool IsFlying(void) const { return m_IsFlying; } /** Returns if a player is sleeping in a bed */ bool IsInBed(void) const { return m_bIsInBed; } - /// returns true if the player has thrown out a floater. + /** returns true if the player has thrown out a floater. */ bool IsFishing(void) const { return m_IsFishing; } void SetIsFishing(bool a_IsFishing, int a_FloaterID = -1) { m_IsFishing = a_IsFishing; m_FloaterID = a_FloaterID; } @@ -285,13 +290,13 @@ public: /** Sets a player's in-bed state; we can't be sure plugins will keep this value updated, so no exporting */ void SetIsInBed(bool a_Flag) { m_bIsInBed = a_Flag; } - /// Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet + /** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */ void StartEating(void); - /// Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets + /** Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets */ void FinishEating(void); - /// Aborts the current eating operation + /** Aborts the current eating operation */ void AbortEating(void); virtual void KilledBy(cEntity * a_Killer) override; @@ -320,45 +325,51 @@ public: cItem & GetDraggingItem(void) {return m_DraggingItem; } // In UI windows, when inventory-painting: - /// Clears the list of slots that are being inventory-painted. To be used by cWindow only + /** Clears the list of slots that are being inventory-painted. To be used by cWindow only */ void ClearInventoryPaintSlots(void); - /// Adds a slot to the list for inventory painting. To be used by cWindow only + /** Adds a slot to the list for inventory painting. To be used by cWindow only */ void AddInventoryPaintSlot(int a_SlotNum); - /// Returns the list of slots currently stored for inventory painting. To be used by cWindow only + /** Returns the list of slots currently stored for inventory painting. To be used by cWindow only */ const cSlotNums & GetInventoryPaintSlots(void) const; // tolua_begin - /// Returns the current maximum speed, as reported in the 1.6.1+ protocol (takes current sprinting state into account) + /** Returns the current relative maximum speed (takes current sprinting / flying state into account) */ double GetMaxSpeed(void) const; - /// Gets the normal maximum speed, as reported in the 1.6.1+ protocol, in the protocol units + /** Gets the normal relative maximum speed */ double GetNormalMaxSpeed(void) const { return m_NormalMaxSpeed; } - /// Gets the sprinting maximum speed, as reported in the 1.6.1+ protocol, in the protocol units + /** Gets the sprinting relative maximum speed */ double GetSprintingMaxSpeed(void) const { return m_SprintingMaxSpeed; } - /// Sets the normal maximum speed, as reported in the 1.6.1+ protocol. Sends the update to player, if needed. + /** Gets the flying relative maximum speed */ + double GetFlyingMaxSpeed(void) const { return m_FlyingMaxSpeed; } + + /** Sets the normal relative maximum speed. Sends the update to player, if needed. */ void SetNormalMaxSpeed(double a_Speed); - /// Sets the sprinting maximum speed, as reported in the 1.6.1+ protocol. Sends the update to player, if needed. + /** Sets the sprinting relative maximum speed. Sends the update to player, if needed. */ void SetSprintingMaxSpeed(double a_Speed); - /// Sets the crouch status, broadcasts to all visible players + /** Sets the flying relative maximum speed. Sends the update to player, if needed. */ + void SetFlyingMaxSpeed(double a_Speed); + + /** Sets the crouch status, broadcasts to all visible players */ void SetCrouch(bool a_IsCrouched); - /// Starts or stops sprinting, sends the max speed update to the client, if needed + /** Starts or stops sprinting, sends the max speed update to the client, if needed */ void SetSprint(bool a_IsSprinting); - /// Flags the player as flying + /** Flags the player as flying */ void SetFlying(bool a_IsFlying); - /// If true the player can fly even when he's not in creative. + /** If true the player can fly even when he's not in creative. */ void SetCanFly(bool a_CanFly); - /// Returns wheter the player can fly or not. + /** Returns wheter the player can fly or not. */ virtual bool CanFly(void) const { return m_CanFly; } // tolua_end @@ -380,7 +391,7 @@ protected: AString m_PlayerName; AString m_LoadedWorldName; - /// Xp Level stuff + /** Xp Level stuff */ enum { XP_TO_LEVEL15 = 255, @@ -391,22 +402,22 @@ protected: bool m_bVisible; // Food-related variables: - /// Represents the food bar, one point equals half a "drumstick" + /** Represents the food bar, one point equals half a "drumstick" */ int m_FoodLevel; - /// "Overcharge" for the m_FoodLevel; is depleted before m_FoodLevel + /** "Overcharge" for the m_FoodLevel; is depleted before m_FoodLevel */ double m_FoodSaturationLevel; - /// Count-up to the healing or damaging action, based on m_FoodLevel + /** Count-up to the healing or damaging action, based on m_FoodLevel */ int m_FoodTickTimer; - /// A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little + /** A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little */ double m_FoodExhaustionLevel; - /// Number of ticks remaining for the foodpoisoning effect; zero if not foodpoisoned + /** Number of ticks remaining for the foodpoisoning effect; zero if not foodpoisoned */ int m_FoodPoisonedTicksRemaining; - /// Last position that has been recorded for food-related processing: + /** Last position that has been recorded for food-related processing: */ Vector3d m_LastFoodPos; float m_LastJumpHeight; @@ -422,7 +433,7 @@ protected: eGameMode m_GameMode; AString m_IP; - /// The item being dragged by the cursor while in a UI window + /** The item being dragged by the cursor while in a UI window */ cItem m_DraggingItem; long long m_LastPlayerListTime; @@ -432,12 +443,21 @@ protected: cSlotNums m_InventoryPaintSlots; - /// Max speed, in ENTITY_PROPERTIES packet's units, when the player is walking. 0.1 by default + /** Max speed, relative to the game default. + 1 means regular speed, 2 means twice as fast, 0.5 means half-speed. + Default value is 1. */ double m_NormalMaxSpeed; - /// Max speed, in ENTITY_PROPERTIES packet's units, when the player is sprinting. 0.13 by default + /** Max speed, relative to the game default max speed, when sprinting. + 1 means regular speed, 2 means twice as fast, 0.5 means half-speed. + Default value is 1.3. */ double m_SprintingMaxSpeed; + /** Max speed, relative to the game default flying max speed, when flying. + 1 means regular speed, 2 means twice as fast, 0.5 means half-speed. + Default value is 1. */ + double m_FlyingMaxSpeed; + bool m_IsCrouched; bool m_IsSprinting; bool m_IsFlying; @@ -447,10 +467,10 @@ protected: bool m_CanFly; // If this is true the player can fly. Even if he is not in creative. - /// The world tick in which eating will be finished. -1 if not eating + /** The world tick in which eating will be finished. -1 if not eating */ Int64 m_EatingFinishTick; - /// Player Xp level + /** Player Xp level */ short int m_LifetimeTotalXp; short int m_CurrentXp; @@ -471,19 +491,19 @@ protected: virtual void Destroyed(void); - /// Filters out damage for creative mode/friendly fire + /** Filters out damage for creative mode/friendly fire */ virtual void DoTakeDamage(TakeDamageInfo & TDI) override; /** Stops players from burning in creative mode */ virtual void TickBurning(cChunk & a_Chunk) override; - /// Called in each tick to handle food-related processing + /** Called in each tick to handle food-related processing */ void HandleFood(void); - /// Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. + /** Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. */ void HandleFloater(void); - /// Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) + /** Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) */ void ApplyFoodExhaustionFromMovement(); /** Flag representing whether the player is currently in a bed diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h index 2db6c829a..32f49cab6 100644 --- a/src/Items/ItemLighter.h +++ b/src/Items/ItemLighter.h @@ -53,8 +53,8 @@ public: { // Activate the TNT: a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f); - a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0); + a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom break; } default: diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp index f6ec0a199..ecb24254f 100644 --- a/src/Protocol/Protocol16x.cpp +++ b/src/Protocol/Protocol16x.cpp @@ -135,7 +135,7 @@ void cProtocol161::SendPlayerMaxSpeed(void) WriteInt(m_Client->GetPlayer()->GetUniqueID()); WriteInt(1); WriteString("generic.movementSpeed"); - WriteDouble(m_Client->GetPlayer()->GetMaxSpeed()); + WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed()); Flush(); } @@ -267,7 +267,7 @@ void cProtocol162::SendPlayerMaxSpeed(void) WriteInt(m_Client->GetPlayer()->GetUniqueID()); WriteInt(1); WriteString("generic.movementSpeed"); - WriteDouble(m_Client->GetPlayer()->GetMaxSpeed()); + WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed()); WriteShort(0); Flush(); } diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 6fc344eaf..721ed349e 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -687,9 +687,8 @@ void cProtocol172::SendPlayerAbilities(void) Flags |= 0x04; } Pkt.WriteByte(Flags); - // TODO: Pkt.WriteFloat(m_Client->GetPlayer()->GetMaxFlyingSpeed()); - Pkt.WriteFloat(0.05f); - Pkt.WriteFloat((float)m_Client->GetPlayer()->GetMaxSpeed()); + Pkt.WriteFloat((float)(0.05 * m_Client->GetPlayer()->GetFlyingMaxSpeed())); + Pkt.WriteFloat((float)(0.1 * m_Client->GetPlayer()->GetMaxSpeed())); } @@ -743,13 +742,14 @@ void cProtocol172::SendPlayerMaxSpeed(void) Pkt.WriteInt(m_Client->GetPlayer()->GetUniqueID()); Pkt.WriteInt(1); // Count Pkt.WriteString("generic.movementSpeed"); - Pkt.WriteDouble(0.1); + // The default game speed is 0.1, multiply that value by the relative speed: + Pkt.WriteDouble(0.1 * m_Client->GetPlayer()->GetNormalMaxSpeed()); if (m_Client->GetPlayer()->IsSprinting()) { Pkt.WriteShort(1); // Modifier count Pkt.WriteInt64(0x662a6b8dda3e4c1c); Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier - Pkt.WriteDouble(0.3); + Pkt.WriteDouble(m_Client->GetPlayer()->GetSprintingMaxSpeed() - m_Client->GetPlayer()->GetNormalMaxSpeed()); Pkt.WriteByte(2); } else diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 6ace8ade9..92659fab7 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -838,8 +838,8 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_ if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); - m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom } } diff --git a/src/World.cpp b/src/World.cpp index 012ba915b..3f157157a 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -250,8 +250,6 @@ cWorld::cWorld(const AString & a_WorldName) : m_SkyDarkness(0), m_Weather(eWeather_Sunny), m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) - m_bCommandBlocksEnabled(false), - m_bUseChatPrefixes(true), m_Scoreboard(this), m_MapManager(this), m_GeneratorCallbacks(*this), @@ -562,29 +560,33 @@ void cWorld::Start(void) m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ); } - m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema); - m_StorageCompressionFactor = IniFile.GetValueSetI("Storage", "CompressionFactor", m_StorageCompressionFactor); - m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3); - m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3); - m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false); - m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true); - m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true); - m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true); - m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true); - m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false); - m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true); - m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true); - m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false); - m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true); - m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false); - m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true); - m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true); - m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false); - m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true); - m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true); - m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); - - m_GameMode = (eGameMode)IniFile.GetValueSetI("General", "Gamemode", m_GameMode); + m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema); + m_StorageCompressionFactor = IniFile.GetValueSetI("Storage", "CompressionFactor", m_StorageCompressionFactor); + m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3); + m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3); + m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false); + m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true); + m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true); + m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true); + m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true); + m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false); + m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true); + m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true); + m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false); + m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true); + m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false); + m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true); + m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true); + int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slNone); + m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false); + m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true); + m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true); + m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); + int GameMode = IniFile.GetValueSetI("General", "Gamemode", (int)m_GameMode); + + // Adjust the enum-backed variables into their respective bounds: + m_GameMode = (eGameMode) Clamp(GameMode, (int)gmSurvival, (int)gmAdventure); + m_TNTShrapnelLevel = (eShrapnelLevel)Clamp(TNTShrapnelLevel, (int)slNone, (int)slAll); // Load allowed mobs: const char * DefaultMonsters = ""; @@ -1727,10 +1729,13 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff) { - UNUSED(a_InitialVelocityCoeff); cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks); TNT->Initialize(this); - // TODO: Add a bit of speed in horiz and vert axes, based on the a_InitialVelocityCoeff + TNT->SetSpeed( + a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1), /** -1, 0, 1 */ + a_InitialVelocityCoeff * 2, + a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1) + ); } diff --git a/src/World.h b/src/World.h index bd9ed8d16..46aece18f 100644 --- a/src/World.h +++ b/src/World.h @@ -605,6 +605,9 @@ public: bool AreCommandBlocksEnabled(void) const { return m_bCommandBlocksEnabled; } void SetCommandBlocksEnabled(bool a_Flag) { m_bCommandBlocksEnabled = a_Flag; } + eShrapnelLevel GetTNTShrapnelLevel(void) const { return m_TNTShrapnelLevel; } + void SetTNTShrapnelLevel(eShrapnelLevel a_Flag) { m_TNTShrapnelLevel = a_Flag; } + bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; } void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; } @@ -862,6 +865,11 @@ private: /** Whether prefixes such as [INFO] are prepended to SendMessageXXX() / BroadcastChatXXX() functions */ bool m_bUseChatPrefixes; + + /** The level of DoExplosionAt() projecting random affected blocks as FallingBlock entities + See the eShrapnelLevel enumeration for details + */ + eShrapnelLevel m_TNTShrapnelLevel; cChunkGenerator m_Generator; |