Esempio n. 1
0
void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
{
	if (m_ClientHandle != NULL)
	{
		if (m_ClientHandle->IsDestroyed())
		{
			// This should not happen, because destroying a client will remove it from the world, but just in case
			m_ClientHandle = NULL;
			return;
		}
		
		if (!m_ClientHandle->IsPlaying())
		{
			// We're not yet in the game, ignore everything
			return;
		}
	}
	
	if (!a_Chunk.IsValid())
	{
		// This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83)
		return;
	}
	
	super::Tick(a_Dt, a_Chunk);
	
	// Handle charging the bow:
	if (m_IsChargingBow)
	{
		m_BowCharge += 1;
	}
	
	//handle updating experience
	if (m_bDirtyExperience)
	{
		SendExperience();
	}

	if (m_bDirtyPosition)
	{
		// Apply food exhaustion from movement:
		ApplyFoodExhaustionFromMovement();
		
		cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this);
		BroadcastMovementUpdate(m_ClientHandle);
		m_ClientHandle->StreamChunks();
	}
	else
	{
		BroadcastMovementUpdate(m_ClientHandle);
	}

	if (m_Health > 0)  // make sure player is alive
	{
		m_World->CollectPickupsByPlayer(this);

		if ((m_EatingFinishTick >= 0) && (m_EatingFinishTick <= m_World->GetWorldAge()))
		{
			FinishEating();
		}
		
		HandleFood();
	}
	
	if (m_IsFishing)
	{
		HandleFloater();
	}

	// Update items (e.g. Maps)
	m_Inventory.UpdateItems();

	// Send Player List (Once per m_LastPlayerListTime/1000 ms)
	cTimer t1;
	if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime())
	{
		m_World->SendPlayerList(this);
		m_LastPlayerListTime = t1.GetNowTime();
	}

	if (IsFlying())
	{
		m_LastGroundHeight = (float)GetPosY();
	}
}
Esempio n. 2
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 ) LOG(" - %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)
	{
		SetYaw      ((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();
	m_IsFlying            = root.get("isflying", 0).asBool();

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

	if (m_GameMode == eGameMode_Creative)
	{
		m_CanFly = true;
	}
	
	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;
}
Esempio n. 3
0
bool cPlayer::SaveToDisk()
{
	cFile::CreateFolder(FILE_IO_PREFIX + AString("players"));

	// create the JSON data
	Json::Value JSON_PlayerPosition;
	JSON_PlayerPosition.append(Json::Value(GetPosX()));
	JSON_PlayerPosition.append(Json::Value(GetPosY()));
	JSON_PlayerPosition.append(Json::Value(GetPosZ()));

	Json::Value JSON_PlayerRotation;
	JSON_PlayerRotation.append(Json::Value(GetYaw()));
	JSON_PlayerRotation.append(Json::Value(GetPitch()));
	JSON_PlayerRotation.append(Json::Value(GetRoll()));

	Json::Value JSON_Inventory;
	m_Inventory.SaveToJson(JSON_Inventory);

	Json::Value root;
	root["position"]       = JSON_PlayerPosition;
	root["rotation"]       = JSON_PlayerRotation;
	root["inventory"]      = JSON_Inventory;
	root["health"]         = m_Health;
	root["xpTotal"]        = m_LifetimeTotalXp;
	root["xpCurrent"]      = m_CurrentXp;
	root["air"]            = m_AirLevel;
	root["food"]           = m_FoodLevel;
	root["foodSaturation"] = m_FoodSaturationLevel;
	root["foodTickTimer"]  = m_FoodTickTimer;
	root["foodExhaustion"] = m_FoodExhaustionLevel;
	root["world"]          = GetWorld()->GetName();
	root["isflying"]       = IsFlying();

	if (m_GameMode == GetWorld()->GetGameMode())
	{
		root["gamemode"] = (int) eGameMode_NotSet;
	}
	else
	{
		root["gamemode"] = (int) m_GameMode;
	}

	Json::StyledWriter writer;
	std::string JsonData = writer.write(root);

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

	cFile f;
	if (!f.Open(SourceFile, cFile::fmWrite))
	{
		LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", m_PlayerName.c_str(), SourceFile.c_str());
		return false;
	}
	if (f.Write(JsonData.c_str(), JsonData.size()) != (int)JsonData.size())
	{
		LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str()); 
		return false;
	}
	return true;
}
Esempio n. 4
0
bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
{
	if ((TDI.Attacker != nullptr) && 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;
}
Esempio n. 5
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();
}
Esempio n. 6
0
void cMinecartWithChest::Destroyed()
{
	cItems Pickups;
	m_Contents.CopyToItems(Pickups);
	GetWorld()->SpawnItemPickups(Pickups, GetPosX(), GetPosY() + 1, GetPosZ(), 4);
}
Esempio n. 7
0
void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
{
	// Initialise to 'slow down' values
	int AccelDecelSpeed = -2;
	int AccelDecelNegSpeed = 2;

	if ((a_RailMeta & 0x8) == 0x8)
	{
		// Rail powered - set variables to 'speed up' values
		AccelDecelSpeed = 1;
		AccelDecelNegSpeed = -1;
	}

	switch (a_RailMeta & 0x07)
	{
		case E_META_RAIL_ZM_ZP:  // NORTHSOUTH
		{
			SetYaw(270);
			SetPosY(floor(GetPosY()) + 0.55);
			SetSpeedY(0);
			SetSpeedX(0);

			bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
			if (EntCol || BlckCol)
			{
				return;
			}
			
			if (GetSpeedZ() != NO_SPEED)
			{
				if (GetSpeedZ() > NO_SPEED)
				{
					AddSpeedZ(AccelDecelSpeed);
				}
				else
				{
					AddSpeedZ(AccelDecelNegSpeed);
				}
			}
			break;
		}
		case E_META_RAIL_XM_XP:  // EASTWEST
		{
			SetYaw(180);
			SetPosY(floor(GetPosY()) + 0.55);
			SetSpeedY(NO_SPEED);
			SetSpeedZ(NO_SPEED);

			bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
			if (EntCol || BlckCol)
			{
				return;
			}

			if (GetSpeedX() != NO_SPEED)
			{
				if (GetSpeedX() > NO_SPEED)
				{
					AddSpeedX(AccelDecelSpeed);
				}
				else
				{
					AddSpeedX(AccelDecelNegSpeed);
				}
			}
			break;
		}
		case E_META_RAIL_ASCEND_XM:  // ASCEND EAST
		{
			SetYaw(180);
			SetSpeedZ(NO_SPEED);

			if (GetSpeedX() >= NO_SPEED)
			{
				if (GetSpeedX() <= MAX_SPEED)
				{
					AddSpeedX(AccelDecelSpeed);
					SetSpeedY(-GetSpeedX());
				}
			}
			else
			{
				AddSpeedX(AccelDecelNegSpeed);
				SetSpeedY(-GetSpeedX());
			}
			break;
		}
		case E_META_RAIL_ASCEND_XP:  // ASCEND WEST
		{
			SetYaw(180);
			SetSpeedZ(NO_SPEED);

			if (GetSpeedX() > NO_SPEED)
			{
				AddSpeedX(AccelDecelSpeed);
				SetSpeedY(GetSpeedX());
			}
			else
			{
				if (GetSpeedX() >= MAX_SPEED_NEGATIVE)
				{
					AddSpeedX(AccelDecelNegSpeed);
					SetSpeedY(GetSpeedX());
				}
			}
			break;
		}
		case E_META_RAIL_ASCEND_ZM:  // ASCEND NORTH
		{
			SetYaw(270);
			SetSpeedX(NO_SPEED);

			if (GetSpeedZ() >= NO_SPEED)
			{
				if (GetSpeedZ() <= MAX_SPEED)
				{
					AddSpeedZ(AccelDecelSpeed);
					SetSpeedY(-GetSpeedZ());
				}
			}
			else
			{
				AddSpeedZ(AccelDecelNegSpeed);
				SetSpeedY(-GetSpeedZ());
			}
			break;
		}
		case E_META_RAIL_ASCEND_ZP:  // ASCEND SOUTH
		{
			SetYaw(270);
			SetSpeedX(NO_SPEED);

			if (GetSpeedZ() > NO_SPEED)
			{
				AddSpeedZ(AccelDecelSpeed);
				SetSpeedY(GetSpeedZ());
			}
			else
			{
				if (GetSpeedZ() >= MAX_SPEED_NEGATIVE)
				{
					AddSpeedZ(AccelDecelNegSpeed);
					SetSpeedY(GetSpeedZ());
				}
			}
			break;
		}
		default: ASSERT(!"Unhandled powered rail metadata!"); break;
	}
}
Esempio n. 8
0
void CGrunt::Update(float fElapsedTime)
{
	// Update common properties across all enemies
	CEnemy::Update(fElapsedTime);

	// if this enemy is cc'd don't 
	if (m_pEState->GetTimer() == true)
	{
		m_pEState->CEntityState::Update(fElapsedTime);
		return;
	}

	m_fUpdateOldPos += fElapsedTime;
	if( cooldown <= 0.0f )
		punching = false;

	if( punching == true )
		cooldown -= fElapsedTime;

	if (GetAnimInfo()->GetAnimationName() == "Grunt_Attack_Animation")
		return;

	if(GetTarget() != nullptr)
	{
		float tar_pos_x = GetTarget()->GetPosX();
		float tar_pos_y = GetTarget()->GetPosY();
		if(tar_pos_x > GetPosX())
		{
			//set Grunt's animation's facing to the right
			m_bFlipped = true;
		}
		else
		{
			// Set Grunt's animation to face to the left
			m_bFlipped = false;
		}

		SetFlipped( m_bFlipped );


		if(m_fMoveAway <= 0)
		{
			tar_pos_x += (m_bFlipped) ? -66 : 66;

			//Simple Pathing twards the player
			if(tar_pos_y != GetPosY() )//Above the Player
			{
				float min_Distance = (float)(GetTarget()->GetWidth()/2 + GetWidth()/2);
				if(GetPosX() + min_Distance > tar_pos_x && GetPosX() - min_Distance < tar_pos_x)
				{
					if( tar_pos_x < GetPosX())

						SetVelX(speed * fElapsedTime);
					else

						SetVelX(-speed * fElapsedTime);
				}
				else
				{
					if( tar_pos_y < GetPosY())

						SetVelY(-speed * fElapsedTime);
					else

						SetVelY(speed * fElapsedTime);
					if( tar_pos_x < GetPosX())

						SetVelX(-speed * fElapsedTime);
					else

						SetVelX(speed * fElapsedTime);
				}
			}
			else
			{
				SetVelY(0);
				if( tar_pos_x < GetPosX())

					SetVelX(-speed * fElapsedTime);
				else

					SetVelX(speed * fElapsedTime);
			}

			//stop 'bouncing'
			int threshold = 5;
			if(tar_pos_x - GetPosX() < threshold && tar_pos_x - GetPosX() > -1 * threshold)
				SetVelX(0);
			if(tar_pos_y - GetPosY() < threshold && tar_pos_y - GetPosY() > -1 * threshold)
				SetVelY(0);
		}
		else//update move away
		{
			m_fMoveAway -= fElapsedTime;
			if(m_bEvadeUp)
				SetVelY(-speed * fElapsedTime);
			else
				SetVelY(speed * fElapsedTime);
		}
		//Check Colider
		if(TileManager::GetInstance()->CheckBlockedTiles(GetPosX(), GetPosY(), GetVelX(), 0))
		{
			SetPosX(GetPosX() + GetVelX());
			if(TileManager::GetInstance()->CheckBlockedTiles(GetPosX(), GetPosY(), 0, GetVelY()))
				SetPosY(GetPosY() + GetVelY());
		}
		else
		{
			if( GetPosY() >= 600 )
				SetPosY( (GetPosY() - (GetPosY() - 599)) );
			else
				SetPosY(GetPosY() + 1);
			SetVelX(0);
			SetVelY(0);
		}
		if(GetPosX() < 0)
			SetPosX(0);
		if(punching == false && GetPosX() - tar_pos_x < 10 && GetPosX() - tar_pos_x > - 10 )
		{
			if(GetPosY() - tar_pos_y < 32 && GetPosY() - tar_pos_y > -32)
			{
				GetAnimInfo()->SetAnimationName("Grunt_Attack_Animation");
				punching = true;
				cooldown = 3.0f;
			}
		}
		//Set/use Move out of the way
		if(m_fUpdateOldPos >= 1.0f)
		{
			if(m_fPosXOld + 5 > GetPosX() && m_fPosXOld - 5 < GetPosX())
			{
				if(m_fPosYOld + 5 > GetPosY() && m_fPosYOld - 5 < GetPosY())
				{
					if(cooldown <= 0)
					{
						m_bEvadeUp = !m_bEvadeUp;
						if(m_fMoveAway <= 0)
							m_fMoveAway = 4.0f;
					}
				}
			}
			m_fPosXOld = GetPosX();
			m_fPosYOld = GetPosY();
			m_fUpdateOldPos = 0.0f;
		}
	}

	
}
Esempio n. 9
0
void cHorse::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	super::Tick(a_Dt, a_Chunk);
	if (!IsTicking())
	{
		// The base class tick destroyed us
		return;
	}

	if (!m_bIsMouthOpen)
	{
		if (m_World->GetTickRandomNumber(50) == 25)
		{
			m_bIsMouthOpen = true;
		}
	}
	else
	{
		if (m_World->GetTickRandomNumber(10) == 5)
		{
			m_bIsMouthOpen = false;
		}
	}

	if ((m_Attachee != nullptr) && (!m_bIsTame))
	{
		if (m_TameAttemptTimes < m_TimesToTame)
		{
			if (m_World->GetTickRandomNumber(50) == 25)
			{
				m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::SOUTH_EAST));
				m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::SOUTH_WEST));
				m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::NORTH_EAST));
				m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::NORTH_WEST));

				m_Attachee->Detach();
				m_bIsRearing = true;
			}
		}
		else
		{
			// TODO: emit hearts here
			m_bIsTame = true;
		}
	}

	if (m_bIsRearing)
	{
		if (m_RearTickCount == 20)
		{
			m_bIsRearing = false;
			m_RearTickCount = 0;
		}
		else
		{
			m_RearTickCount++;
		}
	}

	m_World->BroadcastEntityMetadata(*this);
}
Esempio n. 10
0
void MapMgr::ChangeObjectLocation(Object* obj)
{
	/*
	if ( !obj ) return; // crashfix
	*/

	ARCEMU_ASSERT(obj != NULL);

	// Items and containers are of no interest for us
	if(obj->IsItem() || obj->IsContainer() || obj->GetMapMgr() != this)
	{
		return;
	}

	Player* plObj = NULL;
	ByteBuffer* buf = 0;

	if(obj->IsPlayer())
	{
		plObj = TO< Player* >(obj);
	}

	Object* curObj;
	float fRange = 0.0f;

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

	if(obj->HasInRangeObjects())
	{
		for(Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(); iter != obj->GetInRangeSetEnd();)
		{
			curObj = *iter;
			++iter;

			if(curObj->IsPlayer() && plObj != NULL && plObj->transporter_info.guid && plObj->transporter_info.guid == TO< Player* >(curObj)->transporter_info.guid)
				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.)
			//If the object announcing its position is a transport, or other special object, then deleting it from visible objects should be avoided. - By: VLack
			else if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId())
				fRange = 0.0f;
			//If the object we're checking for possible removal is a transport or other special object, and we are players on the same map, don't remove it...
			else if(plObj && curObj->IsGameObject() && (TO< GameObject* >(curObj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId())
				fRange = 0.0f;
			else if(curObj->IsPlayer() && TO< Player* >(curObj)->GetFarsightTarget() == obj->GetGUID())
				fRange = 0.0f;//Mind Vision, Eye of Kilrogg
			else
				fRange = m_UpdateDistance; // normal distance

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

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

				curObj->RemoveInRangeObject(obj);

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

	///////////////////////////
	// 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(plObj != NULL)
		{
			if(plObj->GetBindMapId() != GetMapId())
			{
				plObj->SafeTeleport(plObj->GetBindMapId(), 0, plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0);
				plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				return;
			}
			else
			{
				obj->GetPositionV()->ChangeCoords(plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0);
				plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				plObj->SendTeleportAckMsg(plObj->GetPosition());
			}
		}
		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 == NULL)
	{
		objCell = Create(cellX, cellY);
		objCell->Init(cellX, cellY, this);
	}

	ARCEMU_ASSERT(objCell != NULL);

	// If object moved cell
	if(objCell != pOldCell)
	{
		// 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->IsActive())
			obj->Deactivate(this);

		if(pOldCell != NULL)
			pOldCell->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->IsPlayer())
		{
			// have to unlock/lock here to avoid a deadlock situation.
			UpdateCellActivity(cellX, cellY, 2);
			if(pOldCell != NULL)
			{
				// only do the second check if there's -/+ 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;

	//If the object announcing it's position is a special one, then it should do so in a much wider area - like the distance between the two transport towers in Orgrimmar, or more. - By: VLack
	if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_ONMOVEWIDE))
	{
		endX = cellX + 5 <= _sizeX ? cellX + 6 : (_sizeX - 1);
		endY = cellY + 5 <= _sizeY ? cellY + 6 : (_sizeY - 1);
		startX = cellX > 5 ? cellX - 6 : 0;
		startY = cellY > 5 ? cellY - 6 : 0;
	}

	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;
}
Esempio n. 11
0
bool CGUIInstance::Update()
{
	// reset render info
	m_VertexInfo.clear();
	if (m_ItemRef)
	{
		m_ItemRef->Update();
		m_ItemRef->GetRenderParams(m_VertexInfo, GetPosX(), GetPosY(), GetWidth(), GetHeight(), m_State, m_fAngle, m_iColor);
		vector<GUIFONTINFO> newFontData;
		m_ItemRef->GetFontParams(newFontData, GetPosX(), GetPosY(), GetWidth(), GetHeight(), m_State);

		for (UINT i=0; i<newFontData.size(); i++)
		{
			DWORD dwNewPrimaryFont = newFontData[i].dwPrimaryFontName;
			DWORD dwNewSecondaryFont = newFontData[i].dwSecondaryFontName;
			DWORD dwNewText = newFontData[i].dwText;

			if (i >= m_pFont.size())
			{
				// create new fonts!
				CREATEFONTINTERFACE cfi;
				static DWORD msgHash_CreateFont = CHashString(_T("CreateFont")).GetUniqueID();
				EngineGetToolBox()->SendMessage(msgHash_CreateFont, sizeof(CREATEFONTINTERFACE), &cfi);
				if (cfi.m_FontInterface == NULL)
				{
					EngineGetToolBox()->Log(LOGERROR, _T("Instance could not create a new font!\n"));
					assert(cfi.m_FontInterface);
					return false;
				}
				m_pFont.push_back(cfi.m_FontInterface);
				m_pFont[i]->UseKerning(false);
				m_pFont[i]->SetKerningScale( 1.0f );
				m_pFont[i]->SetVisible( true );
				m_pFont[i]->SetLeadingScale( 1.0f );					
			}

			if (i >= m_FontInfo.size())
			{
				m_pFont[i]->SetFont(m_ToolBox->GetHashString(dwNewPrimaryFont), newFontData[i].iFontSize);
				m_pFont[i]->SetFontBold(m_ToolBox->GetHashString(dwNewSecondaryFont), newFontData[i].iFontSize);
				m_pFont[i]->SetRenderRect(newFontData[i].renderRect.left, newFontData[i].renderRect.top, 
					newFontData[i].renderRect.right, newFontData[i].renderRect.bottom);				
				
				StdString colorAdjust = MultiplyTextColor(m_ToolBox->GetHashString(dwNewText));
				m_pFont[i]->SetText(colorAdjust);
				if (newFontData[i].bCentered)
				{
					float centerX = GetWidth() / 2.f;
					float centerY = GetHeight() / 2.f;
                    StdString cleanStr = RemoveFormatting(m_ToolBox->GetHashString(dwNewText));
					int textWidth = m_pFont[i]->GetFontPixWidth(cleanStr);
					int textHeight = newFontData[i].iFontSize * m_pFont[i]->GetNumLines();
					float textPosX = centerX - ((float)textWidth / 2.f) + newFontData[i].iXOffset;
					float textPosY = centerY - ((float)textHeight / 2.f) + newFontData[i].iYOffset;
					m_pFont[i]->SetOffset(textPosX, textPosY);
				}
				else
				{
					m_pFont[i]->SetOffset((float)newFontData[i].iXOffset, (float)newFontData[i].iYOffset);
				}

				m_pFont[i]->SetPageOffset(m_iPageOffsetX, m_iPageOffsetY);					
				m_pFont[i]->SetWidthRatio(m_fWidthRatio);
				m_pFont[i]->SetHeightRatio(m_fHeightRatio);
				m_pFont[i]->SetZoomFactor(m_fZoomFactor);

				if (newFontData[i].bUseShadow)
				{
					m_pFont[i]->EnableDropShadow(true);
					m_pFont[i]->SetShadowVals(newFontData[i].iShadowColor, newFontData[i].iShadowXScale, newFontData[i].iShadowYScale, newFontData[i].iShadowXOffset, newFontData[i].iShadowYOffset);
				}

				GUIFONTINFO entry;
				entry.dwPrimaryFontName = newFontData[i].dwPrimaryFontName;
				entry.dwSecondaryFontName = newFontData[i].dwSecondaryFontName;
				entry.dwText = newFontData[i].dwText;
				entry.iFontSize = newFontData[i].iFontSize;
				entry.bCentered = newFontData[i].bCentered;
				entry.iXOffset = newFontData[i].iXOffset;
				entry.iYOffset = newFontData[i].iYOffset;
				entry.renderRect = newFontData[i].renderRect;
				entry.clippingRect = newFontData[i].clippingRect;
				entry.bUseClippingRect = newFontData[i].bUseClippingRect;
				entry.bRender = true;
				entry.bUseShadow = newFontData[i].bUseShadow;
				entry.iShadowColor = newFontData[i].iShadowColor;
				entry.iShadowXScale = newFontData[i].iShadowXScale;
				entry.iShadowYScale = newFontData[i].iShadowYScale;
				entry.iShadowXOffset = newFontData[i].iShadowXOffset;
				entry.iShadowYOffset = newFontData[i].iShadowYOffset;
				
				m_FontInfo.push_back(entry);
			}
			// compare elements
			else
			{	
				if (m_FontInfo[i].dwPrimaryFontName != newFontData[i].dwPrimaryFontName)
				{
					m_pFont[i]->SetFont(m_ToolBox->GetHashString(dwNewPrimaryFont), newFontData[i].iFontSize);
					m_FontInfo[i].dwPrimaryFontName = newFontData[i].dwPrimaryFontName;
					m_FontInfo[i].iFontSize = newFontData[i].iFontSize;
				}
				if (m_FontInfo[i].dwSecondaryFontName != newFontData[i].dwSecondaryFontName)
				{
					m_pFont[i]->SetFontBold(m_ToolBox->GetHashString(dwNewSecondaryFont), newFontData[i].iFontSize);
					m_FontInfo[i].dwSecondaryFontName = newFontData[i].dwSecondaryFontName;
					m_FontInfo[i].iFontSize = newFontData[i].iFontSize;
				}
				if (m_FontInfo[i].iFontSize != newFontData[i].iFontSize)
				{
					m_pFont[i]->SetFont(m_ToolBox->GetHashString(dwNewPrimaryFont), newFontData[i].iFontSize);
					m_pFont[i]->SetFontBold(m_ToolBox->GetHashString(dwNewSecondaryFont), newFontData[i].iFontSize);
					m_FontInfo[i].iFontSize = newFontData[i].iFontSize;
				}
				if (m_FontInfo[i].dwText != newFontData[i].dwText)
				{
					StdString colorAdjust = MultiplyTextColor(m_ToolBox->GetHashString(dwNewText));
					m_pFont[i]->SetText(colorAdjust);
					m_FontInfo[i].dwText = newFontData[i].dwText;
					if (newFontData[i].bCentered)
					{
						float centerX = GetWidth() / 2.f;
						float centerY = GetHeight() / 2.f;
						StdString cleanStr = RemoveFormatting(m_ToolBox->GetHashString(dwNewText));
						int textWidth = m_pFont[i]->GetFontPixWidth(cleanStr);
						int textHeight = m_FontInfo[i].iFontSize * m_pFont[i]->GetNumLines();
						float textPosX = centerX - ((float)textWidth / 2.f) + m_FontInfo[i].iXOffset;
						float textPosY = centerY - ((float)textHeight / 2.f) + m_FontInfo[i].iYOffset;
						m_pFont[i]->SetOffset(textPosX, textPosY);
					}
				}
				if (m_FontInfo[i].bCentered != newFontData[i].bCentered)
				{
					m_FontInfo[i].bCentered = newFontData[i].bCentered;
					if (newFontData[i].bCentered)
					{
						float centerX = GetWidth() / 2.f;
						float centerY = GetHeight() / 2.f;
						StdString cleanStr = RemoveFormatting(m_ToolBox->GetHashString(dwNewText));
						int textWidth = m_pFont[i]->GetFontPixWidth(cleanStr);
						int textHeight = m_FontInfo[i].iFontSize * m_pFont[i]->GetNumLines();
						float textPosX = centerX - ((float)textWidth / 2.f) + newFontData[i].iXOffset;
						float textPosY = centerY - ((float)textHeight / 2.f) + newFontData[i].iYOffset;
						m_pFont[i]->SetOffset(textPosX, textPosY);
					}
					else
					{
						m_pFont[i]->SetOffset((float)newFontData[i].iXOffset, (float)newFontData[i].iYOffset);
					}
				}
				if ((m_FontInfo[i].iXOffset != newFontData[i].iXOffset) || (m_FontInfo[i].iYOffset != newFontData[i].iYOffset))
				{
					if (!m_FontInfo[i].bCentered)
					{
						m_pFont[i]->SetOffset((float)newFontData[i].iXOffset, (float)newFontData[i].iYOffset);
					}
					m_FontInfo[i].iXOffset = newFontData[i].iXOffset;
					m_FontInfo[i].iYOffset = newFontData[i].iYOffset;
				}
				if ((m_FontInfo[i].renderRect.bottom != newFontData[i].renderRect.bottom) ||
					(m_FontInfo[i].renderRect.top != newFontData[i].renderRect.top) ||
					(m_FontInfo[i].renderRect.left != newFontData[i].renderRect.left) ||
					(m_FontInfo[i].renderRect.right != newFontData[i].renderRect.right))
				{
					m_pFont[i]->SetRenderRect(newFontData[i].renderRect.left, newFontData[i].renderRect.top, 
						newFontData[i].renderRect.right, newFontData[i].renderRect.bottom);
					m_FontInfo[i].renderRect = newFontData[i].renderRect;
					if (newFontData[i].bCentered)
					{
						float centerX = GetWidth() / 2.f;
						float centerY = GetHeight() / 2.f;
						StdString cleanStr = RemoveFormatting(m_ToolBox->GetHashString(dwNewText));
						int textWidth = m_pFont[i]->GetFontPixWidth(cleanStr);
						int textHeight = m_FontInfo[i].iFontSize * m_pFont[i]->GetNumLines();
						float textPosX = centerX - ((float)textWidth / 2.f) + newFontData[i].iXOffset;
						float textPosY = centerY - ((float)textHeight / 2.f) + newFontData[i].iYOffset;
						m_pFont[i]->SetOffset(textPosX, textPosY);
					}
					else
					{
						m_pFont[i]->SetOffset((float)newFontData[i].iXOffset, (float)newFontData[i].iYOffset);
					}
				}

				if (m_FontInfo[i].bUseShadow != newFontData[i].bUseShadow)
				{
					m_FontInfo[i].bUseShadow = newFontData[i].bUseShadow;
					m_FontInfo[i].iShadowColor = newFontData[i].iShadowColor;
					m_FontInfo[i].iShadowXScale = newFontData[i].iShadowXScale;
					m_FontInfo[i].iShadowYScale = newFontData[i].iShadowYScale;
					m_FontInfo[i].iShadowXOffset = newFontData[i].iShadowXOffset;
					m_FontInfo[i].iShadowYOffset = newFontData[i].iShadowYOffset;

					if (m_FontInfo[i].bUseShadow)
					{
						m_pFont[i]->EnableDropShadow(true);
						m_pFont[i]->SetShadowVals(m_FontInfo[i].iShadowColor, m_FontInfo[i].iShadowXScale, m_FontInfo[i].iShadowYScale, m_FontInfo[i].iShadowXOffset, m_FontInfo[i].iShadowYOffset);
					}
					else
					{
						m_pFont[i]->EnableDropShadow(false);
					}
				}
				else if(m_FontInfo[i].bUseShadow)					
				{
					m_FontInfo[i].iShadowColor = newFontData[i].iShadowColor;
					m_FontInfo[i].iShadowXScale = newFontData[i].iShadowXScale;
					m_FontInfo[i].iShadowYScale = newFontData[i].iShadowYScale;
					m_FontInfo[i].iShadowXOffset = newFontData[i].iShadowXOffset;
					m_FontInfo[i].iShadowYOffset = newFontData[i].iShadowYOffset;
					m_pFont[i]->SetShadowVals(m_FontInfo[i].iShadowColor, m_FontInfo[i].iShadowXScale, m_FontInfo[i].iShadowYScale, m_FontInfo[i].iShadowXOffset, m_FontInfo[i].iShadowYOffset);
				}
				
				m_FontInfo[i].clippingRect = newFontData[i].clippingRect;
				m_FontInfo[i].bUseClippingRect = newFontData[i].bUseClippingRect;					

				m_FontInfo[i].bRender = true;
			}
			if (m_bColorChanged)
			{
				StdString colorChanged = MultiplyTextColor(m_ToolBox->GetHashString(dwNewText));
				m_pFont[i]->SetText(colorChanged);				
			}
		}

		// disable any fonts that haven't been updated
		for (UINT j=newFontData.size(); j<m_FontInfo.size(); j++)
		{
			m_FontInfo[j].bRender = false;
		}
	}

	return true;
}
Esempio n. 12
0
void MapMgr::RemoveObject(Object* obj, bool free_guid)
{
	/////////////
	// Assertions
	/////////////

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

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

	//there is a very small chance that on double player ports on same update player is added to multiple insertpools but not removed
	//one clear example was the double port proc when exploiting double resurrect
	m_objectinsertlock.Acquire();
	m_objectinsertpool.erase(obj);
	m_objectinsertlock.Release();

	_updates.erase(obj);
	obj->ClearUpdateMask();

	///////////////////////////////////////
	// Remove object from all needed places
	///////////////////////////////////////

	switch(obj->GetTypeFromGUID())
	{
		case HIGHGUID_TYPE_UNIT:
		case HIGHGUID_TYPE_VEHICLE:
			ARCEMU_ASSERT(obj->GetUIdFromGUID() <= m_CreatureHighGuid);
			CreatureStorage[ obj->GetUIdFromGUID() ] = NULL;
			if(TO_CREATURE(obj)->m_spawn != NULL)
			{
				_sqlids_creatures.erase(TO_CREATURE(obj)->m_spawn->id);
			}

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

			break;

		case HIGHGUID_TYPE_PET:
			if(pet_iterator != m_PetStorage.end() && pet_iterator->second->GetGUID() == obj->GetGUID())
				++pet_iterator;
			m_PetStorage.erase(obj->GetUIdFromGUID());
			break;

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

		case HIGHGUID_TYPE_GAMEOBJECT:
			ARCEMU_ASSERT(obj->GetUIdFromGUID() <= m_GOHighGuid);
			GOStorage[ obj->GetUIdFromGUID() ] = NULL;
			if(TO_GAMEOBJECT(obj)->m_spawn != NULL)
			{
				_sqlids_gameobjects.erase(TO_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->IsItem() || obj->IsContainer())
	{
		return;
	}

	if(obj->IsCorpse())
	{
		m_corpses.erase(TO< Corpse* >(obj));
	}

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

	if(cell != NULL)
	{
		// Remove object from cell
		cell->RemoveObject(obj);

		// Unset object's cell
		obj->SetMapCell(NULL);
	}

	Player* plObj = NULL;
	// Clear any updates pending
	if(obj->IsPlayer())
	{
		plObj = TO_PLAYER(obj);
		_processQueue.erase(plObj);
		plObj->ClearAllPendingUpdates();
	}

	obj->RemoveSelfFromInrangeSets();

	// Clear object's in-range set
	obj->ClearInRangeSet();

	// If it's a player - update his nearby cells
	if(!_shutdown && obj->IsPlayer())
	{
		// 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(TO< Player* >(obj)->GetLowGUID());
	}

	// Remove the session from our set if it is a player.
	if(obj->IsPlayer())
	{
		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())
	{
		if(this->pInstance != NULL && this->pInstance->m_persistent)
			this->pInstance->m_creatorGroup = 0;
		if(!InactiveMoveTime && !forced_expire && GetMapInfo()->type != INSTANCE_NULL)
		{
			InactiveMoveTime = UNIXTIME + (MAPMGR_INACTIVE_MOVE_TIME * 60);
			Log.Debug("MapMgr", "Instance %u is now idle. (%s)", m_instanceID, GetBaseMap()->GetName());
		}
	}
}
Esempio n. 13
0
void MapMgr::PushObject(Object* obj)
{
	/////////////
	// Assertions
	/////////////
	ARCEMU_ASSERT(obj != NULL);

	// That object types are not map objects. TODO: add AI groups here?
	if(obj->IsItem() || obj->IsContainer())
	{
		// mark object as updatable and exit
		return;
	}

	if(obj->IsCorpse())
	{
		m_corpses.insert(TO< Corpse* >(obj));
	}

	obj->ClearInRangeSet();

	ARCEMU_ASSERT(obj->GetMapId() == _mapId);
	if(!(obj->GetPositionX() < _maxX && obj->GetPositionX() > _minX) ||
	        !(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY))
	{
		if(obj->IsPlayer())
		{
			Player* plr = TO< 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.");
				plr->SendTeleportAckMsg(plr->GetPosition());
			}
		}
		else
		{
			obj->GetPositionV()->ChangeCoords(0, 0, 0, 0);
		}
	}

	ARCEMU_ASSERT(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY);
	ARCEMU_ASSERT(_cells != NULL);

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

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

	if(x >= _sizeX || y >= _sizeY)
	{
		if(obj->IsPlayer())
		{
			Player* plr = TO< 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.");
				plr->SendTeleportAckMsg(plr->GetPosition());
			}
		}
		else
		{
			obj->GetPositionV()->ChangeCoords(0, 0, 0, 0);
		}

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

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

	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->IsPlayer())
		plObj = TO< Player* >(obj);
	else
		plObj = NULL;

	if(plObj != NULL)
	{
		LOG_DETAIL("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 != NULL)
	{
		m_PlayerStorage[plObj->GetLowGUID()] = plObj;
		UpdateCellActivity(x, y, 2);
	}
	else
	{
		switch(obj->GetTypeFromGUID())
		{
			case HIGHGUID_TYPE_PET:
				m_PetStorage[obj->GetUIdFromGUID()] = TO< Pet* >(obj);
				break;

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

			case HIGHGUID_TYPE_GAMEOBJECT:
				{
					GOStorage[ obj->GetUIdFromGUID() ] = TO< GameObject* >(obj);
					if(TO_GAMEOBJECT(obj)->m_spawn != NULL)
					{
						_sqlids_gameobjects.insert(make_pair(TO_GAMEOBJECT(obj)->m_spawn->id, TO_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 != NULL)
	{
		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())
		{
			uint32 globalcount = 0;
			if(!buf)
				buf = new ByteBuffer(300);

			for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr)
			{
				count = (*itr)->BuildCreateUpdateBlockForPlayer(buf, plObj);
				globalcount += count;
			}
			//VLack: It seems if we use the same buffer then it is a BAD idea to try and push created data one by one, add them at once!
			//       If you try to add them one by one, then as the buffer already contains data, they'll end up repeating some object.
			//       Like 6 object updates for Deeprun Tram, but the built package will contain these entries: 2AFD0, 2AFD0, 2AFD1, 2AFD0, 2AFD1, 2AFD2
			if(globalcount > 0) plObj->PushCreationData(buf, globalcount);
		}
	}

	if(buf)
		delete buf;

	if(plObj != NULL && InactiveMoveTime && !forced_expire)
		InactiveMoveTime = 0;
}
void CBase::Update(float fElapsedTime)
{
	SetPosX( GetPosX() + GetVelX() * fElapsedTime );
	SetPosY( GetPosY() + GetVelY() * fElapsedTime );
}
Esempio n. 15
0
cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
	: super(etPlayer, 0.6, 1.8)
	, m_bVisible(true)
	, m_FoodLevel(MAX_FOOD_LEVEL)
	, m_FoodSaturationLevel(5)
	, m_FoodTickTimer(0)
	, m_FoodExhaustionLevel(0)
	, m_FoodPoisonedTicksRemaining(0)
	, m_LastJumpHeight(0)
	, m_LastGroundHeight(0)
	, m_bTouchGround(false)
	, m_Stance(0.0)
	, m_Inventory(*this)
	, m_CurrentWindow(NULL)
	, m_InventoryWindow(NULL)
	, m_Color('-')
	, m_GameMode(eGameMode_NotSet)
	, m_IP("")
	, m_ClientHandle(a_Client)
	, m_NormalMaxSpeed(1.0)
	, m_SprintingMaxSpeed(1.3)
	, m_FlyingMaxSpeed(1.0)
	, m_IsCrouched(false)
	, m_IsSprinting(false)
	, m_IsFlying(false)
	, m_IsSwimming(false)
	, m_IsSubmerged(false)
	, m_IsFishing(false)
	, m_CanFly(false)
	, m_EatingFinishTick(-1)
	, m_LifetimeTotalXp(0)
	, m_CurrentXp(0)
	, m_bDirtyExperience(false)
	, m_IsChargingBow(false)
	, m_BowCharge(0)
	, m_FloaterID(-1)
	, m_Team(NULL)
{
	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_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;

	if (m_GameMode == gmNotSet)
	{
		cWorld * World = cRoot::Get()->GetWorld(GetLoadedWorldName());
		if (World == NULL)
		{
			World = cRoot::Get()->GetDefaultWorld();
		}
		if (World->IsGameModeCreative())
		{
			m_CanFly = true;
		}
	}
	
	cRoot::Get()->GetServer()->PlayerCreated(this);
}
Esempio n. 16
0
void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{
	//We need to keep updating the clients when there is movement or if there was a change in speed and after 2 ticks
	if( (m_Speed.SqrLength() > 0.0004f || m_bDirtySpeed) && (m_World->GetWorldAge() - m_TimeLastSpeedPacket >= 2))
	{
		m_World->BroadcastEntityVelocity(*this,a_Exclude);
		m_bDirtySpeed = false;
		m_TimeLastSpeedPacket = m_World->GetWorldAge();
	}

	//Have to process position related packets this every two ticks
	if (m_World->GetWorldAge() % 2 == 0)
	{
		int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0));
		int DiffY = (int) (floor(GetPosY() * 32.0) - floor(m_LastPosY * 32.0));
		int DiffZ = (int) (floor(GetPosZ() * 32.0) - floor(m_LastPosZ * 32.0));
		Int64 DiffTeleportPacket = m_World->GetWorldAge() - m_TimeLastTeleportPacket;
		// 4 blocks is max Relative So if the Diff is greater than 127 or. Send an absolute position every 20 seconds
		if (DiffTeleportPacket >= 400 || 
			((DiffX > 127) || (DiffX < -128) ||
			(DiffY > 127) || (DiffY < -128) ||
			(DiffZ > 127) || (DiffZ < -128)))
		{
			//
			m_World->BroadcastTeleportEntity(*this,a_Exclude);
			m_TimeLastTeleportPacket = m_World->GetWorldAge();
			m_TimeLastMoveReltPacket = m_TimeLastTeleportPacket; //Must synchronize.
			m_LastPosX = GetPosX();
			m_LastPosY = GetPosY();
			m_LastPosZ = GetPosZ();
			m_bDirtyPosition = false;
			m_bDirtyOrientation = false;
		}
		else
		{
			Int64 DiffMoveRelPacket = m_World->GetWorldAge() - m_TimeLastMoveReltPacket;
			//if the change is big enough.
			if ((abs(DiffX) >= 4 || abs(DiffY) >= 4 || abs(DiffZ) >= 4 || DiffMoveRelPacket >= 60) && m_bDirtyPosition)
			{
				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);
				}
				m_LastPosX = GetPosX();
				m_LastPosY = GetPosY();
				m_LastPosZ = GetPosZ();
				m_bDirtyPosition = false;
				m_TimeLastMoveReltPacket = m_World->GetWorldAge();
			}
			else
			{
				if (m_bDirtyOrientation)
				{
					m_World->BroadcastEntityLook(*this,a_Exclude);
					m_bDirtyOrientation = false;
				}
			}		
		}
		if (m_bDirtyHead)
		{
			m_World->BroadcastEntityHeadLook(*this,a_Exclude);
			m_bDirtyHead = false;
		}
	}
}
Esempio n. 17
0
void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
	if (IsDestroyed())  // Mainly to stop detector rails triggering again after minecart is dead
	{
		return;
	}

	int PosY = POSY_TOINT;
	if ((PosY <= 0) || (PosY >= cChunkDef::Height))
	{
		// Outside the world, just process normal falling physics
		super::HandlePhysics(a_Dt, a_Chunk);
		BroadcastMovementUpdate();
		return;
	}
	
	int RelPosX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
	int RelPosZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
	cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
	if (Chunk == nullptr)
	{
		// Inside an unloaded chunk, bail out all processing
		return;
	}

	BLOCKTYPE InsideType;
	NIBBLETYPE InsideMeta;
	Chunk->GetBlockTypeMeta(RelPosX, PosY, RelPosZ, InsideType, InsideMeta);

	if (!IsBlockRail(InsideType))
	{
		// When a descending minecart hits a flat rail, it goes through the ground; check for this
		Chunk->GetBlockTypeMeta(RelPosX, PosY + 1, RelPosZ, InsideType, InsideMeta);
		if (IsBlockRail(InsideType))
		{
			// Push cart upwards
			AddPosY(1);
		}
	}

	bool WasDetectorRail = false;
	if (IsBlockRail(InsideType))
	{
		if (InsideType == E_BLOCK_RAIL)
		{
			SnapToRail(InsideMeta);
		}
		else
		{
			SnapToRail(InsideMeta & 0x07);
		}

		switch (InsideType)
		{
			case E_BLOCK_RAIL: HandleRailPhysics(InsideMeta, a_Dt); break;
			case E_BLOCK_ACTIVATOR_RAIL: break;
			case E_BLOCK_POWERED_RAIL: HandlePoweredRailPhysics(InsideMeta); break;
			case E_BLOCK_DETECTOR_RAIL:
			{
				HandleDetectorRailPhysics(InsideMeta, a_Dt);
				WasDetectorRail = true;
				break;
			}
			default: VERIFY(!"Unhandled rail type despite checking if block was rail!"); break;
		}

		AddPosition(GetSpeed() * (a_Dt / 1000));  // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp
	}
	else
	{
		// Not on rail, default physics
		SetPosY(floor(GetPosY()) + 0.35);  // HandlePhysics overrides this if minecart can fall, else, it is to stop ground clipping minecart bottom when off-rail
		super::HandlePhysics(a_Dt, *Chunk);
	}

	if (m_bIsOnDetectorRail && !Vector3i(POSX_TOINT, POSY_TOINT, POSZ_TOINT).Equals(m_DetectorRailPosition))
	{
		m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07);
		m_bIsOnDetectorRail = false;
	}
	else if (WasDetectorRail)
	{
		m_bIsOnDetectorRail = true;
		m_DetectorRailPosition = Vector3i(POSX_TOINT, POSY_TOINT, POSZ_TOINT);
	}
	
	// Broadcast positioning changes to client
	BroadcastMovementUpdate();
}
Esempio n. 18
0
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
	// 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());
	int BlockX = (int) floor(NextPos.x);
	int BlockY = (int) floor(NextPos.y);
	int BlockZ = (int) floor(NextPos.z);
	
	if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
	{
		// Outside of the world

		cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
		// See if we can commit our changes. If not, we will discard them.
		if (NextChunk != NULL)
		{
			SetSpeed(NextSpeed);
			NextPos += (NextSpeed * a_Dt);
			SetPosition(NextPos);
		}
		return;
	}
	
	// Make sure we got the correct chunk and a valid one. No one ever knows...
	cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
	if (NextChunk != NULL)
	{
		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 (!g_BlockIsSolid[BlockIn])  // Making sure we are not inside a solid block
		{
			if (m_bOnGround)  // check if it's still on the ground
			{
				if (!g_BlockIsSolid[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 (int 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 (!g_BlockIsSolid[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;

			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 (IsBlockRail(BlockBelow) && IsMinecart())  // Rails aren't solid, except for Minecarts
			{
				fallspeed = 0;
				m_bOnGround = true;
			}
			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
		{
			if (IsMinecart())
			{
				if (!IsBlockRail(BlockBelow))
				{
					// Friction if minecart is off track, otherwise, Minecart.cpp handles this
					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;
						}
					}
				}
			}
			else
			{
				// Friction for non-minecarts
				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() );
			int Ret = Tracer.Trace( NextPos, NextSpeed, 2 );
			if( Ret ) // Oh noez! we hit something
			{
				// Set to hit position
				if( (Tracer.RealHit - NextPos).SqrLength() <= ( NextSpeed * a_Dt ).SqrLength() )
				{
					if( Ret == 1 )
					{
						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 > 0 ) // means on ground
						{
							m_bOnGround = true;
						}
					}
					NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z);
					NextPos.x += Tracer.HitNormal.x * 0.3f;
					NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot
					NextPos.z += Tracer.HitNormal.z * 0.3f;
				}
				else
				{
					NextPos += (NextSpeed * a_Dt);
				}
			}
			else
			{
				// We didn't hit anything, so move =]
				NextPos += (NextSpeed * a_Dt);
			}
		}
		BlockX = (int) floor(NextPos.x);
		BlockZ = (int) floor(NextPos.z);
		NextChunk = NextChunk->GetNeighborChunk(BlockX,BlockZ);
		// See if we can commit our changes. If not, we will discard them.
		if (NextChunk != NULL)
		{
			if (NextPos.x != GetPosX()) SetPosX(NextPos.x);
			if (NextPos.y != GetPosY()) SetPosY(NextPos.y);
			if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z);
			if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x);
			if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y);
			if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z);
		}
	}
}
Esempio n. 19
0
void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
{
	/*
	NOTE: Please bear in mind that taking away from negatives make them even more negative,
	adding to negatives make them positive, etc.
	*/
	
	switch (a_RailMeta)
	{
		case E_META_RAIL_ZM_ZP:  // NORTHSOUTH
		{
			SetYaw(270);
			SetPosY(floor(GetPosY()) + 0.55);
			SetSpeedY(0);  // Don't move vertically as on ground
			SetSpeedX(0);  // Correct diagonal movement from curved rails

			// Execute both the entity and block collision checks
			bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
			if (EntCol || BlckCol)
			{
				return;
			}
			
			if (GetSpeedZ() != NO_SPEED)  // Don't do anything if cart is stationary
			{
				if (GetSpeedZ() > 0)
				{
					// Going SOUTH, slow down
					AddSpeedZ(-0.1);
				}
				else
				{
					// Going NORTH, slow down
					AddSpeedZ(0.1);
				}
			}
			break;
		}
		case E_META_RAIL_XM_XP:  // EASTWEST
		{
			SetYaw(180);
			SetPosY(floor(GetPosY()) + 0.55);
			SetSpeedY(NO_SPEED);
			SetSpeedZ(NO_SPEED);

			bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
			if (EntCol || BlckCol)
			{
				return;
			}

			if (GetSpeedX() != NO_SPEED)
			{
				if (GetSpeedX() > 0)
				{
					AddSpeedX(-0.1);
				}
				else
				{
					AddSpeedX(0.1);
				}
			}
			break;
		}
		case E_META_RAIL_ASCEND_ZM:  // ASCEND NORTH
		{
			SetYaw(270);
			SetSpeedX(0);

			if (GetSpeedZ() >= 0)
			{
				// SpeedZ POSITIVE, going SOUTH
				if (GetSpeedZ() <= MAX_SPEED)  // Speed limit
				{
					AddSpeedZ(0.5);  // Speed up
					SetSpeedY(-GetSpeedZ());  // Downward movement is negative (0 minus positive numbers is negative)
				}
			}
			else
			{
				// SpeedZ NEGATIVE, going NORTH
				AddSpeedZ(1);  // Slow down
				SetSpeedY(-GetSpeedZ());  // Upward movement is positive (0 minus negative number is positive number)
			}
			break;
		}
		case E_META_RAIL_ASCEND_ZP:  // ASCEND SOUTH
		{
			SetYaw(270);
			SetSpeedX(0);

			if (GetSpeedZ() > 0)
			{
				// SpeedZ POSITIVE, going SOUTH
				AddSpeedZ(-1);  // Slow down
				SetSpeedY(GetSpeedZ());  // Upward movement positive
			}
			else
			{
				if (GetSpeedZ() >= MAX_SPEED_NEGATIVE)  // Speed limit
				{
					// SpeedZ NEGATIVE, going NORTH
					AddSpeedZ(-0.5);  // Speed up
					SetSpeedY(GetSpeedZ());  // Downward movement negative
				}
			}
			break;
		}
		case E_META_RAIL_ASCEND_XM:  // ASCEND EAST
		{
			SetYaw(180);
			SetSpeedZ(NO_SPEED);

			if (GetSpeedX() >= NO_SPEED)
			{
				if (GetSpeedX() <= MAX_SPEED)
				{
					AddSpeedX(0.5);
					SetSpeedY(-GetSpeedX());
				}
			}
			else
			{
				AddSpeedX(1);
				SetSpeedY(-GetSpeedX());
			}
			break;
		}
		case E_META_RAIL_ASCEND_XP:  // ASCEND WEST
		{
			SetYaw(180);
			SetSpeedZ(0);

			if (GetSpeedX() > 0)
			{
				AddSpeedX(-1);
				SetSpeedY(GetSpeedX());
			}
			else
			{
				if (GetSpeedX() >= MAX_SPEED_NEGATIVE)
				{
					AddSpeedX(-0.5);
					SetSpeedY(GetSpeedX());
				}
			}
			break;
		}
		case E_META_RAIL_CURVED_ZM_XM:  // Ends pointing NORTH and WEST
		{
			SetYaw(315);  // Set correct rotation server side
			SetPosY(floor(GetPosY()) + 0.55);  // Levitate dat cart
			SetSpeedY(0);

			TestBlockCollision(a_RailMeta);
			TestEntityCollision(a_RailMeta);

			// SnapToRail handles turning

			break;
		}
		case E_META_RAIL_CURVED_ZM_XP:  // Curved NORTH EAST
		{
			SetYaw(225);
			SetPosY(floor(GetPosY()) + 0.55);
			SetSpeedY(0);

			TestBlockCollision(a_RailMeta);
			TestEntityCollision(a_RailMeta);

			break;
		}
		case E_META_RAIL_CURVED_ZP_XM:  // Curved SOUTH WEST
		{
			SetYaw(135);
			SetPosY(floor(GetPosY()) + 0.55);
			SetSpeedY(0);

			TestBlockCollision(a_RailMeta);
			TestEntityCollision(a_RailMeta);

			break;
		}
		case E_META_RAIL_CURVED_ZP_XP:  // Curved SOUTH EAST
		{
			SetYaw(45);
			SetPosY(floor(GetPosY()) + 0.55);
			SetSpeedY(0);

			TestBlockCollision(a_RailMeta);
			TestEntityCollision(a_RailMeta);

			break;
		}
		default:
		{
			ASSERT(!"Unhandled rail meta!");  // Dun dun DUN!
			break;
		}
	}
}
Esempio n. 20
0
void cEntity::TickBurning(cChunk & a_Chunk)
{
	// Remember the current burning state:
	bool HasBeenBurning = (m_TicksLeftBurning > 0);
	
	// Do the burning damage:
	if (m_TicksLeftBurning > 0)
	{
		m_TicksSinceLastBurnDamage++;
		if (m_TicksSinceLastBurnDamage >= BURN_TICKS_PER_DAMAGE)
		{
			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, (int)floor(GetPosY())));
	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;
			cChunk * CurChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelX, RelZ);
			if (CurChunk == NULL)
			{
				continue;
			}
			for (int y = MinY; y <= MaxY; y++)
			{
				switch (CurChunk->GetBlock(RelX, y, RelZ))
				{
					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)
		{
			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)
		{
			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();
	}
}
Esempio n. 21
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;
}
void CBulletPaper::Render(void)
{
	static RECT r = {615,32,624,42};
	CSGD_TextureManager *pTM = CSGD_TextureManager::GetInstance();
	pTM->Draw(GetImageID(),GetPosX(),GetPosY(),2.0f,2.0f,&r,GetWidth() / 2, GetHeight() /2,GetRotation(),D3DCOLOR_XRGB(255,255,255));
}
Esempio n. 23
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 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 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 != NULL) && (!IsBaby()))
	{
		m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward);
	}
	m_DestroyTimer = 0;
}
Esempio n. 24
0
void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
{
	// GetWorld()->BroadcastTeleportEntity(*this);  // Test position
	
	int BlockX = POSX_TOINT;
	int BlockY = (int)(GetPosY() - 0.5);
	int BlockZ = POSZ_TOINT;
	
	if (BlockY < 0)
	{
		// Fallen out of this world, just continue falling until out of sight, then destroy:
		if (BlockY < VOID_BOUNDARY)
		{
			Destroy(true);
		}
		return;
	}
	
	if (BlockY >= cChunkDef::Height)
	{
		// Above the world, just wait for it to fall back down
		return;
	}
	
	int idx = a_Chunk.MakeIndexNoCheck(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
	BLOCKTYPE BlockBelow = a_Chunk.GetBlock(idx);
	NIBBLETYPE BelowMeta = a_Chunk.GetMeta(idx);
	if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta))
	{
		// Fallen onto a block that breaks this into pickups (e. g. half-slab)
		// Must finish the fall with coords one below the block:
		cSandSimulator::FinishFalling(m_World, BlockX, BlockY, BlockZ, m_BlockType, m_BlockMeta);
		Destroy(true);
		return;
	}
	else if (!cSandSimulator::CanContinueFallThrough(BlockBelow))
	{
		// Fallen onto a solid block
		/*
		LOGD(
			"Sand: Checked below at {%d, %d, %d} (rel {%d, %d, %d}), it's %s, finishing the fall.",
			BlockX, BlockY, BlockZ,
			BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width,
			ItemTypeToString(BlockBelow).c_str()
		);
		*/

		cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta);
		Destroy(true);
		return;
	}
	
	float MilliDt = a_Dt * 0.001f;
	AddSpeedY(MilliDt * -9.8f);
	AddPosition(GetSpeed() * MilliDt);

	// If not static (One billionth precision) broadcast movement.
	static const float epsilon = 0.000000001;
	if ((fabs(GetSpeedX()) > epsilon) || (fabs(GetSpeedZ()) > epsilon))
	{
		BroadcastMovementUpdate();
	}
}