This commit is contained in:
Uleat 2018-10-09 22:04:57 -04:00
commit 9f039b47e9
5 changed files with 118 additions and 82 deletions

View File

@ -389,6 +389,7 @@ RULE_INT(Spells, AI_PursueDetrimentalChance, 90) // Chance while chasing target
RULE_INT(Spells, AI_IdleNoSpellMinRecast, 6000) // AI spell recast time(MS) check when no spell is cast while idle. (min time in random)
RULE_INT(Spells, AI_IdleNoSpellMaxRecast, 60000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random)
RULE_INT(Spells, AI_IdleBeneficialChance, 100) // Chance while idle to do a beneficial spell on self or others.
RULE_INT(Spells, AI_HealHPPct, 50) // HP Pct NPCs will start heals at (in and out of combat) if spell's max_hp is not set
RULE_BOOL(Spells, SHDProcIDOffByOne, true) // pre June 2009 SHD spell procs were off by 1, they stopped doing this in June 2009 (so UF+ spell files need this false)
RULE_BOOL(Spells, Jun182014HundredHandsRevamp, false) // this should be true for if you import a spell file newer than June 18, 2014
RULE_BOOL(Spells, SwarmPetTargetLock, false) // Use old method of swarm pets target locking till target dies then despawning.

View File

@ -253,7 +253,7 @@ Mob::Mob(const char* in_name,
max_mana = 0;
hp_regen = in_hp_regen;
mana_regen = in_mana_regen;
oocregen = RuleI(NPC, OOCRegen); //default Out of Combat Regen
ooc_regen = RuleI(NPC, OOCRegen); //default Out of Combat Regen
maxlevel = in_maxlevel;
scalerate = in_scalerate;
invisible = false;
@ -1303,14 +1303,17 @@ void Mob::CreateHPPacket(EQApplicationPacket* app)
}
}
// sends hp update of this mob to people who might care
void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= false*/)
{
/* If our HP is different from last HP update call - let's update ourself */
void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= false*/) {
/**
* If our HP is different from last HP update call - let's update selves
*/
if (IsClient()) {
if (cur_hp != last_hp || force_update_all) {
/* This is to prevent excessive packet sending under trains/fast combat */
/**
* This is to prevent excessive packet sending under trains/fast combat
*/
if (this->CastToClient()->hp_self_update_throttle_timer.Check() || force_update_all) {
Log(Logs::General, Logs::HP_Update,
"Mob::SendHPUpdate :: Update HP of self (%s) HP: %i last: %i skip_self: %s",
@ -1322,11 +1325,12 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
if (!skip_self || this->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
auto client_packet = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct));
SpawnHPUpdate_Struct* hp_packet_client = (SpawnHPUpdate_Struct*)client_packet->pBuffer;
hp_packet_client->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
SpawnHPUpdate_Struct *hp_packet_client = (SpawnHPUpdate_Struct *) client_packet->pBuffer;
hp_packet_client->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
hp_packet_client->spawn_id = GetID();
hp_packet_client->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP;
hp_packet_client->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP;
CastToClient()->QueuePacket(client_packet);
@ -1335,7 +1339,9 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
ResetHPUpdateTimer();
}
/* Used to check if HP has changed to update self next round */
/**
* Used to check if HP has changed to update self next round
*/
last_hp = cur_hp;
}
}
@ -1343,7 +1349,12 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
int8 current_hp_percent = (max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp));
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: SendHPUpdate %s HP is %i last %i", this->GetCleanName(), current_hp_percent, last_hp_percent);
Log(Logs::General,
Logs::HP_Update,
"Mob::SendHPUpdate :: SendHPUpdate %s HP is %i last %i",
this->GetCleanName(),
current_hp_percent,
last_hp_percent);
if (current_hp_percent == last_hp_percent && !force_update_all) {
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: Same HP - skipping update");
@ -1352,8 +1363,9 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
}
else {
if (IsClient() && RuleB(Character, MarqueeHPUpdates))
if (IsClient() && RuleB(Character, MarqueeHPUpdates)) {
this->CastToClient()->SendHPUpdateMarquee();
}
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: HP Changed - Send update");
@ -1361,52 +1373,69 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
}
EQApplicationPacket hp_packet;
Group *group = nullptr;
Group *group = nullptr;
CreateHPPacket(&hp_packet);
/* Update those who have us targeted */
/**
* Update those who have us targeted
*/
entity_list.QueueClientsByTarget(this, &hp_packet, false, 0, false, true, EQEmu::versions::bit_AllClients);
/* Update those who have us on x-target */
/**
* Update those who have us on x-target
*/
entity_list.QueueClientsByXTarget(this, &hp_packet, false);
/* Update groups using Group LAA health name tag counter */
/**
* Update groups using Group LAA health name tag counter
*/
entity_list.QueueToGroupsForNPCHealthAA(this, &hp_packet);
/* Update group */
if(IsGrouped()) {
/**
* Group
*/
if (IsGrouped()) {
group = entity_list.GetGroupByMob(this);
if(group)
if (group) {
group->SendHPPacketsFrom(this);
}
}
/* Update Raid */
if(IsClient()){
/**
* Raid
*/
if (IsClient()) {
Raid *raid = entity_list.GetRaidByClient(CastToClient());
if (raid)
if (raid) {
raid->SendHPManaEndPacketsFrom(this);
}
}
/* Pet - Update master - group and raid if exists */
if(GetOwner() && GetOwner()->IsClient()) {
/**
* Pet
*/
if (GetOwner() && GetOwner()->IsClient()) {
GetOwner()->CastToClient()->QueuePacket(&hp_packet, false);
group = entity_list.GetGroupByClient(GetOwner()->CastToClient());
if(group)
if (group) {
group->SendHPPacketsFrom(this);
}
Raid *raid = entity_list.GetRaidByClient(GetOwner()->CastToClient());
if(raid)
if (raid) {
raid->SendHPManaEndPacketsFrom(this);
}
}
/* Send to pet */
if(GetPet() && GetPet()->IsClient()) {
if (GetPet() && GetPet()->IsClient()) {
GetPet()->CastToClient()->QueuePacket(&hp_packet, false);
}
/* Destructible objects */
/**
* Destructible objects
*/
if (IsNPC() && IsDestructibleObject()) {
if (GetHPRatio() > 74) {
if (GetAppearance() != eaStanding) {

View File

@ -421,7 +421,7 @@ public:
bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) = 0;
inline virtual void SetHP(int32 hp) { if (hp >= max_hp) cur_hp = max_hp; else cur_hp = hp;}
bool ChangeHP(Mob* other, int32 amount, uint16 spell_id = 0, int8 buffslot = -1, bool iBuffTic = false);
inline void SetOOCRegen(int32 newoocregen) {oocregen = newoocregen;}
inline void SetOOCRegen(int32 newoocregen) {ooc_regen = newoocregen;}
virtual void Heal();
virtual void HealDamage(uint32 ammount, Mob* caster = nullptr, uint16 spell_id = SPELL_UNKNOWN);
virtual void SetMaxHP() { cur_hp = max_hp; }
@ -1223,7 +1223,7 @@ protected:
int32 max_mana;
int32 hp_regen;
int32 mana_regen;
int32 oocregen;
int32 ooc_regen;
uint8 maxlevel;
uint32 scalerate;
Buffs_Struct *buffs;

View File

@ -97,10 +97,11 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates
continue;
}
if (AIspells[i].min_hp != 0 && GetIntHPRatio() < AIspells[i].min_hp)
// we reuse these fields for heal overrides
if (AIspells[i].type != SpellType_Heal && AIspells[i].min_hp != 0 && GetIntHPRatio() < AIspells[i].min_hp)
continue;
if (AIspells[i].max_hp != 0 && GetIntHPRatio() > AIspells[i].max_hp)
if (AIspells[i].type != SpellType_Heal && AIspells[i].max_hp != 0 && GetIntHPRatio() > AIspells[i].max_hp)
continue;
if (iSpellTypes & AIspells[i].type) {
@ -137,9 +138,13 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates
&& tar->DontHealMeBefore() < Timer::GetCurrentTime()
&& !(tar->IsPet() && tar->GetOwner()->IsClient()) //no buffing PC's pets
) {
uint8 hpr = (uint8)tar->GetHPRatio();
if(hpr <= 35 || (!IsEngaged() && hpr <= 50) || (tar->IsClient() && hpr <= 99)) {
auto hp_ratio = tar->GetIntHPRatio();
int min_hp = AIspells[i].min_hp; // well 0 is default, so no special case here
int max_hp = AIspells[i].max_hp ? AIspells[i].max_hp : RuleI(Spells, AI_HealHPPct);
if (EQEmu::ValueWithin(hp_ratio, min_hp, max_hp) || (tar->IsClient() && hp_ratio <= 99)) { // not sure about client bit, leaving it
uint32 tempTime = 0;
AIDoSpellCast(i, tar, mana_cost, &tempTime);
tar->SetDontHealMeBefore(tempTime);

View File

@ -667,77 +667,78 @@ bool NPC::Process()
parse->EventNPC(EVENT_TICK, this, nullptr, "", 0);
BuffProcess();
if (currently_fleeing)
if (currently_fleeing) {
ProcessFlee();
uint32 sitting_bonus = 0;
uint32 petbonus = 0;
uint32 bestregen = 0;
int32 dbregen = GetNPCHPRegen();
if (GetAppearance() == eaSitting)
sitting_bonus += 3;
int32 OOCRegen = 0;
if (oocregen > 0) { //should pull from Mob class
OOCRegen += GetMaxHP() * oocregen / 100;
}
// Fixing NPC regen.NPCs should regen to full during
// a set duration, not based on their HPs.Increase NPC's HPs by
// % of total HPs / tick.
//
// If oocregen set in db, apply to pets as well.
// This allows the obscene #s for pets in the db to be tweaked
// while maintaining a decent ooc regen.
uint32 npc_sitting_regen_bonus = 0;
uint32 pet_regen_bonus = 0;
uint32 npc_regen = 0;
int32 npc_hp_regen = GetNPCHPRegen();
bestregen = std::max(dbregen,OOCRegen);
if (GetAppearance() == eaSitting) {
npc_sitting_regen_bonus += 3;
}
int32 ooc_regen_calc = 0;
if (ooc_regen > 0) { //should pull from Mob class
ooc_regen_calc += GetMaxHP() * ooc_regen / 100;
}
/**
* Use max value between two values
*/
npc_regen = std::max(npc_hp_regen, ooc_regen_calc);
if ((GetHP() < GetMaxHP()) && !IsPet()) {
if (!IsEngaged())
SetHP(GetHP() + bestregen + sitting_bonus);
else
SetHP(GetHP() + dbregen);
if (!IsEngaged()) {
SetHP(GetHP() + npc_regen + npc_sitting_regen_bonus);
}
else {
SetHP(GetHP() + npc_hp_regen);
}
}
else if (GetHP() < GetMaxHP() && GetOwnerID() != 0) {
if (!IsEngaged()) {
if (oocregen > 0) {
petbonus = std::max(OOCRegen,dbregen);
if (ooc_regen > 0) {
pet_regen_bonus = std::max(ooc_regen_calc, npc_hp_regen);
}
else {
petbonus = dbregen + (GetLevel() / 5);
pet_regen_bonus = npc_hp_regen + (GetLevel() / 5);
}
SetHP(GetHP() + sitting_bonus + petbonus);
SetHP(GetHP() + npc_sitting_regen_bonus + pet_regen_bonus);
}
else
SetHP(GetHP() + dbregen);
else {
SetHP(GetHP() + npc_hp_regen);
}
}
else {
SetHP(GetHP() + npc_hp_regen + npc_sitting_regen_bonus);
}
else
SetHP(GetHP() + dbregen + sitting_bonus);
if (GetMana() < GetMaxMana()) {
SetMana(GetMana() + mana_regen + sitting_bonus);
SetMana(GetMana() + mana_regen + npc_sitting_regen_bonus);
}
SendHPUpdate();
if (zone->adv_data && !p_depop)
{
ServerZoneAdventureDataReply_Struct* ds = (ServerZoneAdventureDataReply_Struct*)zone->adv_data;
if (ds->type == Adventure_Rescue && ds->data_id == GetNPCTypeID())
{
if (zone->adv_data && !p_depop) {
ServerZoneAdventureDataReply_Struct *ds = (ServerZoneAdventureDataReply_Struct *) zone->adv_data;
if (ds->type == Adventure_Rescue && ds->data_id == GetNPCTypeID()) {
Mob *o = GetOwner();
if (o && o->IsClient())
{
if (o && o->IsClient()) {
float x_diff = ds->dest_x - GetX();
float y_diff = ds->dest_y - GetY();
float z_diff = ds->dest_z - GetZ();
float dist = ((x_diff * x_diff) + (y_diff * y_diff) + (z_diff * z_diff));
if (dist < RuleR(Adventure, DistanceForRescueComplete))
{
float dist = ((x_diff * x_diff) + (y_diff * y_diff) + (z_diff * z_diff));
if (dist < RuleR(Adventure, DistanceForRescueComplete)) {
zone->DoAdventureCountIncrease();
Say("You don't know what this means to me. Thank you so much for finding and saving me from"
" this wretched place. I'll find my way from here.");
Say(
"You don't know what this means to me. Thank you so much for finding and saving me from"
" this wretched place. I'll find my way from here."
);
Depop();
}
}