Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
FIXED: PvP checks reworked a bit, shamans' fire elemental should not …
…attack unflagged units now

FIXED: Pets will be properly renamable now without messing up their PvP status
FIXED: Summoned guardians will get their owner set before pushing on the world now
ADDED: .npc info will now display whether a creature is owned by a player
  • Loading branch information
dfighter1985 committed Aug 20, 2009
1 parent 3619173 commit d25b63b
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 212 deletions.
11 changes: 1 addition & 10 deletions src/arcemu-world/AIInterface.cpp
Expand Up @@ -4281,12 +4281,7 @@ void AIInterface::Event_Summon_EE_totem(uint32 summon_duration)
static_cast< Creature* >(ourslave)->SetOwner( caster );

ourslave->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED | UNIT_FLAG_SELF_RES);

/*
- Earth Stun (37982)
- taunt
*/
}
}
}

//we only cast once a spell and we will set his health and resistances. Note that this can be made with db too !
Expand Down Expand Up @@ -4316,10 +4311,6 @@ void AIInterface::Event_Summon_FE_totem(uint32 summon_duration)
static_cast< Creature* >(ourslave)->SetOwner( caster );

ourslave->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED | UNIT_FLAG_SELF_RES);
/*
- also : select * from dbc_spell where name like "%fire blast%"
- also : select * from dbc_spell where name like "%fire nova"
*/
}
}
/*
Expand Down
4 changes: 4 additions & 0 deletions src/arcemu-world/Level3.cpp
Expand Up @@ -771,6 +771,10 @@ bool ChatHandler::HandleNpcInfoCommand(const char *args, WorldSession *m_session
sstext << "UNIT_FIELD_BYTES_2 are " << uint16((uint8)theBytes & 0xFF) << " " << uint16((uint8)(theBytes >> 8) & 0xFF) << " ";
sstext << uint16((uint8)(theBytes >> 16) & 0xFF) << " " << uint16((uint8)(theBytes >> 24) & 0xFF) << '\0';
SendMultilineMessage( m_session, sstext.str().c_str() );

if( crt->GetOwner() && crt->GetOwner()->IsPlayer() )
SystemMessage(m_session, "Owner: %s", "player" );

return true;
}

Expand Down
117 changes: 64 additions & 53 deletions src/arcemu-world/NPCHandler.cpp
Expand Up @@ -181,20 +181,37 @@ void WorldSession::SendTrainerList(Creature* pCreature)
SendPacket(&data);
}


void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvPacket)
{
if(!_player->IsInWorld()) return;

////////////////////////////////////////////////////////////////////////////////
// As of 3.1.3 the client sends this when buying a spell
//
// {CLIENT} Packet: (0x01B2) CMSG_TRAINER_BUY_SPELL PacketSize = 12 TimeStamp = 39035859
// A0 85 00 06 7A 00 30 F1 2D 85 00 00
//
// Structure:
// uint64 GUID - GUID of the trainer
// uint32 spellid - ID of the spell being bought
////////////////////////////////////////////////////////////////////////////////

uint64 Guid;
uint32 TeachingSpellID;

recvPacket >> Guid >> TeachingSpellID;
Creature *pCreature = _player->GetMapMgr()->GetCreature(GET_LOWGUID_PART(Guid));
if(pCreature == 0) return;

/////////////////////////////////////////// Checks //////////////////////////////////////

if(pCreature == NULL) return;

Trainer *pTrainer = pCreature->GetTrainer();
if(pTrainer == 0 || !CanTrainAt(_player, pTrainer)) return;
if(pTrainer == NULL || !CanTrainAt(_player, pTrainer)) return;

TrainerSpell * pSpell=NULL;
// Check if the trainer offers that spell
TrainerSpell * pSpell = NULL;
for(vector<TrainerSpell>::iterator itr = pTrainer->Spells.begin(); itr != pTrainer->Spells.end(); ++itr)
{
if( ( itr->pCastSpell && itr->pCastSpell->Id == TeachingSpellID ) ||
Expand All @@ -204,68 +221,44 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvPacket)
}
}

if(pSpell == NULL)
// If the trainer doesn't offer it, this is probably some packet mangling
if(pSpell == NULL){
// Disconnecting the player
this->Disconnect();
return;
}

// We can't learn it
if(TrainerGetSpellStatus(pSpell) > 0)
return;

if(TrainerGetSpellStatus(pSpell) > 0) return;
//////////////////////////////////////////// Teaching ////////////////////////////////////

_player->ModUnsigned32Value(PLAYER_FIELD_COINAGE, -(int32)pSpell->Cost);

if( pSpell->pCastSpell)
{
// Cast teaching spell on player
pCreature->CastTrainerSpell(_player, pSpell->pCastSpell, true);
}

if( pSpell->pLearnSpell )
_player->CastSpell( _player, pSpell->pCastSpell->Id, true );
}
else
{
packetSMSG_PLAY_SPELL_VISUAL pck;
pck.guid = pCreature->GetGUID();
pck.visualid = 0x5b3;
_player->OutPacketToSet( SMSG_PLAY_SPELL_VISUAL, sizeof(packetSMSG_PLAY_SPELL_VISUAL), &pck, true );
/////////////////////////////////////// Showing the learning spellvisuals//////////////
packetSMSG_PLAY_SPELL_VISUAL pck;

pck.guid = _player->GetGUID();
pck.visualid = 0x16a;
_player->OutPacketToSet( 0x1F7, sizeof(packetSMSG_PLAY_SPELL_VISUAL), &pck, true );
pck.guid = pCreature->GetGUID();
pck.visualid = 0x5b3;

// add the spell
_player->addSpell( pSpell->pLearnSpell->Id );
_player->OutPacketToSet( SMSG_PLAY_SPELL_VISUAL, sizeof(packetSMSG_PLAY_SPELL_VISUAL), &pck, true );

uint32 i;
for( i = 0; i < 3; ++i )
{
if( pSpell->pLearnSpell->Effect[i] == SPELL_EFFECT_PROFICIENCY || pSpell->pLearnSpell->Effect[i] == SPELL_EFFECT_WEAPON ||
( pSpell->pLearnSpell->Effect[i] == SPELL_EFFECT_LEARN_SPELL && pSpell->pLearnSpell->EffectImplicitTargetA[i] != EFF_TARGET_PET ) ) // avoid direct pet teaching
{
_player->CastSpell( _player, pSpell->pLearnSpell, true );
break;
}
}
pck.guid = _player->GetGUID();
pck.visualid = 0x16a;

for( i = 0; i < 3; ++i)
{
if( pSpell->pLearnSpell->Effect[i] == SPELL_EFFECT_SKILL )
{
uint32 skill = pSpell->pLearnSpell->EffectMiscValue[i];
uint32 val = (pSpell->pLearnSpell->EffectBasePoints[i]+1) * 75;
if( val > 375 )
val = 375;

if( _player->_GetSkillLineMax(skill) > val ) // cebernic: eq
continue;

if( skill == SKILL_RIDING )
_player->_AddSkillLine( skill, val, val );
else
{
if( _player->_HasSkillLine(skill) )
_player->_ModifySkillMaximum(skill, val);
else
_player->_AddSkillLine( skill, 1, val);
}
}
}
}
_player->OutPacketToSet( SMSG_PLAY_SPELL_IMPACT, sizeof(packetSMSG_PLAY_SPELL_VISUAL), &pck, true );
///////////////////////////////////////////////////////////////////////////////////////

// add the spell itself
_player->addSpell( pSpell->pLearnSpell->Id );
}

if(pSpell->DeleteSpell)
{
Expand All @@ -279,6 +272,24 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvPacket)
}

_player->_UpdateSkillFields();

/////////////////////////////////////////////////////////////////////////////////
// As of 3.1.3 this is sent after buying the spell
//
//
// {SERVER} Packet: (0x01B3) SMSG_TRAINER_BUY_SUCCEEDED PacketSize = 12 TimeStamp = 39035968
// A0 85 00 06 7A 00 30 F1 2D 85 00 00
//
// structure:
//
// uint64 GUID - GUID of the trainer
// uint32 spellid - ID of the spell we bought
//////////////////////////////////////////////////////////////////////////////////

WorldPacket data( SMSG_TRAINER_BUY_SUCCEEDED, 12 );

data << uint64( Guid ) << uint32( TeachingSpellID );
this->SendPacket( &data );
}

uint8 WorldSession::TrainerGetSpellStatus(TrainerSpell* pSpell)
Expand Down
64 changes: 14 additions & 50 deletions src/arcemu-world/Object.cpp
Expand Up @@ -1964,62 +1964,25 @@ void Object::DealDamage(Unit *pVictim, uint32 damage, uint32 targetEvent, uint32

/////////////////////////////////////////////////////// PvP flagging on attack ///////////////////////////////////////////////
{
Player *pOwner = NULL; // Player we are attacking, or the owner of totem/pet/etc
Player *pAttacker = NULL; // This is the player or the player controlling the totem/pet/summon
// Player we are attacking, or the owner of totem/pet/etc
Player *pOwner = GetPlayerOwner( static_cast< Object* >( pVictim ) );

if( pVictim->IsPlayer() ){
pOwner = static_cast< Player* >( pVictim );
}
else
if( pVictim->IsPet() ){
pOwner = static_cast< Pet* >( pVictim )->GetPetOwner();
}
else
if( pVictim->IsCreature() && static_cast< Creature* >( pVictim )->IsTotem() ){
pOwner = static_cast< Creature* >( pVictim )->GetTotemOwner();
}
else
if( pVictim->IsCreature() && static_cast< Creature* >( pVictim )->GetOwner() != NULL && static_cast< Creature* >( pVictim )->GetOwner()->IsPlayer() ){
pOwner = static_cast< Player* >( static_cast< Creature* >( pVictim )->GetOwner() );
}




if( this->IsPlayer() ){
pAttacker = static_cast< Player* >( this );
}
else
if( this->IsPet() ){
pAttacker = static_cast< Pet* >( this )->GetPetOwner();
// This is the player or the player controlling the totem/pet/summon
Player *pAttacker = GetPlayerOwner( this );

// Pet must have an owner
assert( pAttacker != NULL );
}
else // Player totem
if( this->IsCreature() && static_cast< Creature* >( this )->IsTotem() ){
pAttacker = static_cast< Creature* >( this )->GetTotemOwner();

// Totem must have an owner
assert( pAttacker != NULL );

}
else // Player summon
if( this->IsCreature() && static_cast< Creature* >( this )->GetOwner() != NULL && static_cast< Creature* >( this )->GetOwner()->IsPlayer() ){
pAttacker = static_cast< Player*>( static_cast< Creature* >( this )->GetOwner() );
}

// We identified both the attacker and the victim as possible PvP combatants, if we are not dueling we will flag the attacker
if( pOwner != NULL && pAttacker != NULL ){
if( pOwner != pAttacker->DuelingWith ){
pAttacker->SetPvPFlag();
pAttacker->AggroPvPGuards();
}
if( pOwner != NULL && pAttacker != NULL && pOwner != pAttacker->DuelingWith ){
if( !pAttacker->IsPvPFlagged() ){
pAttacker->PvPToggle();
}
pAttacker->AggroPvPGuards();
}

// PvP NPCs
// PvP NPCs will flag the player when attacking them
if( pVictim->IsCreature() && pVictim->IsPvPFlagged() && pAttacker != NULL ){
pAttacker->SetPvPFlag();
if( !pAttacker->IsPvPFlagged() ){
pAttacker->PvPToggle();
}
pAttacker->AggroPvPGuards();
}

Expand Down Expand Up @@ -2533,6 +2496,7 @@ void Object::DealDamage(Unit *pVictim, uint32 damage, uint32 targetEvent, uint32

if( this->IsUnit() )
{
pVictim->RemoveAllAuras();
CALL_SCRIPT_EVENT( this, OnTargetDied )( pVictim );
static_cast< Unit* >( this )->smsg_AttackStop( pVictim );

Expand Down
10 changes: 8 additions & 2 deletions src/arcemu-world/Pet.cpp
Expand Up @@ -214,11 +214,17 @@ void Pet::CreateAsSummon( uint32 entry, CreatureInfo *ci, Creature* created_from
SetUInt32Value( UNIT_FIELD_PETNEXTLEVELEXP, GetNextLevelXP( level ) );
SetUInt32Value( UNIT_FIELD_POWER3, 100 );// Focus
SetUInt32Value( UNIT_FIELD_MAXPOWER3, 100 );
SetUInt32Value( UNIT_FIELD_BYTES_2, 1 | (0x28 << 8) | (0x3 << 16) );// 0x3 -> Enable pet rename.
SetUInt32Value( UNIT_FIELD_BYTES_2, 1 /* | (0x28 << 8) */ | (0x3 << 16) );// 0x3 -> Enable pet rename.
SetPowerType( POWER_TYPE_FOCUS);
}
SetUInt32Value( UNIT_FIELD_FACTIONTEMPLATE, owner->GetUInt32Value( UNIT_FIELD_FACTIONTEMPLATE ) );

BaseDamage[0] = 0;
if( owner->IsPvPFlagged() )
this->SetPvPFlag();
else
this->RemovePvPFlag();

BaseDamage[0] = 0;
BaseDamage[1] = 0;
BaseOffhandDamage[0] = 0;
BaseOffhandDamage[1] = 0;
Expand Down
9 changes: 8 additions & 1 deletion src/arcemu-world/PetHandler.cpp
Expand Up @@ -444,7 +444,14 @@ void WorldSession::HandlePetRename(WorldPacket & recv_data)
pet->Rename(name);

// Disable pet rename.
pet->SetUInt32Value(UNIT_FIELD_BYTES_2, 1 | (0x28 << 8) | (0x2 << 16));
pet->SetUInt32Value(UNIT_FIELD_BYTES_2, 1 | /* (0x28 << 8) | */ (0x2 << 16) );

assert( pet->GetPetOwner() != NULL );

if( pet->GetPetOwner()->IsPvPFlagged() )
pet->SetPvPFlag();
else
pet->RemovePvPFlag();
}

void WorldSession::HandlePetAbandon(WorldPacket & recv_data)
Expand Down
14 changes: 8 additions & 6 deletions src/arcemu-world/Player.cpp
Expand Up @@ -2146,15 +2146,11 @@ void Player::SpawnPet( uint32 pet_number )
Pet *pPet = objmgr.CreatePet( itr->second->entry );
pPet->LoadFromDB( this, itr->second );

// For some awesomely weird reason they get 41 as bytes2, this keeps me from flagging them - dfighter
// dfighter hacks
pPet->SetUInt32Value( UNIT_FIELD_BYTES_2, 0 );

if( this->IsPvPFlagged() )
pPet->SetPvPFlag();
else
pPet->RemovePvPFlag();
////////////////////////////////////////////////////////////////////////////////
pPet->SetUInt32Value( UNIT_FIELD_FACTIONTEMPLATE, this->GetUInt32Value( UNIT_FIELD_FACTIONTEMPLATE ) );

if( itr->second->spellid )
{
Expand Down Expand Up @@ -4852,7 +4848,7 @@ void Player::ResurrectPlayer()

void Player::KillPlayer()
{
if(getDeathState() != ALIVE) //You can't kill what has no life.
if(getDeathState() != ALIVE) //You can't kill what has no life. - amg south park references ftw :P
return;
setDeathState(JUST_DIED);

Expand All @@ -4878,6 +4874,12 @@ void Player::KillPlayer()
else if( getClass() == DEATHKNIGHT )
SetPower( POWER_TYPE_RUNIC_POWER, 0 );


for( int i = 0; i < 4; ++i ){
if( m_TotemSlots[i] != NULL)
m_TotemSlots[i]->TotemExpire();
}

sHookInterface.OnDeath( this );

}
Expand Down

0 comments on commit d25b63b

Please sign in to comment.