#ifndef _WIN32 #include #endif #include "cPickup.h" #include "cClientHandle.h" #include "cInventory.h" #include "cWorld.h" #include "cServer.h" #include "cPlayer.h" #include "cPluginManager.h" #include "cItem.h" #include "cRoot.h" #include "cMCLogger.h" #include "cTracer.h" #include "cChunk.h" #include "packets/cPacket_TeleportEntity.h" #include "packets/cPacket_PickupSpawn.h" #include "packets/cPacket_CollectItem.h" #include "Vector3d.h" #include "Vector3f.h" CLASS_DEFINITION( cPickup, cEntity ) cPickup::~cPickup() { delete m_Item; delete m_Speed; } cPickup::cPickup(int a_X, int a_Y, int a_Z, const cItem & a_Item, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */) : cEntity( ((double)(a_X))/32, ((double)(a_Y))/32, ((double)(a_Z))/32 ) , m_Speed( new Vector3f( a_SpeedX, a_SpeedY, a_SpeedZ ) ) , m_bOnGround( false ) , m_bReplicated( false ) , m_Timer( 0.f ) , m_Item( new cItem( a_Item ) ) , m_bCollected( false ) { //LOG("New pickup: ID(%i) Amount(%i) Health(%i)", m_Item.m_ItemID, m_Item.m_ItemCount, m_Item.m_ItemHealth ); // Spawn it on clients cPacket_PickupSpawn PickupSpawn; PickupSpawn.m_UniqueID = m_UniqueID; PickupSpawn.m_Item = (short)m_Item->m_ItemID; PickupSpawn.m_Count = m_Item->m_ItemCount; PickupSpawn.m_Health = m_Item->m_ItemHealth; PickupSpawn.m_PosX = a_X; PickupSpawn.m_PosY = a_Y; PickupSpawn.m_PosZ = a_Z; PickupSpawn.m_Rotation = (char)(m_Speed->x * 8); PickupSpawn.m_Pitch = (char)(m_Speed->y * 8); PickupSpawn.m_Roll = (char)(m_Speed->z * 8); cRoot::Get()->GetServer()->Broadcast( PickupSpawn ); m_EntityType = E_PICKUP; } cPickup::cPickup(cPacket_PickupSpawn* a_PickupSpawnPacket) : cEntity( ((double)a_PickupSpawnPacket->m_PosX)/32, ((double)a_PickupSpawnPacket->m_PosY)/32, ((double)a_PickupSpawnPacket->m_PosZ)/32 ) , m_Speed( new Vector3f() ) , m_bOnGround( false ) , m_bReplicated( false ) , m_Timer( 0.f ) , m_bCollected( false ) { a_PickupSpawnPacket->m_UniqueID = m_UniqueID; m_Item = new cItem(); m_Item->m_ItemID = (ENUM_ITEM_ID)a_PickupSpawnPacket->m_Item; m_Item->m_ItemCount = a_PickupSpawnPacket->m_Count; m_Item->m_ItemHealth = 0x0; m_Speed->x = (float)(a_PickupSpawnPacket->m_Rotation) / 8; m_Speed->y = (float)(a_PickupSpawnPacket->m_Pitch) / 8; m_Speed->z = (float)(a_PickupSpawnPacket->m_Roll) / 8; // Spawn it on clients cRoot::Get()->GetServer()->Broadcast( *a_PickupSpawnPacket ); m_EntityType = E_PICKUP; } void cPickup::SpawnOn( cClientHandle* a_Target ) { cPacket_PickupSpawn PickupSpawn; PickupSpawn.m_UniqueID = m_UniqueID; PickupSpawn.m_Item = (short)m_Item->m_ItemID; PickupSpawn.m_Count = m_Item->m_ItemCount; PickupSpawn.m_Health = m_Item->m_ItemHealth; PickupSpawn.m_PosX = (int)(m_Pos->x * 32); PickupSpawn.m_PosY = (int)(m_Pos->y * 32); PickupSpawn.m_PosZ = (int)(m_Pos->z * 32); PickupSpawn.m_Rotation = (char)(m_Speed->x * 8); PickupSpawn.m_Pitch = (char)(m_Speed->y * 8); PickupSpawn.m_Roll = (char)(m_Speed->z * 8); a_Target->Send( PickupSpawn ); } void cPickup::Tick(float a_Dt) { m_Timer+=a_Dt; a_Dt = a_Dt / 1000.f; if(m_bCollected) { if(m_Timer > 500.f) // 0.5 second { Destroy(); return; } } if( m_Timer > 1000*60*5 ) // 5 minutes { Destroy(); return; } if( m_Pos->y < 0 ) // Out of this world! { Destroy(); return; } HandlePhysics( a_Dt ); if( !m_bReplicated || m_bDirtyPosition ) { MoveToCorrectChunk(); m_bReplicated = true; m_bDirtyPosition = false; cChunk* Chunk = GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ ); if( Chunk ) { cPacket_TeleportEntity TeleportEntity( this ); Chunk->Broadcast( TeleportEntity ); } } //printf("YSpeed: %f, OnGround: %i\n", m_SpeedY, m_bOnGround ); } void cPickup::HandlePhysics(float a_Dt) { if( m_bOnGround ) // check if it's still on the ground { cWorld* World = GetWorld(); int BlockX = (int)m_Pos->x; if( m_Pos->x < 0 ) BlockX--; int BlockZ = (int)m_Pos->z; if( m_Pos->z < 0 ) BlockZ--; if( World->GetBlock( BlockX, (int)m_Pos->y -1, BlockZ ) == E_BLOCK_AIR ) { m_bOnGround = false; } if( World->GetBlock( BlockX, (int)m_Pos->y, BlockZ ) != E_BLOCK_AIR ) // If in ground itself, push it out { m_bOnGround = true; m_Pos->y += 0.2; m_bReplicated = false; } m_Speed->x *= 0.7f/(1+a_Dt); if( fabs(m_Speed->x) < 0.05 ) m_Speed->x = 0; m_Speed->z *= 0.7f/(1+a_Dt); if( fabs(m_Speed->z) < 0.05 ) m_Speed->z = 0; } if( !m_bOnGround ) { float Gravity = -9.81f*a_Dt; m_Speed->y += Gravity; cTracer Tracer( GetWorld() ); int Ret = Tracer.Trace( *m_Pos, *m_Speed, 2 ); if( Ret ) // Oh noez! we hit something { // Set to hit position if( (*Tracer.RealHit - Vector3f(*m_Pos)).SqrLength() <= ( *m_Speed * a_Dt ).SqrLength() ) { m_bReplicated = false; // It's only interesting to replicate when we actually hit something... if( Ret == 1 ) { if( Tracer.HitNormal->x != 0.f ) m_Speed->x = 0.f; if( Tracer.HitNormal->y != 0.f ) m_Speed->y = 0.f; if( Tracer.HitNormal->z != 0.f ) m_Speed->z = 0.f; if( Tracer.HitNormal->y > 0 ) // means on ground { m_bOnGround = true; } } *m_Pos = Tracer.RealHit; *m_Pos += *Tracer.HitNormal * 0.2; } else *m_Pos += *m_Speed*a_Dt; } else { // We didn't hit anything, so move =] *m_Pos += *m_Speed*a_Dt; } } } bool cPickup::CollectedBy( cPlayer* a_Dest ) { if(m_bCollected) return false; // It's already collected! if(m_Timer < 1000.f) return false; // Not old enough if( cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_COLLECT_ITEM, 2, this, a_Dest ) ) return false; if( a_Dest->GetInventory().AddItem( *m_Item ) ) { cPacket_CollectItem CollectItem; CollectItem.m_CollectedID = m_UniqueID; CollectItem.m_CollectorID = a_Dest->GetUniqueID(); cRoot::Get()->GetServer()->Broadcast( CollectItem ); m_bCollected = true; m_Timer = 0; return true; } return false; }