Bundled fixes [SEE DESC]

* Fixed pickups spawning in an incorrect position from a JukeBox
* Pickups make a popping sound in Prtcl1.7
* Arrows make a *what sort of sound does an arrow make anyway‽* when
hitting a block, and a popping sound when fired
* Mobs again have metadata
* Fixed Prtcl1.7 not using valid JSON to kick a client
* Minecarts and arrows again have metadata
master
Tiger Wang 2013-11-10 20:48:12 +00:00
parent b6ca98f380
commit 71abbb2f56
8 changed files with 80 additions and 48 deletions

View File

@ -68,7 +68,7 @@ void cJukeboxEntity::EjectRecord( void )
{
cItems Drops;
Drops.push_back(cItem(m_Record, 1, 0));
m_World->SpawnItemPickups(Drops, m_PosX, m_PosY+1, m_PosZ);
m_World->SpawnItemPickups(Drops, m_PosX + 0.5, m_PosY + 1, m_PosZ + 0.5, 5);
m_World->BroadcastSoundParticleEffect(1005, m_PosX * 8, m_PosY * 8, m_PosZ * 8, 0);
}

View File

@ -145,6 +145,8 @@ bool cPickup::CollectedBy(cPlayer * a_Dest)
{
m_Item.m_ItemCount -= NumAdded;
m_World->BroadcastCollectPickup(*this, *a_Dest);
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
m_World->BroadcastSoundEffect("random.pop",(int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
if (m_Item.m_ItemCount == 0)
{
// All of the pickup has been collected, schedule the pickup for destroying

View File

@ -425,6 +425,9 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
{
super::OnHitSolidBlock(a_HitPos, a_HitFace);
// Broadcast arrow hit sound
m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
// Broadcast the position and speed packets before teleporting:
BroadcastMovementUpdate();

View File

@ -36,6 +36,7 @@ public:
{
return false;
}
a_Player->StartChargingBow();
return true;
}
@ -71,6 +72,7 @@ public:
return;
}
a_Player->GetWorld()->BroadcastSpawnEntity(*Arrow);
a_Player->GetWorld()->BroadcastSoundEffect("random.bow", (int)a_Player->GetPosX() * 8, (int)a_Player->GetPosY() * 8, (int)a_Player->GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((Arrow->GetUniqueID() * 23) % 32)) / 64));
if (!a_Player->IsGameModeCreative())
{

View File

@ -622,37 +622,41 @@ int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily)
cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType, int a_Size)
cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
{
cFastRandom Random;
cMonster * toReturn = NULL;
// unspecified size get rand[1,3] for Monsters that need size
switch (a_MobType)
{
case mtMagmaCube:
case mtSlime:
{
if (a_Size == -1)
{
a_Size = Random.NextInt(2, a_MobType) + 1;
}
if ((a_Size <= 0) || (a_Size >= 4))
{
ASSERT(!"Random for size was supposed to pick in [1..3] and picked outside");
a_Size = 1;
}
break;
}
default: break;
} // switch (a_MobType)
cFastRandom RandomDerps;
// Create the mob entity
switch (a_MobType)
{
case mtMagmaCube: toReturn = new cMagmaCube(a_Size); break;
case mtSlime: toReturn = new cSlime(a_Size); break;
case mtMagmaCube:
case mtSlime: toReturn = new cSlime (RandomDerps.NextInt(2) + 1); break; // Size parameter
case mtSheep: toReturn = new cSheep (RandomDerps.NextInt(15)); break; // Colour parameter
case mtSkeleton: toReturn = new cSkeleton ((bool)(RandomDerps.NextInt(1))); break; // TODO: Actual detection of spawning in Nether
case mtZombie: toReturn = new cZombie (false); break; // TODO: Infected zombie parameter
case mtVillager:
{
int VilType = RandomDerps.NextInt(6);
if (VilType == 6) { VilType = 0; } // Give farmers a better chance of spawning
toReturn = new cVillager(cVillager::eVillagerType(VilType)); // Type (blacksmith, butcher, etc.) parameter
break;
}
case mtHorse:
{
// Horses take a type (species), a colour, and a style (dots, stripes, etc.)
int HseType = RandomDerps.NextInt(7);
int HseColor = RandomDerps.NextInt(6);
int HseStyle = RandomDerps.NextInt(6);
int HseTameTimes = RandomDerps.NextInt(6) + 1;
if ((HseType == 5) || (HseType == 6) || (HseType == 7)) { HseType = 0; } // Increase chances of normal horse (zero)
toReturn = new cHorse(HseType, HseColor, HseStyle, HseTameTimes);
break;
}
case mtBat: toReturn = new cBat(); break;
case mtBlaze: toReturn = new cBlaze(); break;
case mtCaveSpider: toReturn = new cCavespider(); break;
@ -661,26 +665,18 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType, int a_Size)
case mtCreeper: toReturn = new cCreeper(); break;
case mtEnderman: toReturn = new cEnderman(); break;
case mtGhast: toReturn = new cGhast(); break;
// TODO:
// case cMonster::mtHorse: toReturn = new cHorse(); break;
case mtMooshroom: toReturn = new cMooshroom(); break;
case mtOcelot: toReturn = new cOcelot(); break;
case mtPig: toReturn = new cPig(); break;
// TODO: Implement sheep color
case mtSheep: toReturn = new cSheep(0); break;
case mtSilverfish: toReturn = new cSilverfish(); break;
// TODO: Implement wither skeleton geration
case mtSkeleton: toReturn = new cSkeleton(false); break;
case mtSpider: toReturn = new cSpider(); break;
case mtSquid: toReturn = new cSquid(); break;
case mtVillager: toReturn = new cVillager(cVillager::vtFarmer); break;
case mtWitch: toReturn = new cWitch(); break;
case mtWolf: toReturn = new cWolf(); break;
case mtZombie: toReturn = new cZombie(false); break;
case mtZombiePigman: toReturn = new cZombiePigman(); break;
default:
{
ASSERT(!"Unhandled Mob type");
ASSERT(!"Unhandled mob type whilst trying to spawn mob!");
}
}
return toReturn;

View File

@ -153,12 +153,9 @@ public:
/** Creates a new object of the specified mob.
a_MobType is the type of the mob to be created
a_Size is the size (for mobs with size)
if a_Size is let to -1 for entities that need size, size will be random
asserts and returns null if mob type is not specified
asserts if invalid size for mobs that need size
Asserts and returns null if mob type is not specified
*/
static cMonster * NewMonsterFromType(eType a_MobType, int a_Size = -1);
static cMonster * NewMonsterFromType(eType a_MobType);
protected:

View File

@ -17,6 +17,7 @@ Implements the 1.7.x protocol classes:
#include "../World.h"
#include "../WorldStorage/FastNBT.h"
#include "../StringCompression.h"
#include "../Entities/Minecart.h"
#include "../Entities/FallingBlock.h"
#include "../Entities/Pickup.h"
#include "../Entities/Player.h"
@ -215,7 +216,7 @@ void cProtocol172::SendDestroyEntity(const cEntity & a_Entity)
void cProtocol172::SendDisconnect(const AString & a_Reason)
{
cPacketizer Pkt(*this, 0x40);
Pkt.WriteString(a_Reason);
Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
}
@ -615,9 +616,7 @@ void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
{
cPacketizer Pkt(*this, 0x28); // Effect packet
Pkt.WriteInt(a_EffectID);
Pkt.WriteInt(a_SrcX);
// TODO: Check if this is really an int
// wiki.vg says it's a byte, but that wouldn't cover the entire range needed (Y location * 8 = 0..2048)
Pkt.WriteByte(a_SrcX);
Pkt.WriteInt(a_SrcY);
Pkt.WriteInt(a_SrcZ);
Pkt.WriteInt(a_Data);
@ -1666,12 +1665,43 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
WriteItem(((const cPickup &)a_Entity).GetItem());
break;
}
case cEntity::etMinecart:
{
WriteByte(0x51);
// The following expression makes Minecarts shake more with less health or higher damage taken
// It gets half the maximum health, and takes it away from the current health minus the half health:
/* Health: 5 | 3 - (5 - 3) = 1 (shake power)
Health: 3 | 3 - (3 - 3) = 3
Health: 1 | 3 - (1 - 3) = 5
*/
WriteInt((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * ((const cMinecart &)a_Entity).LastDamage()) * 4);
WriteByte(0x52);
WriteInt(1); // Shaking direction, doesn't seem to affect anything
WriteByte(0x73);
WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer
if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
{
WriteByte(0x10);
WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0);
}
break;
}
case cEntity::etProjectile:
{
if (((cProjectileEntity &)a_Entity).GetProjectileKind() == cProjectileEntity::pkArrow)
{
WriteByte(0x10);
WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
}
break;
}
case cEntity::etMonster:
{
WriteMobMetadata((const cMonster &)a_Entity);
break;
}
// TODO: Other types
}
}

View File

@ -2563,15 +2563,17 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ)
int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType)
{
cMonster * Monster = NULL;
int ShColor = GetTickRandomNumber(15); // 0 .. 15 - Sheep
bool SkType = GetDimension() == dimNether ; // Skeleton
Monster = cMonster::NewMonsterFromType(a_MonsterType);
if (Monster != NULL)
{
Monster->SetPosition(a_PosX, a_PosY, a_PosZ);
}
// Because it's logical that ALL mob spawns need spawn effects, not just spawners
// TODO: Not working - wiki.vg outdated?
BroadcastSoundParticleEffect(2004, (int)a_PosX, (int)a_PosY, (int)a_PosZ, 0);
return SpawnMobFinalize(Monster);
}