1
0

Merge branch 'master' into size_t_lua

Conflicts:
	lib/tolua++/src/bin/basic_lua.h
This commit is contained in:
Tycho 2014-03-22 07:48:16 -07:00
commit 2266c2150d
75 changed files with 5425 additions and 4262 deletions

View File

@ -1,29 +0,0 @@
-- @EnableMobDebug.lua
-- Enables the MobDebug debugger, used by ZeroBrane Studio, for a plugin
-- Needs to be named with a @ at the start so that it's loaded as the first file of the plugin
--[[
Usage:
Copy this file to your plugin's folder when you want to debug that plugin
You should neither check this file into the plugin's version control system,
nor distribute it in the final release.
--]]
-- Try to load the debugger, be silent about failures:
local IsSuccess, MobDebug = pcall(require, "mobdebug")
if (IsSuccess) then
MobDebug.start()
-- The debugger will automatically put a breakpoint on this line, use this opportunity to set more breakpoints in your code
LOG(cPluginManager:GetCurrentPlugin():GetName() .. ": MobDebug enabled")
end

View File

@ -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)." }, 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." }, 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" }, 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." }, 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" }, 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}}" }, 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." }, 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" }, 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)" }, 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" }, 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)" }, 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." }, 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."}, 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."}, 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"}, 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" }, 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." }, 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)" }, 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." }, 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." }, 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." }, 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)." }, 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." }, 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." }, 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)" }, 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." }, 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)." }, 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." }, 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" }, 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." }, 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." }, 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" }, 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()." }, 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.xpcall",
"Globals.decoda_output", -- When running under Decoda, this function gets added to the global namespace "Globals.decoda_output", -- When running under Decoda, this function gets added to the global namespace
"sqlite3.__newindex", "sqlite3.__newindex",
"%a+\.__%a+", -- AnyClass.__Anything "%a+%.__%a+", -- AnyClass.__Anything
"%a+\.\.collector", -- AnyClass..collector "%a+%.%.collector", -- AnyClass..collector
"%a+\.new", -- AnyClass.new "%a+%.new", -- AnyClass.new
"%a+.new_local", -- AnyClass.new_local "%a+%.new_local", -- AnyClass.new_local
"%a+.delete", -- AnyClass.delete "%a+%.delete", -- AnyClass.delete
-- Functions global in the APIDump plugin: -- Functions global in the APIDump plugin:
"CreateAPITables", "CreateAPITables",

File diff suppressed because it is too large Load Diff

View File

@ -217,7 +217,7 @@ function TestBlockAreasString()
return return
end end
cFile:CreateFolder("schematics") cFile:CreateFolder("schematics")
local f = io.open("schematics/StringTest.schematic", "w") local f = io.open("schematics/StringTest.schematic", "wb")
f:write(Data) f:write(Data)
f:close() f:close()
@ -230,7 +230,7 @@ function TestBlockAreasString()
BA2:Clear() BA2:Clear()
-- Load another area from a string in that file: -- Load another area from a string in that file:
f = io.open("schematics/StringTest.schematic", "r") f = io.open("schematics/StringTest.schematic", "rb")
Data = f:read("*all") Data = f:read("*all")
if not(BA2:LoadFromSchematicString(Data)) then if not(BA2:LoadFromSchematicString(Data)) then
LOG("Cannot load schematic from string") LOG("Cannot load schematic from string")

View File

@ -0,0 +1,49 @@
function Initialize(a_Plugin)
a_Plugin:SetName("DumpInfo")
a_Plugin:SetVersion(1)
-- Check if the infodump file exists.
if (not cFile:Exists("Plugins/InfoDump.lua")) then
LOGWARN("[DumpInfo] InfoDump.lua was not found.")
return false
end
-- Add the webtab.
a_Plugin:AddWebTab("DumpPlugin", HandleDumpPluginRequest)
return true
end
function HandleDumpPluginRequest(a_Request)
local Content = ""
-- Check if it already was requested to dump a plugin.
if (a_Request.PostParams["DumpInfo"] ~= nil) then
local F = loadfile("Plugins/InfoDump.lua")
F("Plugins/" .. a_Request.PostParams["DumpInfo"])
end
Content = Content .. [[
<table>
<th colspan="2">DumpInfo</th>]]
-- Loop through each plugin that is found.
for PluginName, k in pairs(cPluginManager:Get():GetAllPlugins()) do
-- Check if there is a file called 'Info.lua' or 'info.lua'
if (cFile:Exists("Plugins/" .. PluginName .. "/Info.lua")) then
Content = Content .. "<tr>"
Content = Content .. "<td>" .. PluginName .. "</td>"
Content = Content .. "<td> <form method='POST'> <input type='hidden' value='" .. PluginName .. "' name='DumpInfo'> <input type='submit' value='DumpInfo'> </form>"
Content = Content .. "</td>"
end
end
Content = Content .. [[
</table>]]
return Content
end

View File

@ -59,13 +59,13 @@ local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_
return true; return true;
end end
-- Check if the handler is valid: -- If the handler is not valid, check the next sublevel:
if (Subcommand.Handler == nil) then if (Subcommand.Handler == nil) then
if (Subcommand.Subcommands == nil) then if (Subcommand.Subcommands == nil) then
LOG("Cannot find handler for command " .. a_CmdString .. " " .. Verb); LOG("Cannot find handler for command " .. a_CmdString .. " " .. Verb);
return false; return false;
end end
ListSubcommands(a_Player, Subcommand.Subcommands, a_CmdString .. " " .. Verb); MultiCommandHandler(a_Split, a_Player, a_CmdString .. " " .. Verb, Subcommand, a_Level + 1);
return true; return true;
end end

View File

@ -22,6 +22,8 @@
#define ALIGN_8 #define ALIGN_8
#define ALIGN_16 #define ALIGN_16
#define FORMATSTRING(formatIndex, va_argsIndex)
#elif defined(__GNUC__) #elif defined(__GNUC__)
// TODO: Can GCC explicitly mark classes as abstract (no instances can be created)? // TODO: Can GCC explicitly mark classes as abstract (no instances can be created)?
@ -38,7 +40,7 @@
// Some portability macros :) // Some portability macros :)
#define stricmp strcasecmp #define stricmp strcasecmp
#define FORMATSTRING(formatIndex,va_argsIndex) #define FORMATSTRING(formatIndex, va_argsIndex)
#else #else
@ -61,7 +63,7 @@
#define ALIGN_16 #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 #endif

View File

@ -9,18 +9,22 @@ include_directories ("${PROJECT_SOURCE_DIR}")
if(UNIX) if(UNIX)
add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/basic_lua.h add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/basic_lua.h
COMMAND xxd -i lua/basic.lua >basic_lua.h COMMAND xxd -i lua/basic.lua | sed 's/unsigned char/static const unsigned char/g' >basic_lua.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/
DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/basic.lua) DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/basic.lua)
add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/enumerate_lua.h add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/enumerate_lua.h
COMMAND xxd -i lua/enumerate.lua >enumerate_lua.h COMMAND xxd -i lua/enumerate.lua | sed 's/unsigned char/static const unsigned char/g' >enumerate_lua.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/
DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/enumerate.lua) DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/enumerate.lua)
add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/function_lua.h add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/function_lua.h
COMMAND xxd -i lua/function.lua >function_lua.h COMMAND xxd -i lua/function.lua | sed 's/unsigned char/static const unsigned char/g' >function_lua.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/
DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/function.lua) DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/function.lua)
set_property(SOURCE src/bin/toluabind.c APPEND PROPERTY OBJECT_DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/enumerate_lua.h ${PROJECT_SOURCE_DIR}/src/bin/basic_lua.h ${PROJECT_SOURCE_DIR}/src/bin/function_lua.h) add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/src/bin/declaration_lua.h
COMMAND xxd -i lua/declaration.lua | sed 's/unsigned char/static const unsigned char/g' >declaration_lua.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bin/
DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/lua/declaration.lua)
set_property(SOURCE src/bin/toluabind.c APPEND PROPERTY OBJECT_DEPENDS ${PROJECT_SOURCE_DIR}/src/bin/enumerate_lua.h ${PROJECT_SOURCE_DIR}/src/bin/basic_lua.h ${PROJECT_SOURCE_DIR}/src/bin/function_lua.h ${PROJECT_SOURCE_DIR}/src/bin/declaration_lua.h)
message(hello) message(hello)
endif() endif()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
unsigned char lua_enumerate_lua[] = { static const unsigned char lua_enumerate_lua[] = {
0x2d, 0x2d, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x3a, 0x20, 0x65, 0x6e, 0x2d, 0x2d, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x3a, 0x20, 0x65, 0x6e,
0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x73, 0x0a, 0x2d, 0x2d, 0x20, 0x57, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e,
@ -103,179 +103,193 @@ unsigned char lua_enumerate_lua[] = {
0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x0a, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74,
0x28, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x2e, 0x22, 0x7d, 0x22, 0x2e, 0x28, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x2e, 0x2e, 0x22, 0x7d, 0x22, 0x2e,
0x2e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x2e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
0x0a, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x6f, 0x75, 0x74, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x6d,
0x70, 0x75, 0x74, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x69, 0x74, 0x65, 0x6e, 0x75, 0x6d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74,
0x7b, 0x7d, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x79, 0x70, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x20, 0x6f,
0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x63, 0x6f, 0x64, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x69, 0x6e, 0x74, 0x20, 0x74,
0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x69, 0x73, 0x22, 0x20, 0x2e, 0x2e, 0x20,
0x6c, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28,
0x65, 0x3a, 0x73, 0x75, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x28, 0x29, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x22, 0x3a, 0x3a, 0x22, 0x2c, 0x22, 0x5f,
0x0a, 0x09, 0x69, 0x66, 0x20, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x22, 0x29, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x20, 0x28, 0x6c, 0x75, 0x61,
0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x20, 0x4c, 0x2c, 0x20, 0x69,
0x73, 0x5b, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x64,
0x20, 0x7e, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x65, 0x66, 0x2c, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x45, 0x72,
0x0a, 0x09, 0x09, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x6f, 0x72, 0x6f, 0x72, 0x2a, 0x20, 0x65, 0x72, 0x72, 0x29, 0x3b, 0x22, 0x29,
0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61,
0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x6c, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x65, 0x6e, 0x75,
0x20, 0x31, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x2d, 0x2d, 0x20,
0x22, 0x69, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x69, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72,
0x73, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
0x61, 0x6d, 0x65, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x20, 0x28, 0x6c, 0x75, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x75,
0x61, 0x5f, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x20, 0x4c, 0x2c, 0x20, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x3a, 0x73, 0x75, 0x70, 0x63, 0x6f,
0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x64, 0x65, 0x20, 0x28, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x5f, 0x67,
0x64, 0x65, 0x66, 0x2c, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x45, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
0x72, 0x72, 0x6f, 0x72, 0x2a, 0x20, 0x65, 0x72, 0x72, 0x29, 0x22, 0x29, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x73, 0x65, 0x6c, 0x66, 0x2e,
0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x69, 0x6c,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x5f, 0x67, 0x6c, 0x6f,
0x62, 0x61, 0x6c, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x65,
0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x61,
0x6d, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x09, 0x09, 0x6f, 0x75,
0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x69, 0x6e, 0x74, 0x20, 0x74, 0x6f,
0x6c, 0x75, 0x61, 0x5f, 0x69, 0x73, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x73,
0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73,
0x65, 0x6c, 0x66, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x22, 0x3a, 0x3a,
0x22, 0x2c, 0x22, 0x5f, 0x22, 0x29, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x20,
0x28, 0x6c, 0x75, 0x61, 0x5f, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x20,
0x4c, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x2c, 0x20, 0x69,
0x6e, 0x74, 0x20, 0x64, 0x65, 0x66, 0x2c, 0x20, 0x74, 0x6f, 0x6c, 0x75,
0x61, 0x5f, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x2a, 0x20, 0x65, 0x72, 0x72,
0x29, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
0x28, 0x22, 0x7b, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70,
0x75, 0x74, 0x28, 0x22, 0x69, 0x66, 0x20, 0x28, 0x21, 0x74, 0x6f, 0x6c,
0x75, 0x61, 0x5f, 0x69, 0x73, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28,
0x4c, 0x2c, 0x6c, 0x6f, 0x2c, 0x64, 0x65, 0x66, 0x2c, 0x65, 0x72, 0x72,
0x29, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x3b,
0x22, 0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28,
0x22, 0x69, 0x66, 0x20, 0x28, 0x21, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x22, 0x6c, 0x75, 0x61, 0x5f, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20,
0x69, 0x73, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x4c, 0x2c, 0x6c, 0x76, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f,
0x6f, 0x2c, 0x64, 0x65, 0x66, 0x2c, 0x65, 0x72, 0x72, 0x29, 0x29, 0x20, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x4c, 0x2c, 0x6c,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x3b, 0x22, 0x29, 0x0a, 0x6f, 0x2c, 0x64, 0x65, 0x66, 0x29, 0x3b, 0x22, 0x29, 0x0a, 0x09, 0x09,
0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x69, 0x6e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x72, 0x65, 0x74, 0x75,
0x74, 0x20, 0x76, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x6c, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x20, 0x3e, 0x3d, 0x20, 0x22, 0x20,
0x61, 0x5f, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x4c, 0x2e, 0x2e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x69, 0x6e, 0x20,
0x2c, 0x6c, 0x6f, 0x2c, 0x64, 0x65, 0x66, 0x29, 0x3b, 0x22, 0x29, 0x0a, 0x2e, 0x2e, 0x20, 0x22, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x76, 0x61,
0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x72, 0x65,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x20, 0x3e, 0x3d, 0x20,
0x22, 0x20, 0x2e, 0x2e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x6d, 0x69,
0x6e, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x20, 0x26, 0x26, 0x20, 0x76, 0x61,
0x6c, 0x20, 0x3c, 0x3d, 0x20, 0x22, 0x20, 0x2e, 0x2e, 0x73, 0x65, 0x6c, 0x6c, 0x20, 0x3c, 0x3d, 0x20, 0x22, 0x20, 0x2e, 0x2e, 0x73, 0x65, 0x6c,
0x66, 0x2e, 0x6d, 0x61, 0x78, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x3b, 0x22, 0x66, 0x2e, 0x6d, 0x61, 0x78, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x2e, 0x30,
0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x28, 0x22, 0x3b, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
0x7d, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x28, 0x22, 0x7d, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x65,
0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63,
0x72, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x74, 0x6f, 0x72, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x28, 0x74, 0x20, 0x5f, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20,
0x2c, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x73, 0x28, 0x74, 0x2c, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a,
0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x20, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c,
0x74, 0x2c, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x65, 0x28, 0x74, 0x2c, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x75,
0x72, 0x61, 0x74, 0x65, 0x29, 0x0a, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x29, 0x0a, 0x20, 0x61, 0x70, 0x70,
0x64, 0x28, 0x74, 0x29, 0x0a, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x64, 0x28, 0x74, 0x29, 0x0a, 0x20, 0x61, 0x70, 0x70, 0x65,
0x65, 0x6e, 0x75, 0x6d, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x20, 0x69, 0x66, 0x6e, 0x64, 0x65, 0x6e, 0x75, 0x6d, 0x28, 0x74, 0x29, 0x0a, 0x09, 0x20,
0x20, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x69, 0x66, 0x20, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x61,
0x20, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x7e, 0x3d, 0x20, 0x6e, 0x64, 0x20, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x7e,
0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09,
0x20, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x69, 0x66, 0x20, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x7e, 0x3d,
0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x56, 0x61, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09,
0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x74, 0x2e, 0x6e,
0x65, 0x2e, 0x2e, 0x22, 0x20, 0x22, 0x2e, 0x2e, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x2e, 0x22, 0x20, 0x22, 0x2e, 0x2e, 0x76, 0x61,
0x61, 0x6d, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6c, 0x73,
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x73, 0x20, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e,
0x3d, 0x20, 0x67, 0x65, 0x74, 0x63, 0x75, 0x72, 0x72, 0x6e, 0x61, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x63, 0x75, 0x72, 0x72, 0x6e,
0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x29, 0x0a, 0x09,
0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x28, 0x22, 0x56, 0x61, 0x72, 0x09, 0x09, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x28, 0x22, 0x56,
0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x22, 0x2e, 0x2e, 0x6e, 0x73, 0x2e, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x22, 0x2e, 0x2e, 0x6e,
0x2e, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x2e, 0x22, 0x20, 0x73, 0x2e, 0x2e, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x2e,
0x6f, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3c, 0x61, 0x6e, 0x6f, 0x22, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3c, 0x61,
0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x3e, 0x6e, 0x6f, 0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x20, 0x65, 0x6e, 0x75,
0x20, 0x69, 0x73, 0x20, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x64, 0x6d, 0x3e, 0x20, 0x69, 0x73, 0x20, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72,
0x20, 0x61, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x2d, 0x6f, 0x6e, 0x6c, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x2d, 0x6f,
0x79, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x6c, 0x79, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x56, 0x61, 0x72,
0x62, 0x6c, 0x65, 0x28, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61, 0x5f, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x22, 0x74, 0x6f, 0x6c, 0x75, 0x61,
0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x69, 0x6e,
0x22, 0x2e, 0x2e, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x74, 0x20, 0x22, 0x2e, 0x2e, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64,
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x0a, 0x09, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x72,
0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43,
0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x0a, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x63, 0x75, 0x72,
0x09, 0x20, 0x69, 0x66, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x72, 0x0a, 0x09, 0x20, 0x69, 0x66, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e,
0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x74, 0x2e, 0x61,
0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x65,
0x2e, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6e, 0x74, 0x2e, 0x63, 0x75, 0x72, 0x72, 0x5f, 0x6d, 0x65, 0x6d, 0x62,
0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x0a, 0x09, 0x09, 0x74, 0x2e, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x0a, 0x09, 0x09,
0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x74, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x61, 0x63, 0x63,
0x73, 0x20, 0x3d, 0x20, 0x74, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x3a, 0x63, 0x68, 0x65, 0x63,
0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x6b, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x63, 0x63,
0x73, 0x28, 0x29, 0x0a, 0x09, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x73, 0x28, 0x29, 0x0a, 0x09, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x0a, 0x65, 0x6e,
0x0a, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72,
0x74, 0x6f, 0x72, 0x0a, 0x2d, 0x2d, 0x20, 0x45, 0x78, 0x70, 0x65, 0x63, 0x75, 0x63, 0x74, 0x6f, 0x72, 0x0a, 0x2d, 0x2d, 0x20, 0x45, 0x78, 0x70,
0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x63, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x67, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x69,
0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x65,
0x74, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x72, 0x61, 0x74, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x0a, 0x66, 0x75,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45, 0x6e, 0x75, 0x6d, 0x65,
0x74, 0x65, 0x20, 0x28, 0x6e, 0x2c, 0x62, 0x2c, 0x76, 0x61, 0x72, 0x6e, 0x72, 0x61, 0x74, 0x65, 0x20, 0x28, 0x6e, 0x2c, 0x62, 0x2c, 0x76, 0x61,
0x61, 0x6d, 0x65, 0x29, 0x0a, 0x09, 0x62, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x09, 0x62, 0x20, 0x3d, 0x20,
0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x62, 0x2c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28,
0x20, 0x22, 0x2c, 0x5b, 0x25, 0x73, 0x5c, 0x6e, 0x5d, 0x2a, 0x7d, 0x22, 0x62, 0x2c, 0x20, 0x22, 0x2c, 0x5b, 0x25, 0x73, 0x5c, 0x6e, 0x5d, 0x2a,
0x2c, 0x20, 0x22, 0x5c, 0x6e, 0x7d, 0x22, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x7d, 0x22, 0x2c, 0x20, 0x22, 0x5c, 0x6e, 0x7d, 0x22, 0x29, 0x20, 0x2d,
0x65, 0x6c, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x6c, 0x61, 0x2d, 0x20, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x20,
0x73, 0x74, 0x20, 0x27, 0x2c, 0x27, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x27, 0x2c, 0x27, 0x0a, 0x09, 0x6c, 0x6f,
0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69,
0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x62, 0x2c, 0x32, 0x2c, 0x2d, 0x74, 0x28, 0x73, 0x74, 0x72, 0x73, 0x75, 0x62, 0x28, 0x62, 0x2c, 0x32,
0x32, 0x29, 0x2c, 0x27, 0x2c, 0x27, 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x65, 0x2c, 0x2d, 0x32, 0x29, 0x2c, 0x27, 0x2c, 0x27, 0x29, 0x20, 0x2d, 0x2d,
0x6c, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x62, 0x72, 0x61, 0x20, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x62,
0x63, 0x65, 0x73, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x72, 0x61, 0x63, 0x65, 0x73, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
0x20, 0x3d, 0x20, 0x31, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61,
0x65, 0x20, 0x3d, 0x20, 0x7b, 0x6e, 0x3d, 0x30, 0x7d, 0x0a, 0x09, 0x6c, 0x6c, 0x20, 0x65, 0x20, 0x3d, 0x20, 0x7b, 0x6e, 0x3d, 0x30, 0x7d, 0x0a,
0x6f, 0x63, 0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x20, 0x30, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x69, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
0x6e, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x6d, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x09, 0x6c, 0x6f, 0x63,
0x20, 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x09, 0x77, 0x68, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x30, 0x0a, 0x09,
0x69, 0x6c, 0x65, 0x20, 0x74, 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x5b, 0x69, 0x5d, 0x20, 0x64,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x74, 0x20, 0x3d, 0x6f, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x74,
0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x74, 0x5b, 0x69, 0x5d, 0x2c, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x74, 0x5b, 0x69,
0x27, 0x3d, 0x27, 0x29, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x64, 0x69, 0x73, 0x5d, 0x2c, 0x27, 0x3d, 0x27, 0x29, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x64,
0x63, 0x61, 0x72, 0x64, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x20, 0x69, 0x6e, 0x69, 0x74, 0x69,
0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x09, 0x09, 0x65, 0x2e, 0x6e, 0x61, 0x6c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x09, 0x09, 0x65,
0x20, 0x3d, 0x20, 0x65, 0x2e, 0x6e, 0x20, 0x2b, 0x20, 0x31, 0x0a, 0x09, 0x2e, 0x6e, 0x20, 0x3d, 0x20, 0x65, 0x2e, 0x6e, 0x20, 0x2b, 0x20, 0x31,
0x09, 0x65, 0x5b, 0x65, 0x2e, 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x74, 0x0a, 0x09, 0x09, 0x65, 0x5b, 0x65, 0x2e, 0x6e, 0x5d, 0x20, 0x3d, 0x20,
0x5b, 0x31, 0x5d, 0x0a, 0x09, 0x09, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x20, 0x74, 0x74, 0x5b, 0x31, 0x5d, 0x0a, 0x09, 0x09, 0x74, 0x74, 0x5b, 0x32,
0x3d, 0x20, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
0x74, 0x5b, 0x32, 0x5d, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x74, 0x28, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x66,
0x74, 0x5b, 0x32, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x20, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x69,
0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x74, 0x74, 0x5b, 0x32, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x74, 0x74,
0x5d, 0x20, 0x3d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x09, 0x09, 0x5b, 0x32, 0x5d, 0x20, 0x3d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a,
0x65, 0x6e, 0x64, 0x20, 0x0a, 0x20, 0x20, 0x09, 0x09, 0x76, 0x61, 0x6c, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x20, 0x0a, 0x20, 0x20, 0x09, 0x09, 0x76,
0x75, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x20, 0x2b, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d,
0x20, 0x31, 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x20, 0x2b, 0x20, 0x31, 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x64, 0x76, 0x61,
0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6c, 0x65,
0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x09, 0x09, 0x69, 0x63, 0x74, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x0a, 0x09,
0x66, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x20, 0x3e, 0x20, 0x6d, 0x61, 0x09, 0x69, 0x66, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x20, 0x3e, 0x20,
0x78, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x6d, 0x61, 0x6d, 0x61, 0x78, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09,
0x78, 0x20, 0x3d, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x0a, 0x09, 0x09, 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x0a,
0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x74, 0x74, 0x5b, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x74,
0x32, 0x5d, 0x20, 0x3c, 0x20, 0x6d, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x74, 0x5b, 0x32, 0x5d, 0x20, 0x3c, 0x20, 0x6d, 0x69, 0x6e, 0x20, 0x74,
0x6e, 0x0a, 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x20, 0x3d,
0x74, 0x5b, 0x32, 0x5d, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x20, 0x74, 0x74, 0x5b, 0x32, 0x5d, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64,
0x09, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x09, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x31, 0x0a, 0x09,
0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x74, 0x20, 0x6c, 0x75, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x74, 0x20,
0x61, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x0a, 0x09, 0x69, 0x20, 0x20, 0x6c, 0x75, 0x61, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x0a, 0x09, 0x69,
0x3d, 0x20, 0x31, 0x0a, 0x09, 0x65, 0x2e, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x0a, 0x09, 0x65, 0x2e, 0x6c, 0x6e, 0x61,
0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6d, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x09, 0x6c, 0x6f,
0x6c, 0x20, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x63, 0x75, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x73, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74,
0x72, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x28, 0x63, 0x75, 0x72, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
0x29, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x65, 0x5b, 0x69, 0x65, 0x28, 0x29, 0x0a, 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x65,
0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63,
0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x65, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74,
0x5b, 0x69, 0x5d, 0x2c, 0x27, 0x40, 0x27, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x28, 0x65, 0x5b, 0x69, 0x5d, 0x2c, 0x27, 0x40, 0x27, 0x29, 0x0a, 0x09,
0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x5b, 0x31, 0x5d, 0x0a, 0x09, 0x09, 0x65, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x5b, 0x31, 0x5d,
0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x74, 0x5b, 0x32, 0x5d, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x74, 0x5b,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x74, 0x5b, 0x32, 0x32, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x74,
0x5d, 0x20, 0x3d, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x72, 0x65, 0x6e, 0x5b, 0x32, 0x5d, 0x20, 0x3d, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x72,
0x61, 0x6d, 0x69, 0x6e, 0x67, 0x28, 0x74, 0x5b, 0x31, 0x5d, 0x29, 0x0a, 0x65, 0x6e, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x28, 0x74, 0x5b, 0x31, 0x5d,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x2e, 0x6c, 0x6e, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x2e,
0x61, 0x6d, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x5b, 0x6c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20,
0x32, 0x5d, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x5b, 0x31, 0x5d, 0x0a, 0x09, 0x74, 0x5b, 0x32, 0x5d, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x5b, 0x31, 0x5d,
0x09, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x6e, 0x75, 0x0a, 0x09, 0x09, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65,
0x6d, 0x73, 0x5b, 0x20, 0x6e, 0x73, 0x2e, 0x2e, 0x65, 0x5b, 0x69, 0x5d, 0x6e, 0x75, 0x6d, 0x73, 0x5b, 0x20, 0x6e, 0x73, 0x2e, 0x2e, 0x65, 0x5b,
0x20, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x6e, 0x73, 0x2e, 0x2e, 0x65, 0x5b, 0x69, 0x5d, 0x20, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x6e, 0x73, 0x2e, 0x2e,
0x69, 0x5d, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20, 0x69, 0x2b, 0x65, 0x5b, 0x69, 0x5d, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x20, 0x3d, 0x20,
0x31, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x2e, 0x6e, 0x61, 0x69, 0x2b, 0x31, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x2e,
0x6d, 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x0a, 0x09, 0x65, 0x2e, 0x6d, 0x69, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x0a, 0x09, 0x65, 0x2e,
0x6e, 0x20, 0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x0a, 0x09, 0x65, 0x2e, 0x6d, 0x6d, 0x69, 0x6e, 0x20, 0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x0a, 0x09, 0x65,
0x61, 0x78, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x0a, 0x09, 0x69, 0x66, 0x2e, 0x6d, 0x61, 0x78, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x0a, 0x09,
0x20, 0x6e, 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x69, 0x66, 0x20, 0x6e, 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74,
0x6e, 0x0a, 0x09, 0x09, 0x54, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x28, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x73,
0x22, 0x69, 0x6e, 0x74, 0x20, 0x22, 0x2e, 0x2e, 0x6e, 0x29, 0x0a, 0x09, 0x5b, 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09,
0x09, 0x5f, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x09, 0x54, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66, 0x28, 0x22, 0x69, 0x6e,
0x6e, 0x73, 0x5b, 0x6e, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x74, 0x6f, 0x6c, 0x74, 0x20, 0x22, 0x2e, 0x2e, 0x6e, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64,
0x75, 0x61, 0x5f, 0x69, 0x73, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x6e, 0x0a, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x45, 0x6e,
0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x28, 0x65, 0x2c, 0x20, 0x76,
0x20, 0x5f, 0x45, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x65, 0x28, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
0x65, 0x2c, 0x20, 0x76, 0x61, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x0a
0x65, 0x6e, 0x64, 0x0a, 0x0a
}; };
unsigned int lua_enumerate_lua_len = 3329; unsigned int lua_enumerate_lua_len = 3493;

File diff suppressed because it is too large Load Diff

View File

@ -67,6 +67,8 @@ _global_enums = {}
-- List of auto renaming -- List of auto renaming
_renaming = {} _renaming = {}
_enums = {}
function appendrenaming (s) function appendrenaming (s)
local b,e,old,new = strfind(s,"%s*(.-)%s*@%s*(.-)%s*$") local b,e,old,new = strfind(s,"%s*(.-)%s*@%s*(.-)%s*$")
if not b then if not b then
@ -146,6 +148,11 @@ function typevar(type)
end end
end end
-- is enum
function isenumtype (type)
return _enums[type]
end
-- check if basic type -- check if basic type
function isbasic (type) function isbasic (type)
local t = gsub(type,'const ','') local t = gsub(type,'const ','')
@ -383,6 +390,7 @@ end
_push_functions = {} _push_functions = {}
_is_functions = {} _is_functions = {}
_enums = {}
_to_functions = {} _to_functions = {}
_base_push_functions = {} _base_push_functions = {}
@ -411,5 +419,8 @@ function get_to_function(t)
end end
function get_is_function(t) function get_is_function(t)
if _enums[t] then
return "tolua_is" .. t
end
return _is_functions[t] or search_base(t, _base_is_functions) or "tolua_isusertype" return _is_functions[t] or search_base(t, _base_is_functions) or "tolua_isusertype"
end end

View File

@ -227,6 +227,8 @@ function classDeclaration:outchecktype (narg)
--else --else
return '!tolua_istable(tolua_S,'..narg..',0,&tolua_err)' return '!tolua_istable(tolua_S,'..narg..',0,&tolua_err)'
--end --end
elseif isenumtype(self.type) ~= nil then
return '!tolua_is'..self.type..'(tolua_S,'..narg..','..def..',&tolua_err)'
elseif t then elseif t then
return '!tolua_is'..t..'(tolua_S,'..narg..','..def..',&tolua_err)' return '!tolua_is'..t..'(tolua_S,'..narg..','..def..',&tolua_err)'
else else

View File

@ -48,17 +48,21 @@ function classEnumerate:print (ident,close)
print(ident.."}"..close) print(ident.."}"..close)
end end
function emitenumprototype(type)
output("int tolua_is" .. string.gsub(type,"::","_") .. " (lua_State* L, int lo, int def, tolua_Error* err);")
end
_global_output_enums = {} _global_output_enums = {}
-- write support code -- write support code
function classEnumerate:supcode () function classEnumerate:supcode ()
if _global_output_enums[self.name] ~= nil then if _global_output_enums[self.name] == nil then
_global_output_enums[self.name] = 1 _global_output_enums[self.name] = 1
output("int tolua_is" .. self.name .. " (lua_State* L, int lo, int def, tolua_Error* err)") output("int tolua_is" .. string.gsub(self.name,"::","_") .. " (lua_State* L, int lo, int def, tolua_Error* err)")
output("{") output("{")
output("if (!tolua_isnumber(L,lo,def,err)) return 0;") output("if (!tolua_isnumber(L,lo,def,err)) return 0;")
output("int val = tolua_tonumber(L,lo,def);") output("lua_Number val = tolua_tonumber(L,lo,def);")
output("return val >= " .. self.min .. " && val <= " ..self.max .. ";") output("return val >= " .. self.min .. ".0 && val <= " ..self.max .. ".0;")
output("}") output("}")
end end
end end
@ -130,8 +134,8 @@ function Enumerate (n,b,varname)
e.min = min e.min = min
e.max = max e.max = max
if n ~= "" then if n ~= "" then
_enums[n] = true
Typedef("int "..n) Typedef("int "..n)
_is_functions[n] = "tolua_is" .. n
end end
return _Enumerate(e, varname) return _Enumerate(e, varname)
end end

View File

@ -54,6 +54,16 @@ function classFunction:supcode (local_constructor)
local nret = 0 -- number of returned values local nret = 0 -- number of returned values
local class = self:inclass() local class = self:inclass()
local _,_,static = strfind(self.mod,'^%s*(static)') local _,_,static = strfind(self.mod,'^%s*(static)')
-- prototypes for enum functions
if self.args[1].type ~= 'void' then
local i=1
while self.args[i] do
if isenumtype(self.args[i].type) then
emitenumprototype(self.args[i].type)
end
i = i+1
end
end
if class then if class then
if self.name == 'new' and self.parent.flags.pure_virtual then if self.name == 'new' and self.parent.flags.pure_virtual then

File diff suppressed because it is too large Load Diff

View File

@ -131,9 +131,6 @@ void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPo
void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ) void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
{ {
// DEBUG:
LOGD("LuaChunkStay: Chunk [%d, %d] is now available, calling the callback...", a_ChunkX, a_ChunkZ);
cPluginLua::cOperation Op(m_Plugin); cPluginLua::cOperation Op(m_Plugin);
Op().Call((int)m_OnChunkAvailable, a_ChunkX, a_ChunkZ); Op().Call((int)m_OnChunkAvailable, a_ChunkX, a_ChunkZ);
} }

View File

@ -689,9 +689,10 @@ void cLuaState::Push(void * a_Ptr)
ASSERT(IsValid()); ASSERT(IsValid());
// Investigate the cause of this - what is the callstack? // 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(); LogStackTrace();
ASSERT(!"A plain pointer should never be pushed on Lua stack");
lua_pushnil(m_LuaState); lua_pushnil(m_LuaState);
m_NumCurrentFunctionArgs += 1; 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:"); LOGWARNING("Stack trace:");
lua_Debug entry; lua_Debug entry;
int depth = 0; int depth = a_StartingDepth;
while (lua_getstack(a_LuaState, depth, &entry)) while (lua_getstack(a_LuaState, depth, &entry))
{ {
lua_getinfo(a_LuaState, "Sln", &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) int cLuaState::ReportFnCallErrors(lua_State * a_LuaState)
{ {
LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1)); 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 return 1; // We left the error message on the stack as the return value
} }

View File

@ -200,7 +200,7 @@ public:
void Push(const HTTPTemplateRequest * a_Request); void Push(const HTTPTemplateRequest * a_Request);
void Push(cTNTEntity * a_TNTEntity); void Push(cTNTEntity * a_TNTEntity);
void Push(Vector3i * a_Vector); void Push(Vector3i * a_Vector);
NORETURNDEBUG void Push(void * a_Ptr); void Push(void * a_Ptr);
void Push(cHopperEntity * a_Hopper); void Push(cHopperEntity * a_Hopper);
void Push(cBlockEntity * a_BlockEntity); void Push(cBlockEntity * a_BlockEntity);
@ -868,10 +868,10 @@ public:
static bool ReportErrors(lua_State * a_LuaState, int status); static bool ReportErrors(lua_State * a_LuaState, int status);
/** Logs all items in the current stack trace to the server console */ /** 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 */ /** 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 */ /** Returns the type of the item on the specified position in the stack */
AString GetTypeText(int a_StackPos); AString GetTypeText(int a_StackPos);

Binary file not shown.

View File

@ -138,6 +138,12 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
break; break;
} }
case E_ITEM_FIRE_CHARGE:
{
// TODO: Spawn fireball entity
break;
}
default: default:
{ {
DropFromSlot(a_Chunk, a_SlotNum); DropFromSlot(a_Chunk, a_SlotNum);

View File

@ -219,7 +219,7 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
Vector3f EntityPos = a_Entity->GetPosition(); Vector3f EntityPos = a_Entity->GetPosition();
Vector3f BlockPos(m_Pos.x + 0.5f, (float)m_Pos.y + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards Vector3f BlockPos(m_Pos.x + 0.5f, (float)m_Pos.y + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards
float Distance = (EntityPos - BlockPos).Length(); double Distance = (EntityPos - BlockPos).Length();
if (Distance < 0.5) if (Distance < 0.5)
{ {

View File

@ -853,9 +853,17 @@ enum eExplosionSource
esWitherSkullBlue, esWitherSkullBlue,
esWitherBirth, esWitherBirth,
esPlugin, esPlugin,
} ;
// Obsolete constants, kept for compatibility, will be removed after some time:
esCreeper = esMonster,
enum eShrapnelLevel
{
slNone,
slGravityAffectedOnly,
slAll
} ; } ;
// tolua_end // tolua_end

View File

@ -93,6 +93,7 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_IRON_BARS ].m_SpreadLightFalloff = 1; ms_Info[E_BLOCK_IRON_BARS ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_IRON_DOOR ].m_SpreadLightFalloff = 1; ms_Info[E_BLOCK_IRON_DOOR ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_LEAVES ].m_SpreadLightFalloff = 1; ms_Info[E_BLOCK_LEAVES ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1; ms_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1; ms_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1; ms_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1;

63
src/Blocks/BlockAnvil.h Normal file
View File

@ -0,0 +1,63 @@
#pragma once
#include "BlockHandler.h"
#include "../World.h"
#include "../Entities/Player.h"
class cBlockAnvilHandler :
public cBlockHandler
{
public:
cBlockAnvilHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2));
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
a_BlockType = m_BlockType;
int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 0.5) & 0x3;
int RawMeta = a_BlockMeta >> 2;
Direction++;
Direction %= 4;
switch (Direction)
{
case 0: a_BlockMeta = 0x2 | RawMeta << 2; break;
case 1: a_BlockMeta = 0x3 | RawMeta << 2; break;
case 2: a_BlockMeta = 0x0 | RawMeta << 2; break;
case 3: a_BlockMeta = 0x1 | RawMeta << 2; break;
default:
{
return false;
}
}
return true;
}
virtual bool IsUseable() override
{
return true;
}
} ;

View File

@ -51,6 +51,49 @@ void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInt
class cTimeFastForwardTester :
public cPlayerListCallback
{
virtual bool Item(cPlayer * a_Player) override
{
if (!a_Player->IsInBed())
{
return true;
}
return false;
}
};
class cPlayerBedStateUnsetter :
public cPlayerListCallback
{
public:
cPlayerBedStateUnsetter(Vector3i a_Position, cWorldInterface & a_WorldInterface) :
m_Position(a_Position), m_WorldInterface(a_WorldInterface)
{
}
virtual bool Item(cPlayer * a_Player) override
{
a_Player->SetIsInBed(false);
m_WorldInterface.GetBroadcastManager().BroadcastEntityAnimation(*a_Player, 2);
return false;
}
private:
Vector3i m_Position;
cWorldInterface & m_WorldInterface;
};
void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{ {
if (a_WorldInterface.GetDimension() != dimOverworld) if (a_WorldInterface.GetDimension() != dimOverworld)
@ -69,6 +112,8 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
} }
else else
{ {
Vector3i PillowDirection(0, 0, 0);
if (Meta & 0x8) if (Meta & 0x8)
{ {
// Is pillow // Is pillow
@ -77,16 +122,30 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
else else
{ {
// Is foot end // Is foot end
Vector3i Direction = MetaDataToDirection( Meta & 0x7 ); VERIFY((Meta & 0x4) != 0x4); // Occupied flag should never be set, else our compilator (intended) is broken
if (a_ChunkInterface.GetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
PillowDirection = MetaDataToDirection(Meta & 0x7);
if (a_ChunkInterface.GetBlock(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
{ {
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z); a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z);
} }
} }
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, (Meta | (1 << 2)));
} a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x4); // Where 0x4 = occupied bit
a_Player->SetIsInBed(true);
} else {
cTimeFastForwardTester Tester;
if (a_WorldInterface.ForEachPlayer(Tester))
{
cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_WorldInterface);
a_WorldInterface.ForEachPlayer(Unsetter);
a_WorldInterface.SetTimeOfDay(0);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0xB); // Where 0xB = 1011, and zero is to make sure 'occupied' bit is always unset
}
}
}
else
{
a_Player->SendMessageFailure("You can only sleep at night"); a_Player->SendMessageFailure("You can only sleep at night");
} }
} }

55
src/Blocks/BlockCake.h Normal file
View File

@ -0,0 +1,55 @@
#pragma once
#include "BlockHandler.h"
class cBlockCakeHandler :
public cBlockHandler
{
public:
cBlockCakeHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
{
}
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (!a_Player->Feed(2, 0.1))
{
return;
}
if (Meta >= 5)
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
}
else
{
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta + 1);
}
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Give nothing
}
virtual bool IsUseable(void) override
{
return true;
}
virtual const char * GetStepSound(void) override
{
return "step.cloth";
}
} ;

View File

@ -6,10 +6,12 @@
#include "../Root.h" #include "../Root.h"
#include "../Bindings/PluginManager.h" #include "../Bindings/PluginManager.h"
#include "../Chunk.h" #include "../Chunk.h"
#include "BlockAnvil.h"
#include "BlockBed.h" #include "BlockBed.h"
#include "BlockBrewingStand.h" #include "BlockBrewingStand.h"
#include "BlockButton.h" #include "BlockButton.h"
#include "BlockCactus.h" #include "BlockCactus.h"
#include "BlockCake.h"
#include "BlockCarpet.h" #include "BlockCarpet.h"
#include "BlockCauldron.h" #include "BlockCauldron.h"
#include "BlockChest.h" #include "BlockChest.h"
@ -85,12 +87,14 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
// Block handlers, alphabetically sorted: // Block handlers, alphabetically sorted:
case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType); case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType); case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType);
case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BREWING_STAND: return new cBlockBrewingStandHandler (a_BlockType); case E_BLOCK_BREWING_STAND: return new cBlockBrewingStandHandler (a_BlockType);
case E_BLOCK_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BROWN_MUSHROOM: return new cBlockMushroomHandler (a_BlockType); case E_BLOCK_BROWN_MUSHROOM: return new cBlockMushroomHandler (a_BlockType);
case E_BLOCK_CACTUS: return new cBlockCactusHandler (a_BlockType); case E_BLOCK_CACTUS: return new cBlockCactusHandler (a_BlockType);
case E_BLOCK_CAKE: return new cBlockCakeHandler (a_BlockType);
case E_BLOCK_CARROTS: return new cBlockCropsHandler (a_BlockType); case E_BLOCK_CARROTS: return new cBlockCropsHandler (a_BlockType);
case E_BLOCK_CARPET: return new cBlockCarpetHandler (a_BlockType); case E_BLOCK_CARPET: return new cBlockCarpetHandler (a_BlockType);
case E_BLOCK_CAULDRON: return new cBlockCauldronHandler (a_BlockType); case E_BLOCK_CAULDRON: return new cBlockCauldronHandler (a_BlockType);

View File

@ -16,6 +16,7 @@
{ \ { \
case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \ case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \
case E_BLOCK_LOG: return true; \ case E_BLOCK_LOG: return true; \
case E_BLOCK_NEW_LOG: return true; \
} }
bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ); bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ);

View File

@ -39,6 +39,7 @@ public:
case E_BLOCK_CACTUS: case E_BLOCK_CACTUS:
case E_BLOCK_ICE: case E_BLOCK_ICE:
case E_BLOCK_LEAVES: case E_BLOCK_LEAVES:
case E_BLOCK_NEW_LEAVES:
case E_BLOCK_AIR: case E_BLOCK_AIR:
{ {
return false; return false;

View File

@ -73,7 +73,7 @@ public:
/// Returns true if the specified block type is good for vines to attach to /// Returns true if the specified block type is good for vines to attach to
static bool IsBlockAttachable(BLOCKTYPE a_BlockType) static bool IsBlockAttachable(BLOCKTYPE a_BlockType)
{ {
return (a_BlockType == E_BLOCK_LEAVES) || cBlockInfo::IsSolid(a_BlockType); return (a_BlockType == E_BLOCK_LEAVES) || (a_BlockType == E_BLOCK_NEW_LEAVES) || cBlockInfo::IsSolid(a_BlockType);
} }

View File

@ -5,6 +5,7 @@ class cBroadcastInterface
{ {
public: public:
virtual void BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0; virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
virtual void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0; virtual void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) = 0;
}; };

View File

@ -27,7 +27,13 @@ public:
/** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */ /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) = 0; virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) = 0;
/** Sends the block on those coords to the player */ /** Sends the block on those coords to the player */
virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer * a_Player) = 0; virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer * a_Player) = 0;
/** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
virtual bool ForEachPlayer(cItemCallback<cPlayer> & a_Callback) = 0;
virtual void SetTimeOfDay(Int64 a_TimeOfDay) = 0;
}; };

View File

@ -58,6 +58,9 @@ if (NOT MSVC)
Entities/Player.h Entities/Player.h
Entities/ProjectileEntity.h Entities/ProjectileEntity.h
Entities/TNTEntity.h Entities/TNTEntity.h
Entities/ExpOrb.h
Entities/HangingEntity.h
Entities/ItemFrame.h
Generating/ChunkDesc.h Generating/ChunkDesc.h
Group.h Group.h
Inventory.h Inventory.h

View File

@ -1376,8 +1376,9 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks)
break; break;
} }
case E_BLOCK_LEAVES: case E_BLOCK_LEAVES:
case E_BLOCK_NEW_LEAVES:
{ {
if (itr->BlockType == E_BLOCK_LOG) if ((itr->BlockType == E_BLOCK_LOG) || (itr->BlockType == E_BLOCK_NEW_LOG))
{ {
Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta); Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta);
} }
@ -1784,57 +1785,73 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
BLOCKTYPE Block = area.GetBlockType(bx + x, by + y, bz + z); BLOCKTYPE Block = area.GetBlockType(bx + x, by + y, bz + z);
switch (Block) switch (Block)
{ {
case E_BLOCK_TNT: case E_BLOCK_TNT:
{
// Activate the TNT, with a random fuse between 10 to 30 game ticks
double FuseTime = (double)(10 + m_World->GetTickRandomNumber(20)) / 20;
m_World->SpawnPrimedTNT(a_BlockX + x + 0.5, a_BlockY + y + 0.5, a_BlockZ + z + 0.5, FuseTime);
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR);
a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
break;
}
case E_BLOCK_OBSIDIAN:
case E_BLOCK_BEDROCK:
case E_BLOCK_WATER:
case E_BLOCK_LAVA:
{
// These blocks are not affected by explosions
break;
}
case E_BLOCK_STATIONARY_WATER:
{
// Turn into simulated water:
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_WATER);
break;
}
case E_BLOCK_STATIONARY_LAVA:
{
// Turn into simulated lava:
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_LAVA);
break;
}
case E_BLOCK_AIR:
{
// No pickups for air
break;
}
default:
{
if (m_World->GetTickRandomNumber(100) <= 25) // 25% chance of pickups
{ {
cItems Drops; // Activate the TNT, with a random fuse between 10 to 30 game ticks
cBlockHandler * Handler = BlockHandler(Block); int FuseTime = 10 + m_World->GetTickRandomNumber(20);
m_World->SpawnPrimedTNT(a_BlockX + x + 0.5, a_BlockY + y + 0.5, a_BlockZ + z + 0.5, FuseTime);
Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc. area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR);
m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
break;
}
case E_BLOCK_OBSIDIAN:
case E_BLOCK_BEDROCK:
case E_BLOCK_WATER:
case E_BLOCK_LAVA:
{
// These blocks are not affected by explosions
break;
}
case E_BLOCK_STATIONARY_WATER:
{
// Turn into simulated water:
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_WATER);
break;
}
case E_BLOCK_STATIONARY_LAVA:
{
// Turn into simulated lava:
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_LAVA);
break;
}
case E_BLOCK_AIR:
{
// No pickups for air
break;
}
default:
{
if (m_World->GetTickRandomNumber(100) <= 25) // 25% chance of pickups
{
cItems Drops;
cBlockHandler * Handler = BlockHandler(Block);
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;
} }
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR);
a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
}
} // switch (BlockType) } // switch (BlockType)
} // for z } // for z
} // for y } // for y
@ -1846,11 +1863,10 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
public cEntityCallback public cEntityCallback
{ {
public: 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_bbTNT(a_bbTNT),
m_ExplosionPos(a_ExplosionPos), m_ExplosionPos(a_ExplosionPos),
m_ExplosionSize(a_ExplosionSize), m_ExplosionSize(a_ExplosionSize)
m_ExplosionSizeSq(a_ExplosionSizeSq)
{ {
} }
@ -1873,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 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 // Work out how far we are from the edge of the TNT's explosive effect
AbsoluteEntityPos -= m_ExplosionPos; AbsoluteEntityPos -= m_ExplosionPos;
AbsoluteEntityPos = MaxExplosionBoundary - AbsoluteEntityPos;
double FinalDamage = ((AbsoluteEntityPos.x + AbsoluteEntityPos.y + AbsoluteEntityPos.z) / 3) * m_ExplosionSize; // All to positive
FinalDamage = a_Entity->GetMaxHealth() - abs(FinalDamage); 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 // Clip damage values
if (FinalDamage > a_Entity->GetMaxHealth()) if (FinalDamage > a_Entity->GetMaxHealth())
@ -1888,7 +1906,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
else if (FinalDamage < 0) else if (FinalDamage < 0)
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); a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0);
} }
@ -1898,7 +1916,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
if (distance_explosion.SqrLength() < 4096.0) if (distance_explosion.SqrLength() < 4096.0)
{ {
distance_explosion.Normalize(); distance_explosion.Normalize();
distance_explosion *= m_ExplosionSizeSq; distance_explosion *= m_ExplosionSize * m_ExplosionSize;
a_Entity->AddSpeed(distance_explosion); a_Entity->AddSpeed(distance_explosion);
} }
@ -1910,14 +1928,13 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
cBoundingBox & m_bbTNT; cBoundingBox & m_bbTNT;
Vector3d m_ExplosionPos; Vector3d m_ExplosionPos;
int m_ExplosionSize; int m_ExplosionSize;
int m_ExplosionSizeSq;
}; };
cBoundingBox bbTNT(Vector3d(a_BlockX, a_BlockY, a_BlockZ), 0.5, 1); cBoundingBox bbTNT(Vector3d(a_BlockX, a_BlockY, a_BlockZ), 0.5, 1);
bbTNT.Expand(ExplosionSizeInt * 2, ExplosionSizeInt * 2, ExplosionSizeInt * 2); 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); ForEachEntity(TNTDamageCallback);
// Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391): // Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391):

View File

@ -290,6 +290,10 @@ inline AString BlockFaceToString(eBlockFace a_BlockFace)
case BLOCK_FACE_ZP: return "BLOCK_FACE_ZP"; case BLOCK_FACE_ZP: return "BLOCK_FACE_ZP";
case BLOCK_FACE_NONE: return "BLOCK_FACE_NONE"; case BLOCK_FACE_NONE: return "BLOCK_FACE_NONE";
} }
// clang optimisises this line away then warns that it has done so.
#if !defined(__clang__)
return Printf("Unknown BLOCK_FACE: %d", a_BlockFace);
#endif
} }
@ -529,16 +533,22 @@ enum eMessageType
// http://forum.mc-server.org/showthread.php?tid=1212 // http://forum.mc-server.org/showthread.php?tid=1212
// MessageType... // MessageType...
mtCustom, // Send raw data without any processing mtCustom, // Send raw data without any processing
mtFailure, // Something could not be done (i.e. command not executed due to insufficient privilege) mtFailure, // Something could not be done (i.e. command not executed due to insufficient privilege)
mtInformation, // Informational message (i.e. command usage) mtInformation, // Informational message (i.e. command usage)
mtSuccess, // Something executed successfully mtSuccess, // Something executed successfully
mtWarning, // Something concerning (i.e. reload) is about to happen mtWarning, // Something concerning (i.e. reload) is about to happen
mtFatal, // Something catastrophic occured (i.e. plugin crash) mtFatal, // Something catastrophic occured (i.e. plugin crash)
mtDeath, // Denotes death of player mtDeath, // Denotes death of player
mtPrivateMessage, // Player to player messaging identifier mtPrivateMessage, // Player to player messaging identifier
mtJoin, // A player has joined the server mtJoin, // A player has joined the server
mtLeave, // A player has left the server mtLeave, // A player has left the server
// Common aliases:
mtFail = mtFailure,
mtError = mtFailure,
mtInfo = mtInformation,
mtPM = mtPrivateMessage,
}; };

View File

@ -521,28 +521,36 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
{ {
if (a_Chunk.IsValid()) if (a_Chunk.IsValid())
{ {
HandlePhysics(a_Dt, a_Chunk); cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT);
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();
}
HandlePhysics(a_Dt, *NextChunk);
} }
} }
if (a_Chunk.IsValid())
{
TickBurning(a_Chunk);
}
if ((a_Chunk.IsValid()) && (GetPosY() < -46))
{
TickInVoid(a_Chunk);
}
else
m_TicksSinceLastVoidDamage = 0;
if (IsMob() || IsPlayer())
{
// Set swimming state
SetSwimState(a_Chunk);
// Handle drowning
HandleAir();
}
} }
@ -562,7 +570,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if ((BlockY >= cChunkDef::Height) || (BlockY < 0)) if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
{ {
// Outside of the world // Outside of the world
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
// See if we can commit our changes. If not, we will discard them. // See if we can commit our changes. If not, we will discard them.
if (NextChunk != NULL) if (NextChunk != NULL)
@ -571,210 +579,205 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
NextPos += (NextSpeed * a_Dt); NextPos += (NextSpeed * a_Dt);
SetPosition(NextPos); SetPosition(NextPos);
} }
return; return;
} }
// Make sure we got the correct chunk and a valid one. No one ever knows... int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width);
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width);
if (NextChunk != NULL) 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); if (m_bOnGround) // check if it's still on the ground
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 (!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 }
else
{
// Push out entity.
BLOCKTYPE GotBlock;
static const struct
{ {
// Push out entity. int x, y, z;
BLOCKTYPE GotBlock; } gCrossCoords[] =
{
{ 1, 0, 0},
{-1, 0, 0},
{ 0, 0, 1},
{ 0, 0, -1},
} ;
static const struct 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))
{ {
int x, y, z; // The pickup is too close to an unloaded chunk, bail out of any physics handling
} gCrossCoords[] = return;
}
if (!cBlockInfo::IsSolid(GotBlock))
{ {
{ 1, 0, 0}, NextPos.x += gCrossCoords[i].x;
{-1, 0, 0}, NextPos.z += gCrossCoords[i].z;
{ 0, 0, 1}, IsNoAirSurrounding = false;
{ 0, 0, -1}, break;
} ; }
} // for i - gCrossCoords[]
bool IsNoAirSurrounding = true;
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
{
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) if (IsNoAirSurrounding)
{ {
NextPos.y += 0.5; NextPos.y += 0.5;
}
m_bOnGround = true;
/*
// DEBUG:
LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}",
m_UniqueID, GetClass(), BlockX, BlockY, BlockZ
);
*/
} }
if (!m_bOnGround) m_bOnGround = true;
/*
// DEBUG:
LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}",
m_UniqueID, GetClass(), BlockX, BlockY, BlockZ
);
*/
}
if (!m_bOnGround)
{
float fallspeed;
if (IsBlockWater(BlockIn))
{ {
float fallspeed; fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
if (IsBlockWater(BlockIn)) }
{ else if (BlockIn == E_BLOCK_COBWEB)
fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water. {
} NextSpeed.y *= 0.05; // Reduce overall falling speed
else if (BlockIn == E_BLOCK_COBWEB) fallspeed = 0; // No falling.
{
NextSpeed.y *= 0.05; // Reduce overall falling speed
fallspeed = 0; // No falling.
}
else
{
// Normal gravity
fallspeed = m_Gravity * a_Dt;
}
NextSpeed.y += fallspeed;
} }
else else
{ {
// Friction // Normal gravity
if (NextSpeed.SqrLength() > 0.0004f) 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); NextSpeed.x = 0;
if (fabs(NextSpeed.x) < 0.05) }
{ NextSpeed.z *= 0.7f / (1 + a_Dt);
NextSpeed.x = 0; if (fabs(NextSpeed.z) < 0.05)
} {
NextSpeed.z *= 0.7f / (1 + a_Dt); NextSpeed.z = 0;
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 // 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. // might have different speed modifiers according to terrain.
if (BlockIn == E_BLOCK_COBWEB) if (BlockIn == E_BLOCK_COBWEB)
{ {
NextSpeed.x *= 0.25; NextSpeed.x *= 0.25;
NextSpeed.z *= 0.25; NextSpeed.z *= 0.25;
} }
//Get water direction //Get water direction
Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ); 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) switch(WaterDir)
{ {
case X_PLUS: case X_PLUS:
m_WaterSpeed.x = 0.2f; m_WaterSpeed.x = 0.2f;
m_bOnGround = false; 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; 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) if (fabs(m_WaterSpeed.x) < 0.05)
{
m_WaterSpeed.x = 0;
}
if (fabs(m_WaterSpeed.z) < 0.05)
{
m_WaterSpeed.z = 0;
}
NextSpeed += m_WaterSpeed;
if( NextSpeed.SqrLength() > 0.f )
{
cTracer Tracer( GetWorld() );
bool HasHit = Tracer.Trace( NextPos, NextSpeed, 2 );
if (HasHit) // Oh noez! we hit something
{ {
m_WaterSpeed.x = 0; // Set to hit position
} if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * a_Dt).SqrLength())
if (fabs(m_WaterSpeed.z) < 0.05)
{
m_WaterSpeed.z = 0;
}
NextSpeed += m_WaterSpeed;
if( NextSpeed.SqrLength() > 0.f )
{
cTracer Tracer( GetWorld() );
int Ret = Tracer.Trace( NextPos, NextSpeed, 2 );
if( Ret ) // Oh noez! we hit something
{ {
// Set to hit position if (Tracer.HitNormal.x != 0.f) NextSpeed.x = 0.f;
if( (Tracer.RealHit - NextPos).SqrLength() <= ( NextSpeed * a_Dt ).SqrLength() ) if (Tracer.HitNormal.y != 0.f) NextSpeed.y = 0.f;
{ if (Tracer.HitNormal.z != 0.f) NextSpeed.z = 0.f;
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 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
{ {
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 else
{ {
// We didn't hit anything, so move =]
NextPos += (NextSpeed * a_Dt); NextPos += (NextSpeed * a_Dt);
} }
} }
BlockX = (int) floor(NextPos.x); else
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)
{ {
if (NextPos.x != GetPosX()) SetPosX(NextPos.x); // We didn't hit anything, so move =]
if (NextPos.y != GetPosY()) SetPosY(NextPos.y); NextPos += (NextSpeed * a_Dt);
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);
} }
} }
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 RelX = x;
int RelZ = z; int RelZ = z;
cChunk * CurChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelX, RelZ);
if (CurChunk == NULL)
{
continue;
}
for (int y = MinY; y <= MaxY; y++) 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: case E_BLOCK_FIRE:
{ {
@ -922,7 +924,7 @@ void cEntity::TickInVoid(cChunk & a_Chunk)
void cEntity::SetSwimState(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)) if ((RelY < 0) || (RelY >= cChunkDef::Height - 1))
{ {
m_IsSwimming = false; m_IsSwimming = false;
@ -931,11 +933,10 @@ void cEntity::SetSwimState(cChunk & a_Chunk)
} }
BLOCKTYPE BlockIn; BLOCKTYPE BlockIn;
int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width; int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width; int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
// Check if the player is swimming: // 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)) if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn))
{ {
// This sometimes happens on Linux machines // This sometimes happens on Linux machines

View File

@ -117,6 +117,7 @@ public:
BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire 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 MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have
DROWNING_TICKS = 20, ///< Number of ticks per heart of damage 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); cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);

View File

@ -5,20 +5,26 @@
#include "../ClientHandle.h" #include "../ClientHandle.h"
cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward) : cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward)
cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98), : cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98)
m_Reward(a_Reward) , m_Reward(a_Reward)
, m_Timer(0.f)
{ {
SetMaxHealth(5);
SetHealth(5);
} }
cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward) : cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward)
cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98), : cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98)
m_Reward(a_Reward) , m_Reward(a_Reward)
, m_Timer(0.f)
{ {
SetMaxHealth(5);
SetHealth(5);
} }
@ -52,7 +58,7 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
LOGD("Player %s picked up an ExpOrb. His reward is %i", a_ClosestPlayer->GetName().c_str(), m_Reward); LOGD("Player %s picked up an ExpOrb. His reward is %i", a_ClosestPlayer->GetName().c_str(), m_Reward);
a_ClosestPlayer->DeltaExperience(m_Reward); a_ClosestPlayer->DeltaExperience(m_Reward);
m_World->BroadcastSoundEffect("random.orb", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); m_World->BroadcastSoundEffect("random.orb", (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
Destroy(); Destroy();
} }
@ -64,4 +70,10 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
BroadcastMovementUpdate(); BroadcastMovementUpdate();
} }
HandlePhysics(a_Dt, a_Chunk); HandlePhysics(a_Dt, a_Chunk);
m_Timer += a_Dt;
if (m_Timer >= 1000 * 60 * 5) // 5 minutes
{
Destroy(true);
}
} }

View File

@ -7,14 +7,17 @@
// tolua_begin
class cExpOrb : class cExpOrb :
public cEntity public cEntity
{ {
typedef cExpOrb super; typedef cExpOrb super;
public: public:
// tolua_end
CLASS_PROTODEF(cExpOrb); CLASS_PROTODEF(cExpOrb);
cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward); cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward);
cExpOrb(const Vector3d & a_Pos, int a_Reward); cExpOrb(const Vector3d & a_Pos, int a_Reward);
@ -22,9 +25,21 @@ public:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override; virtual void SpawnOn(cClientHandle & a_Client) override;
// cExpOrb functions /** Returns the number of ticks that this entity has existed */
int GetReward(void) const { return m_Reward; } int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
/** Set the number of ticks that this entity has existed */
void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export
/** Get the exp amount */
int GetReward(void) const { return m_Reward; } // tolua_export
/** Set the exp amount */
void SetReward(int a_Reward) { m_Reward = a_Reward; } // tolua_export
protected: protected:
int m_Reward; int m_Reward;
} ;
/** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer;
} ; // tolua_export

View File

@ -33,20 +33,16 @@ void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) 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 // GetWorld()->BroadcastTeleportEntity(*this); // Test position
int BlockX = m_OriginalPosition.x; int BlockX = POSX_TOINT;
int BlockY = (int)(GetPosY() - 0.5); int BlockY = (int)(GetPosY() - 0.5);
int BlockZ = m_OriginalPosition.z; int BlockZ = POSZ_TOINT;
if (BlockY < 0) if (BlockY < 0)
{ {
// Fallen out of this world, just continue falling until out of sight, then destroy: // Fallen out of this world, just continue falling until out of sight, then destroy:
if (BlockY < 100) if (BlockY < VOID_BOUNDARY)
{ {
Destroy(true); Destroy(true);
} }
@ -86,6 +82,15 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
Destroy(true); Destroy(true);
return; return;
} }
float MilliDt = a_Dt * 0.001f;
AddSpeedY(MilliDt * -9.8f);
AddPosition(GetSpeed() * MilliDt);
if ((GetSpeedX() != 0) || (GetSpeedZ() != 0))
{
BroadcastMovementUpdate();
}
} }

View File

@ -0,0 +1,53 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "HangingEntity.h"
#include "ClientHandle.h"
#include "Player.h"
cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
: cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8)
, m_BlockFace(a_BlockFace)
{
SetMaxHealth(1);
SetHealth(1);
}
void cHangingEntity::SpawnOn(cClientHandle & a_ClientHandle)
{
int Dir = 0;
// The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
switch (m_BlockFace)
{
case BLOCK_FACE_ZP: break; // Initialised to zero
case BLOCK_FACE_ZM: Dir = 2; break;
case BLOCK_FACE_XM: Dir = 1; break;
case BLOCK_FACE_XP: Dir = 3; break;
default: ASSERT(!"Unhandled block face when trying to spawn item frame!"); return;
}
if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
{
SetYaw((Dir * 90) - 180);
}
else
{
SetYaw(Dir * 90);
}
a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch());
a_ClientHandle.SendEntityMetadata(*this);
}

View File

@ -0,0 +1,49 @@
#pragma once
#include "Entity.h"
// tolua_begin
class cHangingEntity :
public cEntity
{
// tolua_end
typedef cEntity super;
public:
CLASS_PROTODEF(cHangingEntity);
cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z);
/** Returns the orientation from the hanging entity */
eBlockFace GetDirection() const { return m_BlockFace; } // tolua_export
/** Set the orientation from the hanging entity */
void SetDirection(eBlockFace a_BlockFace) { m_BlockFace = a_BlockFace; } // tolua_export
/** Returns the X coord. */
int GetTileX() const { return POSX_TOINT; } // tolua_export
/** Returns the Y coord. */
int GetTileY() const { return POSY_TOINT; } // tolua_export
/** Returns the Z coord. */
int GetTileZ() const { return POSZ_TOINT; } // tolua_export
private:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
eBlockFace m_BlockFace;
}; // tolua_export

View File

@ -10,43 +10,10 @@
cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z) cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
: cEntity(etItemFrame, a_X, a_Y, a_Z, 0.8, 0.8), : cHangingEntity(etItemFrame, a_BlockFace, a_X, a_Y, a_Z)
m_BlockFace(a_BlockFace), , m_Item(E_BLOCK_AIR)
m_Item(E_BLOCK_AIR), , m_Rotation(0)
m_Rotation(0)
{ {
SetMaxHealth(1);
SetHealth(1);
}
void cItemFrame::SpawnOn(cClientHandle & a_ClientHandle)
{
int Dir = 0;
// The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
switch (m_BlockFace)
{
case BLOCK_FACE_ZP: break; // Initialised to zero
case BLOCK_FACE_ZM: Dir = 2; break;
case BLOCK_FACE_XM: Dir = 1; break;
case BLOCK_FACE_XP: Dir = 3; break;
default: ASSERT(!"Unhandled block face when trying to spawn item frame!"); return;
}
if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
{
SetYaw((Dir * 90) - 180);
}
else
{
SetYaw(Dir * 90);
}
a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch());
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "Entity.h" #include "HangingEntity.h"
@ -9,10 +9,10 @@
// tolua_begin // tolua_begin
class cItemFrame : class cItemFrame :
public cEntity public cHangingEntity
{ {
// tolua_end // tolua_end
typedef cEntity super; typedef cHangingEntity super;
public: public:
@ -20,18 +20,24 @@ public:
cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z); cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z);
const cItem & GetItem(void) { return m_Item; } /** Returns the item in the frame */
Byte GetRotation(void) const { return m_Rotation; } const cItem & GetItem(void) { return m_Item; } // tolua_export
/** Set the item in the frame */
void SetItem(cItem & a_Item) { m_Item = a_Item; }; // tolua_export
/** Returns the rotation from the item in the frame */
Byte GetRotation(void) const { return m_Rotation; } // tolua_export
/** Set the rotation from the item in the frame */
void SetRotation(Byte a_Rotation) { m_Rotation = a_Rotation; } // tolua_export
private: private:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void OnRightClicked(cPlayer & a_Player) override; virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
virtual void KilledBy(cEntity * a_Killer) override; virtual void KilledBy(cEntity * a_Killer) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override; virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
eBlockFace m_BlockFace;
cItem m_Item; cItem m_Item;
Byte m_Rotation; Byte m_Rotation;

View File

@ -82,7 +82,7 @@ cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_It
void cPickup::SpawnOn(cClientHandle & a_Client) void cPickup::SpawnOn(cClientHandle & a_Client)
{ {
a_Client.SendPickupSpawn(*this); a_Client.SendPickupSpawn(*this);
} }

View File

@ -26,31 +26,34 @@ public:
CLASS_PROTODEF(cPickup); CLASS_PROTODEF(cPickup);
cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f);
cItem & GetItem(void) {return m_Item; } // tolua_export cItem & GetItem(void) {return m_Item; } // tolua_export
const cItem & GetItem(void) const {return m_Item; } const cItem & GetItem(void) const {return m_Item; }
virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
bool CollectedBy(cPlayer * a_Dest); // tolua_export bool CollectedBy(cPlayer * a_Dest); // tolua_export
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
/// Returns the number of ticks that this entity has existed /** Returns the number of ticks that this entity has existed */
int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
/// Returns true if the pickup has already been collected /** Set the number of ticks that this entity has existed */
void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export
/** Returns true if the pickup has already been collected */
bool IsCollected(void) const { return m_bCollected; } // tolua_export bool IsCollected(void) const { return m_bCollected; } // tolua_export
/// Returns true if created by player (i.e. vomiting), used for determining picking-up delay time /** Returns true if created by player (i.e. vomiting), used for determining picking-up delay time */
bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
private: private:
Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;) Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
Vector3d m_WaterSpeed; Vector3d m_WaterSpeed;
/// The number of ticks that the entity has existed / timer between collect and destroy; in msec /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer; float m_Timer;
cItem m_Item; cItem m_Item;

View File

@ -43,8 +43,9 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_GameMode(eGameMode_NotSet) , m_GameMode(eGameMode_NotSet)
, m_IP("") , m_IP("")
, m_ClientHandle(a_Client) , m_ClientHandle(a_Client)
, m_NormalMaxSpeed(0.1) , m_NormalMaxSpeed(1.0)
, m_SprintingMaxSpeed(0.13) , m_SprintingMaxSpeed(1.3)
, m_FlyingMaxSpeed(1.0)
, m_IsCrouched(false) , m_IsCrouched(false)
, m_IsSprinting(false) , m_IsSprinting(false)
, m_IsFlying(false) , m_IsFlying(false)
@ -684,7 +685,21 @@ const cSlotNums & cPlayer::GetInventoryPaintSlots(void) const
double cPlayer::GetMaxSpeed(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) void cPlayer::SetNormalMaxSpeed(double a_Speed)
{ {
m_NormalMaxSpeed = a_Speed; m_NormalMaxSpeed = a_Speed;
if (!m_IsSprinting) if (!m_IsSprinting && !m_IsFlying)
{ {
m_ClientHandle->SendPlayerMaxSpeed(); m_ClientHandle->SendPlayerMaxSpeed();
} }
@ -707,7 +722,7 @@ void cPlayer::SetNormalMaxSpeed(double a_Speed)
void cPlayer::SetSprintingMaxSpeed(double a_Speed) void cPlayer::SetSprintingMaxSpeed(double a_Speed)
{ {
m_SprintingMaxSpeed = a_Speed; m_SprintingMaxSpeed = a_Speed;
if (m_IsSprinting) if (m_IsSprinting && !m_IsFlying)
{ {
m_ClientHandle->SendPlayerMaxSpeed(); 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) void cPlayer::SetCrouch(bool a_IsCrouched)
{ {
// Set the crouch status, broadcast to all visible players // Set the crouch status, broadcast to all visible players

View File

@ -47,19 +47,19 @@ public:
virtual void HandlePhysics(float a_Dt, cChunk &) override { UNUSED(a_Dt); }; 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(); } 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(); } 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(); } 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(); } 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(); } virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
@ -77,36 +77,41 @@ public:
*/ */
short DeltaExperience(short a_Xp_delta); 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; } inline short GetXpLifetimeTotal(void) { return m_LifetimeTotalXp; }
/// Gets the currrent experience /** Gets the currrent experience */
inline short GetCurrentXp(void) { return m_CurrentXp; } inline short GetCurrentXp(void) { return m_CurrentXp; }
/// Gets the current level - XpLevel /** Gets the current level - XpLevel */
short GetXpLevel(void); short GetXpLevel(void);
/// Gets the experience bar percentage - XpP /** Gets the experience bar percentage - XpP */
float GetXpPercentage(void); 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); 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); static short CalcLevelFromXp(short int a_CurrentXp);
// tolua_end // tolua_end
/// Starts charging the equipped bow /** Starts charging the equipped bow */
void StartChargingBow(void); 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); int FinishChargingBow(void);
/// Cancels the current bow charging /** Cancels the current bow charging */
void CancelChargingBow(void); 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; } bool IsChargingBow(void) const { return m_IsChargingBow; }
void SetTouchGround( bool a_bTouchGround ); void SetTouchGround( bool a_bTouchGround );
@ -124,16 +129,16 @@ public:
// tolua_begin // 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; 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; 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; } 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; } eGameMode GetEffectiveGameMode(void) const { return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode; }
/** Sets the gamemode for the player. /** Sets the gamemode for the player.
@ -142,24 +147,24 @@ public:
*/ */
void SetGameMode(eGameMode a_GameMode); 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; 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; 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; bool IsGameModeAdventure(void) const;
AString GetIP(void) const { return m_IP; } // tolua_export 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 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); 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); cTeam * UpdateTeam(void);
// tolua_end // tolua_end
@ -169,24 +174,24 @@ public:
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client // Sets the current gamemode, doesn't check validity, doesn't send update packets to client
void LoginSetGameMode(eGameMode a_GameMode); 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 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 void MoveTo(const Vector3d & a_NewPos); // tolua_export
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
const cWindow * GetWindow(void) const { return m_CurrentWindow; } 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 void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp
// tolua_begin // 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); 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); void CloseWindowIfID(char a_WindowID, bool a_CanRefuse = true);
cClientHandle * GetClientHandle(void) const { return m_ClientHandle; } cClientHandle * GetClientHandle(void) const { return m_ClientHandle; }
@ -208,10 +213,10 @@ public:
typedef std::list< cGroup* > GroupList; typedef std::list< cGroup* > GroupList;
typedef std::list< std::string > StringList; 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 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 void RemoveFromGroup( const AString & a_GroupName ); // tolua_export
bool HasPermission( const AString & a_Permission ); // tolua_export bool HasPermission( const AString & a_Permission ); // tolua_export
@ -234,7 +239,7 @@ public:
/** tosses a pickup newly created from a_Item */ /** tosses a pickup newly created from a_Item */
void TossPickup(const cItem & 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); void Heal(int a_Health);
int GetFoodLevel (void) const { return m_FoodLevel; } int GetFoodLevel (void) const { return m_FoodLevel; }
@ -243,7 +248,7 @@ public:
double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; } double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; }
int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; } 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); } bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); }
void SetFoodLevel (int a_FoodLevel); void SetFoodLevel (int a_FoodLevel);
@ -252,25 +257,28 @@ public:
void SetFoodExhaustionLevel (double a_FoodExhaustionLevel); void SetFoodExhaustionLevel (double a_FoodExhaustionLevel);
void SetFoodPoisonedTicksRemaining(int a_FoodPoisonedTicksRemaining); 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); 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) void AddFoodExhaustion(double a_Exhaustion)
{ {
m_FoodExhaustionLevel += 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); 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); } 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; } bool IsFlying(void) const { return m_IsFlying; }
/// returns true if the player has thrown out a floater. /** 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. */
bool IsFishing(void) const { return m_IsFishing; } bool IsFishing(void) const { return m_IsFishing; }
void SetIsFishing(bool a_IsFishing, int a_FloaterID = -1) { m_IsFishing = a_IsFishing; m_FloaterID = a_FloaterID; } void SetIsFishing(bool a_IsFishing, int a_FloaterID = -1) { m_IsFishing = a_IsFishing; m_FloaterID = a_FloaterID; }
@ -278,14 +286,17 @@ public:
int GetFloaterID(void) const { return m_FloaterID; } int GetFloaterID(void) const { return m_FloaterID; }
// tolua_end // tolua_end
/** 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); 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); void FinishEating(void);
/// Aborts the current eating operation /** Aborts the current eating operation */
void AbortEating(void); void AbortEating(void);
virtual void KilledBy(cEntity * a_Killer) override; virtual void KilledBy(cEntity * a_Killer) override;
@ -314,45 +325,51 @@ public:
cItem & GetDraggingItem(void) {return m_DraggingItem; } cItem & GetDraggingItem(void) {return m_DraggingItem; }
// In UI windows, when inventory-painting: // 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); 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); 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; const cSlotNums & GetInventoryPaintSlots(void) const;
// tolua_begin // 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; 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; } 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; } 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); 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); 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); 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); void SetSprint(bool a_IsSprinting);
/// Flags the player as flying /** Flags the player as flying */
void SetFlying(bool a_IsFlying); 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); 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; } virtual bool CanFly(void) const { return m_CanFly; }
// tolua_end // tolua_end
@ -371,10 +388,10 @@ protected:
GroupList m_ResolvedGroups; GroupList m_ResolvedGroups;
GroupList m_Groups; GroupList m_Groups;
std::string m_PlayerName; AString m_PlayerName;
std::string m_LoadedWorldName; AString m_LoadedWorldName;
/// Xp Level stuff /** Xp Level stuff */
enum enum
{ {
XP_TO_LEVEL15 = 255, XP_TO_LEVEL15 = 255,
@ -385,22 +402,22 @@ protected:
bool m_bVisible; bool m_bVisible;
// Food-related variables: // 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; 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; 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; 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; 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; 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; Vector3d m_LastFoodPos;
float m_LastJumpHeight; float m_LastJumpHeight;
@ -416,7 +433,7 @@ protected:
eGameMode m_GameMode; eGameMode m_GameMode;
AString m_IP; 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; cItem m_DraggingItem;
long long m_LastPlayerListTime; long long m_LastPlayerListTime;
@ -426,12 +443,21 @@ protected:
cSlotNums m_InventoryPaintSlots; 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; 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; 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_IsCrouched;
bool m_IsSprinting; bool m_IsSprinting;
bool m_IsFlying; bool m_IsFlying;
@ -441,10 +467,10 @@ protected:
bool m_CanFly; // If this is true the player can fly. Even if he is not in creative. 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; Int64 m_EatingFinishTick;
/// Player Xp level /** Player Xp level */
short int m_LifetimeTotalXp; short int m_LifetimeTotalXp;
short int m_CurrentXp; short int m_CurrentXp;
@ -456,7 +482,7 @@ protected:
int m_FloaterID; int m_FloaterID;
cTeam* m_Team; cTeam * m_Team;
@ -465,20 +491,25 @@ protected:
virtual void Destroyed(void); 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; virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
/** Stops players from burning in creative mode */ /** Stops players from burning in creative mode */
virtual void TickBurning(cChunk & a_Chunk) override; 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); 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); 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(); void ApplyFoodExhaustionFromMovement();
/** Flag representing whether the player is currently in a bed
Set by a right click on unoccupied bed, unset by a time fast forward or teleport */
bool m_bIsInBed;
} ; // tolua_export } ; // tolua_export

View File

@ -371,8 +371,8 @@ void cBioGenDistortedVoronoi::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::B
Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z]); Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z]);
} }
LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
for (int z = 0; z < cChunkDef::Width; z++) for (int z = 0; z < cChunkDef::Width; z++)
{ {
@ -477,8 +477,8 @@ void cBioGenMultiStepMap::DecideOceanLandMushroom(int a_ChunkX, int a_ChunkZ, cC
{ {
Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z], DistortSize); Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z], DistortSize);
} }
LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
// Prepare a 9x9 area of neighboring cell seeds // Prepare a 9x9 area of neighboring cell seeds
// (assuming that 7x7 cell area is larger than a chunk being generated) // (assuming that 7x7 cell area is larger than a chunk being generated)
@ -651,8 +651,8 @@ void cBioGenMultiStepMap::BuildTemperatureHumidityMaps(int a_ChunkX, int a_Chunk
HumidityMap[x + 17 * z] = NoiseH; HumidityMap[x + 17 * z] = NoiseH;
} // for x } // for x
} // for z } // for z
LinearUpscale2DArrayInPlace(TemperatureMap, 17, 17, 8, 8); LinearUpscale2DArrayInPlace<17, 17, 8, 8>(TemperatureMap);
LinearUpscale2DArrayInPlace(HumidityMap, 17, 17, 8, 8); LinearUpscale2DArrayInPlace<17, 17, 8, 8>(HumidityMap);
// Re-map into integral values in [0 .. 255] range: // Re-map into integral values in [0 .. 255] range:
for (size_t idx = 0; idx < ARRAYCOUNT(a_TemperatureMap); idx++) for (size_t idx = 0; idx < ARRAYCOUNT(a_TemperatureMap); idx++)
@ -778,8 +778,8 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap
DistortZ[4 * x][4 * z] = BlockZ + (int)(64 * NoiseZ); DistortZ[4 * x][4 * z] = BlockZ + (int)(64 * NoiseZ);
} }
LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4); LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
// Apply distortion to each block coord, then query the voronoi maps for biome group and biome index and choose biome based on that: // Apply distortion to each block coord, then query the voronoi maps for biome group and biome index and choose biome based on that:
for (int z = 0; z < cChunkDef::Width; z++) for (int z = 0; z < cChunkDef::Width; z++)

View File

@ -566,7 +566,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, 0, BaseZ + INTERPOL_Z * z) / m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, 0, BaseZ + INTERPOL_Z * z) /
256; 256;
} // for x, z - FloorLo[] } // for x, z - FloorLo[]
LinearUpscale2DArrayInPlace(FloorLo, 17, 17, INTERPOL_X, INTERPOL_Z); LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorLo);
// Interpolate segments: // Interpolate segments:
for (int Segment = 0; Segment < MaxHeight; Segment += SEGMENT_HEIGHT) for (int Segment = 0; Segment < MaxHeight; Segment += SEGMENT_HEIGHT)
@ -579,7 +579,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) / m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) /
256; 256;
} // for x, z - FloorLo[] } // for x, z - FloorLo[]
LinearUpscale2DArrayInPlace(FloorHi, 17, 17, INTERPOL_X, INTERPOL_Z); LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorHi);
// Interpolate between FloorLo and FloorHi: // Interpolate between FloorLo and FloorHi:
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++) for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)

View File

@ -428,7 +428,7 @@ void cHeiGenBiomal::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMa
Height[x + 17 * z] = GetHeightAt(x, z, a_ChunkX, a_ChunkZ, Biomes); Height[x + 17 * z] = GetHeightAt(x, z, a_ChunkX, a_ChunkZ, Biomes);
} }
} }
LinearUpscale2DArrayInPlace(Height, 17, 17, STEPX, STEPZ); LinearUpscale2DArrayInPlace<17, 17, STEPX, STEPZ>(Height);
// Copy into the heightmap // Copy into the heightmap
for (int z = 0; z < cChunkDef::Width; z++) for (int z = 0; z < cChunkDef::Width; z++)

View File

@ -420,7 +420,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
} }
} }
// Linear-interpolate this XZ floor: // Linear-interpolate this XZ floor:
LinearUpscale2DArrayInPlace(CurFloor, 17, 17, UPSCALE_X, UPSCALE_Z); LinearUpscale2DArrayInPlace<17, 17, UPSCALE_X, UPSCALE_Z>(CurFloor);
} }
// Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis // Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis

View File

@ -578,7 +578,7 @@ void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, BaseY, BaseZ + INTERPOL_Z * z) / m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, BaseY, BaseZ + INTERPOL_Z * z) /
256; 256;
} // for x, z - FloorLo[] } // for x, z - FloorLo[]
LinearUpscale2DArrayInPlace(FloorLo, 17, 17, INTERPOL_X, INTERPOL_Z); LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorLo);
// Interpolate segments: // Interpolate segments:
for (int Segment = BaseY; Segment < MaxHeight; Segment += SEGMENT_HEIGHT) for (int Segment = BaseY; Segment < MaxHeight; Segment += SEGMENT_HEIGHT)
@ -591,7 +591,7 @@ void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) / m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) /
256; 256;
} // for x, z - FloorLo[] } // for x, z - FloorLo[]
LinearUpscale2DArrayInPlace(FloorHi, 17, 17, INTERPOL_X, INTERPOL_Z); LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorHi);
// Interpolate between FloorLo and FloorHi: // Interpolate between FloorLo and FloorHi:
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++) for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)

41
src/Items/ItemCake.h Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include "ItemHandler.h"
class cItemCakeHandler :
public cItemHandler
{
public:
cItemCakeHandler(int a_ItemType) :
cItemHandler(a_ItemType)
{
}
virtual bool IsPlaceable(void) override
{
return true;
}
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
a_BlockType = E_BLOCK_CAKE;
a_BlockMeta = 0;
return true;
}
} ;

View File

@ -13,6 +13,7 @@
#include "ItemBow.h" #include "ItemBow.h"
#include "ItemBrewingStand.h" #include "ItemBrewingStand.h"
#include "ItemBucket.h" #include "ItemBucket.h"
#include "ItemCake.h"
#include "ItemCauldron.h" #include "ItemCauldron.h"
#include "ItemCloth.h" #include "ItemCloth.h"
#include "ItemComparator.h" #include "ItemComparator.h"
@ -94,6 +95,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
// Single item per handler, alphabetically sorted: // Single item per handler, alphabetically sorted:
case E_BLOCK_LEAVES: return new cItemLeavesHandler(a_ItemType); case E_BLOCK_LEAVES: return new cItemLeavesHandler(a_ItemType);
case E_BLOCK_NEW_LEAVES: return new cItemLeavesHandler(a_ItemType);
case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType); case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType);
case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType); case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
case E_ITEM_BED: return new cItemBedHandler(a_ItemType); case E_ITEM_BED: return new cItemBedHandler(a_ItemType);
@ -101,12 +103,14 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler(); case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler();
case E_ITEM_BOW: return new cItemBowHandler; case E_ITEM_BOW: return new cItemBowHandler;
case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType); case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
case E_ITEM_CAKE: return new cItemCakeHandler(a_ItemType);
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType); case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType); case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType);
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType); case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
case E_ITEM_EGG: return new cItemEggHandler(); case E_ITEM_EGG: return new cItemEggHandler();
case E_ITEM_EMPTY_MAP: return new cItemEmptyMapHandler(); case E_ITEM_EMPTY_MAP: return new cItemEmptyMapHandler();
case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler(); case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler();
case E_ITEM_FIRE_CHARGE: return new cItemLighterHandler(a_ItemType);
case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler(); case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler();
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType); case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
@ -337,6 +341,7 @@ char cItemHandler::GetMaxStackSize(void)
case E_ITEM_BREWING_STAND: return 64; case E_ITEM_BREWING_STAND: return 64;
case E_ITEM_BUCKET: return 16; case E_ITEM_BUCKET: return 16;
case E_ITEM_CARROT: return 64; case E_ITEM_CARROT: return 64;
case E_ITEM_CAKE: return 1;
case E_ITEM_CAULDRON: return 64; case E_ITEM_CAULDRON: return 64;
case E_ITEM_CLAY: return 64; case E_ITEM_CLAY: return 64;
case E_ITEM_CLAY_BRICK: return 64; case E_ITEM_CLAY_BRICK: return 64;

View File

@ -34,7 +34,11 @@ public:
if (Block == E_BLOCK_AIR) if (Block == E_BLOCK_AIR)
{ {
cItemFrame * ItemFrame = new cItemFrame(a_Dir, a_BlockX, a_BlockY, a_BlockZ); cItemFrame * ItemFrame = new cItemFrame(a_Dir, a_BlockX, a_BlockY, a_BlockZ);
ItemFrame->Initialize(a_World); if (!ItemFrame->Initialize(a_World))
{
delete ItemFrame;
return false;
}
if (!a_Player->IsGameModeCreative()) if (!a_Player->IsGameModeCreative())
{ {

View File

@ -26,7 +26,26 @@ public:
return false; return false;
} }
a_Player->UseEquippedItem(); if (!a_Player->IsGameModeCreative())
{
switch (m_ItemType)
{
case E_ITEM_FLINT_AND_STEEL:
{
a_Player->UseEquippedItem();
break;
}
case E_ITEM_FIRE_CHARGE:
{
a_Player->GetInventory().RemoveOneEquippedItem();
break;
}
default:
{
ASSERT(!"Unknown Lighter Item!");
}
}
}
switch (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ)) switch (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ))
{ {
@ -34,8 +53,8 @@ public:
{ {
// Activate the TNT: // Activate the TNT:
a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f); 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->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; break;
} }
default: default:
@ -49,6 +68,7 @@ public:
if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
{ {
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0); a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0);
a_World->BroadcastSoundEffect("fire.ignite", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0F, 1.04F);
break; break;
} }
} }

View File

@ -28,10 +28,10 @@ public:
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
{ {
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
if (Block == E_BLOCK_LEAVES) if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES))
{ {
cItems Drops; cItems Drops;
Drops.push_back(cItem(E_BLOCK_LEAVES, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03)); Drops.push_back(cItem(Block, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03));
a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ); a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
@ -49,6 +49,7 @@ public:
case E_BLOCK_COBWEB: case E_BLOCK_COBWEB:
case E_BLOCK_VINES: case E_BLOCK_VINES:
case E_BLOCK_LEAVES: case E_BLOCK_LEAVES:
case E_BLOCK_NEW_LEAVES:
{ {
return true; return true;
} }

View File

@ -18,7 +18,7 @@ Therefore, there is no cpp file.
InPlace upscaling works on a single array and assumes that the values to work on have already InPlace upscaling works on a single array and assumes that the values to work on have already
been interspersed into the array to the cell boundaries. been interspersed into the array to the cell boundaries.
Specifically, a_Array[x * a_AnchorStepX + y * a_AnchorStepY] contains the anchor value. Specifically, a_Array[x * AnchorStepX + y * AnchorStepY] contains the anchor value.
Regular upscaling takes two arrays and "moves" the input from src to dst; src is expected packed. Regular upscaling takes two arrays and "moves" the input from src to dst; src is expected packed.
*/ */
@ -29,46 +29,48 @@ Regular upscaling takes two arrays and "moves" the input from src to dst; src is
/** /**
Linearly interpolates values in the array between the equidistant anchor points (upscales). Linearly interpolates values in the array between the equidistant anchor points (upscales).
Works in-place (input is already present at the correct output coords) Works in-place (input is already present at the correct output coords)
Uses templates to make it possible for the compiler to further optimizer the loops
*/ */
template<typename TYPE> void LinearUpscale2DArrayInPlace( template<
TYPE * a_Array, int SizeX, int SizeY, // Dimensions of the array
int a_SizeX, int a_SizeY, // Dimensions of the array int AnchorStepX, int AnchorStepY,
int a_AnchorStepX, int a_AnchorStepY // Distances between the anchor points in each direction typename TYPE
) >
void LinearUpscale2DArrayInPlace(TYPE * a_Array)
{ {
// First interpolate columns where the anchor points are: // First interpolate columns where the anchor points are:
int LastYCell = a_SizeY - a_AnchorStepY; int LastYCell = SizeY - AnchorStepY;
for (int y = 0; y < LastYCell; y += a_AnchorStepY) for (int y = 0; y < LastYCell; y += AnchorStepY)
{ {
int Idx = a_SizeX * y; int Idx = SizeX * y;
for (int x = 0; x < a_SizeX; x += a_AnchorStepX) for (int x = 0; x < SizeX; x += AnchorStepX)
{ {
TYPE StartValue = a_Array[Idx]; TYPE StartValue = a_Array[Idx];
TYPE EndValue = a_Array[Idx + a_SizeX * a_AnchorStepY]; TYPE EndValue = a_Array[Idx + SizeX * AnchorStepY];
TYPE Diff = EndValue - StartValue; TYPE Diff = EndValue - StartValue;
for (int CellY = 1; CellY < a_AnchorStepY; CellY++) for (int CellY = 1; CellY < AnchorStepY; CellY++)
{ {
a_Array[Idx + a_SizeX * CellY] = StartValue + Diff * CellY / a_AnchorStepY; a_Array[Idx + SizeX * CellY] = StartValue + Diff * CellY / AnchorStepY;
} // for CellY } // for CellY
Idx += a_AnchorStepX; Idx += AnchorStepX;
} // for x } // for x
} // for y } // for y
// Now interpolate in rows, each row has values in the anchor columns // Now interpolate in rows, each row has values in the anchor columns
int LastXCell = a_SizeX - a_AnchorStepX; int LastXCell = SizeX - AnchorStepX;
for (int y = 0; y < a_SizeY; y++) for (int y = 0; y < SizeY; y++)
{ {
int Idx = a_SizeX * y; int Idx = SizeX * y;
for (int x = 0; x < LastXCell; x += a_AnchorStepX) for (int x = 0; x < LastXCell; x += AnchorStepX)
{ {
TYPE StartValue = a_Array[Idx]; TYPE StartValue = a_Array[Idx];
TYPE EndValue = a_Array[Idx + a_AnchorStepX]; TYPE EndValue = a_Array[Idx + AnchorStepX];
TYPE Diff = EndValue - StartValue; TYPE Diff = EndValue - StartValue;
for (int CellX = 1; CellX < a_AnchorStepX; CellX++) for (int CellX = 1; CellX < AnchorStepX; CellX++)
{ {
a_Array[Idx + CellX] = StartValue + CellX * Diff / a_AnchorStepX; a_Array[Idx + CellX] = StartValue + CellX * Diff / AnchorStepX;
} // for CellY } // for CellY
Idx += a_AnchorStepX; Idx += AnchorStepX;
} }
} }
} }

View File

@ -169,7 +169,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
(TargetBlock == E_BLOCK_AIR) && (TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) &&
( (
(BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES)
) && ) &&
(a_RelY >= 62) && (a_RelY >= 62) &&
(m_Random.NextInt(3, a_Biome) != 0) (m_Random.NextInt(3, a_Biome) != 0)

View File

@ -82,11 +82,11 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
, m_AttackRange(2) , m_AttackRange(2)
, m_AttackInterval(0) , m_AttackInterval(0)
, m_SightDistance(25) , m_SightDistance(25)
, m_DropChanceWeapon(0.085) , m_DropChanceWeapon(0.085f)
, m_DropChanceHelmet(0.085) , m_DropChanceHelmet(0.085f)
, m_DropChanceChestplate(0.085) , m_DropChanceChestplate(0.085f)
, m_DropChanceLeggings(0.085) , m_DropChanceLeggings(0.085f)
, m_DropChanceBoots(0.085) , m_DropChanceBoots(0.085f)
, m_CanPickUpLoot(true) , m_CanPickUpLoot(true)
, m_BurnsInDaylight(false) , m_BurnsInDaylight(false)
{ {

View File

@ -73,12 +73,15 @@ int cGZipFile::ReadRestOfFile(AString & a_Contents)
// Since the gzip format doesn't really support getting the uncompressed length, we need to read incrementally. Yuck! // Since the gzip format doesn't really support getting the uncompressed length, we need to read incrementally. Yuck!
int NumBytesRead = 0; int NumBytesRead = 0;
int TotalBytes = 0;
char Buffer[64 KiB]; char Buffer[64 KiB];
while ((NumBytesRead = gzread(m_File, Buffer, sizeof(Buffer))) > 0) while ((NumBytesRead = gzread(m_File, Buffer, sizeof(Buffer))) > 0)
{ {
TotalBytes += NumBytesRead;
a_Contents.append(Buffer, NumBytesRead); a_Contents.append(Buffer, NumBytesRead);
} }
return NumBytesRead; // NumBytesRead is < 0 on error
return (NumBytesRead >= 0) ? TotalBytes : NumBytesRead;
} }

View File

@ -135,7 +135,7 @@ void cProtocol161::SendPlayerMaxSpeed(void)
WriteInt(m_Client->GetPlayer()->GetUniqueID()); WriteInt(m_Client->GetPlayer()->GetUniqueID());
WriteInt(1); WriteInt(1);
WriteString("generic.movementSpeed"); WriteString("generic.movementSpeed");
WriteDouble(m_Client->GetPlayer()->GetMaxSpeed()); WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed());
Flush(); Flush();
} }
@ -267,7 +267,7 @@ void cProtocol162::SendPlayerMaxSpeed(void)
WriteInt(m_Client->GetPlayer()->GetUniqueID()); WriteInt(m_Client->GetPlayer()->GetUniqueID());
WriteInt(1); WriteInt(1);
WriteString("generic.movementSpeed"); WriteString("generic.movementSpeed");
WriteDouble(m_Client->GetPlayer()->GetMaxSpeed()); WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed());
WriteShort(0); WriteShort(0);
Flush(); Flush();
} }

View File

@ -687,9 +687,8 @@ void cProtocol172::SendPlayerAbilities(void)
Flags |= 0x04; Flags |= 0x04;
} }
Pkt.WriteByte(Flags); Pkt.WriteByte(Flags);
// TODO: Pkt.WriteFloat(m_Client->GetPlayer()->GetMaxFlyingSpeed()); Pkt.WriteFloat((float)(0.05 * m_Client->GetPlayer()->GetFlyingMaxSpeed()));
Pkt.WriteFloat(0.05f); Pkt.WriteFloat((float)(0.1 * m_Client->GetPlayer()->GetMaxSpeed()));
Pkt.WriteFloat((float)m_Client->GetPlayer()->GetMaxSpeed());
} }
@ -743,13 +742,14 @@ void cProtocol172::SendPlayerMaxSpeed(void)
Pkt.WriteInt(m_Client->GetPlayer()->GetUniqueID()); Pkt.WriteInt(m_Client->GetPlayer()->GetUniqueID());
Pkt.WriteInt(1); // Count Pkt.WriteInt(1); // Count
Pkt.WriteString("generic.movementSpeed"); 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()) if (m_Client->GetPlayer()->IsSprinting())
{ {
Pkt.WriteShort(1); // Modifier count Pkt.WriteShort(1); // Modifier count
Pkt.WriteInt64(0x662a6b8dda3e4c1c); Pkt.WriteInt64(0x662a6b8dda3e4c1c);
Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier
Pkt.WriteDouble(0.3); Pkt.WriteDouble(m_Client->GetPlayer()->GetSprintingMaxSpeed() - m_Client->GetPlayer()->GetNormalMaxSpeed());
Pkt.WriteByte(2); Pkt.WriteByte(2);
} }
else else

View File

@ -30,7 +30,13 @@ AString cObjective::TypeToString(eType a_Type)
case otStatBlockMine: return "stat.mineBlock"; case otStatBlockMine: return "stat.mineBlock";
case otStatEntityKill: return "stat.killEntity"; case otStatEntityKill: return "stat.killEntity";
case otStatEntityKilledBy: return "stat.entityKilledBy"; case otStatEntityKilledBy: return "stat.entityKilledBy";
// clang optimisises this line away then warns that it has done so.
#if !defined(__clang__)
default: return "";
#endif
} }
} }

View File

@ -838,8 +838,8 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_
if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) 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.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.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
} }
} }
@ -1062,7 +1062,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
{ {
Vector3f EntityPos = a_Entity->GetPosition(); Vector3f EntityPos = a_Entity->GetPosition();
Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
float Distance = (EntityPos - BlockPos).Length(); double Distance = (EntityPos - BlockPos).Length();
if (Distance <= 0.7) if (Distance <= 0.7)
{ {

View File

@ -250,8 +250,6 @@ cWorld::cWorld(const AString & a_WorldName) :
m_SkyDarkness(0), m_SkyDarkness(0),
m_Weather(eWeather_Sunny), m_Weather(eWeather_Sunny),
m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :)
m_bCommandBlocksEnabled(false),
m_bUseChatPrefixes(true),
m_Scoreboard(this), m_Scoreboard(this),
m_MapManager(this), m_MapManager(this),
m_GeneratorCallbacks(*this), m_GeneratorCallbacks(*this),
@ -562,29 +560,33 @@ void cWorld::Start(void)
m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ); m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ);
} }
m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema); m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema);
m_StorageCompressionFactor = IniFile.GetValueSetI("Storage", "CompressionFactor", m_StorageCompressionFactor); m_StorageCompressionFactor = IniFile.GetValueSetI("Storage", "CompressionFactor", m_StorageCompressionFactor);
m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3); m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3);
m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3); m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3);
m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false); m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true); m_IsCarrotsBonemealable = IniFile.GetValueSetB("Plants", "IsCarrotsBonemealable", true);
m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true); m_IsCropsBonemealable = IniFile.GetValueSetB("Plants", "IsCropsBonemealable", true);
m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true); m_IsGrassBonemealable = IniFile.GetValueSetB("Plants", "IsGrassBonemealable", true);
m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true); m_IsMelonStemBonemealable = IniFile.GetValueSetB("Plants", "IsMelonStemBonemealable", true);
m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false); m_IsMelonBonemealable = IniFile.GetValueSetB("Plants", "IsMelonBonemealable", false);
m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true); m_IsPotatoesBonemealable = IniFile.GetValueSetB("Plants", "IsPotatoesBonemealable", true);
m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true); m_IsPumpkinStemBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinStemBonemealable", true);
m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false); m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false);
m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true); m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true);
m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false); m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true); m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true); m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false); int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slNone);
m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true); m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true); m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true); m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
m_GameMode = (eGameMode)IniFile.GetValueSetI("General", "Gamemode", m_GameMode); 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: // Load allowed mobs:
const char * DefaultMonsters = ""; 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) 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); cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks);
TNT->Initialize(this); 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)
);
} }

View File

@ -125,15 +125,16 @@ public:
// tolua_begin // tolua_begin
int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; } int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; }
virtual Int64 GetWorldAge(void) const { return m_WorldAge; }
virtual Int64 GetTimeOfDay(void) const { return m_TimeOfDay; } virtual Int64 GetWorldAge (void) const { return m_WorldAge; } // override, cannot specify due to tolua
virtual Int64 GetTimeOfDay(void) const { return m_TimeOfDay; } // override, cannot specify due to tolua
void SetTicksUntilWeatherChange(int a_WeatherInterval) void SetTicksUntilWeatherChange(int a_WeatherInterval)
{ {
m_WeatherInterval = a_WeatherInterval; m_WeatherInterval = a_WeatherInterval;
} }
void SetTimeOfDay(Int64 a_TimeOfDay) virtual void SetTimeOfDay(Int64 a_TimeOfDay) // override, cannot specify due to tolua
{ {
m_TimeOfDay = a_TimeOfDay; m_TimeOfDay = a_TimeOfDay;
m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0; m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0;
@ -191,35 +192,35 @@ public:
void BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = NULL); void BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = NULL);
// tolua_end // tolua_end
void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);
void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL);
void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = NULL); void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL); void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL); virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) override;
void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); // tolua_export void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); // tolua_export
void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL); void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL); void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
void BroadcastScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); void BroadcastScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
void BroadcastScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode); void BroadcastScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode);
void BroadcastDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display); void BroadcastDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display);
void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8 void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8
void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export void BroadcastSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export
void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL); void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL);
virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ); virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override;
void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL); void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL);
virtual cBroadcastInterface & GetBroadcastManager() virtual cBroadcastInterface & GetBroadcastManager(void) override
{ {
return *this; return *this;
} }
@ -273,7 +274,7 @@ public:
void RemovePlayer( cPlayer* a_Player ); void RemovePlayer( cPlayer* a_Player );
/** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */ /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << virtual bool ForEachPlayer(cPlayerListCallback & a_Callback) override; // >> EXPORTED IN MANUALBINDINGS <<
/** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored */ /** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored */
bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
@ -365,7 +366,7 @@ public:
bool IsChunkLighted(int a_ChunkX, int a_ChunkZ); bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
/** Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully */ /** Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully */
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback); virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback) override;
// tolua_begin // tolua_begin
@ -456,7 +457,7 @@ public:
// tolua_begin // tolua_begin
bool DigBlock (int a_X, int a_Y, int a_Z); bool DigBlock (int a_X, int a_Y, int a_Z);
virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player); virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player); // override, cannot specify due to tolua
double GetSpawnX(void) const { return m_SpawnX; } double GetSpawnX(void) const { return m_SpawnX; }
double GetSpawnY(void) const { return m_SpawnY; } double GetSpawnY(void) const { return m_SpawnY; }
@ -507,7 +508,7 @@ public:
| esWitherBirth | TBD | | esWitherBirth | TBD |
| esPlugin | void * | | esPlugin | void * |
*/ */
virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export // override, cannot specify due to tolua
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp
@ -604,6 +605,9 @@ public:
bool AreCommandBlocksEnabled(void) const { return m_bCommandBlocksEnabled; } bool AreCommandBlocksEnabled(void) const { return m_bCommandBlocksEnabled; }
void SetCommandBlocksEnabled(bool a_Flag) { m_bCommandBlocksEnabled = a_Flag; } 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; } bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; }
void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; } void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; }
@ -703,7 +707,7 @@ public:
bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
/** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */ /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export // override, cannot specify due to tolua
int SpawnMobFinalize(cMonster* a_Monster); int SpawnMobFinalize(cMonster* a_Monster);
/** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */ /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */
@ -861,6 +865,11 @@ private:
/** Whether prefixes such as [INFO] are prepended to SendMessageXXX() / BroadcastChatXXX() functions */ /** Whether prefixes such as [INFO] are prepended to SendMessageXXX() / BroadcastChatXXX() functions */
bool m_bUseChatPrefixes; 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; cChunkGenerator m_Generator;

View File

@ -20,8 +20,14 @@ void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFa
a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker); a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail); a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
a_Writer.AddByte("Type", a_FireworkItem.m_Type); a_Writer.AddByte("Type", a_FireworkItem.m_Type);
a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size()); if (!a_FireworkItem.m_Colours.empty())
a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size()); {
a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
}
if (!a_FireworkItem.m_FadeColours.empty())
{
a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
}
a_Writer.EndCompound(); a_Writer.EndCompound();
a_Writer.EndList(); a_Writer.EndList();
a_Writer.EndCompound(); a_Writer.EndCompound();

View File

@ -29,6 +29,9 @@
#include "../Entities/Pickup.h" #include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h" #include "../Entities/ProjectileEntity.h"
#include "../Entities/TNTEntity.h" #include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
#include "../Entities/ItemFrame.h"
#include "../Mobs/Monster.h" #include "../Mobs/Monster.h"
#include "../Mobs/Bat.h" #include "../Mobs/Bat.h"
@ -526,8 +529,8 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup)
m_Writer.BeginCompound(""); m_Writer.BeginCompound("");
AddBasicEntity(a_Pickup, "Item"); AddBasicEntity(a_Pickup, "Item");
AddItem(a_Pickup->GetItem(), -1, "Item"); AddItem(a_Pickup->GetItem(), -1, "Item");
m_Writer.AddShort("Health", a_Pickup->GetHealth()); m_Writer.AddShort("Health", (Int16)(unsigned char)a_Pickup->GetHealth());
m_Writer.AddShort("Age", a_Pickup->GetAge()); m_Writer.AddShort("Age", (Int16)a_Pickup->GetAge());
m_Writer.EndCompound(); m_Writer.EndCompound();
} }
@ -592,6 +595,25 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
{
m_Writer.AddByte("Direction", (unsigned char)a_Hanging->GetDirection());
m_Writer.AddInt("TileX", a_Hanging->GetTileX());
m_Writer.AddInt("TileY", a_Hanging->GetTileY());
m_Writer.AddInt("TileZ", a_Hanging->GetTileZ());
switch (a_Hanging->GetDirection())
{
case 0: m_Writer.AddByte("Dir", (unsigned char)2); break;
case 1: m_Writer.AddByte("Dir", (unsigned char)1); break;
case 2: m_Writer.AddByte("Dir", (unsigned char)0); break;
case 3: m_Writer.AddByte("Dir", (unsigned char)3); break;
}
}
void cNBTChunkSerializer::AddTNTEntity(cTNTEntity * a_TNT) void cNBTChunkSerializer::AddTNTEntity(cTNTEntity * a_TNT)
{ {
m_Writer.BeginCompound(""); m_Writer.BeginCompound("");
@ -604,6 +626,35 @@ void cNBTChunkSerializer::AddTNTEntity(cTNTEntity * a_TNT)
void cNBTChunkSerializer::AddExpOrbEntity(cExpOrb * a_ExpOrb)
{
m_Writer.BeginCompound("");
AddBasicEntity(a_ExpOrb, "XPOrb");
m_Writer.AddShort("Health", (Int16)(unsigned char)a_ExpOrb->GetHealth());
m_Writer.AddShort("Age", (Int16)a_ExpOrb->GetAge());
m_Writer.AddShort("Value", (Int16)a_ExpOrb->GetReward());
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddItemFrameEntity(cItemFrame * a_ItemFrame)
{
m_Writer.BeginCompound("");
AddBasicEntity(a_ItemFrame, "ItemFrame");
AddHangingEntity(a_ItemFrame);
AddItem(a_ItemFrame->GetItem(), -1, "Item");
m_Writer.AddByte("ItemRotation", (unsigned char)a_ItemFrame->GetRotation());
m_Writer.AddFloat("ItemDropChance", 1.0F);
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart) void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{ {
m_Writer.BeginList("Items", TAG_Compound); m_Writer.BeginList("Items", TAG_Compound);
@ -684,8 +735,8 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break; case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break; case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
case cEntity::etTNT: AddTNTEntity ((cTNTEntity *) a_Entity); break; case cEntity::etTNT: AddTNTEntity ((cTNTEntity *) a_Entity); break;
case cEntity::etExpOrb: /* TODO */ break; case cEntity::etExpOrb: AddExpOrbEntity ((cExpOrb *) a_Entity); break;
case cEntity::etItemFrame: /* TODO */ break; case cEntity::etItemFrame: AddItemFrameEntity ((cItemFrame *) a_Entity); break;
case cEntity::etPainting: /* TODO */ break; case cEntity::etPainting: /* TODO */ break;
case cEntity::etPlayer: return; // Players aren't saved into the world case cEntity::etPlayer: return; // Players aren't saved into the world
default: default:

View File

@ -42,6 +42,9 @@ class cPickup;
class cItemGrid; class cItemGrid;
class cProjectileEntity; class cProjectileEntity;
class cTNTEntity; class cTNTEntity;
class cExpOrb;
class cHangingEntity;
class cItemFrame;
@ -108,7 +111,10 @@ protected:
void AddMonsterEntity (cMonster * a_Monster); void AddMonsterEntity (cMonster * a_Monster);
void AddPickupEntity (cPickup * a_Pickup); void AddPickupEntity (cPickup * a_Pickup);
void AddProjectileEntity (cProjectileEntity * a_Projectile); void AddProjectileEntity (cProjectileEntity * a_Projectile);
void AddHangingEntity (cHangingEntity * a_Hanging);
void AddTNTEntity (cTNTEntity * a_TNT); void AddTNTEntity (cTNTEntity * a_TNT);
void AddExpOrbEntity (cExpOrb * a_ExpOrb);
void AddItemFrameEntity (cItemFrame * a_ItemFrame);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart); void AddMinecartChestContents(cMinecartWithChest * a_Minecart);

View File

@ -37,6 +37,9 @@
#include "../Entities/Pickup.h" #include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h" #include "../Entities/ProjectileEntity.h"
#include "../Entities/TNTEntity.h" #include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
#include "../Entities/ItemFrame.h"
@ -366,6 +369,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
{ {
case E_BLOCK_AIR: case E_BLOCK_AIR:
case E_BLOCK_LEAVES: case E_BLOCK_LEAVES:
case E_BLOCK_NEW_LEAVES:
{ {
// nothing needed // nothing needed
break; break;
@ -1098,6 +1102,18 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{ {
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx); LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
} }
else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
{
LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
else if (strncmp(a_IDTag, "XPOrb", a_IDTagLength) == 0)
{
LoadExpOrbFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
else if (strncmp(a_IDTag, "ItemFrame", a_IDTagLength) == 0)
{
LoadItemFrameFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
else if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0) else if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0)
{ {
LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx); LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
@ -1238,10 +1254,6 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{ {
LoadPigZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx); LoadPigZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
} }
else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
{
LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
// TODO: other entities // TODO: other entities
} }
@ -1384,6 +1396,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{ {
// Load item:
int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item"); int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound)) if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
{ {
@ -1394,11 +1407,27 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{ {
return; return;
} }
std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false
if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx)) if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx))
{ {
return; return;
} }
// Load health:
int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
if (Health > 0)
{
Pickup->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
}
// Load age:
int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
if (Age > 0)
{
Pickup->SetAge(a_NBT.GetShort(Age));
}
a_Entities.push_back(Pickup.release()); a_Entities.push_back(Pickup.release());
} }
@ -1406,6 +1435,148 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
{
return;
}
// Load Fuse Ticks:
int FuseTicks = a_NBT.FindChildByName(a_TagIdx, "Fuse");
if (FuseTicks > 0)
{
TNT->SetFuseTicks((int) a_NBT.GetByte(FuseTicks));
}
a_Entities.push_back(TNT.release());
}
void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::auto_ptr<cExpOrb> ExpOrb(new cExpOrb(0.0, 0.0, 0.0, 0));
if (!LoadEntityBaseFromNBT(*ExpOrb.get(), a_NBT, a_TagIdx))
{
return;
}
// Load Health:
int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
if (Health > 0)
{
ExpOrb->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
}
// Load Age:
int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
if (Age > 0)
{
ExpOrb->SetAge(a_NBT.GetShort(Age));
}
// Load Reward (Value):
int Reward = a_NBT.FindChildByName(a_TagIdx, "Value");
if (Reward > 0)
{
ExpOrb->SetReward(a_NBT.GetShort(Reward));
}
a_Entities.push_back(ExpOrb.release());
}
void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx)
{
int Direction = a_NBT.FindChildByName(a_TagIdx, "Direction");
if (Direction > 0)
{
Direction = (int)a_NBT.GetByte(Direction);
if ((Direction < 0) || (Direction > 5))
{
a_Hanging.SetDirection(BLOCK_FACE_NORTH);
}
else
{
a_Hanging.SetDirection(static_cast<eBlockFace>(Direction));
}
}
else
{
Direction = a_NBT.FindChildByName(a_TagIdx, "Dir");
if (Direction > 0)
{
switch ((int)a_NBT.GetByte(Direction))
{
case 0: a_Hanging.SetDirection(BLOCK_FACE_NORTH); break;
case 1: a_Hanging.SetDirection(BLOCK_FACE_TOP); break;
case 2: a_Hanging.SetDirection(BLOCK_FACE_BOTTOM); break;
case 3: a_Hanging.SetDirection(BLOCK_FACE_SOUTH); break;
}
}
}
int TileX = a_NBT.FindChildByName(a_TagIdx, "TileX");
int TileY = a_NBT.FindChildByName(a_TagIdx, "TileY");
int TileZ = a_NBT.FindChildByName(a_TagIdx, "TileZ");
if ((TileX > 0) && (TileY > 0) && (TileZ > 0))
{
a_Hanging.SetPosition(
(double)a_NBT.GetInt(TileX),
(double)a_NBT.GetInt(TileY),
(double)a_NBT.GetInt(TileZ)
);
}
}
void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
// Load item:
int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
{
return;
}
cItem Item;
if (!LoadItemFromNBT(Item, a_NBT, ItemTag))
{
return;
}
std::auto_ptr<cItemFrame> ItemFrame(new cItemFrame(BLOCK_FACE_NONE, 0.0, 0.0, 0.0));
if (!LoadEntityBaseFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx))
{
return;
}
ItemFrame->SetItem(Item);
LoadHangingFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx);
// Load Rotation:
int Rotation = a_NBT.FindChildByName(a_TagIdx, "ItemRotation");
if (Rotation > 0)
{
ItemFrame->SetRotation((Byte)a_NBT.GetByte(Rotation));
}
a_Entities.push_back(ItemFrame.release());
}
void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{ {
std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
@ -2178,28 +2349,6 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
{
return;
}
// Load Fuse Ticks:
int FuseTicks = a_NBT.FindChildByName(a_TagIdx, "Fuse");
if (FuseTicks > 0)
{
TNT->SetFuseTicks((int) a_NBT.GetByte(FuseTicks));
}
a_Entities.push_back(TNT.release());
}
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx) bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
{ {
double Pos[3]; double Pos[3];

View File

@ -20,6 +20,7 @@
class cItemGrid; class cItemGrid;
class cProjectileEntity; class cProjectileEntity;
class cHangingEntity;
@ -149,6 +150,10 @@ protected:
void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadTNTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadExpOrbFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadHangingFromNBT (cHangingEntity & a_Hanging,const cParsedNBT & a_NBT, int a_TagIdx);
void LoadItemFrameFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
@ -192,7 +197,6 @@ protected:
void LoadWolfFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadWolfFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPigZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadPigZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadTNTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
/// Loads entity common data from the NBT compound; returns true if successful /// Loads entity common data from the NBT compound; returns true if successful
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx); bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);