1
0

Merge remote-tracking branch 'origin/fixes'.

This commit is contained in:
madmaxoft 2013-11-13 11:08:51 +01:00
commit 293051eca8
18 changed files with 268 additions and 95 deletions

View File

@ -96,7 +96,7 @@ void cDropSpenserEntity::DropSpense(cChunk & a_Chunk)
case E_META_DROPSPENSER_FACING_ZM: SmokeDir = 1; break;
case E_META_DROPSPENSER_FACING_ZP: SmokeDir = 7; break;
}
m_World->BroadcastSoundParticleEffect(2000, m_PosX * 8, m_PosY * 8, m_PosZ * 8, SmokeDir);
m_World->BroadcastSoundParticleEffect(2000, m_PosX, m_PosY, m_PosZ, SmokeDir);
m_World->BroadcastSoundEffect("random.click", m_PosX * 8, m_PosY * 8, m_PosZ * 8, 1.0f, 1.0f);
// Update the UI window, if open:

View File

@ -57,7 +57,7 @@ void cJukeboxEntity::UsedBy(cPlayer * a_Player)
void cJukeboxEntity::PlayRecord( void )
{
m_World->BroadcastSoundParticleEffect(1005, m_PosX * 8, m_PosY * 8, m_PosZ * 8, m_Record);
m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, m_Record);
}
@ -68,8 +68,8 @@ 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->BroadcastSoundParticleEffect(1005, m_PosX * 8, m_PosY * 8, m_PosZ * 8, 0);
m_World->SpawnItemPickups(Drops, m_PosX + 0.5, m_PosY + 1, m_PosZ + 0.5, 8);
m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, 0);
}

View File

@ -243,11 +243,11 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d &
{
// The starting point is inside the bounding box.
a_LineCoeff = 0;
a_Face = BLOCK_FACE_YM; // Make it look as the top face was hit, although none really are.
a_Face = BLOCK_FACE_NONE; // No faces hit
return true;
}
char Face = 0;
char Face = BLOCK_FACE_NONE;
double Coeff = Vector3d::NO_INTERSECTION;
// Check each individual bbox face for intersection with the line, remember the one with the lowest coeff

View File

@ -1679,9 +1679,9 @@ void cChunk::CollectPickupsByPlayer(cPlayer * a_Player)
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
{
if (!(*itr)->IsPickup())
if ((!(*itr)->IsPickup()) && (!(*itr)->IsProjectile()))
{
continue; // Only pickups
continue; // Only pickups and projectiles
}
float DiffX = (float)((*itr)->GetPosX() - PosX );
float DiffY = (float)((*itr)->GetPosY() - PosY );
@ -1695,7 +1695,14 @@ void cChunk::CollectPickupsByPlayer(cPlayer * a_Player)
);
*/
MarkDirty();
(reinterpret_cast<cPickup *>(*itr))->CollectedBy( a_Player );
if ((*itr)->IsPickup())
{
(reinterpret_cast<cPickup *>(*itr))->CollectedBy(a_Player);
}
else
{
(reinterpret_cast<cProjectileEntity *>(*itr))->CollectedBy(a_Player);
}
}
else if (SqrDist < 5 * 5)
{

View File

@ -613,7 +613,7 @@ void cChunkMap::BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_S
cCSLock Lock(m_CSLayers);
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(a_SrcX / 8, a_SrcZ / 8, ChunkX, ChunkZ);
cChunkDef::BlockToChunk(a_SrcX, a_SrcZ, ChunkX, ChunkZ);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ);
if (Chunk == NULL)
{

View File

@ -729,7 +729,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
if (a_OldBlock == E_BLOCK_AIR)
{
LOGD("Digged air? wtf?");
LOGD("Dug air - what the function?");
return;
}
@ -738,7 +738,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
// The ItemHandler is also responsible for spawning the pickups
BlockHandler(a_OldBlock)->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
World->BroadcastSoundParticleEffect(2001, a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, a_OldBlock, this);
World->BroadcastSoundParticleEffect(2001, a_BlockX, a_BlockY, a_BlockZ, a_OldBlock, this);
World->DigBlock(a_BlockX, a_BlockY, a_BlockZ);
cRoot::Get()->GetPluginManager()->CallHookPlayerBrokenBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta);

View File

@ -31,8 +31,9 @@ cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_It
, m_bCollected( false )
, m_bIsPlayerCreated( IsPlayerCreated )
{
m_MaxHealth = 5;
m_Health = 5;
SetGravity(-10.5f);
SetMaxHealth(5);
SetHealth(5);
SetSpeed(a_SpeedX, a_SpeedY, a_SpeedZ);
}
@ -145,6 +146,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

@ -371,6 +371,16 @@ void cProjectileEntity::SpawnOn(cClientHandle & a_Client)
void cProjectileEntity::CollectedBy(cPlayer * a_Dest)
{
// Overriden in arrow
UNUSED(a_Dest);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cArrowEntity:
@ -378,7 +388,10 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a
super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
m_PickupState(psNoPickup),
m_DamageCoeff(2),
m_IsCritical(false)
m_IsCritical(false),
m_Timer(0),
m_bIsCollected(false),
m_HitBlockPos(Vector3i(0, 0, 0))
{
SetSpeed(a_Speed);
SetMass(0.1);
@ -398,7 +411,10 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5),
m_PickupState(psInSurvivalOrCreative),
m_DamageCoeff(2),
m_IsCritical((a_Force >= 1))
m_IsCritical((a_Force >= 1)),
m_Timer(0),
m_bIsCollected(false),
m_HitBlockPos(0, 0, 0)
{
}
@ -424,7 +440,31 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
{
if (a_HitFace == BLOCK_FACE_NONE)
{
return;
}
super::OnHitSolidBlock(a_HitPos, a_HitFace);
int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z;
if (a_HitFace != BLOCK_FACE_YP)
{
AddFaceDirection(a_X, a_Y, a_Z, a_HitFace);
}
else if (a_HitFace == BLOCK_FACE_YP) // These conditions because xoft got a little confused on block face directions, so AddFace works with all but YP & YM
{
a_Y--;
}
else
{
a_Y++;
}
m_HitBlockPos = Vector3i(a_X, a_Y, a_Z);
// 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();
@ -439,7 +479,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
{
if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer())
if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat())
{
// Not an entity that interacts with an arrow
return;
@ -452,6 +492,9 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
}
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
// Broadcast successful hit sound
m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
Destroy();
}
@ -459,6 +502,67 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
void cArrowEntity::CollectedBy(cPlayer * a_Dest)
{
if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
{
int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
if (NumAdded > 0) // Only play effects if there was space in inventory
{
m_World->BroadcastCollectPickup((const cPickup &)*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));
m_bIsCollected = true;
}
}
}
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
m_Timer += a_Dt;
if (m_bIsCollected)
{
if (m_Timer > 500.f) // 0.5 seconds
{
Destroy();
return;
}
}
else if (m_Timer > 1000 * 60 * 5) // 5 minutes
{
Destroy();
return;
}
if (m_IsInGround)
{
int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
if (Chunk == NULL)
{
// Inside an unloaded chunk, abort
return;
}
if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
{
m_IsInGround = false; // Yes, begin simulating physics again
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cThrownEggEntity:

View File

@ -53,6 +53,9 @@ public:
/// Called by the physics blocktracer when the entity hits another entity
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) {}
/// Called by Chunk when the projectile is eligible for player collection
virtual void CollectedBy(cPlayer * a_Dest);
// tolua_begin
/// Returns the kind of the projectile (fast class identification)
@ -153,9 +156,20 @@ protected:
/// If true, the arrow deals more damage
bool m_IsCritical;
/// Timer for pickup collection animation or five minute timeout
float m_Timer;
/// If true, the arrow is in the process of being collected - don't go to anyone else
bool m_bIsCollected;
/// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
Vector3i m_HitBlockPos;
// cProjectileEntity overrides:
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
virtual void CollectedBy(cPlayer * a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
// tolua_begin
} ;

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, Force);
if (!a_Player->IsGameModeCreative())
{

View File

@ -55,10 +55,10 @@ void cHorse::Tick(float a_Dt, cChunk & a_Chunk)
{
if (m_World->GetTickRandomNumber(50) == 25)
{
m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 0);
m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 2);
m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 6);
m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 8);
m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 0);
m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 2);
m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 6);
m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 8);
m_Attachee->Detach();
m_bIsRearing = true;

View File

@ -622,65 +622,78 @@ 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
// Create the mob entity
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;
}
toReturn = new cSlime (Random.NextInt(2) + 1);
break;
}
default: break;
} // switch (a_MobType)
case mtSkeleton:
{
// TODO: Actual detection of spawning in Nether
toReturn = new cSkeleton(Random.NextInt(1) == 0 ? false : true);
break;
}
case mtVillager:
{
int VillagerType = Random.NextInt(6);
if (VillagerType == 6)
{
// Give farmers a better chance of spawning
VillagerType = 0;
}
// Create the mob entity
switch (a_MobType)
{
case mtMagmaCube: toReturn = new cMagmaCube(a_Size); break;
case mtSlime: toReturn = new cSlime(a_Size); break;
case mtBat: toReturn = new cBat(); break;
case mtBlaze: toReturn = new cBlaze(); break;
case mtCaveSpider: toReturn = new cCavespider(); break;
case mtChicken: toReturn = new cChicken(); break;
case mtCow: toReturn = new cCow(); break;
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;
toReturn = new cVillager((cVillager::eVillagerType)VillagerType);
break;
}
case mtHorse:
{
// Horses take a type (species), a colour, and a style (dots, stripes, etc.)
int HorseType = Random.NextInt(7);
int HorseColor = Random.NextInt(6);
int HorseStyle = Random.NextInt(6);
int HorseTameTimes = Random.NextInt(6) + 1;
if ((HorseType == 5) || (HorseType == 6) || (HorseType == 7))
{
// Increase chances of normal horse (zero)
HorseType = 0;
}
toReturn = new cHorse(HorseType, HorseColor, HorseStyle, HorseTameTimes);
break;
}
case mtBat: toReturn = new cBat(); break;
case mtBlaze: toReturn = new cBlaze(); break;
case mtCaveSpider: toReturn = new cCavespider(); break;
case mtChicken: toReturn = new cChicken(); break;
case mtCow: toReturn = new cCow(); break;
case mtCreeper: toReturn = new cCreeper(); break;
case mtEnderman: toReturn = new cEnderman(); break;
case mtGhast: toReturn = new cGhast(); break;
case mtMooshroom: toReturn = new cMooshroom(); break;
case mtOcelot: toReturn = new cOcelot(); break;
case mtPig: toReturn = new cPig(); break;
case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter
case mtSilverfish: toReturn = new cSilverfish(); break;
case mtSpider: toReturn = new cSpider(); break;
case mtSquid: toReturn = new cSquid(); break;
case mtWitch: toReturn = new cWitch(); break;
case mtWolf: toReturn = new cWolf(); break;
case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter
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

@ -392,9 +392,9 @@ void cProtocol132::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_SOUND_PARTICLE_EFFECT);
WriteInt (a_EffectID);
WriteInt (a_SrcX / 8);
WriteByte(a_SrcY / 8);
WriteInt (a_SrcZ / 8);
WriteInt (a_SrcX);
WriteByte(a_SrcY);
WriteInt (a_SrcZ);
WriteInt (a_Data);
Flush();
}

View File

@ -109,9 +109,9 @@ void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_SOUND_PARTICLE_EFFECT);
WriteInt (a_EffectID);
WriteInt (a_SrcX / 8);
WriteByte(a_SrcY / 8);
WriteInt (a_SrcZ / 8);
WriteInt (a_SrcX);
WriteByte(a_SrcY);
WriteInt (a_SrcZ);
WriteInt (a_Data);
WriteBool(0);
Flush();

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(EscapeString(a_Reason));
Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
}
@ -615,9 +616,9 @@ 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 / 8);
Pkt.WriteByte(a_SrcY / 8);
Pkt.WriteInt(a_SrcZ / 8);
Pkt.WriteInt(a_SrcX);
Pkt.WriteByte(a_SrcY);
Pkt.WriteInt(a_SrcZ);
Pkt.WriteInt(a_Data);
Pkt.WriteBool(false);
}
@ -819,9 +820,13 @@ void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc
void cProtocol172::SendWeather(eWeather a_Weather)
{
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
Pkt.WriteByte((a_Weather == wSunny) ? 2 : 1); // begin rain / end rain
Pkt.WriteFloat(0); // unused
{
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain
Pkt.WriteFloat(0); // Unused for weather
}
// TODO: Fade effect, somehow
}
@ -1664,12 +1669,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

@ -224,9 +224,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
ItemTypeToString(NewBlock).c_str()
);
a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0);
// TODO: Sound effect
m_World.BroadcastSoundEffect("random.fizz", a_RelX * 8, a_RelY * 8, a_RelZ * 8, 0.5f, 1.5f);
return;
}
}
@ -240,9 +238,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
a_RelX, a_RelY, a_RelZ, ItemTypeToString(NewBlock).c_str()
);
a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0);
// TODO: Sound effect
m_World.BroadcastSoundEffect("random.fizz", a_RelX * 8, a_RelY * 8, a_RelZ * 8, 0.5f, 1.5f);
return;
}
}

View File

@ -1512,7 +1512,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
{
float SpeedX = (float)(a_FlyAwaySpeed * (r1.randInt(1000) - 500));
float SpeedY = 1;
float SpeedY = (float)(a_FlyAwaySpeed * (r1.randInt(1000) - 500));
float SpeedZ = (float)(a_FlyAwaySpeed * (r1.randInt(1000) - 500));
cPickup * Pickup = new cPickup(
@ -2563,15 +2563,16 @@ 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
BroadcastSoundParticleEffect(2004, (int)a_PosX, (int)a_PosY, (int)a_PosZ, 0);
return SpawnMobFinalize(Monster);
}