void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { // Iterate through this entity's applied effects for (tEffectMap::iterator iter = m_EntityEffects.begin(); iter != m_EntityEffects.end();) { // Copies values to prevent pesky wrong accesses and erasures cEntityEffect::eType EffectType = iter->first; cEntityEffect * Effect = iter->second; Effect->OnTick(*this); // Iterates (must be called before any possible erasure) ++iter; // Remove effect if duration has elapsed if (Effect->GetDuration() - Effect->GetTicks() <= 0) { RemoveEntityEffect(EffectType); } // TODO: Check for discrepancies between client and server effect values } class Pusher : public cEntityCallback { public: cEntity * m_Pusher; Pusher(cEntity * a_Pusher) : m_Pusher(a_Pusher) { } virtual bool Item(cEntity * a_Entity) override { if (a_Entity->GetUniqueID() == m_Pusher->GetUniqueID()) { return false; } // we only push other mobs, boats and minecarts if ((a_Entity->GetEntityType() != etMonster) && (a_Entity->GetEntityType() != etMinecart) && (a_Entity->GetEntityType() != etBoat)) { return false; } Vector3d v3Delta = a_Entity->GetPosition() - m_Pusher->GetPosition(); v3Delta.y = 0.0; // we only push sideways v3Delta *= 1.0 / (v3Delta.Length() + 0.01); // we push harder if we're close // QUESTION: is there an additional multiplier for this? current shoving seems a bit weak a_Entity->AddSpeed(v3Delta); return false; } } Callback(this); m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), GetWidth(), GetHeight()), Callback); super::Tick(a_Dt, a_Chunk); }
cBoundingBox cBoundingBox::Union(const cBoundingBox & a_Other) { return cBoundingBox( std::min(m_Min.x, a_Other.m_Min.x), std::min(m_Min.y, a_Other.m_Min.y), std::min(m_Min.z, a_Other.m_Min.z), std::max(m_Max.x, a_Other.m_Max.x), std::max(m_Max.y, a_Other.m_Max.y), std::max(m_Max.z, a_Other.m_Max.z) ); }
bool cOcelot::IsCatSittingOnBlock(cWorld * a_World, Vector3d a_BlockPosition) { return a_World->ForEachEntityInBox( cBoundingBox(Vector3d(a_BlockPosition.x, a_BlockPosition.y + 1, a_BlockPosition.z), 1), [=](cEntity & a_Entity) { return ( (a_Entity.GetEntityType() == cEntity::etMonster) && (static_cast<cMonster &>(a_Entity).GetMobType() == eMonsterType::mtOcelot) && (static_cast<cOcelot &>(a_Entity).IsSitting()) ); } ); }
void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { std::vector<cEntityEffect *> EffectsToTick; // Iterate through this entity's applied effects for (tEffectMap::iterator iter = m_EntityEffects.begin(); iter != m_EntityEffects.end();) { // Copies values to prevent pesky wrong accesses and erasures cEntityEffect::eType EffectType = iter->first; cEntityEffect * Effect = iter->second.get(); // Iterates (must be called before any possible erasure) ++iter; // Remove effect if duration has elapsed if (Effect->GetDuration() - Effect->GetTicks() <= 0) { RemoveEntityEffect(EffectType); } // Call OnTick later to make sure the iterator won't be invalid else { EffectsToTick.push_back(Effect); } // TODO: Check for discrepancies between client and server effect values } for (auto * Effect : EffectsToTick) { Effect->OnTick(*this); } // Spectators cannot push entities around if ((!IsPlayer()) || (!static_cast<cPlayer *>(this)->IsGameModeSpectator())) { m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), GetWidth(), GetHeight()), [=](cEntity & a_Entity) { if (a_Entity.GetUniqueID() == GetUniqueID()) { return false; } // we only push other mobs, boats and minecarts if ((a_Entity.GetEntityType() != etMonster) && (a_Entity.GetEntityType() != etMinecart) && (a_Entity.GetEntityType() != etBoat)) { return false; } // do not push a boat / minecart you're sitting in if (IsAttachedTo(&a_Entity)) { return false; } Vector3d v3Delta = a_Entity.GetPosition() - GetPosition(); v3Delta.y = 0.0; // we only push sideways v3Delta *= 1.0 / (v3Delta.Length() + 0.01); // we push harder if we're close // QUESTION: is there an additional multiplier for this? current shoving seems a bit weak a_Entity.AddSpeed(v3Delta); return false; } ); } super::Tick(a_Dt, a_Chunk); if (!IsTicking()) { // The base class tick destroyed us return; } HandleFalling(); }
bool cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ); if (a_WorldInterface.GetDimension() != dimOverworld) { a_WorldInterface.DoExplosionAt(5, a_BlockX, a_BlockY, a_BlockZ, true, esBed, &Coords); } else if (!((a_WorldInterface.GetTimeOfDay() > 12541) && (a_WorldInterface.GetTimeOfDay() < 23458))) // Source: https://minecraft.gamepedia.com/Bed#Sleeping { a_Player.SendMessageFailure("You can only sleep at night"); } else { NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(Coords); if ((Meta & 0x4) == 0x4) { a_Player.SendMessageFailure("This bed is occupied"); } else { auto FindMobs = [](cEntity & a_Entity) { return ( (a_Entity.GetEntityType() == cEntity::etMonster) && (static_cast<cMonster&>(a_Entity).GetMobFamily() == cMonster::mfHostile) ); }; if (!a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(a_Player.GetPosition() - Vector3i(0, 5, 0), 8, 10), FindMobs)) { a_Player.SendMessageFailure("You may not rest now, there are monsters nearby"); } else { Vector3i PillowDirection(0, 0, 0); if ((Meta & 0x8) == 0x8) { // Is pillow a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, { a_BlockX, a_BlockY, a_BlockZ }); } else { // Is foot end VERIFY((Meta & 0x4) != 0x4); // Occupied flag should never be set, else our compilator (intended) is broken PillowDirection = MetaDataToDirection(Meta & 0x3); if (a_ChunkInterface.GetBlock(Coords + PillowDirection) == E_BLOCK_BED) // Must always use pillow location for sleeping { a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, Vector3i{ a_BlockX, a_BlockY, a_BlockZ } + PillowDirection); } } a_Player.SetBedPos(Coords); SetBedOccupationState(a_ChunkInterface, a_Player.GetLastBedPos(), true); a_Player.SetIsInBed(true); a_Player.SendMessageSuccess("Home position set successfully"); auto TimeFastForwardTester = [](cPlayer & a_OtherPlayer) { if (!a_OtherPlayer.IsInBed()) { return true; } return false; }; if (a_WorldInterface.ForEachPlayer(TimeFastForwardTester)) { a_WorldInterface.ForEachPlayer([&](cPlayer & a_OtherPlayer) { cBlockBedHandler::SetBedOccupationState(a_ChunkInterface, a_OtherPlayer.GetLastBedPos(), false); a_OtherPlayer.SetIsInBed(false); return false; } ); a_WorldInterface.SetTimeOfDay(0); a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0x0b); // Clear the "occupied" bit of the bed's block } } } } return true; }
void cPassiveMonster::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_EMState == ESCAPING) { CheckEventLostPlayer(); } // if we have a partner, mate if (m_LovePartner != nullptr) { if (m_MatingTimer > 0) { // If we should still mate, keep bumping into them until baby is made Vector3d Pos = m_LovePartner->GetPosition(); MoveToPosition(Pos); } else { // Mating finished. Spawn baby Vector3f Pos = (GetPosition() + m_LovePartner->GetPosition()) * 0.5; UInt32 BabyID = m_World->SpawnMob(Pos.x, Pos.y, Pos.z, GetMobType(), true); cPassiveMonster * Baby = nullptr; m_World->DoWithEntityByID(BabyID, [&](cEntity & a_Entity) { Baby = static_cast<cPassiveMonster *>(&a_Entity); return true; } ); if (Baby != nullptr) { Baby->InheritFromParents(this, m_LovePartner); } m_World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, GetRandomProvider().RandInt(1, 6)); m_LovePartner->ResetLoveMode(); ResetLoveMode(); } } else { // We have no partner, so we just chase the player if they have our breeding item cItems FollowedItems; GetFollowedItems(FollowedItems); if (FollowedItems.Size() > 0) { cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), static_cast<float>(m_SightDistance)); if (a_Closest_Player != nullptr) { cItem EquippedItem = a_Closest_Player->GetEquippedItem(); if (FollowedItems.ContainsType(EquippedItem)) { Vector3d PlayerPos = a_Closest_Player->GetPosition(); MoveToPosition(PlayerPos); } } } } // If we are in love mode but we have no partner, search for a partner neabry if (m_LoveTimer > 0) { if (m_LovePartner == nullptr) { m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8), [=](cEntity & a_Entity) { // If the entity is not a monster, don't breed with it // Also, do not self-breed if ((a_Entity.GetEntityType() != etMonster) || (&a_Entity == this)) { return false; } auto & Me = static_cast<cPassiveMonster&>(*this); auto & PotentialPartner = static_cast<cPassiveMonster&>(a_Entity); // If the potential partner is not of the same species, don't breed with it if (PotentialPartner.GetMobType() != Me.GetMobType()) { return false; } // If the potential partner is not in love // Or they already have a mate, do not breed with them if ((!PotentialPartner.IsInLove()) || (PotentialPartner.GetPartner() != nullptr)) { return false; } // All conditions met, let's breed! PotentialPartner.EngageLoveMode(&Me); Me.EngageLoveMode(&PotentialPartner); return true; } ); } m_LoveTimer--; } if (m_MatingTimer > 0) { m_MatingTimer--; } if (m_LoveCooldown > 0) { m_LoveCooldown--; } }