diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 44e4bb35f..9f558f58c 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2075,6 +2075,7 @@ end { Params = "{{cItems|Pickups}}, X, Y, Z, SpeedX, SpeedY, SpeedZ", Return = "", Notes = "Spawns the specified pickups at the position specified. All the pickups fly away from the spawn position using the specified speed." }, }, SpawnMob = { Params = "X, Y, Z, {{cMonster|MonsterType}}", Return = "EntityID", Notes = "Spawns the specified type of mob at the specified coords. Returns the EntityID of the creates entity, or -1 on failure. " }, + SpawnExperienceOrb = { Params = "X, Y, Z, Reward", Return = "", Notes = "Spawns an {{cExpOrb|experience orb at the specified coords, with the given reward" }, SpawnPrimedTNT = { Params = "X, Y, Z, FuseTimeSecs, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse time. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." }, TryGetHeight = { Params = "BlockX, BlockZ", Return = "IsValid, Height", Notes = "Returns true and height of the highest non-air block if the chunk is loaded, or false otherwise." }, UnloadUnusedChunks = { Params = "", Return = "", Notes = "Unloads chunks that are no longer needed, and are saved. NOTE: This API is deprecated and will be removed soon." }, diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 93a34d90a..f9acdd852 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -1267,6 +1267,14 @@ RelativePath="..\source\Entities\ProjectileEntity.h" > + + + + diff --git a/source/Bindings.cpp b/source/Bindings.cpp index ad3ad8423..7bea672da 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/23/13 19:57:30. +** Generated automatically by tolua++-1.0.92 on 11/25/13 21:47:32. */ #ifndef __cplusplus @@ -12589,6 +12589,45 @@ tolua_lerror: } #endif //#ifndef TOLUA_DISABLE +/* method: SpawnExperienceOrb of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_SpawnExperienceOrb00 +static int tolua_AllToLua_cWorld_SpawnExperienceOrb00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnoobj(tolua_S,6,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); + double a_X = ((double) tolua_tonumber(tolua_S,2,0)); + double a_Y = ((double) tolua_tonumber(tolua_S,3,0)); + double a_Z = ((double) tolua_tonumber(tolua_S,4,0)); + int a_Reward = ((int) tolua_tonumber(tolua_S,5,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SpawnExperienceOrb'", NULL); +#endif + { + self->SpawnExperienceOrb(a_X,a_Y,a_Z,a_Reward); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SpawnExperienceOrb'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: SpawnPrimedTNT of class cWorld */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_SpawnPrimedTNT00 static int tolua_AllToLua_cWorld_SpawnPrimedTNT00(lua_State* tolua_S) @@ -30430,6 +30469,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"etBoat",cEntity::etBoat); tolua_constant(tolua_S,"etTNT",cEntity::etTNT); tolua_constant(tolua_S,"etProjectile",cEntity::etProjectile); + tolua_constant(tolua_S,"etExpOrb",cEntity::etExpOrb); tolua_constant(tolua_S,"etMob",cEntity::etMob); tolua_function(tolua_S,"GetEntityType",tolua_AllToLua_cEntity_GetEntityType00); tolua_function(tolua_S,"IsPlayer",tolua_AllToLua_cEntity_IsPlayer00); @@ -30801,6 +30841,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"SetBlockMeta",tolua_AllToLua_cWorld_SetBlockMeta01); tolua_function(tolua_S,"SpawnItemPickups",tolua_AllToLua_cWorld_SpawnItemPickups00); tolua_function(tolua_S,"SpawnItemPickups",tolua_AllToLua_cWorld_SpawnItemPickups01); + tolua_function(tolua_S,"SpawnExperienceOrb",tolua_AllToLua_cWorld_SpawnExperienceOrb00); tolua_function(tolua_S,"SpawnPrimedTNT",tolua_AllToLua_cWorld_SpawnPrimedTNT00); tolua_function(tolua_S,"DigBlock",tolua_AllToLua_cWorld_DigBlock00); tolua_function(tolua_S,"SendBlockTo",tolua_AllToLua_cWorld_SendBlockTo00); diff --git a/source/Bindings.h b/source/Bindings.h index bc8589293..8d20bd0dc 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/23/13 19:57:31. +** Generated automatically by tolua++-1.0.92 on 11/25/13 21:47:33. */ /* Exported function */ diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index daf09d4ea..b3e12ce77 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -1885,6 +1885,15 @@ void cClientHandle::SendExperience(void) +void cClientHandle::SendExperienceOrb(const cExpOrb & a_ExpOrb) +{ + m_Protocol->SendExperienceOrb(a_ExpOrb); +} + + + + + void cClientHandle::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch); diff --git a/source/ClientHandle.h b/source/ClientHandle.h index b887bb11a..b3550110d 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -25,6 +25,7 @@ class cChunkDataSerializer; class cInventory; class cMonster; class cPawn; +class cExpOrb; class cPickup; class cPlayer; class cProtocol; @@ -121,6 +122,7 @@ public: void SendPlayerSpawn (const cPlayer & a_Player); void SendRespawn (void); void SendExperience (void); + void SendExperienceOrb (const cExpOrb & a_ExpOrb); void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch); // a_Src coords are Block * 8 void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data); void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h index dafda7826..de5f176ae 100644 --- a/source/Entities/Entity.h +++ b/source/Entities/Entity.h @@ -74,6 +74,7 @@ public: etBoat, etTNT, etProjectile, + etExpOrb, // Common variations etMob = etMonster, // DEPRECATED, use etMonster instead! diff --git a/source/Entities/ExpOrb.cpp b/source/Entities/ExpOrb.cpp new file mode 100644 index 000000000..1e5ee00ce --- /dev/null +++ b/source/Entities/ExpOrb.cpp @@ -0,0 +1,60 @@ +#include "Globals.h" + +#include "ExpOrb.h" +#include "Player.h" +#include "../ClientHandle.h" + + +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), + m_Reward(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), + m_Reward(a_Reward) +{ +} + + + + + +void cExpOrb::SpawnOn(cClientHandle & a_Client) +{ + a_Client.SendExperienceOrb(*this); + m_bDirtyPosition = false; + m_bDirtySpeed = false; + m_bDirtyOrientation = false; + m_bDirtyHead = false; +} + + + + + +void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk) +{ + cPlayer * a_ClosestPlayer(m_World->FindClosestPlayer(Vector3f(GetPosition()), 4)); + if (a_ClosestPlayer) + { + Vector3f a_PlayerPos(a_ClosestPlayer->GetPosition()); + Vector3f a_Distance(a_PlayerPos - GetPosition()); + if (a_Distance.Length() < 0.1f) + { + a_ClosestPlayer->DeltaExperience(m_Reward); + a_ClosestPlayer->SendExperience(); + Destroy(true); + } + a_Distance.y = 0; + a_Distance.Normalize(); + a_Distance *= 3; + SetSpeedX( a_Distance.x ); + SetSpeedZ( a_Distance.z ); + } +} \ No newline at end of file diff --git a/source/Entities/ExpOrb.h b/source/Entities/ExpOrb.h new file mode 100644 index 000000000..a062eedd3 --- /dev/null +++ b/source/Entities/ExpOrb.h @@ -0,0 +1,29 @@ + +#pragma once + +#include "Entity.h" + + + + + +class cExpOrb : + public cEntity +{ + typedef cExpOrb super; + +public: + + cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward); + cExpOrb(const Vector3d & a_Pos, int a_Reward); + + // Override functions + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void SpawnOn(cClientHandle & a_Client) override; + + // cExpOrb functions + int GetReward(void) const { return m_Reward; } + +protected: + int m_Reward; +} ; \ No newline at end of file diff --git a/source/Mobs/Monster.cpp b/source/Mobs/Monster.cpp index 8a5717e27..091623c8a 100644 --- a/source/Mobs/Monster.cpp +++ b/source/Mobs/Monster.cpp @@ -7,6 +7,7 @@ #include "../ClientHandle.h" #include "../World.h" #include "../Entities/Player.h" +#include "../Entities/ExpOrb.h" #include "../Defines.h" #include "../MonsterConfig.h" #include "../MersenneTwister.h" @@ -258,6 +259,60 @@ void cMonster::KilledBy(cEntity * a_Killer) { m_World->BroadcastSoundEffect(m_SoundDeath, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f); } + int Reward; + switch (m_MobType) + { + // Animals + case cMonster::mtChicken: + case cMonster::mtCow: + case cMonster::mtHorse: + case cMonster::mtPig: + case cMonster::mtSheep: + case cMonster::mtSquid: + case cMonster::mtMooshroom: + case cMonster::mtOcelot: + case cMonster::mtWolf: + { + Reward = m_World->GetTickRandomNumber(2) + 1; + } + + // Monsters + case cMonster::mtCaveSpider: + case cMonster::mtCreeper: + case cMonster::mtEnderman: + case cMonster::mtGhast: + case cMonster::mtSilverfish: + case cMonster::mtSkeleton: + case cMonster::mtSpider: + case cMonster::mtWitch: + case cMonster::mtZombie: + case cMonster::mtZombiePigman: + case cMonster::mtSlime: + case cMonster::mtMagmaCube: + { + Reward = 6 + (m_World->GetTickRandomNumber(2)); + } + case cMonster::mtBlaze: + { + Reward = 10; + } + + // Bosses + case cMonster::mtEnderDragon: + { + Reward = 12000; + } + case cMonster::mtWither: + { + Reward = 50; + } + + default: + { + Reward = 0; + } + } + m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward); m_DestroyTimer = 0; } diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h index 542060ece..9d8183361 100644 --- a/source/Protocol/Protocol.h +++ b/source/Protocol/Protocol.h @@ -16,6 +16,7 @@ +class cExpOrb; class cPlayer; class cEntity; class cWindow; @@ -86,6 +87,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendRespawn (void) = 0; virtual void SendExperience (void) = 0; + virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) = 0; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0; diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index 54be65b12..b1dd17ea1 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -17,6 +17,7 @@ Documentation: #include "../World.h" #include "ChunkDataSerializer.h" #include "../Entities/Entity.h" +#include "../Entities/ExpOrb.h" #include "../Mobs/Monster.h" #include "../Entities/Pickup.h" #include "../Entities/Player.h" @@ -72,6 +73,7 @@ enum PACKET_ENT_STATUS = 0x26, PACKET_ATTACH_ENTITY = 0x27, PACKET_METADATA = 0x28, + PACKET_SPAWN_EXPERIENCE_ORB = 0x1A, PACKET_EXPERIENCE = 0x2b, PACKET_PRE_CHUNK = 0x32, PACKET_MAP_CHUNK = 0x33, @@ -705,6 +707,22 @@ void cProtocol125::SendExperience(void) +void cProtocol125::SendExperienceOrb(const cExpOrb & a_ExpOrb) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SPAWN_EXPERIENCE_ORB); + WriteInt(a_ExpOrb.GetUniqueID()); + WriteInt((int) a_ExpOrb.GetPosX()); + WriteInt((int) a_ExpOrb.GetPosY()); + WriteInt((int) a_ExpOrb.GetPosZ()); + WriteShort(a_ExpOrb.GetReward()); + Flush(); +} + + + + + void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { // Not needed in this protocol version diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h index c5f44c818..5a9218f5b 100644 --- a/source/Protocol/Protocol125.h +++ b/source/Protocol/Protocol125.h @@ -63,6 +63,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; virtual void SendExperience (void) override; + virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; diff --git a/source/Protocol/Protocol17x.cpp b/source/Protocol/Protocol17x.cpp index ae1df7395..746e1c127 100644 --- a/source/Protocol/Protocol17x.cpp +++ b/source/Protocol/Protocol17x.cpp @@ -17,6 +17,7 @@ Implements the 1.7.x protocol classes: #include "../World.h" #include "../WorldStorage/FastNBT.h" #include "../StringCompression.h" +#include "../Entities/ExpOrb.h" #include "../Entities/Minecart.h" #include "../Entities/FallingBlock.h" #include "../Entities/Pickup.h" @@ -609,6 +610,20 @@ void cProtocol172::SendExperience (void) +void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb) +{ + cPacketizer Pkt(*this, 0x11); + Pkt.WriteVarInt(a_ExpOrb.GetUniqueID()); + Pkt.WriteInt((int) a_ExpOrb.GetPosX()); + Pkt.WriteInt((int) a_ExpOrb.GetPosY()); + Pkt.WriteInt((int) a_ExpOrb.GetPosZ()); + Pkt.WriteShort(a_ExpOrb.GetReward()); +} + + + + + void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8 { cPacketizer Pkt(*this, 0x29); // Sound Effect packet diff --git a/source/Protocol/Protocol17x.h b/source/Protocol/Protocol17x.h index e3f2ad922..255cb4ef5 100644 --- a/source/Protocol/Protocol17x.h +++ b/source/Protocol/Protocol17x.h @@ -73,6 +73,7 @@ public: virtual void SendRespawn (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendExperience (void) override; + virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; diff --git a/source/Protocol/ProtocolRecognizer.cpp b/source/Protocol/ProtocolRecognizer.cpp index 64bd83075..489149d74 100644 --- a/source/Protocol/ProtocolRecognizer.cpp +++ b/source/Protocol/ProtocolRecognizer.cpp @@ -476,6 +476,16 @@ void cProtocolRecognizer::SendExperience(void) +void cProtocolRecognizer::SendExperienceOrb(const cExpOrb & a_ExpOrb) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendExperienceOrb(a_ExpOrb); +} + + + + + void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { ASSERT(m_Protocol != NULL); diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h index 03f48fb35..9ca0c1c88 100644 --- a/source/Protocol/ProtocolRecognizer.h +++ b/source/Protocol/ProtocolRecognizer.h @@ -98,6 +98,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; virtual void SendExperience (void) override; + virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; diff --git a/source/World.cpp b/source/World.cpp index 531952e37..432ab32e9 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -13,6 +13,7 @@ #include "OSSupport/Timer.h" // Entities (except mobs): +#include "Entities/ExpOrb.h" #include "Entities/Pickup.h" #include "Entities/Player.h" #include "Entities/TNTEntity.h" @@ -1561,6 +1562,16 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double +void cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) +{ + cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward); + ExpOrb->Initialize(this); +} + + + + + void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff) { cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTimeInSec); diff --git a/source/World.h b/source/World.h index d10aa3b78..9397f8b75 100644 --- a/source/World.h +++ b/source/World.h @@ -353,6 +353,9 @@ public: /// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false); + /// Spawns an experience orb at the given location with the given reward. + void SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward); + /// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);