307 | | // fall damage generation (ignore in flight case that can be triggred also at lags in moment teleportation to another map). |
308 | | if (recv_data.GetOpcode() == MSG_MOVE_FALL_LAND && !GetPlayer()->isInFlight()) |
309 | | { |
310 | | Player *target = GetPlayer(); |
311 | | |
312 | | //Players with Feather Fall or low fall time, or physical immunity (charges used) are ignored |
313 | | if (movementInfo.fallTime > 1100 && !target->isDead() && !target->isGameMaster() && |
314 | | !target->HasAuraType(SPELL_AURA_HOVER) && !target->HasAuraType(SPELL_AURA_FEATHER_FALL) && |
315 | | !target->HasAuraType(SPELL_AURA_FLY) && !target->IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL,true) ) |
316 | | { |
317 | | //Safe fall, fall time reduction |
318 | | int32 safe_fall = target->GetTotalAuraModifier(SPELL_AURA_SAFE_FALL); |
319 | | uint32 fall_time = (movementInfo.fallTime > (safe_fall*10)) ? movementInfo.fallTime - (safe_fall*10) : 0; |
320 | | |
321 | | if(fall_time > 1100) //Prevent damage if fall time < 1100 |
322 | | { |
323 | | //Fall Damage calculation |
324 | | float fallperc = float(fall_time)/1100; |
325 | | uint32 damage = (uint32)(((fallperc*fallperc -1) / 9 * target->GetMaxHealth())*sWorld.getRate(RATE_DAMAGE_FALL)); |
326 | | |
327 | | float height = movementInfo.z; |
328 | | target->UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height); |
329 | | |
330 | | if (damage > 0) |
331 | | { |
332 | | //Prevent fall damage from being more than the player maximum health |
333 | | if (damage > target->GetMaxHealth()) |
334 | | damage = target->GetMaxHealth(); |
335 | | |
336 | | // Gust of Wind |
337 | | if (target->GetDummyAura(43621)) |
338 | | damage = target->GetMaxHealth()/2; |
339 | | |
340 | | target->EnvironmentalDamage(target->GetGUID(), DAMAGE_FALL, damage); |
341 | | } |
342 | | |
343 | | //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction |
344 | | DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, target->GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall); |
345 | | } |
346 | | } |
347 | | |
348 | | //handle fall and logout at the same time (logout started before fall finished) |
349 | | /* outdated and create problems with sit at stun sometime |
350 | | if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE)) |
351 | | { |
352 | | target->SetStandState(PLAYER_STATE_SIT); |
353 | | // Can't move |
354 | | WorldPacket data( SMSG_FORCE_MOVE_ROOT, 12 ); |
355 | | data.append(target->GetPackGUID()); |
356 | | data << (uint32)2; |
357 | | SendPacket( &data ); |
358 | | } |
359 | | */ |
360 | | } |
| 315 | // handle fall damage |
| 316 | if (recv_data.GetOpcode() == MSG_MOVE_FALL_LAND) |
| 317 | GetPlayer()->HandleFallDamage(movementInfo); |
384 | | { |
385 | | if(GetPlayer()->InBattleGround() |
386 | | && GetPlayer()->GetBattleGround() |
387 | | && GetPlayer()->GetBattleGround()->HandlePlayerUnderMap(_player)) |
388 | | { |
389 | | // do nothing, the handle already did if returned true |
390 | | } |
391 | | else |
392 | | { |
393 | | // NOTE: this is actually called many times while falling |
394 | | // even after the player has been teleported away |
395 | | // TODO: discard movement packets after the player is rooted |
396 | | if(GetPlayer()->isAlive()) |
397 | | { |
398 | | GetPlayer()->EnvironmentalDamage(GetPlayer()->GetGUID(),DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); |
399 | | // change the death state to CORPSE to prevent the death timer from |
400 | | // starting in the next player update |
401 | | GetPlayer()->KillPlayer(); |
402 | | GetPlayer()->BuildPlayerRepop(); |
403 | | } |
404 | | |
405 | | // cancel the death timer here if started |
406 | | GetPlayer()->RepopAtGraveyard(); |
407 | | } |
| 341 | GetPlayer()->HandleFallUnderMap(); |
| 342 | } |
| 343 | |
| 344 | void WorldSession::HandlePossessedMovement(WorldPacket& recv_data, MovementInfo& movementInfo, uint32& MovementFlags) |
| 345 | { |
| 346 | // Whatever the client is controlling, it will send the GUID of the original player. |
| 347 | // If current player is controlling, it must be handled like the controlled player sent these opcodes |
| 348 | |
| 349 | Unit* pos_unit = GetPlayer()->GetCharm(); |
| 350 | |
| 351 | if (pos_unit->GetTypeId() == TYPEID_PLAYER && ((Player*)pos_unit)->GetDontMove()) |
| 352 | return; |
| 353 | |
| 354 | //Save movement flags |
| 355 | pos_unit->SetUnitMovementFlags(MovementFlags); |
| 356 | |
| 357 | // Remove possession if possessed unit enters a transport |
| 358 | if (MovementFlags & MOVEMENTFLAG_ONTRANSPORT) |
| 359 | { |
| 360 | GetPlayer()->RemovePossess(true); |
| 361 | return; |
| 362 | } |
| 363 | |
| 364 | recv_data.put<uint32>(5, getMSTime()); |
| 365 | WorldPacket data(recv_data.GetOpcode(), pos_unit->GetPackGUID().size()+recv_data.size()); |
| 366 | data.append(pos_unit->GetPackGUID()); |
| 367 | data.append(recv_data.contents(), recv_data.size()); |
| 368 | // Send the packet to self but not to the possessed player; for creatures the first bool is irrelevant |
| 369 | pos_unit->SendMessageToSet(&data, true, false); |
| 370 | |
| 371 | // Possessed is a player |
| 372 | if (pos_unit->GetTypeId() == TYPEID_PLAYER) |
| 373 | { |
| 374 | Player* plr = (Player*)pos_unit; |
| 375 | |
| 376 | if (recv_data.GetOpcode() == MSG_MOVE_FALL_LAND) |
| 377 | plr->HandleFallDamage(movementInfo); |
| 378 | |
| 379 | if(((MovementFlags & MOVEMENTFLAG_SWIMMING) != 0) != plr->IsInWater()) |
| 380 | { |
| 381 | // Now client not include swimming flag in case jumping under water |
| 382 | plr->SetInWater( !plr->IsInWater() || plr->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z) ); |
| 383 | } |
| 384 | |
| 385 | plr->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o, false); |
| 386 | plr->m_movementInfo = movementInfo; |
| 387 | |
| 388 | if(plr->isMovingOrTurning()) |
| 389 | plr->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); |
| 390 | |
| 391 | if(movementInfo.z < -500.0f) |
| 392 | { |
| 393 | GetPlayer()->RemovePossess(false); |
| 394 | plr->HandleFallUnderMap(); |
| 395 | } |
| 396 | } |
| 397 | else // Possessed unit is a creature |
| 398 | { |
| 399 | Map* map = MapManager::Instance().GetMap(pos_unit->GetMapId(), pos_unit); |
| 400 | map->CreatureRelocation((Creature*)pos_unit, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); |