This commit is contained in:
Michael Rath 2020-08-07 22:13:56 -07:00
commit c7ec3fa6ac
12 changed files with 619 additions and 200 deletions

View file

@ -323,6 +323,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="PkCommands.cpp" />
<ClCompile Include="ChatCommands.cpp" />
<ClCompile Include="Source\command\admin\ConfigCommands.cpp" />
<ClCompile Include="Source\command\admin\Alleg.cpp" />

View file

@ -759,6 +759,9 @@
<ClCompile Include="ChatCommands.cpp">
<Filter>Source Files\Command\Admin</Filter>
</ClCompile>
<ClCompile Include="PkCommands.cpp">
<Filter>Source Files\Command\Admin</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Source\crcwheel.h">

215
PkCommands.cpp Normal file
View file

@ -0,0 +1,215 @@
#include <StdAfx.h>
#include "ClientCommands.h"
#include "Player.h"
#include "Config.h"
CLIENT_COMMAND(getpksettings, "", "Prints out the current server PK CS/CB settings", ADMIN_ACCESS, GENERAL_CATEGORY)
{
pPlayer->SendText("Melee Settings", LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Base Chance: %f", g_pConfig->GetPkCSMeleeBaseChance()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Max Chance: %f", g_pConfig->GetPkCSMeleeMaxChance()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Skill Base: %d", g_pConfig->GetPkCSMeleeMinSkill()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Skill Max: %d", g_pConfig->GetPkCSMeleeMaxSkill()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Base Mutliplier: %f", g_pConfig->GetPkCBMeleeBaseMult()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Max Multiplier: %f", g_pConfig->GetPkCBMeleeMaxMult()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Skill Base: %d", g_pConfig->GetPkCBMeleeMinSkill()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Skill Max: %d", g_pConfig->GetPkCBMeleeMaxSkill()), LTT_DEFAULT);
pPlayer->SendText("Missile Settings", LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Base Chance: %f", g_pConfig->GetPkCSMissileBaseChance()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Max Chance: %f", g_pConfig->GetPkCSMissileMaxChance()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Skill Base: %d", g_pConfig->GetPkCSMissileMinSkill()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Skill Max: %d", g_pConfig->GetPkCSMissileMaxSkill()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Base Mutliplier: %f", g_pConfig->GetPkCBMissileBaseMult()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Max Multiplier: %f", g_pConfig->GetPkCBMissileMaxMult()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Skill Base: %d", g_pConfig->GetPkCBMissileMinSkill()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Skill Max: %d", g_pConfig->GetPkCBMissileMaxSkill()), LTT_DEFAULT);
pPlayer->SendText("Magic Settings", LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Base Chance: %f", g_pConfig->GetPkCSMagicBaseChance()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Max Chance: %f", g_pConfig->GetPkCSMagicMaxChance()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Skill Base: %d", g_pConfig->GetPkCSMagicMinSkill()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CS Skill Max: %d", g_pConfig->GetPkCSMagicMaxSkill()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Base Mutliplier: %f", g_pConfig->GetPkCBMagicBaseMult()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Max Multiplier: %f", g_pConfig->GetPkCBMagicMaxMult()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Skill Base: %d", g_pConfig->GetPkCBMagicMinSkill()), LTT_DEFAULT);
pPlayer->SendText(csprintf("CB Skill Max: %d", g_pConfig->GetPkCBMagicMaxSkill()), LTT_DEFAULT);
return false;
}
CLIENT_COMMAND(setpksetting, "[Combatmode] [Imbue] [Setting] [minmax] value", "Updates setting for melee|missile|magic CS|CB skill|chance|mult base|max", ADMIN_ACCESS, GENERAL_CATEGORY)
{
if (argc < 5)
{
pPlayer->SendText("Input invalid", LTT_DEFAULT);
return true;
}
std::string cmode(argv[0]);
std::transform(cmode.begin(), cmode.end(), cmode.begin(), ::tolower);
int combatMode = 0;
if (!stricmp(cmode.c_str(), "melee"))
{
combatMode = 1;
}
else if (!stricmp(cmode.c_str(), "melee"))
{
combatMode = 2;
}
else if (!stricmp(cmode.c_str(), "melee"))
{
combatMode = 3;
}
else
{
pPlayer->SendText("Invalid combat mode - melee or missile or magic", LTT_DEFAULT);
return true;
}
std::string imbue(argv[1]);
std::transform(imbue.begin(), imbue.end(), imbue.begin(), ::tolower);
int imbueType = 0;
if (!stricmp(imbue.c_str(), "cs"))
{
imbueType = 1;
}
else if (!stricmp(imbue.c_str(), "cb"))
{
imbueType = 2;
}
else
{
pPlayer->SendText("Invalid imbue - CS or CB", LTT_DEFAULT);
return true;
}
std::string setting(argv[2]);
std::transform(setting.begin(), setting.end(), setting.begin(), ::tolower);
int settingValue = 0;
if (!stricmp(setting.c_str(), "skill"))
{
settingValue = 1;
}
else if (!stricmp(setting.c_str(), "chance"))
{
settingValue = 2;
}
else if (!stricmp(setting.c_str(), "mult"))
{
settingValue = 3;
}
else
{
pPlayer->SendText("Invalid setting - skill or chance", LTT_DEFAULT);
return true;
}
std::string minmax(argv[3]);
std::transform(minmax.begin(), minmax.end(), minmax.begin(), ::tolower);
int minmaxValue = 0;
if (!stricmp(minmax.c_str(), "base"))
{
minmaxValue = 1;
}
else if (!stricmp(minmax.c_str(), "max"))
{
minmaxValue = 2;
}
else
{
pPlayer->SendText("Invalid value - min or max", LTT_DEFAULT);
return true;
}
if (combatMode == 1 && imbueType == 1 && settingValue == 1)
{
if (minmaxValue == 1)
g_pConfig->SetPkCSMeleeMinSkill(stoi(argv[4], NULL, 10));
else
g_pConfig->SetPkCSMeleeMaxSkill(stoi(argv[4], NULL, 10));
}
else if (combatMode == 1 && imbueType == 1 && settingValue == 2)
{
if (minmaxValue == 1)
g_pConfig->SetPkCSMeleeBaseChance(atof(argv[4]));
else
g_pConfig->SetPkCSMeleeMaxChance(atof(argv[4]));
}
else if (combatMode == 1 && imbueType == 2 && settingValue == 1)
{
if (minmaxValue == 1)
g_pConfig->SetPkCBMeleeMinSkill(stoi(argv[4], NULL, 10));
else
g_pConfig->SetPkCBMeleeMaxSkill(stoi(argv[4], NULL, 10));
}
else if (combatMode == 1 && imbueType == 2 && settingValue == 3)
{
if (minmaxValue == 1)
g_pConfig->SetPkCBMeleeBaseMult(atof(argv[4]));
else
g_pConfig->SetPkCBMeleeMaxMult(atof(argv[4]));
}
else if (combatMode == 2 && imbueType == 1 && settingValue == 1)
{
if (minmaxValue == 1)
g_pConfig->SetPkCSMissileMinSkill(stoi(argv[4], NULL, 10));
else
g_pConfig->SetPkCSMissileMaxSkill(stoi(argv[4], NULL, 10));
}
else if (combatMode == 2 && imbueType == 1 && settingValue == 2)
{
if (minmaxValue == 1)
g_pConfig->SetPkCSMissileBaseChance(atof(argv[4]));
else
g_pConfig->SetPkCSMissileMaxChance(atof(argv[4]));
}
else if (combatMode == 2 && imbueType == 2 && settingValue == 1)
{
if (minmaxValue == 1)
g_pConfig->SetPkCBMissileMinSkill(stoi(argv[4], NULL, 10));
else
g_pConfig->SetPkCBMissileMaxSkill(stoi(argv[4], NULL, 10));
}
else if (combatMode == 2 && imbueType == 2 && settingValue == 3)
{
if (minmaxValue == 1)
g_pConfig->SetPkCBMissileBaseMult(atof(argv[4]));
else
g_pConfig->SetPkCBMissileMaxMult(atof(argv[4]));
}
else if (combatMode == 3 && imbueType == 1 && settingValue == 1)
{
if (minmaxValue == 1)
g_pConfig->SetPkCSMagicMinSkill(stoi(argv[4], NULL, 10));
else
g_pConfig->SetPkCSMagicMaxSkill(stoi(argv[4], NULL, 10));
}
else if (combatMode == 3 && imbueType == 1 && settingValue == 2)
{
if (minmaxValue == 1)
g_pConfig->SetPkCSMagicBaseChance(atof(argv[4]));
else
g_pConfig->SetPkCSMagicMaxChance(atof(argv[4]));
}
else if (combatMode == 3 && imbueType == 2 && settingValue == 1)
{
if (minmaxValue == 1)
g_pConfig->SetPkCBMagicMinSkill(stoi(argv[4], NULL, 10));
else
g_pConfig->SetPkCBMagicMaxSkill(stoi(argv[4], NULL, 10));
}
else if (combatMode == 3 && imbueType == 2 && settingValue == 3)
{
if (minmaxValue == 1)
g_pConfig->SetPkCBMagicBaseMult(atof(argv[4]));
else
g_pConfig->SetPkCBMagicMaxMult(atof(argv[4]));
}
else
{
pPlayer->SendText("Invalid value combination", LTT_DEFAULT);
return true;
}
return false;
}

View file

@ -173,6 +173,7 @@ void CPhatACServerConfig::PostLoad()
m_bUpdateAllegianceData = atoi(GetValue("update_allegiance_blob", "0")) != 0;
m_bInventoryPurgeOnLogin = atoi(GetValue("inventory_purge_on_login", "0")) != 0;
m_bRatingPurgeOnLogin = atoi(GetValue("reset_ratings_on_login", "0")) != 0;
m_bAllowCoalDispel = atoi(GetValue("allow_coal_dispel", "1")) != 0;
m_WcidForPurge = (unsigned int)max(0, atoi(GetValue("wcid_for_purge", "100000")));
@ -196,6 +197,34 @@ void CPhatACServerConfig::PostLoad()
m_fellowManaThreshold = max(0.0, atof(GetValue("fellow_update_mana", "0.3")));
m_missileAttribAdjust = max(0.0, atof(GetValue("missile_attr_adj", "0.0")));
pkCSmeleebasechance = max(0.0, atof(GetValue("pk_cs_melee_base_chance", "0.1")));
pkCSmeleeminskill = atoi(GetValue("pk_cs_melee_min_skill", "150"));
pkCSmeleemaxskill = atoi(GetValue("pk_cs_melee_max_skill", "400"));
pkCSmeleemaxchance = max(0.0, atof(GetValue("pk_cs_melee_max_chance", "0.5")));
pkCBmeleebasemult = max(0.0, atof(GetValue("pk_cb_melee_base_mult", "1")));
pkCBmeleeminskill = atoi(GetValue("pk_cb_melee_min_skill", "150"));
pkCBmeleemaxskill = atoi(GetValue("pk_cb_melee_max_skill", "400"));
pkCBmeleemaxmult = max(0.0, atof(GetValue("pk_cb_melee_max_mult", "7")));
pkCSmissilebasechance = max(0.0, atof(GetValue("pk_cs_missile_base_chance", "0.1")));
pkCSmissileminskill = atoi(GetValue("pk_cs_missile_min_skill", "125"));
pkCSmissilemaxskill = atoi(GetValue("pk_cs_missile_max_skill", "360"));
pkCSmissilemaxchance = max(0.0, atof(GetValue("pk_cs_missile_max_chance", "0.5")));
pkCBmissilebasemult = max(0.0, atof(GetValue("pk_cb_missile_base_mult", "1")));
pkCBmissileminskill = atoi(GetValue("pk_cb_missile_min_skill", "125"));
pkCBmissilemaxskill = atoi(GetValue("pk_cb_missile_max_skill", "360"));
pkCBmissilemaxmult = max(0.0, atof(GetValue("pk_cb_missile_max_mult", "7")));
pkCSmagicbasechance = max(0.0, atof(GetValue("pk_cs_magic_base_chance", "0.05")));
pkCSmagicminskill = atoi(GetValue("pk_cs_magic_min_skill", "125"));
pkCSmagicmaxskill = atoi(GetValue("pk_cs_magic_max_skill", "360"));
pkCSmagicmaxchance = max(0.0, atof(GetValue("pk_cs_magic_max_chance", "0.25")));
pkCBmagicbasemult = max(0.0, atof(GetValue("pk_cb_magic_base_mult", "0.5")));
pkCBmagicminskill = atoi(GetValue("pk_cb_magic_min_skill", "125"));
pkCBmagicmaxskill = atoi(GetValue("pk_cb_magic_max_skill", "360"));
pkCBmagicmaxmult = max(0.0, atof(GetValue("pk_cb_magic_max_mult", "1")));
m_defaultallegchatgagtime = max(0.0, atof(GetValue("alleg_gag_time", "300")));
}

View file

@ -129,6 +129,62 @@ public:
virtual uint32_t GetDeleteCharLifespan() { return m_defaultsecondstofullchardelete; }
float GetPkCSMeleeBaseChance() { return pkCSmeleebasechance; }
void SetPkCSMeleeBaseChance(float newValue) { pkCSmeleebasechance = max(0.0f, newValue); }
uint32_t GetPkCSMeleeMinSkill() { return pkCSmeleeminskill; }
void SetPkCSMeleeMinSkill(uint32_t newValue) { pkCSmeleeminskill = max((uint32_t)1, newValue); }
uint32_t GetPkCSMeleeMaxSkill() { return pkCSmeleemaxskill; }
void SetPkCSMeleeMaxSkill(uint32_t newValue) { pkCSmeleemaxskill = max((uint32_t)1, newValue); }
float GetPkCSMeleeMaxChance() { return pkCSmeleemaxchance; }
void SetPkCSMeleeMaxChance(float newValue) { pkCSmeleemaxchance = max(0.0f, newValue); }
float GetPkCBMeleeBaseMult() { return pkCBmeleebasemult; }
void SetPkCBMeleeBaseMult(float newValue) { pkCBmeleebasemult = max(0.0f, newValue); }
uint32_t GetPkCBMeleeMinSkill() { return pkCBmeleeminskill; }
void SetPkCBMeleeMinSkill(uint32_t newValue) { pkCBmeleeminskill = max((uint32_t)1, newValue); }
uint32_t GetPkCBMeleeMaxSkill() { return pkCBmeleemaxskill; }
void SetPkCBMeleeMaxSkill(uint32_t newValue) { pkCBmeleemaxskill = max((uint32_t)1, newValue); }
float GetPkCBMeleeMaxMult() { return pkCBmeleemaxmult; }
void SetPkCBMeleeMaxMult(float newValue) { pkCBmeleemaxmult = max(0.0f, newValue); }
float GetPkCSMissileBaseChance() { return pkCSmissilebasechance; }
void SetPkCSMissileBaseChance(float newValue) { pkCSmissilebasechance = max(0.0f, newValue); }
uint32_t GetPkCSMissileMinSkill() { return pkCSmissileminskill; }
void SetPkCSMissileMinSkill(uint32_t newValue) { pkCSmissileminskill = max((uint32_t)1, newValue); }
uint32_t GetPkCSMissileMaxSkill() { return pkCSmissilemaxskill; }
void SetPkCSMissileMaxSkill(uint32_t newValue) { pkCSmissilemaxskill = max((uint32_t)1, newValue); }
float GetPkCSMissileMaxChance() { return pkCSmissilemaxchance; }
void SetPkCSMissileMaxChance(float newValue) { pkCSmissilemaxchance = max(0.0f, newValue); }
float GetPkCBMissileBaseMult() { return pkCBmissilebasemult; }
void SetPkCBMissileBaseMult(float newValue) { pkCBmissilebasemult = max(0.0f, newValue); }
uint32_t GetPkCBMissileMinSkill() { return pkCBmissileminskill; }
void SetPkCBMissileMinSkill(uint32_t newValue) { pkCBmissileminskill = max((uint32_t)1, newValue); }
uint32_t GetPkCBMissileMaxSkill() { return pkCBmissilemaxskill; }
void SetPkCBMissileMaxSkill(uint32_t newValue) { pkCBmissilemaxskill = max((uint32_t)1, newValue); }
float GetPkCBMissileMaxMult() { return pkCBmissilemaxmult; }
void SetPkCBMissileMaxMult(float newValue) { pkCBmissilemaxmult = max(0.0f, newValue); }
float GetPkCSMagicBaseChance() { return pkCSmagicbasechance; }
void SetPkCSMagicBaseChance(float newValue) { pkCSmagicbasechance = max(0.0f, newValue); }
uint32_t GetPkCSMagicMinSkill() { return pkCSmagicminskill; }
void SetPkCSMagicMinSkill(uint32_t newValue) { pkCSmagicminskill = max((uint32_t)1, newValue); }
uint32_t GetPkCSMagicMaxSkill() { return pkCSmagicmaxskill; }
void SetPkCSMagicMaxSkill(uint32_t newValue) { pkCSmagicmaxskill = max((uint32_t)1, newValue); }
float GetPkCSMagicMaxChance() { return pkCSmagicmaxchance; }
void SetPkCSMagicMaxChance(float newValue) { pkCSmagicmaxchance = max(0.0f, newValue); }
float GetPkCBMagicBaseMult() { return pkCBmagicbasemult; }
void SetPkCBMagicBaseMult(float newValue) { pkCBmagicbasemult = max(0.0f, newValue); }
uint32_t GetPkCBMagicMinSkill() { return pkCBmagicminskill; }
void SetPkCBMagicMinSkill(uint32_t newValue) { pkCBmagicminskill = max((uint32_t)1, newValue); }
uint32_t GetPkCBMagicMaxSkill() { return pkCBmagicmaxskill; }
void SetPkCBMagicMaxSkill(uint32_t newValue) { pkCBmagicmaxskill = max((uint32_t)1, newValue); }
float GetPkCBMagicMaxMult() { return pkCBmagicmaxmult; }
void SetPkCBMagicMaxMult(float newValue) { pkCBmagicmaxmult = max(0.0f, newValue); }
bool AllowCoalDispel() { return m_bAllowCoalDispel; } // TODO add set
virtual float GetAllegianceGagTime() { return m_defaultallegchatgagtime; }
protected:
@ -235,6 +291,35 @@ protected:
float m_missileAttribAdjust = 0.0;
float pkCSmeleebasechance = 0.1f;
uint32_t pkCSmeleeminskill = 150;
uint32_t pkCSmeleemaxskill = 400;
float pkCSmeleemaxchance = 0.5f;
float pkCBmeleebasemult = 1.0f;
uint32_t pkCBmeleeminskill = 150;
uint32_t pkCBmeleemaxskill = 400;
float pkCBmeleemaxmult = 7.0f;
float pkCSmissilebasechance = 0.1f;
uint32_t pkCSmissileminskill = 125;
uint32_t pkCSmissilemaxskill = 360;
float pkCSmissilemaxchance = 0.5f;
float pkCBmissilebasemult = 1.0f;
uint32_t pkCBmissileminskill = 125;
uint32_t pkCBmissilemaxskill = 360;
float pkCBmissilemaxmult = 7.0f;
float pkCSmagicbasechance = 0.05f;
uint32_t pkCSmagicminskill = 125;
uint32_t pkCSmagicmaxskill = 360;
float pkCSmagicmaxchance = 0.25f;
float pkCBmagicbasemult = 0.5f;
uint32_t pkCBmagicminskill = 125;
uint32_t pkCBmagicmaxskill = 360;
float pkCBmagicmaxmult = 1.0f;
bool m_bAllowCoalDispel = true;
float m_defaultallegchatgagtime = 300;
};

View file

@ -586,7 +586,7 @@ bool CMonsterWeenie::MoveItemToContainer(uint32_t sourceItemId, uint32_t targetC
return false;
}
sourceItem->m_Qualities.SetInstanceID(FREEZER_IID, 0);
sourceItem->m_Qualities.SetInstanceID(FREEZER_IID, GetID());
bool isExternalTargetContainer = (targetContainer->GetTopLevelID() != GetID());
@ -737,14 +737,7 @@ bool CMonsterWeenie::MoveItemTo3D(uint32_t sourceItemId, bool animationDone)
NotifyInventoryFailedEvent(sourceItemId, WERROR_ATTUNED_ITEM);
return false;
}
//// Temporarily disallow dropping stackable items.
//if (sourceItem->m_Qualities.GetInt(MAX_STACK_SIZE_INT, 0) > 1)
//{
// NotifyInventoryFailedEvent(sourceItemId, WERROR_ATTUNED_ITEM);
// return false;
//}
uint32_t freezer = sourceItem->InqIIDQuality(FREEZER_IID, 0);
if (freezer != 0 && freezer != GetID())
{
@ -2951,11 +2944,10 @@ float CMonsterWeenie::GetEffectiveArmorLevel(DamageEventData &damageData, bool b
//equipment
for (auto item : wielded)
buffDetails.rawValue += item->GetEffectiveArmorLevel(damageData, bIgnoreMagicArmor);
if (damageData.isArmorRending && damageData.armorRendingMultiplier < buffDetails.valueDecreasingMultiplier)
buffDetails.valueDecreasingMultiplier = damageData.armorRendingMultiplier;
buffDetails.CalculateEnchantedValue();
if (bIgnoreMagicArmor)
return buffDetails.rawValue; //Take the Raw value for Hollows. Debuffs should not count.
else

View file

@ -3,8 +3,13 @@
#include "CombatFormulas.h"
#include "Config.h"
double GetImbueMultiplier(double currentSkill, double minEffectivenessSkill, double maxEffectivenessSkill, double maxMultiplier, bool allowNegative)
double GetImbueMultiplier(double currentSkill, double minEffectivenessSkill, double maxEffectivenessSkill, double minMultiplier, double maxMultiplier, bool allowNegative)
{
if (currentSkill < minEffectivenessSkill)
return minMultiplier;
if (currentSkill > maxEffectivenessSkill)
return maxMultiplier;
double multiplier = (currentSkill - minEffectivenessSkill) / (maxEffectivenessSkill - minEffectivenessSkill);
double value = multiplier * maxMultiplier;
if (!allowNegative)
@ -153,6 +158,9 @@ void CalculateSkillDamageBonus(DamageEventData *dmgEvent, SpellCastData *spellDa
skillDamageMod = (spellData->current_skill - (difficulty - 75)) / (difficulty - (difficulty - 75));
}
if (dmgEvent->isPvP)
skillDamageMod *= 0.5;
if (skillDamageMod > 0)
dmgEvent->skillDamageBonus = minDamage * skillDamageMod;
}
@ -192,16 +200,13 @@ void CalculateCriticalHitData(DamageEventData *dmgEvent, SpellCastData *spellDat
dmgEvent->critMultiplier += dmgEvent->weapon->GetCrushingBlowMultiplier();
if (imbueEffects & CriticalStrike_ImbuedEffectType)
dmgEvent->critChance += GetImbueMultiplier(dmgEvent->attackSkillLevel, 150, 400, 0.5);
dmgEvent->critChance = GetImbueMultiplier(dmgEvent->attackSkillLevel, dmgEvent->isPvP ? g_pConfig->GetPkCSMeleeMinSkill() : 150, dmgEvent->isPvP ? g_pConfig->GetPkCSMeleeMaxSkill() : 400,
dmgEvent->isPvP ? g_pConfig->GetPkCSMeleeBaseChance() : dmgEvent->critChance, dmgEvent->isPvP ? g_pConfig->GetPkCSMeleeMaxChance() : 0.5);
if (imbueEffects & CripplingBlow_ImbuedEffectType)
dmgEvent->critMultiplier += GetImbueMultiplier(dmgEvent->attackSkillLevel, 150, 400, 6);
dmgEvent->critMultiplier = GetImbueMultiplier(dmgEvent->attackSkillLevel, dmgEvent->isPvP ? g_pConfig->GetPkCBMeleeMinSkill() : 150, dmgEvent->isPvP ? g_pConfig->GetPkCBMeleeMaxSkill() : 400,
dmgEvent->isPvP ? g_pConfig->GetPkCBMeleeBaseMult() : dmgEvent->critMultiplier, 7);
if (bool critExpertise = dmgEvent->source->m_Qualities.GetInt(AUGMENTATION_CRITICAL_EXPERTISE_INT, 0))
dmgEvent->critChance += 0.01;
dmgEvent->critMultiplier = min(max(dmgEvent->critMultiplier, 0.0), 7.0);
dmgEvent->critChance = min(max(dmgEvent->critChance, 0.0), 0.5);
return;
case DF_MISSILE:
dmgEvent->critChance = 0.1;
@ -219,16 +224,13 @@ void CalculateCriticalHitData(DamageEventData *dmgEvent, SpellCastData *spellDat
dmgEvent->critMultiplier += dmgEvent->weapon->GetCrushingBlowMultiplier();
if (imbueEffects & CriticalStrike_ImbuedEffectType)
dmgEvent->critChance += GetImbueMultiplier(dmgEvent->attackSkillLevel, 125, 360, 0.5);
dmgEvent->critChance = GetImbueMultiplier(dmgEvent->attackSkillLevel, dmgEvent->isPvP ? g_pConfig->GetPkCSMissileMinSkill() : 125, dmgEvent->isPvP ? g_pConfig->GetPkCSMissileMaxSkill() : 360,
dmgEvent->isPvP ? g_pConfig->GetPkCSMissileBaseChance() : dmgEvent->critChance, dmgEvent->isPvP ? g_pConfig->GetPkCSMissileMaxChance() : 0.5);
if (imbueEffects & CripplingBlow_ImbuedEffectType)
dmgEvent->critMultiplier += GetImbueMultiplier(dmgEvent->attackSkillLevel, 125, 360, 6);
dmgEvent->critMultiplier = GetImbueMultiplier(dmgEvent->attackSkillLevel, dmgEvent->isPvP ? g_pConfig->GetPkCBMissileMinSkill() : 125, dmgEvent->isPvP ? g_pConfig->GetPkCBMissileMaxSkill() : 360,
dmgEvent->isPvP ? g_pConfig->GetPkCBMissileBaseMult() : dmgEvent->critMultiplier, 7);
if (bool critExpertise = dmgEvent->source->m_Qualities.GetInt(AUGMENTATION_CRITICAL_EXPERTISE_INT, 0))
dmgEvent->critChance += 0.01;
dmgEvent->critMultiplier = min(max(dmgEvent->critMultiplier, 0.0), 7.0);
dmgEvent->critChance = min(max(dmgEvent->critChance, 0.0), 0.5);
return;
case DF_MAGIC:
dmgEvent->critChance = 0.05;
@ -250,45 +252,22 @@ void CalculateCriticalHitData(DamageEventData *dmgEvent, SpellCastData *spellDat
ProjectileSpellEx *meta = (ProjectileSpellEx *)spellData->spellEx->_meta_spell._spell;
if (dmgEvent->attackSkill == WAR_MAGIC_SKILL || (dmgEvent->attackSkill == VOID_MAGIC_SKILL && meta->AsProjectileSpell()))
{
//Imbue and slayer effects for War Magic now scale from minimum effectiveness at 125 to
//maximum effectiveness at 360 skill instead of from 150 to 400 skill(PvM only).
//maximum effectiveness at 360 skill
//Critical Strike for War Magic scales from 5% critical hit chance to 50% critical hit chance at maximum effectiveness.
//PvP: Critical Strike for War Magic scales from 5% critical hit chance to 25% critical hit chance at maximum effectiveness.
if (imbueEffects & CriticalStrike_ImbuedEffectType)
{
//Critical Strike for War Magic scales from 5% critical hit chance to 50% critical hit chance at maximum effectiveness.
//PvP: Critical Strike for War Magic scales from 5% critical hit chance to 25% critical hit chance at maximum effectiveness.
if (dmgEvent->isPvP)
dmgEvent->critChance += GetImbueMultiplier(dmgEvent->attackSkillLevel, 125, 360, 0.25);
else
dmgEvent->critChance += GetImbueMultiplier(dmgEvent->attackSkillLevel, 125, 360, 0.5);
}
dmgEvent->critChance = GetImbueMultiplier(dmgEvent->attackSkillLevel, dmgEvent->isPvP ? g_pConfig->GetPkCSMagicMinSkill() : 125, dmgEvent->isPvP ? g_pConfig->GetPkCSMagicMaxSkill() : 360,
dmgEvent->isPvP ? g_pConfig->GetPkCSMagicBaseChance() : dmgEvent->critChance, dmgEvent->isPvP ? g_pConfig->GetPkCSMagicMaxChance() : 0.5);
//Crippling Blow for War Magic currently scales from adding 50% of the spells damage
//on critical hits to adding 500% at maximum effectiveness.
//PvP: Crippling Blow for War Magic currently scales from adding 50 % of the spells damage on critical hits
//to adding 100 % at maximum effectiveness
if (imbueEffects & CripplingBlow_ImbuedEffectType)
{
//Crippling Blow for War Magic currently scales from adding 50% of the spells damage
//on critical hits to adding 500% at maximum effectiveness.
//PvP: Crippling Blow for War Magic currently scales from adding 50 % of the spells damage on critical hits
//to adding 100 % at maximum effectiveness
if (dmgEvent->isPvP)
dmgEvent->critMultiplier += GetImbueMultiplier(dmgEvent->attackSkillLevel, 125, 360, 1);
else
dmgEvent->critMultiplier += GetImbueMultiplier(dmgEvent->attackSkillLevel, 125, 360, 5.0);
}
}
if (bool critExpertise = dmgEvent->source->m_Qualities.GetInt(AUGMENTATION_CRITICAL_EXPERTISE_INT, 0))
dmgEvent->critChance += 0.01;
if (isPvP)
{
dmgEvent->critChance = min(max(dmgEvent->critChance, 0.0), 0.25);
dmgEvent->critMultiplier = min(max(dmgEvent->critMultiplier, 0.0), 1.0);
}
else
{
dmgEvent->critChance = min(max(dmgEvent->critChance, 0.0), 0.50);
dmgEvent->critMultiplier = min(max(dmgEvent->critMultiplier, 0.0), 5.0);
dmgEvent->critMultiplier = GetImbueMultiplier(dmgEvent->attackSkillLevel, dmgEvent->isPvP ? g_pConfig->GetPkCBMagicMinSkill() : 125, dmgEvent->isPvP ? g_pConfig->GetPkCBMagicMaxSkill() : 360,
dmgEvent->isPvP ? g_pConfig->GetPkCBMagicBaseMult() : dmgEvent->critMultiplier, 5);
}
return;
@ -314,8 +293,20 @@ void CalculateSlayerData(DamageEventData *dmgEvent)
if (slayerType && slayerType == dmgEvent->target->InqIntQuality(CREATURE_TYPE_INT, 0, TRUE))
slayerDamageMod = dmgEvent->weapon->InqFloatQuality(SLAYER_DAMAGE_BONUS_FLOAT, 0.0, FALSE);
if (slayerDamageMod > 0.0)
dmgEvent->slayerDamageBonus = dmgEvent->baseDamage * (slayerDamageMod - 1.0);
double slayerSkillMod = 1.0;
switch (dmgEvent->damage_form)
{
case DF_MELEE:
slayerSkillMod = GetImbueMultiplier(dmgEvent->attackSkillLevel, 150, 400, 1.0, slayerDamageMod);
break;
case DF_MISSILE:
case DF_MAGIC:
slayerSkillMod = GetImbueMultiplier(dmgEvent->attackSkillLevel, 125, 360, 1.0, slayerDamageMod);
break;
}
if (slayerSkillMod > 0.0)
dmgEvent->slayerDamageBonus = dmgEvent->baseDamage * (slayerSkillMod - 1.0);
}
void CalculateRendingAndMiscData(DamageEventData *dmgEvent)
@ -382,13 +373,13 @@ void CalculateRendingAndMiscData(DamageEventData *dmgEvent)
switch (dmgEvent->damage_form)
{
case DF_MELEE:
dmgEvent->rendingMultiplier = max(GetImbueMultiplier(dmgEvent->attackSkillLevel, 0, 400, 2.5), 1.0);
dmgEvent->rendingMultiplier = max(GetImbueMultiplier(dmgEvent->attackSkillLevel, 0, 400, 1.0, 2.5), 1.0);
break;
case DF_MISSILE:
dmgEvent->rendingMultiplier = max(0.25 + GetImbueMultiplier(dmgEvent->attackSkillLevel, 0, 360, 2.25), 1.0);
dmgEvent->rendingMultiplier = max(0.25 + GetImbueMultiplier(dmgEvent->attackSkillLevel, 0, 360, 1.0, 2.25), 1.0);
break;
case DF_MAGIC:
dmgEvent->rendingMultiplier = max(0.25 + GetImbueMultiplier(dmgEvent->attackSkillLevel, 0, 360, 2.25), 1.0);
dmgEvent->rendingMultiplier = max(0.25 + GetImbueMultiplier(dmgEvent->attackSkillLevel, 0, 360, 1.0, 2.25), 1.0);
break;
default:
return;
@ -400,7 +391,7 @@ void CalculateRendingAndMiscData(DamageEventData *dmgEvent)
if (dmgEvent->weapon->m_Qualities.InqInt(RESISTANCE_MODIFIER_TYPE_INT, resistanceMod))
dmgEvent->isResistanceCleaving = TRUE;
if (dmgEvent->isResistanceCleaving)
if (dmgEvent->isResistanceCleaving && !dmgEvent->isElementalRending)
{
if (resistanceMod == dmgEvent->damage_type)
dmgEvent->isElementalRending = true;
@ -426,10 +417,10 @@ void CalculateRendingAndMiscData(DamageEventData *dmgEvent)
switch (dmgEvent->damage_form)
{
case DF_MELEE:
dmgEvent->armorRendingMultiplier = 1.0 / max(GetImbueMultiplier(dmgEvent->attackSkillLevel, 0, 400, 2.5), 1.0);
dmgEvent->armorRendingMultiplier = 1.0 / max(GetImbueMultiplier(dmgEvent->attackSkillLevel, 150, 400, 1.0, 2.5), 1.0);
break;
case DF_MISSILE:
dmgEvent->armorRendingMultiplier = 1.0 / max(0.25 + GetImbueMultiplier(dmgEvent->attackSkillLevel, 0, 360, 2.25), 1.0);
dmgEvent->armorRendingMultiplier = 1.0 / max(0.25 + GetImbueMultiplier(dmgEvent->attackSkillLevel, 125, 360, 1.0, 2.25), 1.0);
break;
case DF_MAGIC:
default:
@ -440,7 +431,7 @@ void CalculateRendingAndMiscData(DamageEventData *dmgEvent)
if (dmgEvent->weapon->InqFloatQuality(IGNORE_ARMOR_FLOAT, 0, FALSE))
dmgEvent->isArmorCleaving = TRUE;
if (dmgEvent->isArmorCleaving)
if (dmgEvent->isArmorCleaving && !dmgEvent->isArmorRending)
{
switch (dmgEvent->damage_form)
{

View file

@ -2,7 +2,7 @@
#include "SpellcastingManager.h"
#include "WeenieObject.h"
double GetImbueMultiplier(double currentSkill, double minEffectivenessSkill, double maxEffectivenessSkill, double maxMultiplier, bool allowNegative = false);
double GetImbueMultiplier(double currentSkill, double minEffectivenessSkill, double maxEffectivenessSkill, double minMultiplier, double maxMultiplier, bool allowNegative = false);
void CalculateDamage(DamageEventData *dmgEvent, SpellCastData *spellData = NULL);
void CalculateAttributeDamageBonus(DamageEventData *dmgEvent);
void CalculateSkillDamageBonus(DamageEventData *dmgEvent, SpellCastData *spellData);

View file

@ -866,7 +866,7 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
bFizzled = true;
}
else if (!bFizzled && m_pWeenie->m_Position.distance(m_SpellCastData.initial_cast_position) >= 6.0 && m_pWeenie->m_Qualities.GetInt(PLAYER_KILLER_STATUS_INT, 0) == PK_PKStatus)
else if (!bFizzled && m_pWeenie->m_Position.distance(m_SpellCastData.initial_cast_position) >= 6.0)
{
// fizzle
m_pWeenie->EmitEffect(PS_Fizzle, 0.542734265f);
@ -932,6 +932,9 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
m_pWeenie->m_Qualities.SetInt(ITEM_CUR_MANA_INT, m_pWeenie->InqIntQuality(ITEM_CUR_MANA_INT, 0, 0) - m_SpellCastData.spell->_base_mana);
}
CWeenieObject *target = GetCastTarget();
if (!VerifyPkAction(target))
return WERROR_NONE;
bool bSpellPerformed = false;
@ -955,8 +958,6 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
FellowshipBoostSpellEx *meta = (FellowshipBoostSpellEx *)m_SpellCastData.spellEx->_meta_spell._spell;
CWeenieObject *target = GetCastTarget();
if (!target->HasFellowship())
break;
@ -970,8 +971,10 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
if (member->GetBlock() == block)
{
bSpellPerformed = AdjustVital(member);
if (!VerifyPkAction(member))
return WERROR_NONE;
else
bSpellPerformed = AdjustVital(member);
}
}
}
@ -989,27 +992,26 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
int numToDispel = Random::GenInt(minNum, maxNum);
CWeenieObject *pTarget = GetCastTarget();
if (pTarget)
if (target)
{
if (pTarget->AsPlayer() && pTarget->AsPlayer()->CheckPKActivity())
if (target->AsPlayer() && target->AsPlayer()->CheckPKActivity())
{
if (m_pWeenie->AsPlayer() && m_pWeenie->GetID() == pTarget->GetID())
if (m_pWeenie->AsPlayer() && m_pWeenie->GetID() == target->GetID())
{
if (m_pWeenie->AsPlayer())
m_pWeenie->AsPlayer()->SendText("You have been involved in Player Killer combat too recently!", LTT_MAGIC);
break;
}
if (pTarget->AsPlayer() && pTarget->AsPlayer()->CheckPKActivity())
if (target->AsPlayer() && target->AsPlayer()->CheckPKActivity())
{
if (m_pWeenie->AsPlayer())
m_pWeenie->AsPlayer()->SendText(csprintf("%s has been involved in Player Killer combat too recently!", pTarget->GetName().c_str()), LTT_MAGIC);
m_pWeenie->AsPlayer()->SendText(csprintf("%s has been involved in Player Killer combat too recently!", target->GetName().c_str()), LTT_MAGIC);
break;
}
}
if (!(m_SpellCastData.spell->_bitfield & Beneficial_SpellIndex))
{
if (pTarget->GetWorldTopLevelOwner()->ImmuneToDamage(m_pWeenie))
if (target->GetWorldTopLevelOwner()->ImmuneToDamage(m_pWeenie))
{
break;
}
@ -1017,11 +1019,11 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
PackableListWithJson<uint32_t> possibleToDispel;
if (pTarget->m_Qualities._enchantment_reg)
if (target->m_Qualities._enchantment_reg)
{
if (pTarget->m_Qualities._enchantment_reg->_add_list)
if (target->m_Qualities._enchantment_reg->_add_list)
{
for (auto &entry : *pTarget->m_Qualities._enchantment_reg->_add_list)
for (auto &entry : *target->m_Qualities._enchantment_reg->_add_list)
{
if (entry._power_level > meta->_max_power)
continue;
@ -1031,6 +1033,8 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
continue;
if ((entry._id & 0xFFFF) == 666) // vitae
continue;
if (entry._id == 3204 && g_pConfig->AllowCoalDispel())
continue;
if (CSpellTableEx *pSpellTableEx = g_pPortalDataEx->GetSpellTableEx())
{
@ -1067,9 +1071,9 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
}
}
if (pTarget->m_Qualities._enchantment_reg->_mult_list)
if (target->m_Qualities._enchantment_reg->_mult_list)
{
for (auto &entry : *pTarget->m_Qualities._enchantment_reg->_mult_list)
for (auto &entry : *target->m_Qualities._enchantment_reg->_mult_list)
{
if (entry._power_level > meta->_max_power)
continue;
@ -1079,6 +1083,8 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
continue;
if ((entry._id & 0xFFFF) == 666) // vitae
continue;
if (entry._id == 3204 && g_pConfig->AllowCoalDispel())
continue;
if (CSpellTableEx *pSpellTableEx = g_pPortalDataEx->GetSpellTableEx())
{
@ -1162,36 +1168,36 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
if (listToDispel.size() > 0)
{
if (pTarget == m_pWeenie)
if (target == m_pWeenie)
{
m_pWeenie->SendText(csprintf("You cast %s on yourself and dispel: %s", m_SpellCastData.spell->_name.c_str(), spellNames.c_str()), LTT_MAGIC);
}
else
{
m_pWeenie->SendText(csprintf("You cast %s on %s and dispel: %s", m_SpellCastData.spell->_name.c_str(), pTarget->GetName().c_str(), spellNames.c_str()), LTT_MAGIC);
pTarget->SendText(csprintf("%s casts %s on you and dispels: %s", m_pWeenie->GetName().c_str(), m_SpellCastData.spell->_name.c_str(), spellNames.c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("You cast %s on %s and dispel: %s", m_SpellCastData.spell->_name.c_str(), target->GetName().c_str(), spellNames.c_str()), LTT_MAGIC);
target->SendText(csprintf("%s casts %s on you and dispels: %s", m_pWeenie->GetName().c_str(), m_SpellCastData.spell->_name.c_str(), spellNames.c_str()), LTT_MAGIC);
}
if (pTarget->m_Qualities._enchantment_reg)
if (target->m_Qualities._enchantment_reg)
{
pTarget->m_Qualities._enchantment_reg->RemoveEnchantments(&listToDispel);
target->m_Qualities._enchantment_reg->RemoveEnchantments(&listToDispel);
BinaryWriter expireMessage;
expireMessage.Write<uint32_t>(0x2C8);
listToDispel.Pack(&expireMessage);
pTarget->SendNetMessage(&expireMessage, PRIVATE_MSG, TRUE, FALSE);
target->SendNetMessage(&expireMessage, PRIVATE_MSG, TRUE, FALSE);
}
}
else
{
if (pTarget == m_pWeenie)
if (target == m_pWeenie)
{
m_pWeenie->SendText(csprintf("You cast %s on yourself, but the dispel fails.", m_SpellCastData.spell->_name.c_str()), LTT_MAGIC);
}
else
{
m_pWeenie->SendText(csprintf("You cast %s on %s, but the dispel fails.", m_SpellCastData.spell->_name.c_str(), pTarget->GetName().c_str()), LTT_MAGIC);
pTarget->SendText(csprintf("%s casts %s on you, but the dispel fails.", m_pWeenie->GetName().c_str(), m_SpellCastData.spell->_name.c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("You cast %s on %s, but the dispel fails.", m_SpellCastData.spell->_name.c_str(), target->GetName().c_str()), LTT_MAGIC);
target->SendText(csprintf("%s casts %s on you, but the dispel fails.", m_pWeenie->GetName().c_str(), m_SpellCastData.spell->_name.c_str()), LTT_MAGIC);
}
}
@ -1209,8 +1215,6 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
int numToDispel = Random::GenInt(minNum, maxNum);
CWeenieObject *target = GetCastTarget();
if (!target->HasFellowship())
break;
@ -1224,7 +1228,7 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
if (member->GetBlock() == block)
{
if (member)
if (member && VerifyPkAction(member))
{
if (member->AsPlayer() && member->AsPlayer()->CheckPKActivity())
{
@ -1264,6 +1268,8 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
continue;
if ((entry._id & 0xFFFF) == 666) // vitae
continue;
if (entry._id == 3204 && g_pConfig->AllowCoalDispel())
continue;
if (CSpellTableEx *pSpellTableEx = g_pPortalDataEx->GetSpellTableEx())
{
@ -1312,6 +1318,8 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
continue;
if ((entry._id & 0xFFFF) == 666) // vitae
continue;
if (entry._id == 3204 && g_pConfig->AllowCoalDispel())
continue;
if (CSpellTableEx *pSpellTableEx = g_pPortalDataEx->GetSpellTableEx())
{
@ -1444,15 +1452,14 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
PortalLinkSpellEx *meta = (PortalLinkSpellEx *)m_SpellCastData.spellEx->_meta_spell._spell;
CWeenieObject *pTarget = GetCastTarget();
if (pTarget)
if (target)
{
// portal bitmask, 0x10 = cannot be summoned
// portal bitmask, 0x20 = cannot be linked/recalled
int minLevel = pTarget->InqIntQuality(MIN_LEVEL_INT, 0);
int maxLevel = pTarget->InqIntQuality(MAX_LEVEL_INT, 0);
uint32_t origPortID = pTarget->InqDIDQuality(ORIGINAL_PORTAL_DID, 0);
int minLevel = target->InqIntQuality(MIN_LEVEL_INT, 0);
int maxLevel = target->InqIntQuality(MAX_LEVEL_INT, 0);
uint32_t origPortID = target->InqDIDQuality(ORIGINAL_PORTAL_DID, 0);
int currentLevel = m_pWeenie->InqIntQuality(LEVEL_INT, 1);
@ -1475,7 +1482,7 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
switch (meta->_index)
{
case 1:
if (pTarget->m_Qualities.m_WeenieType == LifeStone_WeenieType)
if (target->m_Qualities.m_WeenieType == LifeStone_WeenieType)
{
m_pWeenie->m_Qualities.SetPosition(LINKED_LIFESTONE_POSITION, m_pWeenie->m_Position);
bSpellPerformed = true;
@ -1488,21 +1495,21 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
break;
case 2: // primary portal tie
if (pTarget->m_Qualities.m_WeenieType == Portal_WeenieType &&
!(pTarget->m_Qualities.GetInt(PORTAL_BITMASK_INT, 0) & 0x20))
if (target->m_Qualities.m_WeenieType == Portal_WeenieType &&
!(target->m_Qualities.GetInt(PORTAL_BITMASK_INT, 0) & 0x20))
{
if (origPortID > 0)
{
// This is a summoned portal with an original portal ID
m_pWeenie->m_Qualities.SetDataID(LINKED_PORTAL_ONE_DID, origPortID);
m_pWeenie->m_Qualities.SetPosition(LINKED_PORTAL_ONE_POSITION, pTarget->InqPositionQuality(DESTINATION_POSITION, Position()));
m_pWeenie->m_Qualities.SetPosition(LINKED_PORTAL_ONE_POSITION, target->InqPositionQuality(DESTINATION_POSITION, Position()));
}
else
{
// This is not a summoned portal
m_pWeenie->m_Qualities.SetDataID(LINKED_PORTAL_ONE_DID, pTarget->m_Qualities.id);
m_pWeenie->m_Qualities.SetPosition(LINKED_PORTAL_ONE_POSITION, pTarget->InqPositionQuality(DESTINATION_POSITION, Position()));
m_pWeenie->m_Qualities.SetDataID(LINKED_PORTAL_ONE_DID, target->m_Qualities.id);
m_pWeenie->m_Qualities.SetPosition(LINKED_PORTAL_ONE_POSITION, target->InqPositionQuality(DESTINATION_POSITION, Position()));
}
bSpellPerformed = true;
m_pWeenie->NotifyWeenieError(WERROR_PORTAL_LINK_SUCCESS);
@ -1515,21 +1522,21 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
break;
case 3: // secondary portal tie
if (pTarget->m_Qualities.m_WeenieType == Portal_WeenieType &&
!(pTarget->m_Qualities.GetInt(PORTAL_BITMASK_INT, 0) & 0x20))
if (target->m_Qualities.m_WeenieType == Portal_WeenieType &&
!(target->m_Qualities.GetInt(PORTAL_BITMASK_INT, 0) & 0x20))
{
if (origPortID > 0)
{
// This is a summoned portal with an original portal ID
m_pWeenie->m_Qualities.SetDataID(LINKED_PORTAL_TWO_DID, origPortID);
m_pWeenie->m_Qualities.SetPosition(LINKED_PORTAL_TWO_POSITION, pTarget->InqPositionQuality(DESTINATION_POSITION, Position()));
m_pWeenie->m_Qualities.SetPosition(LINKED_PORTAL_TWO_POSITION, target->InqPositionQuality(DESTINATION_POSITION, Position()));
}
else
{
// This is not a summoned portal
m_pWeenie->m_Qualities.SetDataID(LINKED_PORTAL_TWO_DID, pTarget->m_Qualities.id);
m_pWeenie->m_Qualities.SetPosition(LINKED_PORTAL_TWO_POSITION, pTarget->InqPositionQuality(DESTINATION_POSITION, Position()));
m_pWeenie->m_Qualities.SetDataID(LINKED_PORTAL_TWO_DID, target->m_Qualities.id);
m_pWeenie->m_Qualities.SetPosition(LINKED_PORTAL_TWO_POSITION, target->InqPositionQuality(DESTINATION_POSITION, Position()));
}
bSpellPerformed = true;
m_pWeenie->NotifyWeenieError(WERROR_PORTAL_LINK_SUCCESS);
@ -1679,32 +1686,23 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
std::list<CWeenieObject *> targets;
if (CWeenieObject *castTarget = GetCastTarget())
if (target)
{
// NPKs should not be able to buff PKs
if (m_pWeenie && castTarget && m_pWeenie->AsPlayer() && castTarget->AsPlayer())
{
if (!m_pWeenie->IsPK() && castTarget->IsPK())
{
bSpellPerformed = false;
break;
}
}
if (m_SpellCastData.spell->InqTargetType() != ITEM_TYPE::TYPE_ITEM_ENCHANTABLE_TARGET)
{
targets.push_back(castTarget);
targets.push_back(target);
}
else
{
CContainerWeenie *container = castTarget->AsContainer();
CContainerWeenie *container = target->AsContainer();
if (container && !container->HasOwner())
{
for (auto wielded : container->m_Wielded)
{
if (wielded->GetItemType() & m_SpellCastData.spell->_non_component_target_type)
{
if (castTarget == m_pWeenie || wielded->parent || m_pWeenie->GetWorldTopLevelOwner() == castTarget->GetWorldTopLevelOwner()) // for other targets, only physically wielded allowed, TopLevelOwner for buff gems.
if (target == m_pWeenie || wielded->parent || m_pWeenie->GetWorldTopLevelOwner() == target->GetWorldTopLevelOwner()) // for other targets, only physically wielded allowed, TopLevelOwner for buff gems.
{
targets.push_back(wielded);
}
@ -1713,24 +1711,24 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
}
else
{
if (castTarget->GetItemType() & m_SpellCastData.spell->_non_component_target_type)
if (target->GetItemType() & m_SpellCastData.spell->_non_component_target_type)
{
if (castTarget == m_pWeenie || castTarget->parent || !castTarget->HasOwner() || castTarget->GetWorldTopLevelOwner() == m_pWeenie) // for other targets, only physically wielded allowed
if (target == m_pWeenie || target->parent || !target->HasOwner() || target->GetWorldTopLevelOwner() == m_pWeenie) // for other targets, only physically wielded allowed
{
targets.push_back(castTarget);
targets.push_back(target);
}
}
}
}
for (auto target : targets)
for (auto castTarget : targets)
{
// You cast Harlune's Blessing on yourself, refreshing Harlune's Blessing
// You cast Impenetrability III on Pathwarden Robe, surpassing Impenetrability II
CWeenieObject *topLevelOwner = target->GetWorldTopLevelOwner();
CWeenieObject *topLevelOwner = castTarget->GetWorldTopLevelOwner();
if (target->InqIntQuality(MAX_STACK_SIZE_INT, 1) > 1) //do not allow enchanting stackable items(ammunition)
if (castTarget->InqIntQuality(MAX_STACK_SIZE_INT, 1) > 1) //do not allow enchanting stackable items(ammunition)
{
m_pWeenie->NotifyWeenieError(WERROR_MAGIC_BAD_TARGET_TYPE);
continue;
@ -1738,7 +1736,7 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
int text_option = 0; // 0 = normal cast text, 1 = refreshes text, 2 = surpassed by text, 3 = surpasses text
std::string existing_spell_name = "";
if (CEnchantmentRegistry* enchant_reg = target->m_Qualities._enchantment_reg)
if (CEnchantmentRegistry* enchant_reg = castTarget->m_Qualities._enchantment_reg)
{
if (Enchantment* highest_enchant = enchant_reg->GetHighestEnchantOfCategory(enchant._spell_category, enchant._smod.type)) // check if spell of this category already exists
{
@ -1756,7 +1754,8 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
}
}
if (m_pWeenie != target)
bool isPvP = false;
if (m_pWeenie != castTarget)
{
if (m_SpellCastData.spell->_bitfield & Resistable_SpellIndex)
{
@ -1764,13 +1763,13 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
topLevelOwner->EmitSound(Sound_ResistSpell, 1.0f, false);
topLevelOwner->SendText(csprintf("You resist the spell cast by %s", m_pWeenie->GetName().c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("%s resists your spell", target->GetName().c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("%s resists your spell", castTarget->GetName().c_str()), LTT_MAGIC);
topLevelOwner->OnResistSpell(m_pWeenie);
// Cast on Strike
if (m_pWeenie != m_pWeenie->GetWorldTopLevelOwner())
{
m_pWeenie->GetWorldTopLevelOwner()->SendText(csprintf("%s resists your spell", target->GetName().c_str()), LTT_MAGIC);
m_pWeenie->GetWorldTopLevelOwner()->SendText(csprintf("%s resists your spell", castTarget->GetName().c_str()), LTT_MAGIC);
}
continue;
@ -1779,23 +1778,28 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
if (!(m_SpellCastData.spell->_bitfield & Beneficial_SpellIndex))
{
if (m_pWeenie && target && m_pWeenie->AsPlayer() && target->AsPlayer())
if (m_pWeenie && castTarget && m_pWeenie->AsPlayer() && (castTarget->AsPlayer() || topLevelOwner->AsPlayer()))
{
// Only Update PK Activity if both target and caster are PK, Prevents PKs from tagging NPKs for PK activity.
if (m_pWeenie->IsPK() && target->IsPK())
if (m_pWeenie->IsPK() && (castTarget->IsPK() || topLevelOwner->AsPlayer()))
{
m_pWeenie->AsPlayer()->UpdatePKActivity();
target->AsPlayer()->UpdatePKActivity();
if (castTarget->AsPlayer())
castTarget->AsPlayer()->UpdatePKActivity();
else
topLevelOwner->AsPlayer()->UpdatePKActivity();
isPvP = true;
}
}
if (target->AsPlayer() && target->GetWorldTopLevelOwner()->ImmuneToDamage(m_pWeenie))
if (castTarget->AsPlayer() && castTarget->GetWorldTopLevelOwner()->ImmuneToDamage(m_pWeenie))
{
continue;
}
}
uint32_t resistMagic = target->InqIntQuality(RESIST_MAGIC_INT, 0, FALSE);
uint32_t resistMagic = castTarget->InqIntQuality(RESIST_MAGIC_INT, 0, FALSE);
if (resistMagic > 0 && !(m_SpellCastData.spellEx->_bitfield & DamageOverTime_SpellIndex))
{
if (resistMagic >= 9999 && topLevelOwner->GetID() == m_pWeenie->GetID())
@ -1803,31 +1807,31 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
if (resistMagic >= 9999 || ::TryMagicResist(m_SpellCastData.current_skill, (uint32_t)resistMagic))
{
target->EmitSound(Sound_ResistSpell, 1.0f, false);
castTarget->EmitSound(Sound_ResistSpell, 1.0f, false);
if (m_pWeenie != topLevelOwner)
{
topLevelOwner->SendText(csprintf("%s resists the spell cast by %s", m_pWeenie->GetName().c_str(), m_pWeenie->GetName().c_str()), LTT_MAGIC);
}
m_pWeenie->SendText(csprintf("%s resists your spell", target->GetName().c_str()), LTT_MAGIC);
target->OnResistSpell(m_pWeenie);
m_pWeenie->SendText(csprintf("%s resists your spell", castTarget->GetName().c_str()), LTT_MAGIC);
castTarget->OnResistSpell(m_pWeenie);
continue;
}
}
if (bool resistProjectileMagic = target->InqBoolQuality(NON_PROJECTILE_MAGIC_IMMUNE_BOOL, 0) && !(m_SpellCastData.spellEx->_bitfield & DamageOverTime_SpellIndex))
if (bool resistProjectileMagic = castTarget->InqBoolQuality(NON_PROJECTILE_MAGIC_IMMUNE_BOOL, 0) && !(m_SpellCastData.spellEx->_bitfield & DamageOverTime_SpellIndex))
{
if (resistProjectileMagic == 1 || ::TryMagicResist(m_SpellCastData.current_skill, (uint32_t)resistProjectileMagic))
{
target->EmitSound(Sound_ResistSpell, 1.0f, false);
castTarget->EmitSound(Sound_ResistSpell, 1.0f, false);
if (m_pWeenie != topLevelOwner)
{
topLevelOwner->SendText(csprintf("%s resists the spell cast by %s", m_pWeenie->GetName().c_str(), m_pWeenie->GetName().c_str()), LTT_MAGIC);
}
m_pWeenie->SendText(csprintf("%s resists your spell", target->GetName().c_str()), LTT_MAGIC);
target->OnResistSpell(m_pWeenie);
m_pWeenie->SendText(csprintf("%s resists your spell", castTarget->GetName().c_str()), LTT_MAGIC);
castTarget->OnResistSpell(m_pWeenie);
continue;
}
}
@ -1841,14 +1845,19 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
enchant._duration += 0.25; // Handle extra time so all ticks happen
}
target->m_Qualities.UpdateEnchantment(&enchant);
target->NotifyEnchantmentUpdated(&enchant);
// PVP Item debuffs only last 30 sec
if (isPvP && enchant._spell_category == 153 || enchant._spell_category == 155 || enchant._spell_category == 157 || enchant._spell_category == 159
|| enchant._spell_category == 161)
enchant._duration = 30.0;
target->CheckVitalRanges();
castTarget->m_Qualities.UpdateEnchantment(&enchant);
castTarget->NotifyEnchantmentUpdated(&enchant);
castTarget->CheckVitalRanges();
const char* spell_name = m_SpellCastData.spell->_name.c_str();
if (!silent)
{
if (m_pWeenie == target)
if (m_pWeenie == castTarget)
{
switch (text_option)
{
@ -1871,9 +1880,9 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
if ((m_SpellCastData.spellEx->_category >= 683 && m_SpellCastData.spellEx->_category <= 686) && (m_pWeenie->AsMeleeWeapon() || m_pWeenie->AsMissileLauncher()))
{
//<player> delivers a Traumatic Assault to Hea Apostate Shock Trooper!
m_pWeenie->GetWorldTopLevelOwner()->AsPlayer()->SendText(csprintf("Dirty Fighting! You deliver a %s to %s.", spell_name, target->GetName().c_str()), LTT_COMBAT);
m_pWeenie->GetWorldTopLevelOwner()->AsPlayer()->SendText(csprintf("Dirty Fighting! You deliver a %s to %s.", spell_name, castTarget->GetName().c_str()), LTT_COMBAT);
if (m_pWeenie != topLevelOwner)
topLevelOwner->SendText(csprintf("Dirty Fighting! %s delivers a %s to %s", m_pWeenie->GetWorldOwner()->GetName().c_str(), spell_name, target == topLevelOwner ? "you" : target->GetName().c_str()), LTT_COMBAT);
topLevelOwner->SendText(csprintf("Dirty Fighting! %s delivers a %s to %s", m_pWeenie->GetWorldOwner()->GetName().c_str(), spell_name, castTarget == topLevelOwner ? "you" : castTarget->GetName().c_str()), LTT_COMBAT);
}
else
{
@ -1884,24 +1893,24 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
//default:
case 0:
m_pWeenie->SendText(csprintf("You cast %s on %s", spell_name, target->GetName().c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("You cast %s on %s", spell_name, castTarget->GetName().c_str()), LTT_MAGIC);
if (m_pWeenie != topLevelOwner)
topLevelOwner->SendText(csprintf("%s cast %s on %s", m_pWeenie->GetName().c_str(), spell_name, target == topLevelOwner ? "you" : target->GetName().c_str()), LTT_MAGIC);
topLevelOwner->SendText(csprintf("%s cast %s on %s", m_pWeenie->GetName().c_str(), spell_name, castTarget == topLevelOwner ? "you" : castTarget->GetName().c_str()), LTT_MAGIC);
break;
case 1:
m_pWeenie->SendText(csprintf("You cast %s on %s, refreshing %s", spell_name, target->GetName().c_str(), spell_name), LTT_MAGIC);
m_pWeenie->SendText(csprintf("You cast %s on %s, refreshing %s", spell_name, castTarget->GetName().c_str(), spell_name), LTT_MAGIC);
if (m_pWeenie != topLevelOwner)
topLevelOwner->SendText(csprintf("%s cast %s on %s, refreshing %s", m_pWeenie->GetName().c_str(), spell_name, target == topLevelOwner ? "you" : target->GetName().c_str(), spell_name), LTT_MAGIC);
topLevelOwner->SendText(csprintf("%s cast %s on %s, refreshing %s", m_pWeenie->GetName().c_str(), spell_name, castTarget == topLevelOwner ? "you" : castTarget->GetName().c_str(), spell_name), LTT_MAGIC);
break;
case 2:
m_pWeenie->SendText(csprintf("You cast %s on %s, but it is surpassed by %s", spell_name, target->GetName().c_str(), existing_spell_name.c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("You cast %s on %s, but it is surpassed by %s", spell_name, castTarget->GetName().c_str(), existing_spell_name.c_str()), LTT_MAGIC);
if (m_pWeenie != topLevelOwner)
topLevelOwner->SendText(csprintf("%s cast %s on %s, but it is surpassed by %s", m_pWeenie->GetName().c_str(), spell_name, target == topLevelOwner ? "you" : target->GetName().c_str(), existing_spell_name.c_str()), LTT_MAGIC);
topLevelOwner->SendText(csprintf("%s cast %s on %s, but it is surpassed by %s", m_pWeenie->GetName().c_str(), spell_name, castTarget == topLevelOwner ? "you" : castTarget->GetName().c_str(), existing_spell_name.c_str()), LTT_MAGIC);
break;
case 3:
m_pWeenie->SendText(csprintf("You cast %s on %s, surpassing %s", spell_name, target->GetName().c_str(), existing_spell_name.c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("You cast %s on %s, surpassing %s", spell_name, castTarget->GetName().c_str(), existing_spell_name.c_str()), LTT_MAGIC);
if (m_pWeenie != topLevelOwner)
topLevelOwner->SendText(csprintf("%s cast %s on %s, surpassing %s", m_pWeenie->GetName().c_str(), spell_name, target == topLevelOwner ? "you" : target->GetName().c_str(), existing_spell_name.c_str()), LTT_MAGIC);
topLevelOwner->SendText(csprintf("%s cast %s on %s, surpassing %s", m_pWeenie->GetName().c_str(), spell_name, castTarget == topLevelOwner ? "you" : castTarget->GetName().c_str(), existing_spell_name.c_str()), LTT_MAGIC);
break;
case 4:
CWeenieObject* aetheriaOwner = m_pWeenie->GetWorldTopLevelOwner();
@ -1934,8 +1943,6 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
enchant._last_time_degraded = -1.0;
enchant._smod = meta->_smod;
CWeenieObject *target = GetCastTarget();
if (!target->HasFellowship())
break;
@ -1953,7 +1960,7 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
if (CWeenieObject *member = g_pWorld->FindPlayer(entry.first))
{
if (member->GetBlock() == block)
if (member->GetBlock() == block && VerifyPkAction(member))
{
if (enchant._smod.type & Skill_EnchantmentType)
@ -1998,24 +2005,24 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
}
}
for (auto target : targets)
for (auto castTarget : targets)
{
// You cast Harlune's Blessing on yourself, refreshing Harlune's Blessing
// You cast Impenetrability III on Pathwarden Robe, surpassing Impenetrability II
CWeenieObject *topLevelOwner = target->GetWorldTopLevelOwner();
CWeenieObject *topLevelOwner = castTarget->GetWorldTopLevelOwner();
if (target->InqIntQuality(MAX_STACK_SIZE_INT, 1) > 1) //do not allow enchanting stackable items(ammunition)
if (castTarget->InqIntQuality(MAX_STACK_SIZE_INT, 1) > 1) //do not allow enchanting stackable items(ammunition)
{
m_pWeenie->NotifyWeenieError(WERROR_MAGIC_BAD_TARGET_TYPE);
continue;
}
bool bAlreadyExisted = false;
if (target->m_Qualities._enchantment_reg && target->m_Qualities._enchantment_reg->IsEnchanted(enchant._id))
if (castTarget->m_Qualities._enchantment_reg && castTarget->m_Qualities._enchantment_reg->IsEnchanted(enchant._id))
bAlreadyExisted = true;
if (m_pWeenie != target)
if (m_pWeenie != castTarget)
{
if (m_SpellCastData.spell->_bitfield & Resistable_SpellIndex)
{
@ -2023,7 +2030,7 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
topLevelOwner->EmitSound(Sound_ResistSpell, 1.0f, false);
topLevelOwner->SendText(csprintf("You resist the spell cast by %s", m_pWeenie->GetName().c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("%s resists your spell", target->GetName().c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("%s resists your spell", castTarget->GetName().c_str()), LTT_MAGIC);
topLevelOwner->OnResistSpell(m_pWeenie);
continue;
}
@ -2032,50 +2039,50 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
if (!(m_SpellCastData.spell->_bitfield & Beneficial_SpellIndex))
{
// Only Update PK Activity if both target and caster are PK, Prevents PKs from tagging NPKs for PK activity.
if (m_pWeenie->IsPK() && target->IsPK())
if (m_pWeenie->IsPK() && castTarget->IsPK())
{
m_pWeenie->AsPlayer()->UpdatePKActivity();
target->AsPlayer()->UpdatePKActivity();
castTarget->AsPlayer()->UpdatePKActivity();
}
if (target->AsPlayer() && target->GetWorldTopLevelOwner()->ImmuneToDamage(m_pWeenie))
if (castTarget->AsPlayer() && castTarget->GetWorldTopLevelOwner()->ImmuneToDamage(m_pWeenie))
{
continue;
}
}
if (int resistMagic = target->InqIntQuality(RESIST_MAGIC_INT, 0, FALSE))
if (int resistMagic = castTarget->InqIntQuality(RESIST_MAGIC_INT, 0, FALSE))
{
if (resistMagic >= 9999 && topLevelOwner == m_pWeenie)
continue;
if (resistMagic >= 9999 || ::TryMagicResist(m_SpellCastData.current_skill, (uint32_t)resistMagic))
{
target->EmitSound(Sound_ResistSpell, 1.0f, false);
castTarget->EmitSound(Sound_ResistSpell, 1.0f, false);
if (m_pWeenie != topLevelOwner)
{
topLevelOwner->SendText(csprintf("%s resists the spell cast by %s", m_pWeenie->GetName().c_str(), m_pWeenie->GetName().c_str()), LTT_MAGIC);
}
m_pWeenie->SendText(csprintf("%s resists your spell", target->GetName().c_str()), LTT_MAGIC);
target->OnResistSpell(m_pWeenie);
m_pWeenie->SendText(csprintf("%s resists your spell", castTarget->GetName().c_str()), LTT_MAGIC);
castTarget->OnResistSpell(m_pWeenie);
continue;
}
}
if (bool resistProjectileMagic = target->InqBoolQuality(NON_PROJECTILE_MAGIC_IMMUNE_BOOL, 0))
if (bool resistProjectileMagic = castTarget->InqBoolQuality(NON_PROJECTILE_MAGIC_IMMUNE_BOOL, 0))
{
if (resistProjectileMagic == 1 || ::TryMagicResist(m_SpellCastData.current_skill, (uint32_t)resistProjectileMagic))
{
target->EmitSound(Sound_ResistSpell, 1.0f, false);
castTarget->EmitSound(Sound_ResistSpell, 1.0f, false);
if (m_pWeenie != topLevelOwner)
{
topLevelOwner->SendText(csprintf("%s resists the spell cast by %s", m_pWeenie->GetName().c_str(), m_pWeenie->GetName().c_str()), LTT_MAGIC);
}
m_pWeenie->SendText(csprintf("%s resists your spell", target->GetName().c_str()), LTT_MAGIC);
target->OnResistSpell(m_pWeenie);
m_pWeenie->SendText(csprintf("%s resists your spell", castTarget->GetName().c_str()), LTT_MAGIC);
castTarget->OnResistSpell(m_pWeenie);
continue;
}
}
@ -2083,25 +2090,25 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
topLevelOwner->HandleAggro(m_pWeenie);
target->m_Qualities.UpdateEnchantment(&enchant);
target->NotifyEnchantmentUpdated(&enchant);
castTarget->m_Qualities.UpdateEnchantment(&enchant);
castTarget->NotifyEnchantmentUpdated(&enchant);
target->CheckVitalRanges();
castTarget->CheckVitalRanges();
if (m_pWeenie == target)
if (m_pWeenie == castTarget)
{
m_pWeenie->SendText(csprintf("You cast %s on yourself", m_SpellCastData.spell->_name.c_str()), LTT_MAGIC);
}
else
{
m_pWeenie->SendText(csprintf("You cast %s on %s", m_SpellCastData.spell->_name.c_str(), target->GetName().c_str()), LTT_MAGIC);
m_pWeenie->SendText(csprintf("You cast %s on %s", m_SpellCastData.spell->_name.c_str(), castTarget->GetName().c_str()), LTT_MAGIC);
if (m_pWeenie != topLevelOwner)
{
if (target == topLevelOwner)
target->SendText(csprintf("%s cast %s on you", m_pWeenie->GetName().c_str(), m_SpellCastData.spell->_name.c_str()), LTT_MAGIC);
if (castTarget == topLevelOwner)
castTarget->SendText(csprintf("%s cast %s on you", m_pWeenie->GetName().c_str(), m_SpellCastData.spell->_name.c_str()), LTT_MAGIC);
else
topLevelOwner->SendText(csprintf("%s cast %s on %s", m_pWeenie->GetName().c_str(), m_SpellCastData.spell->_name.c_str(), target->GetName().c_str()), LTT_MAGIC);
topLevelOwner->SendText(csprintf("%s cast %s on %s", m_pWeenie->GetName().c_str(), m_SpellCastData.spell->_name.c_str(), castTarget->GetName().c_str()), LTT_MAGIC);
}
}
@ -2280,8 +2287,6 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
PortalSendingSpellEx *meta = (PortalSendingSpellEx *)m_SpellCastData.spellEx->_meta_spell._spell;
CWeenieObject *target = GetCastTarget();
if (m_pWeenie->AsPlayer() && m_pWeenie->AsPlayer()->CheckPKActivity() || m_pWeenie->HasOwner() && target->AsPlayer() && target->AsPlayer()->CheckPKActivity())
{
m_pWeenie->NotifyWeenieError(WERROR_PORTAL_PK_ATTACKED_TOO_RECENTLY);
@ -2313,8 +2318,6 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
FellowshipPortalSendingSpellEx *meta = (FellowshipPortalSendingSpellEx *)m_SpellCastData.spellEx->_meta_spell._spell;
CWeenieObject *target = GetCastTarget();
if (!target->HasFellowship())
break;
@ -2326,9 +2329,8 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
{
if (CWeenieObject *member = g_pWorld->FindPlayer(entry.first))
{
if (member->GetBlock() == block)
if (member->GetBlock() == block && VerifyPkAction(member))
{
member->Movement_Teleport(meta->_pos, false);
member->SendText("You have been teleported.", LTT_MAGIC);
}
@ -2363,6 +2365,21 @@ int CSpellcastingManager::LaunchSpellEffect(bool bFizzled, bool silent)
return WERROR_NONE;
}
bool CSpellcastingManager::VerifyPkAction(CWeenieObject * target)
{
bool isSpellHelpful = m_SpellCastData.spellEx->_bitfield & Beneficial_SpellIndex;
WErrorType attackerError = WERROR_NONE;
WErrorType defenderError = WERROR_NONE;
if (target && !m_pWeenie->IsValidPkAction(isSpellHelpful, (PKStatusEnum)m_pWeenie->m_Qualities.GetInt(PLAYER_KILLER_STATUS_INT, 1),
(PKStatusEnum)target->m_Qualities.GetInt(PLAYER_KILLER_STATUS_INT, 1), attackerError, defenderError))
{
m_pWeenie->NotifyWeenieErrorWithString(attackerError, target->GetName().c_str());
target->NotifyWeenieErrorWithString(defenderError, m_pWeenie->GetName().c_str());
return false;
}
return true;
}
WErrorType CSpellcastingManager::CanPortalRecall(uint32_t portalDID, uint32_t linkedPortalEnum)
{
WErrorType error = WERROR_NONE;

View file

@ -86,6 +86,7 @@ public:
void PerformCastParticleEffects();
void PerformFellowCastParticleEffects(fellowship_ptr_t &fellow);
int LaunchSpellEffect(bool bFizzled, bool silent = false);
bool VerifyPkAction(CWeenieObject * target);
bool DoTransferSpell(CWeenieObject *other, const TransferSpellEx *meta);
bool AdjustVital(CWeenieObject *target);
void SendAdjustVitalText(CWeenieObject *target, int amount, const char *vitalName);

View file

@ -4139,6 +4139,20 @@ void CWeenieObject::TryToDealDamage(DamageEventData &data)
return;
}
if (data.target->AsPlayer())
{
WErrorType attackerError = WERROR_NONE;
WErrorType defenderError = WERROR_NONE;
if ( !IsValidPkAction(false, (PKStatusEnum)m_Qualities.GetInt(PLAYER_KILLER_STATUS_INT, 1),
(PKStatusEnum)data.target->m_Qualities.GetInt(PLAYER_KILLER_STATUS_INT, 1), attackerError, defenderError))
{
NotifyWeenieErrorWithString(attackerError, data.target->GetName().c_str());
data.target->NotifyWeenieErrorWithString(defenderError, GetName().c_str());
return;
}
}
if (data.damage_form & DF_PHYSICAL)
{
std::map<int32_t, float> bodyParts;
@ -4764,7 +4778,10 @@ void CWeenieObject::TakeDamage(DamageEventData &damageData)
if (procType == 2)
{
int originalDamage = damageData.outputDamageFinal;
damageData.outputDamageFinal -= min(damageData.outputDamageFinal, 200);
if(damageData.isPvP)
damageData.outputDamageFinal -= min(damageData.outputDamageFinal, 100);
else
damageData.outputDamageFinal -= min(damageData.outputDamageFinal, 200);
SendText(csprintf("Your cloak reduced the damage from %u down to %u!", originalDamage, damageData.outputDamageFinal), LTT_MAGIC);
}
else if (procType == 1)
@ -5006,6 +5023,73 @@ PScriptType CWeenieObject::GetScriptByHitLoc(DamageEventData &damageData)
return ps;
}
bool CWeenieObject::IsValidPkAction(bool helpful, PKStatusEnum attacker, PKStatusEnum defender, WErrorType & attackerError, WErrorType & defenderError)
{
bool validAction = false;
if (!helpful)
{
if (attacker == Protected_PKStatus)
{
attackerError = WERROR_PK_PROTECTED_ATTACKER;
defenderError = WERROR_PK_PROTECTED_ATTACKER_PASSIVE;
}
else if (attacker == NPK_PKStatus && defender == PK_PKStatus)
{
attackerError = WERROR_PK_NPK_ATTACKER;
defenderError = WERROR_PK_NPK_ATTACKER_PASSIVE;
}
else if (attacker == PK_PKStatus && defender == NPK_PKStatus)
{
attackerError = WERROR_PK_NPK_TARGET;
defenderError = WERROR_PK_NPK_TARGET_PASSIVE;
}
else if ((attacker == PK_PKStatus && defender == PKLite_PKStatus) || (attacker == PKLite_PKStatus && defender == PK_PKStatus))
{
attackerError = WERROR_PK_WRONG_KIND;
defenderError = WERROR_PK_WRONG_KIND_PASSIVE;
}
else if (attacker == PKLite_PKStatus && defender == NPK_PKStatus)
{
attackerError = WERROR_PK_NPK_TARGET;
defenderError = WERROR_PK_NPK_TARGET_PASSIVE;
}
else if (attacker == NPK_PKStatus && defender == PKLite_PKStatus)
{
attackerError = WERROR_PK_NPK_ATTACKER;
defenderError = WERROR_PK_NPK_TARGET;
}
else
validAction = true;
}
else
{
if (attacker == NPK_PKStatus && defender == PK_PKStatus)
{
attackerError = WERROR_PK_NPK_ATTACKER;
defenderError = WERROR_PK_NPK_ATTACKER_PASSIVE;
}
else if (attacker == PK_PKStatus && defender == NPK_PKStatus)
{
attackerError = WERROR_PK_NPK_TARGET;
defenderError = WERROR_PK_NPK_TARGET_PASSIVE;
}
else if ((attacker == PK_PKStatus && defender == PKLite_PKStatus) || (attacker == PKLite_PKStatus && defender == PK_PKStatus))
{
attackerError = WERROR_PK_WRONG_KIND;
defenderError = WERROR_PK_WRONG_KIND_PASSIVE;
}
else if (attacker == NPK_PKStatus && defender == PKLite_PKStatus)
{
attackerError = WERROR_PK_NPK_ATTACKER;
defenderError = WERROR_PK_NPK_ATTACKER_PASSIVE;
}
else
validAction = true;
}
return validAction;
}
void CWeenieObject::OnTookDamage(DamageEventData &data)
{
if (data.damage_form & DF_PHYSICAL && data.outputDamageFinal >= 0)
@ -6698,7 +6782,7 @@ int CWeenieObject::GetAttackDamage(bool isAssess)
double CWeenieObject::GetElementalDamageMod()
{
double elementdmg = InqFloatQuality(ELEMENTAL_DAMAGE_MOD_FLOAT, 0.0);
double elementdmg = InqFloatQuality(ELEMENTAL_DAMAGE_MOD_FLOAT, 0.0, true);
if (m_Qualities._enchantment_reg)
m_Qualities._enchantment_reg->EnchantFloat(ELEMENTAL_DAMAGE_MOD_FLOAT, &elementdmg);

View file

@ -641,6 +641,7 @@ public:
virtual void OnDealtDamage(DamageEventData &damageData);
virtual void OnRegen(STypeAttribute2nd currentAttrib, int newAmount);
PScriptType GetScriptByHitLoc(DamageEventData &damageData);
bool IsValidPkAction(bool helpful, PKStatusEnum attacker, PKStatusEnum defender, WErrorType &attackerError, WErrorType &defenderError);
virtual float GetEffectiveArmorLevel(DamageEventData &damageData, bool bIgnoreMagicArmor);