Merge branch 'master' into luamod

This commit is contained in:
KimLS 2017-05-15 23:18:28 -07:00
commit 4067397697
31 changed files with 724 additions and 421 deletions

View File

@ -8,7 +8,7 @@
**EQEmulator is a custom completely from-scratch open source server implementation for EverQuest built mostly on C++**
* MySQL/MariaDB is used as the database engine (over 200+ tables)
* Perl and LUA are both supported scripting languages for NPC/Player/Quest oriented events
* Open source database (Project EQ) has content up to expansion GoD (included in server installs)
* Open source database (Project EQ) has content up to expansion OoW (included in server installs)
* Game server environments and databases can be heavily customized to create all new experiences
* Hundreds of Quests/events created and maintained by Project EQ
@ -20,14 +20,14 @@
* [Easy Install](http://wiki.eqemulator.org/p?Akkas_PEQ_Server_Installer&frm=Main#from-scratch-installation-instructions-windows)
* [Advanced Setup](http://wiki.eqemulator.org/p?Complete_Windows-based_Server_Setup_Guide)
### > Debian/Ubuntu
### > Debian/Ubuntu/CentOS/Fedora
* You can use curl or wget to kick off the installer (whichever your OS has)
> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
### > CentOS/Fedora
> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
## Supported Clients
|Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear|

View File

@ -355,6 +355,7 @@ N(OP_OpenTributeMaster),
N(OP_PDeletePetition),
N(OP_PetBuffWindow),
N(OP_PetCommands),
N(OP_PetCommandState),
N(OP_PetHoTT),
N(OP_Petition),
N(OP_PetitionBug),

View File

@ -1116,6 +1116,11 @@ struct PetCommand_Struct {
/*004*/ uint32 target;
};
struct PetCommandState_Struct {
/*00*/ uint32 button_id;
/*04*/ uint32 state;
};
/*
** Delete Spawn
** Length: 4 Bytes

View File

@ -332,7 +332,7 @@ namespace EQEmu
};
struct ItemEffect_Struct {
int16 Effect;
int32 Effect;
uint8 Type;
uint8 Level;
uint8 Level2;

View File

@ -3291,73 +3291,60 @@ namespace SoD
switch (eq->command)
{
case 0x04:
emu->command = 0x00; // /pet health
case 1: // back off
emu->command = 28;
break;
case 0x10:
emu->command = 0x01; // /pet leader
case 2: // get lost
emu->command = 29;
break;
case 0x07:
emu->command = 0x02; // /pet attack or Pet Window
case 3: // as you were ???
emu->command = 4; // fuck it follow
break;
case 0x03: // Case Guessed
emu->command = 0x03; // /pet qattack
case 0x08:
emu->command = 0x04; // /pet follow or Pet Window
case 4: // report HP
emu->command = 0;
break;
case 0x05:
emu->command = 0x05; // /pet guard or Pet Window
case 5: // guard here
emu->command = 5;
break;
case 0x09:
emu->command = 0x07; // /pet sit or Pet Window
case 6: // guard me
emu->command = 4; // fuck it follow
break;
case 0x0a:
emu->command = 0x08; // /pet stand or Pet Window
case 7: // attack
emu->command = 2;
break;
case 0x06:
emu->command = 0x1e; // /pet guard me
case 8: // follow
emu->command = 4;
break;
case 0x0f: // Case Made Up
emu->command = 0x09; // /pet stop
case 9: // sit down
emu->command = 7;
break;
case 0x0b:
emu->command = 0x0d; // /pet taunt or Pet Window
case 10: // stand up
emu->command = 8;
break;
case 0x0e:
emu->command = 0x0e; // /pet notaunt or Pet Window
case 11: // taunt toggle
emu->command = 12;
break;
case 0x0c:
emu->command = 0x0f; // /pet hold
case 12: // hold toggle
emu->command = 15;
break;
case 0x1b:
emu->command = 0x10; // /pet hold on
case 13: // taunt on
emu->command = 13;
break;
case 0x1c:
emu->command = 0x11; // /pet hold off
case 14: // no taunt
emu->command = 14;
break;
case 0x11:
emu->command = 0x12; // Slumber?
// 15 is target, doesn't send packet
case 16: // leader
emu->command = 1;
break;
case 0x12:
emu->command = 0x15; // /pet no cast
case 17: // feign
emu->command = 27;
break;
case 0x0d: // Case Made Up
emu->command = 0x16; // Pet Window No Cast
case 18: // no cast toggle
emu->command = 21;
break;
case 0x13:
emu->command = 0x18; // /pet focus
break;
case 0x19:
emu->command = 0x19; // /pet focus on
break;
case 0x1a:
emu->command = 0x1a; // /pet focus off
break;
case 0x01:
emu->command = 0x1c; // /pet back off
break;
case 0x02:
emu->command = 0x1d; // /pet get lost
case 19: // focus toggle
emu->command = 24;
break;
default:
emu->command = eq->command;

View File

@ -2675,73 +2675,60 @@ namespace SoF
switch (eq->command)
{
case 0x04:
emu->command = 0x00; // /pet health
case 1: // back off
emu->command = 28;
break;
case 0x10:
emu->command = 0x01; // /pet leader
case 2: // get lost
emu->command = 29;
break;
case 0x07:
emu->command = 0x02; // /pet attack or Pet Window
case 3: // as you were ???
emu->command = 4; // fuck it follow
break;
case 0x03: // Case Guessed
emu->command = 0x03; // /pet qattack
case 0x08:
emu->command = 0x04; // /pet follow or Pet Window
case 4: // report HP
emu->command = 0;
break;
case 0x05:
emu->command = 0x05; // /pet guard or Pet Window
case 5: // guard here
emu->command = 5;
break;
case 0x09:
emu->command = 0x07; // /pet sit or Pet Window
case 6: // guard me
emu->command = 4; // fuck it follow
break;
case 0x0a:
emu->command = 0x08; // /pet stand or Pet Window
case 7: // attack
emu->command = 2;
break;
case 0x06:
emu->command = 0x1e; // /pet guard me
case 8: // follow
emu->command = 4;
break;
case 0x0f: // Case Made Up
emu->command = 0x09; // Stop?
case 9: // sit down
emu->command = 7;
break;
case 0x0b:
emu->command = 0x0d; // /pet taunt or Pet Window
case 10: // stand up
emu->command = 8;
break;
case 0x0e:
emu->command = 0x0e; // /pet notaunt or Pet Window
case 11: // taunt toggle
emu->command = 12;
break;
case 0x0c:
emu->command = 0x0f; // /pet hold
case 12: // hold toggle
emu->command = 15;
break;
case 0x1b:
emu->command = 0x10; // /pet hold on
case 13: // taunt on
emu->command = 13;
break;
case 0x1c:
emu->command = 0x11; // /pet hold off
case 14: // no taunt
emu->command = 14;
break;
case 0x11:
emu->command = 0x12; // Slumber?
// 15 is target, doesn't send packet
case 16: // leader
emu->command = 1;
break;
case 0x12:
emu->command = 0x15; // /pet no cast
case 17: // feign
emu->command = 27;
break;
case 0x0d: // Case Made Up
emu->command = 0x16; // Pet Window No Cast
case 18: // no cast toggle
emu->command = 21;
break;
case 0x13:
emu->command = 0x18; // /pet focus
break;
case 0x19:
emu->command = 0x19; // /pet focus on
break;
case 0x1a:
emu->command = 0x1a; // /pet focus off
break;
case 0x01:
emu->command = 0x1c; // /pet back off
break;
case 0x02:
emu->command = 0x1d; // /pet get lost
case 19: // focus toggle
emu->command = 24;
break;
default:
emu->command = eq->command;

View File

@ -2030,73 +2030,60 @@ namespace Titanium
switch (eq->command)
{
case 0x04:
emu->command = 0x00; // /pet health
case 1: // back off
emu->command = 28;
break;
case 0x10:
emu->command = 0x01; // /pet leader
case 2: // get lost
emu->command = 29;
break;
case 0x07:
emu->command = 0x02; // /pet attack or Pet Window
case 3: // as you were ???
emu->command = 4; // fuck it follow
break;
case 0x03: // Case Guessed
emu->command = 0x03; // /pet qattack
case 0x08:
emu->command = 0x04; // /pet follow or Pet Window
case 4: // report HP
emu->command = 0;
break;
case 0x05:
emu->command = 0x05; // /pet guard or Pet Window
case 5: // guard here
emu->command = 5;
break;
case 0x09:
emu->command = 0x07; // /pet sit or Pet Window
case 6: // guard me
emu->command = 4; // fuck it follow
break;
case 0x0a:
emu->command = 0x08; // /pet stand or Pet Window
case 7: // attack
emu->command = 2;
break;
case 0x06:
emu->command = 0x1e; // /pet guard me
case 8: // follow
emu->command = 4;
break;
case 0x0f: // Case Made Up
emu->command = 0x09; // Stop?
case 9: // sit down
emu->command = 7;
break;
case 0x0b:
emu->command = 0x0d; // /pet taunt or Pet Window
case 10: // stand up
emu->command = 8;
break;
case 0x0e:
emu->command = 0x0e; // /pet notaunt or Pet Window
case 11: // taunt toggle
emu->command = 12;
break;
case 0x0c:
emu->command = 0x0f; // /pet hold
case 12: // hold toggle
emu->command = 15;
break;
case 0x1b:
emu->command = 0x10; // /pet hold on
case 13: // taunt on
emu->command = 13;
break;
case 0x1c:
emu->command = 0x11; // /pet hold off
case 14: // no taunt
emu->command = 14;
break;
case 0x11:
emu->command = 0x12; // Slumber?
// 15 is target, doesn't send packet
case 16: // leader
emu->command = 1;
break;
case 0x12:
emu->command = 0x15; // /pet no cast
case 17: // feign
emu->command = 27;
break;
case 0x0d: // Case Made Up
emu->command = 0x16; // Pet Window No Cast
case 18: // no cast toggle
emu->command = 21;
break;
case 0x13:
emu->command = 0x18; // /pet focus
break;
case 0x19:
emu->command = 0x19; // /pet focus on
break;
case 0x1a:
emu->command = 0x1a; // /pet focus off
break;
case 0x01:
emu->command = 0x1c; // /pet back off
break;
case 0x02:
emu->command = 0x1d; // /pet get lost
case 19: // focus toggle
emu->command = 24;
break;
default:
emu->command = eq->command;

View File

@ -468,7 +468,7 @@ typedef enum {
#define SE_Blank 254 // implemented
#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield
#define SE_ShroudofStealth 256 // implemented
#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold
#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold - official name is GivePetHold
#define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab
#define SE_CombatStability 259 // implemented[AA] - damage mitigation
#define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType
@ -478,7 +478,7 @@ typedef enum {
#define SE_HastenedAASkill 264 // implemented
#define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled
#define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon.
#define SE_PetDiscipline2 267 // *not implemented - /pet focus, /pet no cast
#define SE_AddPetCommand 267 // implemented - sets command base2 to base1
#define SE_ReduceTradeskillFail 268 // implemented - reduces chance to fail with given tradeskill by a percent chance
#define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound.
#define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo)

View File

@ -196,6 +196,7 @@ OP_Consent=0x400e
OP_ConsentDeny=0x34c1
OP_AutoFire=0x314e
OP_PetCommands=0x0093
OP_PetCommandState=0x74ed
OP_PetHoTT=0x0df4
OP_DeleteSpell=0x305c
OP_Surname=0x1a87

View File

@ -195,6 +195,7 @@ OP_Consent=0x1fd1
OP_ConsentDeny=0x7a45
OP_AutoFire=0x241e
OP_PetCommands=0x0159
OP_PetCommandState=0x1dc8
OP_PetHoTT=0x794a
OP_DeleteSpell=0x3358
OP_Surname=0x0423

View File

@ -198,6 +198,7 @@ OP_Consent=0x6bb9 # C
OP_ConsentDeny=0x4cd1 # C
OP_AutoFire=0x5db5 # C
OP_PetCommands=0x7706 # C
OP_PetCommandState=0x1a79
OP_PetHoTT=0x2528
OP_DeleteSpell=0x0698 # C
OP_Surname=0x44ae # C

View File

@ -49,6 +49,7 @@ if(-e "eqemu_server_skip_update.txt"){
#::: Check for script self update
do_self_update_check_routine() if !$skip_self_update_check;
get_windows_wget();
get_perl_version();
read_eqemu_config_xml();
get_mysql_path();
@ -517,6 +518,13 @@ sub get_perl_version {
no warnings;
}
sub get_windows_wget {
if(!-e "wget.exe" && $OS eq "Windows"){
eval "use LWP::Simple qw(getstore);";
getstore("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/wget.exe", "wget.exe");
}
}
sub do_self_update_check_routine {
#::: Check for internet connection before updating
@ -524,7 +532,7 @@ sub do_self_update_check_routine {
print "[Update] Cannot check update without internet connection...\n";
return;
}
#::: Check for script changes :: eqemu_server.pl
get_remote_file($eqemu_repository_request_url . "utils/scripts/eqemu_server.pl", "updates_staged/eqemu_server.pl", 0, 1, 1);
@ -997,68 +1005,14 @@ sub get_remote_file{
}
}
if($OS eq "Windows"){
#::: For non-text type requests...
if($content_type == 1){
$break = 0;
while($break == 0) {
eval "use LWP::Simple qw(getstore);";
# use LWP::Simple qw(getstore);
# print "request is " . $request_url . "\n";
# print "destination file is supposed to be " . $destination_file . "\n";
if(!getstore($request_url, $destination_file)){
print "[Download] Error, no connection or failed request...\n\n";
}
# sleep(1);
#::: Make sure the file exists before continuing...
if(-e $destination_file) {
$break = 1;
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
} else { $break = 0; }
usleep(500);
if($no_retry){
$break = 1;
}
}
}
else{
$break = 0;
while($break == 0) {
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->env_proxy;
my $response = $ua->get($request_url);
if ($response->is_success){
open (FILE, '> ' . $destination_file . '');
print FILE $response->decoded_content;
close (FILE);
}
else {
print "[Download] Error, no connection or failed request...\n\n";
}
if(-e $destination_file) {
$break = 1;
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
} else { $break = 0; }
usleep(500);
if($no_retry){
$break = 1;
}
}
}
}
if($OS eq "Linux"){
#::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
$wget = `wget --no-check-certificate --quiet -O $destination_file $request_url`;
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
if($wget=~/unable to resolve/i){
print "Error, no connection or failed request...\n\n";
#die;
}
#::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
$wget = `wget -N --no-check-certificate --quiet -O $destination_file $request_url`;
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
if($wget=~/unable to resolve/i){
print "Error, no connection or failed request...\n\n";
#die;
}
}
#::: Trim Whitespaces

View File

@ -114,9 +114,24 @@ if [[ "$OS" == "Debian" ]]; then
apt-get $apt_options install open-vm-tools
apt-get $apt_options install unzip
apt-get $apt_options install uuid-dev
apt-get $apt_options install wget
apt-get $apt_options install zlib-bin
apt-get $apt_options install zlibc
apt-get $apt_options install libsodium-dev
apt-get $apt_options install libsodium18
# If libsodium18 isn't installed (Debian), let's download both that and the dev package and install them.
if dpkg-query -s "libsodium18" 1>/dev/null 2>&1; then
echo "Sodium library already installed."
else
wget http://ftp.us.debian.org/debian/pool/main/libs/libsodium/libsodium-dev_1.0.11-1~bpo8+1_amd64.deb -O /home/eqemu/libsodium-dev.deb
wget http://ftp.us.debian.org/debian/pool/main/libs/libsodium/libsodium18_1.0.11-1~bpo8+1_amd64.deb -O /home/eqemu/libsodium18.deb
dpkg -i /home/eqemu/libsodium*.deb
# Cleanup after ourselves
rm -f /home/eqemu/libsodium-dev.deb
rm -f /home/eqemu/libsodium18.deb
fi
#::: Install FTP for remote FTP access
echo "proftpd-basic shared/proftpd/inetd_or_standalone select standalone" | debconf-set-selections
apt-get -y -q install proftpd
@ -149,8 +164,35 @@ EOF
elif [[ "$OS" == "fedora_core" ]]; then
# Do Fedora stuff
dnf -y install open-vm-tools vim cmake boost-devel zlib-devel mariadb-server mariadb-devel mariadb-libs perl perl-DBD-MySQL perl-IO-stringy perl-devel lua-devel lua-sql-mysql dos2unix php-mysql proftpd wget compat-lua-libs compat-lua-devel compat-lua perl-Time-HiRes
dnf -y groupinstall "Development Tools" "Basic Web Server" "C Development Tools and Libraries"
dnf -y install open-vm-tools
dnf -y install vim
dnf -y install cmake
dnf -y install boost-devel
dnf -y install zlib-devel
dnf -y install mariadb-server
dnf -y install mariadb-devel
dnf -y install mariadb-libs
dnf -y install perl
dnf -y install perl-DBD-MySQL
dnf -y install perl-IO-stringy
dnf -y install perl-devel
dnf -y install lua-devel
dnf -y install lua-sql-mysql
dnf -y install dos2unix
dnf -y install php-mysql
dnf -y install php-mysqlnd
dnf -y install proftpd
dnf -y install wget
dnf -y install compat-lua-libs
dnf -y install compat-lua-devel
dnf -y install compat-lua
dnf -y install perl-Time-HiRes
dnf -y install libuuid-devel
dnf -y install libsodium
dnf -y install libsodium-devel
dnf -y groupinstall "Development Tools"
dnf -y groupinstall "Basic Web Server"
dnf -y groupinstall "C Development Tools and Libraries"
fi
if [[ "$OS" == "fedora_core" ]] || [[ "$OS" == "red_hat" ]]; then

View File

@ -46,8 +46,16 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
if (targ != nullptr && targ->IsCorpse())
return;
// yep, even these need pet power!
int act_power = 0;
if (IsClient()) {
act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);
act_power = CastToClient()->mod_pet_power(act_power, spell_id);
}
PetRecord record;
if (!database.GetPetEntry(spells[spell_id].teleport_zone, &record))
if (!database.GetPoweredPetEntry(spells[spell_id].teleport_zone, act_power, &record))
{
Log(Logs::General, Logs::Error, "Unknown swarm pet spell id: %d, check pets table", spell_id);
Message(13, "Unable to find data for pet %s", spells[spell_id].teleport_zone);

View File

@ -2529,7 +2529,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::Skil
return true;
}
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/, uint16 spell_id)
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/, uint16 spell_id, bool pet_command)
{
if (!other)
return;
@ -2568,13 +2568,18 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
}
}
if (IsPet() && GetOwner() && GetOwner()->GetAA(aaPetDiscipline) && IsHeld() && !IsFocused()) { //ignore aggro if hold and !focus
return;
}
// Pet that is /pet hold on will not add to their hate list if they're not engaged
// Pet that is /pet hold on and /pet focus on will not add others to their hate list
// Pet that is /pet ghold on will never add to their hate list unless /pet attack or /pet qattack
if (IsPet() && GetOwner() && GetOwner()->GetAA(aaPetDiscipline) && IsHeld() && GetOwner()->GetAA(aaAdvancedPetDiscipline) >= 1 && IsFocused()) {
if (!targetmob)
return;
// we skip these checks if it's forced through a pet command
if (!pet_command) {
if (IsPet()) {
if ((IsGHeld() || (IsHeld() && IsFocused())) && !on_hatelist) // we want them to be able to climb the hate list
return;
if ((IsHeld() || IsPetStop() || IsPetRegroup()) && !wasengaged) // not 100% sure on stop/regroup kind of hard to test, but regroup is like "classic hold"
return;
}
}
if (other->IsNPC() && (other->IsPet() || other->CastToNPC()->GetSwarmOwner() > 0))
@ -2679,7 +2684,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
}
}
if (mypet && (!(GetAA(aaPetDiscipline) && mypet->IsHeld()))) { // I have a pet, add other to it
if (mypet && !mypet->IsHeld() && !mypet->IsPetStop()) { // I have a pet, add other to it
if (!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO))
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
@ -3360,7 +3365,10 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
} //end `if there is some damage being done and theres anattacker person involved`
Mob *pet = GetPet();
if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse())
// pets that have GHold will never automatically add NPCs
// pets that have Hold and no Focus will add NPCs if they're engaged
// pets that have Hold and Focus will not add NPCs
if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse() && !pet->IsGHeld())
{
if (!pet->IsHeld()) {
Log(Logs::Detail, Logs::Aggro, "Sending pet %s into battle due to attack.", pet->GetName());
@ -5358,4 +5366,4 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
}
}
}
}
}

View File

@ -1442,11 +1442,19 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
newbon->FeignedCastOnChance = base1;
break;
case SE_AddPetCommand:
if (base1 && base2 < PET_MAXCOMMANDS)
newbon->PetCommands[base2] = true;
break;
case SE_FeignedMinion:
if (newbon->FeignedMinionChance < base1)
newbon->FeignedMinionChance = base1;
break;
// to do
case SE_PetDiscipline:
break;
case SE_PetDiscipline2:
break;
case SE_PotionBeltSlots:
break;
case SE_BandolierSlots:
@ -1465,8 +1473,6 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
break;
case SE_TrapCircumvention:
break;
case SE_FeignedMinion:
break;
// not handled here
case SE_HastenedAASkill:

View File

@ -3853,8 +3853,8 @@ void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, EQEmu::skills::SkillT
}
//void Bot::AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false)
void Bot::AddToHateList(Mob* other, uint32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) {
Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, iBuffTic);
void Bot::AddToHateList(Mob* other, uint32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic, bool pet_command) {
Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, iBuffTic, pet_command);
}
bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) {

View File

@ -325,7 +325,7 @@ public:
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic);
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
void Camp(bool databaseSave = true);
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false);
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false, bool pet_command = false);
virtual void SetTarget(Mob* mob);
virtual void Zone();
std::vector<AISpells_Struct> GetBotSpells() { return AIspells; }

View File

@ -697,12 +697,13 @@ bool Client::AddPacket(const EQApplicationPacket *pApp, bool bAckreq) {
//drop the packet because it will never get sent.
return(false);
}
auto c = new CLIENTPACKET;
auto c = std::unique_ptr<CLIENTPACKET>(new CLIENTPACKET);
c->ack_req = bAckreq;
c->app = pApp->Copy();
clientpackets.Append(c);
clientpackets.push_back(std::move(c));
return true;
}
@ -714,26 +715,23 @@ bool Client::AddPacket(EQApplicationPacket** pApp, bool bAckreq) {
//drop the packet because it will never get sent.
return(false);
}
auto c = new CLIENTPACKET;
auto c = std::unique_ptr<CLIENTPACKET>(new CLIENTPACKET);
c->ack_req = bAckreq;
c->app = *pApp;
*pApp = nullptr;
clientpackets.Append(c);
clientpackets.push_back(std::move(c));
return true;
}
bool Client::SendAllPackets() {
LinkedListIterator<CLIENTPACKET*> iterator(clientpackets);
CLIENTPACKET* cp = nullptr;
iterator.Reset();
while(iterator.MoreElements()) {
cp = iterator.GetData();
while (!clientpackets.empty()) {
cp = clientpackets.front().get();
if(eqs)
eqs->FastQueuePacket((EQApplicationPacket **)&cp->app, cp->ack_req);
iterator.RemoveCurrent();
clientpackets.pop_front();
Log(Logs::Moderate, Logs::Client_Server_Packet, "Transmitting a packet");
}
return true;
@ -5715,6 +5713,20 @@ void Client::SuspendMinion()
Message_StringID(clientMessageTell, SUSPEND_MINION_UNSUSPEND, CurrentPet->GetCleanName());
memset(&m_suspendedminion, 0, sizeof(struct PetInfo));
// TODO: These pet command states need to be synced ...
// Will just fix them for now
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) {
SetPetCommandState(PET_BUTTON_SIT, 0);
SetPetCommandState(PET_BUTTON_STOP, 0);
SetPetCommandState(PET_BUTTON_REGROUP, 0);
SetPetCommandState(PET_BUTTON_FOLLOW, 1);
SetPetCommandState(PET_BUTTON_GUARD, 0);
SetPetCommandState(PET_BUTTON_TAUNT, 1);
SetPetCommandState(PET_BUTTON_HOLD, 0);
SetPetCommandState(PET_BUTTON_GHOLD, 0);
SetPetCommandState(PET_BUTTON_FOCUS, 0);
SetPetCommandState(PET_BUTTON_SPELLHOLD, 0);
}
}
else
return;
@ -8937,3 +8949,12 @@ void Client::ProcessAggroMeter()
}
}
void Client::SetPetCommandState(int button, int state)
{
auto app = new EQApplicationPacket(OP_PetCommandState, sizeof(PetCommandState_Struct));
auto pcs = (PetCommandState_Struct *)app->pBuffer;
pcs->button_id = button;
pcs->state = state;
FastQueuePacket(&app);
}

View File

@ -70,6 +70,7 @@ namespace EQEmu
#include <set>
#include <algorithm>
#include <memory>
#include <deque>
#define CLIENT_TIMEOUT 90000
@ -351,6 +352,8 @@ public:
inline InspectMessage_Struct& GetInspectMessage() { return m_inspect_message; }
inline const InspectMessage_Struct& GetInspectMessage() const { return m_inspect_message; }
void SetPetCommandState(int button, int state);
bool CheckAccess(int16 iDBLevel, int16 iDefaultLevel);
void CheckQuests(const char* zonename, const char* message, uint32 npc_id, uint32 item_id, Mob* other);
@ -1424,7 +1427,7 @@ private:
bool AddPacket(const EQApplicationPacket *, bool);
bool AddPacket(EQApplicationPacket**, bool);
bool SendAllPackets();
LinkedList<CLIENTPACKET *> clientpackets;
std::deque<std::unique_ptr<CLIENTPACKET>> clientpackets;
//Zoning related stuff
void SendZoneCancel(ZoneChange_Struct *zc);

View File

@ -858,6 +858,21 @@ void Client::CompleteConnect()
CastToClient()->FastQueuePacket(&outapp);
}
// TODO: load these states
// We at least will set them to the correct state for now
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater && GetPet()) {
SetPetCommandState(PET_BUTTON_SIT, 0);
SetPetCommandState(PET_BUTTON_STOP, 0);
SetPetCommandState(PET_BUTTON_REGROUP, 0);
SetPetCommandState(PET_BUTTON_FOLLOW, 1);
SetPetCommandState(PET_BUTTON_GUARD, 0);
SetPetCommandState(PET_BUTTON_TAUNT, 1);
SetPetCommandState(PET_BUTTON_HOLD, 0);
SetPetCommandState(PET_BUTTON_GHOLD, 0);
SetPetCommandState(PET_BUTTON_FOCUS, 0);
SetPetCommandState(PET_BUTTON_SPELLHOLD, 0);
}
entity_list.RefreshClientXTargets(this);
worldserver.RequestTellQueue(GetName());
@ -2993,9 +3008,12 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
if (!solvent)
{
Log(Logs::General, Logs::Error, "Player tried to safely remove an augment without a distiller.");
Message(13, "Error: Missing an augmentation distiller for safely removing this augment.");
return;
old_aug = tobe_auged->GetAugment(in_augment->augment_index);
if (!old_aug || old_aug->GetItem()->AugDistiller != 0) {
Log(Logs::General, Logs::Error, "Player tried to safely remove an augment without a distiller.");
Message(13, "Error: Missing an augmentation distiller for safely removing this augment.");
return;
}
}
else if (solvent->GetItem()->ItemType == EQEmu::item::ItemTypeAugmentationDistiller)
{
@ -3159,7 +3177,8 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
if (itemOneToPush && itemTwoToPush)
{
// Consume the augment distiller
DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true);
if (solvent)
DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true);
// Remove the augmented item
DeleteItemInInventory(item_slot, 0, true);
@ -4802,6 +4821,7 @@ void Client::Handle_OP_Consider(const EQApplicationPacket *app)
mod_consider(tmob, con);
QueuePacket(outapp);
safe_delete(outapp);
// only wanted to check raid target once
// and need con to still be around so, do it here!
if (tmob->IsRaidTarget()) {
@ -4839,7 +4859,15 @@ void Client::Handle_OP_Consider(const EQApplicationPacket *app)
SendColoredText(color, std::string("This creature would take an army to defeat!"));
}
safe_delete(outapp);
// this could be done better, but this is only called when you con so w/e
// Shroud of Stealth has a special message
if (improved_hidden && (!tmob->see_improved_hide && (tmob->see_invis || tmob->see_hide)))
Message_StringID(10, SOS_KEEPS_HIDDEN);
// we are trying to hide but they can see us
else if ((invisible || invisible_undead || hidden || invisible_animals) && !IsInvisible(tmob))
Message_StringID(10, SUSPECT_SEES_YOU);
return;
}
@ -9939,7 +9967,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
Mob *Owner = mypet->GetOwner();
if (Owner)
mypet->Say_StringID(PET_LEADERIS, Owner->GetCleanName());
else
else if (mypet->IsNPC())
mypet->Say_StringID(I_FOLLOW_NOONE);
}
}
@ -9950,9 +9978,6 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
if (mypet->GetPetType() == petTargetLock && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST))
return;
if (mypet->GetPetType() == petAnimation && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST) && !GetAA(aaAnimationEmpathy))
return;
// just let the command "/pet get lost" work for familiars
if (mypet->GetPetType() == petFamiliar && pet->command != PET_GETLOST)
return;
@ -9982,25 +10007,31 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
break; //prevent pet from attacking stuff while feared
if (!mypet->IsAttackAllowed(target)) {
mypet->Say_StringID(NOT_LEGAL_TARGET);
mypet->SayTo_StringID(this, NOT_LEGAL_TARGET);
break;
}
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) {
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
if (target != this && DistanceSquaredNoZ(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
if (mypet->IsHeld()) {
if (!mypet->IsFocused()) {
mypet->SetHeld(false); //break the hold and guard if we explicitly tell the pet to attack.
if (mypet->GetPetOrder() != SPO_Guard)
mypet->SetPetOrder(SPO_Follow);
}
else {
mypet->SetTarget(target);
}
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
}
if (mypet->IsPetRegroup()) {
mypet->SetPetRegroup(false);
SetPetCommandState(PET_BUTTON_REGROUP, 0);
}
zone->AddAggroMob();
mypet->AddToHateList(target, 1);
// classic acts like qattack
int hate = 1;
if (mypet->IsEngaged()) {
auto top = mypet->GetHateMost();
if (top && top != target)
hate += mypet->GetHateAmount(top) - mypet->GetHateAmount(target) + 100; // should be enough to cause target change
}
mypet->AddToHateList(target, hate, 0, true, false, false, SPELL_UNKNOWN, true);
Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), target->GetCleanName());
SetTarget(target);
}
}
break;
@ -10017,14 +10048,22 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
}
if (!mypet->IsAttackAllowed(GetTarget())) {
mypet->Say_StringID(NOT_LEGAL_TARGET);
mypet->SayTo_StringID(this, NOT_LEGAL_TARGET);
break;
}
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) {
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
}
if (mypet->IsPetRegroup()) {
mypet->SetPetRegroup(false);
SetPetCommandState(PET_BUTTON_REGROUP, 0);
}
zone->AddAggroMob();
mypet->AddToHateList(GetTarget(), 1);
mypet->AddToHateList(GetTarget(), 1, 0, true, false, false, SPELL_UNKNOWN, true);
Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName());
}
}
@ -10033,17 +10072,22 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
case PET_BACKOFF: {
if (mypet->IsFeared()) break; //keeps pet running while feared
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(MT_PetResponse, PET_CALMING);
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
mypet->SayTo_StringID(this, MT_PetResponse, PET_CALMING);
mypet->WipeHateList();
mypet->SetTarget(nullptr);
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
}
}
break;
}
case PET_HEALTHREPORT: {
Message_StringID(MT_PetResponse, PET_REPORT_HP, ConvertArrayF(mypet->GetHPRatio(), val1));
mypet->ShowBuffList(this);
//Message(10,"%s tells you, 'I have %d percent of my hit points left.'",mypet->GetName(),(uint8)mypet->GetHPRatio());
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
Message_StringID(MT_PetResponse, PET_REPORT_HP, ConvertArrayF(mypet->GetHPRatio(), val1));
mypet->ShowBuffList(this);
}
break;
}
case PET_GETLOST: {
@ -10060,7 +10104,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
SetPet(nullptr);
}
mypet->Say_StringID(MT_PetResponse, PET_GETLOST_STRING);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GETLOST_STRING);
mypet->CastToNPC()->Depop();
//Oddly, the client (Titanium) will still allow "/pet get lost" command despite me adding the code below. If someone can figure that out, you can uncomment this code and use it.
@ -10076,12 +10120,17 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
case PET_GUARDHERE: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 1) || mypet->GetPetType() != petAnimation) {
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
if (mypet->IsNPC()) {
mypet->SetHeld(false);
mypet->Say_StringID(MT_PetResponse, PET_GUARDINGLIFE);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GUARDINGLIFE);
mypet->SetPetOrder(SPO_Guard);
mypet->CastToNPC()->SaveGuardSpot();
if (!mypet->GetTarget()) // want them to not twitch if they're chasing something down
mypet->SetCurrentSpeed(0);
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
}
}
}
break;
@ -10089,16 +10138,19 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
case PET_FOLLOWME: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 1) || mypet->GetPetType() != petAnimation) {
mypet->SetHeld(false);
mypet->Say_StringID(MT_PetResponse, PET_FOLLOWING);
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
mypet->SayTo_StringID(this, MT_PetResponse, PET_FOLLOWING);
mypet->SetPetOrder(SPO_Follow);
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
}
}
break;
}
case PET_TAUNT: {
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
if (mypet->CastToNPC()->IsTaunting())
{
Message_StringID(MT_PetResponse, PET_NO_TAUNT);
@ -10113,14 +10165,14 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
break;
}
case PET_TAUNT_ON: {
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
Message_StringID(MT_PetResponse, PET_DO_TAUNT);
mypet->CastToNPC()->SetTaunting(true);
}
break;
}
case PET_TAUNT_OFF: {
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
Message_StringID(MT_PetResponse, PET_NO_TAUNT);
mypet->CastToNPC()->SetTaunting(false);
}
@ -10129,27 +10181,30 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
case PET_GUARDME: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 1) || mypet->GetPetType() != petAnimation) {
mypet->SetHeld(false);
mypet->Say_StringID(MT_PetResponse, PET_GUARDME_STRING);
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
mypet->SayTo_StringID(this, MT_PetResponse, PET_GUARDME_STRING);
mypet->SetPetOrder(SPO_Follow);
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
}
}
break;
}
case PET_SIT: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
if (mypet->GetPetOrder() == SPO_Sit)
{
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
mypet->SayTo_StringID(this, MT_PetResponse, PET_SIT_STRING);
mypet->SetPetOrder(SPO_Follow);
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
}
else
{
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
mypet->SayTo_StringID(this, MT_PetResponse, PET_SIT_STRING);
mypet->SetPetOrder(SPO_Sit);
mypet->SetRunAnimSpeed(0);
if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet
@ -10162,8 +10217,8 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
case PET_STANDUP: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
mypet->SayTo_StringID(this, MT_PetResponse, PET_SIT_STRING);
mypet->SetPetOrder(SPO_Follow);
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
}
@ -10172,8 +10227,8 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
case PET_SITDOWN: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
mypet->SayTo_StringID(this, MT_PetResponse, PET_SIT_STRING);
mypet->SetPetOrder(SPO_Sit);
mypet->SetRunAnimSpeed(0);
if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet
@ -10182,152 +10237,274 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
}
break;
}
case PET_SLUMBER: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if (mypet->GetPetType() != petAnimation) {
// Needs to have an IsSleeping() check added and this case should toggle on/off
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
mypet->SetPetOrder(SPO_Sit);
mypet->SetRunAnimSpeed(0);
if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet
mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting
mypet->SendAppearancePacket(AT_Anim, ANIM_DEATH);
}
break;
}
case PET_SLUMBER_ON: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if (mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
mypet->SetPetOrder(SPO_Sit);
mypet->SetRunAnimSpeed(0);
if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet
mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting
mypet->SendAppearancePacket(AT_Anim, ANIM_DEATH);
}
break;
}
case PET_SLUMBER_OFF: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if (mypet->GetPetType() != petAnimation) {
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
mypet->SetPetOrder(SPO_Follow);
mypet->SetRunAnimSpeed(mypet->GetBaseRunspeed());
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
}
break;
}
case PET_HOLD: {
if (GetAA(aaPetDiscipline) && mypet->IsNPC()) {
if (mypet->IsFeared())
break; //could be exploited like PET_BACKOFF
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsHeld())
{
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_HOLD_SET_OFF);
mypet->SetHeld(false);
}
else
{
mypet->Say_StringID(MT_PetResponse, PET_ON_HOLD);
mypet->WipeHateList();
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_HOLD_SET_ON);
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater)
mypet->SayTo_StringID(this, MT_PetResponse, PET_NOW_HOLDING);
else
mypet->SayTo_StringID(this, MT_PetResponse, PET_ON_HOLD);
mypet->SetHeld(true);
}
mypet->SetGHeld(false);
SetPetCommandState(PET_BUTTON_GHOLD, 0);
}
break;
}
case PET_HOLD_ON: {
if (GetAA(aaPetDiscipline) && mypet->IsNPC() && !mypet->IsHeld()) {
if (mypet->IsFeared())
break; //could be exploited like PET_BACKOFF
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && !mypet->IsHeld()) {
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_HOLD_SET_ON);
mypet->Say_StringID(MT_PetResponse, PET_ON_HOLD);
mypet->WipeHateList();
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater)
mypet->SayTo_StringID(this, MT_PetResponse, PET_NOW_HOLDING);
else
mypet->SayTo_StringID(this, MT_PetResponse, PET_ON_HOLD);
mypet->SetHeld(true);
mypet->SetGHeld(false);
SetPetCommandState(PET_BUTTON_GHOLD, 0);
}
break;
}
case PET_HOLD_OFF: {
if (GetAA(aaPetDiscipline) && mypet->IsNPC() && mypet->IsHeld())
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && mypet->IsHeld()) {
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_HOLD_SET_OFF);
mypet->SetHeld(false);
}
break;
}
case PET_GHOLD: {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsGHeld())
{
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater)
Message_StringID(MT_PetResponse, PET_OFF_GHOLD);
mypet->SetGHeld(false);
}
else
{
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) {
Message_StringID(MT_PetResponse, PET_ON_GHOLD);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GHOLD_ON_MSG);
} else {
mypet->SayTo_StringID(this, MT_PetResponse, PET_ON_HOLD);
}
mypet->SetGHeld(true);
}
mypet->SetHeld(false);
SetPetCommandState(PET_BUTTON_HOLD, 0);
}
break;
}
case PET_GHOLD_ON: {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) {
Message_StringID(MT_PetResponse, PET_ON_GHOLD);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GHOLD_ON_MSG);
} else {
mypet->SayTo_StringID(this, MT_PetResponse, PET_ON_HOLD);
}
mypet->SetGHeld(true);
mypet->SetHeld(false);
SetPetCommandState(PET_BUTTON_HOLD, 0);
}
break;
}
case PET_GHOLD_OFF: {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && mypet->IsGHeld()) {
if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater)
Message_StringID(MT_PetResponse, PET_OFF_GHOLD);
mypet->SetGHeld(false);
}
break;
}
case PET_SPELLHOLD: {
if (GetAA(aaAdvancedPetDiscipline) == 2 && mypet->IsNPC()) {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsFeared())
break;
if (mypet->IsNoCast()) {
Message_StringID(MT_PetResponse, PET_CASTING);
mypet->CastToNPC()->SetNoCast(false);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_SPELLHOLD_SET_OFF);
mypet->SetNoCast(false);
}
else {
Message_StringID(MT_PetResponse, PET_NOT_CASTING);
mypet->CastToNPC()->SetNoCast(true);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_SPELLHOLD_SET_ON);
mypet->SetNoCast(true);
}
}
break;
}
case PET_SPELLHOLD_ON: {
if (GetAA(aaAdvancedPetDiscipline) == 2 && mypet->IsNPC()) {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsFeared())
break;
if (!mypet->IsNoCast()) {
Message_StringID(MT_PetResponse, PET_NOT_CASTING);
mypet->CastToNPC()->SetNoCast(true);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_SPELLHOLD_SET_ON);
mypet->SetNoCast(true);
}
}
break;
}
case PET_SPELLHOLD_OFF: {
if (GetAA(aaAdvancedPetDiscipline) == 2 && mypet->IsNPC()) {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsFeared())
break;
if (mypet->IsNoCast()) {
Message_StringID(MT_PetResponse, PET_CASTING);
mypet->CastToNPC()->SetNoCast(false);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_SPELLHOLD_SET_OFF);
mypet->SetNoCast(false);
}
}
break;
}
case PET_FOCUS: {
if (GetAA(aaAdvancedPetDiscipline) >= 1 && mypet->IsNPC()) {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsFeared())
break;
if (mypet->IsFocused()) {
Message_StringID(MT_PetResponse, PET_NOT_FOCUSING);
mypet->CastToNPC()->SetFocused(false);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_FOCUS_SET_OFF);
mypet->SetFocused(false);
}
else {
Message_StringID(MT_PetResponse, PET_NOW_FOCUSING);
mypet->CastToNPC()->SetFocused(true);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_FOCUS_SET_ON);
mypet->SetFocused(true);
}
}
break;
}
case PET_FOCUS_ON: {
if (GetAA(aaAdvancedPetDiscipline) >= 1 && mypet->IsNPC()) {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsFeared())
break;
if (!mypet->IsFocused()) {
Message_StringID(MT_PetResponse, PET_NOW_FOCUSING);
mypet->CastToNPC()->SetFocused(true);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_FOCUS_SET_ON);
mypet->SetFocused(true);
}
}
break;
}
case PET_FOCUS_OFF: {
if (GetAA(aaAdvancedPetDiscipline) >= 1 && mypet->IsNPC()) {
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
if (mypet->IsFeared())
break;
if (mypet->IsFocused()) {
Message_StringID(MT_PetResponse, PET_NOT_FOCUSING);
mypet->CastToNPC()->SetFocused(false);
if (m_ClientVersionBit & EQEmu::versions::bit_SoDAndLater)
Message_StringID(MT_PetResponse, PET_FOCUS_SET_OFF);
mypet->SetFocused(false);
}
}
break;
}
case PET_STOP: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
} else {
mypet->SetPetStop(true);
mypet->SetCurrentSpeed(0);
mypet->SetTarget(nullptr);
if (mypet->IsPetRegroup()) {
mypet->SetPetRegroup(false);
SetPetCommandState(PET_BUTTON_REGROUP, 0);
}
}
mypet->SayTo_StringID(this, MT_PetResponse, PET_GETLOST_STRING);
}
break;
}
case PET_STOP_ON: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
mypet->SetPetStop(true);
mypet->SetCurrentSpeed(0);
mypet->SetTarget(nullptr);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GETLOST_STRING);
if (mypet->IsPetRegroup()) {
mypet->SetPetRegroup(false);
SetPetCommandState(PET_BUTTON_REGROUP, 0);
}
}
break;
}
case PET_STOP_OFF: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
mypet->SetPetStop(false);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GETLOST_STRING);
}
break;
}
case PET_REGROUP: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if (aabonuses.PetCommands[PetCommand]) {
if (mypet->IsPetRegroup()) {
mypet->SetPetRegroup(false);
mypet->SayTo_StringID(this, MT_PetResponse, PET_OFF_REGROUPING);
} else {
mypet->SetPetRegroup(true);
mypet->SetTarget(nullptr);
mypet->SayTo_StringID(this, MT_PetResponse, PET_ON_REGROUPING);
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
}
}
}
break;
}
case PET_REGROUP_ON: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if (aabonuses.PetCommands[PetCommand]) {
mypet->SetPetRegroup(true);
mypet->SetTarget(nullptr);
mypet->SayTo_StringID(this, MT_PetResponse, PET_ON_REGROUPING);
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
}
}
break;
}
case PET_REGROUP_OFF: {
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
if (aabonuses.PetCommands[PetCommand]) {
mypet->SetPetRegroup(false);
mypet->SayTo_StringID(this, MT_PetResponse, PET_OFF_REGROUPING);
}
break;
}
default:
printf("Client attempted to use a unknown pet command:\n");
break;

View File

@ -56,6 +56,55 @@
//Maximum distance from a zone point if zone was specified
#define ZONEPOINT_ZONE_RANGE 40000.0f
// Defines based on the RoF2 Client
#define PET_HEALTHREPORT 0 // 0x00 - /pet health or Pet Window
#define PET_LEADER 1 // 0x01 - /pet leader or Pet Window
#define PET_ATTACK 2 // 0x02 - /pet attack or Pet Window
#define PET_QATTACK 3 // 0x03 - /pet qattack or Pet Window
#define PET_FOLLOWME 4 // 0x04 - /pet follow or Pet Window
#define PET_GUARDHERE 5 // 0x05 - /pet guard or Pet Window
#define PET_SIT 6 // 0x06 - /pet sit or Pet Window
#define PET_SITDOWN 7 // 0x07 - /pet sit on
#define PET_STANDUP 8 // 0x08 - /pet sit off
#define PET_STOP 9 // 0x09 - /pet stop or Pet Window - Not implemented
#define PET_STOP_ON 10 // 0x0a - /pet stop on - Not implemented
#define PET_STOP_OFF 11 // 0x0b - /pet stop off - Not implemented
#define PET_TAUNT 12 // 0x0c - /pet taunt or Pet Window
#define PET_TAUNT_ON 13 // 0x0d - /pet taunt on
#define PET_TAUNT_OFF 14 // 0x0e - /pet taunt off
#define PET_HOLD 15 // 0x0f - /pet hold or Pet Window, won't add to hate list unless attacking
#define PET_HOLD_ON 16 // 0x10 - /pet hold on
#define PET_HOLD_OFF 17 // 0x11 - /pet hold off
#define PET_GHOLD 18 // 0x12 - /pet ghold, will never add to hate list unless told to
#define PET_GHOLD_ON 19 // 0x13 - /pet ghold on
#define PET_GHOLD_OFF 20 // 0x14 - /pet ghold off
#define PET_SPELLHOLD 21 // 0x15 - /pet no cast or /pet spellhold or Pet Window
#define PET_SPELLHOLD_ON 22 // 0x16 - /pet spellhold on
#define PET_SPELLHOLD_OFF 23 // 0x17 - /pet spellhold off
#define PET_FOCUS 24 // 0x18 - /pet focus or Pet Window
#define PET_FOCUS_ON 25 // 0x19 - /pet focus on
#define PET_FOCUS_OFF 26 // 0x1a - /pet focus off
#define PET_FEIGN 27 // 0x1b - /pet feign
#define PET_BACKOFF 28 // 0x1c - /pet back off
#define PET_GETLOST 29 // 0x1d - /pet get lost
#define PET_GUARDME 30 // 0x1e - Same as /pet follow, but different message in older clients - define not from client /pet target in modern clients but doesn't send packet
#define PET_REGROUP 31 // 0x1f - /pet regroup, acts like classic hold. Stops attack and moves back to guard/you but doesn't clear hate list
#define PET_REGROUP_ON 32 // 0x20 - /pet regroup on, turns on regroup
#define PET_REGROUP_OFF 33 // 0x21 - /pet regroup off, turns off regroup
#define PET_MAXCOMMANDS PET_REGROUP_OFF + 1
// can change the state of these buttons with a packet
#define PET_BUTTON_SIT 0
#define PET_BUTTON_STOP 1
#define PET_BUTTON_REGROUP 2
#define PET_BUTTON_FOLLOW 3
#define PET_BUTTON_GUARD 4
#define PET_BUTTON_TAUNT 5
#define PET_BUTTON_HOLD 6
#define PET_BUTTON_GHOLD 7
#define PET_BUTTON_FOCUS 8
#define PET_BUTTON_SPELLHOLD 9
typedef enum { //focus types
focusSpellHaste = 1,
focusSpellDuration,
@ -485,6 +534,8 @@ struct StatBonuses {
uint8 TradeSkillMastery; // Allow number of tradeskills to exceed 200 skill.
int16 NoBreakAESneak; // Percent value
int16 FeignedCastOnChance; // Percent Value
bool PetCommands[PET_MAXCOMMANDS]; // SPA 267
int FeignedMinionChance; // SPA 281 base1 = chance, just like normal FD
};
typedef struct

View File

@ -648,7 +648,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
}
}
if (GetLeader() == nullptr)
if (!GetLeaderName())
{
DisbandGroup();
return true;

View File

@ -344,8 +344,11 @@ Mob::Mob(const char* in_name,
typeofpet = petNone; // default to not a pet
petpower = 0;
held = false;
gheld = false;
nocast = false;
focused = false;
pet_stop = false;
pet_regroup = false;
_IsTempPet = false;
pet_owner_client = false;
pet_targetlock_id = 0;
@ -3093,6 +3096,26 @@ void Mob::Say_StringID(uint32 type, uint32 string_id, const char *message3, cons
);
}
void Mob::SayTo_StringID(Client *to, uint32 string_id, const char *message3, const char *message4, const char *message5, const char *message6, const char *message7, const char *message8, const char *message9)
{
if (!to)
return;
auto string_id_str = std::to_string(string_id);
to->Message_StringID(10, GENERIC_STRINGID_SAY, GetCleanName(), string_id_str.c_str(), message3, message4, message5, message6, message7, message8, message9);
}
void Mob::SayTo_StringID(Client *to, uint32 type, uint32 string_id, const char *message3, const char *message4, const char *message5, const char *message6, const char *message7, const char *message8, const char *message9)
{
if (!to)
return;
auto string_id_str = std::to_string(string_id);
to->Message_StringID(type, GENERIC_STRINGID_SAY, GetCleanName(), string_id_str.c_str(), message3, message4, message5, message6, message7, message8, message9);
}
void Mob::Shout(const char *format, ...)
{
char buf[1000];

View File

@ -536,7 +536,7 @@ public:
inline uint32 GetLevelCon(uint8 iOtherLevel) const {
return this ? GetLevelCon(GetLevel(), iOtherLevel) : CON_GRAY; }
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true,
bool bFrenzy = false, bool iBuffTic = false, uint16 spell_id = SPELL_UNKNOWN);
bool bFrenzy = false, bool iBuffTic = false, uint16 spell_id = SPELL_UNKNOWN, bool pet_comand = false);
bool RemoveFromHateList(Mob* mob);
void SetHateAmountOnEnt(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.SetHateAmountOnEnt(other,hate,damage);}
void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHateAmountOnEnt(other, (in_hate > 1 ? in_hate / 2 : 1)); }
@ -645,6 +645,10 @@ public:
const char *message6 = 0, const char *message7 = 0, const char *message8 = 0, const char *message9 = 0);
void Say_StringID(uint32 type, uint32 string_id, const char *message3 = 0, const char *message4 = 0, const char *message5 = 0,
const char *message6 = 0, const char *message7 = 0, const char *message8 = 0, const char *message9 = 0);
void SayTo_StringID(Client *to, uint32 string_id, const char *message3 = 0, const char *message4 = 0, const char *message5 = 0,
const char *message6 = 0, const char *message7 = 0, const char *message8 = 0, const char *message9 = 0);
void SayTo_StringID(Client *to, uint32 type, uint32 string_id, const char *message3 = 0, const char *message4 = 0, const char *message5 = 0,
const char *message6 = 0, const char *message7 = 0, const char *message8 = 0, const char *message9 = 0);
void Shout(const char *format, ...);
void Emote(const char *format, ...);
void QuestJournalledSay(Client *QuestInitiator, const char *str);
@ -872,10 +876,16 @@ public:
inline const eStandingPetOrder GetPetOrder() const { return pStandingPetOrder; }
inline void SetHeld(bool nState) { held = nState; }
inline const bool IsHeld() const { return held; }
inline void SetGHeld(bool nState) { gheld = nState; }
inline const bool IsGHeld() const { return gheld; }
inline void SetNoCast(bool nState) { nocast = nState; }
inline const bool IsNoCast() const { return nocast; }
inline void SetFocused(bool nState) { focused = nState; }
inline const bool IsFocused() const { return focused; }
inline void SetPetStop(bool nState) { pet_stop = nState; }
inline const bool IsPetStop() const { return pet_stop; }
inline void SetPetRegroup(bool nState) { pet_regroup = nState; }
inline const bool IsPetRegroup() const { return pet_regroup; }
inline const bool IsRoamer() const { return roamer; }
inline const int GetWanderType() const { return wandertype; }
inline const bool IsRooted() const { return rooted || permarooted; }
@ -1184,8 +1194,11 @@ protected:
uint32 pLastChange;
bool held;
bool gheld;
bool nocast;
bool focused;
bool pet_stop;
bool pet_regroup;
bool spawned;
void CalcSpellBonuses(StatBonuses* newbon);
virtual void CalcBonuses();

View File

@ -935,7 +935,7 @@ void Mob::AI_Process() {
bool engaged = IsEngaged();
bool doranged = false;
if (!zone->CanDoCombat()) {
if (!zone->CanDoCombat() || IsPetStop() || IsPetRegroup()) {
engaged = false;
}
@ -943,7 +943,7 @@ void Mob::AI_Process() {
//
if(RuleB(Combat, EnableFearPathing)){
if(currently_fleeing) {
if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) {
if((IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) && !IsPetStop() && !IsPetRegroup()) {
//make sure everybody knows were not moving, for appearance sake
if(IsMoving())
{
@ -1300,10 +1300,12 @@ void Mob::AI_Process() {
}
}
else {
if (m_PlayerState & static_cast<uint32>(PlayerState::Aggressive))
SendRemovePlayerState(PlayerState::Aggressive);
if (IsPetStop()) // pet stop won't be engaged, so we will always get here and we want the above branch to execute
return;
if(zone->CanDoCombat() && AI_feign_remember_timer->Check()) {
// 6/14/06
// Improved Feign Death Memory
@ -1409,6 +1411,8 @@ void Mob::AI_Process() {
break;
}
}
if (IsPetRegroup())
return;
}
/* Entity has been assigned another entity to follow */
else if (GetFollowID())

View File

@ -706,7 +706,7 @@ bool ZoneDatabase::GetBasePetItems(int32 equipmentset, uint32 *items) {
// all of the result rows. Check if we have something in the slot
// already. If no, add the item id to the equipment array.
while (curset >= 0 && depth < 5) {
std::string query = StringFormat("SELECT nested_set FROM pets_equipmentset WHERE set_id = '%s'", curset);
std::string query = StringFormat("SELECT nested_set FROM pets_equipmentset WHERE set_id = '%d'", curset);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
@ -721,7 +721,7 @@ bool ZoneDatabase::GetBasePetItems(int32 equipmentset, uint32 *items) {
auto row = results.begin();
nextset = atoi(row[0]);
query = StringFormat("SELECT slot, item_id FROM pets_equipmentset_entries WHERE set_id='%s'", curset);
query = StringFormat("SELECT slot, item_id FROM pets_equipmentset_entries WHERE set_id='%d'", curset);
results = QueryDatabase(query);
if (results.Success()) {
for (row = results.begin(); row != results.end(); ++row)

View File

@ -1,38 +1,6 @@
#ifndef PETS_H
#define PETS_H
// Defines based on the RoF2 Client
#define PET_HEALTHREPORT 0 // 0x00 - /pet health or Pet Window
#define PET_LEADER 1 // 0x01 - /pet leader or Pet Window
#define PET_ATTACK 2 // 0x02 - /pet attack or Pet Window
#define PET_QATTACK 3 // 0x03 - /pet qattack or Pet Window
#define PET_FOLLOWME 4 // 0x04 - /pet follow or Pet Window
#define PET_GUARDHERE 5 // 0x05 - /pet guard or Pet Window
#define PET_SIT 6 // 0x06 - /pet sit or Pet Window
#define PET_SITDOWN 7 // 0x07 - /pet sit on
#define PET_STANDUP 8 // 0x08 - /pet sit off
#define PET_STOP 9 // 0x09 - /pet stop or Pet Window - Not implemented
#define PET_STOP_ON 10 // 0x0a - /pet stop on - Not implemented
#define PET_STOP_OFF 11 // 0x0b - /pet stop off - Not implemented
#define PET_TAUNT 12 // 0x0c - /pet taunt or Pet Window
#define PET_TAUNT_ON 13 // 0x0d - /pet taunt on
#define PET_TAUNT_OFF 14 // 0x0e - /pet taunt off
#define PET_HOLD 15 // 0x0f - /pet hold or Pet Window
#define PET_HOLD_ON 16 // 0x10 - /pet hold on
#define PET_HOLD_OFF 17 // 0x11 - /pet hold off
#define PET_SLUMBER 18 // 0x12 - What activates this? - define guessed
#define PET_SLUMBER_ON 19 // 0x13 - What activates this? - define guessed
#define PET_SLUMBER_OFF 20 // 0x14 - What activates this? - define guessed
#define PET_SPELLHOLD 21 // 0x15 - /pet no cast or /pet spellhold or Pet Window
#define PET_SPELLHOLD_ON 22 // 0x16 - /pet spellhold on
#define PET_SPELLHOLD_OFF 23 // 0x17 - /pet spellhold off
#define PET_FOCUS 24 // 0x18 - /pet focus or Pet Window
#define PET_FOCUS_ON 25 // 0x19 - /pet focus on
#define PET_FOCUS_OFF 26 // 0x1a - /pet focus off
#define PET_BACKOFF 28 // 0x1c - /pet back off
#define PET_GETLOST 29 // 0x1d - /pet get lost
#define PET_GUARDME 30 // 0x1e - Same as /pet follow, but different message in older clients - define not from client
class Mob;
struct NPCType;

View File

@ -1240,6 +1240,23 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
else
{
MakePet(spell_id, spell.teleport_zone);
// TODO: we need to sync the states for these clients ...
// Will fix buttons for now
if (IsClient()) {
auto c = CastToClient();
if (c->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) {
c->SetPetCommandState(PET_BUTTON_SIT, 0);
c->SetPetCommandState(PET_BUTTON_STOP, 0);
c->SetPetCommandState(PET_BUTTON_REGROUP, 0);
c->SetPetCommandState(PET_BUTTON_FOLLOW, 1);
c->SetPetCommandState(PET_BUTTON_GUARD, 0);
c->SetPetCommandState(PET_BUTTON_TAUNT, 1);
c->SetPetCommandState(PET_BUTTON_HOLD, 0);
c->SetPetCommandState(PET_BUTTON_GHOLD, 0);
c->SetPetCommandState(PET_BUTTON_FOCUS, 0);
c->SetPetCommandState(PET_BUTTON_SPELLHOLD, 0);
}
}
}
break;
}
@ -6669,23 +6686,26 @@ void Mob::ResourceTap(int32 damage, uint16 spellid)
for (int i = 0; i < EFFECT_COUNT; i++) {
if (spells[spellid].effectid[i] == SE_ResourceTap) {
damage += (damage * spells[spellid].base[i]) / 100;
if (spells[spellid].max[i] && (damage > spells[spellid].max[i]))
damage = spells[spellid].max[i];
if (spells[spellid].base2[i] == 0) { // HP Tap
if (damage > 0)
HealDamage(damage);
else
Damage(this, -damage, 0, EQEmu::skills::SkillEvocation, false);
damage = (damage * spells[spellid].base[i]) / 1000;
if (damage) {
if (spells[spellid].max[i] && (damage > spells[spellid].max[i]))
damage = spells[spellid].max[i];
if (spells[spellid].base2[i] == 0) { // HP Tap
if (damage > 0)
HealDamage(damage);
else
Damage(this, -damage, 0, EQEmu::skills::SkillEvocation, false);
}
if (spells[spellid].base2[i] == 1) // Mana Tap
SetMana(GetMana() + damage);
if (spells[spellid].base2[i] == 2 && IsClient()) // Endurance Tap
CastToClient()->SetEndurance(CastToClient()->GetEndurance() + damage);
}
if (spells[spellid].base2[i] == 1) // Mana Tap
SetMana(GetMana() + damage);
if (spells[spellid].base2[i] == 2 && IsClient()) // Endurance Tap
CastToClient()->SetEndurance(CastToClient()->GetEndurance() + damage);
}
}
}

View File

@ -2140,6 +2140,27 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui
spell_target->CalcSpellPowerDistanceMod(spell_id, dist2);
}
//AE Duration spells were ignoring distance check from item clickies
if(ae_center != nullptr && ae_center != this) {
//casting a spell on somebody but ourself, make sure they are in range
float dist2 = DistanceSquared(m_Position, ae_center->GetPosition());
float range2 = range * range;
float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range;
if(dist2 > range2) {
//target is out of range.
Log(Logs::Detail, Logs::Spells, "Spell %d: Spell target is out of range (squared: %f > %f)", spell_id, dist2, range2);
Message_StringID(13, TARGET_OUT_OF_RANGE);
return(false);
}
else if (dist2 < min_range2){
//target is too close range.
Log(Logs::Detail, Logs::Spells, "Spell %d: Spell target is too close (squared: %f < %f)", spell_id, dist2, min_range2);
Message_StringID(13, TARGET_TOO_CLOSE);
return(false);
}
ae_center->CalcSpellPowerDistanceMod(spell_id, dist2);
}
//
// Switch #2 - execute the spell

View File

@ -164,6 +164,12 @@
#define PVP_ON 552 //You are now player kill and follow the ways of Discord.
#define GENERIC_STRINGID_SAY 554 //%1 says '%T2'
#define CANNOT_WAKE 555 //%1 tells you, 'I am unable to wake %2, master.'
#define PET_HOLD_SET_ON 698 //The pet hold mode has been set to on.
#define PET_HOLD_SET_OFF 699 //The pet hold mode has been set to off.
#define PET_FOCUS_SET_ON 700 //The pet focus mode has been set to on.
#define PET_FOCUS_SET_OFF 701 //The pet focus mode has been set to off.
#define PET_SPELLHOLD_SET_ON 702 //The pet spellhold mode has been set to on.
#define PET_SPELLHOLD_SET_OFF 703 //The pet spellhold mode has been set to off.
#define GUILD_NAME_IN_USE 711 //You cannot create a guild with that name, that guild already exists on this server.
#define GM_GAINXP 1002 //[GM] You have gained %1 AXP and %2 EXP (%3).
#define MALE_SLAYUNDEAD 1007 //%1's holy blade cleanses his target!(%2)
@ -288,6 +294,7 @@
#define CORPSEDRAG_BEGIN 4064 //You begin to drag %1.
#define CORPSEDRAG_STOPALL 4065 //You stop dragging the corpses.
#define CORPSEDRAG_STOP 4066 //You stop dragging the corpse.
#define SOS_KEEPS_HIDDEN 4086 //Your Shroud of Stealth keeps you hidden from watchful eyes.␣␣
#define TARGET_TOO_CLOSE 4602 //You are too close to your target. Get farther away.
#define WHOALL_NO_RESULTS 5029 //There are no players in EverQuest that match those who filters.
#define TELL_QUEUED_MESSAGE 5045 //You told %1 '%T2. %3'
@ -302,6 +309,7 @@
#define PET_ATTACKING 5501 //%1 tells you, 'Attacking %2 Master.'
#define AVOID_STUNNING_BLOW 5753 //You avoid the stunning blow.
#define FATAL_BOW_SHOT 5745 //%1 performs a FATAL BOW SHOT!!
#define SUSPECT_SEES_YOU 5746 //You suspect that this being can see you.
#define MELEE_SILENCE 5806 //You *CANNOT* use this melee ability, you are suffering from amnesia!
#define DISCIPLINE_REUSE_MSG 5807 //You can use the ability %1 again in %2 hour(s) %3 minute(s) %4 seconds.
#define DISCIPLINE_REUSE_MSG2 5808 //You can use the ability %1 again in %2 minute(s) %3 seconds.
@ -320,6 +328,12 @@
#define SENTINEL_TRIG_YOU 6724 //You have triggered your sentinel.
#define SENTINEL_TRIG_OTHER 6725 //%1 has triggered your sentinel.
#define IDENTIFY_SPELL 6765 //Item Lore: %1.
#define PET_NOW_HOLDING 6834 //Now holding, Master. I will not start attacks until ordered.
#define PET_ON_GHOLD 6843 //Pet greater hold has been set to on.
#define PET_OFF_GHOLD 6846 //Pet greater hold has been set to off.
#define PET_GHOLD_ON_MSG 6847 //Now greater holding master. I will only attack something new if ordered.
#define PET_ON_REGROUPING 6854 //Now regrouping, master.
#define PET_OFF_REGROUPING 6855 //No longer regrouping, master.
#define BUFF_NOT_BLOCKABLE 7608 //You cannot block this effect.
#define LDON_DONT_KNOW_TRAPPED 7552 //You do not know if this object is trapped.
#define LDON_HAVE_DISARMED 7553 //You have disarmed %1!