Upstream merge

This commit is contained in:
Arthur Ice
2014-07-30 14:22:17 -07:00
92 changed files with 4376 additions and 1633 deletions
+149 -227
View File
@@ -74,17 +74,17 @@ void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg)
case SkillFlyingKick:
case SkillRoundKick:
case SkillKick:
item_slot = SLOT_FEET;
item_slot = MainFeet;
break;
case SkillBash:
item_slot = SLOT_SECONDARY;
item_slot = MainSecondary;
break;
case SkillDragonPunch:
case SkillEagleStrike:
case SkillTigerClaw:
item_slot = SLOT_HANDS;
item_slot = MainHands;
break;
default:
@@ -105,6 +105,9 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
//this really should go through the same code as normal melee damage to
//pick up all the special behavior there
if (!who)
return;
int32 hate = max_damage;
if(hate_override > -1)
hate = hate_override;
@@ -113,7 +116,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
{
if(IsClient())
{
ItemInst *item = CastToClient()->GetInv().GetItem(SLOT_SECONDARY);
ItemInst *item = CastToClient()->GetInv().GetItem(MainSecondary);
if(item)
{
if(item->GetItem()->ItemType == ItemTypeShield)
@@ -128,7 +131,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
min_damage += min_damage * GetMeleeMinDamageMod_SE(skill) / 100;
if(HitChance && !who->CheckHitChance(this, skill, 13))
if(HitChance && !who->CheckHitChance(this, skill, MainPrimary))
max_damage = 0;
else{
@@ -141,26 +144,18 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
who->MeleeMitigation(this, max_damage, min_damage);
if(max_damage > 0) {
ApplyMeleeDamageBonus(skill, max_damage);
max_damage += who->GetFcDamageAmtIncoming(this, 0, true, skill);
max_damage += (itembonuses.HeroicSTR / 10) + (max_damage * who->GetSkillDmgTaken(skill) / 100) + GetSkillDmgAmt(skill);
TryCriticalHit(who, skill, max_damage);
}
if(max_damage > 0)
CommonOutgoingHitSuccess(who, max_damage, skill);
}
if(max_damage >= 0) //You should probably get aggro no matter what, but unclear why it was set like this.
who->AddToHateList(this, hate);
who->AddToHateList(this, hate, 0, false);
who->Damage(this, max_damage, SPELL_UNKNOWN, skill, false);
//Make sure 'this' has not killed the target and 'this' is not dead (Damage shield ect).
if(!GetTarget())return;
if (HasDied()) return;
if (max_damage > 0)
CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess);
//[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){
int kb_chance = 25;
@@ -200,7 +195,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
//These two are not subject to the combat ability timer, as they
//allready do their checking in conjunction with the attack timer
//throwing weapons
if(ca_atk->m_atk == 11) {
if(ca_atk->m_atk == MainRange) {
if (ca_atk->m_skill == SkillThrowing) {
SetAttackTimer();
ThrowingAttack(GetTarget());
@@ -242,6 +237,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
int32 skill_reduction = this->GetSkillReuseTime(ca_atk->m_skill);
// not sure what the '100' indicates..if ->m_atk is not used as 'slot' reference, then change MainRange above back to '11'
if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == SkillBash)) { // SLAM - Bash without a shield equipped
if (GetTarget() != this) {
@@ -249,8 +245,8 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
DoAnim(animTailRake);
int32 ht = 0;
if(GetWeaponDamage(GetTarget(), GetInv().GetItem(SLOT_SECONDARY)) <= 0 &&
GetWeaponDamage(GetTarget(), GetInv().GetItem(SLOT_SHOULDER)) <= 0){
if(GetWeaponDamage(GetTarget(), GetInv().GetItem(MainSecondary)) <= 0 &&
GetWeaponDamage(GetTarget(), GetInv().GetItem(MainShoulders)) <= 0){
dmg = -5;
}
else{
@@ -329,7 +325,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
DoAnim(animKick);
int32 ht = 0;
if(GetWeaponDamage(GetTarget(), GetInv().GetItem(SLOT_FEET)) <= 0){
if(GetWeaponDamage(GetTarget(), GetInv().GetItem(MainFeet)) <= 0){
dmg = -5;
}
else{
@@ -405,7 +401,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type)
int32 min_dmg = 1;
int reuse = 0;
SkillUseTypes skill_type; //to avoid casting... even though it "would work"
uint8 itemslot = SLOT_FEET;
uint8 itemslot = MainFeet;
switch(unchecked_type)
{
@@ -421,7 +417,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type)
case SkillDragonPunch:{
skill_type = SkillDragonPunch;
max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, DragonPunchBonus) / 100) + 26;
itemslot = SLOT_HANDS;
itemslot = MainHands;
ApplySpecialAttackMod(skill_type, max_dmg, min_dmg);
DoAnim(animTailRake);
reuse = TailRakeReuseTime;
@@ -431,7 +427,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type)
case SkillEagleStrike:{
skill_type = SkillEagleStrike;
max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, EagleStrikeBonus) / 100) + 19;
itemslot = SLOT_HANDS;
itemslot = MainHands;
ApplySpecialAttackMod(skill_type, max_dmg, min_dmg);
DoAnim(animEagleStrike);
reuse = EagleStrikeReuseTime;
@@ -441,7 +437,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type)
case SkillTigerClaw:{
skill_type = SkillTigerClaw;
max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, TigerClawBonus) / 100) + 12;
itemslot = SLOT_HANDS;
itemslot = MainHands;
ApplySpecialAttackMod(skill_type, max_dmg, min_dmg);
DoAnim(animTigerClaw);
reuse = TigerClawReuseTime;
@@ -511,7 +507,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
//make sure we have a proper weapon if we are a client.
if(IsClient()) {
const ItemInst *wpn = CastToClient()->GetInv().GetItem(SLOT_PRIMARY);
const ItemInst *wpn = CastToClient()->GetInv().GetItem(MainPrimary);
if(!wpn || (wpn->GetItem()->ItemType != ItemType1HPiercing)){
Message_StringID(13, BACKSTAB_WEAPON);
return;
@@ -574,7 +570,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
}
else { //We do a single regular attack if we attack from the front without chaotic stab
Attack(other, 13);
Attack(other, MainPrimary);
}
}
@@ -593,11 +589,11 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
if(IsClient()){
const ItemInst *wpn = nullptr;
wpn = CastToClient()->GetInv().GetItem(SLOT_PRIMARY);
wpn = CastToClient()->GetInv().GetItem(MainPrimary);
if(wpn) {
primaryweapondamage = GetWeaponDamage(other, wpn);
backstab_dmg = wpn->GetItem()->BackstabDmg;
for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i)
for (int i = 0; i < EmuConstants::ITEM_COMMON_SIZE; ++i)
{
ItemInst *aug = wpn->GetAugment(i);
if(aug)
@@ -676,7 +672,7 @@ void Mob::RogueAssassinate(Mob* other)
{
//can you dodge, parry, etc.. an assassinate??
//if so, use DoSpecialAttackDamage(other, BACKSTAB, 32000); instead
if(GetWeaponDamage(other, IsClient()?CastToClient()->GetInv().GetItem(SLOT_PRIMARY):(const ItemInst*)nullptr) > 0){
if(GetWeaponDamage(other, IsClient()?CastToClient()->GetInv().GetItem(MainPrimary):(const ItemInst*)nullptr) > 0){
other->Damage(this, 32000, SPELL_UNKNOWN, SkillBackstab);
}else{
other->Damage(this, -5, SPELL_UNKNOWN, SkillBackstab);
@@ -695,20 +691,20 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
//Message(0, "Error: Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
return;
}
const ItemInst* RangeWeapon = m_inv[SLOT_RANGE];
const ItemInst* RangeWeapon = m_inv[MainRange];
//locate ammo
int ammo_slot = SLOT_AMMO;
const ItemInst* Ammo = m_inv[SLOT_AMMO];
int ammo_slot = MainAmmo;
const ItemInst* Ammo = m_inv[MainAmmo];
if (!RangeWeapon || !RangeWeapon->IsType(ItemClassCommon)) {
mlog(COMBAT__RANGED, "Ranged attack canceled. Missing or invalid ranged weapon (%d) in slot %d", GetItemIDAt(SLOT_RANGE), SLOT_RANGE);
Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have no bow!", GetItemIDAt(SLOT_RANGE));
mlog(COMBAT__RANGED, "Ranged attack canceled. Missing or invalid ranged weapon (%d) in slot %d", GetItemIDAt(MainRange), MainRange);
Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have no bow!", GetItemIDAt(MainRange));
return;
}
if (!Ammo || !Ammo->IsType(ItemClassCommon)) {
mlog(COMBAT__RANGED, "Ranged attack canceled. Missing or invalid ammo item (%d) in slot %d", GetItemIDAt(SLOT_AMMO), SLOT_AMMO);
Message(0, "Error: Ammo: GetItem(%i)==0, you have no ammo!", GetItemIDAt(SLOT_AMMO));
mlog(COMBAT__RANGED, "Ranged attack canceled. Missing or invalid ammo item (%d) in slot %d", GetItemIDAt(MainAmmo), MainAmmo);
Message(0, "Error: Ammo: GetItem(%i)==0, you have no ammo!", GetItemIDAt(MainAmmo));
return;
}
@@ -733,7 +729,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
//first look for quivers
int r;
bool found = false;
for(r = SLOT_PERSONAL_BEGIN; r <= SLOT_PERSONAL_END; r++) {
for(r = EmuConstants::GENERAL_BEGIN; r <= EmuConstants::GENERAL_END; r++) {
const ItemInst *pi = m_inv[r];
if(pi == nullptr || !pi->IsType(ItemClassContainer))
continue;
@@ -765,7 +761,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
//if we dont find a quiver, look through our inventory again
//not caring if the thing is a quiver.
int32 aslot = m_inv.HasItem(AmmoItem->ID, 1, invWherePersonal);
if(aslot != SLOT_INVALID) {
if (aslot != INVALID_INDEX) {
ammo_slot = aslot;
Ammo = m_inv[aslot];
mlog(COMBAT__RANGED, "Using ammo from inventory stack at slot %d. %d in stack.", ammo_slot, Ammo->GetCharges());
@@ -813,39 +809,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
CheckIncreaseSkill(SkillArchery, GetTarget(), -15);
//break invis when you attack
if(invisible) {
mlog(COMBAT__ATTACKS, "Removing invisibility due to melee attack.");
BuffFadeByEffect(SE_Invisibility);
BuffFadeByEffect(SE_Invisibility2);
invisible = false;
}
if(invisible_undead) {
mlog(COMBAT__ATTACKS, "Removing invisibility vs. undead due to melee attack.");
BuffFadeByEffect(SE_InvisVsUndead);
BuffFadeByEffect(SE_InvisVsUndead2);
invisible_undead = false;
}
if(invisible_animals){
mlog(COMBAT__ATTACKS, "Removing invisibility vs. animals due to melee attack.");
BuffFadeByEffect(SE_InvisVsAnimals);
invisible_animals = false;
}
if (spellbonuses.NegateIfCombat)
BuffFadeByEffect(SE_NegateIfCombat);
if(hidden || improved_hidden){
hidden = false;
improved_hidden = false;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer;
sa_out->spawn_id = GetID();
sa_out->type = 0x03;
sa_out->parameter = 0;
entity_list.QueueClients(this, outapp, true);
safe_delete(outapp);
}
CommonBreakInvisible();
}
void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime)
@@ -853,7 +817,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
if (!CanDoSpecialAttack(other))
return;
if (!other->CheckHitChance(this, SkillArchery, 13,chance_mod)) {
if (!other->CheckHitChance(this, SkillArchery, MainPrimary, chance_mod)) {
mlog(COMBAT__RANGED, "Ranged attack missed %s.", other->GetName());
other->Damage(this, 0, SPELL_UNKNOWN, SkillArchery);
} else {
@@ -975,27 +939,27 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
if (ReuseTime)
TrySkillProc(other, SkillArchery, ReuseTime);
else
TrySkillProc(other, SkillArchery, 0, true, 11);
TrySkillProc(other, SkillArchery, 0, true, MainRange);
}
}
//try proc on hits and misses
if((RangeWeapon != nullptr) && GetTarget() && other && !other->HasDied())
{
TryWeaponProc(RangeWeapon, other, 11);
TryWeaponProc(RangeWeapon, other, MainRange);
}
//Arrow procs because why not?
if((Ammo != NULL) && GetTarget() && other && !other->HasDied())
{
TryWeaponProc(Ammo, other, 11);
TryWeaponProc(Ammo, other, MainRange);
}
if (HasSkillProcs() && GetTarget() && other && !other->HasDied()){
if (ReuseTime)
TrySkillProc(other, SkillArchery, ReuseTime);
else
TrySkillProc(other, SkillArchery, 0, false, 11);
TrySkillProc(other, SkillArchery, 0, false, MainRange);
}
}
@@ -1018,19 +982,30 @@ void NPC::RangedAttack(Mob* other)
return;
}
float range = 250; // needs to be longer than 200(most spells)
mlog(COMBAT__RANGED, "Calculated bow range to be %.1f", range);
range *= range;
if(DistNoRootNoZ(*GetTarget()) > range) {
mlog(COMBAT__RANGED, "Ranged attack out of range...%.2f vs %.2f", DistNoRootNoZ(*GetTarget()), range);
int sa_min_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 0); //Min Range of NPC attack
int sa_max_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 1); //Max Range of NPC attack
float min_range = static_cast<float>(RuleI(Combat, MinRangedAttackDist));
float max_range = 250; // needs to be longer than 200(most spells)
if (sa_max_range)
max_range = static_cast<float>(sa_max_range);
if (sa_min_range)
min_range = static_cast<float>(sa_min_range);
mlog(COMBAT__RANGED, "Calculated bow range to be %.1f", max_range);
max_range *= max_range;
if(DistNoRootNoZ(*other) > max_range) {
mlog(COMBAT__RANGED, "Ranged attack out of range...%.2f vs %.2f", DistNoRootNoZ(*other), max_range);
//target is out of range, client does a message
return;
}
else if(DistNoRootNoZ(*GetTarget()) < (RuleI(Combat, MinRangedAttackDist)*RuleI(Combat, MinRangedAttackDist))){
else if(DistNoRootNoZ(*other) < (min_range * min_range))
return;
}
if(!IsAttackAllowed(GetTarget()) ||
if(!other || !IsAttackAllowed(other) ||
IsCasting() ||
DivineAura() ||
IsStunned() ||
@@ -1040,32 +1015,33 @@ void NPC::RangedAttack(Mob* other)
return;
}
if(!ammo)
{
SkillUseTypes skillinuse = SkillArchery;
skillinuse = static_cast<SkillUseTypes>(GetRangedSkill());
if(!ammo && !GetAmmoIDfile())
ammo = database.GetItem(8005);
}
if(ammo)
SendItemAnimation(GetTarget(), ammo, SkillArchery);
SendItemAnimation(other, ammo, SkillArchery);
else
ProjectileAnimation(other, 0,false,0,0,0,0,GetAmmoIDfile(),skillinuse);
FaceTarget(other);
// Face the Target
FaceTarget(GetTarget());
// Hit?
if (!GetTarget()->CheckHitChance(this, SkillArchery, 13))
if (!other->CheckHitChance(this, skillinuse, MainRange, GetSpecialAbilityParam(SPECATK_RANGED_ATK, 2)))
{
mlog(COMBAT__RANGED, "Ranged attack missed %s.", GetTarget()->GetName());
GetTarget()->Damage(this, 0, SPELL_UNKNOWN, SkillArchery);
mlog(COMBAT__RANGED, "Ranged attack missed %s.", other->GetName());
other->Damage(this, 0, SPELL_UNKNOWN, skillinuse);
}
else
{
int16 WDmg = GetWeaponDamage(GetTarget(), weapon);
int16 ADmg = GetWeaponDamage(GetTarget(), ammo);
int16 WDmg = GetWeaponDamage(other, weapon);
int16 ADmg = GetWeaponDamage(other, ammo);
int32 TotalDmg = 0;
if(WDmg > 0 || ADmg > 0)
{
mlog(COMBAT__RANGED, "Ranged attack hit %s.", GetTarget()->GetName());
int32 TotalDmg = 0;
mlog(COMBAT__RANGED, "Ranged attack hit %s.", other->GetName());
int32 MaxDmg = max_dmg * RuleR(Combat, ArcheryNPCMultiplier); // should add a field to npc_types
int32 MinDmg = min_dmg * RuleR(Combat, ArcheryNPCMultiplier);
@@ -1074,54 +1050,36 @@ void NPC::RangedAttack(Mob* other)
else
TotalDmg = MakeRandomInt(MinDmg, MaxDmg);
int32 hate = TotalDmg;
GetTarget()->MeleeMitigation(this, TotalDmg, MinDmg);
ApplyMeleeDamageBonus(SkillArchery, TotalDmg);
TryCriticalHit(GetTarget(), SkillArchery, TotalDmg);
GetTarget()->AddToHateList(this, hate, 0, false);
GetTarget()->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery);
CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess);
TotalDmg += TotalDmg * GetSpecialAbilityParam(SPECATK_RANGED_ATK, 3) / 100; //Damage modifier
other->AvoidDamage(this, TotalDmg, false);
other->MeleeMitigation(this, TotalDmg, MinDmg);
if (TotalDmg > 0)
CommonOutgoingHitSuccess(other, TotalDmg, skillinuse);
}
else
{
GetTarget()->Damage(this, -5, SPELL_UNKNOWN, SkillArchery);
}
TotalDmg = -5;
if (TotalDmg > 0)
other->AddToHateList(this, TotalDmg, 0, false);
else
other->AddToHateList(this, 0, 0, false);
other->Damage(this, TotalDmg, SPELL_UNKNOWN, skillinuse);
if (TotalDmg > 0 && HasSkillProcSuccess() && GetTarget() && !other->HasDied())
TrySkillProc(other, skillinuse, 0, true, MainRange);
}
//break invis when you attack
if(invisible) {
mlog(COMBAT__ATTACKS, "Removing invisibility due to melee attack.");
BuffFadeByEffect(SE_Invisibility);
BuffFadeByEffect(SE_Invisibility2);
invisible = false;
}
if(invisible_undead) {
mlog(COMBAT__ATTACKS, "Removing invisibility vs. undead due to melee attack.");
BuffFadeByEffect(SE_InvisVsUndead);
BuffFadeByEffect(SE_InvisVsUndead2);
invisible_undead = false;
}
if(invisible_animals){
mlog(COMBAT__ATTACKS, "Removing invisibility vs. animals due to melee attack.");
BuffFadeByEffect(SE_InvisVsAnimals);
invisible_animals = false;
}
//try proc on hits and misses
if(other && !other->HasDied())
TrySpellProc(nullptr, (const Item_Struct*)nullptr, other, MainRange);
if (spellbonuses.NegateIfCombat)
BuffFadeByEffect(SE_NegateIfCombat);
if (HasSkillProcs() && other && !other->HasDied())
TrySkillProc(other, skillinuse, 0, false, MainRange);
if(hidden || improved_hidden){
hidden = false;
improved_hidden = false;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer;
sa_out->spawn_id = GetID();
sa_out->type = 0x03;
sa_out->parameter = 0;
entity_list.QueueClients(this, outapp, true);
safe_delete(outapp);
}
CommonBreakInvisible();
}
uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg)
@@ -1165,19 +1123,19 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
return;
}
int ammo_slot = SLOT_RANGE;
const ItemInst* RangeWeapon = m_inv[SLOT_RANGE];
int ammo_slot = MainRange;
const ItemInst* RangeWeapon = m_inv[MainRange];
if (!RangeWeapon || !RangeWeapon->IsType(ItemClassCommon)) {
mlog(COMBAT__RANGED, "Ranged attack canceled. Missing or invalid ranged weapon (%d) in slot %d", GetItemIDAt(SLOT_RANGE), SLOT_RANGE);
Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have nothing to throw!", GetItemIDAt(SLOT_RANGE));
mlog(COMBAT__RANGED, "Ranged attack canceled. Missing or invalid ranged weapon (%d) in slot %d", GetItemIDAt(MainRange), MainRange);
Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have nothing to throw!", GetItemIDAt(MainRange));
return;
}
const Item_Struct* item = RangeWeapon->GetItem();
if(item->ItemType != ItemTypeLargeThrowing && item->ItemType != ItemTypeSmallThrowing) {
mlog(COMBAT__RANGED, "Ranged attack canceled. Ranged item %d is not a throwing weapon. type %d.", item->ItemType);
Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have nothing useful to throw!", GetItemIDAt(SLOT_RANGE));
Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have nothing useful to throw!", GetItemIDAt(MainRange));
return;
}
@@ -1185,16 +1143,16 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
if(RangeWeapon->GetCharges() == 1) {
//first check ammo
const ItemInst* AmmoItem = m_inv[SLOT_AMMO];
const ItemInst* AmmoItem = m_inv[MainAmmo];
if(AmmoItem != nullptr && AmmoItem->GetID() == RangeWeapon->GetID()) {
//more in the ammo slot, use it
RangeWeapon = AmmoItem;
ammo_slot = SLOT_AMMO;
ammo_slot = MainAmmo;
mlog(COMBAT__RANGED, "Using ammo from ammo slot, stack at slot %d. %d in stack.", ammo_slot, RangeWeapon->GetCharges());
} else {
//look through our inventory for more
int32 aslot = m_inv.HasItem(item->ID, 1, invWherePersonal);
if(aslot != SLOT_INVALID) {
if (aslot != INVALID_INDEX) {
//the item wont change, but the instance does, not that it matters
ammo_slot = aslot;
RangeWeapon = m_inv[aslot];
@@ -1234,39 +1192,7 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
DeleteItemInInventory(ammo_slot, 1, true);
CheckIncreaseSkill(SkillThrowing, GetTarget());
//break invis when you attack
if(invisible) {
mlog(COMBAT__ATTACKS, "Removing invisibility due to melee attack.");
BuffFadeByEffect(SE_Invisibility);
BuffFadeByEffect(SE_Invisibility2);
invisible = false;
}
if(invisible_undead) {
mlog(COMBAT__ATTACKS, "Removing invisibility vs. undead due to melee attack.");
BuffFadeByEffect(SE_InvisVsUndead);
BuffFadeByEffect(SE_InvisVsUndead2);
invisible_undead = false;
}
if(invisible_animals){
mlog(COMBAT__ATTACKS, "Removing invisibility vs. animals due to melee attack.");
BuffFadeByEffect(SE_InvisVsAnimals);
invisible_animals = false;
}
if (spellbonuses.NegateIfCombat)
BuffFadeByEffect(SE_NegateIfCombat);
if(hidden || improved_hidden){
hidden = false;
improved_hidden = false;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer;
sa_out->spawn_id = GetID();
sa_out->type = 0x03;
sa_out->parameter = 0;
entity_list.QueueClients(this, outapp, true);
safe_delete(outapp);
}
CommonBreakInvisible();
}
void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* item, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime)
@@ -1274,7 +1200,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
if (!CanDoSpecialAttack(other))
return;
if (!other->CheckHitChance(this, SkillThrowing, 13, chance_mod)){
if (!other->CheckHitChance(this, SkillThrowing, MainPrimary, chance_mod)){
mlog(COMBAT__RANGED, "Ranged attack missed %s.", other->GetName());
other->Damage(this, 0, SPELL_UNKNOWN, SkillThrowing);
} else {
@@ -1312,38 +1238,31 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
other->MeleeMitigation(this, TotalDmg, minDmg);
if(TotalDmg > 0)
{
ApplyMeleeDamageBonus(SkillThrowing, TotalDmg);
TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillThrowing);
TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillThrowing) / 100) + GetSkillDmgAmt(SkillThrowing);
TryCriticalHit(other, SkillThrowing, TotalDmg);
int32 hate = (2*WDmg);
other->AddToHateList(this, hate, 0, false);
CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess);
}
CommonOutgoingHitSuccess(other, TotalDmg, SkillThrowing);
}
else
TotalDmg = -5;
other->AddToHateList(this, 2*WDmg, 0, false);
other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillThrowing);
if (TotalDmg > 0 && HasSkillProcSuccess() && GetTarget() && other && !other->HasDied()){
if (ReuseTime)
TrySkillProc(other, SkillThrowing, ReuseTime);
else
TrySkillProc(other, SkillThrowing, 0, true, 11);
TrySkillProc(other, SkillThrowing, 0, true, MainRange);
}
}
if((RangeWeapon != nullptr) && GetTarget() && other && (other->GetHP() > -10))
TryWeaponProc(RangeWeapon, other, 11);
TryWeaponProc(RangeWeapon, other, MainRange);
if (HasSkillProcs() && GetTarget() && other && !other->HasDied()){
if (ReuseTime)
TrySkillProc(other, SkillThrowing, ReuseTime);
else
TrySkillProc(other, SkillThrowing, 0, false, 11);
TrySkillProc(other, SkillThrowing, 0, false, MainRange);
}
}
@@ -1394,7 +1313,10 @@ void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skil
safe_delete(outapp);
}
void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile) {
void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) {
if (!to)
return;
const Item_Struct* item = nullptr;
uint8 item_type = 0;
@@ -1412,9 +1334,12 @@ void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, f
if(IsArrow) {
item_type = 27;
}
if(!item_type) {
if(!item_type && !skillInUse) {
item_type = item->ItemType;
}
else if (skillInUse)
item_type = GetItemTypeBySkill(skillInUse);
if(!speed) {
speed = 4.0;
}
@@ -1444,7 +1369,7 @@ void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, f
as->target_id = to->GetID();
as->item_id = item->ID;
as->item_type = item_type;
as->skill = 0; // Doesn't seem to have any effect
as->skill = skillInUse; // Doesn't seem to have any effect
strn0cpy(as->model_name, item_IDFile, 16);
as->velocity = speed;
as->launch_angle = angle;
@@ -1768,8 +1693,8 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
{
DoAnim(animTailRake);
if(GetWeaponDamage(ca_target, GetInv().GetItem(SLOT_SECONDARY)) <= 0 &&
GetWeaponDamage(ca_target, GetInv().GetItem(SLOT_SHOULDER)) <= 0){
if(GetWeaponDamage(ca_target, GetInv().GetItem(MainSecondary)) <= 0 &&
GetWeaponDamage(ca_target, GetInv().GetItem(MainShoulders)) <= 0){
dmg = -5;
}
else{
@@ -1839,7 +1764,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
{
DoAnim(animKick);
if(GetWeaponDamage(ca_target, GetInv().GetItem(SLOT_FEET)) <= 0){
if(GetWeaponDamage(ca_target, GetInv().GetItem(MainFeet)) <= 0){
dmg = -5;
}
else{
@@ -2062,7 +1987,7 @@ uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){
float ProcChance = GetSpecialProcChances(11);
float ProcChance = GetSpecialProcChances(MainRange);
if(ProcChance > MakeRandomFloat(0,1))
return HeadShot_Dmg;
}
@@ -2125,7 +2050,7 @@ uint32 Mob::TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 Reuse
float ProcChance = 0.0f;
if (skillInUse == SkillThrowing)
ProcChance = GetSpecialProcChances(11);
ProcChance = GetSpecialProcChances(MainRange);
else
ProcChance = GetAssassinateProcChances(ReuseTime);
@@ -2173,8 +2098,8 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
skillinuse = SkillOffense;
int damage = 0;
uint32 hate = 0;
int Hand = 13;
int32 hate = 0;
int Hand = MainPrimary;
if (hate == 0 && weapon_damage > 1) hate = weapon_damage;
if(weapon_damage > 0){
@@ -2199,6 +2124,19 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
hate += ucDamageBonus;
}
if(skillinuse == SkillBash){
if(IsClient()){
ItemInst *item = CastToClient()->GetInv().GetItem(MainSecondary);
if(item){
if(item->GetItem()->ItemType == ItemTypeShield) {
hate += item->GetItem()->AC;
}
const Item_Struct *itm = item->GetItem();
hate = hate * (100 + GetFuriousBash(itm->Focus.Effect)) / 100;
}
}
}
ApplySpecialAttackMod(skillinuse, max_hit, min_hit);
min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100;
@@ -2210,18 +2148,14 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
damage = max_hit;
else
damage = MakeRandomInt(min_hit, max_hit);
if(!other->CheckHitChance(this, skillinuse, Hand, chance_mod)) {
damage = 0;
} else {
other->AvoidDamage(this, damage, CanRiposte);
other->MeleeMitigation(this, damage, min_hit);
if(damage > 0) {
ApplyMeleeDamageBonus(skillinuse, damage);
damage += other->GetFcDamageAmtIncoming(this, 0, true, skillinuse);
damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse);
TryCriticalHit(other, skillinuse, damage);
}
if(damage > 0)
CommonOutgoingHitSuccess(other, damage, skillinuse);
}
if (damage == -3) {
@@ -2234,19 +2168,6 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
else
damage = -5;
if(skillinuse == SkillBash){
if(IsClient()){
ItemInst *item = CastToClient()->GetInv().GetItem(SLOT_SECONDARY);
if(item){
if(item->GetItem()->ItemType == ItemTypeShield) {
hate += item->GetItem()->AC;
}
const Item_Struct *itm = item->GetItem();
hate = hate * (100 + GetFuriousBash(itm->Focus.Effect)) / 100;
}
}
}
other->AddToHateList(this, hate);
bool CanSkillProc = true;
@@ -2255,6 +2176,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
CanSkillProc = false; //Disable skill procs
}
other->AddToHateList(this, hate, 0, false);
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
if (HasDied())