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:
SecretsOTheP
2015-05-25 12:35:53 -04:00
parent aaca6fd2d9
commit 788959a5e2
22 changed files with 751 additions and 419 deletions
+231 -51
View File
@@ -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();
}
}
}