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; }; } }
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; }
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; }
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(); }
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 {
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; } } }
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(); } }
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); } }
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; }
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 } }
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; }
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; }
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; }
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; }
/** 创建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 ); }
/// 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(); }
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); }
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; }
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); } } } }
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); }
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; }
Vector3d cPlayer::GetEyePosition(void) const { return Vector3d( GetPosX(), m_Stance, GetPosZ() ); }
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; } }
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); }
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; }
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()); }
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); }