void CPatrolEnemy::Update(float fElapsedTime)
{
	CBaseEnemy::Update(fElapsedTime);

	if(GetCurrentHP() <= 0)
		ChangeAIState(pDead);
	else
	{
		tVector2D Result;
		Result.fX = GetTargetPosition().fX - GetPosX();
		Result.fY = GetTargetPosition().fY - GetPosY();

		float Distance = sqrt(Result.fX*Result.fX + Result.fY*Result.fY);

		if(Distance <= GetSightRange())
		{
			ChangeAIState(pActive);
			this->ReturnAIState();
		}
		else
			ChangeAIState(Patrol);

		switch(ReturnAIState())
		{
		case Patrol:
			{
				SetPosX((GetPosX() + GetBaseVelX() * fElapsedTime));

				if(GetPosX() <= 0)
				{
					SetPosX(0);
					SetCurrentDist(0);
					SetSpeed(-1*GetSpeed());
				}

				SetCurrentDist(GetCurrentDist() + (fabs(GetBaseVelX()) * fElapsedTime));

				if(GetCurrentDist() >= GetMaxDist())
				{
					SetCurrentDist(0);
					SetSpeed(-1*GetSpeed());
				}

				SetBaseVelX(GetBaseVelX() + GetSpeed() * fElapsedTime);

				if(GetBaseVelX() > 50)
					SetBaseVelX(50);
				else if(GetBaseVelX() < -50)
					SetBaseVelX(-50);
			}
			break;
		case pActive:
			{
				SetSpeed(-1*GetSpeed());
				SetBaseVelX(0);
			}
			break;
		case pDead:
			{
			}
			break;
		};
	}
}
Exemple #2
0
bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
{
	switch (a_RailMeta)
	{
		case E_META_RAIL_ZM_ZP:
		{
			if (GetSpeedZ() > 0)
			{
				BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, (int)ceil(GetPosZ()));
				if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
				{
					// We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P
					cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, (int)ceil(GetPosZ())), 0.5, 1);
					cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());

					if (bbBlock.DoesIntersect(bbMinecart))
					{
						SetSpeed(0, 0, 0);
						SetPosZ(floor(GetPosZ()) + 0.4);
						return true;
					}
				}
			}
			else if (GetSpeedZ() < 0)
			{
				BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1);
				if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
				{
					cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1), 0.5, 1);
					cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight());

					if (bbBlock.DoesIntersect(bbMinecart))
					{
						SetSpeed(0, 0, 0);
						SetPosZ(floor(GetPosZ()) + 0.65);
						return true;
					}
				}
			}
			break;
		}
		case E_META_RAIL_XM_XP:
		{
			if (GetSpeedX() > 0)
			{
				BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), POSY_TOINT, POSZ_TOINT);
				if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
				{
					cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), POSY_TOINT, POSZ_TOINT), 0.5, 1);
					cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());

					if (bbBlock.DoesIntersect(bbMinecart))
					{
						SetSpeed(0, 0, 0);
						SetPosX(floor(GetPosX()) + 0.4);
						return true;
					}
				}
			}
			else if (GetSpeedX() < 0)
			{
				BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT);
				if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
				{
					cBoundingBox bbBlock(Vector3d(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT), 0.5, 1);
					cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());

					if (bbBlock.DoesIntersect(bbMinecart))
					{
						SetSpeed(0, 0, 0);
						SetPosX(floor(GetPosX()) + 0.65);
						return true;
					}
				}
			}
			break;
		}
		case E_META_RAIL_CURVED_ZM_XM:
		case E_META_RAIL_CURVED_ZM_XP:
		case E_META_RAIL_CURVED_ZP_XM:
		case E_META_RAIL_CURVED_ZP_XP:
		{
			BLOCKTYPE BlockXM = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT);
			BLOCKTYPE BlockXP = m_World->GetBlock(POSX_TOINT + 1, POSY_TOINT, POSZ_TOINT);
			BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1);
			BLOCKTYPE BlockZP = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1);
			if (
				(!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) ||
				(!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP)) ||
				(!IsBlockRail(BlockZM) && cBlockInfo::IsSolid(BlockZM)) ||
				(!IsBlockRail(BlockZP) && cBlockInfo::IsSolid(BlockZP))
				)
			{
				SetSpeed(0, 0, 0);
				SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5);
				return true;
			}
			break;
		}
		default: break;
	}
	return false;
}
Exemple #3
0
bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
{
	if ((TDI.Attacker != NULL) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative())
	{
		Destroy();
		TDI.FinalDamage = GetMaxHealth();  // Instant hit for creative
		SetInvulnerableTicks(0);
		return super::DoTakeDamage(TDI);  // No drops for creative
	}

	m_LastDamage = TDI.FinalDamage;
	if (!super::DoTakeDamage(TDI))
	{
		return false;
	}

	m_World->BroadcastEntityMetadata(*this);

	if (GetHealth() <= 0)
	{
		Destroy();
		
		cItems Drops;
		switch (m_Payload)
		{
			case mpNone:
			{
				Drops.push_back(cItem(E_ITEM_MINECART, 1, 0));
				break;
			}
			case mpChest:
			{
				Drops.push_back(cItem(E_ITEM_CHEST_MINECART, 1, 0));
				break;
			}
			case mpFurnace:
			{
				Drops.push_back(cItem(E_ITEM_FURNACE_MINECART, 1, 0));
				break;
			}
			case mpTNT:
			{
				Drops.push_back(cItem(E_ITEM_MINECART_WITH_TNT, 1, 0));
				break;
			}
			case mpHopper:
			{
				Drops.push_back(cItem(E_ITEM_MINECART_WITH_HOPPER, 1, 0));
				break;
			}
			default:
			{
				ASSERT(!"Unhandled minecart type when spawning pickup!");
				return true;
			}
		}
		
		m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
	}
	return true;
}
Exemple #4
0
CEnemy::~CEnemy( )
{
	if(m_SpellType == OBJ_WIND)
	{
		if(dynamic_cast<AIStateWind*>(currState))
		{
			if(((AIStateWind*)currState)->GetFlock())
			{
				((AIStateWind*)currState)->GetFlock()->RemoveMember(this);
			}
		}
	}
	if( currState ) 
		delete currState;

	CPickup * newpickup = new CPickup();
	newpickup->SetPosX(GetPosX());
	newpickup->SetPosY(GetPosY());
	newpickup->SetActive(true);

	if(!(rand() % 20))
	{
		newpickup->SetType(OBJ_T3SPELL);
		//newpickup->SetImage( CSGD_TextureManager::GetInstance()->LoadTexture("resource/graphics/Lapid_SuperEnergy.png"));
		newpickup->SetWidth(32);
		newpickup->SetHeight(32);
		CEmitter* hahaiworknow = CParticleManager::GetInstance()->LoadEmitter("resource/data/powerSpecial.lapipt",newpickup->GetPosX(),newpickup->GetPosY());
		newpickup->SetEmitter(hahaiworknow);
		CParticleManager::GetInstance()->AddEmitter(newpickup->GetEmitter());

	}
	else
	{
		newpickup->SetType(OBJ_ENERGY);
		if(GetEleType() == OBJ_EARTH)
		{
			newpickup->SetEleType(OBJ_EARTH);
			//newpickup->SetImage( CSGD_TextureManager::GetInstance()->LoadTexture("resource/graphics/Lapid_EarthEnergy.png"));
			newpickup->SetWidth(64);
			newpickup->SetHeight(48);
			CEmitter* hahaiworknow = CParticleManager::GetInstance()->LoadEmitter("resource/data/powerEarth.lapipt",newpickup->GetPosX(),newpickup->GetPosY());
			newpickup->SetEmitter(hahaiworknow);
			CParticleManager::GetInstance()->AddEmitter(newpickup->GetEmitter());
		}
		else if(GetEleType() == OBJ_FIRE)
		{
			newpickup->SetEleType(OBJ_FIRE);
			//newpickup->SetImage( CSGD_TextureManager::GetInstance()->LoadTexture("resource/graphics/Lapid_FireEnergy.png"));
			newpickup->SetWidth(64);
			newpickup->SetHeight(48);
			CEmitter* hahaiworknow = CParticleManager::GetInstance()->LoadEmitter("resource/data/powerFire.lapipt",newpickup->GetPosX(),newpickup->GetPosY());
			newpickup->SetEmitter(hahaiworknow);
			CParticleManager::GetInstance()->AddEmitter(newpickup->GetEmitter());
		}
		else if(GetEleType() == OBJ_ICE)
		{
			newpickup->SetEleType(OBJ_ICE);
			//newpickup->SetImage( CSGD_TextureManager::GetInstance()->LoadTexture("resource/graphics/Lapid_IceEnergy.png"));
			newpickup->SetWidth(64);
			newpickup->SetHeight(48);

			CEmitter* hahaiworknow = CParticleManager::GetInstance()->LoadEmitter("resource/data/powerIce.lapipt",newpickup->GetPosX(),newpickup->GetPosY());
			newpickup->SetEmitter(hahaiworknow);
			CParticleManager::GetInstance()->AddEmitter(newpickup->GetEmitter());
		}
		else
		{
			newpickup->SetEleType(OBJ_WIND);
			//newpickup->SetImage( CSGD_TextureManager::GetInstance()->LoadTexture("resource/graphics/Lapid_WindEnergy.png"));
			newpickup->SetWidth(64);
			newpickup->SetHeight(58);
			CEmitter* hahaiworknow = CParticleManager::GetInstance()->LoadEmitter("resource/data/powerWind.lapipt",newpickup->GetPosX(),newpickup->GetPosY());
			newpickup->SetEmitter(hahaiworknow);
			CParticleManager::GetInstance()->AddEmitter(newpickup->GetEmitter());
		}
	}
	Corona_ObjectManager::GetInstance()->AddObject(newpickup);
	newpickup->Release();
}
Exemple #5
0
void CEnemy::Update( float fElapsedTime )
{
	if( ! ( CGameplayState::GetInstance()->GetLevel()->GetTile((int)GetPosX(), (int)GetPosY() ) ) )
	{
		SetHealth(0);
	}
	if(m_nHealth >0)
	{

		Frame * currFrame = (animation->GetAllFrames())[animation->GetFrame()];

		if(LastFrame && currAnimation == 2 || currAnimation == 1)
		{
			float oldheight = m_fLastPosition + (LastFrame->DrawRect.bottom - LastFrame->DrawRect.top) * m_fScale;

			while(oldheight < GetPosY() + (currFrame->DrawRect.bottom - currFrame->DrawRect.top) * m_fScale)
			{
				SetPosY(GetPosY() - 1);
			}
			while(oldheight > GetPosY() + (currFrame->DrawRect.bottom - currFrame->DrawRect.top) * m_fScale)
			{
				SetPosY(GetPosY() + 1);
			}
		}

		LastFrame = currFrame;
		m_fLastPosition = GetPosY();

		if(!m_bKnockBack)
		{
			m_fShotTimer = m_fShotTimer - fElapsedTime;

			if( 0.0f == m_fWaitTimer )
			{	
				if(m_SpellType == OBJ_WIND)
				{
					CBase::Update( fElapsedTime );
				}
				else
				{
					CCharacter::Update( fElapsedTime );
				}

				m_nAttackWho = currState->Update( fElapsedTime, this );

				if( m_nAttackWho && m_fShotTimer < 0 )
				{
					m_fWaitTimer += fElapsedTime;
					m_fShotTimer = 2.0f;
					animation->Reset();
					SetAnimation(m_nAnimation,2);

				}
			}
			else
			{
				m_fWaitTimer = m_fWaitTimer + fElapsedTime;

				/*if(m_SpellType !=OBJ_WIND)
				SetPosY( GetPosY( ) + 150.0f * fElapsedTime );*/


				char* pleasework = animation->GetTrigger();
				if(strcmp(pleasework, "Done") == 0)
				{	
					if( 1 == m_nAttackWho )
					{
						currState->Attack( CGameplayState::GetInstance( )->GetPlayerOne( ), this );
					}
					else if( 2 == m_nAttackWho )
					{
						currState->Attack( CGameplayState::GetInstance( )->GetPlayerTwo( ), this );
					}
					animation->Reset();
					SetAnimation(m_nAnimation,0);

					m_fWaitTimer = 0.0f;
				}

			}
		}
		else
		{
			if(m_fKnockBack < 0)
			{
				m_bKnockBack = false;
			}
			else
			{
				CCharacter::Update(fElapsedTime);
				m_fKnockBack-=fElapsedTime * 100;
			}
		}

		if(m_bBurning)
		{
			m_fBurnTimer -= fElapsedTime;

			if(m_fBurnTimer <= 0)
			{
				m_bBurning = false;
				m_nBurnDamage = 0;
			}

			if(!((int)m_fBurnTimer %  3))
			{
				m_fBurnTimer -= 1.0f;
				StickyNumbers* SN = new StickyNumbers();
				SN->SetTimer(2.5f);
				SN->SetPosX( GetPosX());
				SN->SetPosY( GetPosY() - 24);
				char buffer[16];
				sprintf_s(buffer, 16, "%i", TakeDamage(m_nBurnDamage));
				SN->SetText(buffer);
				SN->SetVelY(-30);

				Corona_ObjectManager::GetInstance()->AddObject(SN);
				SN->Release();
			}
		}

		if( m_bIsFrozen )
		{
			m_fFreezeTimer = m_fFreezeTimer - fElapsedTime;

			if( m_fFreezeTimer <= 0 )
				m_bIsFrozen = false;

			SetVelX( m_fFrozenSpeed );
		}
	}
	else
	{
		if(currAnimation != 1)
		{
			animation->Reset();
			SetAnimation(m_nAnimation,1);
		}
		char* pleasework = animation->GetTrigger();
		if(strcmp(pleasework,"Dead") ==0)
		{
			Corona_EventHandler::GetInstance( )->SendEvent( "EnemyDied", ( void* )this );
			SetActive( false );
		}
	}
	animation->Update(fElapsedTime);
	CHANGE_ANIM
	{
		if(GetVelX() <30)
		{
			IsRotated = true;
		}
		else if(GetVelX() >-30)
		{
			IsRotated = false;
		}
		m_fChangeAnimationTimer =0.0f;
	}
	else
	{
Exemple #6
0
void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{
	// Process packet sending every two ticks
	if (GetWorld()->GetWorldAge() % 2 == 0)
	{
		double SpeedSqr = GetSpeed().SqrLength();
		if (SpeedSqr == 0.0)
		{
			// Speed is zero, send this to clients once only as well as an absolute position
			if (!m_bHasSentNoSpeed)
			{
				m_World->BroadcastEntityVelocity(*this, a_Exclude);
				m_World->BroadcastTeleportEntity(*this, a_Exclude);
				m_bHasSentNoSpeed = true;
			}
		}
		else
		{
			// Movin'
			m_World->BroadcastEntityVelocity(*this, a_Exclude);
			m_bHasSentNoSpeed = false;
		}
		
		// TODO: Pickups move disgracefully if relative move packets are sent as opposed to just velocity. Have a system to send relmove only when SetPosXXX() is called with a large difference in position
		int DiffX = (int)(floor(GetPosX() * 32.0) - floor(m_LastPos.x * 32.0));
		int DiffY = (int)(floor(GetPosY() * 32.0) - floor(m_LastPos.y * 32.0));
		int DiffZ = (int)(floor(GetPosZ() * 32.0) - floor(m_LastPos.z * 32.0));

		if ((DiffX != 0) || (DiffY != 0) || (DiffZ != 0)) // Have we moved?
		{
			if ((abs(DiffX) <= 127) && (abs(DiffY) <= 127) && (abs(DiffZ) <= 127)) // Limitations of a Byte
			{
				// Difference within Byte limitations, use a relative move packet
				if (m_bDirtyOrientation)
				{
					m_World->BroadcastEntityRelMoveLook(*this, (char)DiffX, (char)DiffY, (char)DiffZ, a_Exclude);
					m_bDirtyOrientation = false;
				}
				else
				{
					m_World->BroadcastEntityRelMove(*this, (char)DiffX, (char)DiffY, (char)DiffZ, a_Exclude);
				}
				// Clients seem to store two positions, one for the velocity packet and one for the teleport/relmove packet
				// The latter is only changed with a relmove/teleport, and m_LastPos stores this position
				m_LastPos = GetPosition();
			}
			else
			{
				// Too big a movement, do a teleport
				m_World->BroadcastTeleportEntity(*this, a_Exclude);
				m_LastPos = GetPosition(); // See above
				m_bDirtyOrientation = false;
			}
		}

		if (m_bDirtyHead)
		{
			m_World->BroadcastEntityHeadLook(*this, a_Exclude);
			m_bDirtyHead = false;
		}
		if (m_bDirtyOrientation)
		{
			// Send individual update in case above (sending with rel-move packet) wasn't done
			GetWorld()->BroadcastEntityLook(*this, a_Exclude);
			m_bDirtyOrientation = false;
		}
	}
}
Exemple #7
0
void cEntity::TickBurning(cChunk & a_Chunk)
{
	// Remember the current burning state:
	bool HasBeenBurning = (m_TicksLeftBurning > 0);

	if (m_World->IsWeatherWet())
	{
		if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT))
		{
			m_TicksLeftBurning = 0;
		}		
	}
	
	// Do the burning damage:
	if (m_TicksLeftBurning > 0)
	{
		m_TicksSinceLastBurnDamage++;
		if (m_TicksSinceLastBurnDamage >= BURN_TICKS_PER_DAMAGE)
		{
			if (!m_IsFireproof)
			{
				TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0);
			}
			m_TicksSinceLastBurnDamage = 0;
		}
		m_TicksLeftBurning--;
	}
	
	// Update the burning times, based on surroundings:
	int MinRelX = (int)floor(GetPosX() - m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width;
	int MaxRelX = (int)floor(GetPosX() + m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width;
	int MinRelZ = (int)floor(GetPosZ() - m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
	int MaxRelZ = (int)floor(GetPosZ() + m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
	int MinY = std::max(0, std::min(cChunkDef::Height - 1, POSY_TOINT));
	int MaxY = std::max(0, std::min(cChunkDef::Height - 1, (int)ceil (GetPosY() + m_Height)));
	bool HasWater = false;
	bool HasLava = false;
	bool HasFire = false;
	
	for (int x = MinRelX; x <= MaxRelX; x++)
	{
		for (int z = MinRelZ; z <= MaxRelZ; z++)
		{
			int RelX = x;
			int RelZ = z;

			for (int y = MinY; y <= MaxY; y++)
			{
				BLOCKTYPE Block;
				a_Chunk.UnboundedRelGetBlockType(RelX, y, RelZ, Block);
				
				switch (Block)
				{
					case E_BLOCK_FIRE:
					{
						HasFire = true;
						break;
					}
					case E_BLOCK_LAVA:
					case E_BLOCK_STATIONARY_LAVA:
					{
						HasLava = true;
						break;
					}
					case E_BLOCK_STATIONARY_WATER:
					case E_BLOCK_WATER:
					{
						HasWater = true;
						break;
					}
				}  // switch (BlockType)
			}  // for y
		}  // for z
	}  // for x
	
	if (HasWater)
	{
		// Extinguish the fire
		m_TicksLeftBurning = 0;
	}
	
	if (HasLava)
	{
		// Burn:
		m_TicksLeftBurning = BURN_TICKS;
		
		// Periodically damage:
		m_TicksSinceLastLavaDamage++;
		if (m_TicksSinceLastLavaDamage >= LAVA_TICKS_PER_DAMAGE)
		{
			if (!m_IsFireproof)
			{
				TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0);
			}
			m_TicksSinceLastLavaDamage = 0;
		}
	}
	else
	{
		m_TicksSinceLastLavaDamage = 0;
	}
	
	if (HasFire)
	{
		// Burn:
		m_TicksLeftBurning = BURN_TICKS;
		
		// Periodically damage:
		m_TicksSinceLastFireDamage++;
		if (m_TicksSinceLastFireDamage >= FIRE_TICKS_PER_DAMAGE)
		{
			if (!m_IsFireproof)
			{
				TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0);
			}
			m_TicksSinceLastFireDamage = 0;
		}
	}
	else
	{
		m_TicksSinceLastFireDamage = 0;
	}
	
	// If just started / finished burning, notify descendants:
	if ((m_TicksLeftBurning > 0) && !HasBeenBurning)
	{
		OnStartedBurning();
	}
	else if ((m_TicksLeftBurning <= 0) && HasBeenBurning)
	{
		OnFinishedBurning();
	}
}
Exemple #8
0
void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
{
	super::DoTakeDamage(a_TDI);
	if((m_SoundHurt != "") && (m_Health > 0)) m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
	if (a_TDI.Attacker != NULL)
	{
		m_Target = a_TDI.Attacker;
		AddReference(m_Target);
	}
}
Exemple #9
0
void cMonster::KilledBy(cEntity * a_Killer)
{
	super::KilledBy(a_Killer);
	if (m_SoundHurt != "")
	{
		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;
			break;
		}

		// 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));
			break;
		}
		case cMonster::mtBlaze:
		{
			Reward = 10;
			break;
		}

		// Bosses
		case cMonster::mtEnderDragon:
		{
			Reward = 12000;
			break;
		}
		case cMonster::mtWither:
		{
			Reward = 50;
			break;
		}

		default:
		{
			Reward = 0;
			break;
		}
	}
	if ((a_Killer != NULL) && (!IsBaby()))
	{
		m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward);
	}
	m_DestroyTimer = 0;
}
Exemple #10
0
void MapMgr::RemoveObject(Object *obj, bool free_guid)
{
	/////////////
	// Assertions
	/////////////

	ASSERT(obj);
	ASSERT(obj->GetMapId() == _mapId);
	//ASSERT(obj->GetPositionX() > _minX && obj->GetPositionX() < _maxX);
	//ASSERT(obj->GetPositionY() > _minY && obj->GetPositionY() < _maxY);
	ASSERT(_cells);

	if(obj->Active)
		obj->Deactivate(this);

	_updates.erase( obj );
	obj->ClearUpdateMask();
	Player* plObj = (obj->GetTypeId() == TYPEID_PLAYER) ? static_cast< Player* >( obj ) : 0;

	///////////////////////////////////////
	// Remove object from all needed places
	///////////////////////////////////////
 
	switch(obj->GetTypeFromGUID())
	{
		case HIGHGUID_TYPE_UNIT:
			ASSERT(obj->GetUIdFromGUID() <= m_CreatureHighGuid);
			m_CreatureStorage[obj->GetUIdFromGUID()] = 0;
			if(((Creature*)obj)->m_spawn != NULL)
			{
				_sqlids_creatures.erase(((Creature*)obj)->m_spawn->id);
			}

			if(free_guid)
				_reusable_guids_creature.push_back(obj->GetUIdFromGUID());

			  break;

		case HIGHGUID_TYPE_PET:
			m_PetStorage.erase(obj->GetUIdFromGUID());
			break;

		case HIGHGUID_TYPE_DYNAMICOBJECT:
			m_DynamicObjectStorage.erase(obj->GetLowGUID());
			break;

		case HIGHGUID_TYPE_GAMEOBJECT:
			ASSERT(obj->GetUIdFromGUID() <= m_GOHighGuid);
			m_GOStorage[obj->GetUIdFromGUID()] = 0;
			if(((GameObject*)obj)->m_spawn != NULL)
			{
				_sqlids_gameobjects.erase(((GameObject*)obj)->m_spawn->id);
			}

			if(free_guid)
				_reusable_guids_gameobject.push_back(obj->GetUIdFromGUID());

			break;
	}

	// That object types are not map objects. TODO: add AI groups here?
	if(obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER || obj->GetTypeId()==10)
	{
		return;
	}

	if(obj->GetTypeId() == TYPEID_CORPSE)
	{
		m_corpses.erase(((Corpse*)obj));
	}

	if(!obj->GetMapCell())
	{
		/* set the map cell correctly */
		if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minY ||
			obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY)
		{
			// do nothing
		}
		else
		{
			obj->SetMapCell(this->GetCellByCoords(obj->GetPositionX(), obj->GetPositionY()));
		}		
	}

	if(obj->GetMapCell())
	{
		ASSERT(obj->GetMapCell());
	
		// Remove object from cell
		obj->GetMapCell()->RemoveObject(obj);
	
		// Unset object's cell
		obj->SetMapCell(NULL);
	}

	// Clear any updates pending
	if(obj->GetTypeId() == TYPEID_PLAYER)
	{
		_processQueue.erase( static_cast< Player* >( obj ) );
		static_cast< Player* >( obj )->ClearAllPendingUpdates();
	}
	
	// Remove object from all objects 'seeing' him
	for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin();
		iter != obj->GetInRangeSetEnd(); ++iter)
	{
		if( (*iter) )
		{
			if( (*iter)->GetTypeId() == TYPEID_PLAYER )
			{
				if( static_cast< Player* >( *iter )->IsVisible( obj ) && static_cast< Player* >( *iter )->m_TransporterGUID != obj->GetGUID() )
					static_cast< Player* >( *iter )->PushOutOfRange(obj->GetNewGUID());
			}
			(*iter)->RemoveInRangeObject(obj);
		}
	}
	
	// Clear object's in-range set
	obj->ClearInRangeSet();

	// If it's a player - update his nearby cells
	if(!_shutdown && obj->GetTypeId() == TYPEID_PLAYER)
	{
		// get x/y
		if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minY ||
			obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY)
		{
			// do nothing
		}
		else
		{
			uint32 x = GetPosX(obj->GetPositionX());
			uint32 y = GetPosY(obj->GetPositionY());
			UpdateCellActivity(x, y, 2);
		}
		m_PlayerStorage.erase( static_cast< Player* >( obj )->GetLowGUID() );
	}

	// Remove the session from our set if it is a player.
	if(plObj)
	{
		for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr)
		{
			plObj->PushOutOfRange((*itr)->GetNewGUID());
		}

		// Setting an instance ID here will trigger the session to be removed
		// by MapMgr::run(). :)
		plObj->GetSession()->SetInstance(0);

		// Add it to the global session set.
		// Don't "re-add" to session if it is being deleted.
		if(!plObj->GetSession()->bDeleted)
			sWorld.AddGlobalSession(plObj->GetSession());
	}

	if(!HasPlayers() && !InactiveMoveTime && !forced_expire && GetMapInfo()->type != INSTANCE_NULL)
	{
		InactiveMoveTime = UNIXTIME + (MAPMGR_INACTIVE_MOVE_TIME * 60);	   // 5 mins -> move to inactive
	}
}
Exemple #11
0
void MapMgr::ChangeObjectLocation( Object *obj )
{
	// Items and containers are of no interest for us
	if( obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER || obj->GetMapMgr() != this )
	{
		return;
	}

	Player* plObj;
	ByteBuffer * buf = 0;

	if( obj->GetTypeId() == TYPEID_PLAYER )
	{
		plObj = static_cast< Player* >( obj );
	}
	else
	{
		plObj = NULL;
	}

	Object* curObj;
	float fRange;

	///////////////////////////////////////
	// Update in-range data for old objects
	///////////////////////////////////////

	/** let's duplicate some code here :P Less branching is always good.
	 * - Burlex
	 */
/*#define IN_RANGE_LOOP \
	for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(), iter2; \
		iter != obj->GetInRangeSetEnd();) \
	{ \
		curObj = *iter; \
		iter2 = iter; \
		++iter; \
		if(curObj->IsPlayer() && obj->IsPlayer() && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID ) \
			fRange = 0.0f;		\
		else if((curObj->GetGUIDHigh() == HIGHGUID_TRANSPORTER || obj->GetGUIDHigh() == HIGHGUID_TRANSPORTER)) \
			fRange = 0.0f;		\
		else if((curObj->GetGUIDHigh() == HIGHGUID_GAMEOBJECT && curObj->GetUInt32Value(GAMEOBJECT_TYPE_ID) == GAMEOBJECT_TYPE_TRANSPORT || obj->GetGUIDHigh() == HIGHGUID_GAMEOBJECT && obj->GetUInt32Value(GAMEOBJECT_TYPE_ID) == GAMEOBJECT_TYPE_TRANSPORT)) \
			fRange = 0.0f;		\
		else \
			fRange = m_UpdateDistance;	\
		if (curObj->GetDistance2dSq(obj) > fRange && fRange > 0) \

#define END_IN_RANGE_LOOP } \

	if(plObj)
	{
		IN_RANGE_LOOP
		{
			plObj->RemoveIfVisible(curObj);
			plObj->RemoveInRangeObject(iter2);

			if(curObj->NeedsInRangeSet())
				curObj->RemoveInRangeObject(obj);

			if(curObj->IsPlayer())
				static_cast< Player* >( curObj )->RemoveIfVisible(obj);
		}
		END_IN_RANGE_LOOP
	}
	else if(obj->NeedsInRangeSet())
	{
		IN_RANGE_LOOP
		{
			if(curObj->NeedsInRangeSet())
				curObj->RemoveInRangeObject(obj);

			if(curObj->IsPlayer())
				static_cast< Player* >( curObj )->RemoveIfVisible(obj);

			obj->RemoveInRangeObject(iter2);
		}
		END_IN_RANGE_LOOP
	}
	else
	{
		IN_RANGE_LOOP
		{
			if(curObj->NeedsInRangeSet())
				curObj->RemoveInRangeObject(obj);

			if(curObj->IsPlayer())
			{
				static_cast< Player* >( curObj )->RemoveIfVisible(obj);
				obj->RemoveInRangePlayer(curObj);
			}
		}
		END_IN_RANGE_LOOP
	}

#undef IN_RANGE_LOOP
#undef END_IN_RANGE_LOOP*/

	if(obj->HasInRangeObjects()) {
		for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(), iter2;
			iter != obj->GetInRangeSetEnd();)
		{
			curObj = *iter;
			iter2 = iter++;
			if( curObj->IsPlayer() && obj->IsPlayer() && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID )
				fRange = 0.0f; // unlimited distance for people on same boat
			else if( curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER )
				fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.)
			else
				fRange = m_UpdateDistance; // normal distance

			if( fRange > 0.0f && curObj->GetDistance2dSq(obj) > fRange )
			{
				if( plObj )
					plObj->RemoveIfVisible(curObj);

				if( curObj->IsPlayer() )
					static_cast< Player* >( curObj )->RemoveIfVisible(obj);

				curObj->RemoveInRangeObject(obj);

				if( obj->GetMapMgr() != this )
				{
					/* Something removed us. */
					return;
				}
				obj->RemoveInRangeObject(iter2);
			}
		}
	}

	///////////////////////////
	// Get new cell coordinates
	///////////////////////////
	if(obj->GetMapMgr() != this)
	{
		/* Something removed us. */
		return;
	}

	if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minX ||
		obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY)
	{
		if(obj->IsPlayer())
		{
			Player* plr = static_cast< Player* >( obj );
			if(plr->GetBindMapId() != GetMapId())
			{
				plr->SafeTeleport(plr->GetBindMapId(),0,plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0);
				plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				return;
			}
			else
			{
				obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0);
				plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				WorldPacket * data = plr->BuildTeleportAckMsg(plr->GetPosition());
				plr->GetSession()->SendPacket(data);
				delete data;
			}
		}
		else
		{
			obj->GetPositionV()->ChangeCoords(0,0,0,0);
		}
	}

	uint32 cellX = GetPosX(obj->GetPositionX());
	uint32 cellY = GetPosY(obj->GetPositionY());

	if(cellX >= _sizeX || cellY >= _sizeY)
	{
		return;
	}

	MapCell *objCell = GetCell(cellX, cellY);
	MapCell * pOldCell = obj->GetMapCell();
	if (!objCell)
	{
		objCell = Create(cellX,cellY);
		objCell->Init(cellX, cellY, _mapId, this);
	}

	// If object moved cell
	if (objCell != obj->GetMapCell())
	{
		// THIS IS A HACK!
		// Current code, if a creature on a long waypoint path moves from an active
		// cell into an inactive one, it will disable itself and will never return.
		// This is to prevent cpu leaks. I will think of a better solution very soon :P

		if(!objCell->IsActive() && !plObj && obj->Active)
			obj->Deactivate(this);

		if(obj->GetMapCell())
			obj->GetMapCell()->RemoveObject(obj);
	
		objCell->AddObject(obj);
		obj->SetMapCell(objCell);

		// if player we need to update cell activity
		// radius = 2 is used in order to update both
		// old and new cells
		if(obj->GetTypeId() == TYPEID_PLAYER)
		{
			// have to unlock/lock here to avoid a deadlock situation.
			UpdateCellActivity(cellX, cellY, 2);
			if( pOldCell != NULL )
			{
				// only do the second check if theres -/+ 2 difference
				if( abs( (int)cellX - (int)pOldCell->_x ) > 2 ||
					abs( (int)cellY - (int)pOldCell->_y ) > 2 )
				{
					UpdateCellActivity( pOldCell->_x, pOldCell->_y, 2 );
				}
			}
		}
	}


	//////////////////////////////////////
	// Update in-range set for new objects
	//////////////////////////////////////

	uint32 endX = cellX <= _sizeX ? cellX + 1 : (_sizeX-1);
	uint32 endY = cellY <= _sizeY ? cellY + 1 : (_sizeY-1);
	uint32 startX = cellX > 0 ? cellX - 1 : 0;
	uint32 startY = cellY > 0 ? cellY - 1 : 0;
	uint32 posX, posY;
	MapCell *cell;
	MapCell::ObjectSet::iterator iter;

	for (posX = startX; posX <= endX; ++posX )
	{
		for (posY = startY; posY <= endY; ++posY )
		{
			cell = GetCell(posX, posY);
			if (cell)
			UpdateInRangeSet(obj, plObj, cell, &buf);
		}
	}

	if(buf)
		delete buf;
}
Exemple #12
0
void MapMgr::PushObject(Object *obj)
{
	/////////////
	// Assertions
	/////////////
	ASSERT(obj);
	
	// That object types are not map objects. TODO: add AI groups here?
	if(obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER)
	{
		// mark object as updatable and exit
		return;
	}

	if(obj->GetTypeId() == TYPEID_CORPSE)
	{
		m_corpses.insert(((Corpse*)obj));
	}	
	
	obj->ClearInRangeSet();
	ASSERT(obj->GetMapId() == _mapId);
	if(!(obj->GetPositionX() < _maxX && obj->GetPositionX() > _minX) || 
	   !(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY))
	{
		if(obj->IsPlayer())
		{
			Player * plr = static_cast< Player* >( obj );
			if(plr->GetBindMapId() != GetMapId())
			{
				plr->SafeTeleport(plr->GetBindMapId(),0,plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0);
				plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				return;
			}
			else
			{
				obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0);
				plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				WorldPacket * data = plr->BuildTeleportAckMsg(plr->GetPosition());
				plr->GetSession()->SendPacket(data);
				delete data;
			}
		}
		else
		{
			obj->GetPositionV()->ChangeCoords(0,0,0,0);
		}
	}

	ASSERT(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY);
	ASSERT(_cells);

	///////////////////////
	// Get cell coordinates
	///////////////////////

	uint32 x = GetPosX(obj->GetPositionX());
	uint32 y = GetPosY(obj->GetPositionY());

	if(x >= _sizeX || y >= _sizeY)
	{
		if(obj->IsPlayer())
		{
			Player * plr = static_cast< Player* >( obj );
			if(plr->GetBindMapId() != GetMapId())
			{
				plr->SafeTeleport(plr->GetBindMapId(),0,plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0);
				plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				return;
			}
			else
			{
				obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0);
				plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				WorldPacket * data = plr->BuildTeleportAckMsg(plr->GetPosition());
				plr->GetSession()->SendPacket(data);
				delete data;
			}
		}
		else
		{
			obj->GetPositionV()->ChangeCoords(0,0,0,0);
		}

		x = GetPosX(obj->GetPositionX());
		y = GetPosY(obj->GetPositionY());
	}

	MapCell *objCell = GetCell(x,y);
	if (!objCell)
	{
		objCell = Create(x,y);
		objCell->Init(x, y, _mapId, this);
	}

	uint32 endX = (x <= _sizeX) ? x + 1 : (_sizeX-1);
	uint32 endY = (y <= _sizeY) ? y + 1 : (_sizeY-1);
	uint32 startX = x > 0 ? x - 1 : 0;
	uint32 startY = y > 0 ? y - 1 : 0;
	uint32 posX, posY;
	MapCell *cell;
	MapCell::ObjectSet::iterator iter;

	ByteBuffer * buf = 0;
	uint32 count;
	Player *plObj;

	if(obj->GetTypeId() == TYPEID_PLAYER)
		plObj = static_cast< Player* >( obj );
	else
		plObj = NULL;

	if(plObj)
	{
		sLog.outDetail("Creating player "I64FMT" for himself.", obj->GetGUID());
		ByteBuffer pbuf(10000);
		count = plObj->BuildCreateUpdateBlockForPlayer(&pbuf, plObj);
		plObj->PushCreationData(&pbuf, count);
	}

	//////////////////////
	// Build in-range data
	//////////////////////

	for (posX = startX; posX <= endX; posX++ )
	{
		for (posY = startY; posY <= endY; posY++ )
		{
			cell = GetCell(posX, posY);
			if (cell)
			{
				UpdateInRangeSet(obj, plObj, cell, &buf);
			}
		}
	}

	//Add to the cell's object list
	objCell->AddObject(obj);

	obj->SetMapCell(objCell);
	 //Add to the mapmanager's object list
	if(plObj)
	{
	   m_PlayerStorage[plObj->GetLowGUID()] = plObj;
	   UpdateCellActivity(x, y, 2);
	}
	else
	{
		switch(obj->GetTypeFromGUID())
		{
		case HIGHGUID_TYPE_PET:
			m_PetStorage[obj->GetUIdFromGUID()] = static_cast< Pet* >( obj );
			break;

		case HIGHGUID_TYPE_UNIT:
			{
				ASSERT((obj->GetUIdFromGUID()) <= m_CreatureHighGuid);
				m_CreatureStorage[obj->GetUIdFromGUID()] = (Creature*)obj;
				if(((Creature*)obj)->m_spawn != NULL)
				{
					_sqlids_creatures.insert(make_pair( ((Creature*)obj)->m_spawn->id, ((Creature*)obj) ) );
				}
			}break;

		case HIGHGUID_TYPE_GAMEOBJECT:
			{
				m_GOStorage[obj->GetUIdFromGUID()] = (GameObject*)obj;
				if(((GameObject*)obj)->m_spawn != NULL)
				{
					_sqlids_gameobjects.insert(make_pair( ((GameObject*)obj)->m_spawn->id, ((GameObject*)obj) ) );
				}
			}break;

		case HIGHGUID_TYPE_DYNAMICOBJECT:
			m_DynamicObjectStorage[obj->GetLowGUID()] = (DynamicObject*)obj;
			break;
		}
	}

	// Handle activation of that object.
	if(objCell->IsActive() && obj->CanActivate())
		obj->Activate(this);

	// Add the session to our set if it is a player.
	if(plObj)
	{
		Sessions.insert(plObj->GetSession());

		// Change the instance ID, this will cause it to be removed from the world thread (return value 1)
		plObj->GetSession()->SetInstance(GetInstanceID());

		/* Add the map wide objects */
		if(_mapWideStaticObjects.size())
		{
			if(!buf)
				buf = new ByteBuffer(300);

			for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr)
			{
				count = (*itr)->BuildCreateUpdateBlockForPlayer(buf, plObj);
				plObj->PushCreationData(buf, count);
			}
		}
	}

	if(buf)
		delete buf;

	if(plObj && InactiveMoveTime && !forced_expire)
		InactiveMoveTime = 0;
}
Exemple #13
0
bool MMapManager::GetWalkingHeightInternal(float positionx, float positiony, float positionz, float endz, LocationVector& out)
{
	if(m_navMesh == NULL)
		return false;

	dtNavMeshQuery* query = mallocNavMeshQuery();
	if(query->init(m_navMesh, 1024) != DT_SUCCESS)
	{
		freeNavMeshQuery(query);
		Log.Error("NavMeshInterface", "Failed to initialize dtNavMeshQuery for mapId %03u", ManagerMapId);
		return false;
	}

	dtStatus result;
	//convert to nav coords.
	float startPos[3] = { positionx, positiony, positionz };
	float endPos[3] = { positionx, positiony, endz };
	float mPolyPickingExtents[3] = { 2.00f, 2.00f, 4.00f };
	float closestPoint[3] = {0.0f, 0.0f, 0.0f};
	int gx = GetPosX(positionx)/8;
	int gy = GetPosY(positiony)/8;
	dtQueryFilter* mPathFilter = new dtQueryFilter();
	if(mPathFilter)
	{
		dtPolyRef mStartRef;
		result = query->findNearestPoly(startPos, mPolyPickingExtents, mPathFilter, &mStartRef, closestPoint);
		if(result != DT_SUCCESS || !mStartRef)
		{
			freeNavMeshQuery(query);
			delete mPathFilter;
			mPathFilter = NULL;
			return false;
		}

		dtPolyRef mEndRef;
		result = query->findNearestPoly(endPos, mPolyPickingExtents, mPathFilter, &mEndRef, closestPoint);
		if(result != DT_SUCCESS || !mEndRef)
		{
			freeNavMeshQuery(query);
			delete mPathFilter;
			mPathFilter = NULL;
			return false;
		}

		if (mStartRef != 0 && mEndRef != 0)
		{
			int mNumPathResults;
			dtPolyRef mPathResults[50];
			result = query->findPath(mStartRef, mEndRef,startPos, endPos, mPathFilter, mPathResults, &mNumPathResults, 50);
			if(result != DT_SUCCESS || mNumPathResults <= 0)
			{
				freeNavMeshQuery(query);
				delete mPathFilter;
				mPathFilter = NULL;
				return false;
			}

			int mNumPathPoints;
			float actualpath[3*2];
			dtPolyRef polyrefs = 0;
			result = query->findStraightPath(startPos, endPos, mPathResults, mNumPathResults, actualpath, NULL, &polyrefs, &mNumPathPoints, 2);
			if (result != DT_SUCCESS)
			{
				freeNavMeshQuery(query);
				delete mPathFilter;
				mPathFilter = NULL;
				return false;
			}

			if(mNumPathPoints < 3)
			{
				out.y = positiony;
				out.z = positionz;
				out.x = positionx;
				freeNavMeshQuery(query);
				delete mPathFilter;
				mPathFilter = NULL;
				return true;
			}

			out.y = actualpath[3];
			out.z = actualpath[4];
			out.x = actualpath[5];
			freeNavMeshQuery(query);
			delete mPathFilter;
			mPathFilter = NULL;
			return true;
		}
	}
	return false;
}
Exemple #14
0
LocationVector MMapManager::getNextPositionOnPathToLocation(float startx, float starty, float startz, float endx, float endy, float endz)
{
	if(m_navMesh == NULL)
		return LocationVector(endx, endy, endz);

	dtNavMeshQuery* query = mallocNavMeshQuery();
	if(query->init(m_navMesh, 1024) != DT_SUCCESS)
	{
		freeNavMeshQuery(query);
		Log.Error("NavMeshInterface", "Failed to initialize dtNavMeshQuery for mapId %03u", ManagerMapId);
		return LocationVector(endx, endy, endz);
	}

	//convert to nav coords.
	float startPos[3] = { starty, startz, startx };
	float endPos[3] = { endy, endz, endx };
	float mPolyPickingExtents[3] = { 2.00f, 4.00f, 2.00f };
	float closestPoint[3] = {0.0f, 0.0f, 0.0f};
	int gx = GetPosX(startx)/8;
	int gy = GetPosY(starty)/8;
	LocationVector pos;
	pos.x = endx;
	pos.y = endy;
	pos.z = endz;
	dtStatus result;
	dtQueryFilter* mPathFilter = new dtQueryFilter();
	if(mPathFilter)
	{
		dtPolyRef mStartRef;
		result = query->findNearestPoly(startPos, mPolyPickingExtents, mPathFilter, &mStartRef, closestPoint);
		if(result != DT_SUCCESS || !mStartRef)
		{
			freeNavMeshQuery(query);
			delete mPathFilter;
			mPathFilter = NULL;
			return pos;
		}

		dtPolyRef mEndRef;
		result = query->findNearestPoly(endPos, mPolyPickingExtents, mPathFilter, &mEndRef, closestPoint);
		if(result != DT_SUCCESS || !mEndRef)
		{
			freeNavMeshQuery(query);
			delete mPathFilter;
			mPathFilter = NULL;
			return pos;
		}

		if (mStartRef != 0 && mEndRef != 0)
		{
			int mNumPathResults;
			dtPolyRef mPathResults[50];
			result = query->findPath(mStartRef, mEndRef,startPos, endPos, mPathFilter, mPathResults, &mNumPathResults, 50);
			if(result != DT_SUCCESS || mNumPathResults <= 0)
			{
				freeNavMeshQuery(query);
				delete mPathFilter;
				mPathFilter = NULL;
				return pos;
			}

			int mNumPathPoints;
			float actualpath[3*20];
			dtPolyRef polyrefs = 0;
			result = query->findStraightPath(startPos, endPos, mPathResults, mNumPathResults, actualpath, NULL, &polyrefs, &mNumPathPoints, 20);
			if (result != DT_SUCCESS || mNumPathPoints < 3)
			{
				freeNavMeshQuery(query);
				delete mPathFilter;
				mPathFilter = NULL;
				return pos;
			}

			pos.y = actualpath[3]; //0 3 6
			pos.z = actualpath[4]; //1 4 7
			pos.x = actualpath[5]; //2 5 8
			freeNavMeshQuery(query);
			delete mPathFilter;
			mPathFilter = NULL;
			return pos;
		}
	}
	return pos;
}
Exemple #15
0
/** 创建windows窗口 */
bool GLWindow::Create(const char * window_title,const char * class_name,bool fullscreen, HINSTANCE h_instance, LPVOID lpParam)
{
	m_IsFullScreen = fullscreen;
	int nX=0;
	int nY=0;
	PIXELFORMATDESCRIPTOR pfd =											/**< 设置像素描述结构 */
	{
		sizeof(PIXELFORMATDESCRIPTOR),									/**< 像素描述结构的大小 */ 
		1,																/**< 版本号 */
		PFD_DRAW_TO_WINDOW	|											/**< 缓存区的输出显示在一个窗口中 */
		PFD_SUPPORT_OPENGL	|											/**< 缓存区支持OpenGL绘图 */
		PFD_STEREO			|											/**< 颜色缓存区是立体缓存 */
		PFD_DOUBLEBUFFER,												/**< 颜色缓存区是双缓存 */
		PFD_TYPE_RGBA,													/**< 使用RGBA颜色格式 */
		m_BitsPerPixel,													/**< 颜色缓存区中颜色值所占的位深 */
		0, 0, 0, 0, 0, 0,												/**< 使用默认的颜色设置 */
		0,																/**< 无Alpha缓存 */
		0,																/**< 颜色缓存区中alpha成分的移位计数 */
		0,																/**< 无累计缓存区 */
		0, 0, 0, 0,														/**< 累计缓存区无移位 */
		32,																/**< 32位深度缓存 */
		0,																/**< 无蒙版缓存 */
		0,																/**< 无辅助缓存区 */
		PFD_MAIN_PLANE,													/**< 必须为PFD_MAIN_PLANE,设置为主绘图层 */
		0,																/**< 表示OpenGL实现所支持的上层或下层平面的数量 */
		0, 0, 0															/**< 过时,已不再使用 */
	};

	DWORD windowStyle = WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX &~WS_MINIMIZEBOX;	/**< 定义我们窗口类型,使用常规设定,去掉最大化按钮,并不能改变窗体大小 */
	DWORD windowExtendedStyle = WS_EX_APPWINDOW;						

	if (m_IsFullScreen == true)											/**< 如果为全屏模式,尝试转化为全屏模式 */
	{
		if (ChangeScreenSetting() == false)
		{																/**< 全屏模式转换失败,弹出对话框提示,并尝试窗口模式 */
			MessageBox(HWND_DESKTOP, "模式转换失败.\n在窗口模式下运行.", "Error", MB_OK | MB_ICONEXCLAMATION);
			m_IsFullScreen = false;										/**< 设置为窗口模式 */
		}
		else															/**< 如果为窗口模式 */
		{
			//ShowCursor(false);											/**< 隐藏鼠标 */
			windowStyle = WS_POPUP;										/**< 设置窗口模式为顶层窗口 */
			windowExtendedStyle |= WS_EX_TOPMOST;						
		}																
	}

	/// 调整我们窗口的大小,使其客户区的大小为我们设置的大小
	RECT windowRect = {GetPosX(), GetPosY(), GetPosX() + GetWidth(), GetPosY() + GetHeight()};
	if (m_IsFullScreen == false)										/**< 在窗口模式下使用 */
	{	
		windowExtendedStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;	/**< 使窗口具有3D外观 */
		int wid = GetSystemMetrics(SM_CXSCREEN);		/**< 获取当前屏幕宽 */
		int hei = GetSystemMetrics(SM_CYSCREEN);		/**< 获取当前屏幕高 */
		nX = (wid - GetWidth()) / 2;                    /**< 计算窗口居中用 */
		nY = (hei - GetHeight()) / 2;			
		/// 调整我们窗口的大小,使其客户区的大小为我们设置的大小
		AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle);
		/// 判断窗口的左上角是否隐藏在桌面外
		if (windowRect.left < 0)										/**< 如果窗口X坐标为负,移动坐标到0处,并调整窗口的位置 */
		{
			windowRect.right -= windowRect.left;						
			windowRect.left = 0;										
		}
		if (windowRect.top < 0)											/**< 如果窗口Y坐标为负,移动坐标到0处,并调整窗口的位置 */
		{
			windowRect.bottom -= windowRect.top;						
			windowRect.top = 0;											
		}
	}

	/// 创建窗口
	m_hWnd = CreateWindowEx(windowExtendedStyle,						/**< 窗口的扩展风格 */
							class_name,									/**< 窗口的类名 */
							window_title,								/**< 窗口标题 */
							windowStyle,								/**< 窗口的风格 */
							nX,nY,                                      /**< 窗口的左上角位置 */
							windowRect.right - windowRect.left,			/**< 窗口的宽度 */
							windowRect.bottom - windowRect.top,			/**< 窗口的高度 */
                            HWND_DESKTOP,								/**< 窗口的父窗口为桌面 */
							0,											/**< 无菜单 */
							h_instance,									/**< 传入窗口的实例句柄 */
							lpParam);									/**< 传入程序类参数 */

	while (m_hWnd != 0)													/**< 窗口是否创建成功 */
	{
		m_hDC = GetDC(m_hWnd);											/**< 返回窗口的设备描述表 */
		if (m_hDC == 0)													/**< 如果为空 */
		{																/**< 失败 */
			break;														
		}

		GLuint PixelFormat = ChoosePixelFormat(m_hDC, &pfd);			/**< 查找一个兼容的像素格式 */
		if (PixelFormat == 0)											/**< 如果没找到 */
		{																/**< 失败 */
			break;														
		}
		if (SetPixelFormat(m_hDC, PixelFormat, &pfd) == false)			/**< 设置像素格式 */
		{																/**< 失败 */
			break;														
		}
		m_hRC = wglCreateContext(m_hDC);								/**< 创建OpenGL的渲染描述表 */
		if (m_hRC == 0)													/**< 如果为空 */
		{																/**< 失败 */
			break;														
		}
		if (wglMakeCurrent(m_hDC, m_hRC) == false)						/**< 设置当前的OpenGL的渲染对象为当前的窗口 */
		{																/**< 失败 */
			break;														
		}
        
		ShowWindow(m_hWnd, SW_NORMAL);									/**< 显示窗口 */
		ReshapeGL();													/**< 告诉OpenGL调整窗口大小 */
		return true;													/**< 成功返回 */
	}																	

	Destroy();															/**< 释放资源 */
	return false;														/**< 返回失败 */
}
void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
	if (m_IsInGround)
	{
		// Already-grounded projectiles don't move at all
		return;
	}
	
	Vector3d PerTickSpeed = GetSpeed() / 20;
	Vector3d Pos = GetPosition();
	
	// Trace the tick's worth of movement as a line:
	Vector3d NextPos = Pos + PerTickSpeed;
	cProjectileTracerCallback TracerCallback(this);
	if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
	{
		// Something has been hit, abort all other processing
		return;
	}
	// The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff
	
	// Test for entity collisions:
	cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos);
	a_Chunk.ForEachEntity(EntityCollisionCallback);
	if (EntityCollisionCallback.HasHit())
	{
		// An entity was hit:
		Vector3d HitPos = Pos + (NextPos - Pos) * EntityCollisionCallback.GetMinCoeff();

		// DEBUG:
		LOGD("Projectile %d has hit an entity %d (%s) at {%.02f, %.02f, %.02f} (coeff %.03f)",
			m_UniqueID,
			EntityCollisionCallback.GetHitEntity()->GetUniqueID(),
			EntityCollisionCallback.GetHitEntity()->GetClass(),
			HitPos.x, HitPos.y, HitPos.z,
			EntityCollisionCallback.GetMinCoeff()
		);
		
		OnHitEntity(*(EntityCollisionCallback.GetHitEntity()), HitPos);
	}
	// TODO: Test the entities in the neighboring chunks, too

	// Update the position:
	SetPosition(NextPos);
	
	// Add slowdown and gravity effect to the speed:
	Vector3d NewSpeed(GetSpeed());
	NewSpeed.y += m_Gravity / 20;
	NewSpeed *= TracerCallback.GetSlowdownCoeff();
	SetSpeed(NewSpeed);
	SetRotationFromSpeed();
	SetPitchFromSpeed();

	// DEBUG:
	LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}, rot {%.02f, %.02f}",
		m_UniqueID,
		GetPosX(), GetPosY(), GetPosZ(),
		GetSpeedX(), GetSpeedY(), GetSpeedZ(),
		GetRotation(), GetPitch()
	);
}
void CBase::Update(float fElapsedTime)
{
	SetPosX( GetPosX() + GetVelX() * fElapsedTime );
	SetPosY( GetPosY() + GetVelY() * fElapsedTime );
}
Exemple #18
0
/// Moves pickups from above this hopper into it. Returns true if the contents have changed.
bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
{
	UNUSED(a_CurrentTick);

	class cHopperPickupSearchCallback :
		public cEntityCallback
	{
	public:
		cHopperPickupSearchCallback(const Vector3i & a_Pos, cItemGrid & a_Contents) :
			m_Pos(a_Pos),
			m_bFoundPickupsAbove(false),
			m_Contents(a_Contents)
		{
		}

		virtual bool Item(cEntity * a_Entity) override
		{
			ASSERT(a_Entity != NULL);

			if (!a_Entity->IsPickup() || a_Entity->IsDestroyed())
			{
				return false;
			}

			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
			double Distance = (EntityPos - BlockPos).Length();

			if (Distance < 0.5)
			{
				if (TrySuckPickupIn((cPickup *)a_Entity))
				{
					return false;
				}
			}

			return false;
		}

		bool TrySuckPickupIn(cPickup * a_Pickup)
		{
			cItem & Item = a_Pickup->GetItem();

			for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
			{
				if (m_Contents.IsSlotEmpty(i))
				{
					m_bFoundPickupsAbove = true;
					m_Contents.SetSlot(i, Item);
					a_Pickup->Destroy();  // Kill pickup

					return true;
				}
				else if (m_Contents.GetSlot(i).IsEqual(Item) && !m_Contents.GetSlot(i).IsFullStack())
				{
					m_bFoundPickupsAbove = true;

					int PreviousCount = m_Contents.GetSlot(i).m_ItemCount;
					
					Item.m_ItemCount -= m_Contents.ChangeSlotCount(i, Item.m_ItemCount) - PreviousCount;  // Set count to however many items were added
					
					if (Item.IsEmpty())
					{
						a_Pickup->Destroy();  // Kill pickup if all items were added
					}
					return true;
				}
			}
			return false;
		}

		bool FoundPickupsAbove(void) const
		{
			return m_bFoundPickupsAbove;
		}

	protected:
		Vector3i m_Pos;
		bool m_bFoundPickupsAbove;
		cItemGrid & m_Contents;
	};

	cHopperPickupSearchCallback HopperPickupSearchCallback(Vector3i(GetPosX(), GetPosY(), GetPosZ()), m_Contents);
	a_Chunk.ForEachEntity(HopperPickupSearchCallback);

	return HopperPickupSearchCallback.FoundPickupsAbove();
}
Exemple #19
0
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
	int BlockX = POSX_TOINT;
	int BlockY = POSY_TOINT;
	int BlockZ = POSZ_TOINT;

	// Position changed -> super::HandlePhysics() called
	GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, BlockX, BlockZ)

	// TODO Add collision detection with entities.
	a_Dt /= 1000;  // Convert from msec to sec
	Vector3d NextPos = Vector3d(GetPosX(), GetPosY(), GetPosZ());
	Vector3d NextSpeed = Vector3d(GetSpeedX(), GetSpeedY(), GetSpeedZ());
	
	if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
	{
		// Outside of the world		
		AddSpeedY(m_Gravity * a_Dt);
		AddPosition(GetSpeed() * a_Dt);
		return;
	}
	
	int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
	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.
			{
				m_bOnGround = false;
			}
		}
	}
	else
	{
		// Push out entity.
		BLOCKTYPE GotBlock;

		static const struct
		{
			int x, y, z;
		} gCrossCoords[] =
		{
			{ 1, 0,  0},
			{-1, 0,  0},
			{ 0, 0,  1},
			{ 0, 0, -1},
		} ;

		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)
		{
			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)
	{
		float fallspeed;
		if (IsBlockWater(BlockIn))
		{
			fallspeed = m_Gravity * a_Dt / 3;  // Fall 3x slower in water.
		}
		else if (BlockIn == E_BLOCK_COBWEB)
		{
			NextSpeed.y *= 0.05;  // Reduce overall falling speed
			fallspeed = 0;  // No falling.
		}
		else
		{
			// Normal gravity
			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;
			}
			NextSpeed.z *= 0.7f / (1 + a_Dt);
			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
	// might have different speed modifiers according to terrain.
	if (BlockIn == E_BLOCK_COBWEB)
	{
		NextSpeed.x *= 0.25;
		NextSpeed.z *= 0.25;
	}
					
	//Get water direction
	Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ);

	m_WaterSpeed *= 0.9f;		//Reduce speed each tick

	switch(WaterDir)
	{
		case X_PLUS:
			m_WaterSpeed.x = 0.2f;
			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;
	}

	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());
		// Distance traced is an integer, so we round up from the distance we should go (Speed * Delta), else we will encounter collision detection failurse
		int DistanceToTrace = (int)(ceil((NextSpeed * a_Dt).SqrLength()) * 2);
		bool HasHit = Tracer.Trace(NextPos, NextSpeed, DistanceToTrace);

		if (HasHit)
		{
			// Oh noez! We hit something: verify that the (hit position - current) was smaller or equal to the (position that we should travel without obstacles - current)
			// This is because previously, we traced with a length that was rounded up (due to integer limitations), and in the case that something was hit, we don't want to overshoot our projected movement
			if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * a_Dt).SqrLength())
			{
				// Block hit was within our projected path
				// Begin by stopping movement in the direction that we hit something. The Normal is the line perpendicular to a 2D face and in this case, stores what block face was hit through either -1 or 1.
				// For example: HitNormal.y = -1 : BLOCK_FACE_YM; HitNormal.y = 1 : BLOCK_FACE_YP
				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 == 1) // Hit BLOCK_FACE_YP, we are on the ground
				{
					m_bOnGround = true;
				}

				// Now, set our position to the hit block (i.e. move part way along our intended trajectory)
				NextPos.Set(Tracer.RealHit.x, Tracer.RealHit.y, Tracer.RealHit.z);
				NextPos.x += Tracer.HitNormal.x * 0.1;
				NextPos.y += Tracer.HitNormal.y * 0.05;
				NextPos.z += Tracer.HitNormal.z * 0.1;
			}
			else
			{
				// We have hit a block but overshot our intended trajectory, move normally, safe in the warm cocoon of knowledge that we won't appear to teleport forwards on clients,
				// and that this piece of software will come to be hailed as the epitome of performance and functionality in C++, never before seen, and of such a like that will never
				// be henceforth seen again in the time of programmers and man alike
				// </&sensationalist>
				NextPos += (NextSpeed * a_Dt);
			}
		}
		else
		{
			// We didn't hit anything, so move =]
			NextPos += (NextSpeed * a_Dt);
		}
	}

	SetPosition(NextPos);
	SetSpeed(NextSpeed);
}
Exemple #20
0
bool cPlayer::LoadFromDisk()
{
    LoadPermissionsFromDisk();

    // Log player permissions, cause it's what the cool kids do
    LOGINFO("Player %s has permissions:", m_PlayerName.c_str() );
    for( PermissionMap::iterator itr = m_ResolvedPermissions.begin(); itr != m_ResolvedPermissions.end(); ++itr )
    {
        if( itr->second ) LOGINFO("%s", itr->first.c_str() );
    }

    AString SourceFile;
    Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() );

    cFile f;
    if (!f.Open(SourceFile, cFile::fmRead))
    {
        // This is a new player whom we haven't seen yet, bail out, let them have the defaults
        return false;
    }

    AString buffer;
    if (f.ReadRestOfFile(buffer) != f.GetSize())
    {
        LOGWARNING("Cannot read player data from file \"%s\"", SourceFile.c_str());
        return false;
    }
    f.Close(); //cool kids play nice

    Json::Value root;
    Json::Reader reader;
    if (!reader.parse(buffer, root, false))
    {
        LOGWARNING("Cannot parse player data in file \"%s\", player will be reset", SourceFile.c_str());
    }

    Json::Value & JSON_PlayerPosition = root["position"];
    if (JSON_PlayerPosition.size() == 3)
    {
        SetPosX(JSON_PlayerPosition[(unsigned int)0].asDouble());
        SetPosY(JSON_PlayerPosition[(unsigned int)1].asDouble());
        SetPosZ(JSON_PlayerPosition[(unsigned int)2].asDouble());
        m_LastPosX = GetPosX();
        m_LastPosY = GetPosY();
        m_LastPosZ = GetPosZ();
        m_LastFoodPos = GetPosition();
    }

    Json::Value & JSON_PlayerRotation = root["rotation"];
    if (JSON_PlayerRotation.size() == 3)
    {
        SetRotation ((float)JSON_PlayerRotation[(unsigned int)0].asDouble());
        SetPitch    ((float)JSON_PlayerRotation[(unsigned int)1].asDouble());
        SetRoll     ((float)JSON_PlayerRotation[(unsigned int)2].asDouble());
    }

    m_Health              = root.get("health", 0).asInt();
    m_AirLevel            = root.get("air",            MAX_AIR_LEVEL).asInt();
    m_FoodLevel           = root.get("food",           MAX_FOOD_LEVEL).asInt();
    m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble();
    m_FoodTickTimer       = root.get("foodTickTimer",  0).asInt();
    m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble();
    m_LifetimeTotalXp     = (short) root.get("xpTotal", 0).asInt();
    m_CurrentXp           = (short) root.get("xpCurrent", 0).asInt();

    //SetExperience(root.get("experience", 0).asInt());

    m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt();

    m_Inventory.LoadFromJson(root["inventory"]);

    m_LoadedWorldName = root.get("world", "world").asString();

    LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
         m_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str()
        );

    return true;
}
Exemple #21
0
void GUIcontrol::Process()
{
	if(visible)
	{
		if(GetChildCount() == 0)
		{
			if(PointInBox(mouseX, mouseY, GetPosX(), GetPosY(), GetPatternWidth(), GetPatternHeight()))
			{
				GUIMessage temp_message;
							
				if(GetPatternCount() > 1)
					SetCurrentPattern(1);

				//temp_message.from = GetGID();
				//temp_message.a1 = MOUSE_OVER;
				//temp_message.a2 = 0;

				if(mouse[0])
				{
					_pressed = true;
					//mouse[0] = false;

					
					if(GetPatternCount() > 1)
					{
						SetCurrentPattern(2);
						_pos_dx = 1;
						_pos_dy = 1;
						if(_caption)
						{
							_caption_dx = 1;
							_caption_dy = 1;
						}
					}
				}
				else
				{
					_pos_dx = 0;
					_pos_dy = 0;
					if(_caption)
					{
						_caption_dx = 0;
						_caption_dy = 0;
					}

					if(_pressed)
					{
						_pressed = false;

						temp_message.from = GetGID();
						temp_message.a1 = MOUSE_LEFT_CLICKED;
						temp_message.a2 = 0;
						temp_message.solved = false;

						SendMessage(temp_message);

					}

				}

			}

			else
			{
				if(GetCurrentPattern() != 0) SetCurrentPattern(0);
			}
		}
	}

}
Exemple #22
0
cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
    : super(etPlayer, 0.6, 1.8)
    , m_GameMode(eGameMode_NotSet)
    , m_IP("")
    , m_LastBlockActionTime( 0 )
    , m_LastBlockActionCnt( 0 )
    , m_AirLevel( MAX_AIR_LEVEL )
    , m_AirTickTimer( DROWNING_TICKS )
    , m_bVisible( true )
    , m_LastGroundHeight( 0 )
    , m_bTouchGround( false )
    , m_Stance( 0.0 )
    , m_Inventory(*this)
    , m_CurrentWindow(NULL)
    , m_InventoryWindow(NULL)
    , m_TimeLastPickupCheck( 0.f )
    , m_Color('-')
    , m_ClientHandle( a_Client )
    , m_FoodLevel(MAX_FOOD_LEVEL)
    , m_FoodSaturationLevel(5)
    , m_FoodTickTimer(0)
    , m_FoodExhaustionLevel(0)
    , m_FoodPoisonedTicksRemaining(0)
    , m_NormalMaxSpeed(0.1)
    , m_SprintingMaxSpeed(0.13)
    , m_IsCrouched(false)
    , m_IsSprinting(false)
    , m_IsSwimming(false)
    , m_IsSubmerged(false)
    , m_EatingFinishTick(-1)
    , m_IsChargingBow(false)
    , m_BowCharge(0)
    , m_CurrentXp(0)
    , m_LifetimeTotalXp(0)
    , m_bDirtyExperience(false)
{
    LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
         a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
         this, GetUniqueID()
        );

    m_InventoryWindow = new cInventoryWindow(*this);
    m_CurrentWindow = m_InventoryWindow;
    m_InventoryWindow->OpenedByPlayer(*this);

    SetMaxHealth(MAX_HEALTH);
    m_Health = MAX_HEALTH;

    cTimer t1;
    m_LastPlayerListTime = t1.GetNowTime();

    m_TimeLastTeleportPacket = 0;
    m_TimeLastPickupCheck = 0;

    m_PlayerName = a_PlayerName;
    m_bDirtyPosition = true; // So chunks are streamed to player at spawn

    if (!LoadFromDisk())
    {
        m_Inventory.Clear();
        SetPosX(cRoot::Get()->GetDefaultWorld()->GetSpawnX());
        SetPosY(cRoot::Get()->GetDefaultWorld()->GetSpawnY());
        SetPosZ(cRoot::Get()->GetDefaultWorld()->GetSpawnZ());

        LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}",
             a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ()
            );
    }
    m_LastJumpHeight = (float)(GetPosY());
    m_LastGroundHeight = (float)(GetPosY());
    m_Stance = GetPosY() + 1.62;

    cRoot::Get()->GetServer()->PlayerCreated(this);
}
Exemple #23
0
CEnemy::CEnemy( EleType ElementToBe, float initx, float inity, int boss, CFlock* Flock )
{
	m_nType         = OBJ_ENEMY;
	m_bIsFrozen     = false;
	m_fFrozenSpeed  = 0.5f;
	m_fFreezeTimer  = 0.0f;
	m_fChangeAnimationTimer = 0.76f;
	LastFrame = NULL;
	m_fLastPosition = inity;


	if(!boss)
	{
		switch( ElementToBe )
		{
		case OBJ_EARTH:
			{
				currState = new AIStateEarth( );
				SetHeight( 100 );
				SetWidth( 135 );
				SetPosX(initx);
				SetPosY(inity - GetHeight());
				SetVelX(25.0f);
				SetVelY(0.0f);
				( ( AIStateEarth* )currState )->SetInitPos( int( GetPosX( ) ), int( GetPosY( ) ) );
				SetHeight( 80 );
				SetWidth( 135 );
				m_nHealth      = 80 * CGameplayState::GetInstance()->GetDifficulty() + (CSpellFactory::GetInstance()->GetWindLevel() * 10);
				m_SpellType    = OBJ_EARTH;
				currDirec      = RIGHT;
				m_nAnimation = m_SpellType +1;
				m_fScale = .65f;
				SetAnimation(OBJ_EARTH +1,0);
			} break;
		case OBJ_FIRE:
			{
				currState = new AIStateFire( );
				SetPosX(initx);
				SetPosY(inity - 55);
				SetVelX(75.0f);
				SetVelY(0.0f);
				SetHeight( 54 );
				SetWidth ( 32 );
				m_nHealth      = 50 * CGameplayState::GetInstance()->GetDifficulty() + (CSpellFactory::GetInstance()->GetEarthLevel() * 7);
				m_SpellType    = OBJ_FIRE;
				currDirec      = RIGHT;
				m_fScale = 0.5f;
				m_nAnimation = m_SpellType +1;
				SetAnimation(OBJ_FIRE +1,0);

			} break;
		case OBJ_ICE:
			{
				currState = new AIStateIce( );
				SetPosX(initx);
				SetPosY(inity - 55);
				SetVelX(50.0f);
				SetVelY(0.0f);
				SetHeight( 64 );
				SetWidth ( 64 );
				SetAnimation(1,0);
				m_nHealth      = 50 * CGameplayState::GetInstance()->GetDifficulty() + (CSpellFactory::GetInstance()->GetFireLevel() * 7);
				m_SpellType    = OBJ_ICE;
				m_fScale = 0.5f;
				currDirec      = RIGHT;
				m_nAnimation = m_SpellType +1;
				SetAnimation(OBJ_ICE +1,0);
			} break;
		case OBJ_WIND:
			{
				currState = new AIStateWind();
				SetPosX(initx);
				SetPosY(inity);
				m_fScale = 0.4f;

				((AIStateWind*)currState)->SetFlock((CFlock*)Flock);
				SetVelX((float)(rand()%150));
				SetVelY((float)(rand()%150));
				if(rand()%2)
				{
					SetVelX((float)(rand()%150));
					SetVelY((float)(rand()%150));
				}
				else
				{
					SetVelX(rand()%150 * -1.0f);
					SetVelY(rand()%150 * -1.0f);
				}

				SetHeight(16);
				SetWidth(16);
				m_nHealth = 25 * CGameplayState::GetInstance()->GetDifficulty() + CSpellFactory::GetInstance()->GetIceLevel() * 5;
				m_SpellType = OBJ_WIND;
				currDirec = RIGHT;
				m_nAnimation = m_SpellType +1;
				SetAnimation(OBJ_WIND +1,0);
				currAnimation = NULL;
				break;
			} 
		}
	}


	else if(boss  == 1)
	{
		currState = new AIDocBoss(1500 + (CSpellFactory::GetInstance()->GetIceLevel() + CSpellFactory::GetInstance()->GetWindLevel() + CSpellFactory::GetInstance()->GetEarthLevel() + CSpellFactory::GetInstance()->GetFireLevel()) * 15);

		SetPosX(initx);
		SetPosY(inity);
		SetVelX(0.0f);
		SetVelY(0.0f);
		SetHeight(64);
		SetWidth(40);
		m_nAnimation = 5;
		SetImage(CSGD_TextureManager::GetInstance()->LoadTexture("resource/graphics/Doctorboss.png"));
		m_nHealth = 1500 + (CSpellFactory::GetInstance()->GetIceLevel() + CSpellFactory::GetInstance()->GetWindLevel() + CSpellFactory::GetInstance()->GetEarthLevel() + CSpellFactory::GetInstance()->GetFireLevel()) * 15;
		m_SpellType = OBJ_SHIELD;
		m_fScale = 1.0f;
		currDirec = RIGHT;
		SetAnimation(5,0);
	}
	else if(boss >= 2)
	{
		currState = new AISisBoss;

		SetPosX(initx);
		SetPosY(inity);
		SetVelX(0.0f);
		SetVelY(0.0f);
		SetHeight(60);
		m_fScale = 1.0f;
		SetWidth(50);
		m_nHealth = 1500;
		m_SpellType = OBJ_EARTH;
		currDirec = RIGHT;
		m_nAnimation = 6;
		SetAnimation(6,0);
	}

	m_fShotTimer   = 3.0f;
	m_fWaitTimer   = 0.0f;
	m_nAttackWho   = 0;
	m_fKnockBack   = 0.0f;
	m_bKnockBack   = false;
	m_bBurning     = false;
	m_nBurnDamage  = 0;
	m_fBurnTimer   = 0.0f;
}
Exemple #24
0
Vector3d cPlayer::GetEyePosition(void) const
{
    return Vector3d( GetPosX(), m_Stance, GetPosZ() );
}
Exemple #25
0
void cMinecart::SnapToRail(NIBBLETYPE a_RailMeta)
{
	switch (a_RailMeta)
	{
		case E_META_RAIL_ASCEND_XM:
		case E_META_RAIL_ASCEND_XP:
		case E_META_RAIL_XM_XP:
		{
			SetSpeedZ(NO_SPEED);
			SetPosZ(floor(GetPosZ()) + 0.5);
			break;
		}
		case E_META_RAIL_ASCEND_ZM:
		case E_META_RAIL_ASCEND_ZP:
		case E_META_RAIL_ZM_ZP:
		{
			SetSpeedX(NO_SPEED);
			SetPosX(floor(GetPosX()) + 0.5);
			break;
		}
		// Curved rail physics: once minecart has reached more than half of the block in the direction that it is travelling in, jerk it in the direction of curvature
		case E_META_RAIL_CURVED_ZM_XM:
		{
			if (GetPosZ() > floor(GetPosZ()) + 0.5)
			{
				if (GetSpeedZ() > NO_SPEED)
				{
					SetSpeedX(-GetSpeedZ() * 0.7);
				}

				SetSpeedZ(NO_SPEED);
				SetPosZ(floor(GetPosZ()) + 0.5);
			}
			else if (GetPosX() > floor(GetPosX()) + 0.5)
			{
				if (GetSpeedX() > 0)
				{
					SetSpeedZ(-GetSpeedX() * 0.7);
				}

				SetSpeedX(NO_SPEED);
				SetPosX(floor(GetPosX()) + 0.5);
			}
			SetSpeedY(NO_SPEED);
			break;
		}
		case E_META_RAIL_CURVED_ZM_XP:
		{
			if (GetPosZ() > floor(GetPosZ()) + 0.5)
			{
				if (GetSpeedZ() > NO_SPEED)
				{
					SetSpeedX(GetSpeedZ() * 0.7);
				}

				SetSpeedZ(NO_SPEED);
				SetPosZ(floor(GetPosZ()) + 0.5);
			}
			else if (GetPosX() < floor(GetPosX()) + 0.5)
			{
				if (GetSpeedX() < NO_SPEED)
				{
					SetSpeedZ(GetSpeedX() * 0.7);
				}

				SetSpeedX(NO_SPEED);
				SetPosX(floor(GetPosX()) + 0.5);
			}
			SetSpeedY(NO_SPEED);
			break;
		}
		case E_META_RAIL_CURVED_ZP_XM:
		{
			if (GetPosZ() < floor(GetPosZ()) + 0.5)
			{
				if (GetSpeedZ() < NO_SPEED)
				{
					SetSpeedX(GetSpeedZ() * 0.7);
				}

				SetSpeedZ(NO_SPEED);
				SetPosZ(floor(GetPosZ()) + 0.5);
			}
			else if (GetPosX() > floor(GetPosX()) + 0.5)
			{
				if (GetSpeedX() > NO_SPEED)
				{
					SetSpeedZ(GetSpeedX() * 0.7);
				}

				SetSpeedX(NO_SPEED);
				SetPosX(floor(GetPosX()) + 0.5);
			}
			SetSpeedY(NO_SPEED);
			break;
		}
		case E_META_RAIL_CURVED_ZP_XP:
		{
			if (GetPosZ() < floor(GetPosZ()) + 0.5)
			{
				if (GetSpeedZ() < NO_SPEED)
				{
					SetSpeedX(-GetSpeedZ() * 0.7);
				}

				SetSpeedZ(NO_SPEED);
				SetPosZ(floor(GetPosZ()) + 0.5);
			}
			else if (GetPosX() < floor(GetPosX()) + 0.5)
			{
				if (GetSpeedX() < NO_SPEED)
				{
					SetSpeedZ(-GetSpeedX() * 0.7);
				}

				SetSpeedX(NO_SPEED);
				SetPosX(floor(GetPosX()) + 0.5);
			}
			SetSpeedY(0);
			break;
		}
		default: break;
	}
}
Exemple #26
0
void cMonster::KilledBy(TakeDamageInfo & a_TDI)
{
	super::KilledBy(a_TDI);
	if (m_SoundHurt != "")
	{
		m_World->BroadcastSoundEffect(m_SoundDeath, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
	}
	int Reward;
	switch (m_MobType)
	{
		// Animals
		case mtChicken:
		case mtCow:
		case mtHorse:
		case mtPig:
		case mtRabbit:
		case mtSheep:
		case mtSquid:
		case mtMooshroom:
		case mtOcelot:
		case mtWolf:
		{
			Reward = m_World->GetTickRandomNumber(2) + 1;
			break;
		}

		// Monsters
		case mtCaveSpider:
		case mtCreeper:
		case mtEnderman:
		case mtGhast:
		case mtGuardian:
		case mtSilverfish:
		case mtSkeleton:
		case mtSpider:
		case mtWitch:
		case mtZombie:
		case mtZombiePigman:
		case mtSlime:
		case mtMagmaCube:
		{
			Reward = 6 + (m_World->GetTickRandomNumber(2));
			break;
		}
		case mtBlaze:
		{
			Reward = 10;
			break;
		}

		// Bosses
		case mtEnderDragon:
		{
			Reward = 12000;
			break;
		}
		case mtWither:
		{
			Reward = 50;
			break;
		}

		default:
		{
			Reward = 0;
			break;
		}
	}
	if ((a_TDI.Attacker != nullptr) && (!IsBaby()))
	{
		m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward);
	}
	m_DestroyTimer = std::chrono::milliseconds(0);
}
Exemple #27
0
bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
{
	cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == NULL) ? -1 : m_Attachee->GetUniqueID()));
	int ChunkX, ChunkZ;
	cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ);
	m_World->ForEachEntityInChunk(ChunkX, ChunkZ, MinecartCollisionCallback);

	if (!MinecartCollisionCallback.FoundIntersection())
	{
		return false;
	}

	switch (a_RailMeta)
	{
		case E_META_RAIL_ZM_ZP:
		{
			if (MinecartCollisionCallback.GetCollidedEntityPosition().z >= GetPosZ())
			{
				if ((-GetSpeedZ() * 0.4) < 0.01)
				{
					AddSpeedZ(-4);
				}
				else
				{
					SetSpeedZ(-GetSpeedZ() * 0.4);
				}
			}
			else
			{
				if ((GetSpeedZ() * 0.4) < 0.01)
				{
					AddSpeedZ(4);
				}
				else
				{
					SetSpeedZ(GetSpeedZ() * 0.4);
				}
			}
			return true;
		}
		case E_META_RAIL_XM_XP:
		{
			if (MinecartCollisionCallback.GetCollidedEntityPosition().x >= GetPosX())
			{
				if ((-GetSpeedX() * 0.4) < 0.01)
				{
					AddSpeedX(-4);
				}
				else
				{
					SetSpeedX(-GetSpeedX() * 0.4);
				}
			}
			else
			{
				if ((GetSpeedX() * 0.4) < 0.01)
				{
					AddSpeedX(4);
				}
				else
				{
					SetSpeedX(GetSpeedX() * 0.4);
				}
			}
			return true;
		}
		case E_META_RAIL_CURVED_ZM_XM:
		case E_META_RAIL_CURVED_ZP_XP:
		{
			Vector3d Distance = MinecartCollisionCallback.GetCollidedEntityPosition() - Vector3d(GetPosX(), 0, GetPosZ());

			// Prevent division by small numbers
			if (std::abs(Distance.z) < 0.001)
			{
				Distance.z = 0.001;
			}

			/* Check to which side the minecart is to be pushed.
			Let's consider a z-x-coordinate system where the minecart is the center (0/0).
			The minecart moves along the line x = -z, the perpendicular line to this is x = z.
			In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */
			if (
				((Distance.z > 0) && ((Distance.x / Distance.z) >= 1)) ||
				((Distance.z < 0) && ((Distance.x / Distance.z) <= 1))
			)
			{
				// Moving -X +Z
				if ((-GetSpeedX() * 0.4 / sqrt(2.0)) < 0.01)
				{
					// ~ SpeedX >= 0 Immobile or not moving in the "right" direction. Give it a bump!
					AddSpeedX(-4 / sqrt(2.0));
					AddSpeedZ(4 / sqrt(2.0));
				}
				else
				{
					// ~ SpeedX < 0 Moving in the "right" direction. Only accelerate it a bit.
					SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0));
					SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0));
				}
			}
			else if ((GetSpeedX() * 0.4 / sqrt(2.0)) < 0.01)
			{
				// Moving +X -Z
				// ~ SpeedX <= 0 Immobile or not moving in the "right" direction
				AddSpeedX(4 / sqrt(2.0));
				AddSpeedZ(-4 / sqrt(2.0));
			}
			else
			{
				// ~ SpeedX > 0 Moving in the "right" direction
				SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0));
				SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0));
			}
			break;
		}
		case E_META_RAIL_CURVED_ZM_XP:
		case E_META_RAIL_CURVED_ZP_XM:
		{
			Vector3d Distance = MinecartCollisionCallback.GetCollidedEntityPosition() - Vector3d(GetPosX(), 0, GetPosZ());

			// Prevent division by small numbers
			if (std::abs(Distance.z) < 0.001)
			{
				Distance.z = 0.001;
			}

			/* Check to which side the minecart is to be pushed.
			Let's consider a z-x-coordinate system where the minecart is the center (0/0).
			The minecart moves along the line x = z, the perpendicular line to this is x = -z.
			In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */
			if (
				((Distance.z > 0) && ((Distance.x / Distance.z) <= -1)) ||
				((Distance.z < 0) && ((Distance.x / Distance.z) >= -1))
			)
			{
				// Moving +X +Z
				if ((GetSpeedX() * 0.4) < 0.01)
				{
					// ~ SpeedX <= 0 Immobile or not moving in the "right" direction
					AddSpeedX(4 / sqrt(2.0));
					AddSpeedZ(4 / sqrt(2.0));
				}
				else
				{
					// ~ SpeedX > 0 Moving in the "right" direction
					SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0));
					SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0));
				}
			}
			else if ((-GetSpeedX() * 0.4) < 0.01)
			{
				// Moving -X -Z
				// ~ SpeedX >= 0 Immobile or not moving in the "right" direction
				AddSpeedX(-4 / sqrt(2.0));
				AddSpeedZ(-4 / sqrt(2.0));
			}
			else
			{
				// ~ SpeedX < 0 Moving in the "right" direction
				SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0));
				SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0));
			}
			break;
		}
		default: break;
	}

	return false;
}
Exemple #28
0
void CBattleItem::Render()
{
	CSGD_TextureManager::GetInstance()->DrawWithZSort(GetImageID(), (int)GetPosX(), (int)GetPosY(), GetPosZ());
}
void CSweepingWind::Render( void )
{
	CCamera* Game_Camera = CCamera::GetInstance();
	AnimationManager::GetInstance()->Render(GetPosX() - Game_Camera->GetPosX(),
		GetPosY() - Game_Camera->GetPosY(), CEntity::IsFlipped(), *GetAnimInfo());
}
Exemple #30
0
void cPlayer::KilledBy(TakeDamageInfo & a_TDI)
{
	super::KilledBy(a_TDI);

	if (m_Health > 0)
	{
		return;  //  not dead yet =]
	}

	m_bVisible = false;  // So new clients don't see the player

	// Puke out all the items
	cItems Pickups;
	m_Inventory.CopyToItems(Pickups);
	m_Inventory.Clear();

	if (GetName() == "Notch")
	{
		Pickups.Add(cItem(E_ITEM_RED_APPLE));
	}

	m_Stats.AddValue(statItemsDropped, (StatValue)Pickups.Size());

	m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
	SaveToDisk();  // Save it, yeah the world is a tough place !

	if ((a_TDI.Attacker == NULL) && m_World->ShouldBroadcastDeathMessages())
	{
		AString DamageText;
		switch (a_TDI.DamageType)
		{
			case dtRangedAttack: DamageText = "was shot"; break;
			case dtLightning: DamageText = "was plasmified by lightining"; break;
			case dtFalling: DamageText = (GetWorld()->GetTickRandomNumber(10) % 2 == 0) ? "fell to death" : "hit the ground too hard"; break;
			case dtDrowning: DamageText = "drowned"; break;
			case dtSuffocating: DamageText = (GetWorld()->GetTickRandomNumber(10) % 2 == 0) ? "git merge'd into a block" : "fused with a block"; break;
			case dtStarving: DamageText = "forgot the importance of food"; break;
			case dtCactusContact: DamageText = "was impaled on a cactus"; break;
			case dtLavaContact: DamageText = "was melted by lava"; break;
			case dtPoisoning: DamageText = "died from septicaemia"; break;
			case dtWithering: DamageText = "is a husk of their former selves"; break;
			case dtOnFire: DamageText = "forgot to stop, drop, and roll"; break;
			case dtFireContact: DamageText = "burnt themselves to death"; break;
			case dtInVoid: DamageText = "somehow fell out of the world"; break;
			case dtPotionOfHarming: DamageText = "was magicked to death"; break;
			case dtEnderPearl: DamageText = "misused an ender pearl"; break;
			case dtAdmin: DamageText = "was administrator'd"; break;
			case dtExplosion: DamageText = "blew up"; break;
			default: DamageText = "died, somehow; we've no idea how though"; break;
		}
		GetWorld()->BroadcastChatDeath(Printf("%s %s", GetName().c_str(), DamageText.c_str()));
	}
	else if (a_TDI.Attacker == NULL)  // && !m_World->ShouldBroadcastDeathMessages() by fallthrough
	{
		// no-op
	}
	else if (a_TDI.Attacker->IsPlayer())
	{
		cPlayer * Killer = (cPlayer *)a_TDI.Attacker;

		GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), Killer->GetName().c_str()));
	}
	else
	{
		AString KillerClass = a_TDI.Attacker->GetClass();
		KillerClass.erase(KillerClass.begin());  // Erase the 'c' of the class (e.g. "cWitch" -> "Witch")

		GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str()));
	}

	m_Stats.AddValue(statDeaths);

	m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1);
}