Merge branch 'master' into lets_move

This commit is contained in:
KimLS
2016-01-09 01:40:54 -08:00
41 changed files with 918 additions and 407 deletions
+179 -122
View File
@@ -846,7 +846,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) {
}
else{
if((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30){
dmg = GetMonkHandToHandDamage();
dmg = GetHandToHandDamage();
}
else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){
//pets wouldn't actually use this but...
@@ -868,12 +868,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) {
dmg = dmg <= 0 ? 1 : dmg;
}
else{
if(GetClass() == MONK || GetClass() == BEASTLORD){
dmg = GetMonkHandToHandDamage();
}
else{
dmg = 1;
}
dmg = GetHandToHandDamage();
}
}
@@ -1006,7 +1001,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
if((GetClass() == MONK || GetClass() == BEASTLORD)) {
if(MagicGloves || GetLevel() >= 30){
dmg = GetMonkHandToHandDamage();
dmg = GetHandToHandDamage();
if (hate) *hate += dmg;
}
}
@@ -1041,13 +1036,8 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
}
}
else{
if(GetClass() == MONK || GetClass() == BEASTLORD){
dmg = GetMonkHandToHandDamage();
if (hate) *hate += dmg;
}
else{
dmg = 1;
}
dmg = GetHandToHandDamage();
if (hate) *hate += dmg;
}
}
@@ -2009,15 +1999,15 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack
}
}
bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack_skill) {
Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killerMob->GetName(), damage, spell, attack_skill);
bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attack_skill) {
Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killer_mob->GetName(), damage, spell, attack_skill);
Mob *oos = nullptr;
if(killerMob) {
oos = killerMob->GetOwnerOrSelf();
if(killer_mob) {
oos = killer_mob->GetOwnerOrSelf();
char buffer[48] = { 0 };
snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
if(parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0)
{
if(GetHP() < 0) {
@@ -2026,15 +2016,15 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
return false;
}
if(killerMob && killerMob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) {
if(killer_mob && killer_mob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) {
char val1[20]={0};
entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE,
killerMob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1));
killer_mob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1));
}
} else {
char buffer[48] = { 0 };
snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
if(parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0)
{
if(GetHP() < 0) {
@@ -2072,21 +2062,21 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
EQApplicationPacket* app= new EQApplicationPacket(OP_Death,sizeof(Death_Struct));
Death_Struct* d = (Death_Struct*)app->pBuffer;
d->spawn_id = GetID();
d->killer_id = killerMob ? killerMob->GetID() : 0;
d->killer_id = killer_mob ? killer_mob->GetID() : 0;
d->bindzoneid = 0;
d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell;
d->attack_skill = SkillDamageTypes[attack_skill];
d->damage = damage;
app->priority = 6;
entity_list.QueueClients(killerMob, app, false);
entity_list.QueueClients(killer_mob, app, false);
if(respawn2) {
respawn2->DeathReset(1);
}
if (killerMob) {
if (killer_mob) {
if(GetClass() != LDON_TREASURE)
hate_list.AddEntToHateList(killerMob, damage);
hate_list.AddEntToHateList(killer_mob, damage);
}
safe_delete(app);
@@ -2148,8 +2138,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
{
if(!IsLdonTreasure && MerchantType == 0) {
kr->SplitExp((finalxp), this);
if(killerMob && (kr->IsRaidMember(killerMob->GetName()) || kr->IsRaidMember(killerMob->GetUltimateOwner()->GetName())))
killerMob->TrySpellOnKill(killed_level,spell);
if(killer_mob && (kr->IsRaidMember(killer_mob->GetName()) || kr->IsRaidMember(killer_mob->GetUltimateOwner()->GetName())))
killer_mob->TrySpellOnKill(killed_level,spell);
}
/* Send the EVENT_KILLED_MERIT event for all raid members */
for (int i = 0; i < MAX_RAID_MEMBERS; i++) {
@@ -2193,8 +2183,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
{
if(!IsLdonTreasure && MerchantType == 0) {
kg->SplitExp((finalxp), this);
if(killerMob && (kg->IsGroupMember(killerMob->GetName()) || kg->IsGroupMember(killerMob->GetUltimateOwner()->GetName())))
killerMob->TrySpellOnKill(killed_level,spell);
if(killer_mob && (kg->IsGroupMember(killer_mob->GetName()) || kg->IsGroupMember(killer_mob->GetUltimateOwner()->GetName())))
killer_mob->TrySpellOnKill(killed_level,spell);
}
/* Send the EVENT_KILLED_MERIT event and update kill tasks
* for all group members */
@@ -2244,8 +2234,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
if(!GetOwner() || (GetOwner() && !GetOwner()->IsClient()))
{
give_exp_client->AddEXP((finalxp), conlevel);
if(killerMob && (killerMob->GetID() == give_exp_client->GetID() || killerMob->GetUltimateOwner()->GetID() == give_exp_client->GetID()))
killerMob->TrySpellOnKill(killed_level,spell);
if(killer_mob && (killer_mob->GetID() == give_exp_client->GetID() || killer_mob->GetUltimateOwner()->GetID() == give_exp_client->GetID()))
killer_mob->TrySpellOnKill(killed_level,spell);
}
}
}
@@ -2393,20 +2383,30 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
uint16 emoteid = oos->GetEmoteID();
if(emoteid != 0)
oos->CastToNPC()->DoNPCEmote(KILLEDNPC, emoteid);
killerMob->TrySpellOnKill(killed_level, spell);
killer_mob->TrySpellOnKill(killed_level, spell);
}
}
WipeHateList();
p_depop = true;
if(killerMob && killerMob->GetTarget() == this) //we can kill things without having them targeted
killerMob->SetTarget(nullptr); //via AE effects and such..
if(killer_mob && killer_mob->GetTarget() == this) //we can kill things without having them targeted
killer_mob->SetTarget(nullptr); //via AE effects and such..
entity_list.UpdateFindableNPCState(this, true);
char buffer[48] = { 0 };
snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, buffer, 0);
/* Zone controller process EVENT_DEATH_ZONE (Death events) */
if (RuleB(Zone, UseZoneController)) {
if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && this->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){
char data_pass[100] = { 0 };
snprintf(data_pass, 99, "%d %d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill), this->GetNPCTypeID());
parse->EventNPC(EVENT_DEATH_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0);
}
}
return true;
}
@@ -2693,82 +2693,140 @@ uint8 Mob::GetWeaponDamageBonus(const Item_Struct *weapon, bool offhand)
}
} else {
// 2h damage bonus
int damage_bonus = 1 + (level - 28) / 3;
if (delay <= 27)
return 1 + ((level - 28) / 3);
else if (delay < 40)
return 1 + ((level - 28) / 3) + ((level - 30) / 5);
else if (delay < 43)
return 2 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3);
else if (delay < 45)
return 3 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3);
else if (delay >= 45)
return 4 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3);
return damage_bonus + 1;
// Client isn't reflecting what the dev quoted, this matches better
if (level > 29) {
int level_bonus = (level - 30) / 5 + 1;
if (level > 50) {
level_bonus++;
int level_bonus2 = level - 50;
if (level > 67)
level_bonus2 += 5;
else if (level > 59)
level_bonus2 += 4;
else if (level > 58)
level_bonus2 += 3;
else if (level > 56)
level_bonus2 += 2;
else if (level > 54)
level_bonus2++;
level_bonus += level_bonus2 * delay / 40;
}
damage_bonus += level_bonus;
}
if (delay >= 40) {
int delay_bonus = (delay - 40) / 3 + 1;
if (delay >= 45)
delay_bonus += 2;
else if (delay >= 43)
delay_bonus++;
damage_bonus += delay_bonus;
}
return damage_bonus;
}
}
int Mob::GetMonkHandToHandDamage(void)
int Mob::GetHandToHandDamage(void)
{
// Kaiyodo - Determine a monk's fist damage. Table data from www.monkly-business.com
// saved as static array - this should speed this function up considerably
static int damage[66] = {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
99, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11,
12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,
14,14,15,15,15,15 };
// Have a look to see if we have epic fists on
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652)
return(9);
else
{
int Level = GetLevel();
if (Level > 65)
return(19);
else
return damage[Level];
if (RuleB(Combat, UseRevampHandToHand)) {
// everyone uses this in the revamp!
int skill = GetSkill(SkillHandtoHand);
int epic = 0;
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 46)
epic = 280;
if (epic > skill)
skill = epic;
return skill / 15 + 3;
}
static uint8 mnk_dmg[] = {99,
4, 4, 4, 4, 5, 5, 5, 5, 5, 6, // 1-10
6, 6, 6, 6, 7, 7, 7, 7, 7, 8, // 11-20
8, 8, 8, 8, 9, 9, 9, 9, 9, 10, // 21-30
10, 10, 10, 10, 11, 11, 11, 11, 11, 12, // 31-40
12, 12, 12, 12, 13, 13, 13, 13, 13, 14, // 41-50
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, // 51-60
14, 14}; // 61-62
static uint8 bst_dmg[] = {99,
4, 4, 4, 4, 4, 5, 5, 5, 5, 5, // 1-10
5, 6, 6, 6, 6, 6, 6, 7, 7, 7, // 11-20
7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30
9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40
10, 11, 11, 11, 11, 11, 11, 12, 12}; // 41-49
if (GetClass() == MONK) {
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50)
return 9;
if (level > 62)
return 15;
return mnk_dmg[level];
} else if (GetClass() == BEASTLORD) {
if (level > 49)
return 13;
return bst_dmg[level];
}
return 2;
}
int Mob::GetMonkHandToHandDelay(void)
int Mob::GetHandToHandDelay(void)
{
// Kaiyodo - Determine a monk's fist delay. Table data from www.monkly-business.com
// saved as static array - this should speed this function up considerably
static int delayshuman[66] = {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
99,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
36,36,36,36,36,35,35,35,35,35,34,34,34,34,34,33,33,33,33,33,
32,32,32,32,32,31,31,31,31,31,30,30,30,29,29,29,28,28,28,27,
26,24,22,20,20,20 };
static int delaysiksar[66] = {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
99,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
36,36,36,36,36,36,36,36,36,36,35,35,35,35,35,34,34,34,34,34,
33,33,33,33,33,32,32,32,32,32,31,31,31,30,30,30,29,29,29,28,
27,24,22,20,20,20 };
// Have a look to see if we have epic fists on
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652)
return(16);
else
{
int Level = GetLevel();
if (GetRace() == HUMAN)
{
if (Level > 65)
return(24);
else
return delayshuman[Level];
}
else //heko: iksar table
{
if (Level > 65)
return(25);
else
return delaysiksar[Level];
}
if (RuleB(Combat, UseRevampHandToHand)) {
// everyone uses this in the revamp!
int skill = GetSkill(SkillHandtoHand);
int epic = 0;
int iksar = 0;
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 46)
epic = 280;
else if (GetRace() == IKSAR)
iksar = 1;
if (epic > skill)
skill = epic;
return iksar - skill / 21 + 38;
}
int delay = 35;
static uint8 mnk_hum_delay[] = {99,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20
35, 35, 35, 35, 35, 35, 35, 34, 34, 34, // 21-30
34, 33, 33, 33, 33, 32, 32, 32, 32, 31, // 31-40
31, 31, 31, 30, 30, 30, 30, 29, 29, 29, // 41-50
29, 28, 28, 28, 28, 27, 27, 27, 27, 26, // 51-60
24, 22}; // 61-62
static uint8 mnk_iks_delay[] = {99,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20
35, 35, 35, 35, 35, 35, 35, 35, 35, 34, // 21-30
34, 34, 34, 34, 34, 33, 33, 33, 33, 33, // 31-40
33, 32, 32, 32, 32, 32, 32, 31, 31, 31, // 41-50
31, 31, 31, 30, 30, 30, 30, 30, 30, 29, // 51-60
25, 23}; // 61-62
static uint8 bst_delay[] = {99,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10
35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20
35, 35, 35, 35, 35, 35, 35, 35, 34, 34, // 21-30
34, 34, 34, 33, 33, 33, 33, 33, 32, 32, // 31-40
32, 32, 32, 31, 31, 31, 31, 31, 30, 30, // 41-50
30, 30, 30, 29, 29, 29, 29, 29, 28, 28, // 51-60
28, 28, 28, 27, 27, 27, 27, 27, 26, 26, // 61-70
26, 26, 26}; // 71-73
if (GetClass() == MONK) {
// Have a look to see if we have epic fists on
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50)
return 16;
int level = GetLevel();
if (level > 62)
return GetRace() == IKSAR ? 21 : 20;
return GetRace() == IKSAR ? mnk_iks_delay[level] : mnk_hum_delay[level];
} else if (GetClass() == BEASTLORD) {
int level = GetLevel();
if (level > 73)
return 25;
return bst_delay[level];
}
return 35;
}
int32 Mob::ReduceDamage(int32 damage)
@@ -4617,28 +4675,27 @@ void Client::SetAttackTimer()
int hhe = itembonuses.HundredHands + spellbonuses.HundredHands;
int speed = 0;
int delay = 36;
float quiver_haste = 0.0f;
int delay = 3500;
//if we have no weapon..
if (ItemToUse == nullptr) {
//above checks ensure ranged weapons do not fall into here
// Work out if we're a monk
if (GetClass() == MONK || GetClass() == BEASTLORD)
delay = GetMonkHandToHandDelay();
} else {
//we have a weapon, use its delay
delay = ItemToUse->Delay;
if (ItemToUse->ItemType == ItemTypeBow || ItemToUse->ItemType == ItemTypeLargeThrowing)
quiver_haste = GetQuiverHaste();
}
if (RuleB(Spells, Jun182014HundredHandsRevamp))
speed = static_cast<int>(((delay / haste_mod) + ((hhe / 1000.0f) * (delay / haste_mod))) * 100);
if (ItemToUse == nullptr)
delay = 100 * GetHandToHandDelay();
else
speed = static_cast<int>(((delay / haste_mod) + ((hhe / 100.0f) * delay)) * 100);
// this is probably wrong
if (quiver_haste > 0)
speed *= quiver_haste;
//we have a weapon, use its delay
delay = 100 * ItemToUse->Delay;
speed = delay / haste_mod;
if (ItemToUse && ItemToUse->ItemType == ItemTypeBow) {
// Live actually had a bug here where they would return the non-modified attack speed
// rather than the cap ...
speed = std::max(speed - GetQuiverHaste(speed), RuleI(Combat, QuiverHasteCap));
} else {
if (RuleB(Spells, Jun182014HundredHandsRevamp))
speed = static_cast<int>(speed + ((hhe / 1000.0f) * speed));
else
speed = static_cast<int>(speed + ((hhe / 100.0f) * delay));
}
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
}
}
+37 -25
View File
@@ -6236,31 +6236,44 @@ float Bot::GetProcChances(float ProcBonus, uint16 hand) {
return ProcChance;
}
int Bot::GetMonkHandToHandDamage(void) {
static int damage[66] = {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
99, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11,
12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,
14,14,15,15,15,15 };
int Bot::GetHandToHandDamage(void) {
if (RuleB(Combat, UseRevampHandToHand)) {
// everyone uses this in the revamp!
int skill = GetSkill(SkillHandtoHand);
int epic = 0;
if (CastToNPC()->GetEquipment(MaterialHands) == 10652 && GetLevel() > 46)
epic = 280;
if (epic > skill)
skill = epic;
return skill / 15 + 3;
}
uint32 botWeaponId = INVALID_ID;
botWeaponId = CastToNPC()->GetEquipment(MaterialHands);
if(botWeaponId == 10652)
static uint8 mnk_dmg[] = {99,
4, 4, 4, 4, 5, 5, 5, 5, 5, 6, // 1-10
6, 6, 6, 6, 7, 7, 7, 7, 7, 8, // 11-20
8, 8, 8, 8, 9, 9, 9, 9, 9, 10, // 21-30
10, 10, 10, 10, 11, 11, 11, 11, 11, 12, // 31-40
12, 12, 12, 12, 13, 13, 13, 13, 13, 14, // 41-50
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, // 51-60
14, 14}; // 61-62
static uint8 bst_dmg[] = {99,
4, 4, 4, 4, 4, 5, 5, 5, 5, 5, // 1-10
5, 6, 6, 6, 6, 6, 6, 7, 7, 7, // 11-20
7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30
9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40
10, 11, 11, 11, 11, 11, 11, 12, 12}; // 41-49
if (GetClass() == MONK) {
if (CastToNPC()->GetEquipment(MaterialHands) == 10652 && GetLevel() > 50)
return 9;
else {
int Level = GetLevel();
if(Level > 65)
return 19;
else
return damage[Level];
}
int Level = GetLevel();
if (Level > 65)
return 19;
else
return damage[Level];
if (level > 62)
return 15;
return mnk_dmg[level];
} else if (GetClass() == BEASTLORD) {
if (level > 49)
return 13;
return bst_dmg[level];
}
return 2;
}
bool Bot::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) {
@@ -7012,8 +7025,7 @@ void Bot::SetAttackTimer() {
int speed = 0;
int delay = 36;
if (ItemToUse == nullptr) {
if ((GetClass() == MONK) || (GetClass() == BEASTLORD))
delay = GetMonkHandToHandDelay();
delay = GetHandToHandDelay();
} else {
delay = ItemToUse->Delay;
}
+1 -1
View File
@@ -171,7 +171,7 @@ public:
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
virtual float GetProcChances(float ProcBonus, uint16 hand);
virtual int GetMonkHandToHandDamage(void);
virtual int GetHandToHandDamage(void);
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
virtual void DoRiposte(Mob* defender);
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(SkillOffense)) * 9 / 10); }
+12 -13
View File
@@ -6803,7 +6803,8 @@ void Client::SendStatsWindow(Client* client, bool use_window)
/* AC */ indP << "<c \"#CCFF00\">AC: " << CalcAC() << "</c><br>" <<
/* AC2 */ indP << "- Mit: " << GetACMit() << " | Avoid: " << GetACAvoid() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "<br>" <<
/* Haste */ indP << "<c \"#CCFF00\">Haste: " << GetHaste() << "</c><br>" <<
/* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "<br><br>" <<
/* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "<br>" <<
/* RunSpeed*/ indP << "<c \"#CCFF00\">Runspeed: " << GetRunspeed() << "</c><br>" <<
/* RegenLbl */ indL << indS << "Regen<br>" << indS << indP << indP << " Base | Items (Cap) " << indP << " | Spell | A.A.s | Total<br>" <<
/* Regen */ regen_string << "<br>" <<
/* Stats */ stat_field << "<br><br>" <<
@@ -8355,21 +8356,19 @@ void Client::ShowNumHits()
return;
}
float Client::GetQuiverHaste()
int Client::GetQuiverHaste(int delay)
{
float quiver_haste = 0;
const ItemInst *pi = nullptr;
for (int r = EmuConstants::GENERAL_BEGIN; r <= EmuConstants::GENERAL_END; r++) {
const ItemInst *pi = GetInv().GetItem(r);
if (!pi)
continue;
if (pi->IsType(ItemClassContainer) && pi->GetItem()->BagType == BagTypeQuiver) {
float temp_wr = (pi->GetItem()->BagWR / RuleI(Combat, QuiverWRHasteDiv));
quiver_haste = std::max(temp_wr, quiver_haste);
}
pi = GetInv().GetItem(r);
if (pi && pi->IsType(ItemClassContainer) && pi->GetItem()->BagType == BagTypeQuiver &&
pi->GetItem()->BagWR > 0)
break;
if (r == EmuConstants::GENERAL_END)
// we will get here if we don't find a valid quiver
return 0;
}
if (quiver_haste > 0)
quiver_haste = 1.0f / (1.0f + static_cast<float>(quiver_haste) / 100.0f);
return quiver_haste;
return (pi->GetItem()->BagWR * 0.0025f * delay) + 1;
}
void Client::SendColoredText(uint32 color, std::string message)
+1 -1
View File
@@ -226,7 +226,7 @@ public:
virtual inline bool IsBerserk() { return berserk; }
virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
virtual void SetAttackTimer();
float GetQuiverHaste();
int GetQuiverHaste(int delay);
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
void AI_Init();
+2 -2
View File
@@ -58,8 +58,8 @@ int32 Client::GetMaxResist() const
{
int level = GetLevel();
int32 base = 500;
if (level > 60) {
base += ((level - 60) * 5);
if (level > 65) {
base += ((level - 65) * 5);
}
return base;
}
+33
View File
@@ -194,6 +194,7 @@ int command_init(void)
command_add("enablerecipe", "[recipe_id] - Enables a recipe using the recipe id.", 80, command_enablerecipe) ||
command_add("equipitem", "[slotid(0-21)] - Equip the item on your cursor into the specified slot", 50, command_equipitem) ||
command_add("face", "- Change the face of your target", 80, command_face) ||
command_add("findaliases", "[search term]- Searches for available command aliases, by alias or command", 0, command_findaliases) ||
command_add("findnpctype", "[search criteria] - Search database NPC types", 100, command_findnpctype) ||
command_add("findspell", "[searchstring] - Search for a spell", 50, command_findspell) ||
command_add("findzone", "[search criteria] - Search database zones", 100, command_findzone) ||
@@ -4945,6 +4946,38 @@ void command_face(Client *c, const Seperator *sep)
}
}
void command_findaliases(Client *c, const Seperator *sep)
{
if (!sep->arg[1][0]) {
c->Message(0, "Usage: #findaliases [alias | command]");
return;
}
std::map<std::string, std::string>::iterator find_iter = commandaliases.find(sep->arg[1]);
if (find_iter == commandaliases.end()) {
c->Message(15, "No commands or aliases match '%s'", sep->arg[1]);
return;
}
std::map<std::string, CommandRecord *>::iterator command_iter = commandlist.find(find_iter->second);
if (find_iter->second.empty() || command_iter == commandlist.end()) {
c->Message(0, "An unknown condition occurred...");
return;
}
c->Message(0, "Available command aliases for '%s':", command_iter->first.c_str());
int commandaliasesshown = 0;
for (std::map<std::string, std::string>::iterator alias_iter = commandaliases.begin(); alias_iter != commandaliases.end(); ++alias_iter) {
if (strcasecmp(find_iter->second.c_str(), alias_iter->second.c_str()) || c->Admin() < command_iter->second->access)
continue;
c->Message(0, "%c%s", COMMAND_CHAR, alias_iter->first.c_str());
++commandaliasesshown;
}
c->Message(0, "%d command alias%s listed.", commandaliasesshown, commandaliasesshown != 1 ? "es" : "");
}
void command_details(Client *c, const Seperator *sep)
{
Mob *target=c->GetTarget();
+1
View File
@@ -94,6 +94,7 @@ void command_emoteview(Client* c, const Seperator *sep);
void command_enablerecipe(Client *c, const Seperator *sep);
void command_equipitem(Client *c, const Seperator *sep);
void command_face(Client *c, const Seperator *sep);
void command_findaliases(Client *c, const Seperator *sep);
void command_findnpctype(Client *c, const Seperator *sep);
void command_findspell(Client *c, const Seperator *sep);
void command_findzone(Client *c, const Seperator *sep);
+18 -1
View File
@@ -114,7 +114,9 @@ const char *QuestEventSubroutines[_LargestEventID] = {
"EVENT_RESPAWN",
"EVENT_DEATH_COMPLETE",
"EVENT_UNHANDLED_OPCODE",
"EVENT_TICK"
"EVENT_TICK",
"EVENT_SPAWN_ZONE",
"EVENT_DEATH_ZONE",
};
PerlembParser::PerlembParser() : perl(nullptr) {
@@ -1424,6 +1426,21 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
ExportVar(package_name.c_str(), "slotid", extradata);
break;
}
case EVENT_SPAWN_ZONE: {
Seperator sep(data);
ExportVar(package_name.c_str(), "spawned_entity_id", sep.arg[0]);
ExportVar(package_name.c_str(), "spawned_npc_id", sep.arg[1]);
break;
}
case EVENT_DEATH_ZONE: {
Seperator sep(data);
ExportVar(package_name.c_str(), "killer_id", sep.arg[0]);
ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]);
break;
}
default: {
break;
+39
View File
@@ -2919,6 +2919,29 @@ XS(XS__UpdateInstanceTimer) {
XSRETURN_EMPTY;
}
XS(XS__GetInstanceTimer);
XS(XS__GetInstanceTimer) {
dXSARGS;
if (items != 0)
Perl_croak(aTHX_ "Usage: GetInstanceTimer()");
uint32 timer = quest_manager.GetInstanceTimer();
XSRETURN_UV(timer);
}
XS(XS__GetInstanceTimerByID);
XS(XS__GetInstanceTimerByID) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: GetInstanceTimerByID(instance_id)");
uint16 instance_id = (uint16)SvUV(ST(0));
uint32 timer = quest_manager.GetInstanceTimerByID(instance_id);
XSRETURN_UV(timer);
}
XS(XS__GetInstanceID);
XS(XS__GetInstanceID) {
dXSARGS;
@@ -3614,6 +3637,19 @@ XS(XS__debug)
XSRETURN_EMPTY;
}
XS(XS__UpdateZoneHeader);
XS(XS__UpdateZoneHeader) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: UpdateZoneHeader(type, value)");
std::string type = (std::string)SvPV_nolen(ST(0));
std::string value = (std::string)SvPV_nolen(ST(1));
quest_manager.UpdateZoneHeader(type, value);
XSRETURN_EMPTY;
}
/*
This is the callback perl will look for to setup the
@@ -3650,6 +3686,8 @@ EXTERN_C XS(boot_quest)
newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file);
newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file);
newXS(strcpy(buf, "UpdateInstanceTimer"), XS__UpdateInstanceTimer, file);
newXS(strcpy(buf, "GetInstanceTimer"), XS__GetInstanceTimer, file);
newXS(strcpy(buf, "GetInstanceTimerByID"), XS__GetInstanceTimerByID, file);
newXS(strcpy(buf, "FlagInstanceByGroupLeader"), XS__FlagInstanceByGroupLeader, file);
newXS(strcpy(buf, "FlagInstanceByRaidLeader"), XS__FlagInstanceByRaidLeader, file);
newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file);
@@ -3841,6 +3879,7 @@ EXTERN_C XS(boot_quest)
newXS(strcpy(buf, "untraindiscs"), XS__untraindiscs, file);
newXS(strcpy(buf, "updatespawntimer"), XS__UpdateSpawnTimer, file);
newXS(strcpy(buf, "updatetaskactivity"), XS__updatetaskactivity, file);
newXS(strcpy(buf, "UpdateZoneHeader"), XS__UpdateZoneHeader, file);
newXS(strcpy(buf, "varlink"), XS__varlink, file);
newXS(strcpy(buf, "voicetell"), XS__voicetell, file);
newXS(strcpy(buf, "we"), XS__we, file);
+10
View File
@@ -641,8 +641,18 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
{
npc->SetID(GetFreeID());
npc->SetMerchantProbability((uint8) zone->random.Int(0, 99));
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
/* Zone controller process EVENT_SPAWN_ZONE */
if (RuleB(Zone, UseZoneController)) {
if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && npc->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){
char data_pass[100] = { 0 };
snprintf(data_pass, 99, "%d %d", npc->GetID(), npc->GetNPCTypeID());
parse->EventNPC(EVENT_SPAWN_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0);
}
}
uint16 emoteid = npc->GetEmoteID();
if (emoteid != 0)
npc->DoNPCEmote(ONSPAWN, emoteid);
+2 -1
View File
@@ -83,7 +83,8 @@ typedef enum {
EVENT_DEATH_COMPLETE,
EVENT_UNHANDLED_OPCODE,
EVENT_TICK,
EVENT_SPAWN_ZONE,
EVENT_DEATH_ZONE,
_LargestEventID
} QuestEventID;
+15 -1
View File
@@ -808,6 +808,14 @@ void lua_update_instance_timer(uint16 instance_id, uint32 new_duration) {
quest_manager.UpdateInstanceTimer(instance_id, new_duration);
}
uint32 lua_get_instance_timer() {
return quest_manager.GetInstanceTimer();
}
uint32 lua_get_instance_timer_by_id(uint16 instance_id) {
return quest_manager.GetInstanceTimerByID(instance_id);
}
int lua_get_instance_id(const char *zone, uint32 version) {
return quest_manager.GetInstanceID(zone, version);
}
@@ -1296,6 +1304,10 @@ void lua_debug(std::string message, int level) {
Log.Out(static_cast<Logs::DebugLevel>(level), Logs::QuestDebug, message);
}
void lua_update_zone_header(std::string type, std::string value) {
quest_manager.UpdateZoneHeader(type, value);
}
#define LuaCreateNPCParse(name, c_type, default_value) do { \
cur = table[#name]; \
if(luabind::type(cur) != LUA_TNIL) { \
@@ -1719,7 +1731,9 @@ luabind::scope lua_register_events() {
luabind::value("leave_area", static_cast<int>(EVENT_LEAVE_AREA)),
luabind::value("death_complete", static_cast<int>(EVENT_DEATH_COMPLETE)),
luabind::value("unhandled_opcode", static_cast<int>(EVENT_UNHANDLED_OPCODE)),
luabind::value("tick", static_cast<int>(EVENT_TICK))
luabind::value("tick", static_cast<int>(EVENT_TICK)),
luabind::value("spawn_zone", static_cast<int>(EVENT_SPAWN_ZONE)),
luabind::value("death_zone", static_cast<int>(EVENT_DEATH_ZONE))
];
}
+7 -7
View File
@@ -1023,14 +1023,14 @@ int Lua_Mob::GetHaste() {
return self->GetHaste();
}
int Lua_Mob::GetMonkHandToHandDamage() {
int Lua_Mob::GetHandToHandDamage() {
Lua_Safe_Call_Int();
return self->GetMonkHandToHandDamage();
return self->GetHandToHandDamage();
}
int Lua_Mob::GetMonkHandToHandDelay() {
int Lua_Mob::GetHandToHandDelay() {
Lua_Safe_Call_Int();
return self->GetMonkHandToHandDelay();
return self->GetHandToHandDelay();
}
void Lua_Mob::Mesmerize() {
@@ -2165,8 +2165,8 @@ luabind::scope lua_register_mob() {
.def("GetInvul", (bool(Lua_Mob::*)(void))&Lua_Mob::GetInvul)
.def("SetExtraHaste", (void(Lua_Mob::*)(int))&Lua_Mob::SetExtraHaste)
.def("GetHaste", (int(Lua_Mob::*)(void))&Lua_Mob::GetHaste)
.def("GetMonkHandToHandDamage", (int(Lua_Mob::*)(void))&Lua_Mob::GetMonkHandToHandDamage)
.def("GetMonkHandToHandDelay", (int(Lua_Mob::*)(void))&Lua_Mob::GetMonkHandToHandDelay)
.def("GetHandToHandDamage", (int(Lua_Mob::*)(void))&Lua_Mob::GetHandToHandDamage)
.def("GetHandToHandDelay", (int(Lua_Mob::*)(void))&Lua_Mob::GetHandToHandDelay)
.def("Mesmerize", (void(Lua_Mob::*)(void))&Lua_Mob::Mesmerize)
.def("IsMezzed", (bool(Lua_Mob::*)(void))&Lua_Mob::IsMezzed)
.def("IsEnraged", (bool(Lua_Mob::*)(void))&Lua_Mob::IsEnraged)
@@ -2303,7 +2303,7 @@ luabind::scope lua_register_mob() {
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot)
.def("CanBuffStack", (int(Lua_Mob::*)(int,int))&Lua_Mob::CanBuffStack)
.def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack)
.def("SetPseudoRoot", (void(Lua_Mob::*)(void))&Lua_Mob::SetPseudoRoot)
.def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot)
.def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible)
.def("SeeInvisibleUndead", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead)
.def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide)
+2 -2
View File
@@ -217,8 +217,8 @@ public:
bool GetInvul();
void SetExtraHaste(int haste);
int GetHaste();
int GetMonkHandToHandDamage();
int GetMonkHandToHandDelay();
int GetHandToHandDamage();
int GetHandToHandDelay();
void Mesmerize();
bool IsMezzed();
bool IsEnraged();
+6
View File
@@ -428,6 +428,11 @@ float Lua_NPC::GetAttackSpeed() {
return self->GetAttackSpeed();
}
int Lua_NPC::GetAttackDelay() {
Lua_Safe_Call_Int();
return self->GetAttackDelay();
}
int Lua_NPC::GetAccuracyRating() {
Lua_Safe_Call_Int();
return self->GetAccuracyRating();
@@ -550,6 +555,7 @@ luabind::scope lua_register_npc() {
.def("GetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::GetSpellFocusHeal)
.def("GetSlowMitigation", (int(Lua_NPC::*)(void))&Lua_NPC::GetSlowMitigation)
.def("GetAttackSpeed", (float(Lua_NPC::*)(void))&Lua_NPC::GetAttackSpeed)
.def("GetAttackDelay", (int(Lua_NPC::*)(void))&Lua_NPC::GetAttackDelay)
.def("GetAccuracyRating", (int(Lua_NPC::*)(void))&Lua_NPC::GetAccuracyRating)
.def("GetSpawnKillCount", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnKillCount)
.def("GetScore", (int(Lua_NPC::*)(void))&Lua_NPC::GetScore)
+1
View File
@@ -111,6 +111,7 @@ public:
int GetSpellFocusHeal();
float GetSlowMitigation();
float GetAttackSpeed();
int GetAttackDelay();
int GetAccuracyRating();
int GetSpawnKillCount();
int GetScore();
+3 -1
View File
@@ -117,7 +117,9 @@ const char *LuaEvents[_LargestEventID] = {
"event_respawn",
"event_death_complete",
"event_unhandled_opcode",
"event_tick"
"event_tick",
"event_spawn_zone",
"event_death_zone"
};
extern Zone *zone;
+2 -2
View File
@@ -756,7 +756,7 @@ public:
uint8 GetWeaponDamageBonus(const Item_Struct* weapon, bool offhand = false);
uint16 GetDamageTable(SkillUseTypes skillinuse);
virtual int GetMonkHandToHandDamage(void);
virtual int GetHandToHandDamage(void);
bool CanThisClassDoubleAttack(void) const;
bool CanThisClassTripleAttack() const;
@@ -766,7 +766,7 @@ public:
bool CanThisClassParry(void) const;
bool CanThisClassBlock(void) const;
int GetMonkHandToHandDelay(void);
int GetHandToHandDelay(void);
uint32 GetClassLevelFactor();
void Mesmerize();
inline bool IsMezzed() const { return mezzed; }
+48
View File
@@ -843,6 +843,54 @@ bool NPC::DatabaseCastAccepted(int spell_id) {
return false;
}
bool NPC::SpawnZoneController(){
if (!RuleB(Zone, UseZoneController))
return false;
NPCType* npc_type = new NPCType;
memset(npc_type, 0, sizeof(NPCType));
strncpy(npc_type->name, "zone_controller", 60);
npc_type->cur_hp = 2000000000;
npc_type->max_hp = 2000000000;
npc_type->hp_regen = 100000000;
npc_type->race = 240;
npc_type->size = .1;
npc_type->gender = 2;
npc_type->class_ = 1;
npc_type->deity = 1;
npc_type->level = 200;
npc_type->npc_id = ZONE_CONTROLLER_NPC_ID;
npc_type->loottable_id = 0;
npc_type->texture = 3;
npc_type->runspeed = 0;
npc_type->d_melee_texture1 = 0;
npc_type->d_melee_texture2 = 0;
npc_type->merchanttype = 0;
npc_type->bodytype = 11;
npc_type->prim_melee_type = 28;
npc_type->sec_melee_type = 28;
npc_type->findable = 0;
npc_type->trackable = 0;
strcpy(npc_type->special_abilities, "12,1^13,1^14,1^15,1^16,1^17,1^19,1^22,1^24,1^25,1^28,1^31,1^35,1^39,1^42,1");
glm::vec4 point;
point.x = 3000;
point.y = 1000;
point.z = 500;
NPC* npc = new NPC(npc_type, nullptr, point, FlyMode3);
npc->GiveNPCTypeData(npc_type);
entity_list.AddNPC(npc);
return true;
}
NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client) {
if(spawncommand == 0 || spawncommand[0] == 0) {
return 0;
+1
View File
@@ -96,6 +96,7 @@ class NPC : public Mob
{
public:
static NPC* SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client = nullptr);
static bool SpawnZoneController();
static int8 GetAILevel(bool iForceReRead = false);
NPC(const NPCType* data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false);
+10 -10
View File
@@ -4721,12 +4721,12 @@ XS(XS_Mob_GetHaste)
XSRETURN(1);
}
XS(XS_Mob_GetMonkHandToHandDamage); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_GetMonkHandToHandDamage)
XS(XS_Mob_GetHandToHandDamage); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_GetHandToHandDamage)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetMonkHandToHandDamage(THIS)");
Perl_croak(aTHX_ "Usage: Mob::GetHandToHandDamage(THIS)");
{
Mob * THIS;
int RETVAL;
@@ -4741,7 +4741,7 @@ XS(XS_Mob_GetMonkHandToHandDamage)
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetMonkHandToHandDamage();
RETVAL = THIS->GetHandToHandDamage();
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
@@ -4877,12 +4877,12 @@ XS(XS_Mob_CanThisClassParry)
XSRETURN(1);
}
XS(XS_Mob_GetMonkHandToHandDelay); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_GetMonkHandToHandDelay)
XS(XS_Mob_GetHandToHandDelay); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_GetHandToHandDelay)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::GetMonkHandToHandDelay(THIS)");
Perl_croak(aTHX_ "Usage: Mob::GetHandToHandDelay(THIS)");
{
Mob * THIS;
int RETVAL;
@@ -4897,7 +4897,7 @@ XS(XS_Mob_GetMonkHandToHandDelay)
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetMonkHandToHandDelay();
RETVAL = THIS->GetHandToHandDelay();
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
@@ -9192,13 +9192,13 @@ XS(boot_Mob)
newXSproto(strcpy(buf, "GetInvul"), XS_Mob_GetInvul, file, "$");
newXSproto(strcpy(buf, "SetExtraHaste"), XS_Mob_SetExtraHaste, file, "$$");
newXSproto(strcpy(buf, "GetHaste"), XS_Mob_GetHaste, file, "$");
newXSproto(strcpy(buf, "GetMonkHandToHandDamage"), XS_Mob_GetMonkHandToHandDamage, file, "$");
newXSproto(strcpy(buf, "GetHandToHandDamage"), XS_Mob_GetHandToHandDamage, file, "$");
newXSproto(strcpy(buf, "CanThisClassDoubleAttack"), XS_Mob_CanThisClassDoubleAttack, file, "$");
newXSproto(strcpy(buf, "CanThisClassDualWield"), XS_Mob_CanThisClassDualWield, file, "$");
newXSproto(strcpy(buf, "CanThisClassRiposte"), XS_Mob_CanThisClassRiposte, file, "$");
newXSproto(strcpy(buf, "CanThisClassDodge"), XS_Mob_CanThisClassDodge, file, "$");
newXSproto(strcpy(buf, "CanThisClassParry"), XS_Mob_CanThisClassParry, file, "$");
newXSproto(strcpy(buf, "GetMonkHandToHandDelay"), XS_Mob_GetMonkHandToHandDelay, file, "$");
newXSproto(strcpy(buf, "GetHandToHandDelay"), XS_Mob_GetHandToHandDelay, file, "$");
newXSproto(strcpy(buf, "GetClassLevelFactor"), XS_Mob_GetClassLevelFactor, file, "$");
newXSproto(strcpy(buf, "Mesmerize"), XS_Mob_Mesmerize, file, "$");
newXSproto(strcpy(buf, "IsMezzed"), XS_Mob_IsMezzed, file, "$");
+9 -2
View File
@@ -484,10 +484,17 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string
//second look for /quests/zone/npcname.ext (precedence)
const NPCType *npc_type = database.LoadNPCTypesData(npcid);
if(!npc_type) {
if (!npc_type && npcid != ZONE_CONTROLLER_NPC_ID) {
return nullptr;
}
std::string npc_name = npc_type->name;
std::string npc_name;
if (npcid == ZONE_CONTROLLER_NPC_ID){
npc_name = "zone_controller";
}
else{
npc_name = npc_type->name;
}
int sz = static_cast<int>(npc_name.length());
for(int i = 0; i < sz; ++i) {
if(npc_name[i] == '`') {
+95
View File
@@ -2598,6 +2598,29 @@ void QuestManager::UpdateInstanceTimer(uint16 instance_id, uint32 new_duration)
}
}
uint32 QuestManager::GetInstanceTimer() {
if (zone && zone->GetInstanceID() > 0 && zone->GetInstanceTimer()) {
uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime();
return ttime;
}
return 0;
}
uint32 QuestManager::GetInstanceTimerByID(uint16 instance_id) {
if (instance_id == 0)
return 0;
std::string query = StringFormat("SELECT ((start_time + duration) - UNIX_TIMESTAMP()) AS `remaining` FROM `instance_list` WHERE `id` = %lu", (unsigned long)instance_id);
auto results = database.QueryDatabase(query);
if (results.Success()) {
auto row = results.begin();
uint32 timer = atoi(row[0]);
return timer;
}
return 0;
}
uint16 QuestManager::GetInstanceID(const char *zone, int16 version)
{
QuestManagerCurrentQuestVars();
@@ -3070,3 +3093,75 @@ std::string QuestManager::GetEncounter() const {
return "";
}
void QuestManager::UpdateZoneHeader(std::string type, std::string value) {
if (strcasecmp(type.c_str(), "ztype") == 0)
zone->newzone_data.ztype = atoi(value.c_str());
else if (strcasecmp(type.c_str(), "fog_red") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_red[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "fog_green") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_green[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "fog_blue") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_blue[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "fog_minclip") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_minclip[i] = atof(value.c_str());
}
} else if (strcasecmp(type.c_str(), "fog_maxclip") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.fog_maxclip[i] = atof(value.c_str());
}
}
else if (strcasecmp(type.c_str(), "gravity") == 0)
zone->newzone_data.gravity = atof(value.c_str());
else if (strcasecmp(type.c_str(), "time_type") == 0)
zone->newzone_data.time_type = atoi(value.c_str());
else if (strcasecmp(type.c_str(), "rain_chance") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.rain_chance[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "rain_duration") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.rain_duration[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "snow_chance") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.snow_chance[i] = atoi(value.c_str());
}
} else if (strcasecmp(type.c_str(), "snow_duration") == 0) {
for (int i = 0; i < 4; i++) {
zone->newzone_data.snow_duration[i] = atoi(value.c_str());
}
}
else if (strcasecmp(type.c_str(), "sky") == 0)
zone->newzone_data.sky = atoi(value.c_str());
else if (strcasecmp(type.c_str(), "safe_x") == 0)
zone->newzone_data.safe_x = atof(value.c_str());
else if (strcasecmp(type.c_str(), "safe_y") == 0)
zone->newzone_data.safe_y = atof(value.c_str());
else if (strcasecmp(type.c_str(), "safe_z") == 0)
zone->newzone_data.safe_z = atof(value.c_str());
else if (strcasecmp(type.c_str(), "max_z") == 0)
zone->newzone_data.max_z = atof(value.c_str());
else if (strcasecmp(type.c_str(), "underworld") == 0)
zone->newzone_data.underworld = atof(value.c_str());
else if (strcasecmp(type.c_str(), "minclip") == 0)
zone->newzone_data.minclip = atof(value.c_str());
else if (strcasecmp(type.c_str(), "maxclip") == 0)
zone->newzone_data.maxclip = atof(value.c_str());
else if (strcasecmp(type.c_str(), "fog_density") == 0)
zone->newzone_data.fog_density = atof(value.c_str());
else if (strcasecmp(type.c_str(), "suspendbuffs") == 0)
zone->newzone_data.SuspendBuffs = atoi(value.c_str());
EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct));
memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size);
entity_list.QueueClients(0, outapp);
safe_delete(outapp);
}
+3
View File
@@ -218,6 +218,9 @@ public:
uint32 MerchantCountItem(uint32 NPCid, uint32 itemid);
uint16 CreateInstance(const char *zone, int16 version, uint32 duration);
void UpdateInstanceTimer(uint16 instance_id, uint32 new_duration);
void UpdateZoneHeader(std::string type, std::string value);
uint32 GetInstanceTimer();
uint32 GetInstanceTimerByID(uint16 instance_id = 0);
void DestroyInstance(uint16 instance_id);
uint16 GetInstanceID(const char *zone, int16 version);
void AssignToInstance(uint16 instance_id);
+2
View File
@@ -549,6 +549,8 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spa
spawn2_list.Insert(new_spawn);
}
NPC::SpawnZoneController();
return true;
}
+52 -18
View File
@@ -1268,6 +1268,14 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
}
}
// we're done casting, now try to apply the spell
if( !SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust) )
{
Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: SpellFinished returned false.", spell_id);
InterruptSpell();
return;
}
if(IsClient()) {
CheckNumHitsRemaining(NumHit::MatchingSpells);
TrySympatheticProc(target, spell_id);
@@ -1277,14 +1285,6 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
TryTriggerOnCast(spell_id, 0);
// we're done casting, now try to apply the spell
if( !SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust) )
{
Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: SpellFinished returned false.", spell_id);
InterruptSpell();
return;
}
if(DeleteChargeFromSlot >= 0)
CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true);
@@ -5310,6 +5310,7 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff)
EQApplicationPacket* outapp;
outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct));
SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer;
int index;
sbf->entityid = GetID();
sbf->slot = 2;
@@ -5317,6 +5318,19 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff)
sbf->slotid = 0;
sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
// We really don't know what to send as sbf->effect.
// The code used to send level (and still does for cases we don't know)
//
// The fixes below address known issues with sending level in this field.
// Typically, when the packet is sent, or when the user
// next does something on the UI that causes an update (like opening a
// pack), the stats updated by the spell in question get corrupted.
//
// The values were determined by trial and error. I could not find a
// pattern or find a field in spells_new that would work.
sbf->effect=sbf->level;
if (IsEffectInSpell(buff.spellid, SE_TotalHP))
{
// If any of the lower 6 bits are set, the GUI changes MAX_HP AGAIN.
@@ -5327,25 +5341,45 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff)
else if (IsEffectInSpell(buff.spellid, SE_CurrentHP))
{
// This is mostly a problem when we try and update duration on a
// dot or a hp->mana conversion. Zero cancels the effect, any
// other value has the GUI doing that value at the same time server
// is doing theirs. This makes the two match.
int index = GetSpellEffectIndex(buff.spellid, SE_CurrentHP);
// dot or a hp->mana conversion. Zero cancels the effect
// Sending teh actual change again seems to work.
index = GetSpellEffectIndex(buff.spellid, SE_CurrentHP);
sbf->effect = abs(spells[buff.spellid].base[index]);
}
else if (IsEffectInSpell(buff.spellid, SE_SeeInvis))
{
// Wish I knew what this sbf->effect field was trying to tell
// the client. 10 seems to not break SeeInvis spells. Level,
// 10 seems to not break SeeInvis spells. Level,
// which is what the old client sends breaks the client at at
// least level 9, maybe more.
sbf->effect = 10;
}
else
else if (IsEffectInSpell(buff.spellid, SE_ArmorClass) ||
IsEffectInSpell(buff.spellid, SE_ResistFire) ||
IsEffectInSpell(buff.spellid, SE_ResistCold) ||
IsEffectInSpell(buff.spellid, SE_ResistPoison) ||
IsEffectInSpell(buff.spellid, SE_ResistDisease) ||
IsEffectInSpell(buff.spellid, SE_ResistMagic) ||
IsEffectInSpell(buff.spellid, SE_STR) ||
IsEffectInSpell(buff.spellid, SE_STA) ||
IsEffectInSpell(buff.spellid, SE_DEX) ||
IsEffectInSpell(buff.spellid, SE_WIS) ||
IsEffectInSpell(buff.spellid, SE_INT) ||
IsEffectInSpell(buff.spellid, SE_AGI))
{
// Default to what old code did until we find a better fix for
// other spell lines.
sbf->effect=sbf->level;
// This seems to work. Previosly stats got corrupted when sending
// level.
sbf->effect = 46;
}
else if (IsEffectInSpell(buff.spellid, SE_CHA))
{
index = GetSpellEffectIndex(buff.spellid, SE_CHA);
sbf->effect = abs(spells[buff.spellid].base[index]);
// Only use this valie if its not a spacer.
if (sbf->effect != 0)
{
// Same as other stats, need this to prevent a double update.
sbf->effect = 46;
}
}
sbf->bufffade = 0;