mirror of
https://github.com/EQEmu/Server.git
synced 2026-01-06 21:53:51 +00:00
Added PVP based logic
This commit is contained in:
parent
0f5a7e1317
commit
64b64222d1
7
.vscode/c_cpp_properties.json
vendored
7
.vscode/c_cpp_properties.json
vendored
@ -4,10 +4,13 @@
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"/usr/include/mysql"
|
||||
"/usr/include/mysql",
|
||||
"/usr/local/include",
|
||||
"/usr/include",
|
||||
"/usr/include/lua5.1"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"compilerPath": "/usr/bin/c++",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
}
|
||||
|
||||
@ -163,6 +163,7 @@ RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishin
|
||||
RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted")
|
||||
RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated")
|
||||
RULE_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared")
|
||||
RULE_INT(Character, PVPRespawnManaPercent, 100, "How much mana to respawn with")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
@ -239,6 +240,14 @@ RULE_INT(World, ExpansionSettings, 16383, "Sets the expansion settings for the s
|
||||
RULE_BOOL(World, UseClientBasedExpansionSettings, true, "If true it will overrule World, ExpansionSettings and set someone's expansion based on the client they're using")
|
||||
RULE_INT(World, PVPSettings, 0, "Sets the PVP settings for the server. 1=Rallos Zek RuleSet, 2=Tallon/Vallon Zek Ruleset, 4=Sullon Zek Ruleset, 6=Discord Ruleset, anything above 6 is the Discord Ruleset without the no-drop restrictions removed. NOTE: edit IsAttackAllowed in Zone-table to accomodate for these rules")
|
||||
RULE_INT(World, PVPMinLevel, 0, "Minimum level to pvp")
|
||||
RULE_BOOL(World, PVPUseDeityBasedPVP, false, "In PvP, deity is used to determine if a player can attack another.")
|
||||
RULE_BOOL(World, PVPUseTeamsBySizeBasedPVP, false, "In PVP, size of a race is used to determine if a player can attack another.")
|
||||
RULE_INT(World, PVPLevelDifference, 0, "In PvP, if value is greater than 0, players with a difference greater than value will not be attackable")
|
||||
RULE_INT(World, PVPLoseExperienceLevelDifference, 0, "In PvP, if value is greater than 0, players lose experience if killed by a player within level difference")
|
||||
RULE_INT(World, PVPPetDamageMitigation, 100, "In PvP, pet damage is mitigated by this amount")
|
||||
RULE_INT(World, PVPMeleeMitigation, 67, "In PvP, melee is mitigated by this amount")
|
||||
RULE_INT(World, PVPSpellMitigation, 67, "In PvP, spells are mitigated by this amount")
|
||||
RULE_INT(World, PVPRangedMitigation, 80, "In PvP, ranged attacks (archery/throwing) is mitigated by this amount")
|
||||
RULE_BOOL (World, IsGMPetitionWindowEnabled, false, "Setting whether the GM petition window is available")
|
||||
RULE_INT (World, FVNoDropFlag, 0, "Sets the Firiona Vie settings on the client, allowing trading of no-drop items. 1=for all players, 2=for GM only")
|
||||
RULE_BOOL (World, IPLimitDisconnectAll, false, "Disconnect all current clients by IP if they go over the IP limit. This should allow people to quickly reconnect in the case of dead sessions waiting to timeout")
|
||||
@ -390,6 +399,7 @@ RULE_BOOL(Spells, AllowItemTGB, false, "Target group buff (/tgb) doesn't work wi
|
||||
RULE_BOOL(Spells, NPCInnateProcOverride, true, "NPC innate procs override the target type to single target")
|
||||
RULE_BOOL(Spells, OldRainTargets, false, "Use old incorrectly implemented maximum targets for rains")
|
||||
RULE_BOOL(Spells, NPCSpellPush, false, "Enable spell push on NPCs")
|
||||
RULE_INT(Spells, PVPRootBreakFromSpells, 75, "Chance for root to break when cast on by a client")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Combat)
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user