|
|
 |
 |
 |
 |
|
 |
 |
|
 |
 |
|
 |
|
 |
|
 |

01-23-2008, 01:03 PM
|
Sarnak
|
|
Join Date: Sep 2005
Posts: 34
|
|
multiple fixes to common damage and death
common damage from attack.cpp
Changes:
Moved death and other checks to the bottom to allow proper damage message generation in the case of the damage still killing the mob.
Made hits that dealt no damage to not interrupt spells.
Code:
got knocked down to 2nd post due to length
next, fixing the death struct, need to update all instances of it to my knowledge.
Code:
struct Death_Struct
{
/*000*/ int32 spawn_id;
/*004*/ int32 killer_id;
/*008*/ int32 corpseid; // was corpseid
/*012*/ int32 bindzoneid; // was type -- was attack_skill
/*016*/ int32 spell_id;
/*020*/ int32 attack_skill; //was bindzoneid -- switched by Ailia
/*024*/ int32 damage;
/*028*/ int32 unknown028;
};
now preventing the client from displaying damage message from the death packet it was sent since the server is generating the damage message instead.
Code:
void NPC::Death(Mob* other, sint32 damage, int16 spell, SkillType attack_skill) {
mlog(COMBAT__HITS, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", other->GetName(), damage, spell, attack_skill);
if (this->IsEngaged())
{
zone->DelAggroMob();
#if EQDEBUG >= 11
LogFile->write(EQEMuLog::Debug,"NPC::Death() Mobs currently Aggro %i", zone->MobsAggroCount());
#endif
}
SetHP(0);
SetPet(0);
Mob* killer = GetHateDamageTop(this);
entity_list.RemoveFromTargets(this);
if(p_depop == true)
return;
BuffFadeAll();
EQApplicationPacket* app= new EQApplicationPacket(OP_Death,sizeof(Death_Struct));
Death_Struct* d = (Death_Struct*)app->pBuffer;
d->spawn_id = GetID();
d->killer_id = other ? other->GetID() : 0;
// d->unknown12 = 1;
d->bindzoneid = 0;
d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell;
d->attack_skill = 231; // prevent client from displaying extra hit message
d->damage = damage;
app->priority = 6;
entity_list.QueueClients(other, app, false);
and again for client death
Code:
void Client::Death(Mob* other, sint32 damage, int16 spell, SkillType attack_skill)
{
if(dead)
return; //cant die more than once...
int exploss;
mlog(COMBAT__HITS, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", other->GetName(), damage, spell, attack_skill);
//
// #1: Send death packet to everyone
//
if(!spell) spell = SPELL_UNKNOWN;
SendLogoutPackets();
//make our become corpse packet, and queue to ourself before OP_Death.
EQApplicationPacket app2(OP_BecomeCorpse, sizeof(BecomeCorpse_Struct));
BecomeCorpse_Struct* bc = (BecomeCorpse_Struct*)app2.pBuffer;
bc->spawn_id = GetID();
bc->x = GetX();
bc->y = GetY();
bc->z = GetZ();
QueuePacket(&app2);
// make death packet
EQApplicationPacket app(OP_Death, sizeof(Death_Struct));
Death_Struct* d = (Death_Struct*)app.pBuffer;
d->spawn_id = GetID();
d->killer_id = other ? other->GetID() : 0;
//d->unknown12 = 1;
d->bindzoneid = m_pp.binds[0].zoneId;
d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell;
d->attack_skill = 231;
d->damage = damage;
app.priority = 6;
entity_list.QueueClients(this, &app);
|
 |
|
 |
 |
|
 |

01-23-2008, 01:04 PM
|
Sarnak
|
|
Join Date: Sep 2005
Posts: 34
|
|
Code:
void Mob::CommonDamage(Mob* attacker, sint32 &damage, const int16 spell_id, const SkillType skill_used, bool &avoidable, const sint8 buffslot, const bool iBuffTic) {
mlog(COMBAT__HITS, "Applying damage %d done by %s with skill %d and spell %d, avoidable? %s, is %sa buff tic in slot %d",
damage, attacker?attacker->GetName():"NOBODY", skill_used, spell_id, avoidable?"yes":"no", iBuffTic?"":"not ", buffslot);
if (GetInvul() || DivineAura()) {
mlog(COMBAT__DAMAGE, "Avoiding %d damage due to invulnerability.", damage);
damage = -5;
}
if( spell_id != SPELL_UNKNOWN || attacker == NULL )
avoidable = false;
// only apply DS if physical damage (no spell damage)
// damage shield calls this function with spell_id set, so its unavoidable
if (attacker && damage > 0 && spell_id == SPELL_UNKNOWN) {
this->DamageShield(attacker);
for(int bs = 0; bs < BUFF_COUNT; bs++){
if(buffs[bs].numhits > 0 && !IsDiscipline(buffs[bs].spellid)){
if(buffs[bs].numhits == 1){
BuffFadeBySlot(bs, true);
}
else{
buffs[bs].numhits--;
}
}
}
}
if(attacker){
if(attacker->IsClient()){
if(!attacker->CastToClient()->GetFeigned())
AddToHateList(attacker, 0, damage, true, false, iBuffTic);
}
else
AddToHateList(attacker, 0, damage, true, false, iBuffTic);
}
if(damage > 0) {
//if there is some damage being done and theres an attacker involved
if(attacker) {
if(spell_id == SPELL_HARM_TOUCH2 && attacker->IsClient() && attacker->CastToClient()->CheckAAEffect(aaEffectLeechTouch)){
int healed = damage;
healed = attacker->GetActSpellHealing(spell_id, healed);
attacker->HealDamage(healed);
entity_list.MessageClose(this, true, 300, MT_Emote, "%s beams a smile at %s", attacker->GetCleanName(), this->GetCleanName() );
attacker->CastToClient()->DisableAAEffect(aaEffectLeechTouch);
}
// if spell is lifetap add hp to the caster
if (spell_id != SPELL_UNKNOWN && IsLifetapSpell( spell_id )) {
int healed = damage;
healed = attacker->GetActSpellHealing(spell_id, healed);
mlog(COMBAT__DAMAGE, "Applying lifetap heal of %d to %s", healed, attacker->GetName());
attacker->HealDamage(healed);
//we used to do a message to the client, but its gone now.
// emote goes with every one ... even npcs
entity_list.MessageClose(this, true, 300, MT_Emote, "%s beams a smile at %s", attacker->GetCleanName(), this->GetCleanName() );
}
// if we got a pet, thats not already fighting something send it into battle
Mob *pet = GetPet();
if (pet && !pet->IsFamiliar() && !pet->SpecAttacks[IMMUNE_AGGRO] && !pet->IsEngaged() && attacker != this)
{
mlog(PETS__AGGRO, "Sending pet %s into battle due to attack.", pet->GetName());
pet->AddToHateList(attacker, 1);
pet->SetTarget(attacker);
Message_StringID(10, PET_ATTACKING, pet->GetCleanName(), attacker->GetCleanName());
}
} //end `if there is some damage being done and theres anattacker person involved`
//see if any runes want to reduce this damage
if(spell_id == SPELL_UNKNOWN) {
damage = ReduceDamage(damage);
mlog(COMBAT__HITS, "Melee Damage reduced to %d", damage);
} else {
sint32 origdmg = damage;
damage = ReduceMagicalDamage(damage);
mlog(COMBAT__HITS, "Melee Damage reduced to %d", damage);
if (origdmg != damage && attacker && attacker->IsClient()) {
if(attacker->CastToClient()->GetFilter(FILTER_DAMAGESHIELD) != FilterHide)
attacker->Message(15, "The Spellshield absorbed %d of %d points of damage", origdmg - damage, origdmg);
}
}
if(IsClient() && CastToClient()->sneaking){
CastToClient()->sneaking = false;
SendAppearancePacket(AT_Sneak, 0);
}
if(attacker && attacker->IsClient() && attacker->CastToClient()->sneaking){
attacker->CastToClient()->sneaking = false;
attacker->SendAppearancePacket(AT_Sneak, 0);
}
//final damage has been determined.
} //end `if damage was done`
|
 |
|
 |
 |
|
 |

01-23-2008, 01:05 PM
|
Sarnak
|
|
Join Date: Sep 2005
Posts: 34
|
|
and the rest
Code:
//send damage packet...
if(!iBuffTic) { //buff ticks do not send damage, instead they just call SendHPUpdate(), which is done below
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct));
CombatDamage_Struct* a = (CombatDamage_Struct*)outapp->pBuffer;
a->target = GetID();
if (attacker == NULL)
a->source = 0;
else if (attacker->IsClient() && attacker->CastToClient()->GMHideMe())
a->source = 0;
else
a->source = attacker->GetID();
a->type = SkillDamageTypes[skill_used]; // was 0x1c
a->damage = damage;
// if (attack_skill != 231)
// a->spellid = SPELL_UNKNOWN;
// else
a->spellid = spell_id;
//Note: if players can become pets, they will not receive damage messages of their own
//this was done to simplify the code here (since we can only effectively skip one mob on queue)
eqFilterType filter;
Mob *skip = attacker;
if(attacker && attacker->GetOwnerID()) {
//attacker is a pet, let pet owners see their pet's damage
Mob* owner = attacker->GetOwner();
if (owner && owner->IsClient()) {
if ((spell_id != SPELL_UNKNOWN) && damage>0) {
//special crap for spell damage, looks hackish to me
char val1[20]={0};
owner->Message_StringID(4,OTHER_HIT_NONMELEE,GetCleanName(),ConvertArray(damage,val1));
} else {
if(damage > 0) {
if(spell_id != SPELL_UNKNOWN)
filter = iBuffTic ? FilterDOT : FilterSpellDamage;
else
filter = FILTER_MYPETHITS;
} else if(damage == -5)
filter = FilterNone; //cant filter invulnerable
else
filter = FILTER_MYPETMISSES;
owner->CastToClient()->QueuePacket(outapp,true,CLIENT_CONNECTED,filter);
}
}
skip = owner;
} else {
//attacker is not a pet, send to the attacker
//if the attacker is a client, try them with the correct filter
if(attacker && attacker->IsClient()) {
if ((spell_id != SPELL_UNKNOWN) && damage>0) {
//special crap for spell damage, looks hackish to me
char val1[20]={0};
attacker->Message_StringID(4,OTHER_HIT_NONMELEE,GetCleanName(),ConvertArray(damage,val1));
} else {
if(damage > 0) {
if(spell_id != SPELL_UNKNOWN)
filter = iBuffTic ? FilterDOT : FilterSpellDamage;
else
filter = FilterNone; //cant filter our own hits
} else if(damage == -5)
filter = FilterNone; //cant filter invulnerable
else
filter = FILTER_MYMISSES;
attacker->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter);
}
}
skip = attacker;
}
//send damage to all clients around except the specified skip mob (attacker or the attacker's owner) and ourself
if(damage > 0) {
if(spell_id != SPELL_UNKNOWN)
filter = iBuffTic ? FilterDOT : FilterSpellDamage;
else
filter = FILTER_OTHERHITS;
} else if(damage == -5)
filter = FilterNone; //cant filter invulnerable
else
filter = FILTER_OTHERMISSES;
//make attacker (the attacker) send the packet so we can skip them and the owner
//this call will send the packet to `this` as well (using the wrong filter) (will not happen until PC charm works)
//LogFile->write(EQEMuLog::Debug, "Queue damage to all except %s with filter %d (%d), type %d", skip->GetName(), filter, IsClient()?CastToClient()->GetFilter(filter):-1, a->type);
entity_list.QueueCloseClients(this, outapp, true, 200, skip, true, filter);
//send the damage to ourself if we are a client
if(IsClient()) {
//I dont think any filters apply to damage affecting us
CastToClient()->QueuePacket(outapp);
}
safe_delete(outapp);
} else {
//else, it is a buff tic...
// Everhood - So we can see our dot dmg like live shows it.
if(spell_id != SPELL_UNKNOWN && damage > 0 && attacker && attacker != this && attacker->IsClient()) {
//might filter on (attack_skill>200 && attack_skill<250), but I dont think we need it
if(attacker->CastToClient()->GetFilter(FilterDOT) != FilterHide) {
attacker->Message_StringID(MT_DoTDamage, OTHER_HIT_DOT, GetCleanName(),itoa(damage),spells[spell_id].name);
}
}
} //end packet sending
if(damage > 0) {
//check for death conditions
if(IsClient()) {
if((GetHP() - damage) <= -10) {
Death(attacker, damage, spell_id, skill_used);
return;
}
} else {
if (damage >= GetHP()) {
//killed...
SetHP(-100);
Death(attacker, damage, spell_id, skill_used);
return;
}
}
//not killed. Apply the damage
SetHP(GetHP() - damage);
//fade mez if we are mezzed
if (IsMezzed()) {
mlog(COMBAT__HITS, "Breaking mez due to attack.");
BuffFadeByEffect(SE_Mez);
}
//check stun chances if bashing
if ((skill_used == BASH || skill_used == KICK && (attacker && attacker->GetLevel() >= 55)) && GetLevel() < 56) {
int stun_resist = itembonuses.StunResist+spellbonuses.StunResist;
if(this->GetBaseRace() == OGRE && this->IsClient() && !attacker->BehindMob(this, attacker->GetX(), attacker->GetY())) {
mlog(COMBAT__HITS, "Stun Resisted. Ogres are immune to frontal melee stuns.");
} else {
if(stun_resist <= 0 || MakeRandomInt(0,99) >= stun_resist) {
mlog(COMBAT__HITS, "Stunned. We had %dpercent resist chance.");
Stun(0);
} else {
mlog(COMBAT__HITS, "Stun Resisted. We had %dpercent resist chance.");
}
}
}
if(spell_id != SPELL_UNKNOWN) {
//see if root will break
if (IsRooted()) { // neotoyko: only spells cancel root
if(GetAA(aaEnhancedRoot))
{
if (MakeRandomInt(0, 99) < 10) {
mlog(COMBAT__HITS, "Spell broke root! 10percent chance");
BuffFadeByEffect(SE_Root, buffslot); // buff slot is passed through so a root w/ dam doesnt cancel itself
} else {
mlog(COMBAT__HITS, "Spell did not break root. 10 percent chance");
}
}
else
{
if (MakeRandomInt(0, 99) < 20) {
mlog(COMBAT__HITS, "Spell broke root! 20percent chance");
BuffFadeByEffect(SE_Root, buffslot); // buff slot is passed through so a root w/ dam doesnt cancel itself
} else {
mlog(COMBAT__HITS, "Spell did not break root. 20 percent chance");
}
}
}
}
else{
//increment chances of interrupting
if(IsCasting() && damage > 0) { //shouldnt interrupt on regular spell damage
attacked_count++;
mlog(COMBAT__HITS, "Melee attack while casting. Attack count %d", attacked_count);
}
}
//send an HP update if we are hurt
if(GetHP() < GetMaxHP())
SendHPUpdate();
}
}
|
 |
|
 |

01-23-2008, 01:11 PM
|
Sarnak
|
|
Join Date: Sep 2005
Posts: 34
|
|
REALLY NEED THIS LOOKED AT --
Not sure if only the eq_packet_structs and Titanium struct are the only needing the values swapped, problem only verified on titanium client.
|

01-23-2008, 01:18 PM
|
Sarnak
|
|
Join Date: Sep 2005
Posts: 34
|
|
Damn 5 minute edit timer....
anyways, since my explanation was rather bad, the death struct changes fix the "you crush mobname for # damage" no matter how you killed it messages, that was even displaying from spells.
now no damage message is displayed by client when mob dies, so calling death routine will kill a mob with only the X was slain by X message, so no more "mobname tries to punch itself but misses" on #kill for example either.
|

01-23-2008, 03:00 PM
|
Discordant
|
|
Join Date: Jun 2005
Posts: 286
|
|
Very nice  That has annoyed me for quite some time.
__________________
-Croup (the rogue)
Creator of Pandemic (PvP-Racewars)
|

02-26-2008, 09:09 AM
|
Dragon
|
|
Join Date: May 2006
Location: Cincinnati, OH
Posts: 689
|
|
Was there any chance of this getting committed?
|

02-26-2008, 10:02 AM
|
Administrator
|
|
Join Date: Sep 2006
Posts: 1,348
|
|
Yeah I had it ready to be committed but lost my system so it sorta got set back, I'll get it done sooner or later >< sorry.
|

02-26-2008, 01:40 PM
|
Dragon
|
|
Join Date: May 2006
Location: Cincinnati, OH
Posts: 689
|
|
Doh! Was wondering where you'd been, hehe. Sorry to hear it, hope you were able to get up and running again without too much trouble.
|

03-04-2008, 08:59 PM
|
Administrator
|
|
Join Date: Sep 2006
Posts: 1,348
|
|
Alright poking back in, if this hasn't been put in yet I hope to have it or something similar in in a few days now that I can compile.
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -4. The time now is 11:58 AM.
|
|
 |
|
 |
|
|
|
 |
|
 |
|
 |