mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-01 14:21:37 +00:00
Added PVP based logic
This commit is contained in:
+2
-28
@@ -527,22 +527,7 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
|
||||
c1 = mob1->CastToClient();
|
||||
c2 = mob2->CastToClient();
|
||||
|
||||
if // if both are pvp they can fight
|
||||
(
|
||||
c1->GetPVP() &&
|
||||
c2->GetPVP()
|
||||
)
|
||||
return true;
|
||||
else if // if they're dueling they can go at it
|
||||
(
|
||||
c1->IsDueling() &&
|
||||
c2->IsDueling() &&
|
||||
c1->GetDuelTarget() == c2->GetID() &&
|
||||
c2->GetDuelTarget() == c1->GetID()
|
||||
)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return c1->CanPvP(c2);
|
||||
}
|
||||
else if(_NPC(mob2)) // client vs npc
|
||||
{
|
||||
@@ -698,18 +683,7 @@ bool Mob::IsBeneficialAllowed(Mob *target)
|
||||
c1 = mob1->CastToClient();
|
||||
c2 = mob2->CastToClient();
|
||||
|
||||
if(c1->GetPVP() == c2->GetPVP())
|
||||
return true;
|
||||
else if // if they're dueling they can heal each other too
|
||||
(
|
||||
c1->IsDueling() &&
|
||||
c2->IsDueling() &&
|
||||
c1->GetDuelTarget() == c2->GetID() &&
|
||||
c2->GetDuelTarget() == c1->GetID()
|
||||
)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return c1->CanPvP(c2);
|
||||
}
|
||||
else if(_NPC(mob2)) // client to npc
|
||||
{
|
||||
|
||||
+39
-12
@@ -1574,11 +1574,15 @@ void Client::Damage(Mob* other, int32 damage, uint16 spell_id, EQ::skills::Skill
|
||||
//should this be applied to all damage? comments sound like some is for spell DMG
|
||||
//patch notes on PVP reductions only mention archery/throwing ... not normal dmg
|
||||
if (other && other->IsClient() && (other != this) && damage > 0) {
|
||||
int PvPMitigation = 100;
|
||||
if (attack_skill == EQ::skills::SkillArchery || attack_skill == EQ::skills::SkillThrowing)
|
||||
PvPMitigation = 80;
|
||||
else
|
||||
PvPMitigation = 67;
|
||||
int PvPMitigation = RuleI(World, PVPMeleeMitigation);
|
||||
if (attack_skill == EQ::skills::SkillAbjuration || //spells
|
||||
attack_skill == EQ::skills::SkillAlteration ||
|
||||
attack_skill == EQ::skills::SkillConjuration ||
|
||||
attack_skill == EQ::skills::SkillDivination ||
|
||||
attack_skill == EQ::skills::SkillEvocation) PvPMitigation = RuleI(World, PVPSpellMitigation);
|
||||
if (attack_skill == EQ::skills::SkillArchery || //ranged
|
||||
attack_skill == EQ::skills::SkillThrowing) PvPMitigation = RuleI(World, PVPRangedMitigation);
|
||||
|
||||
damage = std::max((damage * PvPMitigation) / 100, 1);
|
||||
}
|
||||
|
||||
@@ -1754,7 +1758,27 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill
|
||||
{
|
||||
if (killerMob->IsClient())
|
||||
{
|
||||
exploss = 0;
|
||||
int pvpleveldifference = 0;
|
||||
|
||||
if (RuleI(World, PVPSettings) == 4)
|
||||
pvpleveldifference = 5; //Sullon Zek
|
||||
if (RuleI(World, PVPLoseExperienceLevelDifference) > 0)
|
||||
pvpleveldifference = RuleI(World, PVPLoseExperienceLevelDifference);
|
||||
|
||||
if (pvpleveldifference > 0) {
|
||||
int level_difference = 0;
|
||||
if (GetLevel() > killerMob->GetLevel())
|
||||
level_difference = GetLevel() - killerMob->GetLevel();
|
||||
else
|
||||
level_difference = killerMob->GetLevel() - GetLevel();
|
||||
|
||||
if (level_difference > pvpleveldifference)
|
||||
exploss = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
exploss = 0;
|
||||
}
|
||||
}
|
||||
else if (killerMob->GetOwner() && killerMob->GetOwner()->IsClient())
|
||||
{
|
||||
@@ -2068,14 +2092,11 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
|
||||
other->AddToHateList(this, hate);
|
||||
|
||||
LogCombat("Final damage against [{}]: [{}]", other->GetName(), my_hit.damage_done);
|
||||
|
||||
if (other->IsClient() && IsPet() && GetOwner()->IsClient()) {
|
||||
//pets do half damage to clients in pvp
|
||||
my_hit.damage_done /= 2;
|
||||
if (my_hit.damage_done < 1)
|
||||
my_hit.damage_done = 1;
|
||||
my_hit.damage_done = std::max(my_hit.damage_done * RuleI(World, PVPPetDamageMitigation) / 100, 1);
|
||||
}
|
||||
|
||||
LogCombat("Final damage against [{}]: [{}]", other->GetName(), my_hit.damage_done);
|
||||
}
|
||||
else {
|
||||
my_hit.damage_done = DMG_INVULNERABLE;
|
||||
@@ -4976,6 +4997,12 @@ bool Mob::TryRootFadeByDamage(int buffslot, Mob* attacker) {
|
||||
|
||||
if (IsDetrimentalSpell(spellbonuses.Root[1]) && spellbonuses.Root[1] != buffslot) {
|
||||
int BreakChance = RuleI(Spells, RootBreakFromSpells);
|
||||
if (attacker && attacker->IsClient() && IsClient()) {
|
||||
if (RuleI(World, PVPSettings) > 0) BreakChance = 75; //All PVP servers is default 75% chance for root to break
|
||||
|
||||
|
||||
if (RuleI(Spells, PVPRootBreakFromSpells) > 0) BreakChance = RuleI(Spells, PVPRootBreakFromSpells);
|
||||
}
|
||||
|
||||
BreakChance -= BreakChance*buffs[spellbonuses.Root[1]].RootBreakChance / 100;
|
||||
int level_diff = attacker->GetLevel() - GetLevel();
|
||||
|
||||
@@ -10009,4 +10009,83 @@ void Client::Fling(float value, float target_x, float target_y, float target_z,
|
||||
outapp_fling->priority = 6;
|
||||
FastQueuePacket(&outapp_fling);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//CanPvP returns true if provided player can attack this player
|
||||
bool Client::CanPvP(Client *c) {
|
||||
if (c == nullptr)
|
||||
return false;
|
||||
|
||||
//Dueling overrides normal PvP logic
|
||||
if (IsDueling() && c->IsDueling() && GetDuelTarget() == c->GetID() && c->GetDuelTarget() == GetID())
|
||||
return true;
|
||||
|
||||
//If PVPLevelDifference is enabled, only allow PVP if players are of proper range
|
||||
int rule_level_diff = 0;
|
||||
if (RuleI(World, PVPSettings) == 4)
|
||||
rule_level_diff = 100; //Sullon Zek rules can attack anyone of opposing deity.
|
||||
if (RuleI(World, PVPLevelDifference) > 0)
|
||||
rule_level_diff = RuleI(World, PVPLevelDifference);
|
||||
|
||||
if (rule_level_diff > 0) {
|
||||
int level_diff = 0;
|
||||
if (c->GetLevel() > GetLevel())
|
||||
level_diff = c->GetLevel() - GetLevel();
|
||||
else
|
||||
level_diff = GetLevel() - c->GetLevel();
|
||||
if (level_diff > rule_level_diff)
|
||||
return false;
|
||||
}
|
||||
|
||||
//players need to be proper level for pvp
|
||||
int rule_min_level = 0;
|
||||
if (RuleI(World, PVPSettings) == 4)
|
||||
rule_min_level = 6;
|
||||
if (RuleI(World, PVPMinLevel) > 0)
|
||||
rule_min_level = RuleI(World, PVPMinLevel);
|
||||
|
||||
if (rule_min_level > 0 && (GetLevel() < rule_min_level || c->GetLevel() < rule_min_level))
|
||||
return false;
|
||||
|
||||
//is deity pvp rule enabled? If so, if we're same alignment, don't allow pvp
|
||||
if ((RuleI(World, PVPSettings) == 4 || RuleB(World, PVPUseDeityBasedPVP)) && GetAlignment() == c->GetAlignment())
|
||||
return false;
|
||||
|
||||
//VZTZ Zek PVP Setting
|
||||
if ((RuleI(World, PVPSettings) == 2 || RuleB(World, PVPUseTeamsBySizeBasedPVP)) && GetPVPRaceTeamBySize() == c->GetPVPRaceTeamBySize())
|
||||
return false;
|
||||
|
||||
//Check if players are flagged pvp. This may need to be removed later
|
||||
if (!GetPVP() || !c->GetPVP()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//GetAlignment returns 0 = neutral, 1 = good, 2 = evil, used for pvp sullon zek rules
|
||||
int Client::GetAlignment() {
|
||||
if (GetDeity() == EQ::deity::DeityErollisiMarr ||
|
||||
GetDeity() == EQ::deity::DeityMithanielMarr ||
|
||||
GetDeity() == EQ::deity::DeityRodcetNife ||
|
||||
GetDeity() == EQ::deity::DeityQuellious ||
|
||||
GetDeity() == EQ::deity::DeityTunare) return 1; //good
|
||||
if (GetDeity() == EQ::deity::DeityBertoxxulous ||
|
||||
GetDeity() == EQ::deity::DeityCazicThule ||
|
||||
GetDeity() == EQ::deity::DeityInnoruuk ||
|
||||
GetDeity() == EQ::deity::DeityRallosZek) return 2; //evil
|
||||
return 0; //neutral
|
||||
}
|
||||
|
||||
//GetPVPRaceSize returns based on racial divisions
|
||||
int Client::GetPVPRaceTeamBySize() {
|
||||
if (GetRace() == HUMAN || GetRace() == BARBARIAN || GetRace() == ERUDITE || GetRace() == DRAKKIN)
|
||||
return 1;
|
||||
if (GetRace() == GNOME || GetRace() == HALFLING || GetRace() == DWARF || GetRace() == FROGLOK)
|
||||
return 2;
|
||||
if (GetRace() == HIGH_ELF || GetRace() == WOOD_ELF || GetRace() == HALF_ELF || GetRace() == VAHSHIR)
|
||||
return 3;
|
||||
if (GetRace() == DARK_ELF || GetRace() == OGRE || GetRace() == TROLL || GetRace() == IKSAR)
|
||||
return 4;
|
||||
return 1;
|
||||
}
|
||||
+4
-1
@@ -770,6 +770,9 @@ public:
|
||||
bool TradeskillExecute(DBTradeskillRecipe_Struct *spec);
|
||||
void CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, EQ::skills::SkillType tradeskill);
|
||||
void InitInnates();
|
||||
bool CanPvP(Client * c);
|
||||
int GetAlignment();
|
||||
int GetPVPRaceTeamBySize();
|
||||
|
||||
void GMKill();
|
||||
inline bool IsMedding() const {return medding;}
|
||||
@@ -903,7 +906,7 @@ public:
|
||||
void IncStats(uint8 type,int16 increase_val);
|
||||
void DropItem(int16 slot_id, bool recurse = true);
|
||||
void DropItemQS(EQ::ItemInstance* inst, bool pickup);
|
||||
|
||||
|
||||
int GetItemLinkHash(const EQ::ItemInstance* inst); // move to ItemData..or make use of the pre-calculated database field
|
||||
|
||||
void SendItemLink(const EQ::ItemInstance* inst, bool sendtoall=false);
|
||||
|
||||
+10
-1
@@ -2077,7 +2077,16 @@ void Client::HandleRespawnFromHover(uint32 Option)
|
||||
|
||||
CalcBonuses();
|
||||
SetHP(GetMaxHP());
|
||||
SetMana(GetMaxMana());
|
||||
if (GetPVP()) {
|
||||
int mana_pct = 100;
|
||||
if (RuleI(World, PVPSettings) > 0)
|
||||
mana_pct = 0; //All PVP servers spawn you with zero mana
|
||||
if (RuleI(Character, PVPRespawnManaPercent) != 100) //override mana if it's not 100%
|
||||
mana_pct = RuleI(Character, PVPRespawnManaPercent);
|
||||
SetMana(std::max(GetMaxMana() * mana_pct / 100, 0));
|
||||
} else {
|
||||
SetMana(GetMaxMana());
|
||||
}
|
||||
SetEndurance(GetMaxEndurance());
|
||||
|
||||
m_Position.x = chosen->x;
|
||||
|
||||
Reference in New Issue
Block a user