mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Haynar's movement fixes.
Changes Speed from float to int. EQ client deals with int step locs better than it does floats according to Haynar's testing. This also contains mob runspeed changes. I recommend you set runspeeds to start in the DB 1.25 for NPCs below 1.25 which will match player runspeeds almost equally. Existing DBs will need to be updated. General Cleanup of MobAI functions. Mobs now change their heading on AIMovement timers if their targets' heading has changed since that time. This prevents players from being able to land backstabs inbetween mob swings. Charmed/feared players now send the appropriate packet, there was a missing CastToClient() in spells that was missing. Mob runspeed can no longer be snared to 0%, instead, 1% of their base runspeed is the maximum. Roots apply as roots instead of a modifier under this code. There is going to be bugs with this code. It's better we push through it than revert it. Sanctuary has been running this for a good week and we've worked through the issues. Misc updates: Exported some variables to perl, including: EVENT_ITE_CLICK_CAST: EVENT_ITEM_CLICK: spell_id - returns the spell_id of the click effect. return value - cancels the cast. EVENT_DROP_ITEM: quantity - returns the # of items dropped in the packet. If the item has charges, charges are returned here instead. itemname - name of the item being dropped itemid - id of the item being droppped spell_id - spell_id associated with the item's click effect. slotid - the inventory slot id of the item being dropped. return value - cancels the item from being dropped. Added Perl function: CalcEXP. Calculates the experience you would gain for an NPC that cons a specific con value to you. Fixed a bug where you would receive the group experience bonus and group experience messages for simply being in a group, regardless of the player being in the same zone as you.
This commit is contained in:
parent
aaca6fd2d9
commit
788959a5e2
194
zone/bonuses.cpp
194
zone/bonuses.cpp
@ -335,8 +335,8 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
}
|
||||
|
||||
//FatherNitwit: New style haste, shields, and regens
|
||||
if(newbon->haste < (int32)item->Haste) {
|
||||
newbon->haste = item->Haste;
|
||||
if((int32)item->Haste > 0) {
|
||||
newbon->haste += item->Haste;
|
||||
}
|
||||
if(item->Regen > 0)
|
||||
newbon->HPRegen += item->Regen;
|
||||
@ -390,10 +390,10 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
newbon->HitChance += item->Accuracy;
|
||||
}
|
||||
if(item->CombatEffects > 0) {
|
||||
if((newbon->ProcChance + item->CombatEffects) > RuleI(Character, ItemCombatEffectsCap))
|
||||
newbon->ProcChance = RuleI(Character, ItemCombatEffectsCap);
|
||||
if((newbon->MeleeDamage + item->CombatEffects) > RuleI(Character, ItemCombatEffectsCap))
|
||||
newbon->MeleeDamage = RuleI(Character, ItemCombatEffectsCap);
|
||||
else
|
||||
newbon->ProcChance += item->CombatEffects;
|
||||
newbon->MeleeDamage += item->CombatEffects;
|
||||
}
|
||||
if(item->DotShielding > 0) {
|
||||
if((newbon->DoTShielding + item->DotShielding) > RuleI(Character, ItemDoTShieldingCap))
|
||||
@ -428,7 +428,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
newbon->DSMitigation += item->DSMitigation;
|
||||
}
|
||||
if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
}
|
||||
|
||||
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
||||
@ -559,7 +559,7 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool
|
||||
/*
|
||||
Powerful Non-live like option allows developers to add worn effects on items that
|
||||
can stack with other worn effects of the same spell effect type, instead of only taking the highest value.
|
||||
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus.
|
||||
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus.
|
||||
To enable use RuleI(Spells, AdditiveBonusWornType)
|
||||
Setting value = 2 Will force all live items to automatically be calculated additivily
|
||||
Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation
|
||||
@ -579,7 +579,7 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool
|
||||
|
||||
if(GetLevel() < item->ReqLevel)
|
||||
return;
|
||||
|
||||
|
||||
if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType))
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);// Non-live like - Addititive latent effects
|
||||
|
||||
@ -691,7 +691,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
continue;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName());
|
||||
|
||||
|
||||
uint8 focus = IsFocusEffect(0, 0, true,effect);
|
||||
if (focus)
|
||||
{
|
||||
@ -1007,7 +1007,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
case SE_BlockBehind:
|
||||
newbon->BlockBehind += base1;
|
||||
break;
|
||||
|
||||
|
||||
case SE_StrikeThrough:
|
||||
case SE_StrikeThrough2:
|
||||
newbon->StrikeThrough += base1;
|
||||
@ -1313,7 +1313,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_Vampirism:
|
||||
newbon->Vampirism += base1;
|
||||
break;
|
||||
break;
|
||||
|
||||
case SE_FrenziedDevastation:
|
||||
newbon->FrenziedDevastation += base2;
|
||||
@ -1416,7 +1416,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
}
|
||||
|
||||
case SE_SkillProcSuccess:{
|
||||
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid)
|
||||
@ -1449,7 +1449,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(i = 0; i < buff_count; i++) {
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN){
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining, i, buffs[i].instrument_mod);
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining,i);
|
||||
|
||||
if (buffs[i].numhits > 0)
|
||||
Numhits(true);
|
||||
@ -1472,9 +1472,8 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
|
||||
}
|
||||
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *new_bonus, uint16 casterId,
|
||||
uint8 WornType, int32 ticsremaining, int buffslot, int instrument_mod,
|
||||
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, uint8 WornType, uint32 ticsremaining, int buffslot,
|
||||
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
||||
{
|
||||
int i, effect_value, base2, max, effectid;
|
||||
bool AdditiveWornBonus = false;
|
||||
@ -1510,9 +1509,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType))
|
||||
AdditiveWornBonus = true;
|
||||
|
||||
|
||||
effectid = spells[spell_id].effectid[i];
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, instrument_mod, caster, ticsremaining);
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining);
|
||||
base2 = spells[spell_id].base2[i];
|
||||
max = spells[spell_id].max[i];
|
||||
}
|
||||
@ -1561,49 +1560,100 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_AttackSpeed:
|
||||
{
|
||||
if ((effect_value - 100) > 0) { // Haste
|
||||
if (new_bonus->haste < 0) break; // Slowed - Don't apply haste
|
||||
if ((effect_value - 100) > new_bonus->haste) {
|
||||
new_bonus->haste = effect_value - 100;
|
||||
|
||||
if (AdditiveWornBonus) {
|
||||
if ((effect_value - 100) > 0) { // Haste
|
||||
if (new_bonus->haste < 0) break; // Slowed - Don't apply haste
|
||||
if ((effect_value - 100) > new_bonus->haste) {
|
||||
new_bonus->haste += effect_value - 100;
|
||||
}
|
||||
}
|
||||
else if ((effect_value - 100) < 0) { // Slow
|
||||
int real_slow_value = (100 - effect_value) * -1;
|
||||
real_slow_value -= ((real_slow_value * GetSlowMitigation()/100));
|
||||
if (real_slow_value < new_bonus->haste)
|
||||
new_bonus->haste += real_slow_value;
|
||||
}
|
||||
}
|
||||
else if ((effect_value - 100) < 0) { // Slow
|
||||
int real_slow_value = (100 - effect_value) * -1;
|
||||
real_slow_value -= ((real_slow_value * GetSlowMitigation()/100));
|
||||
if (real_slow_value < new_bonus->haste)
|
||||
new_bonus->haste = real_slow_value;
|
||||
else
|
||||
{
|
||||
if ((effect_value - 100) > 0) { // Haste
|
||||
if (new_bonus->haste < 0) break; // Slowed - Don't apply haste
|
||||
if ((effect_value - 100) > new_bonus->haste) {
|
||||
new_bonus->haste = effect_value - 100;
|
||||
}
|
||||
}
|
||||
else if ((effect_value - 100) < 0) { // Slow
|
||||
int real_slow_value = (100 - effect_value) * -1;
|
||||
real_slow_value -= ((real_slow_value * GetSlowMitigation()/100));
|
||||
if (real_slow_value < new_bonus->haste)
|
||||
new_bonus->haste = real_slow_value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_AttackSpeed2:
|
||||
{
|
||||
if ((effect_value - 100) > 0) { // Haste V2 - Stacks with V1 but does not Overcap
|
||||
if (new_bonus->hastetype2 < 0) break; //Slowed - Don't apply haste2
|
||||
if ((effect_value - 100) > new_bonus->hastetype2) {
|
||||
new_bonus->hastetype2 = effect_value - 100;
|
||||
{
|
||||
if (AdditiveWornBonus) {
|
||||
if ((effect_value - 100) > 0) { // Haste
|
||||
if (new_bonus->hastetype2 < 0) break; // Slowed - Don't apply haste
|
||||
if ((effect_value - 100) > new_bonus->hastetype2) {
|
||||
new_bonus->hastetype2 += effect_value - 100;
|
||||
}
|
||||
}
|
||||
else if ((effect_value - 100) < 0) { // Slow
|
||||
int real_slow_value = (100 - effect_value) * -1;
|
||||
real_slow_value -= ((real_slow_value * GetSlowMitigation()/100));
|
||||
if (real_slow_value < new_bonus->hastetype2)
|
||||
new_bonus->hastetype2 += real_slow_value;
|
||||
}
|
||||
}
|
||||
else if ((effect_value - 100) < 0) { // Slow
|
||||
int real_slow_value = (100 - effect_value) * -1;
|
||||
real_slow_value -= ((real_slow_value * GetSlowMitigation()/100));
|
||||
if (real_slow_value < new_bonus->hastetype2)
|
||||
new_bonus->hastetype2 = real_slow_value;
|
||||
else
|
||||
{
|
||||
if ((effect_value - 100) > 0) { // Haste
|
||||
if (new_bonus->hastetype2 < 0) break; // Slowed - Don't apply haste
|
||||
if ((effect_value - 100) > new_bonus->hastetype2) {
|
||||
new_bonus->hastetype2 = effect_value - 100;
|
||||
}
|
||||
}
|
||||
else if ((effect_value - 100) < 0) { // Slow
|
||||
int real_slow_value = (100 - effect_value) * -1;
|
||||
real_slow_value -= ((real_slow_value * GetSlowMitigation()/100));
|
||||
if (real_slow_value < new_bonus->hastetype2)
|
||||
new_bonus->hastetype2 = real_slow_value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_AttackSpeed3:
|
||||
{
|
||||
if (effect_value < 0){ //Slow
|
||||
effect_value -= ((effect_value * GetSlowMitigation()/100));
|
||||
if (effect_value < new_bonus->hastetype3)
|
||||
new_bonus->hastetype3 = effect_value;
|
||||
}
|
||||
if (AdditiveWornBonus) {
|
||||
if (effect_value < 0){ //Slow
|
||||
effect_value -= ((effect_value * GetSlowMitigation()/100));
|
||||
if (effect_value < new_bonus->hastetype3)
|
||||
new_bonus->hastetype3 += effect_value;
|
||||
}
|
||||
|
||||
else if (effect_value > 0) { // Haste V3 - Stacks and Overcaps
|
||||
if (effect_value > new_bonus->hastetype3) {
|
||||
new_bonus->hastetype3 = effect_value;
|
||||
else if (effect_value > 0) { // Haste V3 - Stacks and Overcaps
|
||||
if (effect_value > new_bonus->hastetype3) {
|
||||
new_bonus->hastetype3 += effect_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (effect_value < 0){ //Slow
|
||||
effect_value -= ((effect_value * GetSlowMitigation()/100));
|
||||
if (effect_value < new_bonus->hastetype3)
|
||||
new_bonus->hastetype3 = effect_value;
|
||||
}
|
||||
|
||||
else if (effect_value > 0) { // Haste V3 - Stacks and Overcaps
|
||||
if (effect_value > new_bonus->hastetype3) {
|
||||
new_bonus->hastetype3 = effect_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1618,13 +1668,21 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
if (effect_value < 0) //A few spells use negative values(Descriptions all indicate it should be a slow)
|
||||
effect_value = effect_value * -1;
|
||||
|
||||
if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) {
|
||||
effect_value -= ((effect_value * GetSlowMitigation()/100));
|
||||
if (effect_value > new_bonus->inhibitmelee)
|
||||
new_bonus->inhibitmelee = effect_value;
|
||||
if (AdditiveWornBonus) {
|
||||
if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) {
|
||||
effect_value -= ((effect_value * GetSlowMitigation()/100));
|
||||
if (effect_value > new_bonus->inhibitmelee)
|
||||
new_bonus->inhibitmelee += effect_value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) {
|
||||
effect_value -= ((effect_value * GetSlowMitigation()/100));
|
||||
if (effect_value > new_bonus->inhibitmelee)
|
||||
new_bonus->inhibitmelee = effect_value;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1840,7 +1898,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
new_bonus->DamageShieldType = GetDamageShieldType(spell_id, max);
|
||||
else
|
||||
new_bonus->DamageShieldType = GetDamageShieldType(spell_id);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2021,7 +2079,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_Vampirism:
|
||||
new_bonus->Vampirism += effect_value;
|
||||
break;
|
||||
break;
|
||||
|
||||
case SE_AllInstrumentMod:
|
||||
{
|
||||
@ -2264,7 +2322,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
case SE_CriticalSpellChance:
|
||||
{
|
||||
new_bonus->CriticalSpellChance += effect_value;
|
||||
|
||||
|
||||
if (base2 > new_bonus->SpellCritDmgIncNoStack)
|
||||
new_bonus->SpellCritDmgIncNoStack = base2;
|
||||
break;
|
||||
@ -2474,7 +2532,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_NegateAttacks:
|
||||
{
|
||||
if (!new_bonus->NegateAttacks[0] ||
|
||||
if (!new_bonus->NegateAttacks[0] ||
|
||||
((new_bonus->NegateAttacks[0] && new_bonus->NegateAttacks[2]) && (new_bonus->NegateAttacks[2] < max))){
|
||||
new_bonus->NegateAttacks[0] = 1;
|
||||
new_bonus->NegateAttacks[1] = buffslot;
|
||||
@ -2494,7 +2552,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
case SE_MeleeThresholdGuard:
|
||||
{
|
||||
if (new_bonus->MeleeThresholdGuard[0] < effect_value){
|
||||
@ -2861,17 +2919,17 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
new_bonus->NegateIfCombat = true;
|
||||
break;
|
||||
|
||||
case SE_Screech:
|
||||
case SE_Screech:
|
||||
new_bonus->Screech = effect_value;
|
||||
break;
|
||||
|
||||
case SE_AlterNPCLevel:
|
||||
|
||||
if (IsNPC()){
|
||||
if (!new_bonus->AlterNPCLevel
|
||||
|| ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value))
|
||||
if (!new_bonus->AlterNPCLevel
|
||||
|| ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value))
|
||||
|| ((effect_value > 0) && (new_bonus->AlterNPCLevel < effect_value))) {
|
||||
|
||||
|
||||
int tmp_lv = GetOrigLevel() + effect_value;
|
||||
if (tmp_lv < 1)
|
||||
tmp_lv = 1;
|
||||
@ -2909,7 +2967,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
new_bonus->BerserkSPA = true;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case SE_Metabolism:
|
||||
new_bonus->Metabolism += effect_value;
|
||||
break;
|
||||
@ -3010,7 +3068,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
}
|
||||
|
||||
case SE_SkillProc:{
|
||||
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(new_bonus->SkillProc[e] && new_bonus->SkillProc[e] == spell_id)
|
||||
@ -3025,7 +3083,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
}
|
||||
|
||||
case SE_SkillProcSuccess:{
|
||||
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(new_bonus->SkillProcSuccess[e] && new_bonus->SkillProcSuccess[e] == spell_id)
|
||||
@ -3041,9 +3099,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
|
||||
if (IsAISpellEffect) {
|
||||
|
||||
|
||||
//Non-Focused Effect to modify incoming spell damage by resist type.
|
||||
case SE_FcSpellVulnerability:
|
||||
case SE_FcSpellVulnerability:
|
||||
ModVulnerability(base2, effect_value);
|
||||
break;
|
||||
}
|
||||
@ -3109,7 +3167,7 @@ void NPC::CalcItemBonuses(StatBonuses *newbon)
|
||||
newbon->HitChance += cur->Accuracy;
|
||||
}
|
||||
if(cur->CombatEffects > 0) {
|
||||
newbon->ProcChance += cur->CombatEffects;
|
||||
newbon->MeleeDamage += cur->CombatEffects;
|
||||
}
|
||||
if (cur->Worn.Effect>0 && (cur->Worn.Type == ET_WornEffect)) { // latent effects
|
||||
ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon, 0, cur->Worn.Type);
|
||||
@ -4395,7 +4453,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
aabonuses.SlayUndead[0] = effect_value;
|
||||
aabonuses.SlayUndead[1] = effect_value;
|
||||
break;
|
||||
|
||||
|
||||
case SE_DoubleRangedAttack:
|
||||
spellbonuses.DoubleRangedAttack = effect_value;
|
||||
aabonuses.DoubleRangedAttack = effect_value;
|
||||
@ -4415,7 +4473,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
aabonuses.ShieldEquipDmgMod[1] = effect_value;
|
||||
itembonuses.ShieldEquipDmgMod[0] = effect_value;
|
||||
itembonuses.ShieldEquipDmgMod[1] = effect_value;
|
||||
break;
|
||||
break;
|
||||
|
||||
case SE_TriggerMeleeThreshold:
|
||||
spellbonuses.TriggerMeleeThreshold = false;
|
||||
|
||||
28
zone/bot.cpp
28
zone/bot.cpp
@ -292,9 +292,7 @@ void Bot::ChangeBotArcherWeapons(bool isArcher) {
|
||||
void Bot::Sit() {
|
||||
if(IsMoving()) {
|
||||
moved = false;
|
||||
// SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
tar_ndx = 0;
|
||||
}
|
||||
|
||||
@ -3448,11 +3446,10 @@ void Bot::AI_Process() {
|
||||
if(IsMoving()) {
|
||||
SetHeading(0);
|
||||
SetRunAnimSpeed(0);
|
||||
SetCurrentSpeed(GetRunSpeed());
|
||||
|
||||
if(moved) {
|
||||
moved = false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3495,11 +3492,10 @@ void Bot::AI_Process() {
|
||||
if(IsMoving()) {
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
|
||||
SetCurrentSpeed(0);
|
||||
if(moved) {
|
||||
moved = false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3517,11 +3513,10 @@ void Bot::AI_Process() {
|
||||
if(IsMoving()) {
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
|
||||
SetCurrentSpeed(0);
|
||||
if(moved) {
|
||||
moved = false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3740,7 +3735,7 @@ void Bot::AI_Process() {
|
||||
|
||||
if(follow) {
|
||||
float dist = DistanceSquared(m_Position, follow->GetPosition());
|
||||
float speed = follow->GetRunspeed();
|
||||
int speed = follow->GetRunspeed();
|
||||
|
||||
if(dist < GetFollowDistance() + 1000)
|
||||
speed = follow->GetWalkspeed();
|
||||
@ -3757,9 +3752,8 @@ void Bot::AI_Process() {
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
moved=false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
moved = false;
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3987,6 +3981,7 @@ void Bot::PetAIProcess() {
|
||||
botPet->SetHeading(botPet->GetTarget()->GetHeading());
|
||||
if(moved) {
|
||||
moved=false;
|
||||
SetCurrentSpeed(0);
|
||||
botPet->SendPosition();
|
||||
botPet->SetMoving(false);
|
||||
}
|
||||
@ -4020,6 +4015,7 @@ void Bot::PetAIProcess() {
|
||||
botPet->SetHeading(botPet->GetTarget()->GetHeading());
|
||||
if(moved) {
|
||||
moved=false;
|
||||
SetCurrentSpeed(0);
|
||||
botPet->SendPosition();
|
||||
botPet->SetMoving(false);
|
||||
}
|
||||
|
||||
@ -4991,7 +4991,7 @@ void Client::SetShadowStepExemption(bool v)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
printf("%s %i moving too fast! moved: %.2f in %ims, speed %.2f\n", __FILE__, __LINE__,
|
||||
@ -5048,7 +5048,7 @@ void Client::SetKnockBackExemption(bool v)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
|
||||
@ -5105,7 +5105,7 @@ void Client::SetPortExemption(bool v)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
|
||||
|
||||
@ -557,6 +557,7 @@ public:
|
||||
void SendCrystalCounts();
|
||||
|
||||
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
|
||||
uint32 CalcEXP(uint8 conlevel = 0xFF);
|
||||
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false);
|
||||
void AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0);
|
||||
void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp);
|
||||
@ -1129,7 +1130,6 @@ public:
|
||||
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
|
||||
void DragCorpses();
|
||||
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
|
||||
inline void ResetPositionTimer() { position_timer_counter = 0; }
|
||||
void SendAltCurrencies();
|
||||
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
|
||||
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
|
||||
|
||||
@ -4266,7 +4266,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 0)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
|
||||
@ -4334,7 +4334,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 2500)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
|
||||
|
||||
@ -1484,7 +1484,7 @@ void command_npcstats(Client *c, const Seperator *sep)
|
||||
c->Message(0, "Current HP: %i Max HP: %i", c->GetTarget()->GetHP(), c->GetTarget()->GetMaxHP());
|
||||
//c->Message(0, "Weapon Item Number: %s", c->GetTarget()->GetWeapNo());
|
||||
c->Message(0, "Gender: %i Size: %f Bodytype: %d", c->GetTarget()->GetGender(), c->GetTarget()->GetSize(), c->GetTarget()->GetBodyType());
|
||||
c->Message(0, "Runspeed: %f Walkspeed: %f", c->GetTarget()->GetRunspeed(), c->GetTarget()->GetWalkspeed());
|
||||
c->Message(0, "Runspeed: %i Walkspeed: %i", c->GetTarget()->GetRunspeed(), c->GetTarget()->GetWalkspeed());
|
||||
c->Message(0, "Spawn Group: %i Grid: %i", c->GetTarget()->CastToNPC()->GetSp2(), c->GetTarget()->CastToNPC()->GetGrid());
|
||||
c->Message(0, "EmoteID: %i", c->GetTarget()->CastToNPC()->GetEmoteID());
|
||||
c->GetTarget()->CastToNPC()->QueryLoot(c);
|
||||
|
||||
@ -89,7 +89,7 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
if (IsClient() && GetClass() == WIZARD)
|
||||
ratio += RuleI(Spells, WizCritRatio); //Default is zero
|
||||
|
||||
|
||||
if (Critical){
|
||||
|
||||
value = value_BaseEffect*ratio/100;
|
||||
@ -138,7 +138,7 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
|
||||
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
|
||||
if(itembonuses.SpellDmg)
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);
|
||||
|
||||
if (IsNPC() && CastToNPC()->GetSpellScale())
|
||||
@ -172,7 +172,7 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100;
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
|
||||
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
|
||||
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
|
||||
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
|
||||
int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) +
|
||||
GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
|
||||
@ -200,6 +200,11 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
extra_dmg /= duration;
|
||||
}
|
||||
|
||||
//Sanctuary Custom: Spelldmg per tick
|
||||
if(itembonuses.SpellDmg)
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg / 6, value); //per tick
|
||||
|
||||
|
||||
value -= extra_dmg;
|
||||
}
|
||||
|
||||
@ -211,23 +216,6 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg)
|
||||
{
|
||||
int total_cast_time = 0;
|
||||
|
||||
if (spells[spell_id].recast_time >= spells[spell_id].recovery_time)
|
||||
total_cast_time = spells[spell_id].recast_time + spells[spell_id].cast_time;
|
||||
else
|
||||
total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time;
|
||||
|
||||
if (total_cast_time > 0 && total_cast_time <= 2500)
|
||||
extra_spell_amt = extra_spell_amt*25/100;
|
||||
else if (total_cast_time > 2500 && total_cast_time < 7000)
|
||||
extra_spell_amt = extra_spell_amt*(167*((total_cast_time - 1000)/1000)) / 1000;
|
||||
else
|
||||
extra_spell_amt = extra_spell_amt * total_cast_time / 7000;
|
||||
|
||||
if(extra_spell_amt*2 < base_spell_dmg)
|
||||
return 0;
|
||||
|
||||
return extra_spell_amt;
|
||||
}
|
||||
|
||||
@ -270,7 +258,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
value += GetFocusEffect(focusFcHealAmt, spell_id);
|
||||
value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);
|
||||
|
||||
if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
|
||||
if(itembonuses.HealAmt)
|
||||
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier;
|
||||
|
||||
value += value*target->GetHealRate(spell_id, this)/100;
|
||||
@ -281,7 +269,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
if (Critical) {
|
||||
entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
|
||||
OTHER_CRIT_HEAL, GetName(), itoa(value));
|
||||
|
||||
|
||||
if (IsClient())
|
||||
Message_StringID(MT_SpellCrits, YOU_CRIT_HEAL, itoa(value));
|
||||
}
|
||||
@ -301,6 +289,9 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
if(chance && zone->random.Roll(chance))
|
||||
value *= 2;
|
||||
|
||||
if(itembonuses.HealAmt)
|
||||
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt / 6, value) * modifier;
|
||||
}
|
||||
|
||||
if (IsNPC() && CastToNPC()->GetHealScale())
|
||||
@ -421,10 +412,14 @@ int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
|
||||
int tic_inc = 0;
|
||||
tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id);
|
||||
|
||||
// unsure on the exact details, but bard songs that don't cost mana at some point get an extra tick, 60 for now
|
||||
// a level 53 bard reported getting 2 tics
|
||||
if (IsShortDurationBuff(spell_id) && IsBardSong(spell_id) && spells[spell_id].mana == 0 && GetClass() == BARD && GetLevel() > 60)
|
||||
tic_inc++;
|
||||
// Only need this for clients, since the change was for bard songs, I assume we should keep non bard songs getting +1
|
||||
// However if its bard or not and is mez, charm or fear, we need to add 1 so that client is in sync
|
||||
if (IsClient() && !(IsShortDurationBuff(spell_id) && IsBardSong(spell_id)) ||
|
||||
IsFearSpell(spell_id) ||
|
||||
IsCharmSpell(spell_id) ||
|
||||
IsMezSpell(spell_id) ||
|
||||
IsBlindSpell(spell_id))
|
||||
tic_inc += 1;
|
||||
|
||||
return (((duration * increase) / 100) + tic_inc);
|
||||
}
|
||||
@ -767,7 +762,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
}
|
||||
} else {
|
||||
if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets)
|
||||
if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets)
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
if (!spells[spell_id].aemaxtargets)
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
@ -855,7 +850,7 @@ void EntityList::AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool aff
|
||||
if (!center->CheckLosFN(curmob))
|
||||
continue;
|
||||
} else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies...
|
||||
// See notes in AESpell() above for more info.
|
||||
// See notes in AESpell() above for more info.
|
||||
if (caster->IsAttackAllowed(curmob, true))
|
||||
continue;
|
||||
if (caster->CheckAggro(curmob))
|
||||
|
||||
@ -1321,6 +1321,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
ExportVar(package_name.c_str(), "itemid", objid);
|
||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||
ExportVar(package_name.c_str(), "slotid", extradata);
|
||||
ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1399,6 +1400,14 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
|
||||
break;
|
||||
}
|
||||
case EVENT_DROP_ITEM: {
|
||||
ExportVar(package_name.c_str(), "quantity", iteminst->IsStackable() ? iteminst->GetCharges() : 1);
|
||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||
ExportVar(package_name.c_str(), "itemid", iteminst->GetItem()->ID);
|
||||
ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect);
|
||||
ExportVar(package_name.c_str(), "slotid", extradata);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
|
||||
109
zone/exp.cpp
109
zone/exp.cpp
@ -59,6 +59,97 @@ static uint32 MaxBankedRaidLeadershipPoints(int Level)
|
||||
return 10;
|
||||
}
|
||||
|
||||
uint32 Client::CalcEXP(uint8 conlevel) {
|
||||
|
||||
uint32 in_add_exp = EXP_FORMULA;
|
||||
|
||||
|
||||
if((XPRate != 0))
|
||||
in_add_exp = static_cast<uint32>(in_add_exp * (static_cast<float>(XPRate) / 100.0f));
|
||||
|
||||
float totalmod = 1.0;
|
||||
float zemmod = 1.0;
|
||||
//get modifiers
|
||||
if(RuleR(Character, ExpMultiplier) >= 0){
|
||||
totalmod *= RuleR(Character, ExpMultiplier);
|
||||
}
|
||||
|
||||
if(zone->newzone_data.zone_exp_multiplier >= 0){
|
||||
zemmod *= zone->newzone_data.zone_exp_multiplier;
|
||||
}
|
||||
|
||||
if(RuleB(Character,UseRaceClassExpBonuses))
|
||||
{
|
||||
if(GetBaseRace() == HALFLING){
|
||||
totalmod *= 1.05;
|
||||
}
|
||||
|
||||
if(GetClass() == ROGUE || GetClass() == WARRIOR){
|
||||
totalmod *= 1.05;
|
||||
}
|
||||
}
|
||||
|
||||
if(zone->IsHotzone())
|
||||
{
|
||||
totalmod += RuleR(Zone, HotZoneBonus);
|
||||
}
|
||||
|
||||
in_add_exp = uint32(float(in_add_exp) * totalmod * zemmod);
|
||||
|
||||
if(RuleB(Character,UseXPConScaling))
|
||||
{
|
||||
if (conlevel != 0xFF) {
|
||||
switch (conlevel)
|
||||
{
|
||||
case CON_GREEN:
|
||||
in_add_exp = 0;
|
||||
return 0;
|
||||
case CON_LIGHTBLUE:
|
||||
in_add_exp = in_add_exp * RuleI(Character, LightBlueModifier)/100;
|
||||
break;
|
||||
case CON_BLUE:
|
||||
in_add_exp = in_add_exp * RuleI(Character, BlueModifier)/100;
|
||||
break;
|
||||
case CON_WHITE:
|
||||
in_add_exp = in_add_exp * RuleI(Character, WhiteModifier)/100;
|
||||
break;
|
||||
case CON_YELLOW:
|
||||
in_add_exp = in_add_exp * RuleI(Character, YellowModifier)/100;
|
||||
break;
|
||||
case CON_RED:
|
||||
in_add_exp = in_add_exp * RuleI(Character, RedModifier)/100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float aatotalmod = 1.0;
|
||||
if(zone->newzone_data.zone_exp_multiplier >= 0){
|
||||
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(RuleB(Character,UseRaceClassExpBonuses))
|
||||
{
|
||||
if(GetBaseRace() == HALFLING){
|
||||
aatotalmod *= 1.05;
|
||||
}
|
||||
|
||||
if(GetClass() == ROGUE || GetClass() == WARRIOR){
|
||||
aatotalmod *= 1.05;
|
||||
}
|
||||
}
|
||||
|
||||
if(RuleB(Zone, LevelBasedEXPMods)){
|
||||
if(zone->level_exp_mod[GetLevel()].ExpMod){
|
||||
in_add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
|
||||
}
|
||||
}
|
||||
|
||||
return in_add_exp;
|
||||
}
|
||||
|
||||
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
|
||||
this->EVENT_ITEM_ScriptStopReturn();
|
||||
@ -78,7 +169,7 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
|
||||
//figure out how much of this goes to AAs
|
||||
add_aaxp = add_exp * m_epp.perAA / 100;
|
||||
//take that ammount away from regular exp
|
||||
//take that amount away from regular exp
|
||||
add_exp -= add_aaxp;
|
||||
|
||||
float totalmod = 1.0;
|
||||
@ -247,12 +338,22 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
Message(13, "Error in Client::SetEXP. EXP not set.");
|
||||
return; // Must be invalid class/race
|
||||
}
|
||||
uint32 i = 0;
|
||||
uint32 membercount = 0;
|
||||
if(GetGroup())
|
||||
{
|
||||
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if (GetGroup()->members[i] != nullptr) {
|
||||
membercount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) {
|
||||
if (isrezzexp)
|
||||
this->Message_StringID(MT_Experience, REZ_REGAIN);
|
||||
else{
|
||||
if(this->IsGrouped())
|
||||
if(membercount > 1)
|
||||
this->Message_StringID(MT_Experience, GAIN_GROUPXP);
|
||||
else if(IsRaidGrouped())
|
||||
Message_StringID(MT_Experience, GAIN_RAIDEXP);
|
||||
@ -604,8 +705,8 @@ void Group::SplitExp(uint32 exp, Mob* other) {
|
||||
groupmod = 2.16;
|
||||
else
|
||||
groupmod = 1.0;
|
||||
|
||||
groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier)));
|
||||
if(membercount > 1 && membercount < 6)
|
||||
groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier)));
|
||||
|
||||
int conlevel = Mob::GetLevelCon(maxlevel, other->GetLevel());
|
||||
if(conlevel == CON_GREEN)
|
||||
|
||||
@ -123,29 +123,6 @@ void Mob::ProcessFlee()
|
||||
}
|
||||
}
|
||||
|
||||
float Mob::GetFearSpeed()
|
||||
{
|
||||
if (flee_mode) {
|
||||
//we know ratio < FLEE_HP_RATIO
|
||||
float speed = GetBaseRunspeed();
|
||||
float ratio = GetHPRatio();
|
||||
float multiplier = RuleR(Combat, FleeMultiplier);
|
||||
|
||||
if (GetSnaredAmount() > 40)
|
||||
multiplier = multiplier / 6.0f;
|
||||
|
||||
speed = speed * ratio * multiplier / 100;
|
||||
|
||||
//NPC will eventually stop. Snares speeds this up.
|
||||
if (speed < 0.09)
|
||||
speed = 0.0001f;
|
||||
|
||||
return speed;
|
||||
}
|
||||
// fear and blind use their normal run speed
|
||||
return GetRunspeed();
|
||||
}
|
||||
|
||||
void Mob::CalculateNewFearpoint()
|
||||
{
|
||||
if(RuleB(Pathing, Fear) && zone->pathing)
|
||||
|
||||
@ -606,7 +606,7 @@ void Client::DropItem(int16 slot_id)
|
||||
// Take control of item in client inventory
|
||||
ItemInst *inst = m_inv.PopItem(slot_id);
|
||||
if(inst) {
|
||||
int i = parse->EventItem(EVENT_DROP_ITEM, this, inst, nullptr, "", 0);
|
||||
int i = parse->EventItem(EVENT_DROP_ITEM, this, inst, nullptr, "", slot_id);
|
||||
if(i != 0) {
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
@ -1460,8 +1460,7 @@ void Merc::AI_Process() {
|
||||
|
||||
if(moved) {
|
||||
moved = false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1497,9 +1496,7 @@ void Merc::AI_Process() {
|
||||
SetRunAnimSpeed(0);
|
||||
|
||||
if(moved) {
|
||||
moved = false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1710,7 +1707,7 @@ void Merc::AI_Process() {
|
||||
if(follow)
|
||||
{
|
||||
float dist = DistanceSquared(m_Position, follow->GetPosition());
|
||||
float speed = GetRunspeed();
|
||||
int speed = GetRunspeed();
|
||||
|
||||
if(dist < GetFollowDistance() + 1000)
|
||||
speed = GetWalkspeed();
|
||||
@ -1727,9 +1724,8 @@ void Merc::AI_Process() {
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
moved=false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
moved = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
282
zone/mob.cpp
282
zone/mob.cpp
@ -26,6 +26,7 @@
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
@ -148,6 +149,28 @@ Mob::Mob(const char* in_name,
|
||||
size = in_size;
|
||||
base_size = size;
|
||||
runspeed = in_runspeed;
|
||||
// neotokyo: sanity check
|
||||
if (runspeed < 0 || runspeed > 20)
|
||||
runspeed = 1.25f;
|
||||
base_runspeed = (int)((float)runspeed * 40.0f);
|
||||
// clients
|
||||
if (runspeed == 0.7f) {
|
||||
base_runspeed = 28;
|
||||
walkspeed = 0.3f;
|
||||
base_walkspeed = 12;
|
||||
fearspeed = 0.625f;
|
||||
base_fearspeed = 25;
|
||||
// npcs
|
||||
} else {
|
||||
base_walkspeed = base_runspeed * 100 / 265;
|
||||
walkspeed = ((float)base_walkspeed) * 0.025f;
|
||||
base_fearspeed = base_runspeed * 100 / 127;
|
||||
fearspeed = ((float)base_fearspeed) * 0.025f;
|
||||
}
|
||||
|
||||
|
||||
current_speed = base_runspeed;
|
||||
|
||||
m_PlayerState = 0;
|
||||
|
||||
|
||||
@ -531,48 +554,32 @@ bool Mob::IsInvisible(Mob* other) const
|
||||
return(false);
|
||||
}
|
||||
|
||||
float Mob::_GetMovementSpeed(int mod) const
|
||||
{
|
||||
// List of movement speed modifiers, including AAs & spells:
|
||||
// http://everquest.allakhazam.com/db/item.html?item=1721;page=1;howmany=50#m10822246245352
|
||||
if (IsRooted())
|
||||
return 0.0f;
|
||||
int Mob::_GetWalkSpeed() const {
|
||||
|
||||
if (IsRooted() || IsStunned() || IsMezzed())
|
||||
return 0;
|
||||
|
||||
else if (IsPseudoRooted())
|
||||
return 0.00001f;
|
||||
return 0;
|
||||
|
||||
float speed_mod = runspeed;
|
||||
int aa_mod = 0;
|
||||
int speed_mod = base_walkspeed;
|
||||
int base_run = base_runspeed;
|
||||
bool has_horse = false;
|
||||
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
|
||||
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
aa_mod += aabonuses.BaseMovementSpeed;
|
||||
|
||||
// These two cases ignore the cap, be wise in the DB for horses.
|
||||
if (IsClient()) {
|
||||
if (CastToClient()->GetGMSpeed()) {
|
||||
speed_mod = 3.125f;
|
||||
if (mod != 0)
|
||||
speed_mod += speed_mod * static_cast<float>(mod) / 100.0f;
|
||||
Mob *horse = entity_list.GetMob(CastToClient()->GetHorseId());
|
||||
if (horse) {
|
||||
speed_mod = horse->GetBaseRunspeed();
|
||||
return speed_mod;
|
||||
} else {
|
||||
Mob *horse = entity_list.GetMob(CastToClient()->GetHorseId());
|
||||
if (horse) {
|
||||
speed_mod = horse->GetBaseRunspeed();
|
||||
if (mod != 0)
|
||||
speed_mod += speed_mod * static_cast<float>(mod) / 100.0f;
|
||||
return speed_mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int aa_mod = 0;
|
||||
int spell_mod = 0;
|
||||
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
|
||||
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
int movemod = 0;
|
||||
float frunspeedcap = 0.0f;
|
||||
|
||||
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
aa_mod += itembonuses.BaseMovementSpeed + spellbonuses.BaseMovementSpeed + aabonuses.BaseMovementSpeed;
|
||||
spell_mod += spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
|
||||
// hard cap
|
||||
if (runspeedcap > 225)
|
||||
runspeedcap = 225;
|
||||
|
||||
if (spell_mod < 0)
|
||||
movemod += spell_mod;
|
||||
@ -581,27 +588,189 @@ float Mob::_GetMovementSpeed(int mod) const
|
||||
else
|
||||
movemod = aa_mod;
|
||||
|
||||
// cap negative movemods from snares mostly
|
||||
if (movemod < -85)
|
||||
// hard cap
|
||||
if (runspeedcap > 225)
|
||||
runspeedcap = 225;
|
||||
|
||||
if(movemod < -85) //cap it at moving very very slow
|
||||
movemod = -85;
|
||||
|
||||
if (movemod != 0)
|
||||
speed_mod += speed_mod * static_cast<float>(movemod) / 100.0f;
|
||||
if (!has_horse && movemod != 0)
|
||||
speed_mod += (base_run * movemod / 100);
|
||||
|
||||
// runspeed caps
|
||||
frunspeedcap = static_cast<float>(runspeedcap) / 100.0f;
|
||||
if (IsClient() && speed_mod > frunspeedcap)
|
||||
speed_mod = frunspeedcap;
|
||||
if(speed_mod < 1)
|
||||
return(1);
|
||||
|
||||
// apply final mod such as the -47 for walking
|
||||
// use runspeed since it should stack with snares
|
||||
// and if we get here, we know runspeed was the initial
|
||||
// value before we applied movemod.
|
||||
if (mod != 0)
|
||||
speed_mod += runspeed * static_cast<float>(mod) / 100.0f;
|
||||
//runspeed cap.
|
||||
if(IsClient())
|
||||
{
|
||||
if(speed_mod > runspeedcap)
|
||||
speed_mod = runspeedcap;
|
||||
}
|
||||
return speed_mod;
|
||||
}
|
||||
|
||||
if (speed_mod <= 0.0f)
|
||||
speed_mod = IsClient() ? 0.0001f : 0.0f;
|
||||
int Mob::_GetRunSpeed() const {
|
||||
if (IsRooted() || IsStunned() || IsMezzed())
|
||||
return 0;
|
||||
|
||||
int aa_mod = 0;
|
||||
int speed_mod = base_runspeed;
|
||||
int base_walk = base_walkspeed;
|
||||
bool has_horse = false;
|
||||
if (IsClient())
|
||||
{
|
||||
if(CastToClient()->GetGMSpeed())
|
||||
{
|
||||
speed_mod = 325;
|
||||
}
|
||||
else
|
||||
{
|
||||
Mob* horse = entity_list.GetMob(CastToClient()->GetHorseId());
|
||||
if(horse)
|
||||
{
|
||||
speed_mod = horse->GetBaseRunspeed();
|
||||
base_walk = horse->GetBaseWalkspeed();
|
||||
has_horse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
|
||||
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
|
||||
aa_mod = itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
int movemod = 0;
|
||||
|
||||
if(spell_mod < 0)
|
||||
{
|
||||
movemod += spell_mod;
|
||||
}
|
||||
else if(spell_mod > aa_mod)
|
||||
{
|
||||
movemod = spell_mod;
|
||||
}
|
||||
else
|
||||
{
|
||||
movemod = aa_mod;
|
||||
}
|
||||
|
||||
if(movemod < -85) //cap it at moving very very slow
|
||||
movemod = -85;
|
||||
|
||||
if (!has_horse && movemod != 0)
|
||||
{
|
||||
if (IsClient())
|
||||
{
|
||||
speed_mod += (speed_mod * movemod / 100);
|
||||
} else {
|
||||
if (movemod < 0) {
|
||||
speed_mod += (50 * movemod / 100);
|
||||
// basically stoped
|
||||
if(speed_mod < 1)
|
||||
{
|
||||
return(1);
|
||||
}
|
||||
// moving slowly
|
||||
if (speed_mod < 8)
|
||||
return(8);
|
||||
} else {
|
||||
speed_mod += GetBaseWalkspeed();
|
||||
if (movemod > 50)
|
||||
speed_mod += 4;
|
||||
if (movemod > 40)
|
||||
speed_mod += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(speed_mod < 1)
|
||||
{
|
||||
return(1);
|
||||
}
|
||||
//runspeed cap.
|
||||
if(IsClient())
|
||||
{
|
||||
if(speed_mod > runspeedcap)
|
||||
speed_mod = runspeedcap;
|
||||
}
|
||||
return speed_mod;
|
||||
}
|
||||
|
||||
int Mob::_GetFearSpeed() const {
|
||||
|
||||
if (IsRooted() || IsStunned() || IsMezzed())
|
||||
return 0;
|
||||
|
||||
//float speed_mod = fearspeed;
|
||||
int speed_mod = GetBaseFearSpeed();
|
||||
|
||||
// use a max of 1.75f in calcs.
|
||||
int base_run = std::min(GetBaseRunspeed(), 70);
|
||||
|
||||
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
int movemod = 0;
|
||||
|
||||
if(spell_mod < 0)
|
||||
{
|
||||
movemod += spell_mod;
|
||||
}
|
||||
|
||||
if(movemod < -85) //cap it at moving very very slow
|
||||
movemod = -85;
|
||||
|
||||
if (IsClient()) {
|
||||
if (CastToClient()->IsRunning())
|
||||
speed_mod = GetBaseRunspeed();
|
||||
else
|
||||
speed_mod = GetBaseWalkspeed();
|
||||
if (movemod < 0)
|
||||
return GetBaseWalkspeed();
|
||||
speed_mod += (base_run * movemod / 100);
|
||||
return speed_mod;
|
||||
} else {
|
||||
int hp_ratio = GetIntHPRatio();
|
||||
// very large snares 50% or higher
|
||||
if (movemod < -49)
|
||||
{
|
||||
if (hp_ratio < 25)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
if (hp_ratio < 50)
|
||||
return (8);
|
||||
else
|
||||
return (12);
|
||||
}
|
||||
if (hp_ratio < 5) {
|
||||
speed_mod = base_walkspeed / 3;
|
||||
} else if (hp_ratio < 15) {
|
||||
speed_mod = base_walkspeed / 2;
|
||||
} else if (hp_ratio < 25) {
|
||||
speed_mod = base_walkspeed + 1; // add the +1 so they do the run animation
|
||||
} else if (hp_ratio < 50) {
|
||||
speed_mod *= 82;
|
||||
speed_mod /= 100;
|
||||
}
|
||||
if (movemod > 0) {
|
||||
speed_mod += GetBaseWalkspeed();
|
||||
if (movemod > 50)
|
||||
speed_mod += 4;
|
||||
if (movemod > 40)
|
||||
speed_mod += 3;
|
||||
return speed_mod;
|
||||
}
|
||||
else if (movemod < 0) {
|
||||
speed_mod += (base_run * movemod / 100);
|
||||
}
|
||||
}
|
||||
if (speed_mod < 1)
|
||||
return (1);
|
||||
if (speed_mod < 9)
|
||||
return (8);
|
||||
if (speed_mod < 13)
|
||||
return (12);
|
||||
|
||||
return speed_mod;
|
||||
}
|
||||
@ -1201,7 +1370,6 @@ void Mob::SendPosition()
|
||||
PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)app->pBuffer;
|
||||
MakeSpawnUpdateNoDelta(spu);
|
||||
move_tic_count = 0;
|
||||
tar_ndx = 20;
|
||||
entity_list.QueueClients(this, app, true);
|
||||
safe_delete(app);
|
||||
}
|
||||
@ -1303,7 +1471,7 @@ void Mob::ShowStats(Client* client)
|
||||
if(n->respawn2 != 0)
|
||||
spawngroupid = n->respawn2->SpawnGroupID();
|
||||
client->Message(0, " NPCID: %u SpawnGroupID: %u Grid: %i LootTable: %u FactionID: %i SpellsID: %u ", GetNPCTypeID(),spawngroupid, n->GetGrid(), n->GetLoottableID(), n->GetNPCFactionID(), n->GetNPCSpellsID());
|
||||
client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %f Walkspeed: %f", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), n->GetRunspeed(), n->GetWalkspeed());
|
||||
client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %u Walkspeed: %u", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), n->GetRunspeed(), n->GetWalkspeed());
|
||||
n->QueryLoot(client);
|
||||
}
|
||||
if (IsAIControlled()) {
|
||||
@ -5437,3 +5605,15 @@ void Mob::SendRemovePlayerState(PlayerState old_state)
|
||||
safe_delete(app);
|
||||
}
|
||||
|
||||
void Mob::SetCurrentSpeed(int in){
|
||||
if (current_speed != in)
|
||||
{
|
||||
current_speed = in;
|
||||
tar_ndx = 20;
|
||||
if (in == 0) {
|
||||
SetRunAnimSpeed(0);
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
30
zone/mob.h
30
zone/mob.h
@ -364,6 +364,7 @@ public:
|
||||
inline Mob* GetTarget() const { return target; }
|
||||
virtual void SetTarget(Mob* mob);
|
||||
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); }
|
||||
virtual inline float GetIntHPRatio() const { return max_hp == 0 ? 0 : (cur_hp/max_hp*100); }
|
||||
inline virtual int32 GetAC() const { return AC + itembonuses.AC + spellbonuses.AC; }
|
||||
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; }
|
||||
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
|
||||
@ -441,9 +442,12 @@ public:
|
||||
virtual void SetMoving(bool move) { moving = move; m_Delta = glm::vec4(); }
|
||||
virtual void GoToBind(uint8 bindnum = 0) { }
|
||||
virtual void Gate();
|
||||
float GetWalkspeed() const { return(_GetMovementSpeed(-47)); }
|
||||
float GetRunspeed() const { return(_GetMovementSpeed(0)); }
|
||||
float GetBaseRunspeed() const { return runspeed; }
|
||||
int GetWalkspeed() const { return(_GetWalkSpeed()); }
|
||||
int GetRunspeed() const { return(_GetRunSpeed()); }
|
||||
void SetCurrentSpeed(int in);
|
||||
int GetBaseRunspeed() const { return base_runspeed; }
|
||||
int GetBaseWalkspeed() const { return base_walkspeed; }
|
||||
int GetBaseFearSpeed() const { return base_fearspeed; }
|
||||
float GetMovespeed() const { return IsRunning() ? GetRunspeed() : GetWalkspeed(); }
|
||||
bool IsRunning() const { return m_is_running; }
|
||||
void SetRunning(bool val) { m_is_running = val; }
|
||||
@ -801,7 +805,7 @@ public:
|
||||
|
||||
//old fear function
|
||||
//void SetFeared(Mob *caster, uint32 duration, bool flee = false);
|
||||
float GetFearSpeed();
|
||||
int GetFearSpeed() { return _GetFearSpeed(); }
|
||||
bool IsFeared() { return (spellbonuses.IsFeared || flee_mode); } // This returns true if the mob is feared or fleeing due to low HP
|
||||
inline void StartFleeing() { flee_mode = true; CalculateNewFearpoint(); }
|
||||
void ProcessFlee();
|
||||
@ -810,8 +814,8 @@ public:
|
||||
|
||||
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
|
||||
float CalculateHeadingToTarget(float in_x, float in_y);
|
||||
bool CalculateNewPosition(float x, float y, float z, float speed, bool checkZ = false);
|
||||
virtual bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true);
|
||||
bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = false, bool calcheading = true);
|
||||
virtual bool CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ = true, bool calcheading = true);
|
||||
float CalculateDistance(float x, float y, float z);
|
||||
float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||
void SendTo(float new_x, float new_y, float new_z);
|
||||
@ -882,6 +886,8 @@ public:
|
||||
Timer *GetSpecialAbilityTimer(int ability);
|
||||
void ClearSpecialAbilities();
|
||||
void ProcessSpecialAbilities(const std::string &str);
|
||||
bool IsMoved() { return moved; }
|
||||
void SetMoved(bool moveflag) { moved = moveflag; }
|
||||
|
||||
Shielders_Struct shielder[MAX_SHIELDERS];
|
||||
Trade* trade;
|
||||
@ -951,7 +957,10 @@ protected:
|
||||
void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic);
|
||||
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
||||
float _GetMovementSpeed(int mod) const;
|
||||
virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool checkZ);
|
||||
int _GetWalkSpeed() const;
|
||||
int _GetRunSpeed() const;
|
||||
int _GetFearSpeed() const;
|
||||
virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ);
|
||||
|
||||
virtual bool AI_EngagedCastCheck() { return(false); }
|
||||
virtual bool AI_PursueCastCheck() { return(false); }
|
||||
@ -1048,6 +1057,13 @@ protected:
|
||||
float base_size;
|
||||
float size;
|
||||
float runspeed;
|
||||
float walkspeed;
|
||||
float fearspeed;
|
||||
int base_runspeed;
|
||||
int base_walkspeed;
|
||||
int base_fearspeed;
|
||||
int current_speed;
|
||||
|
||||
uint32 pLastChange;
|
||||
bool held;
|
||||
bool nocast;
|
||||
|
||||
291
zone/mob_ai.cpp
291
zone/mob_ai.cpp
@ -339,9 +339,7 @@ bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
|
||||
|
||||
//stop moving if were casting a spell and were not a bard...
|
||||
if(!IsBardSong(AIspells[i].spellid)) {
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
|
||||
return CastSpell(AIspells[i].spellid, tar->GetID(), 1, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0, &(AIspells[i].resist_adjust));
|
||||
@ -698,9 +696,7 @@ void Client::AI_SpellCast()
|
||||
{
|
||||
if(!IsBardSong(spell_to_cast))
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
|
||||
return;
|
||||
@ -714,9 +710,7 @@ void Client::AI_SpellCast()
|
||||
{
|
||||
if(!IsBardSong(spell_to_cast))
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
|
||||
return;
|
||||
@ -772,16 +766,13 @@ void Client::AI_Process()
|
||||
{
|
||||
if(GetTarget())
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
//continue on to attack code, ensuring that we execute the engaged code
|
||||
engaged = true;
|
||||
} else {
|
||||
if(AImovement_timer->Check()) {
|
||||
animation = GetRunspeed() * 21;
|
||||
//animation = GetFearSpeed() * 21;
|
||||
// Check if we have reached the last fear point
|
||||
if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) &&
|
||||
(std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) {
|
||||
@ -839,16 +830,13 @@ void Client::AI_Process()
|
||||
}
|
||||
|
||||
if (AImovement_timer->Check()) {
|
||||
SetRunAnimSpeed(0);
|
||||
if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
|
||||
{
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
}
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
if(IsMoving()) {
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
tar_ndx =0;
|
||||
}
|
||||
|
||||
if(GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) {
|
||||
if(attack_timer.Check()) {
|
||||
Attack(GetTarget(), MainPrimary);
|
||||
@ -944,28 +932,27 @@ void Client::AI_Process()
|
||||
{
|
||||
if(!IsRooted())
|
||||
{
|
||||
animation = 21 * GetRunspeed();
|
||||
if(!RuleB(Pathing, Aggro) || !zone->pathing)
|
||||
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
|
||||
else
|
||||
if(AImovement_timer->Check())
|
||||
{
|
||||
bool WaypointChanged, NodeReached;
|
||||
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(),
|
||||
GetRunspeed(), WaypointChanged, NodeReached);
|
||||
if(!RuleB(Pathing, Aggro) || !zone->pathing)
|
||||
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
|
||||
else
|
||||
{
|
||||
bool WaypointChanged, NodeReached;
|
||||
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(),
|
||||
GetRunspeed(), WaypointChanged, NodeReached);
|
||||
|
||||
if(WaypointChanged)
|
||||
tar_ndx = 20;
|
||||
if(WaypointChanged)
|
||||
tar_ndx = 20;
|
||||
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed());
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(IsMoving())
|
||||
{
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
AI_SpellCast();
|
||||
@ -998,21 +985,23 @@ void Client::AI_Process()
|
||||
return;
|
||||
|
||||
float dist = DistanceSquared(m_Position, owner->GetPosition());
|
||||
if (dist >= 100)
|
||||
if (dist >= 400)
|
||||
{
|
||||
float speed = dist >= 225 ? GetRunspeed() : GetWalkspeed();
|
||||
animation = 21 * speed;
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
||||
if(AImovement_timer->Check())
|
||||
{
|
||||
int speed = GetWalkspeed();
|
||||
if (dist >= 5625)
|
||||
speed = GetRunspeed();
|
||||
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetHeading(owner->GetHeading());
|
||||
if(moved)
|
||||
{
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
SetRunAnimSpeed(0);
|
||||
SetCurrentSpeed(0);
|
||||
moved = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1042,9 +1031,7 @@ void Mob::AI_Process() {
|
||||
{
|
||||
if(target)
|
||||
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
moved=false;
|
||||
}
|
||||
//continue on to attack code, ensuring that we execute the engaged code
|
||||
@ -1058,7 +1045,9 @@ void Mob::AI_Process() {
|
||||
CalculateNewFearpoint();
|
||||
}
|
||||
if(!RuleB(Pathing, Fear) || !zone->pathing)
|
||||
{
|
||||
CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool WaypointChanged, NodeReached;
|
||||
@ -1156,15 +1145,21 @@ void Mob::AI_Process() {
|
||||
{
|
||||
if (AImovement_timer->Check())
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
|
||||
{
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
}
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
if(IsMoving())
|
||||
{
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
|
||||
SendPosition();
|
||||
tar_ndx =0;
|
||||
if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
|
||||
{
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
}
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
|
||||
//casting checked above...
|
||||
@ -1369,7 +1364,7 @@ void Mob::AI_Process() {
|
||||
CastToNPC()->DoClassAttacks(target);
|
||||
}
|
||||
AI_EngagedCastCheck();
|
||||
} //end is within combat range
|
||||
} //end is within combat rangepet
|
||||
else {
|
||||
//we cannot reach our target...
|
||||
//underwater stuff only works with water maps in the zone!
|
||||
@ -1425,10 +1420,7 @@ void Mob::AI_Process() {
|
||||
}
|
||||
else if(IsMoving()) {
|
||||
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetCurrentSpeed(0);
|
||||
|
||||
}
|
||||
}
|
||||
@ -1481,7 +1473,6 @@ void Mob::AI_Process() {
|
||||
}
|
||||
else if (AImovement_timer->Check() && !IsRooted())
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
if (IsPet())
|
||||
{
|
||||
// we're a pet, do as we're told
|
||||
@ -1500,18 +1491,18 @@ void Mob::AI_Process() {
|
||||
float dist = DistanceSquared(m_Position, owner->GetPosition());
|
||||
if (dist >= 400)
|
||||
{
|
||||
float speed = GetWalkspeed();
|
||||
int speed = GetWalkspeed();
|
||||
if (dist >= 5625)
|
||||
speed = GetRunspeed();
|
||||
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
SetCurrentSpeed(0);
|
||||
moved = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1557,19 +1548,15 @@ void Mob::AI_Process() {
|
||||
|
||||
if (dist2 >= followdist) // Default follow distance is 100
|
||||
{
|
||||
float speed = GetWalkspeed();
|
||||
int speed = GetWalkspeed();
|
||||
if (dist2 >= followdist + 150)
|
||||
speed = GetRunspeed();
|
||||
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
SendPosition();
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
}
|
||||
moved = false;
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1666,40 +1653,92 @@ void NPC::AI_DoMovement() {
|
||||
|
||||
if (gridno > 0 || cur_wp==-2) {
|
||||
if (movetimercompleted==true) { // time to pause at wp is over
|
||||
AI_SetupNextWaypoint();
|
||||
|
||||
int32 spawn_id = this->GetSpawnPointID();
|
||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||
iterator.Reset();
|
||||
Spawn2 *found_spawn = nullptr;
|
||||
|
||||
while(iterator.MoreElements())
|
||||
{
|
||||
Spawn2* cur = iterator.GetData();
|
||||
iterator.Advance();
|
||||
if(cur->GetID() == spawn_id)
|
||||
{
|
||||
found_spawn = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
CastToNPC()->Depop(true); //depop and resart spawn timer
|
||||
if(found_spawn)
|
||||
found_spawn->SetNPCPointerNull();
|
||||
}
|
||||
else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
CastToNPC()->Depop(false);//depop without spawn timer
|
||||
if(found_spawn)
|
||||
found_spawn->SetNPCPointerNull();
|
||||
}
|
||||
else {
|
||||
movetimercompleted=false;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp);
|
||||
|
||||
//if we were under quest control (with no grid), we are done now..
|
||||
if(cur_wp == -2) {
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode.");
|
||||
roamer = false;
|
||||
cur_wp = 0;
|
||||
}
|
||||
|
||||
if(GetAppearance() != eaStanding)
|
||||
SetAppearance(eaStanding, false);
|
||||
|
||||
entity_list.OpenDoorsNear(CastToNPC());
|
||||
|
||||
if(!DistractedFromGrid) {
|
||||
//kick off event_waypoint depart
|
||||
char temp[16];
|
||||
sprintf(temp, "%d", cur_wp);
|
||||
parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0);
|
||||
|
||||
//setup our next waypoint, if we are still on our normal grid
|
||||
//remember that the quest event above could have done anything it wanted with our grid
|
||||
if(gridno > 0) {
|
||||
CastToNPC()->CalculateNewWaypoint();
|
||||
}
|
||||
}
|
||||
else {
|
||||
DistractedFromGrid = false;
|
||||
}
|
||||
}
|
||||
} // endif (movetimercompleted==true)
|
||||
else if (!(AIwalking_timer->Enabled()))
|
||||
{ // currently moving
|
||||
bool doMove = true;
|
||||
if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY())
|
||||
{ // are we there yet? then stop
|
||||
Log.Out(Logs::Detail, Logs::AI, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid());
|
||||
if (cur_wp_pause != 0) {
|
||||
SetWaypointPause();
|
||||
SetWaypointPause();
|
||||
if(GetAppearance() != eaStanding)
|
||||
SetAppearance(eaStanding, false);
|
||||
SetMoving(false);
|
||||
if (m_CurrentWayPoint.w >= 0.0) {
|
||||
SetHeading(m_CurrentWayPoint.w);
|
||||
}
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
if (m_CurrentWayPoint.w >= 0.0) {
|
||||
SetHeading(m_CurrentWayPoint.w);
|
||||
}
|
||||
SendPosition();
|
||||
|
||||
//kick off event_waypoint arrive
|
||||
char temp[16];
|
||||
sprintf(temp, "%d", cur_wp);
|
||||
parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0);
|
||||
// start moving directly to next waypoint if we're at a 0 pause waypoint and we didn't get quest halted.
|
||||
if (!AIwalking_timer->Enabled())
|
||||
AI_SetupNextWaypoint();
|
||||
else
|
||||
doMove = false;
|
||||
|
||||
// wipe feign memory since we reached our first waypoint
|
||||
if(cur_wp == 1)
|
||||
ClearFeignMemory();
|
||||
}
|
||||
if (doMove)
|
||||
{ // not at waypoint yet or at 0 pause WP, so keep moving
|
||||
else
|
||||
{ // not at waypoint yet, so keep moving
|
||||
if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0))
|
||||
CalculateNewPosition2(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true);
|
||||
else
|
||||
@ -1727,7 +1766,8 @@ void NPC::AI_DoMovement() {
|
||||
SetGrid( 0 - GetGrid()); // revert to AI control
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "Quest pathing is finished. Resuming on grid %d", GetGrid());
|
||||
|
||||
SetAppearance(eaStanding, false);
|
||||
if(GetAppearance() != eaStanding)
|
||||
SetAppearance(eaStanding, false);
|
||||
|
||||
CalculateNewWaypoint();
|
||||
}
|
||||
@ -1763,86 +1803,28 @@ void NPC::AI_DoMovement() {
|
||||
Log.Out(Logs::Detail, Logs::AI, "Reached guard point (%.3f,%.3f,%.3f)", m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z);
|
||||
ClearFeignMemory();
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5*5 )
|
||||
{
|
||||
SetHeading(m_GuardPoint.w);
|
||||
} else {
|
||||
FaceTarget(GetTarget());
|
||||
}
|
||||
SendPosition();
|
||||
SetCurrentSpeed(0);
|
||||
SetAppearance(GetGuardPointAnim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void NPC::AI_SetupNextWaypoint() {
|
||||
int32 spawn_id = this->GetSpawnPointID();
|
||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||
iterator.Reset();
|
||||
Spawn2 *found_spawn = nullptr;
|
||||
|
||||
while (iterator.MoreElements())
|
||||
{
|
||||
Spawn2* cur = iterator.GetData();
|
||||
iterator.Advance();
|
||||
if (cur->GetID() == spawn_id)
|
||||
{
|
||||
found_spawn = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
CastToNPC()->Depop(true); //depop and restart spawn timer
|
||||
if (found_spawn)
|
||||
found_spawn->SetNPCPointerNull();
|
||||
}
|
||||
else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
CastToNPC()->Depop(false);//depop without spawn timer
|
||||
if (found_spawn)
|
||||
found_spawn->SetNPCPointerNull();
|
||||
}
|
||||
else {
|
||||
movetimercompleted = false;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp);
|
||||
|
||||
//if we were under quest control (with no grid), we are done now..
|
||||
if (cur_wp == -2) {
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode.");
|
||||
roamer = false;
|
||||
cur_wp = 0;
|
||||
}
|
||||
|
||||
SetAppearance(eaStanding, false);
|
||||
|
||||
entity_list.OpenDoorsNear(CastToNPC());
|
||||
|
||||
if (!DistractedFromGrid) {
|
||||
//kick off event_waypoint depart
|
||||
char temp[16];
|
||||
sprintf(temp, "%d", cur_wp);
|
||||
parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0);
|
||||
|
||||
//setup our next waypoint, if we are still on our normal grid
|
||||
//remember that the quest event above could have done anything it wanted with our grid
|
||||
if (GetGrid() > 0) {
|
||||
CastToNPC()->CalculateNewWaypoint();
|
||||
}
|
||||
}
|
||||
else {
|
||||
DistractedFromGrid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Mob that caused this may not get added to the hate list until after this function call completes
|
||||
void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
|
||||
SetAppearance(eaStanding);
|
||||
if(GetAppearance() != eaStanding)
|
||||
{
|
||||
SetAppearance(eaStanding);
|
||||
}
|
||||
|
||||
if (iYellForHelp) {
|
||||
if(IsPet()) {
|
||||
@ -1889,9 +1871,10 @@ void Mob::AI_Event_NoLongerEngaged() {
|
||||
pLastFightingDelayMoving += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving);
|
||||
// So mobs don't keep running as a ghost until AIwalking_timer fires
|
||||
// if they were moving prior to losing all hate
|
||||
if(IsMoving()){
|
||||
// except if we're a pet, then we might run into some issues with pets backing off when they should immediately be moving
|
||||
if(!IsPet())
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
}
|
||||
ClearRampage();
|
||||
|
||||
@ -119,7 +119,6 @@ public:
|
||||
virtual void AI_Start(uint32 iMoveDelay = 0);
|
||||
virtual void AI_Stop();
|
||||
void AI_DoMovement();
|
||||
void AI_SetupNextWaypoint();
|
||||
bool AI_AddNPCSpells(uint32 iDBSpellsID);
|
||||
bool AI_AddNPCSpellsEffects(uint32 iDBSpellsEffectsID);
|
||||
virtual bool AI_EngagedCastCheck();
|
||||
|
||||
@ -6188,6 +6188,35 @@ XS(XS_Client_GetTargetRingZ)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Client_CalcEXP); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_CalcEXP)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 1 || items > 2)
|
||||
Perl_croak(aTHX_ "Usage: CalcEXP(THIS, uint8 conlevel)");
|
||||
{
|
||||
Client * THIS;
|
||||
uint8 conlevel = 0xFF;
|
||||
uint32 RETVAL;
|
||||
if(items == 2)
|
||||
conlevel = (uint16)SvUV(ST(1));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Client")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Client *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Client");
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->CalcEXP(conlevel);
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Client_QuestReward); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_QuestReward)
|
||||
{
|
||||
@ -6482,6 +6511,7 @@ XS(boot_Client)
|
||||
newXSproto(strcpy(buf, "GetTargetRingY"), XS_Client_GetTargetRingY, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetTargetRingZ"), XS_Client_GetTargetRingZ, file, "$$");
|
||||
newXSproto(strcpy(buf, "QuestReward"), XS_Client_QuestReward, file, "$$;$$$$$$$");
|
||||
newXSproto(strcpy(buf, "CalcEXP"), XS_Client_CalcEXP, file, "$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
@ -787,8 +787,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
|
||||
if (IsClient())
|
||||
{
|
||||
AI_Start();
|
||||
SendAppearancePacket(14, 100, true, true);
|
||||
CastToClient()->AI_Start();
|
||||
} else if(IsNPC()) {
|
||||
CastToNPC()->SetPetSpellID(0); //not a pet spell.
|
||||
}
|
||||
@ -877,8 +876,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
if(RuleB(Combat, EnableFearPathing)){
|
||||
if(IsClient())
|
||||
{
|
||||
AI_Start();
|
||||
animation = static_cast<uint16>(GetRunspeed() * 21.0f); //set our animation to match our speed about
|
||||
CastToClient()->AI_Start();
|
||||
}
|
||||
|
||||
CalculateNewFearpoint();
|
||||
@ -3911,9 +3909,9 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
if(IsNPC())
|
||||
{
|
||||
CastToNPC()->RestoreGuardSpotCharm();
|
||||
SendAppearancePacket(AT_Pet, 0, true, true);
|
||||
}
|
||||
|
||||
SendAppearancePacket(AT_Pet, 0, true, true);
|
||||
Mob* tempmob = GetOwner();
|
||||
SetOwnerID(0);
|
||||
if(tempmob)
|
||||
@ -3943,12 +3941,12 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
{
|
||||
InterruptSpell();
|
||||
if (this->CastToClient()->IsLD())
|
||||
AI_Start(CLIENT_LD_TIMEOUT);
|
||||
CastToClient()->AI_Start(CLIENT_LD_TIMEOUT);
|
||||
else
|
||||
{
|
||||
bool feared = FindType(SE_Fear);
|
||||
if(!feared)
|
||||
AI_Stop();
|
||||
CastToClient()->AI_Stop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -3973,7 +3971,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
{
|
||||
bool charmed = FindType(SE_Charm);
|
||||
if(!charmed)
|
||||
AI_Stop();
|
||||
CastToClient()->AI_Stop();
|
||||
}
|
||||
|
||||
if(curfp) {
|
||||
|
||||
@ -4754,14 +4754,12 @@ void Client::UnStun() {
|
||||
|
||||
void NPC::Stun(int duration) {
|
||||
Mob::Stun(duration);
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
|
||||
void NPC::UnStun() {
|
||||
Mob::UnStun();
|
||||
SetRunAnimSpeed(static_cast<int8>(GetRunspeed()));
|
||||
SendPosition();
|
||||
SetCurrentSpeed(GetRunspeed());
|
||||
}
|
||||
|
||||
void Mob::Mesmerize()
|
||||
|
||||
@ -1561,6 +1561,8 @@ bool ZoneDatabase::EnableRecipe(uint32 recipe_id)
|
||||
if (!results.Success())
|
||||
|
||||
return results.RowsAffected() > 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::DisableRecipe(uint32 recipe_id)
|
||||
@ -1571,4 +1573,6 @@ bool ZoneDatabase::DisableRecipe(uint32 recipe_id)
|
||||
if (!results.Success())
|
||||
|
||||
return results.RowsAffected() > 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -394,7 +394,6 @@ void NPC::SetWaypointPause()
|
||||
|
||||
if (cur_wp_pause == 0) {
|
||||
AIwalking_timer->Start(100);
|
||||
AIwalking_timer->Trigger();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -437,9 +436,8 @@ void NPC::NextGuardPosition() {
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
moved = false;
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -490,10 +488,16 @@ float Mob::CalculateHeadingToTarget(float in_x, float in_y) {
|
||||
return (256*(360-angle)/360.0f);
|
||||
}
|
||||
|
||||
bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool checkZ) {
|
||||
bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ) {
|
||||
if(GetID()==0)
|
||||
return true;
|
||||
|
||||
if(speed == 0)
|
||||
{
|
||||
SetCurrentSpeed(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((m_Position.x-x == 0) && (m_Position.y-y == 0)) {//spawn is at target coords
|
||||
if(m_Position.z-z != 0) {
|
||||
m_Position.z = z;
|
||||
@ -515,9 +519,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
return true;
|
||||
}
|
||||
|
||||
bool send_update = false;
|
||||
int compare_steps = IsBoat() ? 1 : 20;
|
||||
|
||||
if(tar_ndx < compare_steps && m_TargetLocation.x==x && m_TargetLocation.y==y) {
|
||||
|
||||
float new_x = m_Position.x + m_TargetV.x*tar_vector;
|
||||
@ -589,7 +591,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
m_TargetV.x = x - nx;
|
||||
m_TargetV.y = y - ny;
|
||||
m_TargetV.z = z - nz;
|
||||
|
||||
SetCurrentSpeed((int8)speed);
|
||||
pRunAnimSpeed = speed;
|
||||
if(IsClient())
|
||||
{
|
||||
animation = speed;
|
||||
}
|
||||
//pRunAnimSpeed = (int8)(speed*NPC_RUNANIM_RATIO);
|
||||
//speed *= NPC_SPEED_MULTIPLIER;
|
||||
|
||||
@ -599,10 +606,10 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
// 2: get unit vector
|
||||
// --------------------------------------------------------------------------
|
||||
float mag = sqrtf (m_TargetV.x*m_TargetV.x + m_TargetV.y*m_TargetV.y + m_TargetV.z*m_TargetV.z);
|
||||
tar_vector = speed / mag;
|
||||
tar_vector = (float)speed / mag;
|
||||
|
||||
// mob move fix
|
||||
int numsteps = (int) ( mag * 20 / speed) + 1;
|
||||
int numsteps = (int) ( mag * 16.0f / (float)speed);
|
||||
|
||||
|
||||
// mob move fix
|
||||
@ -612,9 +619,9 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
if (numsteps>1)
|
||||
{
|
||||
tar_vector=1.0f ;
|
||||
m_TargetV.x = m_TargetV.x/numsteps;
|
||||
m_TargetV.y = m_TargetV.y/numsteps;
|
||||
m_TargetV.z = m_TargetV.z/numsteps;
|
||||
m_TargetV.x = 1.25f * m_TargetV.x/(float)numsteps;
|
||||
m_TargetV.y = 1.25f * m_TargetV.y/(float)numsteps;
|
||||
m_TargetV.z = 1.25f *m_TargetV.z/(float)numsteps;
|
||||
|
||||
float new_x = m_Position.x + m_TargetV.x;
|
||||
float new_y = m_Position.y + m_TargetV.y;
|
||||
@ -640,14 +647,13 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
m_Position.y = y;
|
||||
m_Position.z = z;
|
||||
|
||||
tar_ndx = 20;
|
||||
Log.Out(Logs::Detail, Logs::AI, "Only a single step to get there... jumping.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
tar_vector/=20.0f;
|
||||
tar_vector/=16.0f;
|
||||
|
||||
float new_x = m_Position.x + m_TargetV.x*tar_vector;
|
||||
float new_y = m_Position.y + m_TargetV.y*tar_vector;
|
||||
@ -703,32 +709,20 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f);
|
||||
|
||||
if (IsClient())
|
||||
{
|
||||
SendPosUpdate(1);
|
||||
CastToClient()->ResetPositionTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
// force an update now
|
||||
move_tic_count = RuleI(Zone, NPCPositonUpdateTicCount);
|
||||
SendPosUpdate();
|
||||
SetAppearance(eaStanding, false);
|
||||
}
|
||||
pLastChange = Timer::GetCurrentTime();
|
||||
|
||||
SetAppearance(eaStanding, false);
|
||||
pLastChange = Timer::GetCurrentTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mob::CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ) {
|
||||
if(IsNPC() || IsClient() || IsPet()) {
|
||||
pRunAnimSpeed = (int8)(speed*NPC_RUNANIM_RATIO);
|
||||
speed *= NPC_SPEED_MULTIPLIER;
|
||||
}
|
||||
|
||||
bool Mob::CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ, bool calcHeading) {
|
||||
return MakeNewPositionAndSendUpdate(x, y, z, speed, checkZ);
|
||||
}
|
||||
|
||||
bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool checkZ) {
|
||||
bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ, bool calcHeading) {
|
||||
if(GetID()==0)
|
||||
return true;
|
||||
|
||||
@ -737,14 +731,12 @@ bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool chec
|
||||
float nz = m_Position.z;
|
||||
|
||||
// if NPC is rooted
|
||||
if (speed == 0.0) {
|
||||
if (speed == 0) {
|
||||
SetHeading(CalculateHeadingToTarget(x, y));
|
||||
if(moved){
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
moved=false;
|
||||
}
|
||||
SetRunAnimSpeed(0);
|
||||
Log.Out(Logs::Detail, Logs::AI, "Rooted while calculating new position to (%.3f, %.3f, %.3f)", x, y, z);
|
||||
return true;
|
||||
}
|
||||
@ -756,8 +748,8 @@ bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool chec
|
||||
|
||||
if (m_TargetV.x == 0 && m_TargetV.y == 0)
|
||||
return false;
|
||||
pRunAnimSpeed = (uint8)(speed*NPC_RUNANIM_RATIO);
|
||||
speed *= NPC_SPEED_MULTIPLIER;
|
||||
SetCurrentSpeed((int8)(speed)); //*NPC_RUNANIM_RATIO);
|
||||
//speed *= NPC_SPEED_MULTIPLIER;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::AI, "Calculating new position to (%.3f, %.3f, %.3f) vector (%.3f, %.3f, %.3f) rate %.3f RAS %d", x, y, z, m_TargetV.x, m_TargetV.y, m_TargetV.z, speed, pRunAnimSpeed);
|
||||
|
||||
|
||||
@ -2209,9 +2209,9 @@ void Zone::ReloadWorld(uint32 Option){
|
||||
entity_list.ClearAreas();
|
||||
parse->ReloadQuests();
|
||||
} else if(Option == 1) {
|
||||
zone->Repop(0);
|
||||
entity_list.ClearAreas();
|
||||
parse->ReloadQuests();
|
||||
zone->Repop(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user