mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 09:06:46 +00:00
Merge from master, probably wont compile but will fix that soon
This commit is contained in:
@@ -20,6 +20,7 @@ SET(zone_sources
|
||||
embparser_api.cpp
|
||||
embperl.cpp
|
||||
embxs.cpp
|
||||
encounter.cpp
|
||||
entity.cpp
|
||||
exp.cpp
|
||||
fearpath.cpp
|
||||
@@ -35,6 +36,7 @@ SET(zone_sources
|
||||
lua_corpse.cpp
|
||||
lua_client.cpp
|
||||
lua_door.cpp
|
||||
lua_encounter.cpp
|
||||
lua_entity.cpp
|
||||
lua_entity_list.cpp
|
||||
lua_general.cpp
|
||||
@@ -137,6 +139,7 @@ SET(zone_headers
|
||||
embparser.h
|
||||
embperl.h
|
||||
embxs.h
|
||||
encounter.h
|
||||
entity.h
|
||||
errmsg.h
|
||||
event_codes.h
|
||||
@@ -148,6 +151,7 @@ SET(zone_headers
|
||||
lua_bit.h
|
||||
lua_client.h
|
||||
lua_corpse.h
|
||||
lua_encounter.h
|
||||
lua_entity.h
|
||||
lua_entity_list.h
|
||||
lua_general.h
|
||||
|
||||
+21
-14
@@ -1104,9 +1104,9 @@ void Client::SendAATable() {
|
||||
|
||||
uint32 i;
|
||||
for(i=0;i < MAX_PP_AA_ARRAY;i++){
|
||||
aa2->aa_list[i].aa_skill = aa[i]->AA;
|
||||
aa2->aa_list[i].aa_value = aa[i]->value;
|
||||
aa2->aa_list[i].unknown08 = 0;
|
||||
aa2->aa_list[i].AA = aa[i]->value ? aa[i]->AA : 0; // bit of a hack to prevent expendables punching a hole
|
||||
aa2->aa_list[i].value = aa[i]->value;
|
||||
aa2->aa_list[i].charges = aa[i]->charges;
|
||||
}
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
@@ -1309,11 +1309,9 @@ void Client::SendAA(uint32 id, int seq) {
|
||||
SendAA_Struct* saa_next = nullptr;
|
||||
saa_next = zone->FindAA(saa->sof_next_id);
|
||||
|
||||
// hard-coding values like this is dangerous and makes adding/updating clients a nightmare...
|
||||
if (saa_next &&
|
||||
(((GetClientVersionBit() == 4) && (saa_next->clientver > 4))
|
||||
|| ((GetClientVersionBit() == 8) && (saa_next->clientver > 5))
|
||||
|| ((GetClientVersionBit() == 16) && (saa_next->clientver > 6)))){
|
||||
// this check should work as long as we continue to just add the clients and just increase
|
||||
// each number ....
|
||||
if (saa_next && static_cast<int>(GetClientVersion()) < saa_next->clientver - 1) {
|
||||
saa->next_id=0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
@@ -1397,26 +1395,33 @@ uint32 Client::GetAA(uint32 aa_id) const {
|
||||
bool Client::SetAA(uint32 aa_id, uint32 new_value) {
|
||||
aa_points[aa_id] = new_value;
|
||||
uint32 cur;
|
||||
auto sendaa = zone->FindAA(aa_id); // this is a bit hacky
|
||||
uint32 charges = sendaa->special_category == 7 && new_value ? 1 : 0;
|
||||
for(cur=0;cur < MAX_PP_AA_ARRAY;cur++){
|
||||
if((aa[cur]->value > 1) && ((aa[cur]->AA - aa[cur]->value + 1)== aa_id)){
|
||||
aa[cur]->value = new_value;
|
||||
if(new_value > 0)
|
||||
aa[cur]->AA++;
|
||||
else
|
||||
aa[cur]->AA = 0;
|
||||
aa[cur]->charges = charges;
|
||||
return true;
|
||||
}
|
||||
else if((aa[cur]->value == 1) && (aa[cur]->AA == aa_id)){
|
||||
aa[cur]->value = new_value;
|
||||
if(new_value > 0)
|
||||
aa[cur]->AA++;
|
||||
else
|
||||
aa[cur]->AA = 0;
|
||||
aa[cur]->charges = charges;
|
||||
return true;
|
||||
}
|
||||
// hack to prevent expendable exploit, we should probably be reshuffling the array to fix the hole
|
||||
else if(aa[cur]->value == 0 && new_value == 1 && aa[cur]->AA == aa_id) {
|
||||
aa[cur]->value = new_value;
|
||||
aa[cur]->charges = charges;
|
||||
return true;
|
||||
}
|
||||
else if(aa[cur]->AA==0){ //end of list
|
||||
aa[cur]->AA = aa_id;
|
||||
aa[cur]->value = new_value;
|
||||
aa[cur]->charges = charges;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1487,8 +1492,10 @@ void Client::ResetAA(){
|
||||
for (i=0; i < MAX_PP_AA_ARRAY; i++) {
|
||||
aa[i]->AA = 0;
|
||||
aa[i]->value = 0;
|
||||
m_pp.aa_array[MAX_PP_AA_ARRAY].AA = 0;
|
||||
m_pp.aa_array[MAX_PP_AA_ARRAY].value = 0;
|
||||
aa[i]->charges = 0;
|
||||
m_pp.aa_array[i].AA = 0;
|
||||
m_pp.aa_array[i].value = 0;
|
||||
m_pp.aa_array[i].charges= 0;
|
||||
}
|
||||
|
||||
std::map<uint32,uint8>::iterator itr;
|
||||
|
||||
+40
-13
@@ -982,14 +982,24 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
if((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30){
|
||||
dmg = GetMonkHandToHandDamage();
|
||||
if (hate) *hate += dmg;
|
||||
bool MagicGloves=false;
|
||||
if (IsClient()) {
|
||||
ItemInst *gloves=CastToClient()->GetInv().GetItem(MainHands);
|
||||
if (gloves != nullptr) {
|
||||
MagicGloves = gloves->GetItem()->Magic;
|
||||
}
|
||||
}
|
||||
|
||||
if((GetClass() == MONK || GetClass() == BEASTLORD)) {
|
||||
if(MagicGloves || GetLevel() >= 30){
|
||||
dmg = GetMonkHandToHandDamage();
|
||||
if (hate) *hate += dmg;
|
||||
}
|
||||
}
|
||||
else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){ //pets wouldn't actually use this but...
|
||||
dmg = 1; //it gives us an idea if we can hit
|
||||
}
|
||||
else if(GetSpecialAbility(SPECATK_MAGICAL)){
|
||||
else if(MagicGloves || GetSpecialAbility(SPECATK_MAGICAL)){
|
||||
dmg = 1;
|
||||
}
|
||||
else
|
||||
@@ -2134,6 +2144,10 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
if(give_exp && give_exp->IsClient())
|
||||
give_exp_client = give_exp->CastToClient();
|
||||
|
||||
//do faction hits even if we are a merchant, so long as a player killed us
|
||||
if (give_exp_client && !RuleB(NPC, EnableMeritBasedFaction))
|
||||
hate_list.DoFactionHits(GetNPCFactionID());
|
||||
|
||||
bool IsLdonTreasure = (this->GetClass() == LDON_TREASURE);
|
||||
if (give_exp_client && !IsCorpse())
|
||||
{
|
||||
@@ -2277,10 +2291,6 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
}
|
||||
}
|
||||
|
||||
//do faction hits even if we are a merchant, so long as a player killed us
|
||||
if(give_exp_client && !RuleB(NPC, EnableMeritBasedFaction))
|
||||
hate_list.DoFactionHits(GetNPCFactionID());
|
||||
|
||||
if (!HasOwner() && !IsMerc() && class_ != MERCHANT && class_ != ADVENTUREMERCHANT && !GetSwarmInfo()
|
||||
&& MerchantType == 0 && killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) ||
|
||||
(killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient())))
|
||||
@@ -3683,7 +3693,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
|
||||
//send an HP update if we are hurt
|
||||
if(GetHP() < GetMaxHP())
|
||||
SendHPUpdate();
|
||||
SendHPUpdate(!iBuffTic); // the OP_Damage actually updates the client in these cases, so we skill them
|
||||
} //end `if damage was done`
|
||||
|
||||
//send damage packet...
|
||||
@@ -3700,6 +3710,23 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
a->type = SkillDamageTypes[skill_used]; // was 0x1c
|
||||
a->damage = damage;
|
||||
a->spellid = spell_id;
|
||||
a->meleepush_xy = attacker->GetHeading() * 2.0f;
|
||||
if (RuleB(Combat, MeleePush) && damage > 0 && !IsRooted() &&
|
||||
(IsClient() || zone->random.Roll(RuleI(Combat, MeleePushChance)))) {
|
||||
a->force = EQEmu::GetSkillMeleePushForce(skill_used);
|
||||
// update NPC stuff
|
||||
auto new_pos = glm::vec3(m_Position.x + (a->force * std::sin(a->meleepush_xy) + m_Delta.x),
|
||||
m_Position.y + (a->force * std::cos(a->meleepush_xy) + m_Delta.y), m_Position.z);
|
||||
if (zone->zonemap && zone->zonemap->CheckLoS(glm::vec3(m_Position), new_pos)) { // If we have LoS on the new loc it should be reachable.
|
||||
if (IsNPC()) {
|
||||
// Is this adequate?
|
||||
Teleport(new_pos);
|
||||
SendPosUpdate();
|
||||
}
|
||||
} else {
|
||||
a->force = 0.0f; // we couldn't move there, so lets not
|
||||
}
|
||||
}
|
||||
|
||||
//Note: if players can become pets, they will not receive damage messages of their own
|
||||
//this was done to simplify the code here (since we can only effectively skip one mob on queue)
|
||||
@@ -3968,7 +3995,7 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) {
|
||||
}
|
||||
|
||||
// Innate + aug procs from weapons
|
||||
// TODO: powersource procs
|
||||
// TODO: powersource procs -- powersource procs are on invis augs, so shouldn't need anything extra
|
||||
TryWeaponProc(weapon_g, weapon_g->GetItem(), on, hand);
|
||||
// Procs from Buffs and AA both melee and range
|
||||
TrySpellProc(weapon_g, weapon_g->GetItem(), on, hand);
|
||||
@@ -4054,7 +4081,7 @@ void Mob::TryWeaponProc(const ItemInst *inst, const ItemData *weapon, Mob *on, u
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Powersource procs
|
||||
// TODO: Powersource procs -- powersource procs are from augs so shouldn't need anything extra
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -4116,7 +4143,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const ItemData *weapon, Mob *on, ui
|
||||
outapp->priority = 3;
|
||||
entity_list.QueueCloseClients(this, outapp, false, 200, 0, true);
|
||||
safe_delete(outapp);
|
||||
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on);
|
||||
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
|
||||
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
|
||||
SpellProcs[i].base_spellID);
|
||||
} else {
|
||||
@@ -4222,7 +4249,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
if (this->IsPet() && this->GetOwner()->IsBot()) {
|
||||
if (this->IsPet() && this->GetOwner() && this->GetOwner()->IsBot()) {
|
||||
this->TryPetCriticalHit(defender,skill,damage);
|
||||
return;
|
||||
}
|
||||
|
||||
+31
-30
@@ -428,7 +428,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
newbon->DSMitigation += item->DSMitigation;
|
||||
}
|
||||
if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
}
|
||||
|
||||
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
||||
@@ -559,7 +559,7 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool
|
||||
/*
|
||||
Powerful Non-live like option allows developers to add worn effects on items that
|
||||
can stack with other worn effects of the same spell effect type, instead of only taking the highest value.
|
||||
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus.
|
||||
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus.
|
||||
To enable use RuleI(Spells, AdditiveBonusWornType)
|
||||
Setting value = 2 Will force all live items to automatically be calculated additivily
|
||||
Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation
|
||||
@@ -579,7 +579,7 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool
|
||||
|
||||
if(GetLevel() < item->ReqLevel)
|
||||
return;
|
||||
|
||||
|
||||
if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType))
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);// Non-live like - Addititive latent effects
|
||||
|
||||
@@ -691,7 +691,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
continue;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName());
|
||||
|
||||
|
||||
uint8 focus = IsFocusEffect(0, 0, true,effect);
|
||||
if (focus)
|
||||
{
|
||||
@@ -1007,7 +1007,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
case SE_BlockBehind:
|
||||
newbon->BlockBehind += base1;
|
||||
break;
|
||||
|
||||
|
||||
case SE_StrikeThrough:
|
||||
case SE_StrikeThrough2:
|
||||
newbon->StrikeThrough += base1;
|
||||
@@ -1313,7 +1313,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_Vampirism:
|
||||
newbon->Vampirism += base1;
|
||||
break;
|
||||
break;
|
||||
|
||||
case SE_FrenziedDevastation:
|
||||
newbon->FrenziedDevastation += base2;
|
||||
@@ -1416,7 +1416,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
}
|
||||
|
||||
case SE_SkillProcSuccess:{
|
||||
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid)
|
||||
@@ -1449,7 +1449,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(i = 0; i < buff_count; i++) {
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN){
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining,i);
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining, i, buffs[i].instrument_mod);
|
||||
|
||||
if (buffs[i].numhits > 0)
|
||||
Numhits(true);
|
||||
@@ -1472,8 +1472,9 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
|
||||
}
|
||||
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, uint8 WornType, uint32 ticsremaining, int buffslot,
|
||||
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *new_bonus, uint16 casterId,
|
||||
uint8 WornType, int32 ticsremaining, int buffslot, int instrument_mod,
|
||||
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
||||
{
|
||||
int i, effect_value, base2, max, effectid;
|
||||
bool AdditiveWornBonus = false;
|
||||
@@ -1509,9 +1510,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType))
|
||||
AdditiveWornBonus = true;
|
||||
|
||||
|
||||
effectid = spells[spell_id].effectid[i];
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining);
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, instrument_mod, caster, ticsremaining);
|
||||
base2 = spells[spell_id].base2[i];
|
||||
max = spells[spell_id].max[i];
|
||||
}
|
||||
@@ -1620,10 +1621,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) {
|
||||
effect_value -= ((effect_value * GetSlowMitigation()/100));
|
||||
if (effect_value > new_bonus->inhibitmelee)
|
||||
if (effect_value > new_bonus->inhibitmelee)
|
||||
new_bonus->inhibitmelee = effect_value;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1839,7 +1840,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
new_bonus->DamageShieldType = GetDamageShieldType(spell_id, max);
|
||||
else
|
||||
new_bonus->DamageShieldType = GetDamageShieldType(spell_id);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2020,7 +2021,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_Vampirism:
|
||||
new_bonus->Vampirism += effect_value;
|
||||
break;
|
||||
break;
|
||||
|
||||
case SE_AllInstrumentMod:
|
||||
{
|
||||
@@ -2263,7 +2264,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_CriticalSpellChance:
|
||||
{
|
||||
new_bonus->CriticalSpellChance += effect_value;
|
||||
|
||||
|
||||
if (base2 > new_bonus->SpellCritDmgIncNoStack)
|
||||
new_bonus->SpellCritDmgIncNoStack = base2;
|
||||
break;
|
||||
@@ -2473,7 +2474,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_NegateAttacks:
|
||||
{
|
||||
if (!new_bonus->NegateAttacks[0] ||
|
||||
if (!new_bonus->NegateAttacks[0] ||
|
||||
((new_bonus->NegateAttacks[0] && new_bonus->NegateAttacks[2]) && (new_bonus->NegateAttacks[2] < max))){
|
||||
new_bonus->NegateAttacks[0] = 1;
|
||||
new_bonus->NegateAttacks[1] = buffslot;
|
||||
@@ -2493,7 +2494,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
case SE_MeleeThresholdGuard:
|
||||
{
|
||||
if (new_bonus->MeleeThresholdGuard[0] < effect_value){
|
||||
@@ -2860,17 +2861,17 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
new_bonus->NegateIfCombat = true;
|
||||
break;
|
||||
|
||||
case SE_Screech:
|
||||
case SE_Screech:
|
||||
new_bonus->Screech = effect_value;
|
||||
break;
|
||||
|
||||
case SE_AlterNPCLevel:
|
||||
|
||||
if (IsNPC()){
|
||||
if (!new_bonus->AlterNPCLevel
|
||||
|| ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value))
|
||||
if (!new_bonus->AlterNPCLevel
|
||||
|| ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value))
|
||||
|| ((effect_value > 0) && (new_bonus->AlterNPCLevel < effect_value))) {
|
||||
|
||||
|
||||
int tmp_lv = GetOrigLevel() + effect_value;
|
||||
if (tmp_lv < 1)
|
||||
tmp_lv = 1;
|
||||
@@ -2908,7 +2909,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
new_bonus->BerserkSPA = true;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case SE_Metabolism:
|
||||
new_bonus->Metabolism += effect_value;
|
||||
break;
|
||||
@@ -3009,7 +3010,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
}
|
||||
|
||||
case SE_SkillProc:{
|
||||
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(new_bonus->SkillProc[e] && new_bonus->SkillProc[e] == spell_id)
|
||||
@@ -3024,7 +3025,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
}
|
||||
|
||||
case SE_SkillProcSuccess:{
|
||||
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(new_bonus->SkillProcSuccess[e] && new_bonus->SkillProcSuccess[e] == spell_id)
|
||||
@@ -3040,9 +3041,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
|
||||
if (IsAISpellEffect) {
|
||||
|
||||
|
||||
//Non-Focused Effect to modify incoming spell damage by resist type.
|
||||
case SE_FcSpellVulnerability:
|
||||
case SE_FcSpellVulnerability:
|
||||
ModVulnerability(base2, effect_value);
|
||||
break;
|
||||
}
|
||||
@@ -4394,7 +4395,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
aabonuses.SlayUndead[0] = effect_value;
|
||||
aabonuses.SlayUndead[1] = effect_value;
|
||||
break;
|
||||
|
||||
|
||||
case SE_DoubleRangedAttack:
|
||||
spellbonuses.DoubleRangedAttack = effect_value;
|
||||
aabonuses.DoubleRangedAttack = effect_value;
|
||||
@@ -4414,7 +4415,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
aabonuses.ShieldEquipDmgMod[1] = effect_value;
|
||||
itembonuses.ShieldEquipDmgMod[0] = effect_value;
|
||||
itembonuses.ShieldEquipDmgMod[1] = effect_value;
|
||||
break;
|
||||
break;
|
||||
|
||||
case SE_TriggerMeleeThreshold:
|
||||
spellbonuses.TriggerMeleeThreshold = false;
|
||||
|
||||
+3091
-5714
File diff suppressed because it is too large
Load Diff
+9
-3
@@ -60,6 +60,7 @@ enum SpellTypeIndex {
|
||||
};
|
||||
|
||||
class Bot : public NPC {
|
||||
friend class Mob;
|
||||
public:
|
||||
// Class enums
|
||||
enum BotfocusType { //focus types
|
||||
@@ -154,7 +155,7 @@ public:
|
||||
// Class Methods
|
||||
bool IsValidRaceClassCombo();
|
||||
bool IsValidName();
|
||||
bool IsBotNameAvailable(std::string* errorMessage);
|
||||
static bool IsBotNameAvailable(char *botName, std::string* errorMessage);
|
||||
bool DeleteBot(std::string* errorMessage);
|
||||
void Spawn(Client* botCharacterOwner, std::string* errorMessage);
|
||||
virtual void SetLevel(uint8 in_level, bool command = false);
|
||||
@@ -190,7 +191,9 @@ public:
|
||||
bool CanDoSpecialAttack(Mob *other);
|
||||
virtual int32 CheckAggroAmount(uint16 spellid);
|
||||
virtual void CalcBonuses();
|
||||
void CalcItemBonuses();
|
||||
void CalcItemBonuses(StatBonuses* newbon);
|
||||
void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false);
|
||||
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
|
||||
virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr);
|
||||
virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther);
|
||||
inline virtual bool IsPet() { return false; }
|
||||
@@ -310,7 +313,7 @@ public:
|
||||
virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration);
|
||||
virtual float GetAOERange(uint16 spell_id);
|
||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
|
||||
virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0);
|
||||
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr);
|
||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
|
||||
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
||||
@@ -464,6 +467,7 @@ public:
|
||||
uint32 GetHealRotationNextHealTime() { return _healRotationNextHeal; }
|
||||
uint32 GetHealRotationTimer () { return _healRotationTimer; }
|
||||
bool GetBardUseOutOfCombatSongs() { return _bardUseOutOfCombatSongs;}
|
||||
bool GetShowHelm() { return _showhelm; }
|
||||
inline virtual int32 GetAC() const { return AC; }
|
||||
inline virtual int32 GetSTR() const { return STR; }
|
||||
inline virtual int32 GetSTA() const { return STA; }
|
||||
@@ -547,6 +551,7 @@ public:
|
||||
void SetHealRotationTimer( uint32 timer ) { _healRotationTimer = timer; }
|
||||
void SetNumHealRotationMembers( uint8 numMembers ) { _numHealRotationMembers = numMembers; }
|
||||
void SetBardUseOutOfCombatSongs(bool useOutOfCombatSongs) { _bardUseOutOfCombatSongs = useOutOfCombatSongs;}
|
||||
void SetShowHelm(bool showhelm) { _showhelm = showhelm; }
|
||||
|
||||
// Class Destructors
|
||||
virtual ~Bot();
|
||||
@@ -619,6 +624,7 @@ private:
|
||||
std::map<uint32, BotAA> botAAs;
|
||||
InspectMessage_Struct _botInspectMessage;
|
||||
bool _bardUseOutOfCombatSongs;
|
||||
bool _showhelm;
|
||||
|
||||
// Private "base stats" Members
|
||||
int32 _baseMR;
|
||||
|
||||
+84
-27
@@ -116,7 +116,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
),
|
||||
//these must be listed in the order they appear in client.h
|
||||
position_timer(250),
|
||||
hpupdate_timer(1800),
|
||||
hpupdate_timer(2000),
|
||||
camp_timer(29000),
|
||||
process_timer(100),
|
||||
stamina_timer(40000),
|
||||
@@ -208,6 +208,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
npclevel = 0;
|
||||
pQueuedSaveWorkID = 0;
|
||||
position_timer_counter = 0;
|
||||
position_update_same_count = 0;
|
||||
fishing_timer.Disable();
|
||||
shield_timer.Disable();
|
||||
dead_timer.Disable();
|
||||
@@ -549,17 +550,22 @@ bool Client::SaveAA(){
|
||||
}
|
||||
}
|
||||
m_pp.aapoints_spent = spentpoints + m_epp.expended_aa;
|
||||
int highest = 0;
|
||||
for (int a = 0; a < MAX_PP_AA_ARRAY; a++) {
|
||||
if (aa[a]->AA > 0 && aa[a]->value){
|
||||
if (aa[a]->AA > 0) { // those with value 0 will be cleaned up on next load
|
||||
if (first_entry != 1){
|
||||
rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, slot, aa_id, aa_value)"
|
||||
" VALUES (%u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value);
|
||||
rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, slot, aa_id, aa_value, charges)"
|
||||
" VALUES (%u, %u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value, aa[a]->charges);
|
||||
first_entry = 1;
|
||||
} else {
|
||||
rquery = rquery + StringFormat(", (%u, %u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value, aa[a]->charges);
|
||||
}
|
||||
rquery = rquery + StringFormat(", (%u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value);
|
||||
highest = a;
|
||||
}
|
||||
}
|
||||
auto results = database.QueryDatabase(rquery);
|
||||
/* This is another part of the hack to clean up holes left by expendable AAs */
|
||||
rquery = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u AND `slot` > %d", character_id, highest);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1051,12 +1057,12 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
if(quest_manager.ProximitySayInUse())
|
||||
entity_list.ProcessProximitySay(message, this, language);
|
||||
|
||||
if (GetTarget() != 0 && GetTarget()->IsNPC()) {
|
||||
if (GetTarget() != 0 && GetTarget()->IsNPC() &&
|
||||
!IsInvisible(GetTarget())) {
|
||||
if(!GetTarget()->CastToNPC()->IsEngaged()) {
|
||||
CheckLDoNHail(GetTarget());
|
||||
CheckEmoteHail(GetTarget(), message);
|
||||
|
||||
|
||||
if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= 200) {
|
||||
NPC *tar = GetTarget()->CastToNPC();
|
||||
parse->EventNPC(EVENT_SAY, tar->CastToNPC(), this, message, language);
|
||||
@@ -2540,12 +2546,12 @@ void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32
|
||||
|
||||
bool Client::BindWound(Mob* bindmob, bool start, bool fail){
|
||||
EQApplicationPacket* outapp = 0;
|
||||
if(!fail)
|
||||
if(!fail)
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_Bind_Wound, sizeof(BindWound_Struct));
|
||||
BindWound_Struct* bind_out = (BindWound_Struct*) outapp->pBuffer;
|
||||
// Start bind
|
||||
if(!bindwound_timer.Enabled())
|
||||
if(!bindwound_timer.Enabled())
|
||||
{
|
||||
//make sure we actually have a bandage... and consume it.
|
||||
int16 bslot = m_inv.HasItemByUse(ItemTypeBandage, 1, invWhereWorn|invWherePersonal);
|
||||
@@ -2592,9 +2598,9 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){
|
||||
; // Binding self
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bindwound_timer.Check()) // Did the timer finish?
|
||||
{
|
||||
{
|
||||
// finish bind
|
||||
// disable complete timer
|
||||
bindwound_timer.Disable();
|
||||
@@ -4991,7 +4997,7 @@ void Client::SetShadowStepExemption(bool v)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
printf("%s %i moving too fast! moved: %.2f in %ims, speed %.2f\n", __FILE__, __LINE__,
|
||||
@@ -5048,7 +5054,7 @@ void Client::SetKnockBackExemption(bool v)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
|
||||
@@ -5105,7 +5111,7 @@ void Client::SetPortExemption(bool v)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
|
||||
@@ -5709,8 +5715,8 @@ void Client::ProcessInspectRequest(Client* requestee, Client* requester) {
|
||||
else if (inst && inst->GetOrnamentationIcon())
|
||||
{
|
||||
insr->itemicons[L] = inst->GetOrnamentationIcon();
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
insr->itemicons[L] = item->Icon;
|
||||
}
|
||||
@@ -7491,6 +7497,10 @@ void Client::GarbleMessage(char *message, uint8 variance)
|
||||
const char delimiter = 0x12;
|
||||
int delimiter_count = 0;
|
||||
|
||||
// Don't garble # commands
|
||||
if (message[0] == '#')
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < strlen(message); i++) {
|
||||
// Client expects hex values inside of a text link body
|
||||
if (message[i] == delimiter) {
|
||||
@@ -7500,7 +7510,7 @@ void Client::GarbleMessage(char *message, uint8 variance)
|
||||
}
|
||||
|
||||
uint8 chance = (uint8)zone->random.Int(0, 115); // variation just over worst possible scrambling
|
||||
if (isalpha(message[i]) && (chance <= variance)) {
|
||||
if (isalpha((unsigned char)message[i]) && (chance <= variance)) {
|
||||
uint8 rand_char = (uint8)zone->random.Int(0,51); // choose a random character from the alpha list
|
||||
message[i] = alpha_list[rand_char];
|
||||
}
|
||||
@@ -7584,7 +7594,7 @@ FACTION_VALUE Client::GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_ra
|
||||
}
|
||||
|
||||
//Sets the characters faction standing with the specified NPC.
|
||||
void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity)
|
||||
void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity, bool quest)
|
||||
{
|
||||
int32 faction_id[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
int32 npc_value[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
@@ -7608,9 +7618,18 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui
|
||||
// Find out starting faction for this faction
|
||||
// It needs to be used to adj max and min personal
|
||||
// The range is still the same, 1200-3000(4200), but adjusted for base
|
||||
database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(),
|
||||
database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(),
|
||||
faction_id[i]);
|
||||
|
||||
if (quest)
|
||||
{
|
||||
//The ole switcheroo
|
||||
if (npc_value[i] > 0)
|
||||
npc_value[i] = -abs(npc_value[i]);
|
||||
else if (npc_value[i] < 0)
|
||||
npc_value[i] = abs(npc_value[i]);
|
||||
}
|
||||
|
||||
// Adjust the amount you can go up or down so the resulting range
|
||||
// is PERSONAL_MAX - PERSONAL_MIN
|
||||
//
|
||||
@@ -7649,7 +7668,7 @@ void Client::SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class
|
||||
// Find out starting faction for this faction
|
||||
// It needs to be used to adj max and min personal
|
||||
// The range is still the same, 1200-3000(4200), but adjusted for base
|
||||
database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(),
|
||||
database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(),
|
||||
faction_id);
|
||||
|
||||
// Adjust the amount you can go up or down so the resulting range
|
||||
@@ -7835,14 +7854,14 @@ void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_
|
||||
char name[50];
|
||||
int32 faction_value;
|
||||
|
||||
// If we're dropping from MAX or raising from MIN or repairing,
|
||||
// If we're dropping from MAX or raising from MIN or repairing,
|
||||
// we should base the message on the new updated value so we don't show
|
||||
// a min MAX message
|
||||
//
|
||||
// If we're changing any other place, we use the value before the
|
||||
// hit. For example, if we go from 1199 to 1200 which is the MAX
|
||||
// we still want to say faction got better this time around.
|
||||
|
||||
|
||||
if ( (faction_before_hit >= this_faction_max) ||
|
||||
(faction_before_hit <= this_faction_min))
|
||||
faction_value = totalvalue;
|
||||
@@ -8378,10 +8397,10 @@ std::string Client::TextLink::GenerateLink()
|
||||
m_Link.clear();
|
||||
m_LinkBody.clear();
|
||||
m_LinkText.clear();
|
||||
|
||||
|
||||
generate_body();
|
||||
generate_text();
|
||||
|
||||
|
||||
if ((m_LinkBody.length() == EmuConstants::TEXT_LINK_BODY_LENGTH) && (m_LinkText.length() > 0)) {
|
||||
m_Link.push_back(0x12);
|
||||
m_Link.append(m_LinkBody);
|
||||
@@ -8420,7 +8439,7 @@ void Client::TextLink::generate_body()
|
||||
{
|
||||
/*
|
||||
Current server mask: EQClientRoF2
|
||||
|
||||
|
||||
RoF2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X" (56)
|
||||
RoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (55)
|
||||
SoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (50)
|
||||
@@ -8428,7 +8447,6 @@ void Client::TextLink::generate_body()
|
||||
*/
|
||||
|
||||
memset(&m_LinkBodyStruct, 0, sizeof(TextLinkBody_Struct));
|
||||
|
||||
const ItemData* item_data = nullptr;
|
||||
|
||||
switch (m_LinkType) {
|
||||
@@ -8475,7 +8493,7 @@ void Client::TextLink::generate_body()
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (m_ProxyItemID != NOT_USED) {
|
||||
m_LinkBodyStruct.item_id = m_ProxyItemID;
|
||||
}
|
||||
@@ -8580,3 +8598,42 @@ bool Client::TextLink::GenerateLinkBody(std::string& textLinkBody, const TextLin
|
||||
if (textLinkBody.length() != EmuConstants::TEXT_LINK_BODY_LENGTH) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction) {
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct));
|
||||
memset(outapp->pBuffer, 0, sizeof(outapp->pBuffer));
|
||||
QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer;
|
||||
|
||||
qr->mob_id = target->GetID(); // Entity ID for the from mob name
|
||||
qr->target_id = GetID(); // The Client ID (this)
|
||||
qr->copper = copper;
|
||||
qr->silver = silver;
|
||||
qr->gold = gold;
|
||||
qr->platinum = platinum;
|
||||
qr->item_id = itemid;
|
||||
qr->exp_reward = exp;
|
||||
|
||||
if (copper > 0 || silver > 0 || gold > 0 || platinum > 0)
|
||||
AddMoneyToPP(copper, silver, gold, platinum, false);
|
||||
|
||||
if (itemid > 0)
|
||||
SummonItem(itemid, 0, 0, 0, 0, 0, 0, false, MainPowerSource);
|
||||
|
||||
if (faction)
|
||||
{
|
||||
if (target->IsNPC())
|
||||
{
|
||||
int32 nfl_id = target->CastToNPC()->GetNPCFactionID();
|
||||
SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true);
|
||||
qr->faction = target->CastToNPC()->GetPrimaryFaction();
|
||||
qr->faction_mod = 1; // Too lazy to get real value, not sure if this is even used by client anyhow.
|
||||
}
|
||||
}
|
||||
|
||||
if (exp > 0)
|
||||
AddEXP(exp);
|
||||
|
||||
QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
+10
-1
@@ -559,6 +559,7 @@ public:
|
||||
void SendCrystalCounts();
|
||||
|
||||
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
|
||||
uint32 CalcEXP(uint8 conlevel = 0xFF);
|
||||
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false);
|
||||
void AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0);
|
||||
void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp);
|
||||
@@ -613,7 +614,7 @@ public:
|
||||
void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max);
|
||||
|
||||
void UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max);
|
||||
void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity);
|
||||
void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity, bool quest = false);
|
||||
void SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp);
|
||||
int32 GetRawItemAC();
|
||||
uint16 GetCombinedAC_TEST();
|
||||
@@ -930,6 +931,7 @@ public:
|
||||
bool DecreaseByID(uint32 type, uint8 amt);
|
||||
uint8 SlotConvert2(uint8 slot); //Maybe not needed.
|
||||
void Escape(); //AA Escape
|
||||
void DisenchantSummonedBags(bool client_update = true);
|
||||
void RemoveNoRent(bool client_update = true);
|
||||
void RemoveDuplicateLore(bool client_update = true);
|
||||
void MoveSlotNotAllowed(bool client_update = true);
|
||||
@@ -1154,6 +1156,7 @@ public:
|
||||
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
|
||||
void DragCorpses();
|
||||
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
|
||||
inline void ResetPositionTimer() { position_timer_counter = 0; }
|
||||
void SendAltCurrencies();
|
||||
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
|
||||
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
|
||||
@@ -1279,6 +1282,9 @@ public:
|
||||
virtual int32 Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
|
||||
int32 GetMeleeDamage(Mob* other, bool GetMinDamage = false);
|
||||
|
||||
void QuestReward(Mob* target, uint32 copper = 0, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0, uint32 itemid = 0, uint32 exp = 0, bool faction = false);
|
||||
|
||||
void ResetHPUpdateTimer() { hpupdate_timer.Start(); }
|
||||
protected:
|
||||
friend class Mob;
|
||||
void CalcItemBonuses(StatBonuses* newbon);
|
||||
@@ -1466,6 +1472,9 @@ private:
|
||||
Timer position_timer;
|
||||
uint8 position_timer_counter;
|
||||
|
||||
// this is used to try to cut back on position update reflections
|
||||
int position_update_same_count;
|
||||
|
||||
PTimerList p_timers; //persistent timers
|
||||
Timer hpupdate_timer;
|
||||
Timer camp_timer;
|
||||
|
||||
+72
-86
@@ -1974,101 +1974,87 @@ int32 Client::CalcATK()
|
||||
|
||||
uint32 Mob::GetInstrumentMod(uint16 spell_id) const
|
||||
{
|
||||
if (GetClass() != BARD) {
|
||||
if (GetClass() != BARD || spells[spell_id].IsDisciplineBuff) // Puretone is Singing but doesn't get any mod
|
||||
return 10;
|
||||
}
|
||||
|
||||
uint32 effectmod = 10;
|
||||
int effectmodcap = RuleI(Character, BaseInstrumentSoftCap);
|
||||
//this should never use spell modifiers...
|
||||
//if a spell grants better modifers, they are copied into the item mods
|
||||
//because the spells are supposed to act just like having the intrument.
|
||||
//item mods are in 10ths of percent increases
|
||||
// this should never use spell modifiers...
|
||||
// if a spell grants better modifers, they are copied into the item mods
|
||||
// because the spells are supposed to act just like having the intrument.
|
||||
// item mods are in 10ths of percent increases
|
||||
// clickies (Symphony of Battle) that have a song skill don't get AA bonus for some reason
|
||||
// but clickies that are songs (selo's on Composers Greaves) do get AA mod as well
|
||||
switch (spells[spell_id].skill) {
|
||||
case SkillPercussionInstruments:
|
||||
if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (GetSkill(SkillPercussionInstruments) == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.percussionMod > spellbonuses.percussionMod) {
|
||||
effectmod = itembonuses.percussionMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.percussionMod;
|
||||
}
|
||||
effectmod += aabonuses.percussionMod;
|
||||
break;
|
||||
case SkillStringedInstruments:
|
||||
if (itembonuses.stringedMod == 0 && spellbonuses.stringedMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (GetSkill(SkillStringedInstruments) == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.stringedMod > spellbonuses.stringedMod) {
|
||||
effectmod = itembonuses.stringedMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.stringedMod;
|
||||
}
|
||||
effectmod += aabonuses.stringedMod;
|
||||
break;
|
||||
case SkillWindInstruments:
|
||||
if (itembonuses.windMod == 0 && spellbonuses.windMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (GetSkill(SkillWindInstruments) == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.windMod > spellbonuses.windMod) {
|
||||
effectmod = itembonuses.windMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.windMod;
|
||||
}
|
||||
effectmod += aabonuses.windMod;
|
||||
break;
|
||||
case SkillBrassInstruments:
|
||||
if (itembonuses.brassMod == 0 && spellbonuses.brassMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (GetSkill(SkillBrassInstruments) == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.brassMod > spellbonuses.brassMod) {
|
||||
effectmod = itembonuses.brassMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.brassMod;
|
||||
}
|
||||
effectmod += aabonuses.brassMod;
|
||||
break;
|
||||
case SkillSinging:
|
||||
if (itembonuses.singingMod == 0 && spellbonuses.singingMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.singingMod > spellbonuses.singingMod) {
|
||||
effectmod = itembonuses.singingMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.singingMod;
|
||||
}
|
||||
effectmod += aabonuses.singingMod + spellbonuses.Amplification;
|
||||
break;
|
||||
default:
|
||||
case SkillPercussionInstruments:
|
||||
if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0)
|
||||
effectmod = 10;
|
||||
break;
|
||||
else if (GetSkill(SkillPercussionInstruments) == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.percussionMod > spellbonuses.percussionMod)
|
||||
effectmod = itembonuses.percussionMod;
|
||||
else
|
||||
effectmod = spellbonuses.percussionMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.percussionMod;
|
||||
break;
|
||||
case SkillStringedInstruments:
|
||||
if (itembonuses.stringedMod == 0 && spellbonuses.stringedMod == 0)
|
||||
effectmod = 10;
|
||||
else if (GetSkill(SkillStringedInstruments) == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.stringedMod > spellbonuses.stringedMod)
|
||||
effectmod = itembonuses.stringedMod;
|
||||
else
|
||||
effectmod = spellbonuses.stringedMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.stringedMod;
|
||||
break;
|
||||
case SkillWindInstruments:
|
||||
if (itembonuses.windMod == 0 && spellbonuses.windMod == 0)
|
||||
effectmod = 10;
|
||||
else if (GetSkill(SkillWindInstruments) == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.windMod > spellbonuses.windMod)
|
||||
effectmod = itembonuses.windMod;
|
||||
else
|
||||
effectmod = spellbonuses.windMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.windMod;
|
||||
break;
|
||||
case SkillBrassInstruments:
|
||||
if (itembonuses.brassMod == 0 && spellbonuses.brassMod == 0)
|
||||
effectmod = 10;
|
||||
else if (GetSkill(SkillBrassInstruments) == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.brassMod > spellbonuses.brassMod)
|
||||
effectmod = itembonuses.brassMod;
|
||||
else
|
||||
effectmod = spellbonuses.brassMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.brassMod;
|
||||
break;
|
||||
case SkillSinging:
|
||||
if (itembonuses.singingMod == 0 && spellbonuses.singingMod == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.singingMod > spellbonuses.singingMod)
|
||||
effectmod = itembonuses.singingMod;
|
||||
else
|
||||
effectmod = spellbonuses.singingMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.singingMod + spellbonuses.Amplification;
|
||||
break;
|
||||
default:
|
||||
effectmod = 10;
|
||||
return effectmod;
|
||||
}
|
||||
effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap;
|
||||
if (effectmod < 10) {
|
||||
if (effectmod < 10)
|
||||
effectmod = 10;
|
||||
}
|
||||
if (effectmod > effectmodcap) {
|
||||
if (effectmod > effectmodcap)
|
||||
effectmod = effectmodcap;
|
||||
}
|
||||
Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n",
|
||||
GetName(), spell_id, effectmod, effectmodcap);
|
||||
Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n", GetName(), spell_id,
|
||||
effectmod, effectmodcap);
|
||||
return effectmod;
|
||||
}
|
||||
|
||||
|
||||
+84
-25
@@ -306,6 +306,8 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_PetitionRefresh] = &Client::Handle_OP_PetitionRefresh;
|
||||
ConnectedOpcodes[OP_PetitionResolve] = &Client::Handle_OP_PetitionResolve;
|
||||
ConnectedOpcodes[OP_PetitionUnCheckout] = &Client::Handle_OP_PetitionUnCheckout;
|
||||
ConnectedOpcodes[OP_PlayerStateAdd] = &Client::Handle_OP_PlayerStateAdd;
|
||||
ConnectedOpcodes[OP_PlayerStateRemove] = &Client::Handle_OP_PlayerStateRemove;
|
||||
ConnectedOpcodes[OP_PickPocket] = &Client::Handle_OP_PickPocket;
|
||||
ConnectedOpcodes[OP_PopupResponse] = &Client::Handle_OP_PopupResponse;
|
||||
ConnectedOpcodes[OP_PotionBelt] = &Client::Handle_OP_PotionBelt;
|
||||
@@ -703,7 +705,7 @@ void Client::CompleteConnect()
|
||||
case SE_AddMeleeProc:
|
||||
case SE_WeaponProc:
|
||||
{
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid, buffs[j1].casterlevel);
|
||||
break;
|
||||
}
|
||||
case SE_DefensiveProc:
|
||||
@@ -1444,22 +1446,32 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; }
|
||||
|
||||
/* Initialize AA's : Move to function eventually */
|
||||
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ aa[a] = &m_pp.aa_array[a]; }
|
||||
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++)
|
||||
aa[a] = &m_pp.aa_array[a];
|
||||
query = StringFormat(
|
||||
"SELECT "
|
||||
"slot, "
|
||||
"aa_id, "
|
||||
"aa_value "
|
||||
"aa_value, "
|
||||
"charges "
|
||||
"FROM "
|
||||
"`character_alternate_abilities` "
|
||||
"WHERE `id` = %u ORDER BY `slot`", this->CharacterID());
|
||||
results = database.QueryDatabase(query); i = 0;
|
||||
int offset = 0; // offset to fix the hole from expendables
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]);
|
||||
i = atoi(row[0]) - offset;
|
||||
m_pp.aa_array[i].AA = atoi(row[1]);
|
||||
m_pp.aa_array[i].value = atoi(row[2]);
|
||||
aa[i]->AA = atoi(row[1]);
|
||||
aa[i]->value = atoi(row[2]);
|
||||
m_pp.aa_array[i].charges = atoi(row[3]);
|
||||
/* A used expendable could cause there to be a "hole" in the array, this is very bad. Bad things like keeping your expendable after use.
|
||||
We could do a few things, one of them being reshuffling when the hole is created or defer the fixing until a later point, like during load!
|
||||
Or just never making a hole in the array and just have hacks every where. Fixing the hole at load really just keeps 1 hack in Client::SendAATable
|
||||
and keeping this offset that will cause the next AA to be pushed back over the hole. We also need to clean up on save so we don't have multiple
|
||||
entries for a single AA.
|
||||
*/
|
||||
if (m_pp.aa_array[i].value == 0)
|
||||
offset++;
|
||||
}
|
||||
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){
|
||||
uint32 id = aa[a]->AA;
|
||||
@@ -1498,7 +1510,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
for (int i = 0; i < max_slots; i++) {
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
m_pp.buffs[i].spellid = buffs[i].spellid;
|
||||
m_pp.buffs[i].bard_modifier = 10;
|
||||
m_pp.buffs[i].bard_modifier = buffs[i].instrument_mod;
|
||||
m_pp.buffs[i].slotid = 2;
|
||||
m_pp.buffs[i].player_id = 0x2211;
|
||||
m_pp.buffs[i].level = buffs[i].casterlevel;
|
||||
@@ -1707,7 +1719,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
/* Time of Day packet */
|
||||
outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct));
|
||||
TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer;
|
||||
zone->zone_time.getEQTimeOfDay(time(0), tod);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(time(0), tod);
|
||||
outapp->priority = 6;
|
||||
FastQueuePacket(&outapp);
|
||||
|
||||
@@ -4129,7 +4141,7 @@ void Client::Handle_OP_ClickObject(const EQApplicationPacket *app)
|
||||
char buf[10];
|
||||
snprintf(buf, 9, "%u", click_object->drop_id);
|
||||
buf[9] = '\0';
|
||||
parse->EventPlayer(EVENT_CLICK_OBJECT, this, buf, 0, &args);
|
||||
parse->EventPlayer(EVENT_CLICK_OBJECT, this, buf, GetID(), &args);
|
||||
}
|
||||
|
||||
// Observed in RoF after OP_ClickObjectAction:
|
||||
@@ -4267,7 +4279,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 0)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
|
||||
@@ -4335,7 +4347,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
|
||||
if((cur_time - m_TimeSinceLastPositionCheck) > 2500)
|
||||
{
|
||||
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
|
||||
float runs = GetRunspeed();
|
||||
int runs = GetRunspeed();
|
||||
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
|
||||
{
|
||||
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
|
||||
@@ -4448,9 +4460,20 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
|
||||
|
||||
// Outgoing client packet
|
||||
float tmpheading = EQ19toFloat(ppu->heading);
|
||||
/* The clients send an update at best every 1.3 seconds
|
||||
* We want to avoid reflecting these updates to other clients as much as possible
|
||||
* The client also sends an update every 280 ms while turning, if we prevent
|
||||
* sending these by checking if the location is the same too aggressively, clients end up spinning
|
||||
* so keep a count of how many packets are the same within a tolerance and stop when we get there */
|
||||
|
||||
if (!FCMP(ppu->y_pos, m_Position.y) || !FCMP(ppu->x_pos, m_Position.x) || !FCMP(tmpheading, m_Position.w) || ppu->animation != animation)
|
||||
bool pos_same = FCMP(ppu->y_pos, m_Position.y) && FCMP(ppu->x_pos, m_Position.x) && FCMP(tmpheading, m_Position.w) && ppu->animation == animation;
|
||||
if (!pos_same || (pos_same && position_update_same_count < 6))
|
||||
{
|
||||
if (pos_same)
|
||||
position_update_same_count++;
|
||||
else
|
||||
position_update_same_count = 0;
|
||||
|
||||
m_Position.x = ppu->x_pos;
|
||||
m_Position.y = ppu->y_pos;
|
||||
m_Position.z = ppu->z_pos;
|
||||
@@ -6355,15 +6378,25 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
|
||||
Bot::ProcessBotGroupDisband(this, std::string());
|
||||
}
|
||||
else {
|
||||
Mob* tempMember = entity_list.GetMob(gd->name2);
|
||||
if (tempMember) {
|
||||
if (tempMember->IsBot())
|
||||
Bot::ProcessBotGroupDisband(this, std::string(tempMember->GetCleanName()));
|
||||
Mob* tempMember = entity_list.GetMob(gd->name1); //Name1 is the target you are disbanding
|
||||
if (tempMember && tempMember->IsBot()) {
|
||||
tempMember->CastToBot()->RemoveBotFromGroup(tempMember->CastToBot(), group);
|
||||
if (LFP)
|
||||
{
|
||||
// If we are looking for players, update to show we are on our own now.
|
||||
UpdateLFP();
|
||||
}
|
||||
return; //No need to continue from here we were removing a bot from party
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group = GetGroup();
|
||||
if (!group) //We must recheck this here.. incase the final bot disbanded the party..otherwise we crash
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (group->GroupCount() < 3)
|
||||
{
|
||||
group->DisbandGroup();
|
||||
@@ -9705,6 +9738,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
char val1[20] = { 0 };
|
||||
PetCommand_Struct* pet = (PetCommand_Struct*)app->pBuffer;
|
||||
Mob* mypet = this->GetPet();
|
||||
Mob *target = entity_list.GetMob(pet->target);
|
||||
|
||||
if (!mypet || pet->command == PET_LEADER)
|
||||
{
|
||||
@@ -9752,22 +9786,22 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
switch (PetCommand)
|
||||
{
|
||||
case PET_ATTACK: {
|
||||
if (!GetTarget())
|
||||
if (!target)
|
||||
break;
|
||||
if (GetTarget()->IsMezzed()) {
|
||||
Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), GetTarget()->GetCleanName());
|
||||
if (target->IsMezzed()) {
|
||||
Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), target->GetCleanName());
|
||||
break;
|
||||
}
|
||||
if (mypet->IsFeared())
|
||||
break; //prevent pet from attacking stuff while feared
|
||||
|
||||
if (!mypet->IsAttackAllowed(GetTarget())) {
|
||||
if (!mypet->IsAttackAllowed(target)) {
|
||||
mypet->Say_StringID(NOT_LEGAL_TARGET);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) {
|
||||
if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
|
||||
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.
|
||||
@@ -9775,12 +9809,12 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
mypet->SetPetOrder(SPO_Follow);
|
||||
}
|
||||
else {
|
||||
mypet->SetTarget(GetTarget());
|
||||
mypet->SetTarget(target);
|
||||
}
|
||||
}
|
||||
zone->AddAggroMob();
|
||||
mypet->AddToHateList(GetTarget(), 1);
|
||||
Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName());
|
||||
mypet->AddToHateList(target, 1);
|
||||
Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), target->GetCleanName());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -10275,6 +10309,31 @@ void Client::Handle_OP_PetitionUnCheckout(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_PlayerStateAdd(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(PlayerState_Struct)) {
|
||||
std::cout << "Wrong size: OP_PlayerStateAdd, size=" << app->size << ", expected " << sizeof(PlayerState_Struct) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerState_Struct *ps = (PlayerState_Struct *)app->pBuffer;
|
||||
AddPlayerState(ps->state);
|
||||
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_PlayerStateRemove(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(PlayerState_Struct)) {
|
||||
std::cout << "Wrong size: OP_PlayerStateRemove, size=" << app->size << ", expected " << sizeof(PlayerState_Struct) << std::endl;
|
||||
return;
|
||||
}
|
||||
PlayerState_Struct *ps = (PlayerState_Struct *)app->pBuffer;
|
||||
RemovePlayerState(ps->state);
|
||||
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_PickPocket(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(PickPocket_Struct))
|
||||
@@ -12745,7 +12804,7 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app)
|
||||
inspect_buffs = group->GetLeadershipAA(groupAAInspectBuffs);
|
||||
}
|
||||
}
|
||||
if (nt == this || inspect_buffs || (nt->IsClient() && !nt->CastToClient()->GetPVP()) ||
|
||||
if (GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs) || nt == this || inspect_buffs || (nt->IsClient() && !nt->CastToClient()->GetPVP()) ||
|
||||
(nt->IsPet() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()) ||
|
||||
(nt->IsMerc() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()))
|
||||
nt->SendBuffsToClient(this);
|
||||
|
||||
@@ -218,6 +218,8 @@
|
||||
void Handle_OP_PetitionRefresh(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionResolve(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionUnCheckout(const EQApplicationPacket *app);
|
||||
void Handle_OP_PlayerStateAdd(const EQApplicationPacket *app);
|
||||
void Handle_OP_PlayerStateRemove(const EQApplicationPacket *app);
|
||||
void Handle_OP_PickPocket(const EQApplicationPacket *app);
|
||||
void Handle_OP_PopupResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_PotionBelt(const EQApplicationPacket *app);
|
||||
|
||||
@@ -129,7 +129,9 @@ bool Client::Process() {
|
||||
if(IsTracking() && (GetClientVersion() >= ClientVersion::SoD) && TrackingTimer.Check())
|
||||
DoTracking();
|
||||
|
||||
if(hpupdate_timer.Check())
|
||||
// SendHPUpdate calls hpupdate_timer.Start so it can delay this timer, so lets not reset with the check
|
||||
// since the function will anyways
|
||||
if(hpupdate_timer.Check(false))
|
||||
SendHPUpdate();
|
||||
|
||||
if(mana_timer.Check())
|
||||
@@ -197,10 +199,8 @@ bool Client::Process() {
|
||||
instalog = true;
|
||||
}
|
||||
|
||||
if (IsStunned() && stunned_timer.Check()) {
|
||||
this->stunned = false;
|
||||
this->stunned_timer.Disable();
|
||||
}
|
||||
if (IsStunned() && stunned_timer.Check())
|
||||
Mob::UnStun();
|
||||
|
||||
if(!m_CheatDetectMoved)
|
||||
{
|
||||
@@ -262,7 +262,7 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
if(light_update_timer.Check()) {
|
||||
|
||||
|
||||
UpdateEquipmentLight();
|
||||
if(UpdateActiveLight()) {
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
@@ -562,7 +562,7 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
ProjectileAttack();
|
||||
|
||||
|
||||
if(spellbonuses.GravityEffect == 1) {
|
||||
if(gravity_timer.Check())
|
||||
DoGravityEffect();
|
||||
@@ -793,7 +793,7 @@ void Client::OnDisconnect(bool hard_disconnect) {
|
||||
Mob *Other = trade->With();
|
||||
if(Other)
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client disconnected during a trade. Returning their items.");
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client disconnected during a trade. Returning their items.");
|
||||
FinishTrade(this);
|
||||
|
||||
if(Other->IsClient())
|
||||
|
||||
+27
-27
@@ -1369,7 +1369,7 @@ void command_date(Client *c, const Seperator *sep)
|
||||
else {
|
||||
int h=0, m=0;
|
||||
TimeOfDay_Struct eqTime;
|
||||
zone->zone_time.getEQTimeOfDay( time(0), &eqTime);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime);
|
||||
if(!sep->IsNumber(4))
|
||||
h=eqTime.hour;
|
||||
else
|
||||
@@ -1402,7 +1402,7 @@ void command_timezone(Client *c, const Seperator *sep)
|
||||
// Update all clients with new TZ.
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct));
|
||||
TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer;
|
||||
zone->zone_time.getEQTimeOfDay(time(0), tod);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(time(0), tod);
|
||||
entity_list.QueueClients(c, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
@@ -1484,7 +1484,7 @@ void command_npcstats(Client *c, const Seperator *sep)
|
||||
c->Message(0, "Current HP: %i Max HP: %i", c->GetTarget()->GetHP(), c->GetTarget()->GetMaxHP());
|
||||
//c->Message(0, "Weapon Item Number: %s", c->GetTarget()->GetWeapNo());
|
||||
c->Message(0, "Gender: %i Size: %f Bodytype: %d", c->GetTarget()->GetGender(), c->GetTarget()->GetSize(), c->GetTarget()->GetBodyType());
|
||||
c->Message(0, "Runspeed: %f Walkspeed: %f", c->GetTarget()->GetRunspeed(), c->GetTarget()->GetWalkspeed());
|
||||
c->Message(0, "Runspeed: %i Walkspeed: %i", c->GetTarget()->GetRunspeed(), c->GetTarget()->GetWalkspeed());
|
||||
c->Message(0, "Spawn Group: %i Grid: %i", c->GetTarget()->CastToNPC()->GetSp2(), c->GetTarget()->CastToNPC()->GetGrid());
|
||||
c->Message(0, "EmoteID: %i", c->GetTarget()->CastToNPC()->GetEmoteID());
|
||||
c->GetTarget()->CastToNPC()->QueryLoot(c);
|
||||
@@ -4393,7 +4393,7 @@ void command_time(Client *c, const Seperator *sep)
|
||||
else {
|
||||
c->Message(13, "To set the Time: #time HH [MM]");
|
||||
TimeOfDay_Struct eqTime;
|
||||
zone->zone_time.getEQTimeOfDay( time(0), &eqTime);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime);
|
||||
sprintf(timeMessage,"%02d:%s%d %s (Timezone: %ih %im)",
|
||||
((eqTime.hour - 1) % 12) == 0 ? 12 : ((eqTime.hour - 1) % 12),
|
||||
(eqTime.minute < 10) ? "0" : "",
|
||||
@@ -8565,20 +8565,20 @@ void command_object(Client *c, const Seperator *sep)
|
||||
|
||||
od.object_type = atoi(row[7]);
|
||||
icon = atoi(row[8]);
|
||||
od.unknown008 = atoi(row[9]);
|
||||
od.unknown010 = atoi(row[10]);
|
||||
od.size = atoi(row[9]);
|
||||
od.solidtype = atoi(row[10]);
|
||||
od.unknown020 = atoi(row[11]);
|
||||
|
||||
switch (od.object_type) {
|
||||
case 0: // Static Object
|
||||
case staticType: // Static Object unlocked for changes
|
||||
if (od.unknown008 == 0) // Unknown08 field is optional Size parameter for static objects
|
||||
od.unknown008 = 100; // Static object default Size is 100%
|
||||
if (od.size == 0) // Unknown08 field is optional Size parameter for static objects
|
||||
od.size = 100; // Static object default Size is 100%
|
||||
|
||||
c->Message(0, "- STATIC Object (%s): id %u, x %.1f, y %.1f, z %.1f, h %.1f, model %s, "
|
||||
"size %u, solidtype %u, incline %u",
|
||||
(od.object_type == 0) ? "locked" : "unlocked", id, od.x, od.y, od.z,
|
||||
od.heading, od.object_name, od.unknown008, od.unknown010, od.unknown020);
|
||||
od.heading, od.object_name, od.size, od.solidtype, od.unknown020);
|
||||
break;
|
||||
|
||||
case OT_DROPPEDITEM: // Ground Spawn
|
||||
@@ -8636,10 +8636,10 @@ void command_object(Client *c, const Seperator *sep)
|
||||
switch (od.object_type) {
|
||||
case 0: // Static Object
|
||||
if ((sep->argnum - col) > 3) {
|
||||
od.unknown008 = atoi(sep->arg[4 + col]); // Size specified
|
||||
od.size = atoi(sep->arg[4 + col]); // Size specified
|
||||
|
||||
if ((sep->argnum - col) > 4) {
|
||||
od.unknown010 = atoi(sep->arg[5 + col]); // SolidType specified
|
||||
od.solidtype = atoi(sep->arg[5 + col]); // SolidType specified
|
||||
|
||||
if ((sep->argnum - col) > 5)
|
||||
od.unknown020 = atoi(sep->arg[6 + col]); // Incline specified
|
||||
@@ -8938,16 +8938,16 @@ void command_object(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
od.unknown008 = atoi(sep->arg[4]);
|
||||
od.size = atoi(sep->arg[4]);
|
||||
o->SetObjectData(&od);
|
||||
|
||||
if (od.unknown008 == 0) // 0 == unspecified == 100%
|
||||
od.unknown008 = 100;
|
||||
if (od.size == 0) // 0 == unspecified == 100%
|
||||
od.size = 100;
|
||||
|
||||
c->Message(0, "Static Object %u set to %u%% size. Size will take effect when you commit to the "
|
||||
"database with '#object Save', after which the object will be unchangeable until "
|
||||
"you unlock it again with '#object Edit' and zone out and back in.",
|
||||
id, od.unknown008);
|
||||
id, od.size);
|
||||
} else if (strcmp(sep->arg[3], "solidtype") == 0) {
|
||||
|
||||
if (od.object_type != staticType) {
|
||||
@@ -8962,13 +8962,13 @@ void command_object(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
od.unknown010 = atoi(sep->arg[4]);
|
||||
od.solidtype = atoi(sep->arg[4]);
|
||||
o->SetObjectData(&od);
|
||||
|
||||
c->Message(0, "Static Object %u set to SolidType %u. Change will take effect when you commit "
|
||||
"to the database with '#object Save'. Support for this property is on a "
|
||||
"per-model basis, mostly seen in smaller objects such as chests and tables.",
|
||||
id, od.unknown010);
|
||||
id, od.solidtype);
|
||||
} else if (strcmp(sep->arg[3], "icon") == 0) {
|
||||
|
||||
if ((od.object_type < 2) || (od.object_type == staticType)) {
|
||||
@@ -9255,24 +9255,24 @@ void command_object(Client *c, const Seperator *sep)
|
||||
"unknown08 = %u, unknown10 = %u, unknown20 = %u "
|
||||
"WHERE ID = %u",
|
||||
zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z,
|
||||
od.heading, od.object_name, od.object_type, icon, od.unknown008,
|
||||
od.unknown010, od.unknown020, id);
|
||||
od.heading, od.object_name, od.object_type, icon, od.size,
|
||||
od.solidtype, od.unknown020, id);
|
||||
else if (id == 0)
|
||||
query = StringFormat("INSERT INTO object "
|
||||
"(zoneid, version, xpos, ypos, zpos, heading, objectname, "
|
||||
"type, icon, unknown08, unknown10, unknown20) "
|
||||
"VALUES (%u, %u, %.1f, %.1f, %.1f, %.1f, '%s', %u, %u, %u, %u, %u)",
|
||||
zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z,
|
||||
od.heading, od.object_name, od.object_type, icon, od.unknown008,
|
||||
od.unknown010, od.unknown020);
|
||||
od.heading, od.object_name, od.object_type, icon, od.size,
|
||||
od.solidtype, od.unknown020);
|
||||
else
|
||||
query = StringFormat("INSERT INTO object "
|
||||
"(id, zoneid, version, xpos, ypos, zpos, heading, objectname, "
|
||||
"type, icon, unknown08, unknown10, unknown20) "
|
||||
"VALUES (%u, %u, %u, %.1f, %.1f, %.1f, %.1f, '%s', %u, %u, %u, %u, %u)",
|
||||
id, zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z,
|
||||
od.heading, od.object_name, od.object_type, icon, od.unknown008,
|
||||
od.unknown010, od.unknown020);
|
||||
od.heading, od.object_name, od.object_type, icon, od.size,
|
||||
od.solidtype, od.unknown020);
|
||||
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
@@ -9330,12 +9330,12 @@ void command_object(Client *c, const Seperator *sep)
|
||||
|
||||
memcpy(door.dest_zone, "NONE", 5);
|
||||
|
||||
if ((door.size = od.unknown008) == 0) // unknown08 = optional size percentage
|
||||
if ((door.size = od.size) == 0) // unknown08 = optional size percentage
|
||||
door.size = 100;
|
||||
|
||||
switch (
|
||||
door.opentype =
|
||||
od.unknown010) // unknown10 = optional request_nonsolid (0 or 1 or experimental number)
|
||||
od.solidtype) // unknown10 = optional request_nonsolid (0 or 1 or experimental number)
|
||||
{
|
||||
case 0:
|
||||
door.opentype = 31;
|
||||
@@ -9592,8 +9592,8 @@ void command_object(Client *c, const Seperator *sep)
|
||||
strn0cpy(od.object_name, row[4], sizeof(od.object_name));
|
||||
od.object_type = atoi(row[5]);
|
||||
icon = atoi(row[6]);
|
||||
od.unknown008 = atoi(row[7]);
|
||||
od.unknown010 = atoi(row[8]);
|
||||
od.size = atoi(row[7]);
|
||||
od.solidtype = atoi(row[8]);
|
||||
od.unknown020 = atoi(row[9]);
|
||||
|
||||
if (od.object_type == 0)
|
||||
|
||||
+17
-2
@@ -173,6 +173,18 @@ enum class NumHit { // Numhits type
|
||||
OffensiveSpellProcs = 11 // Offensive buff procs
|
||||
};
|
||||
|
||||
enum class PlayerState : uint32 {
|
||||
None = 0,
|
||||
Open = 1,
|
||||
WeaponSheathed = 2,
|
||||
Aggressive = 4,
|
||||
ForcedAggressive = 8,
|
||||
InstrumentEquipped = 16,
|
||||
Stunned = 32,
|
||||
PrimaryWeaponEquipped = 64,
|
||||
SecondaryWeaponEquipped = 128
|
||||
};
|
||||
|
||||
//this is our internal representation of the BUFF struct, can put whatever we want in it
|
||||
struct Buffs_Struct {
|
||||
uint16 spellid;
|
||||
@@ -190,6 +202,7 @@ struct Buffs_Struct {
|
||||
int32 caston_z;
|
||||
int32 ExtraDIChance;
|
||||
int16 RootBreakChance; //Not saved to dbase
|
||||
uint32 instrument_mod;
|
||||
bool persistant_buff;
|
||||
bool client; //True if the caster is a client
|
||||
bool UpdateClient;
|
||||
@@ -438,7 +451,7 @@ struct StatBonuses {
|
||||
int32 ShieldEquipHateMod; // Hate mod when shield equiped.
|
||||
int32 ShieldEquipDmgMod[2]; // Damage mod when shield equiped. 0 = damage modifier 1 = Unknown
|
||||
bool TriggerOnValueAmount; // Triggers off various different conditions, bool to check if client has effect.
|
||||
int8 StunBashChance; // chance to stun with bash.
|
||||
int8 StunBashChance; // chance to stun with bash.
|
||||
int8 IncreaseChanceMemwipe; // increases chance to memory wipe
|
||||
int8 CriticalMend; // chance critical monk mend
|
||||
int32 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy
|
||||
@@ -455,6 +468,7 @@ typedef struct
|
||||
uint16 spellID;
|
||||
uint16 chance;
|
||||
uint16 base_spellID;
|
||||
int level_override;
|
||||
} tProc;
|
||||
|
||||
struct Shielders_Struct {
|
||||
@@ -507,7 +521,8 @@ typedef enum {
|
||||
petOther,
|
||||
petCharmed,
|
||||
petNPCFollow,
|
||||
petTargetLock //remain active as long something is on the hatelist. Don't listen to any commands
|
||||
petTargetLock, //remain active as long something is on the hatelist. Don't listen to any commands
|
||||
petNone = 0xFF // not a pet
|
||||
} PetType;
|
||||
|
||||
typedef enum {
|
||||
|
||||
+24
-19
@@ -89,7 +89,7 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
if (IsClient() && GetClass() == WIZARD)
|
||||
ratio += RuleI(Spells, WizCritRatio); //Default is zero
|
||||
|
||||
|
||||
if (Critical){
|
||||
|
||||
value = value_BaseEffect*ratio/100;
|
||||
@@ -172,7 +172,7 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100;
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
|
||||
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
|
||||
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
|
||||
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
|
||||
int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) +
|
||||
GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
|
||||
@@ -219,11 +219,11 @@ int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_s
|
||||
total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time;
|
||||
|
||||
if (total_cast_time > 0 && total_cast_time <= 2500)
|
||||
extra_spell_amt = extra_spell_amt*25/100;
|
||||
else if (total_cast_time > 2500 && total_cast_time < 7000)
|
||||
extra_spell_amt = extra_spell_amt*(167*((total_cast_time - 1000)/1000)) / 1000;
|
||||
else
|
||||
extra_spell_amt = extra_spell_amt * total_cast_time / 7000;
|
||||
extra_spell_amt = extra_spell_amt*25/100;
|
||||
else if (total_cast_time > 2500 && total_cast_time < 7000)
|
||||
extra_spell_amt = extra_spell_amt*(167*((total_cast_time - 1000)/1000)) / 1000;
|
||||
else
|
||||
extra_spell_amt = extra_spell_amt * total_cast_time / 7000;
|
||||
|
||||
if(extra_spell_amt*2 < base_spell_dmg)
|
||||
return 0;
|
||||
@@ -281,7 +281,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
if (Critical) {
|
||||
entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
|
||||
OTHER_CRIT_HEAL, GetName(), itoa(value));
|
||||
|
||||
|
||||
if (IsClient())
|
||||
Message_StringID(MT_SpellCrits, YOU_CRIT_HEAL, itoa(value));
|
||||
}
|
||||
@@ -421,16 +421,21 @@ int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
|
||||
int tic_inc = 0;
|
||||
tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id);
|
||||
|
||||
// Only need this for clients, since the change was for bard songs, I assume we should keep non bard songs getting +1
|
||||
// However if its bard or not and is mez, charm or fear, we need to add 1 so that client is in sync
|
||||
if (IsClient() && !(IsShortDurationBuff(spell_id) && IsBardSong(spell_id)) ||
|
||||
IsFearSpell(spell_id) ||
|
||||
IsCharmSpell(spell_id) ||
|
||||
IsMezSpell(spell_id) ||
|
||||
IsBlindSpell(spell_id))
|
||||
tic_inc += 1;
|
||||
// unsure on the exact details, but bard songs that don't cost mana at some point get an extra tick, 60 for now
|
||||
// a level 53 bard reported getting 2 tics
|
||||
// bard DOTs do get this extra tick, but beneficial long bard songs don't? (invul, crescendo)
|
||||
if ((IsShortDurationBuff(spell_id) || IsDetrimentalSpell(spell_id)) && IsBardSong(spell_id) &&
|
||||
spells[spell_id].mana == 0 && GetClass() == BARD && GetLevel() > 60)
|
||||
tic_inc++;
|
||||
float focused = ((duration * increase) / 100.0f) + tic_inc;
|
||||
int ifocused = static_cast<int>(focused);
|
||||
|
||||
return (((duration * increase) / 100) + tic_inc);
|
||||
// 7.6 is rounded to 7, 8.6 is rounded to 9
|
||||
// 6 is 6, etc
|
||||
if (FCMP(focused, ifocused) || ifocused % 2) // equal or odd
|
||||
return ifocused;
|
||||
else // even and not equal round to odd
|
||||
return ifocused + 1;
|
||||
}
|
||||
|
||||
int32 Client::GetActSpellCasttime(uint16 spell_id, int32 casttime)
|
||||
@@ -771,7 +776,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
}
|
||||
} else {
|
||||
if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets)
|
||||
if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets)
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
if (!spells[spell_id].aemaxtargets)
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
@@ -859,7 +864,7 @@ void EntityList::AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool aff
|
||||
if (!center->CheckLosFN(curmob))
|
||||
continue;
|
||||
} else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies...
|
||||
// See notes in AESpell() above for more info.
|
||||
// See notes in AESpell() above for more info.
|
||||
if (caster->IsAttackAllowed(curmob, true))
|
||||
continue;
|
||||
if (caster->CheckAggro(curmob))
|
||||
|
||||
+12
-1
@@ -1072,7 +1072,7 @@ void PerlembParser::ExportZoneVariables(std::string &package_name) {
|
||||
ExportVar(package_name.c_str(), "instanceid", zone->GetInstanceID());
|
||||
ExportVar(package_name.c_str(), "instanceversion", zone->GetInstanceVersion());
|
||||
TimeOfDay_Struct eqTime;
|
||||
zone->zone_time.getEQTimeOfDay( time(0), &eqTime);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime);
|
||||
ExportVar(package_name.c_str(), "zonehour", eqTime.hour - 1);
|
||||
ExportVar(package_name.c_str(), "zonemin", eqTime.minute);
|
||||
ExportVar(package_name.c_str(), "zonetime", (eqTime.hour - 1) * 100 + eqTime.minute);
|
||||
@@ -1277,6 +1277,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
|
||||
case EVENT_PLAYER_PICKUP:{
|
||||
ExportVar(package_name.c_str(), "picked_up_id", data);
|
||||
ExportVar(package_name.c_str(), "picked_up_entity_id", extradata);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1320,6 +1321,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
ExportVar(package_name.c_str(), "itemid", objid);
|
||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||
ExportVar(package_name.c_str(), "slotid", extradata);
|
||||
ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1367,6 +1369,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
|
||||
case EVENT_CLICK_OBJECT: {
|
||||
ExportVar(package_name.c_str(), "objectid", data);
|
||||
ExportVar(package_name.c_str(), "clicker_id", extradata);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1397,6 +1400,14 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
|
||||
break;
|
||||
}
|
||||
case EVENT_DROP_ITEM: {
|
||||
ExportVar(package_name.c_str(), "quantity", iteminst->IsStackable() ? iteminst->GetCharges() : 1);
|
||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||
ExportVar(package_name.c_str(), "itemid", iteminst->GetItem()->ID);
|
||||
ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect);
|
||||
ExportVar(package_name.c_str(), "slotid", extradata);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
|
||||
+66
-5
@@ -1182,13 +1182,26 @@ XS(XS__settime);
|
||||
XS(XS__settime)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: settime(new_hour, new_min)");
|
||||
if (items < 2)
|
||||
Perl_croak(aTHX_ "Usage: settime(new_hour, new_min, [update_world = true])");
|
||||
|
||||
int new_hour = (int)SvIV(ST(0));
|
||||
int new_min = (int)SvIV(ST(1));
|
||||
if (items == 2){
|
||||
int new_hour = (int)SvIV(ST(0));
|
||||
int new_min = (int)SvIV(ST(1));
|
||||
quest_manager.settime(new_hour, new_min, true);
|
||||
}
|
||||
else if (items == 3){
|
||||
int new_hour = (int)SvIV(ST(0));
|
||||
int new_min = (int)SvIV(ST(1));
|
||||
|
||||
quest_manager.settime(new_hour, new_min);
|
||||
int update_world = (int)SvIV(ST(2));
|
||||
if (update_world == 1){
|
||||
quest_manager.settime(new_hour, new_min, true);
|
||||
}
|
||||
else{
|
||||
quest_manager.settime(new_hour, new_min, false);
|
||||
}
|
||||
}
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@@ -1917,6 +1930,52 @@ XS(XS__repopzone)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__ConnectNodeToNode);
|
||||
XS(XS__ConnectNodeToNode)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 4)
|
||||
Perl_croak(aTHX_ "Usage: ConnectNodeToNode(node1, node2, teleport, doorid)");
|
||||
|
||||
int node1 = (int)SvIV(ST(0));
|
||||
int node2 = (int)SvIV(ST(1));
|
||||
int teleport = (int)SvIV(ST(2));
|
||||
int doorid = (int)SvIV(ST(3));
|
||||
|
||||
quest_manager.ConnectNodeToNode(node1, node2, teleport, doorid);
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__AddNode);
|
||||
XS(XS__AddNode)
|
||||
{
|
||||
dXSARGS;
|
||||
//void QuestManager::AddNode(float x, float y, float z, float best_z, int32 requested_id);
|
||||
if (items < 3 || items > 5)
|
||||
Perl_croak(aTHX_ "Usage: AddNode(x, y, z, [best_z], [requested_id])");
|
||||
|
||||
int x = (int)SvIV(ST(0));
|
||||
int y = (int)SvIV(ST(1));
|
||||
int z = (int)SvIV(ST(2));
|
||||
int best_z = 0;
|
||||
int requested_id = 0;
|
||||
|
||||
if (items == 4)
|
||||
{
|
||||
best_z = (int)SvIV(ST(3));
|
||||
}
|
||||
else if (items == 5)
|
||||
{
|
||||
best_z = (int)SvIV(ST(3));
|
||||
requested_id = (int)SvIV(ST(4));
|
||||
}
|
||||
|
||||
quest_manager.AddNode(x, y, z, best_z, requested_id);
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__npcrace);
|
||||
XS(XS__npcrace)
|
||||
{
|
||||
@@ -3699,6 +3758,8 @@ EXTERN_C XS(boot_quest)
|
||||
newXS(strcpy(buf, "reloadzonestaticdata"), XS__reloadzonestaticdata, file);
|
||||
newXS(strcpy(buf, "removetitle"), XS__removetitle, file);
|
||||
newXS(strcpy(buf, "repopzone"), XS__repopzone, file);
|
||||
newXS(strcpy(buf, "ConnectNodeToNode"), XS__ConnectNodeToNode, file);
|
||||
newXS(strcpy(buf, "AddNode"), XS__AddNode, file);
|
||||
newXS(strcpy(buf, "resettaskactivity"), XS__resettaskactivity, file);
|
||||
newXS(strcpy(buf, "respawn"), XS__respawn, file);
|
||||
newXS(strcpy(buf, "resume"), XS__resume, file);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#include "../common/races.h"
|
||||
#include "encounter.h"
|
||||
#include "entity.h"
|
||||
#include "mob.h"
|
||||
|
||||
class Zone;
|
||||
|
||||
Encounter::Encounter(const char* enc_name)
|
||||
:Mob
|
||||
(
|
||||
nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, glm::vec4(0,0,0,0), 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
)
|
||||
{
|
||||
encounter_name[0] = 0;
|
||||
strn0cpy(encounter_name, enc_name, 64);
|
||||
remove_me = false;
|
||||
}
|
||||
|
||||
Encounter::~Encounter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Encounter::Process() {
|
||||
if (remove_me) return false;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef ENCOUNTER_H
|
||||
#define ENCOUNTER_H
|
||||
|
||||
#include "mob.h"
|
||||
#include "../common/types.h"
|
||||
#include "../common/timer.h"
|
||||
|
||||
class Group;
|
||||
class Raid;
|
||||
struct ExtraAttackOptions;
|
||||
|
||||
class Encounter : public Mob
|
||||
{
|
||||
public:
|
||||
Encounter(const char* enc_name);
|
||||
~Encounter();
|
||||
|
||||
//abstract virtual function implementations required by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) { return true; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false) { return; }
|
||||
virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
ExtraAttackOptions *opts = nullptr) {
|
||||
return false;
|
||||
}
|
||||
virtual bool HasRaid() { return false; }
|
||||
virtual bool HasGroup() { return false; }
|
||||
virtual Raid* GetRaid() { return 0; }
|
||||
virtual Group* GetGroup() { return 0; }
|
||||
|
||||
bool IsEncounter() const { return true; }
|
||||
const char* GetEncounterName() const { return encounter_name; }
|
||||
|
||||
bool Process();
|
||||
virtual void Depop(bool not_used = true) { remove_me = true; }
|
||||
|
||||
|
||||
protected:
|
||||
bool remove_me;
|
||||
char encounter_name[64];
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
+92
-8
@@ -79,7 +79,7 @@ Client *Entity::CastToClient()
|
||||
}
|
||||
#ifdef _EQDEBUG
|
||||
if (!IsClient()) {
|
||||
Log.Out(Logs::General, Logs::Error, "CastToClient error (not client)");
|
||||
Log.Out(Logs::General, Logs::Error, "CastToClient error (not client)");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -173,6 +173,11 @@ Beacon *Entity::CastToBeacon()
|
||||
return static_cast<Beacon *>(this);
|
||||
}
|
||||
|
||||
Encounter *Entity::CastToEncounter()
|
||||
{
|
||||
return static_cast<Encounter *>(this);
|
||||
}
|
||||
|
||||
const Client *Entity::CastToClient() const
|
||||
{
|
||||
if (this == 0x00) {
|
||||
@@ -263,6 +268,11 @@ const Beacon* Entity::CastToBeacon() const
|
||||
return static_cast<const Beacon *>(this);
|
||||
}
|
||||
|
||||
const Encounter* Entity::CastToEncounter() const
|
||||
{
|
||||
return static_cast<const Encounter *>(this);
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
Bot *Entity::CastToBot()
|
||||
{
|
||||
@@ -533,6 +543,21 @@ void EntityList::BeaconProcess()
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::EncounterProcess()
|
||||
{
|
||||
auto it = encounter_list.begin();
|
||||
while (it != encounter_list.end()) {
|
||||
if (!it->second->Process()) {
|
||||
safe_delete(it->second);
|
||||
free_ids.push(it->first);
|
||||
it = encounter_list.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::AddGroup(Group *group)
|
||||
{
|
||||
if (group == nullptr) //this seems to be happening somehow...
|
||||
@@ -540,7 +565,7 @@ void EntityList::AddGroup(Group *group)
|
||||
|
||||
uint32 gid = worldserver.NextGroupID();
|
||||
if (gid == 0) {
|
||||
Log.Out(Logs::General, Logs::Error,
|
||||
Log.Out(Logs::General, Logs::Error,
|
||||
"Unable to get new group ID from world server. group is going to be broken.");
|
||||
return;
|
||||
}
|
||||
@@ -569,7 +594,7 @@ void EntityList::AddRaid(Raid *raid)
|
||||
|
||||
uint32 gid = worldserver.NextGroupID();
|
||||
if (gid == 0) {
|
||||
Log.Out(Logs::General, Logs::Error,
|
||||
Log.Out(Logs::General, Logs::Error,
|
||||
"Unable to get new group ID from world server. group is going to be broken.");
|
||||
return;
|
||||
}
|
||||
@@ -618,6 +643,8 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
|
||||
EQApplicationPacket *app = new EQApplicationPacket;
|
||||
npc->CreateSpawnPacket(app, npc);
|
||||
QueueClients(npc, app);
|
||||
npc->SendArmorAppearance();
|
||||
npc->SetAppearance(npc->GetGuardPointAnim(),false);
|
||||
safe_delete(app);
|
||||
} else {
|
||||
NewSpawn_Struct *ns = new NewSpawn_Struct;
|
||||
@@ -706,6 +733,12 @@ void EntityList::AddBeacon(Beacon *beacon)
|
||||
beacon_list.insert(std::pair<uint16, Beacon *>(beacon->GetID(), beacon));
|
||||
}
|
||||
|
||||
void EntityList::AddEncounter(Encounter *encounter)
|
||||
{
|
||||
encounter->SetID(GetFreeID());
|
||||
encounter_list.insert(std::pair<uint16, Encounter *>(encounter->GetID(), encounter));
|
||||
}
|
||||
|
||||
void EntityList::AddToSpawnQueue(uint16 entityid, NewSpawn_Struct **ns)
|
||||
{
|
||||
uint32 count;
|
||||
@@ -726,10 +759,23 @@ void EntityList::CheckSpawnQueue()
|
||||
EQApplicationPacket *outapp = 0;
|
||||
|
||||
iterator.Reset();
|
||||
NewSpawn_Struct *ns;
|
||||
|
||||
while(iterator.MoreElements()) {
|
||||
outapp = new EQApplicationPacket;
|
||||
Mob::CreateSpawnPacket(outapp, iterator.GetData());
|
||||
ns = iterator.GetData();
|
||||
Mob::CreateSpawnPacket(outapp, ns);
|
||||
QueueClients(0, outapp);
|
||||
auto it = npc_list.find(ns->spawn.spawnId);
|
||||
if (it == npc_list.end()) {
|
||||
// We must of despawned, hope that's the reason!
|
||||
Log.Out(Logs::General, Logs::Error, "Error in EntityList::CheckSpawnQueue: Unable to find NPC for spawnId '%u'", ns->spawn.spawnId);
|
||||
}
|
||||
else {
|
||||
NPC *pnpc = it->second;
|
||||
pnpc->SendArmorAppearance();
|
||||
pnpc->SetAppearance(pnpc->GetGuardPointAnim(), false);
|
||||
}
|
||||
safe_delete(outapp);
|
||||
iterator.RemoveCurrent();
|
||||
}
|
||||
@@ -920,6 +966,11 @@ Entity *EntityList::GetEntityBeacon(uint16 id)
|
||||
return beacon_list.count(id) ? beacon_list.at(id) : nullptr;
|
||||
}
|
||||
|
||||
Entity *EntityList::GetEntityEncounter(uint16 id)
|
||||
{
|
||||
return encounter_list.count(id) ? encounter_list.at(id) : nullptr;
|
||||
}
|
||||
|
||||
Entity *EntityList::GetID(uint16 get_id)
|
||||
{
|
||||
Entity *ent = 0;
|
||||
@@ -935,6 +986,8 @@ Entity *EntityList::GetID(uint16 get_id)
|
||||
return ent;
|
||||
else if ((ent=entity_list.GetEntityBeacon(get_id)) != 0)
|
||||
return ent;
|
||||
else if ((ent = entity_list.GetEntityEncounter(get_id)) != 0)
|
||||
return ent;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@@ -1149,19 +1202,39 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
|
||||
NewSpawn_Struct ns;
|
||||
Mob *spawn;
|
||||
uint32 maxspawns = 100;
|
||||
EQApplicationPacket *app;
|
||||
|
||||
if (maxspawns > mob_list.size())
|
||||
maxspawns = mob_list.size();
|
||||
BulkZoneSpawnPacket *bzsp = new BulkZoneSpawnPacket(client, maxspawns);
|
||||
|
||||
int32 race=-1;
|
||||
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
||||
spawn = it->second;
|
||||
if (spawn && spawn->InZone()) {
|
||||
if (spawn->IsClient() && (spawn->CastToClient()->GMHideMe(client) ||
|
||||
spawn->CastToClient()->IsHoveringForRespawn()))
|
||||
continue;
|
||||
memset(&ns, 0, sizeof(NewSpawn_Struct));
|
||||
spawn->FillSpawnStruct(&ns, client);
|
||||
bzsp->AddSpawn(&ns);
|
||||
|
||||
race = spawn->GetRace();
|
||||
|
||||
// Illusion races on PCs don't work as a mass spawn
|
||||
// But they will work as an add_spawn AFTER CLIENT_CONNECTED.
|
||||
if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) {
|
||||
app = new EQApplicationPacket;
|
||||
spawn->CreateSpawnPacket(app);
|
||||
client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
|
||||
safe_delete(app);
|
||||
}
|
||||
else {
|
||||
memset(&ns, 0, sizeof(NewSpawn_Struct));
|
||||
spawn->FillSpawnStruct(&ns, client);
|
||||
bzsp->AddSpawn(&ns);
|
||||
}
|
||||
|
||||
// Despite being sent in the OP_ZoneSpawns packet, the client
|
||||
// does not display worn armor correctly so display it.
|
||||
spawn->SendArmorAppearance(client);
|
||||
}
|
||||
}
|
||||
safe_delete(bzsp);
|
||||
@@ -1355,7 +1428,9 @@ void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *ap
|
||||
if (c != sender) {
|
||||
if (Target == sender) {
|
||||
if (inspect_buffs) { // if inspect_buffs is true we're sending a mob's buffs to those with the LAA
|
||||
if (c->IsRaidGrouped()) {
|
||||
if (c->GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs)) {
|
||||
Send = true;
|
||||
} else if (c->IsRaidGrouped()) {
|
||||
Raid *raid = c->GetRaid();
|
||||
if (!raid)
|
||||
continue;
|
||||
@@ -3389,6 +3464,15 @@ bool EntityList::IsMobInZone(Mob *who)
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
auto enc_it = encounter_list.begin();
|
||||
while (enc_it != encounter_list.end()) {
|
||||
if (enc_it->second == who) {
|
||||
return true;
|
||||
}
|
||||
++enc_it;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "position.h"
|
||||
#include "zonedump.h"
|
||||
|
||||
class Encounter;
|
||||
class Beacon;
|
||||
class Client;
|
||||
class Corpse;
|
||||
@@ -77,6 +78,7 @@ public:
|
||||
virtual bool IsDoor() const { return false; }
|
||||
virtual bool IsTrap() const { return false; }
|
||||
virtual bool IsBeacon() const { return false; }
|
||||
virtual bool IsEncounter() const { return false; }
|
||||
|
||||
virtual bool Process() { return false; }
|
||||
virtual bool Save() { return true; }
|
||||
@@ -91,6 +93,7 @@ public:
|
||||
Doors *CastToDoors();
|
||||
Trap *CastToTrap();
|
||||
Beacon *CastToBeacon();
|
||||
Encounter *CastToEncounter();
|
||||
|
||||
const Client *CastToClient() const;
|
||||
const NPC *CastToNPC() const;
|
||||
@@ -101,6 +104,7 @@ public:
|
||||
const Doors *CastToDoors() const;
|
||||
const Trap *CastToTrap() const;
|
||||
const Beacon *CastToBeacon() const;
|
||||
const Encounter *CastToEncounter() const;
|
||||
|
||||
inline const uint16& GetID() const { return id; }
|
||||
inline const time_t& GetSpawnTimeStamp() const { return spawn_timestamp; }
|
||||
@@ -203,6 +207,7 @@ public:
|
||||
void MobProcess();
|
||||
void TrapProcess();
|
||||
void BeaconProcess();
|
||||
void EncounterProcess();
|
||||
void ProcessMove(Client *c, const glm::vec3& location);
|
||||
void ProcessMove(NPC *n, float x, float y, float z);
|
||||
void AddArea(int id, int type, float min_x, float max_x, float min_y, float max_y, float min_z, float max_z);
|
||||
@@ -228,6 +233,7 @@ public:
|
||||
void AddDoor(Doors* door);
|
||||
void AddTrap(Trap* trap);
|
||||
void AddBeacon(Beacon *beacon);
|
||||
void AddEncounter(Encounter *encounter);
|
||||
void AddProximity(NPC *proximity_for);
|
||||
void Clear();
|
||||
bool RemoveMob(uint16 delete_id);
|
||||
@@ -266,6 +272,7 @@ public:
|
||||
Entity *GetEntityCorpse(uint16 id);
|
||||
Entity *GetEntityTrap(uint16 id);
|
||||
Entity *GetEntityBeacon(uint16 id);
|
||||
Entity *GetEntityEncounter(uint16 id);
|
||||
Entity *GetEntityMob(const char *name);
|
||||
Entity *GetEntityCorpse(const char *name);
|
||||
|
||||
@@ -448,6 +455,7 @@ private:
|
||||
std::unordered_map<uint16, Doors *> door_list;
|
||||
std::unordered_map<uint16, Trap *> trap_list;
|
||||
std::unordered_map<uint16, Beacon *> beacon_list;
|
||||
std::unordered_map<uint16, Encounter *> encounter_list;
|
||||
std::list<NPC *> proximity_list;
|
||||
std::list<Group *> group_list;
|
||||
std::list<Raid *> raid_list;
|
||||
|
||||
+124
-13
@@ -59,6 +59,97 @@ static uint32 MaxBankedRaidLeadershipPoints(int Level)
|
||||
return 10;
|
||||
}
|
||||
|
||||
uint32 Client::CalcEXP(uint8 conlevel) {
|
||||
|
||||
uint32 in_add_exp = EXP_FORMULA;
|
||||
|
||||
|
||||
if((XPRate != 0))
|
||||
in_add_exp = static_cast<uint32>(in_add_exp * (static_cast<float>(XPRate) / 100.0f));
|
||||
|
||||
float totalmod = 1.0;
|
||||
float zemmod = 1.0;
|
||||
//get modifiers
|
||||
if(RuleR(Character, ExpMultiplier) >= 0){
|
||||
totalmod *= RuleR(Character, ExpMultiplier);
|
||||
}
|
||||
|
||||
if(zone->newzone_data.zone_exp_multiplier >= 0){
|
||||
zemmod *= zone->newzone_data.zone_exp_multiplier;
|
||||
}
|
||||
|
||||
if(RuleB(Character,UseRaceClassExpBonuses))
|
||||
{
|
||||
if(GetBaseRace() == HALFLING){
|
||||
totalmod *= 1.05;
|
||||
}
|
||||
|
||||
if(GetClass() == ROGUE || GetClass() == WARRIOR){
|
||||
totalmod *= 1.05;
|
||||
}
|
||||
}
|
||||
|
||||
if(zone->IsHotzone())
|
||||
{
|
||||
totalmod += RuleR(Zone, HotZoneBonus);
|
||||
}
|
||||
|
||||
in_add_exp = uint32(float(in_add_exp) * totalmod * zemmod);
|
||||
|
||||
if(RuleB(Character,UseXPConScaling))
|
||||
{
|
||||
if (conlevel != 0xFF) {
|
||||
switch (conlevel)
|
||||
{
|
||||
case CON_GREEN:
|
||||
in_add_exp = 0;
|
||||
return 0;
|
||||
case CON_LIGHTBLUE:
|
||||
in_add_exp = in_add_exp * RuleI(Character, LightBlueModifier)/100;
|
||||
break;
|
||||
case CON_BLUE:
|
||||
in_add_exp = in_add_exp * RuleI(Character, BlueModifier)/100;
|
||||
break;
|
||||
case CON_WHITE:
|
||||
in_add_exp = in_add_exp * RuleI(Character, WhiteModifier)/100;
|
||||
break;
|
||||
case CON_YELLOW:
|
||||
in_add_exp = in_add_exp * RuleI(Character, YellowModifier)/100;
|
||||
break;
|
||||
case CON_RED:
|
||||
in_add_exp = in_add_exp * RuleI(Character, RedModifier)/100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float aatotalmod = 1.0;
|
||||
if(zone->newzone_data.zone_exp_multiplier >= 0){
|
||||
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(RuleB(Character,UseRaceClassExpBonuses))
|
||||
{
|
||||
if(GetBaseRace() == HALFLING){
|
||||
aatotalmod *= 1.05;
|
||||
}
|
||||
|
||||
if(GetClass() == ROGUE || GetClass() == WARRIOR){
|
||||
aatotalmod *= 1.05;
|
||||
}
|
||||
}
|
||||
|
||||
if(RuleB(Zone, LevelBasedEXPMods)){
|
||||
if(zone->level_exp_mod[GetLevel()].ExpMod){
|
||||
in_add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
|
||||
}
|
||||
}
|
||||
|
||||
return in_add_exp;
|
||||
}
|
||||
|
||||
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
|
||||
ItemScriptStopReturn();
|
||||
@@ -78,7 +169,7 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
|
||||
//figure out how much of this goes to AAs
|
||||
add_aaxp = add_exp * m_epp.perAA / 100;
|
||||
//take that ammount away from regular exp
|
||||
//take that amount away from regular exp
|
||||
add_exp -= add_aaxp;
|
||||
|
||||
float totalmod = 1.0;
|
||||
@@ -247,12 +338,22 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
Message(13, "Error in Client::SetEXP. EXP not set.");
|
||||
return; // Must be invalid class/race
|
||||
}
|
||||
uint32 i = 0;
|
||||
uint32 membercount = 0;
|
||||
if(GetGroup())
|
||||
{
|
||||
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if (GetGroup()->members[i] != nullptr) {
|
||||
membercount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) {
|
||||
if (isrezzexp)
|
||||
this->Message_StringID(MT_Experience, REZ_REGAIN);
|
||||
else{
|
||||
if(this->IsGrouped())
|
||||
if(membercount > 1)
|
||||
this->Message_StringID(MT_Experience, GAIN_GROUPXP);
|
||||
else if(IsRaidGrouped())
|
||||
Message_StringID(MT_Experience, GAIN_RAIDEXP);
|
||||
@@ -268,12 +369,17 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
//this ammount of exp (once these loops complete)
|
||||
uint16 check_level = GetLevel()+1;
|
||||
//see if we gained any levels
|
||||
bool level_increase = true;
|
||||
int8 level_count = 0;
|
||||
|
||||
while (set_exp >= GetEXPForLevel(check_level)) {
|
||||
check_level++;
|
||||
if (check_level > 127) { //hard level cap
|
||||
check_level = 127;
|
||||
break;
|
||||
}
|
||||
level_count++;
|
||||
|
||||
if(GetMercID())
|
||||
UpdateMercLevel();
|
||||
}
|
||||
@@ -284,6 +390,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
check_level = 2;
|
||||
break;
|
||||
}
|
||||
level_increase = false;
|
||||
if(GetMercID())
|
||||
UpdateMercLevel();
|
||||
}
|
||||
@@ -364,17 +471,21 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
|
||||
if ((GetLevel() != check_level) && !(check_level >= maxlevel)) {
|
||||
char val1[20]={0};
|
||||
if (GetLevel() == check_level-1){
|
||||
Message_StringID(MT_Experience, GAIN_LEVEL,ConvertArray(check_level,val1));
|
||||
SendLevelAppearance();
|
||||
/* Message(15, "You have gained a level! Welcome to level %i!", check_level); */
|
||||
}
|
||||
if (GetLevel() == check_level){
|
||||
Message_StringID(MT_Experience, LOSE_LEVEL,ConvertArray(check_level,val1));
|
||||
/* Message(15, "You lost a level! You are now level %i!", check_level); */
|
||||
if (level_increase)
|
||||
{
|
||||
if (level_count == 1)
|
||||
Message_StringID(MT_Experience, GAIN_LEVEL, ConvertArray(check_level, val1));
|
||||
else
|
||||
Message(15, "Welcome to level %i!", check_level);
|
||||
|
||||
if (check_level == RuleI(Character, DeathItemLossLevel))
|
||||
Message_StringID(15, CORPSE_ITEM_LOST);
|
||||
|
||||
if (check_level == RuleI(Character, DeathExpLossLevel))
|
||||
Message_StringID(15, CORPSE_EXP_LOST);
|
||||
}
|
||||
else
|
||||
Message(15, "Welcome to level %i!", check_level);
|
||||
Message_StringID(MT_Experience, LOSE_LEVEL, ConvertArray(check_level, val1));
|
||||
|
||||
#ifdef BOTS
|
||||
uint8 myoldlevel = GetLevel();
|
||||
@@ -594,8 +705,8 @@ void Group::SplitExp(uint32 exp, Mob* other) {
|
||||
groupmod = 2.16;
|
||||
else
|
||||
groupmod = 1.0;
|
||||
|
||||
groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier)));
|
||||
if(membercount > 1 && membercount <= 6)
|
||||
groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier)));
|
||||
|
||||
int conlevel = Mob::GetLevelCon(maxlevel, other->GetLevel());
|
||||
if(conlevel == CON_GREEN)
|
||||
|
||||
@@ -123,29 +123,6 @@ void Mob::ProcessFlee()
|
||||
}
|
||||
}
|
||||
|
||||
float Mob::GetFearSpeed()
|
||||
{
|
||||
if (flee_mode) {
|
||||
//we know ratio < FLEE_HP_RATIO
|
||||
float speed = GetBaseRunspeed();
|
||||
float ratio = GetHPRatio();
|
||||
float multiplier = RuleR(Combat, FleeMultiplier);
|
||||
|
||||
if (GetSnaredAmount() > 40)
|
||||
multiplier = multiplier / 6.0f;
|
||||
|
||||
speed = speed * ratio * multiplier / 100;
|
||||
|
||||
//NPC will eventually stop. Snares speeds this up.
|
||||
if (speed < 0.09)
|
||||
speed = 0.0001f;
|
||||
|
||||
return speed;
|
||||
}
|
||||
// fear and blind use their normal run speed
|
||||
return GetRunspeed();
|
||||
}
|
||||
|
||||
void Mob::CalculateNewFearpoint()
|
||||
{
|
||||
if(RuleB(Pathing, Fear) && zone->pathing)
|
||||
|
||||
+25
-16
@@ -185,26 +185,35 @@ bool Client::CanFish() {
|
||||
|
||||
rodPosition.x = m_Position.x + RodLength * sin(HeadingDegrees * M_PI/180.0f);
|
||||
rodPosition.y = m_Position.y + RodLength * cos(HeadingDegrees * M_PI/180.0f);
|
||||
rodPosition.z = m_Position.z;
|
||||
|
||||
// Do BestZ to find where the line hanging from the rod intersects the water (if it is water).
|
||||
// and go 1 unit into the water.
|
||||
glm::vec3 dest;
|
||||
dest.x = rodPosition.x;
|
||||
dest.y = rodPosition.y;
|
||||
dest.z = m_Position.z+10;
|
||||
|
||||
rodPosition.z = zone->zonemap->FindBestZ(dest, nullptr) + 4;
|
||||
bool in_lava = zone->watermap->InLava(rodPosition);
|
||||
bool in_water = zone->watermap->InWater(rodPosition) || zone->watermap->InVWater(rodPosition);
|
||||
//Message(0, "Rod is at %4.3f, %4.3f, %4.3f, InWater says %d, InLava says %d", RodX, RodY, RodZ, in_water, in_lava);
|
||||
if (in_lava) {
|
||||
Message_StringID(MT_Skills, FISHING_LAVA); //Trying to catch a fire elemental or something?
|
||||
float bestz = zone->zonemap->FindBestZ(rodPosition, nullptr);
|
||||
float len = m_Position.z - bestz;
|
||||
if(len > LineLength || len < 0.0f) {
|
||||
Message_StringID(MT_Skills, FISHING_LAND);
|
||||
return false;
|
||||
}
|
||||
if((!in_water) || (m_Position.z-rodPosition.z)>LineLength) { //Didn't hit the water OR the water is too far below us
|
||||
Message_StringID(MT_Skills, FISHING_LAND); //Trying to catch land sharks perhaps?
|
||||
return false;
|
||||
|
||||
float step_size = RuleR(Watermap, FishingLineStepSize);
|
||||
|
||||
for(float i = 0.0f; i < len; i += step_size) {
|
||||
glm::vec3 dest(rodPosition.x, rodPosition.y, m_Position.z - i);
|
||||
|
||||
bool in_lava = zone->watermap->InLava(dest);
|
||||
bool in_water = zone->watermap->InWater(dest) || zone->watermap->InVWater(dest);
|
||||
|
||||
if (in_lava) {
|
||||
Message_StringID(MT_Skills, FISHING_LAVA); //Trying to catch a fire elemental or something?
|
||||
return false;
|
||||
}
|
||||
|
||||
if(in_water) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Message_StringID(MT_Skills, FISHING_LAND);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+182
-1
@@ -606,7 +606,7 @@ void Client::DropItem(int16 slot_id)
|
||||
// Take control of item in client inventory
|
||||
ItemInst *inst = m_inv.PopItem(slot_id);
|
||||
if(inst) {
|
||||
int i = parse->EventItem(EVENT_DROP_ITEM, this, inst, nullptr, "", 0);
|
||||
int i = parse->EventItem(EVENT_DROP_ITEM, this, inst, nullptr, "", slot_id);
|
||||
if(i != 0) {
|
||||
safe_delete(inst);
|
||||
}
|
||||
@@ -2199,6 +2199,187 @@ bool Client::DecreaseByID(uint32 type, uint8 amt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsSummonedBagID(uint32 item_id)
|
||||
{
|
||||
switch (item_id) {
|
||||
case 17147: // "Spiritual Prismatic Pack"
|
||||
case 17303: // "Spirit Pouch"
|
||||
case 17304: // "Dimensional Pocket"
|
||||
case 17305: // "Dimensional Hole"
|
||||
case 17306: // "Glowing Backpack"
|
||||
case 17307: // "Quiver of Marr"
|
||||
case 17308: // "Bandoleer of Luclin"
|
||||
case 17309: // "Pouch of Quellious"
|
||||
case 17310: // "Phantom Satchel"
|
||||
case 17510: // "Glowing Chest"
|
||||
case 17900: // "Grandmaster's Satchel"
|
||||
case 57260: // "Glowing Backpack"
|
||||
case 57261: // "Pouch of Quellious"
|
||||
case 57262: // "Phantom Satchel"
|
||||
case 60224: // "Faded-Glyph Tablet"
|
||||
case 95199: // "Beginner Artisan Satchel"
|
||||
case 95200: // "Apprentice Artisan Satchel"
|
||||
case 95201: // "Freshman Artisan Satchel"
|
||||
case 95202: // "Journeyman Artisan Satchel"
|
||||
case 95203: // "Expert Artisan Satchel"
|
||||
case 95204: // "Master Artisan Satchel"
|
||||
//case 96960: // "Artisan Satchel" - no 12-slot disenchanted bags
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32 GetDisenchantedBagID(uint8 bag_slots)
|
||||
{
|
||||
switch (bag_slots) {
|
||||
case 4:
|
||||
return 77772; // "Small Disenchanted Backpack"
|
||||
case 6:
|
||||
return 77774; // "Disenchanted Backpack"
|
||||
case 8:
|
||||
return 77776; // "Large Disenchanted Backpack"
|
||||
case 10:
|
||||
return 77778; // "Huge Disenchanted Backpack"
|
||||
default:
|
||||
return 0; // no suitable conversions
|
||||
}
|
||||
}
|
||||
|
||||
static bool CopyBagContents(ItemInst* new_bag, const ItemInst* old_bag)
|
||||
{
|
||||
if (!new_bag || !old_bag) { return false; }
|
||||
if (new_bag->GetItem()->BagSlots < old_bag->GetItem()->BagSlots) { return false; }
|
||||
|
||||
// pre-check for size comparisons
|
||||
for (auto bag_slot = 0; bag_slot < old_bag->GetItem()->BagSlots; ++bag_slot) {
|
||||
if (!old_bag->GetItem(bag_slot)) { continue; }
|
||||
if (old_bag->GetItem(bag_slot)->GetItem()->Size > new_bag->GetItem()->BagSize) {
|
||||
Log.Out(Logs::General, Logs::Inventory, "Copy Bag Contents: Failure due to %s is larger than size capacity of %s (%i > %i)",
|
||||
old_bag->GetItem(bag_slot)->GetItem()->Name, new_bag->GetItem()->Name, old_bag->GetItem(bag_slot)->GetItem()->Size, new_bag->GetItem()->BagSize);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto bag_slot = 0; bag_slot < old_bag->GetItem()->BagSlots; ++bag_slot) {
|
||||
if (!old_bag->GetItem(bag_slot)) { continue; }
|
||||
new_bag->PutItem(bag_slot, *(old_bag->GetItem(bag_slot)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::DisenchantSummonedBags(bool client_update)
|
||||
{
|
||||
for (auto slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; ++slot_id) {
|
||||
auto inst = m_inv[slot_id];
|
||||
if (!inst) { continue; }
|
||||
if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; }
|
||||
if (inst->GetItem()->ItemClass != ItemClassContainer) { continue; }
|
||||
if (inst->GetTotalItemCount() == 1) { continue; }
|
||||
|
||||
auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots);
|
||||
if (!new_id) { continue; }
|
||||
auto new_item = database.GetItem(new_id);
|
||||
if (!new_item) { continue; }
|
||||
auto new_inst = database.CreateBaseItem(new_item);
|
||||
if (!new_inst) { continue; }
|
||||
|
||||
if (CopyBagContents(new_inst, inst)) {
|
||||
Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id);
|
||||
PutItemInInventory(slot_id, *new_inst, client_update);
|
||||
}
|
||||
safe_delete(new_inst);
|
||||
}
|
||||
|
||||
for (auto slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; ++slot_id) {
|
||||
auto inst = m_inv[slot_id];
|
||||
if (!inst) { continue; }
|
||||
if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; }
|
||||
if (inst->GetItem()->ItemClass != ItemClassContainer) { continue; }
|
||||
if (inst->GetTotalItemCount() == 1) { continue; }
|
||||
|
||||
auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots);
|
||||
if (!new_id) { continue; }
|
||||
auto new_item = database.GetItem(new_id);
|
||||
if (!new_item) { continue; }
|
||||
auto new_inst = database.CreateBaseItem(new_item);
|
||||
if (!new_inst) { continue; }
|
||||
|
||||
if (CopyBagContents(new_inst, inst)) {
|
||||
Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id);
|
||||
PutItemInInventory(slot_id, *new_inst, client_update);
|
||||
}
|
||||
safe_delete(new_inst);
|
||||
}
|
||||
|
||||
for (auto slot_id = EmuConstants::SHARED_BANK_BEGIN; slot_id <= EmuConstants::SHARED_BANK_END; ++slot_id) {
|
||||
auto inst = m_inv[slot_id];
|
||||
if (!inst) { continue; }
|
||||
if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; }
|
||||
if (inst->GetItem()->ItemClass != ItemClassContainer) { continue; }
|
||||
if (inst->GetTotalItemCount() == 1) { continue; }
|
||||
|
||||
auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots);
|
||||
if (!new_id) { continue; }
|
||||
auto new_item = database.GetItem(new_id);
|
||||
if (!new_item) { continue; }
|
||||
auto new_inst = database.CreateBaseItem(new_item);
|
||||
if (!new_inst) { continue; }
|
||||
|
||||
if (CopyBagContents(new_inst, inst)) {
|
||||
Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id);
|
||||
PutItemInInventory(slot_id, *new_inst, client_update);
|
||||
}
|
||||
safe_delete(new_inst);
|
||||
}
|
||||
|
||||
while (!m_inv.CursorEmpty()) {
|
||||
auto inst = m_inv[MainCursor];
|
||||
if (!inst) { break; }
|
||||
if (!IsSummonedBagID(inst->GetItem()->ID)) { break; }
|
||||
if (inst->GetItem()->ItemClass != ItemClassContainer) { break; }
|
||||
if (inst->GetTotalItemCount() == 1) { break; }
|
||||
|
||||
auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots);
|
||||
if (!new_id) { break; }
|
||||
auto new_item = database.GetItem(new_id);
|
||||
if (!new_item) { break; }
|
||||
auto new_inst = database.CreateBaseItem(new_item);
|
||||
if (!new_inst) { break; }
|
||||
|
||||
if (CopyBagContents(new_inst, inst)) {
|
||||
Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, MainCursor);
|
||||
std::list<ItemInst*> local;
|
||||
local.push_front(new_inst);
|
||||
m_inv.PopItem(MainCursor);
|
||||
safe_delete(inst);
|
||||
|
||||
while (!m_inv.CursorEmpty()) {
|
||||
auto limbo_inst = m_inv.PopItem(MainCursor);
|
||||
if (limbo_inst == nullptr) { continue; }
|
||||
local.push_back(limbo_inst);
|
||||
}
|
||||
|
||||
for (auto iter = local.begin(); iter != local.end(); ++iter) {
|
||||
auto cur_inst = *iter;
|
||||
if (cur_inst == nullptr) { continue; }
|
||||
m_inv.PushCursor(*cur_inst);
|
||||
safe_delete(cur_inst);
|
||||
}
|
||||
local.clear();
|
||||
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
database.SaveCursor(this->CharacterID(), s, e);
|
||||
}
|
||||
else {
|
||||
safe_delete(new_inst); // deletes disenchanted bag if not used
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::RemoveNoRent(bool client_update)
|
||||
{
|
||||
for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) {
|
||||
|
||||
+5
-1
@@ -58,7 +58,7 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
|
||||
if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) {
|
||||
float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash);
|
||||
float avg_cash_roll = (float)zone->random.Real(0.0, 1.0);
|
||||
|
||||
|
||||
if(avg_cash_roll < upper_chance) {
|
||||
cash = zone->random.Int(lts->avgcoin, max_cash);
|
||||
} else {
|
||||
@@ -332,6 +332,8 @@ void NPC::AddLootDrop(const ItemData *item2, ItemList* itemlist, int16 charges,
|
||||
CastToMob()->AddProcToWeapon(item2->Proc.Effect, true);
|
||||
|
||||
eslot = MaterialPrimary;
|
||||
if (item2->Damage > 0)
|
||||
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
|
||||
}
|
||||
else if (foundslot == MainSecondary
|
||||
&& (GetOwner() != nullptr || (GetLevel() >= 13 && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) &&
|
||||
@@ -342,6 +344,8 @@ void NPC::AddLootDrop(const ItemData *item2, ItemList* itemlist, int16 charges,
|
||||
CastToMob()->AddProcToWeapon(item2->Proc.Effect, true);
|
||||
|
||||
eslot = MaterialSecondary;
|
||||
if (item2->Damage > 0)
|
||||
SendAddPlayerState(PlayerState::SecondaryWeaponEquipped);
|
||||
}
|
||||
else if (foundslot == MainHead) {
|
||||
eslot = MaterialHead;
|
||||
|
||||
+49
-1
@@ -1255,6 +1255,46 @@ void Lua_Client::PlayMP3(std::string file)
|
||||
self->PlayMP3(file.c_str());
|
||||
}
|
||||
|
||||
void Lua_Client::QuestReward(Lua_Mob target) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(target);
|
||||
}
|
||||
|
||||
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(target, copper);
|
||||
}
|
||||
|
||||
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(target, copper, silver);
|
||||
}
|
||||
|
||||
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(target, copper, silver, gold);
|
||||
}
|
||||
|
||||
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(target, copper, silver, gold, platinum);
|
||||
}
|
||||
|
||||
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(target, copper, silver, gold, platinum, itemid);
|
||||
}
|
||||
|
||||
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(target, copper, silver, gold, platinum, itemid, exp);
|
||||
}
|
||||
|
||||
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(target, copper, silver, gold, platinum, itemid, exp, faction);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_client() {
|
||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||
.def(luabind::constructor<>())
|
||||
@@ -1504,7 +1544,15 @@ luabind::scope lua_register_client() {
|
||||
.def("SetConsumption", (void(Lua_Client::*)(int, int))&Lua_Client::SetConsumption)
|
||||
.def("SendMarqueeMessage", (void(Lua_Client::*)(uint32, uint32, uint32, uint32, uint32, std::string))&Lua_Client::SendMarqueeMessage)
|
||||
.def("SendColoredText", (void(Lua_Client::*)(uint32, std::string))&Lua_Client::SendColoredText)
|
||||
.def("PlayMP3", (void(Lua_Client::*)(std::string))&Lua_Client::PlayMP3);
|
||||
.def("PlayMP3", (void(Lua_Client::*)(std::string))&Lua_Client::PlayMP3)
|
||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob))&Lua_Client::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32))&Lua_Client::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32))&Lua_Client::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32))&Lua_Client::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32, bool))&Lua_Client::QuestReward);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_inventory_where() {
|
||||
|
||||
@@ -278,6 +278,14 @@ public:
|
||||
void SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, std::string msg);
|
||||
void SendColoredText(uint32 type, std::string msg);
|
||||
void PlayMP3(std::string file);
|
||||
void QuestReward(Lua_Mob target);
|
||||
void QuestReward(Lua_Mob target, uint32 copper);
|
||||
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver);
|
||||
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold);
|
||||
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum);
|
||||
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid);
|
||||
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp);
|
||||
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifdef LUA_EQEMU
|
||||
|
||||
#include "lua.hpp"
|
||||
#include <luabind/luabind.hpp>
|
||||
#include "lua_encounter.h"
|
||||
#include "encounter.h"
|
||||
|
||||
|
||||
luabind::scope lua_register_encounter() {
|
||||
return luabind::class_<Lua_Encounter>("Encounter");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef EQEMU_LUA_ENCOUNTER_H
|
||||
#define EQEMU_LUA_ENCOUNTER_H
|
||||
#ifdef LUA_EQEMU
|
||||
|
||||
#include "lua_ptr.h"
|
||||
|
||||
class Encounter;
|
||||
|
||||
namespace luabind {
|
||||
struct scope;
|
||||
class object;
|
||||
}
|
||||
|
||||
luabind::scope lua_register_encounter();
|
||||
|
||||
class Lua_Encounter : public Lua_Ptr<Encounter>
|
||||
{
|
||||
typedef Encounter NativeType;
|
||||
public:
|
||||
Lua_Encounter() { SetLuaPtrData(nullptr); }
|
||||
Lua_Encounter(Encounter *d) { SetLuaPtrData(reinterpret_cast<Encounter*>(d)); }
|
||||
virtual ~Lua_Encounter() { }
|
||||
|
||||
operator Encounter*() {
|
||||
return reinterpret_cast<Encounter*>(GetLuaPtrData());
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
+41
-9
@@ -18,6 +18,8 @@
|
||||
#include "qglobals.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "encounter.h"
|
||||
#include "lua_encounter.h"
|
||||
|
||||
struct Events { };
|
||||
struct Factions { };
|
||||
@@ -34,6 +36,8 @@ struct lua_registered_event {
|
||||
|
||||
extern std::map<std::string, std::list<lua_registered_event>> lua_encounter_events_registered;
|
||||
extern std::map<std::string, bool> lua_encounters_loaded;
|
||||
extern std::map<std::string, Encounter *> lua_encounters;
|
||||
|
||||
extern void MapOpcodes();
|
||||
extern void ClearMappedOpcode(EmuOpcode op);
|
||||
|
||||
@@ -42,19 +46,23 @@ void unregister_event(std::string package_name, std::string name, int evt);
|
||||
void load_encounter(std::string name) {
|
||||
if(lua_encounters_loaded.count(name) > 0)
|
||||
return;
|
||||
|
||||
Encounter *enc = new Encounter(name.c_str());
|
||||
entity_list.AddEncounter(enc);
|
||||
lua_encounters[name] = enc;
|
||||
lua_encounters_loaded[name] = true;
|
||||
parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, 0);
|
||||
parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, "", 0);
|
||||
}
|
||||
|
||||
void load_encounter_with_data(std::string name, std::string info_str) {
|
||||
if(lua_encounters_loaded.count(name) > 0)
|
||||
return;
|
||||
|
||||
Encounter *enc = new Encounter(name.c_str());
|
||||
entity_list.AddEncounter(enc);
|
||||
lua_encounters[name] = enc;
|
||||
lua_encounters_loaded[name] = true;
|
||||
std::vector<EQEmu::Any> info_ptrs;
|
||||
info_ptrs.push_back(&info_str);
|
||||
parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, 0, &info_ptrs);
|
||||
parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, "", 0, &info_ptrs);
|
||||
}
|
||||
|
||||
void unload_encounter(std::string name) {
|
||||
@@ -80,8 +88,10 @@ void unload_encounter(std::string name) {
|
||||
}
|
||||
}
|
||||
|
||||
lua_encounters[name]->Depop();
|
||||
lua_encounters.erase(name);
|
||||
lua_encounters_loaded.erase(name);
|
||||
parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0);
|
||||
parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, "", 0);
|
||||
}
|
||||
|
||||
void unload_encounter_with_data(std::string name, std::string info_str) {
|
||||
@@ -109,10 +119,12 @@ void unload_encounter_with_data(std::string name, std::string info_str) {
|
||||
}
|
||||
}
|
||||
|
||||
lua_encounters[name]->Depop();
|
||||
lua_encounters.erase(name);
|
||||
lua_encounters_loaded.erase(name);
|
||||
std::vector<EQEmu::Any> info_ptrs;
|
||||
info_ptrs.push_back(&info_str);
|
||||
parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0, &info_ptrs);
|
||||
parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, "", 0, &info_ptrs);
|
||||
}
|
||||
|
||||
void register_event(std::string package_name, std::string name, int evt, luabind::adl::object func) {
|
||||
@@ -285,6 +297,10 @@ void lua_set_timer(const char *timer, int time_ms, Lua_Mob mob) {
|
||||
quest_manager.settimerMS(timer, time_ms, mob);
|
||||
}
|
||||
|
||||
void lua_set_timer(const char *timer, int time_ms, Lua_Encounter enc) {
|
||||
quest_manager.settimerMS(timer, time_ms, enc);
|
||||
}
|
||||
|
||||
void lua_stop_timer(const char *timer) {
|
||||
quest_manager.stoptimer(timer);
|
||||
}
|
||||
@@ -297,6 +313,10 @@ void lua_stop_timer(const char *timer, Lua_Mob mob) {
|
||||
quest_manager.stoptimer(timer, mob);
|
||||
}
|
||||
|
||||
void lua_stop_timer(const char *timer, Lua_Encounter enc) {
|
||||
quest_manager.stoptimer(timer, enc);
|
||||
}
|
||||
|
||||
void lua_stop_all_timers() {
|
||||
quest_manager.stopalltimers();
|
||||
}
|
||||
@@ -309,6 +329,10 @@ void lua_stop_all_timers(Lua_Mob mob) {
|
||||
quest_manager.stopalltimers(mob);
|
||||
}
|
||||
|
||||
void lua_stop_all_timers(Lua_Encounter enc) {
|
||||
quest_manager.stopalltimers(enc);
|
||||
}
|
||||
|
||||
void lua_depop() {
|
||||
quest_manager.depop(0);
|
||||
}
|
||||
@@ -386,7 +410,11 @@ void lua_create_guild(const char *name, const char *leader) {
|
||||
}
|
||||
|
||||
void lua_set_time(int hour, int min) {
|
||||
quest_manager.settime(hour, min);
|
||||
quest_manager.settime(hour, min, true);
|
||||
}
|
||||
|
||||
void lua_set_time(int hour, int min, bool update_world) {
|
||||
quest_manager.settime(hour, min, update_world);
|
||||
}
|
||||
|
||||
void lua_signal(int npc_id, int signal_id) {
|
||||
@@ -979,7 +1007,7 @@ int lua_get_zone_weather() {
|
||||
|
||||
luabind::adl::object lua_get_zone_time(lua_State *L) {
|
||||
TimeOfDay_Struct eqTime;
|
||||
zone->zone_time.getEQTimeOfDay(time(0), &eqTime);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eqTime);
|
||||
|
||||
luabind::adl::object ret = luabind::newtable(L);
|
||||
ret["zone_hour"] = eqTime.hour - 1;
|
||||
@@ -1442,12 +1470,15 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("set_timer", (void(*)(const char*, int))&lua_set_timer),
|
||||
luabind::def("set_timer", (void(*)(const char*, int, Lua_ItemInst))&lua_set_timer),
|
||||
luabind::def("set_timer", (void(*)(const char*, int, Lua_Mob))&lua_set_timer),
|
||||
luabind::def("set_timer", (void(*)(const char*, int, Lua_Encounter))&lua_set_timer),
|
||||
luabind::def("stop_timer", (void(*)(const char*))&lua_stop_timer),
|
||||
luabind::def("stop_timer", (void(*)(const char*, Lua_ItemInst))&lua_stop_timer),
|
||||
luabind::def("stop_timer", (void(*)(const char*, Lua_Mob))&lua_stop_timer),
|
||||
luabind::def("stop_timer", (void(*)(const char*, Lua_Encounter))&lua_stop_timer),
|
||||
luabind::def("stop_all_timers", (void(*)(void))&lua_stop_all_timers),
|
||||
luabind::def("stop_all_timers", (void(*)(Lua_ItemInst))&lua_stop_all_timers),
|
||||
luabind::def("stop_all_timers", (void(*)(Lua_Mob))&lua_stop_all_timers),
|
||||
luabind::def("stop_all_timers", (void(*)(Lua_Encounter))&lua_stop_all_timers),
|
||||
luabind::def("depop", (void(*)(void))&lua_depop),
|
||||
luabind::def("depop", (void(*)(int))&lua_depop),
|
||||
luabind::def("depop_with_timer", (void(*)(void))&lua_depop_with_timer),
|
||||
@@ -1467,7 +1498,8 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("set_sky", &lua_set_sky),
|
||||
luabind::def("set_guild", &lua_set_guild),
|
||||
luabind::def("create_guild", &lua_create_guild),
|
||||
luabind::def("set_time", &lua_set_time),
|
||||
luabind::def("set_time", (void(*)(int, int))&lua_set_time),
|
||||
luabind::def("set_time", (void(*)(int, int, bool))&lua_set_time),
|
||||
luabind::def("signal", (void(*)(int,int))&lua_signal),
|
||||
luabind::def("signal", (void(*)(int,int,int))&lua_signal),
|
||||
luabind::def("set_global", &lua_set_global),
|
||||
|
||||
+12
-25
@@ -1590,26 +1590,6 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) {
|
||||
beard, aa_title, drakkin_heritage, drakkin_tattoo, drakkin_details, size);
|
||||
}
|
||||
|
||||
void Lua_Mob::QuestReward(Lua_Client c) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(c);
|
||||
}
|
||||
|
||||
void Lua_Mob::QuestReward(Lua_Client c, uint32 silver) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(c, silver);
|
||||
}
|
||||
|
||||
void Lua_Mob::QuestReward(Lua_Client c, uint32 silver, uint32 gold) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(c, silver, gold);
|
||||
}
|
||||
|
||||
void Lua_Mob::QuestReward(Lua_Client c, uint32 silver, uint32 gold, uint32 platinum) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->QuestReward(c, silver, gold, platinum);
|
||||
}
|
||||
|
||||
void Lua_Mob::CameraEffect(uint32 duration, uint32 intensity) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->CameraEffect(duration, intensity);
|
||||
@@ -1651,6 +1631,11 @@ void Lua_Mob::TempName(const char *newname) {
|
||||
self->TempName(newname);
|
||||
}
|
||||
|
||||
std::string Lua_Mob::GetGlobal(const char *varname) {
|
||||
Lua_Safe_Call_String();
|
||||
return self->GetGlobal(varname);
|
||||
}
|
||||
|
||||
void Lua_Mob::SetGlobal(const char *varname, const char *newvalue, int options, const char *duration) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetGlobal(varname, newvalue, options, duration);
|
||||
@@ -1866,6 +1851,10 @@ int Lua_Mob::CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite
|
||||
return self->CanBuffStack(spell_id, caster_level, fail_if_overwrite);
|
||||
}
|
||||
|
||||
void Lua_Mob::SetPseudoRoot(bool in) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetPseudoRoot(in);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_mob() {
|
||||
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
||||
@@ -2132,10 +2121,6 @@ luabind::scope lua_register_mob() {
|
||||
.def("SetRace", (void(Lua_Mob::*)(int))&Lua_Mob::SetRace)
|
||||
.def("SetGender", (void(Lua_Mob::*)(int))&Lua_Mob::SetGender)
|
||||
.def("SendIllusionPacket", (void(Lua_Mob::*)(luabind::adl::object))&Lua_Mob::SendIllusionPacket)
|
||||
.def("QuestReward", (void(Lua_Mob::*)(Lua_Client))&Lua_Mob::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32))&Lua_Mob::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32,uint32))&Lua_Mob::QuestReward)
|
||||
.def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32,uint32,uint32))&Lua_Mob::QuestReward)
|
||||
.def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32))&Lua_Mob::CameraEffect)
|
||||
.def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client))&Lua_Mob::CameraEffect)
|
||||
.def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client,bool))&Lua_Mob::CameraEffect)
|
||||
@@ -2144,6 +2129,7 @@ luabind::scope lua_register_mob() {
|
||||
.def("SendSpellEffect", (void(Lua_Mob::*)(uint32,uint32,uint32,bool,uint32,bool,Lua_Client))&Lua_Mob::SendSpellEffect)
|
||||
.def("TempName", (void(Lua_Mob::*)(void))&Lua_Mob::TempName)
|
||||
.def("TempName", (void(Lua_Mob::*)(const char*))&Lua_Mob::TempName)
|
||||
.def("GetGlobal", (std::string(Lua_Mob::*)(const char*))&Lua_Mob::GetGlobal)
|
||||
.def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*))&Lua_Mob::SetGlobal)
|
||||
.def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*,Lua_Mob))&Lua_Mob::SetGlobal)
|
||||
.def("TarGlobal", (void(Lua_Mob::*)(const char*,const char*,const char*,int,int,int))&Lua_Mob::TarGlobal)
|
||||
@@ -2186,7 +2172,8 @@ luabind::scope lua_register_mob() {
|
||||
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int))&Lua_Mob::BuffFadeBySlot)
|
||||
.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("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack)
|
||||
.def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_special_abilities() {
|
||||
|
||||
+3
-5
@@ -169,7 +169,7 @@ public:
|
||||
bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost);
|
||||
bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot);
|
||||
bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration);
|
||||
bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration,
|
||||
bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration,
|
||||
int resist_adjust);
|
||||
bool SpellFinished(int spell_id, Lua_Mob target);
|
||||
bool SpellFinished(int spell_id, Lua_Mob target, int slot);
|
||||
@@ -296,10 +296,6 @@ public:
|
||||
void SetRace(int in);
|
||||
void SetGender(int in);
|
||||
void SendIllusionPacket(luabind::adl::object illusion);
|
||||
void QuestReward(Lua_Client c);
|
||||
void QuestReward(Lua_Client c, uint32 silver);
|
||||
void QuestReward(Lua_Client c, uint32 silver, uint32 gold);
|
||||
void QuestReward(Lua_Client c, uint32 silver, uint32 gold, uint32 platinum);
|
||||
void CameraEffect(uint32 duration, uint32 intensity);
|
||||
void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c);
|
||||
void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c, bool global);
|
||||
@@ -311,6 +307,7 @@ public:
|
||||
uint32 unk020, bool perm_effect, Lua_Client c);
|
||||
void TempName();
|
||||
void TempName(const char *newname);
|
||||
std::string GetGlobal(const char *varname);
|
||||
void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration);
|
||||
void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Lua_Mob other);
|
||||
void TarGlobal(const char *varname, const char *value, const char *duration, int npc_id, int char_id, int zone_id);
|
||||
@@ -355,6 +352,7 @@ public:
|
||||
void BuffFadeBySlot(int slot, bool recalc_bonuses);
|
||||
int CanBuffStack(int spell_id, int caster_level);
|
||||
int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite);
|
||||
void SetPseudoRoot(bool in);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@ Lua_Packet::Lua_Packet(int opcode, int size, bool raw) {
|
||||
if(raw) {
|
||||
SetLuaPtrData(new EQApplicationPacket(OP_Unknown, size));
|
||||
owned_ = true;
|
||||
|
||||
|
||||
EQApplicationPacket *self = reinterpret_cast<EQApplicationPacket*>(d_);
|
||||
self->SetOpcodeBypass(opcode);
|
||||
} else {
|
||||
@@ -692,8 +692,8 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("VetClaimRequest", static_cast<int>(OP_VetClaimRequest)),
|
||||
luabind::value("VetClaimReply", static_cast<int>(OP_VetClaimReply)),
|
||||
luabind::value("WeaponEquip1", static_cast<int>(OP_WeaponEquip1)),
|
||||
luabind::value("WeaponEquip2", static_cast<int>(OP_WeaponEquip2)),
|
||||
luabind::value("WeaponUnequip2", static_cast<int>(OP_WeaponUnequip2)),
|
||||
luabind::value("PlayerStateAdd", static_cast<int>(OP_PlayerStateAdd)),
|
||||
luabind::value("PlayerStateRemove", static_cast<int>(OP_PlayerStateRemove)),
|
||||
luabind::value("WorldLogout", static_cast<int>(OP_WorldLogout)),
|
||||
luabind::value("SessionReady", static_cast<int>(OP_SessionReady)),
|
||||
luabind::value("Login", static_cast<int>(OP_Login)),
|
||||
|
||||
+21
-9
@@ -34,6 +34,7 @@
|
||||
#include "questmgr.h"
|
||||
#include "zone.h"
|
||||
#include "lua_parser.h"
|
||||
#include "lua_encounter.h"
|
||||
|
||||
const char *LuaEvents[_LargestEventID] = {
|
||||
"event_say",
|
||||
@@ -128,6 +129,7 @@ struct lua_registered_event {
|
||||
|
||||
std::map<std::string, std::list<lua_registered_event>> lua_encounter_events_registered;
|
||||
std::map<std::string, bool> lua_encounters_loaded;
|
||||
std::map<std::string, Encounter *> lua_encounters;
|
||||
|
||||
LuaParser::LuaParser() {
|
||||
for(int i = 0; i < _LargestEventID; ++i) {
|
||||
@@ -135,6 +137,7 @@ LuaParser::LuaParser() {
|
||||
PlayerArgumentDispatch[i] = handle_player_null;
|
||||
ItemArgumentDispatch[i] = handle_item_null;
|
||||
SpellArgumentDispatch[i] = handle_spell_null;
|
||||
EncounterArgumentDispatch[i] = handle_encounter_null;
|
||||
}
|
||||
|
||||
NPCArgumentDispatch[EVENT_SAY] = handle_npc_event_say;
|
||||
@@ -213,6 +216,10 @@ LuaParser::LuaParser() {
|
||||
SpellArgumentDispatch[EVENT_SPELL_FADE] = handle_spell_fade;
|
||||
SpellArgumentDispatch[EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE] = handle_translocate_finish;
|
||||
|
||||
EncounterArgumentDispatch[EVENT_TIMER] = handle_encounter_timer;
|
||||
EncounterArgumentDispatch[EVENT_ENCOUNTER_LOAD] = handle_encounter_load;
|
||||
EncounterArgumentDispatch[EVENT_ENCOUNTER_UNLOAD] = handle_encounter_unload;
|
||||
|
||||
L = nullptr;
|
||||
}
|
||||
|
||||
@@ -575,7 +582,7 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers) {
|
||||
int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers) {
|
||||
evt = ConvertLuaEvent(evt);
|
||||
if(evt >= _LargestEventID) {
|
||||
return 0;
|
||||
@@ -587,10 +594,10 @@ int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, uint
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _EventEncounter(package_name, evt, encounter_name, extra_data, extra_pointers);
|
||||
return _EventEncounter(package_name, evt, encounter_name, data, extra_data, extra_pointers);
|
||||
}
|
||||
|
||||
int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data,
|
||||
int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) {
|
||||
const char *sub_name = LuaEvents[evt];
|
||||
|
||||
@@ -604,13 +611,12 @@ int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::
|
||||
lua_pushstring(L, encounter_name.c_str());
|
||||
lua_setfield(L, -2, "name");
|
||||
|
||||
if(extra_pointers) {
|
||||
std::string *str = EQEmu::any_cast<std::string*>(extra_pointers->at(0));
|
||||
lua_pushstring(L, str->c_str());
|
||||
lua_setfield(L, -2, "data");
|
||||
}
|
||||
Encounter *enc = lua_encounters[encounter_name];
|
||||
|
||||
quest_manager.StartQuest(nullptr, nullptr, nullptr, encounter_name);
|
||||
auto arg_function = EncounterArgumentDispatch[evt];
|
||||
arg_function(this, L, enc, data, extra_data, extra_pointers);
|
||||
|
||||
quest_manager.StartQuest(enc, nullptr, nullptr, encounter_name);
|
||||
if(lua_pcall(L, 1, 1, 0)) {
|
||||
std::string error = lua_tostring(L, -1);
|
||||
AddError(error);
|
||||
@@ -786,6 +792,11 @@ void LuaParser::ReloadQuests() {
|
||||
lua_encounter_events_registered.clear();
|
||||
lua_encounters_loaded.clear();
|
||||
|
||||
for (auto encounter : lua_encounters) {
|
||||
encounter.second->Depop();
|
||||
}
|
||||
lua_encounters.clear();
|
||||
|
||||
if(L) {
|
||||
lua_close(L);
|
||||
}
|
||||
@@ -968,6 +979,7 @@ void LuaParser::MapFunctions(lua_State *L) {
|
||||
lua_register_client_version(),
|
||||
lua_register_appearance(),
|
||||
lua_register_entity(),
|
||||
lua_register_encounter(),
|
||||
lua_register_mob(),
|
||||
lua_register_special_abilities(),
|
||||
lua_register_npc(),
|
||||
|
||||
+4
-2
@@ -39,7 +39,7 @@ public:
|
||||
std::vector<EQEmu::Any> *extra_pointers);
|
||||
virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers);
|
||||
virtual int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data,
|
||||
virtual int EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers);
|
||||
|
||||
virtual bool HasQuestSub(uint32 npc_id, QuestEventID evt);
|
||||
@@ -82,7 +82,7 @@ private:
|
||||
uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr);
|
||||
int _EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr);
|
||||
int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data,
|
||||
int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers);
|
||||
|
||||
void LoadScript(std::string filename, std::string package_name);
|
||||
@@ -99,6 +99,8 @@ private:
|
||||
PlayerArgumentHandler PlayerArgumentDispatch[_LargestEventID];
|
||||
ItemArgumentHandler ItemArgumentDispatch[_LargestEventID];
|
||||
SpellArgumentHandler SpellArgumentDispatch[_LargestEventID];
|
||||
EncounterArgumentHandler EncounterArgumentDispatch[_LargestEventID];
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "lua_door.h"
|
||||
#include "lua_object.h"
|
||||
#include "lua_packet.h"
|
||||
#include "lua_encounter.h"
|
||||
#include "zone.h"
|
||||
#include "lua_parser_events.h"
|
||||
|
||||
@@ -704,4 +705,39 @@ void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* cl
|
||||
std::vector<EQEmu::Any> *extra_pointers) {
|
||||
}
|
||||
|
||||
void handle_encounter_timer(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) {
|
||||
lua_pushstring(L, data.c_str());
|
||||
lua_setfield(L, -2, "timer");
|
||||
}
|
||||
|
||||
void handle_encounter_load(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) {
|
||||
if (encounter) {
|
||||
Lua_Encounter l_enc(encounter);
|
||||
luabind::adl::object l_enc_o = luabind::adl::object(L, l_enc);
|
||||
l_enc_o.push(L);
|
||||
lua_setfield(L, -2, "encounter");
|
||||
}
|
||||
if (extra_pointers) {
|
||||
std::string *str = EQEmu::any_cast<std::string*>(extra_pointers->at(0));
|
||||
lua_pushstring(L, str->c_str());
|
||||
lua_setfield(L, -2, "data");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_encounter_unload(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) {
|
||||
if (extra_pointers) {
|
||||
std::string *str = EQEmu::any_cast<std::string*>(extra_pointers->at(0));
|
||||
lua_pushstring(L, str->c_str());
|
||||
lua_setfield(L, -2, "data");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_encounter_null(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,7 @@ typedef void(*NPCArgumentHandler)(QuestInterface*, lua_State*, NPC*, Mob*, std::
|
||||
typedef void(*PlayerArgumentHandler)(QuestInterface*, lua_State*, Client*, std::string, uint32, std::vector<EQEmu::Any>*);
|
||||
typedef void(*ItemArgumentHandler)(QuestInterface*, lua_State*, Client*, ItemInst*, Mob*, std::string, uint32, std::vector<EQEmu::Any>*);
|
||||
typedef void(*SpellArgumentHandler)(QuestInterface*, lua_State*, NPC*, Client*, uint32, uint32, std::vector<EQEmu::Any>*);
|
||||
typedef void(*EncounterArgumentHandler)(QuestInterface*, lua_State*, Encounter* encounter, std::string, uint32, std::vector<EQEmu::Any>*);
|
||||
|
||||
//NPC
|
||||
void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
|
||||
@@ -127,5 +128,16 @@ void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Cl
|
||||
void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers);
|
||||
|
||||
|
||||
//Encounter
|
||||
void handle_encounter_timer(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers);
|
||||
void handle_encounter_load(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers);
|
||||
void handle_encounter_unload(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers);
|
||||
void handle_encounter_null(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+36
-1
@@ -64,7 +64,7 @@ Map::~Map() {
|
||||
|
||||
float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
|
||||
if (!imp)
|
||||
return false;
|
||||
return BEST_Z_INVALID;
|
||||
|
||||
glm::vec3 tmp;
|
||||
if(!result)
|
||||
@@ -93,6 +93,41 @@ float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
|
||||
return BEST_Z_INVALID;
|
||||
}
|
||||
|
||||
float Map::FindClosestZ(glm::vec3 &start, glm::vec3 *result) const {
|
||||
// Unlike FindBestZ, this method finds the closest Z value above or below the specified point.
|
||||
//
|
||||
if (!imp)
|
||||
return false;
|
||||
|
||||
float ClosestZ = BEST_Z_INVALID;
|
||||
|
||||
glm::vec3 tmp;
|
||||
if (!result)
|
||||
result = &tmp;
|
||||
|
||||
glm::vec3 from(start.x, start.y, start.z);
|
||||
glm::vec3 to(start.x, start.y, BEST_Z_INVALID);
|
||||
float hit_distance;
|
||||
bool hit = false;
|
||||
|
||||
// first check is below us
|
||||
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
||||
if (hit) {
|
||||
ClosestZ = result->z;
|
||||
|
||||
}
|
||||
|
||||
// Find nearest Z above us
|
||||
to.z = -BEST_Z_INVALID;
|
||||
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
||||
if (hit) {
|
||||
if (abs(from.z - result->z) < abs(ClosestZ - from.z))
|
||||
return result->z;
|
||||
}
|
||||
|
||||
return ClosestZ;
|
||||
}
|
||||
|
||||
bool Map::LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const {
|
||||
if(!imp)
|
||||
return false;
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
~Map();
|
||||
|
||||
float FindBestZ(glm::vec3 &start, glm::vec3 *result) const;
|
||||
float FindClosestZ(glm::vec3 &start, glm::vec3 *result) const;
|
||||
bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const;
|
||||
bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const;
|
||||
bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const;
|
||||
|
||||
+12
-13
@@ -1236,10 +1236,7 @@ void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
||||
bool Merc::Process()
|
||||
{
|
||||
if(IsStunned() && stunned_timer.Check())
|
||||
{
|
||||
this->stunned = false;
|
||||
this->stunned_timer.Disable();
|
||||
}
|
||||
Mob::UnStun();
|
||||
|
||||
if (GetDepop())
|
||||
{
|
||||
@@ -1463,14 +1460,16 @@ void Merc::AI_Process() {
|
||||
|
||||
if(moved) {
|
||||
moved = false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(m_PlayerState & static_cast<uint32>(PlayerState::Aggressive)))
|
||||
SendAddPlayerState(PlayerState::Aggressive);
|
||||
|
||||
bool atCombatRange = false;
|
||||
|
||||
float meleeDistance = GetMaxMeleeRangeToTarget(GetTarget());
|
||||
@@ -1497,9 +1496,7 @@ void Merc::AI_Process() {
|
||||
SetRunAnimSpeed(0);
|
||||
|
||||
if(moved) {
|
||||
moved = false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1684,6 +1681,9 @@ void Merc::AI_Process() {
|
||||
confidence_timer.Disable();
|
||||
_check_confidence = false;
|
||||
|
||||
if (m_PlayerState & static_cast<uint32>(PlayerState::Aggressive))
|
||||
SendRemovePlayerState(PlayerState::Aggressive);
|
||||
|
||||
if(!check_target_timer.Enabled())
|
||||
check_target_timer.Start(2000, false);
|
||||
|
||||
@@ -1707,7 +1707,7 @@ void Merc::AI_Process() {
|
||||
if(follow)
|
||||
{
|
||||
float dist = DistanceSquared(m_Position, follow->GetPosition());
|
||||
float speed = GetRunspeed();
|
||||
int speed = GetRunspeed();
|
||||
|
||||
if(dist < GetFollowDistance() + 1000)
|
||||
speed = GetWalkspeed();
|
||||
@@ -1724,9 +1724,8 @@ void Merc::AI_Process() {
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
moved=false;
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
moved = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+364
-95
@@ -26,6 +26,7 @@
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
@@ -149,6 +150,29 @@ Mob::Mob(const char* in_name,
|
||||
size = in_size;
|
||||
base_size = size;
|
||||
runspeed = in_runspeed;
|
||||
// neotokyo: sanity check
|
||||
if (runspeed < 0 || runspeed > 20)
|
||||
runspeed = 1.25f;
|
||||
base_runspeed = (int)((float)runspeed * 40.0f);
|
||||
// clients
|
||||
if (runspeed == 0.7f) {
|
||||
base_runspeed = 28;
|
||||
walkspeed = 0.3f;
|
||||
base_walkspeed = 12;
|
||||
fearspeed = 0.625f;
|
||||
base_fearspeed = 25;
|
||||
// npcs
|
||||
} else {
|
||||
base_walkspeed = base_runspeed * 100 / 265;
|
||||
walkspeed = ((float)base_walkspeed) * 0.025f;
|
||||
base_fearspeed = base_runspeed * 100 / 127;
|
||||
fearspeed = ((float)base_fearspeed) * 0.025f;
|
||||
}
|
||||
|
||||
|
||||
current_speed = base_runspeed;
|
||||
|
||||
m_PlayerState = 0;
|
||||
|
||||
|
||||
// sanity check
|
||||
@@ -161,7 +185,7 @@ Mob::Mob(const char* in_name,
|
||||
m_Light.Level.Spell = m_Light.Type.Spell = 0;
|
||||
m_Light.Type.Active = m_Light.Type.Innate;
|
||||
m_Light.Level.Active = m_Light.Level.Innate;
|
||||
|
||||
|
||||
texture = in_texture;
|
||||
helmtexture = in_helmtexture;
|
||||
armtexture = in_armtexture;
|
||||
@@ -240,15 +264,19 @@ Mob::Mob(const char* in_name,
|
||||
PermaProcs[j].spellID = SPELL_UNKNOWN;
|
||||
PermaProcs[j].chance = 0;
|
||||
PermaProcs[j].base_spellID = SPELL_UNKNOWN;
|
||||
PermaProcs[j].level_override = -1;
|
||||
SpellProcs[j].spellID = SPELL_UNKNOWN;
|
||||
SpellProcs[j].chance = 0;
|
||||
SpellProcs[j].base_spellID = SPELL_UNKNOWN;
|
||||
SpellProcs[j].level_override = -1;
|
||||
DefensiveProcs[j].spellID = SPELL_UNKNOWN;
|
||||
DefensiveProcs[j].chance = 0;
|
||||
DefensiveProcs[j].base_spellID = SPELL_UNKNOWN;
|
||||
DefensiveProcs[j].level_override = -1;
|
||||
RangedProcs[j].spellID = SPELL_UNKNOWN;
|
||||
RangedProcs[j].chance = 0;
|
||||
RangedProcs[j].base_spellID = SPELL_UNKNOWN;
|
||||
RangedProcs[j].level_override = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < _MaterialCount; i++)
|
||||
@@ -311,7 +339,7 @@ Mob::Mob(const char* in_name,
|
||||
pLastChange = 0;
|
||||
SetPetID(0);
|
||||
SetOwnerID(0);
|
||||
typeofpet = petCharmed; //default to charmed...
|
||||
typeofpet = petNone; // default to not a pet
|
||||
petpower = 0;
|
||||
held = false;
|
||||
nocast = false;
|
||||
@@ -531,48 +559,32 @@ bool Mob::IsInvisible(Mob* other) const
|
||||
return(false);
|
||||
}
|
||||
|
||||
float Mob::_GetMovementSpeed(int mod) const
|
||||
{
|
||||
// List of movement speed modifiers, including AAs & spells:
|
||||
// http://everquest.allakhazam.com/db/item.html?item=1721;page=1;howmany=50#m10822246245352
|
||||
if (IsRooted())
|
||||
return 0.0f;
|
||||
int Mob::_GetWalkSpeed() const {
|
||||
|
||||
if (IsRooted() || IsStunned() || IsMezzed())
|
||||
return 0;
|
||||
|
||||
else if (IsPseudoRooted())
|
||||
return 0.00001f;
|
||||
return 0;
|
||||
|
||||
float speed_mod = runspeed;
|
||||
int aa_mod = 0;
|
||||
int speed_mod = base_walkspeed;
|
||||
int base_run = base_runspeed;
|
||||
bool has_horse = false;
|
||||
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
|
||||
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
aa_mod += aabonuses.BaseMovementSpeed;
|
||||
|
||||
// These two cases ignore the cap, be wise in the DB for horses.
|
||||
if (IsClient()) {
|
||||
if (CastToClient()->GetGMSpeed()) {
|
||||
speed_mod = 3.125f;
|
||||
if (mod != 0)
|
||||
speed_mod += speed_mod * static_cast<float>(mod) / 100.0f;
|
||||
Mob *horse = entity_list.GetMob(CastToClient()->GetHorseId());
|
||||
if (horse) {
|
||||
speed_mod = horse->GetBaseRunspeed();
|
||||
return speed_mod;
|
||||
} else {
|
||||
Mob *horse = entity_list.GetMob(CastToClient()->GetHorseId());
|
||||
if (horse) {
|
||||
speed_mod = horse->GetBaseRunspeed();
|
||||
if (mod != 0)
|
||||
speed_mod += speed_mod * static_cast<float>(mod) / 100.0f;
|
||||
return speed_mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int aa_mod = 0;
|
||||
int spell_mod = 0;
|
||||
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
|
||||
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
int movemod = 0;
|
||||
float frunspeedcap = 0.0f;
|
||||
|
||||
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
aa_mod += itembonuses.BaseMovementSpeed + spellbonuses.BaseMovementSpeed + aabonuses.BaseMovementSpeed;
|
||||
spell_mod += spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
|
||||
// hard cap
|
||||
if (runspeedcap > 225)
|
||||
runspeedcap = 225;
|
||||
|
||||
if (spell_mod < 0)
|
||||
movemod += spell_mod;
|
||||
@@ -581,27 +593,189 @@ float Mob::_GetMovementSpeed(int mod) const
|
||||
else
|
||||
movemod = aa_mod;
|
||||
|
||||
// cap negative movemods from snares mostly
|
||||
if (movemod < -85)
|
||||
// hard cap
|
||||
if (runspeedcap > 225)
|
||||
runspeedcap = 225;
|
||||
|
||||
if(movemod < -85) //cap it at moving very very slow
|
||||
movemod = -85;
|
||||
|
||||
if (movemod != 0)
|
||||
speed_mod += speed_mod * static_cast<float>(movemod) / 100.0f;
|
||||
if (!has_horse && movemod != 0)
|
||||
speed_mod += (base_run * movemod / 100);
|
||||
|
||||
// runspeed caps
|
||||
frunspeedcap = static_cast<float>(runspeedcap) / 100.0f;
|
||||
if (IsClient() && speed_mod > frunspeedcap)
|
||||
speed_mod = frunspeedcap;
|
||||
if(speed_mod < 1)
|
||||
return(0);
|
||||
|
||||
// apply final mod such as the -47 for walking
|
||||
// use runspeed since it should stack with snares
|
||||
// and if we get here, we know runspeed was the initial
|
||||
// value before we applied movemod.
|
||||
if (mod != 0)
|
||||
speed_mod += runspeed * static_cast<float>(mod) / 100.0f;
|
||||
//runspeed cap.
|
||||
if(IsClient())
|
||||
{
|
||||
if(speed_mod > runspeedcap)
|
||||
speed_mod = runspeedcap;
|
||||
}
|
||||
return speed_mod;
|
||||
}
|
||||
|
||||
if (speed_mod <= 0.0f)
|
||||
speed_mod = IsClient() ? 0.0001f : 0.0f;
|
||||
int Mob::_GetRunSpeed() const {
|
||||
if (IsRooted() || IsStunned() || IsMezzed() || IsPseudoRooted())
|
||||
return 0;
|
||||
|
||||
int aa_mod = 0;
|
||||
int speed_mod = base_runspeed;
|
||||
int base_walk = base_walkspeed;
|
||||
bool has_horse = false;
|
||||
if (IsClient())
|
||||
{
|
||||
if(CastToClient()->GetGMSpeed())
|
||||
{
|
||||
speed_mod = 325;
|
||||
}
|
||||
else
|
||||
{
|
||||
Mob* horse = entity_list.GetMob(CastToClient()->GetHorseId());
|
||||
if(horse)
|
||||
{
|
||||
speed_mod = horse->GetBaseRunspeed();
|
||||
base_walk = horse->GetBaseWalkspeed();
|
||||
has_horse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
|
||||
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
|
||||
aa_mod = itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
int movemod = 0;
|
||||
|
||||
if(spell_mod < 0)
|
||||
{
|
||||
movemod += spell_mod;
|
||||
}
|
||||
else if(spell_mod > aa_mod)
|
||||
{
|
||||
movemod = spell_mod;
|
||||
}
|
||||
else
|
||||
{
|
||||
movemod = aa_mod;
|
||||
}
|
||||
|
||||
if(movemod < -85) //cap it at moving very very slow
|
||||
movemod = -85;
|
||||
|
||||
if (!has_horse && movemod != 0)
|
||||
{
|
||||
if (IsClient())
|
||||
{
|
||||
speed_mod += (speed_mod * movemod / 100);
|
||||
} else {
|
||||
if (movemod < 0) {
|
||||
speed_mod += (50 * movemod / 100);
|
||||
// basically stoped
|
||||
if(speed_mod < 1)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
// moving slowly
|
||||
if (speed_mod < 8)
|
||||
return(8);
|
||||
} else {
|
||||
speed_mod += GetBaseWalkspeed();
|
||||
if (movemod > 50)
|
||||
speed_mod += 4;
|
||||
if (movemod > 40)
|
||||
speed_mod += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(speed_mod < 1)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
//runspeed cap.
|
||||
if(IsClient())
|
||||
{
|
||||
if(speed_mod > runspeedcap)
|
||||
speed_mod = runspeedcap;
|
||||
}
|
||||
return speed_mod;
|
||||
}
|
||||
|
||||
int Mob::_GetFearSpeed() const {
|
||||
|
||||
if (IsRooted() || IsStunned() || IsMezzed())
|
||||
return 0;
|
||||
|
||||
//float speed_mod = fearspeed;
|
||||
int speed_mod = GetBaseFearSpeed();
|
||||
|
||||
// use a max of 1.75f in calcs.
|
||||
int base_run = std::min(GetBaseRunspeed(), 70);
|
||||
|
||||
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
int movemod = 0;
|
||||
|
||||
if(spell_mod < 0)
|
||||
{
|
||||
movemod += spell_mod;
|
||||
}
|
||||
|
||||
if(movemod < -85) //cap it at moving very very slow
|
||||
movemod = -85;
|
||||
|
||||
if (IsClient()) {
|
||||
if (CastToClient()->IsRunning())
|
||||
speed_mod = GetBaseRunspeed();
|
||||
else
|
||||
speed_mod = GetBaseWalkspeed();
|
||||
if (movemod < 0)
|
||||
return GetBaseWalkspeed();
|
||||
speed_mod += (base_run * movemod / 100);
|
||||
return speed_mod;
|
||||
} else {
|
||||
int hp_ratio = GetIntHPRatio();
|
||||
// very large snares 50% or higher
|
||||
if (movemod < -49)
|
||||
{
|
||||
if (hp_ratio < 25)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
if (hp_ratio < 50)
|
||||
return (8);
|
||||
else
|
||||
return (12);
|
||||
}
|
||||
if (hp_ratio < 5) {
|
||||
speed_mod = base_walkspeed / 3;
|
||||
} else if (hp_ratio < 15) {
|
||||
speed_mod = base_walkspeed / 2;
|
||||
} else if (hp_ratio < 25) {
|
||||
speed_mod = base_walkspeed + 1; // add the +1 so they do the run animation
|
||||
} else if (hp_ratio < 50) {
|
||||
speed_mod *= 82;
|
||||
speed_mod /= 100;
|
||||
}
|
||||
if (movemod > 0) {
|
||||
speed_mod += GetBaseWalkspeed();
|
||||
if (movemod > 50)
|
||||
speed_mod += 4;
|
||||
if (movemod > 40)
|
||||
speed_mod += 3;
|
||||
return speed_mod;
|
||||
}
|
||||
else if (movemod < 0) {
|
||||
speed_mod += (base_run * movemod / 100);
|
||||
}
|
||||
}
|
||||
if (speed_mod < 1)
|
||||
return (0);
|
||||
if (speed_mod < 9)
|
||||
return (8);
|
||||
if (speed_mod < 13)
|
||||
return (12);
|
||||
|
||||
return speed_mod;
|
||||
}
|
||||
@@ -740,7 +914,7 @@ void Mob::CreateSpawnPacket(EQApplicationPacket* app, Mob* ForWho) {
|
||||
NewSpawn_Struct* ns = (NewSpawn_Struct*)app->pBuffer;
|
||||
FillSpawnStruct(ns, ForWho);
|
||||
|
||||
if(strlen(ns->spawn.lastName) == 0)
|
||||
if(strlen(ns->spawn.lastName) == 0)
|
||||
{
|
||||
switch(ns->spawn.class_)
|
||||
{
|
||||
@@ -916,6 +1090,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.class_ = class_;
|
||||
ns->spawn.gender = gender;
|
||||
ns->spawn.level = level;
|
||||
ns->spawn.PlayerState = m_PlayerState;
|
||||
ns->spawn.deity = deity;
|
||||
ns->spawn.animation = 0;
|
||||
ns->spawn.findable = findable?1:0;
|
||||
@@ -1092,7 +1267,7 @@ void Mob::CreateHPPacket(EQApplicationPacket* app)
|
||||
}
|
||||
|
||||
// sends hp update of this mob to people who might care
|
||||
void Mob::SendHPUpdate()
|
||||
void Mob::SendHPUpdate(bool skip_self)
|
||||
{
|
||||
EQApplicationPacket hp_app;
|
||||
Group *group;
|
||||
@@ -1181,8 +1356,7 @@ void Mob::SendHPUpdate()
|
||||
}
|
||||
|
||||
// send to self - we need the actual hps here
|
||||
if(IsClient())
|
||||
{
|
||||
if(IsClient() && !skip_self) {
|
||||
EQApplicationPacket* hp_app2 = new EQApplicationPacket(OP_HPUpdate,sizeof(SpawnHPUpdate_Struct));
|
||||
SpawnHPUpdate_Struct* ds = (SpawnHPUpdate_Struct*)hp_app2->pBuffer;
|
||||
ds->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
|
||||
@@ -1191,6 +1365,7 @@ void Mob::SendHPUpdate()
|
||||
CastToClient()->QueuePacket(hp_app2);
|
||||
safe_delete(hp_app2);
|
||||
}
|
||||
ResetHPUpdateTimer(); // delay the timer
|
||||
}
|
||||
|
||||
// this one just warps the mob to the current location
|
||||
@@ -1301,7 +1476,7 @@ void Mob::ShowStats(Client* client)
|
||||
if(n->respawn2 != 0)
|
||||
spawngroupid = n->respawn2->SpawnGroupID();
|
||||
client->Message(0, " NPCID: %u SpawnGroupID: %u Grid: %i LootTable: %u FactionID: %i SpellsID: %u ", GetNPCTypeID(),spawngroupid, n->GetGrid(), n->GetLoottableID(), n->GetNPCFactionID(), n->GetNPCSpellsID());
|
||||
client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %f Walkspeed: %f", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), n->GetRunspeed(), n->GetWalkspeed());
|
||||
client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %u Walkspeed: %u", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), n->GetRunspeed(), n->GetWalkspeed());
|
||||
n->QueryLoot(client);
|
||||
}
|
||||
if (IsAIControlled()) {
|
||||
@@ -1788,7 +1963,7 @@ bool Mob::IsPlayerRace(uint16 in_race) {
|
||||
|
||||
|
||||
uint8 Mob::GetDefaultGender(uint16 in_race, uint8 in_gender) {
|
||||
if (Mob::IsPlayerRace(in_race) || in_race == 15 || in_race == 50 || in_race == 57 || in_race == 70 || in_race == 98 || in_race == 118) {
|
||||
if (Mob::IsPlayerRace(in_race) || in_race == 15 || in_race == 50 || in_race == 57 || in_race == 70 || in_race == 98 || in_race == 118 || in_race == 23) {
|
||||
if (in_gender >= 2) {
|
||||
// Male default for PC Races
|
||||
return 0;
|
||||
@@ -1909,22 +2084,6 @@ void Mob::SendTargetable(bool on, Client *specific_target) {
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Mob::QuestReward(Client *c, uint32 silver, uint32 gold, uint32 platinum) {
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct));
|
||||
QuestReward_Struct* qr = (QuestReward_Struct*) outapp->pBuffer;
|
||||
|
||||
qr->from_mob = GetID(); // Entity ID for the from mob name
|
||||
qr->silver = silver;
|
||||
qr->gold = gold;
|
||||
qr->platinum = platinum;
|
||||
|
||||
if(c)
|
||||
c->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Mob::CameraEffect(uint32 duration, uint32 intensity, Client *c, bool global) {
|
||||
|
||||
|
||||
@@ -2041,12 +2200,12 @@ const int32& Mob::SetMana(int32 amount)
|
||||
|
||||
|
||||
void Mob::SetAppearance(EmuAppearance app, bool iIgnoreSelf) {
|
||||
if (_appearance != app) {
|
||||
_appearance = app;
|
||||
SendAppearancePacket(AT_Anim, GetAppearanceValue(app), true, iIgnoreSelf);
|
||||
if (this->IsClient() && this->IsAIControlled())
|
||||
SendAppearancePacket(AT_Anim, ANIM_FREEZE, false, false);
|
||||
}
|
||||
if (_appearance == app)
|
||||
return;
|
||||
_appearance = app;
|
||||
SendAppearancePacket(AT_Anim, GetAppearanceValue(app), true, iIgnoreSelf);
|
||||
if (this->IsClient() && this->IsAIControlled())
|
||||
SendAppearancePacket(AT_Anim, ANIM_FREEZE, false, false);
|
||||
}
|
||||
|
||||
bool Mob::UpdateActiveLight()
|
||||
@@ -2138,8 +2297,10 @@ void Mob::SetOwnerID(uint16 NewOwnerID) {
|
||||
if (NewOwnerID == GetID() && NewOwnerID != 0) // ok, no charming yourself now =p
|
||||
return;
|
||||
ownerid = NewOwnerID;
|
||||
if (ownerid == 0 && this->IsNPC() && this->GetPetType() != petCharmed)
|
||||
this->Depop();
|
||||
// if we're setting the owner ID to 0 and they're not either charmed or not-a-pet then
|
||||
// they're a normal pet and should be despawned
|
||||
if (ownerid == 0 && IsNPC() && GetPetType() != petCharmed && GetPetType() != petNone)
|
||||
Depop();
|
||||
}
|
||||
|
||||
// used in checking for behind (backstab) and checking in front (melee LoS)
|
||||
@@ -2553,7 +2714,35 @@ uint32 NPC::GetEquipment(uint8 material_slot) const
|
||||
return equipment[invslot];
|
||||
}
|
||||
|
||||
void Mob::SendWearChange(uint8 material_slot)
|
||||
void Mob::SendArmorAppearance(Client *one_client)
|
||||
{
|
||||
// one_client of 0 means sent to all clients
|
||||
//
|
||||
// Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the
|
||||
// armor being worn and its mats, the client doesn't update the display
|
||||
// on arrival of these packets reliably.
|
||||
//
|
||||
// Send Wear changes if mob is a PC race and item is an armor slot.
|
||||
// The other packets work for primary/secondary.
|
||||
|
||||
if (IsPlayerRace(race))
|
||||
{
|
||||
if (!IsClient())
|
||||
{
|
||||
const Item_Struct *item;
|
||||
for (int i=0; i< 7 ; ++i)
|
||||
{
|
||||
item=database.GetItem(GetEquipment(i));
|
||||
if (item != 0)
|
||||
{
|
||||
SendWearChange(i,one_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SendWearChange(uint8 material_slot, Client *one_client)
|
||||
{
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer;
|
||||
@@ -2565,7 +2754,15 @@ void Mob::SendWearChange(uint8 material_slot)
|
||||
wc->color.Color = GetEquipmentColor(material_slot);
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
if (!one_client)
|
||||
{
|
||||
entity_list.QueueClients(this, outapp);
|
||||
}
|
||||
else
|
||||
{
|
||||
one_client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
@@ -2691,7 +2888,7 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const
|
||||
const ItemData *item;
|
||||
item = database.GetItem(GetEquipment(material_slot));
|
||||
int16 invslot = InventoryOld::CalcSlotFromMaterial(material_slot);
|
||||
|
||||
|
||||
if (item != 0 && invslot != INVALID_INDEX)
|
||||
{
|
||||
if (IsClient())
|
||||
@@ -2949,10 +3146,10 @@ uint32 Mob::GetLevelHP(uint8 tlevel)
|
||||
}
|
||||
|
||||
int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime) {
|
||||
|
||||
|
||||
int32 cast_reducer = 0;
|
||||
cast_reducer += GetFocusEffect(focusSpellHaste, spell_id);
|
||||
|
||||
|
||||
if (level >= 60 && casttime > 1000)
|
||||
{
|
||||
casttime = casttime / 2;
|
||||
@@ -2970,7 +3167,7 @@ int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime) {
|
||||
return casttime;
|
||||
}
|
||||
|
||||
void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on) {
|
||||
void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on, int level_override) {
|
||||
// Changed proc targets to look up based on the spells goodEffect flag.
|
||||
// This should work for the majority of weapons.
|
||||
if(spell_id == SPELL_UNKNOWN || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
||||
@@ -3009,14 +3206,14 @@ void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on) {
|
||||
twinproc = true;
|
||||
|
||||
if (IsBeneficialSpell(spell_id)) {
|
||||
SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff, true);
|
||||
SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff, true, level_override);
|
||||
if(twinproc)
|
||||
SpellOnTarget(spell_id, this, false, false, 0, true);
|
||||
SpellOnTarget(spell_id, this, false, false, 0, true, level_override);
|
||||
}
|
||||
else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients
|
||||
SpellFinished(spell_id, on, 10, 0, -1, spells[spell_id].ResistDiff, true);
|
||||
SpellFinished(spell_id, on, 10, 0, -1, spells[spell_id].ResistDiff, true, level_override);
|
||||
if(twinproc)
|
||||
SpellOnTarget(spell_id, on, false, false, 0, true);
|
||||
SpellOnTarget(spell_id, on, false, false, 0, true, level_override);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3566,7 +3763,7 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)
|
||||
// All skill dmg mod + Skill specific
|
||||
skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] +
|
||||
itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used];
|
||||
|
||||
|
||||
|
||||
skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1];
|
||||
|
||||
@@ -4006,6 +4203,39 @@ int32 Mob::GetItemStat(uint32 itemid, const char *identifier)
|
||||
return stat;
|
||||
}
|
||||
|
||||
std::string Mob::GetGlobal(const char *varname) {
|
||||
int qgCharid = 0;
|
||||
int qgNpcid = 0;
|
||||
|
||||
if (this->IsNPC())
|
||||
qgNpcid = this->GetNPCTypeID();
|
||||
|
||||
if (this->IsClient())
|
||||
qgCharid = this->CastToClient()->CharacterID();
|
||||
|
||||
QGlobalCache *qglobals = nullptr;
|
||||
std::list<QGlobal> globalMap;
|
||||
|
||||
if (this->IsClient())
|
||||
qglobals = this->CastToClient()->GetQGlobals();
|
||||
|
||||
if (this->IsNPC())
|
||||
qglobals = this->CastToNPC()->GetQGlobals();
|
||||
|
||||
if(qglobals)
|
||||
QGlobalCache::Combine(globalMap, qglobals->GetBucket(), qgNpcid, qgCharid, zone->GetZoneID());
|
||||
|
||||
std::list<QGlobal>::iterator iter = globalMap.begin();
|
||||
while(iter != globalMap.end()) {
|
||||
if ((*iter).name.compare(varname) == 0)
|
||||
return (*iter).value;
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
return "Undefined";
|
||||
}
|
||||
|
||||
void Mob::SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Mob *other) {
|
||||
|
||||
int qgZoneid = zone->GetZoneID();
|
||||
@@ -5284,7 +5514,7 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
|
||||
|
||||
if (slot < 4){
|
||||
if (id == "components") { return spells[spell_id].components[slot];}
|
||||
else if (id == "component_counts") { return spells[spell_id].component_counts[slot];}
|
||||
else if (id == "component_counts") { return spells[spell_id].component_counts[slot];}
|
||||
else if (id == "NoexpendReagent") {return spells[spell_id].NoexpendReagent[slot];}
|
||||
}
|
||||
|
||||
@@ -5362,7 +5592,7 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
|
||||
else if (id == "max_dist") {return static_cast<int32>(spells[spell_id].max_dist); }
|
||||
else if (id == "min_range") {return static_cast<int32>(spells[spell_id].min_range); }
|
||||
else if (id == "DamageShieldType") {return spells[spell_id].DamageShieldType; }
|
||||
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
@@ -5382,9 +5612,48 @@ bool Mob::CanClassEquipItem(uint32 item_id)
|
||||
|
||||
int bitmask = 1;
|
||||
bitmask = bitmask << (GetClass() - 1);
|
||||
|
||||
|
||||
if(!(itm->Classes & bitmask))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mob::SendAddPlayerState(PlayerState new_state)
|
||||
{
|
||||
auto app = new EQApplicationPacket(OP_PlayerStateAdd, sizeof(PlayerState_Struct));
|
||||
auto ps = (PlayerState_Struct *)app->pBuffer;
|
||||
|
||||
ps->spawn_id = GetID();
|
||||
ps->state = static_cast<uint32>(new_state);
|
||||
|
||||
AddPlayerState(ps->state);
|
||||
entity_list.QueueClients(nullptr, app);
|
||||
safe_delete(app);
|
||||
}
|
||||
|
||||
void Mob::SendRemovePlayerState(PlayerState old_state)
|
||||
{
|
||||
auto app = new EQApplicationPacket(OP_PlayerStateRemove, sizeof(PlayerState_Struct));
|
||||
auto ps = (PlayerState_Struct *)app->pBuffer;
|
||||
|
||||
ps->spawn_id = GetID();
|
||||
ps->state = static_cast<uint32>(old_state);
|
||||
|
||||
RemovePlayerState(ps->state);
|
||||
entity_list.QueueClients(nullptr, app);
|
||||
safe_delete(app);
|
||||
}
|
||||
|
||||
void Mob::SetCurrentSpeed(int in){
|
||||
if (current_speed != in)
|
||||
{
|
||||
current_speed = in;
|
||||
tar_ndx = 20;
|
||||
if (in == 0) {
|
||||
SetRunAnimSpeed(0);
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+46
-21
@@ -172,7 +172,8 @@ public:
|
||||
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5,
|
||||
Client *specific_target=nullptr);
|
||||
void SendTargetable(bool on, Client *specific_target = nullptr);
|
||||
virtual void SendWearChange(uint8 material_slot);
|
||||
virtual void SendArmorAppearance(Client *one_client = nullptr);
|
||||
virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr);
|
||||
virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0,
|
||||
uint32 unknown06 = 0, uint32 unknown18 = 0);
|
||||
virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint);
|
||||
@@ -200,7 +201,7 @@ public:
|
||||
bool IsBeneficialAllowed(Mob *target);
|
||||
virtual int GetCasterLevel(uint16 spell_id);
|
||||
void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0,
|
||||
uint8 WornType = 0, uint32 ticsremaining = 0, int buffslot = -1,
|
||||
uint8 WornType = 0, int32 ticsremaining = 0, int buffslot = -1, int instrument_mod = 10,
|
||||
bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0);
|
||||
void NegateSpellsBonuses(uint16 spell_id);
|
||||
virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false);
|
||||
@@ -211,7 +212,8 @@ public:
|
||||
virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration);
|
||||
virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime);
|
||||
float ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override = false,
|
||||
int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false);
|
||||
int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false,
|
||||
int level_override = -1);
|
||||
int ResistPhysical(int level_diff, uint8 caster_level);
|
||||
uint16 GetSpecializeSkillValue(uint16 spell_id) const;
|
||||
void SendSpellBarDisable();
|
||||
@@ -227,10 +229,10 @@ public:
|
||||
void CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, uint16 mana_used,
|
||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
|
||||
bool SpellFinished(uint16 spell_id, Mob *target, uint16 slot = 10, uint16 mana_used = 0,
|
||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false);
|
||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
|
||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect = false,
|
||||
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false);
|
||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
|
||||
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
|
||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1);
|
||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center,
|
||||
CastAction_type &CastAction);
|
||||
virtual bool CheckFizzle(uint16 spell_id);
|
||||
@@ -253,7 +255,7 @@ public:
|
||||
|
||||
//Buff
|
||||
void BuffProcess();
|
||||
virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0);
|
||||
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
|
||||
void BuffFadeBySpellID(uint16 spell_id);
|
||||
void BuffFadeByEffect(int effectid, int skipslot = -1);
|
||||
void BuffFadeAll();
|
||||
@@ -364,6 +366,7 @@ public:
|
||||
inline Mob* GetTarget() const { return target; }
|
||||
virtual void SetTarget(Mob* mob);
|
||||
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); }
|
||||
virtual inline float GetIntHPRatio() const { return max_hp == 0 ? 0 : (cur_hp/max_hp*100); }
|
||||
inline virtual int32 GetAC() const { return AC + itembonuses.AC + spellbonuses.AC; }
|
||||
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; }
|
||||
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
|
||||
@@ -441,9 +444,12 @@ public:
|
||||
virtual void SetMoving(bool move) { moving = move; m_Delta = glm::vec4(); }
|
||||
virtual void GoToBind(uint8 bindnum = 0) { }
|
||||
virtual void Gate();
|
||||
float GetWalkspeed() const { return(_GetMovementSpeed(-47)); }
|
||||
float GetRunspeed() const { return(_GetMovementSpeed(0)); }
|
||||
float GetBaseRunspeed() const { return runspeed; }
|
||||
int GetWalkspeed() const { return(_GetWalkSpeed()); }
|
||||
int GetRunspeed() const { return(_GetRunSpeed()); }
|
||||
void SetCurrentSpeed(int in);
|
||||
int GetBaseRunspeed() const { return base_runspeed; }
|
||||
int GetBaseWalkspeed() const { return base_walkspeed; }
|
||||
int GetBaseFearSpeed() const { return base_fearspeed; }
|
||||
float GetMovespeed() const { return IsRunning() ? GetRunspeed() : GetWalkspeed(); }
|
||||
bool IsRunning() const { return m_is_running; }
|
||||
void SetRunning(bool val) { m_is_running = val; }
|
||||
@@ -493,7 +499,6 @@ public:
|
||||
inline bool CheckLastLosState() const { return last_los_check; }
|
||||
|
||||
//Quest
|
||||
void QuestReward(Client *c = nullptr, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0);
|
||||
void CameraEffect(uint32 duration, uint32 intensity, Client *c = nullptr, bool global = false);
|
||||
inline bool GetQglobal() const { return qglobal; }
|
||||
|
||||
@@ -504,7 +509,8 @@ public:
|
||||
static void CreateSpawnPacket(EQApplicationPacket* app, NewSpawn_Struct* ns);
|
||||
virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
|
||||
void CreateHPPacket(EQApplicationPacket* app);
|
||||
void SendHPUpdate();
|
||||
void SendHPUpdate(bool skip_self = false);
|
||||
virtual void ResetHPUpdateTimer() {}; // does nothing
|
||||
|
||||
//Util
|
||||
static uint32 RandomTimer(int min, int max);
|
||||
@@ -533,7 +539,7 @@ public:
|
||||
bool HasDefensiveProcs() const;
|
||||
bool HasSkillProcs() const;
|
||||
bool HasSkillProcSuccess() const;
|
||||
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
|
||||
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN, int level_override = -1);
|
||||
bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false);
|
||||
bool HasProcs() const;
|
||||
bool IsCombatProc(uint16 spell_id);
|
||||
@@ -802,9 +808,8 @@ public:
|
||||
|
||||
//old fear function
|
||||
//void SetFeared(Mob *caster, uint32 duration, bool flee = false);
|
||||
float GetFearSpeed();
|
||||
bool IsFeared() { return curfp; } // This returns true if the mob is feared or fleeing due to low HP
|
||||
//old fear: inline void StartFleeing() { SetFeared(GetHateTop(), FLEE_RUN_DURATION, true); }
|
||||
int GetFearSpeed() { return _GetFearSpeed(); }
|
||||
bool IsFeared() { return (spellbonuses.IsFeared || flee_mode); } // This returns true if the mob is feared or fleeing due to low HP
|
||||
inline void StartFleeing() { flee_mode = true; CalculateNewFearpoint(); }
|
||||
void ProcessFlee();
|
||||
void CheckFlee();
|
||||
@@ -812,8 +817,8 @@ public:
|
||||
|
||||
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
|
||||
float CalculateHeadingToTarget(float in_x, float in_y);
|
||||
bool CalculateNewPosition(float x, float y, float z, float speed, bool checkZ = false);
|
||||
virtual bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true);
|
||||
bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = false, bool calcheading = true);
|
||||
virtual bool CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ = true, bool calcheading = true);
|
||||
float CalculateDistance(float x, float y, float z);
|
||||
float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||
void SendTo(float new_x, float new_y, float new_z);
|
||||
@@ -859,7 +864,7 @@ public:
|
||||
virtual uint32 GetAA(uint32 aa_id) const { return(0); }
|
||||
|
||||
uint32 GetInstrumentMod(uint16 spell_id) const;
|
||||
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, Mob *caster = nullptr, int ticsremaining = 0);
|
||||
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0);
|
||||
int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0);
|
||||
virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1);
|
||||
uint32 GetCastedSpellInvSlot() const { return casting_spell_inventory_slot; }
|
||||
@@ -884,6 +889,8 @@ public:
|
||||
Timer *GetSpecialAbilityTimer(int ability);
|
||||
void ClearSpecialAbilities();
|
||||
void ProcessSpecialAbilities(const std::string &str);
|
||||
bool IsMoved() { return moved; }
|
||||
void SetMoved(bool moveflag) { moved = moveflag; }
|
||||
|
||||
Shielders_Struct shielder[MAX_SHIELDERS];
|
||||
Trade* trade;
|
||||
@@ -906,6 +913,7 @@ public:
|
||||
inline virtual bool IsBlockedBuff(int16 SpellID) { return false; }
|
||||
inline virtual bool IsBlockedPetBuff(int16 SpellID) { return false; }
|
||||
|
||||
std::string GetGlobal(const char *varname);
|
||||
void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Mob *other = nullptr);
|
||||
void TarGlobal(const char *varname, const char *value, const char *duration, int npcid, int charid, int zoneid);
|
||||
void DelGlobal(const char *varname);
|
||||
@@ -956,7 +964,10 @@ protected:
|
||||
void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic);
|
||||
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
||||
float _GetMovementSpeed(int mod) const;
|
||||
virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool checkZ);
|
||||
int _GetWalkSpeed() const;
|
||||
int _GetRunSpeed() const;
|
||||
int _GetFearSpeed() const;
|
||||
virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ);
|
||||
|
||||
virtual bool AI_EngagedCastCheck() { return(false); }
|
||||
virtual bool AI_PursueCastCheck() { return(false); }
|
||||
@@ -1030,6 +1041,13 @@ protected:
|
||||
uint32 follow_dist;
|
||||
bool no_target_hotkey;
|
||||
|
||||
uint32 m_PlayerState;
|
||||
uint32 GetPlayerState() { return m_PlayerState; }
|
||||
void AddPlayerState(uint32 new_state) { m_PlayerState |= new_state; }
|
||||
void RemovePlayerState(uint32 old_state) { m_PlayerState &= ~old_state; }
|
||||
void SendAddPlayerState(PlayerState new_state);
|
||||
void SendRemovePlayerState(PlayerState old_state);
|
||||
|
||||
uint8 gender;
|
||||
uint16 race;
|
||||
uint8 base_gender;
|
||||
@@ -1046,6 +1064,13 @@ protected:
|
||||
float base_size;
|
||||
float size;
|
||||
float runspeed;
|
||||
float walkspeed;
|
||||
float fearspeed;
|
||||
int base_runspeed;
|
||||
int base_walkspeed;
|
||||
int base_fearspeed;
|
||||
int current_speed;
|
||||
|
||||
uint32 pLastChange;
|
||||
bool held;
|
||||
bool nocast;
|
||||
@@ -1059,7 +1084,7 @@ protected:
|
||||
void TryWeaponProc(const ItemInst* inst, const ItemData* weapon, Mob *on, uint16 hand = MainPrimary);
|
||||
void TrySpellProc(const ItemInst* inst, const ItemData* weapon, Mob *on, uint16 hand = MainPrimary);
|
||||
void TryWeaponProc(const ItemInst* weapon, Mob *on, uint16 hand = MainPrimary);
|
||||
void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on);
|
||||
void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on, int level_override = -1);
|
||||
virtual float GetProcChances(float ProcBonus, uint16 hand = MainPrimary);
|
||||
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = MainPrimary, Mob *on = nullptr);
|
||||
virtual float GetSpecialProcChances(uint16 hand);
|
||||
|
||||
+150
-157
@@ -339,9 +339,7 @@ bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
|
||||
|
||||
//stop moving if were casting a spell and were not a bard...
|
||||
if(!IsBardSong(AIspells[i].spellid)) {
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
|
||||
return CastSpell(AIspells[i].spellid, tar->GetID(), 1, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0, &(AIspells[i].resist_adjust));
|
||||
@@ -698,9 +696,7 @@ void Client::AI_SpellCast()
|
||||
{
|
||||
if(!IsBardSong(spell_to_cast))
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
|
||||
return;
|
||||
@@ -714,9 +710,7 @@ void Client::AI_SpellCast()
|
||||
{
|
||||
if(!IsBardSong(spell_to_cast))
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
|
||||
return;
|
||||
@@ -772,16 +766,13 @@ void Client::AI_Process()
|
||||
{
|
||||
if(GetTarget())
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
//continue on to attack code, ensuring that we execute the engaged code
|
||||
engaged = true;
|
||||
} else {
|
||||
if(AImovement_timer->Check()) {
|
||||
animation = GetRunspeed() * 21;
|
||||
//animation = GetFearSpeed() * 21;
|
||||
// Check if we have reached the last fear point
|
||||
if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) &&
|
||||
(std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) {
|
||||
@@ -839,16 +830,13 @@ void Client::AI_Process()
|
||||
}
|
||||
|
||||
if (AImovement_timer->Check()) {
|
||||
SetRunAnimSpeed(0);
|
||||
if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
|
||||
{
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
}
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
if(IsMoving()) {
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
tar_ndx =0;
|
||||
}
|
||||
|
||||
if(GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) {
|
||||
if(attack_timer.Check()) {
|
||||
Attack(GetTarget(), MainPrimary);
|
||||
@@ -944,28 +932,27 @@ void Client::AI_Process()
|
||||
{
|
||||
if(!IsRooted())
|
||||
{
|
||||
animation = 21 * GetRunspeed();
|
||||
if(!RuleB(Pathing, Aggro) || !zone->pathing)
|
||||
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
|
||||
else
|
||||
if(AImovement_timer->Check())
|
||||
{
|
||||
bool WaypointChanged, NodeReached;
|
||||
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(),
|
||||
GetRunspeed(), WaypointChanged, NodeReached);
|
||||
if(!RuleB(Pathing, Aggro) || !zone->pathing)
|
||||
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
|
||||
else
|
||||
{
|
||||
bool WaypointChanged, NodeReached;
|
||||
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(),
|
||||
GetRunspeed(), WaypointChanged, NodeReached);
|
||||
|
||||
if(WaypointChanged)
|
||||
tar_ndx = 20;
|
||||
if(WaypointChanged)
|
||||
tar_ndx = 20;
|
||||
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed());
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(IsMoving())
|
||||
{
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
AI_SpellCast();
|
||||
@@ -998,21 +985,23 @@ void Client::AI_Process()
|
||||
return;
|
||||
|
||||
float dist = DistanceSquared(m_Position, owner->GetPosition());
|
||||
if (dist >= 100)
|
||||
if (dist >= 400)
|
||||
{
|
||||
float speed = dist >= 225 ? GetRunspeed() : GetWalkspeed();
|
||||
animation = 21 * speed;
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
||||
if(AImovement_timer->Check())
|
||||
{
|
||||
int speed = GetWalkspeed();
|
||||
if (dist >= 5625)
|
||||
speed = GetRunspeed();
|
||||
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetHeading(owner->GetHeading());
|
||||
if(moved)
|
||||
{
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
SetRunAnimSpeed(0);
|
||||
SetCurrentSpeed(0);
|
||||
moved = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1042,9 +1031,7 @@ void Mob::AI_Process() {
|
||||
{
|
||||
if(target)
|
||||
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
moved=false;
|
||||
}
|
||||
//continue on to attack code, ensuring that we execute the engaged code
|
||||
@@ -1058,7 +1045,9 @@ void Mob::AI_Process() {
|
||||
CalculateNewFearpoint();
|
||||
}
|
||||
if(!RuleB(Pathing, Fear) || !zone->pathing)
|
||||
{
|
||||
CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool WaypointChanged, NodeReached;
|
||||
@@ -1084,6 +1073,8 @@ void Mob::AI_Process() {
|
||||
|
||||
if (engaged)
|
||||
{
|
||||
if (!(m_PlayerState & static_cast<uint32>(PlayerState::Aggressive)))
|
||||
SendAddPlayerState(PlayerState::Aggressive);
|
||||
// we are prevented from getting here if we are blind and don't have a target in range
|
||||
// from above, so no extra blind checks needed
|
||||
if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind())
|
||||
@@ -1114,7 +1105,7 @@ void Mob::AI_Process() {
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
if (IsPet() && GetOwner()->IsBot() && target == GetOwner())
|
||||
if (IsPet() && GetOwner() && GetOwner()->IsBot() && target == GetOwner())
|
||||
{
|
||||
// this blocks all pet attacks against owner..bot pet test (copied above check)
|
||||
RemoveFromHateList(this);
|
||||
@@ -1154,15 +1145,21 @@ void Mob::AI_Process() {
|
||||
{
|
||||
if (AImovement_timer->Check())
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
|
||||
{
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
}
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
if(IsMoving())
|
||||
{
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
|
||||
SendPosition();
|
||||
tar_ndx =0;
|
||||
if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
|
||||
{
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
}
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
|
||||
//casting checked above...
|
||||
@@ -1367,7 +1364,7 @@ void Mob::AI_Process() {
|
||||
CastToNPC()->DoClassAttacks(target);
|
||||
}
|
||||
AI_EngagedCastCheck();
|
||||
} //end is within combat range
|
||||
} //end is within combat rangepet
|
||||
else {
|
||||
//we cannot reach our target...
|
||||
//underwater stuff only works with water maps in the zone!
|
||||
@@ -1423,10 +1420,7 @@ void Mob::AI_Process() {
|
||||
}
|
||||
else if(IsMoving()) {
|
||||
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
SetCurrentSpeed(0);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1435,6 +1429,8 @@ void Mob::AI_Process() {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_PlayerState & static_cast<uint32>(PlayerState::Aggressive))
|
||||
SendRemovePlayerState(PlayerState::Aggressive);
|
||||
if(AIfeignremember_timer->Check()) {
|
||||
// 6/14/06
|
||||
// Improved Feign Death Memory
|
||||
@@ -1477,7 +1473,6 @@ void Mob::AI_Process() {
|
||||
}
|
||||
else if (AImovement_timer->Check() && !IsRooted())
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
if (IsPet())
|
||||
{
|
||||
// we're a pet, do as we're told
|
||||
@@ -1496,18 +1491,18 @@ void Mob::AI_Process() {
|
||||
float dist = DistanceSquared(m_Position, owner->GetPosition());
|
||||
if (dist >= 400)
|
||||
{
|
||||
float speed = GetWalkspeed();
|
||||
int speed = GetWalkspeed();
|
||||
if (dist >= 5625)
|
||||
speed = GetRunspeed();
|
||||
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
SetCurrentSpeed(0);
|
||||
moved = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1553,19 +1548,15 @@ void Mob::AI_Process() {
|
||||
|
||||
if (dist2 >= followdist) // Default follow distance is 100
|
||||
{
|
||||
float speed = GetWalkspeed();
|
||||
int speed = GetWalkspeed();
|
||||
if (dist2 >= followdist + 150)
|
||||
speed = GetRunspeed();
|
||||
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
SendPosition();
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
}
|
||||
moved = false;
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1662,92 +1653,39 @@ void NPC::AI_DoMovement() {
|
||||
|
||||
if (gridno > 0 || cur_wp==-2) {
|
||||
if (movetimercompleted==true) { // time to pause at wp is over
|
||||
|
||||
int32 spawn_id = this->GetSpawnPointID();
|
||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||
iterator.Reset();
|
||||
Spawn2 *found_spawn = nullptr;
|
||||
|
||||
while(iterator.MoreElements())
|
||||
{
|
||||
Spawn2* cur = iterator.GetData();
|
||||
iterator.Advance();
|
||||
if(cur->GetID() == spawn_id)
|
||||
{
|
||||
found_spawn = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
CastToNPC()->Depop(true); //depop and resart spawn timer
|
||||
if(found_spawn)
|
||||
found_spawn->SetNPCPointerNull();
|
||||
}
|
||||
else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
CastToNPC()->Depop(false);//depop without spawn timer
|
||||
if(found_spawn)
|
||||
found_spawn->SetNPCPointerNull();
|
||||
}
|
||||
else {
|
||||
movetimercompleted=false;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp);
|
||||
|
||||
//if we were under quest control (with no grid), we are done now..
|
||||
if(cur_wp == -2) {
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode.");
|
||||
roamer = false;
|
||||
cur_wp = 0;
|
||||
}
|
||||
|
||||
if(GetAppearance() != eaStanding)
|
||||
SetAppearance(eaStanding, false);
|
||||
|
||||
entity_list.OpenDoorsNear(CastToNPC());
|
||||
|
||||
if(!DistractedFromGrid) {
|
||||
//kick off event_waypoint depart
|
||||
char temp[16];
|
||||
sprintf(temp, "%d", cur_wp);
|
||||
parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0);
|
||||
|
||||
//setup our next waypoint, if we are still on our normal grid
|
||||
//remember that the quest event above could have done anything it wanted with our grid
|
||||
if(gridno > 0) {
|
||||
CastToNPC()->CalculateNewWaypoint();
|
||||
}
|
||||
}
|
||||
else {
|
||||
DistractedFromGrid = false;
|
||||
}
|
||||
}
|
||||
AI_SetupNextWaypoint();
|
||||
} // endif (movetimercompleted==true)
|
||||
else if (!(AIwalking_timer->Enabled()))
|
||||
{ // currently moving
|
||||
bool doMove = true;
|
||||
if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY())
|
||||
{ // are we there yet? then stop
|
||||
Log.Out(Logs::Detail, Logs::AI, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid());
|
||||
SetWaypointPause();
|
||||
if(GetAppearance() != eaStanding)
|
||||
if (cur_wp_pause != 0) {
|
||||
SetWaypointPause();
|
||||
SetAppearance(eaStanding, false);
|
||||
SetMoving(false);
|
||||
if (m_CurrentWayPoint.w >= 0.0) {
|
||||
SetHeading(m_CurrentWayPoint.w);
|
||||
SetMoving(false);
|
||||
if (m_CurrentWayPoint.w >= 0.0) {
|
||||
SetHeading(m_CurrentWayPoint.w);
|
||||
}
|
||||
SendPosition();
|
||||
}
|
||||
SendPosition();
|
||||
|
||||
//kick off event_waypoint arrive
|
||||
char temp[16];
|
||||
sprintf(temp, "%d", cur_wp);
|
||||
parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0);
|
||||
|
||||
// start moving directly to next waypoint if we're at a 0 pause waypoint and we didn't get quest halted.
|
||||
if (!AIwalking_timer->Enabled())
|
||||
AI_SetupNextWaypoint();
|
||||
else
|
||||
doMove = false;
|
||||
// wipe feign memory since we reached our first waypoint
|
||||
if(cur_wp == 1)
|
||||
ClearFeignMemory();
|
||||
}
|
||||
else
|
||||
{ // not at waypoint yet, so keep moving
|
||||
if (doMove)
|
||||
{ // not at waypoint yet or at 0 pause WP, so keep moving
|
||||
if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0))
|
||||
CalculateNewPosition2(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true);
|
||||
else
|
||||
@@ -1775,8 +1713,7 @@ void NPC::AI_DoMovement() {
|
||||
SetGrid( 0 - GetGrid()); // revert to AI control
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "Quest pathing is finished. Resuming on grid %d", GetGrid());
|
||||
|
||||
if(GetAppearance() != eaStanding)
|
||||
SetAppearance(eaStanding, false);
|
||||
SetAppearance(eaStanding, false);
|
||||
|
||||
CalculateNewWaypoint();
|
||||
}
|
||||
@@ -1812,29 +1749,86 @@ void NPC::AI_DoMovement() {
|
||||
Log.Out(Logs::Detail, Logs::AI, "Reached guard point (%.3f,%.3f,%.3f)", m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z);
|
||||
ClearFeignMemory();
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5*5 )
|
||||
{
|
||||
SetHeading(m_GuardPoint.w);
|
||||
} else {
|
||||
FaceTarget(GetTarget());
|
||||
}
|
||||
SendPosition();
|
||||
SetCurrentSpeed(0);
|
||||
SetAppearance(GetGuardPointAnim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NPC::AI_SetupNextWaypoint() {
|
||||
int32 spawn_id = this->GetSpawnPointID();
|
||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||
iterator.Reset();
|
||||
Spawn2 *found_spawn = nullptr;
|
||||
|
||||
while (iterator.MoreElements())
|
||||
{
|
||||
Spawn2* cur = iterator.GetData();
|
||||
iterator.Advance();
|
||||
if (cur->GetID() == spawn_id)
|
||||
{
|
||||
found_spawn = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
CastToNPC()->Depop(true); //depop and restart spawn timer
|
||||
if (found_spawn)
|
||||
found_spawn->SetNPCPointerNull();
|
||||
}
|
||||
else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
CastToNPC()->Depop(false);//depop without spawn timer
|
||||
if (found_spawn)
|
||||
found_spawn->SetNPCPointerNull();
|
||||
}
|
||||
else {
|
||||
movetimercompleted = false;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp);
|
||||
|
||||
//if we were under quest control (with no grid), we are done now..
|
||||
if (cur_wp == -2) {
|
||||
Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode.");
|
||||
roamer = false;
|
||||
cur_wp = 0;
|
||||
}
|
||||
|
||||
SetAppearance(eaStanding, false);
|
||||
|
||||
entity_list.OpenDoorsNear(CastToNPC());
|
||||
|
||||
if (!DistractedFromGrid) {
|
||||
//kick off event_waypoint depart
|
||||
char temp[16];
|
||||
sprintf(temp, "%d", cur_wp);
|
||||
parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0);
|
||||
|
||||
//setup our next waypoint, if we are still on our normal grid
|
||||
//remember that the quest event above could have done anything it wanted with our grid
|
||||
if (GetGrid() > 0) {
|
||||
CastToNPC()->CalculateNewWaypoint();
|
||||
}
|
||||
}
|
||||
else {
|
||||
DistractedFromGrid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Mob that caused this may not get added to the hate list until after this function call completes
|
||||
void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
|
||||
if(GetAppearance() != eaStanding)
|
||||
{
|
||||
SetAppearance(eaStanding);
|
||||
}
|
||||
SetAppearance(eaStanding);
|
||||
|
||||
if (iYellForHelp) {
|
||||
if(IsPet()) {
|
||||
@@ -1881,9 +1875,10 @@ void Mob::AI_Event_NoLongerEngaged() {
|
||||
pLastFightingDelayMoving += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving);
|
||||
// So mobs don't keep running as a ghost until AIwalking_timer fires
|
||||
// if they were moving prior to losing all hate
|
||||
if(IsMoving()){
|
||||
// except if we're a pet, then we might run into some issues with pets backing off when they should immediately be moving
|
||||
if(!IsPet())
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
}
|
||||
ClearRampage();
|
||||
@@ -2557,11 +2552,9 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
|
||||
if (!AI_HasSpellsEffects())
|
||||
return;
|
||||
|
||||
for(int i=0; i < AIspellsEffects.size(); i++)
|
||||
{
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, 0, 0,-1,
|
||||
true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
|
||||
}
|
||||
for (int i = 0; i < AIspellsEffects.size(); i++)
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, 0, 0, -1, 10, true, AIspellsEffects[i].spelleffectid,
|
||||
AIspellsEffects[i].base, AIspellsEffects[i].limit, AIspellsEffects[i].max);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -423,6 +423,7 @@ int main(int argc, char** argv) {
|
||||
entity_list.Process();
|
||||
entity_list.MobProcess();
|
||||
entity_list.BeaconProcess();
|
||||
entity_list.EncounterProcess();
|
||||
|
||||
if (zone) {
|
||||
if(!zone->Process()) {
|
||||
|
||||
+10
-10
@@ -115,7 +115,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
knightattack_timer(1000),
|
||||
assist_timer(AIassistcheck_delay),
|
||||
qglobal_purge_timer(30000),
|
||||
sendhpupdate_timer(1000),
|
||||
sendhpupdate_timer(2000),
|
||||
enraged_timer(1000),
|
||||
taunt_timer(TauntReuseTime * 1000),
|
||||
m_SpawnPoint(position),
|
||||
@@ -522,7 +522,7 @@ void NPC::QueryLoot(Client* to)
|
||||
linker.SetItemData(item);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
|
||||
to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", item_link.c_str(), item->ID, (*cur)->min_level, (*cur)->max_level);
|
||||
}
|
||||
|
||||
@@ -569,8 +569,7 @@ bool NPC::Process()
|
||||
{
|
||||
if (IsStunned() && stunned_timer.Check())
|
||||
{
|
||||
this->stunned = false;
|
||||
this->stunned_timer.Disable();
|
||||
Mob::UnStun();
|
||||
this->spun_timer.Disable();
|
||||
}
|
||||
|
||||
@@ -651,7 +650,8 @@ bool NPC::Process()
|
||||
}
|
||||
}
|
||||
|
||||
if (sendhpupdate_timer.Check() && (IsTargeted() || (IsPet() && GetOwner() && GetOwner()->IsClient()))) {
|
||||
// we might actually want to reset in this check ... won't until issues arise at least :P
|
||||
if (sendhpupdate_timer.Check(false) && (IsTargeted() || (IsPet() && GetOwner() && GetOwner()->IsClient()))) {
|
||||
if(!IsFullHP || cur_hp<max_hp){
|
||||
SendHPUpdate();
|
||||
}
|
||||
@@ -724,7 +724,7 @@ void NPC::UpdateEquipmentLight()
|
||||
{
|
||||
m_Light.Type.Equipment = 0;
|
||||
m_Light.Level.Equipment = 0;
|
||||
|
||||
|
||||
for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) {
|
||||
if (index == MainAmmo) { continue; }
|
||||
|
||||
@@ -1933,7 +1933,7 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
|
||||
else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; }
|
||||
else if(id == "special_abilities") { ProcessSpecialAbilities(val.c_str()); return; }
|
||||
else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; }
|
||||
else if(id == "attack_delay") { attack_delay = atoi(val.c_str()); CalcBonuses(); return; }
|
||||
else if(id == "attack_delay") { attack_delay = atoi(val.c_str()); CalcBonuses(); return; }
|
||||
else if(id == "atk") { ATK = atoi(val.c_str()); return; }
|
||||
else if(id == "accuracy") { accuracy_rating = atoi(val.c_str()); return; }
|
||||
else if(id == "avoidance") { avoidance_rating = atoi(val.c_str()); return; }
|
||||
@@ -2418,7 +2418,7 @@ void NPC::DoQuestPause(Mob *other) {
|
||||
|
||||
}
|
||||
|
||||
void NPC::ChangeLastName(const char* in_lastname)
|
||||
void NPC::ChangeLastName(const char* in_lastname)
|
||||
{
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct));
|
||||
@@ -2468,9 +2468,9 @@ void NPC::DepopSwarmPets()
|
||||
}
|
||||
|
||||
if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()){
|
||||
|
||||
|
||||
Mob *targMob = entity_list.GetMob(GetPetTargetLockID());
|
||||
|
||||
|
||||
if(!targMob || (targMob && targMob->IsCorpse())){
|
||||
Kill();
|
||||
return;
|
||||
|
||||
@@ -119,6 +119,7 @@ public:
|
||||
virtual void AI_Start(uint32 iMoveDelay = 0);
|
||||
virtual void AI_Stop();
|
||||
void AI_DoMovement();
|
||||
void AI_SetupNextWaypoint();
|
||||
bool AI_AddNPCSpells(uint32 iDBSpellsID);
|
||||
bool AI_AddNPCSpellsEffects(uint32 iDBSpellsEffectsID);
|
||||
virtual bool AI_EngagedCastCheck();
|
||||
@@ -406,6 +407,7 @@ public:
|
||||
void SetHeroForgeModel(uint32 model) { herosforgemodel = model; }
|
||||
|
||||
bool IsRaidTarget() const { return raid_target; };
|
||||
void ResetHPUpdateTimer() { sendhpupdate_timer.Start(); }
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
+20
-5
@@ -485,7 +485,22 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
|
||||
buf[9] = '\0';
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(m_inst);
|
||||
parse->EventPlayer(EVENT_PLAYER_PICKUP, sender, buf, 0, &args);
|
||||
if(parse->EventPlayer(EVENT_PLAYER_PICKUP, sender, buf, this->GetID(), &args))
|
||||
{
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClickObject, sizeof(ClickObject_Struct));
|
||||
memcpy(outapp->pBuffer, click_object, sizeof(ClickObject_Struct));
|
||||
ClickObject_Struct* co = (ClickObject_Struct*)outapp->pBuffer;
|
||||
co->drop_id = 0;
|
||||
entity_list.QueueClients(nullptr, outapp, false);
|
||||
safe_delete(outapp);
|
||||
|
||||
// No longer using a tradeskill object
|
||||
sender->SetTradeskillObject(nullptr);
|
||||
user = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Transfer item to client
|
||||
sender->PutItemInInventory(MainCursor, *m_inst, false);
|
||||
@@ -809,7 +824,7 @@ void Object::SetModelName(const char* modelname)
|
||||
|
||||
void Object::SetSize(uint16 size)
|
||||
{
|
||||
m_data.unknown008 = size;
|
||||
m_data.size = size;
|
||||
EQApplicationPacket* app = new EQApplicationPacket();
|
||||
EQApplicationPacket* app2 = new EQApplicationPacket();
|
||||
this->CreateDeSpawnPacket(app);
|
||||
@@ -822,7 +837,7 @@ void Object::SetSize(uint16 size)
|
||||
|
||||
void Object::SetSolidType(uint16 solidtype)
|
||||
{
|
||||
m_data.unknown010 = solidtype;
|
||||
m_data.solidtype = solidtype;
|
||||
EQApplicationPacket* app = new EQApplicationPacket();
|
||||
EQApplicationPacket* app2 = new EQApplicationPacket();
|
||||
this->CreateDeSpawnPacket(app);
|
||||
@@ -835,12 +850,12 @@ void Object::SetSolidType(uint16 solidtype)
|
||||
|
||||
uint16 Object::GetSize()
|
||||
{
|
||||
return m_data.unknown008;
|
||||
return m_data.size;
|
||||
}
|
||||
|
||||
uint16 Object::GetSolidType()
|
||||
{
|
||||
return m_data.unknown010;
|
||||
return m_data.solidtype;
|
||||
}
|
||||
|
||||
const char* Object::GetModelName()
|
||||
|
||||
+6
-3
@@ -16,7 +16,7 @@
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
//#define PATHDEBUG
|
||||
//#define PATHDEBUG
|
||||
|
||||
extern Zone *zone;
|
||||
|
||||
@@ -205,10 +205,10 @@ glm::vec3 PathManager::GetPathNodeCoordinates(int NodeNumber, bool BestZ)
|
||||
}
|
||||
|
||||
std::deque<int> PathManager::FindRoute(int startID, int endID)
|
||||
{
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::None, "FindRoute from node %i to %i", startID, endID);
|
||||
|
||||
memset(ClosedListFlag, 0, sizeof(int) * Head.PathNodeCount);
|
||||
memset(ClosedListFlag, 0, sizeof(int) * Head.PathNodeCount);
|
||||
|
||||
std::deque<AStarNode> OpenList, ClosedList;
|
||||
|
||||
@@ -665,6 +665,9 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa
|
||||
|
||||
bool SameDestination = (To == PathingDestination);
|
||||
|
||||
if (Speed <= 0) // our speed is 0, we cant move so lets return the dest
|
||||
return To; // this will also avoid the teleports cleanly
|
||||
|
||||
int NextNode;
|
||||
|
||||
if(To == From)
|
||||
|
||||
+80
-1
@@ -6188,6 +6188,84 @@ XS(XS_Client_GetTargetRingZ)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Client_CalcEXP); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_CalcEXP)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 1 || items > 2)
|
||||
Perl_croak(aTHX_ "Usage: CalcEXP(THIS, uint8 conlevel)");
|
||||
{
|
||||
Client * THIS;
|
||||
uint8 conlevel = 0xFF;
|
||||
uint32 RETVAL;
|
||||
if(items == 2)
|
||||
conlevel = (uint16)SvUV(ST(1));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Client")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Client *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Client");
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->CalcEXP(conlevel);
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Client_QuestReward); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_QuestReward)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 1 || items > 9)
|
||||
Perl_croak(aTHX_ "Usage: Client::QuestReward(THIS, mob, copper, silver, gold, platinum, itemid, exp, faction)");
|
||||
{
|
||||
Client* THIS;
|
||||
Mob * mob = nullptr;
|
||||
int32 copper = 0;
|
||||
int32 silver = 0;
|
||||
int32 gold = 0;
|
||||
int32 platinum = 0;
|
||||
int32 itemid = 0;
|
||||
int32 exp = 0;
|
||||
bool faction = false;
|
||||
|
||||
if (sv_derived_from(ST(0), "THIS")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Client *, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type client");
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items > 1) {
|
||||
if (sv_derived_from(ST(1), "mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
mob = INT2PTR(Mob *, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "mob is not of type Mob");
|
||||
if (mob == nullptr)
|
||||
Perl_croak(aTHX_ "mob is nullptr, avoiding crash.");
|
||||
}
|
||||
if (items > 2) { copper = (int32)SvIV(ST(2)); }
|
||||
if (items > 3) { silver = (int32)SvIV(ST(3)); }
|
||||
if (items > 4) { gold = (int32)SvIV(ST(4)); }
|
||||
if (items > 5) { platinum = (int32)SvIV(ST(5)); }
|
||||
if (items > 6) { itemid = (int32)SvIV(ST(6)); }
|
||||
if (items > 7) { exp = (int32)SvIV(ST(7)); }
|
||||
if (items > 8) { faction = (bool)SvIV(ST(8)); }
|
||||
|
||||
THIS->QuestReward(mob, copper, silver, gold, platinum, itemid, exp, faction);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
@@ -6432,7 +6510,8 @@ XS(boot_Client)
|
||||
newXSproto(strcpy(buf, "GetTargetRingX"), XS_Client_GetTargetRingX, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetTargetRingY"), XS_Client_GetTargetRingY, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetTargetRingZ"), XS_Client_GetTargetRingZ, file, "$$");
|
||||
|
||||
newXSproto(strcpy(buf, "QuestReward"), XS_Client_QuestReward, file, "$$;$$$$$$$");
|
||||
newXSproto(strcpy(buf, "CalcEXP"), XS_Client_CalcEXP, file, "$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
+32
-42
@@ -7027,47 +7027,6 @@ XS(XS_Mob_SendAppearanceEffect)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_QuestReward); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_QuestReward)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 1 || items > 5)
|
||||
Perl_croak(aTHX_ "Usage: Mob::QuestReward(THIS, client, silver, gold, platinum)");
|
||||
{
|
||||
Mob * THIS;
|
||||
Client* client = nullptr;
|
||||
int32 silver = 0;
|
||||
int32 gold = 0;
|
||||
int32 platinum = 0;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items > 1) {
|
||||
if (sv_derived_from(ST(1), "Client")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
client = INT2PTR(Client *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "client is not of type Client");
|
||||
if(client == nullptr)
|
||||
Perl_croak(aTHX_ "client is nullptr, avoiding crash.");
|
||||
}
|
||||
if (items > 2) { silver = (int32)SvIV(ST(2)); }
|
||||
if (items > 3) { gold = (int32)SvIV(ST(3)); }
|
||||
if (items > 4) { platinum = (int32)SvIV(ST(4)); }
|
||||
|
||||
THIS->QuestReward(client, silver, gold, platinum);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_SetFlyMode); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_SetFlyMode)
|
||||
{
|
||||
@@ -7362,6 +7321,37 @@ XS(XS_Mob_GetItemStat)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetGlobal);
|
||||
XS(XS_Mob_GetGlobal)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 2)
|
||||
Perl_croak(aTHX_ "Usage: GetGlobal(THIS, varname)");
|
||||
{
|
||||
Mob* THIS;
|
||||
Const_char* varname = (Const_char*)SvPV_nolen(ST(1));
|
||||
std::string ret_val = "Undefined";
|
||||
Const_char* RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob *, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (THIS->GetGlobal(varname) != "Undefined")
|
||||
ret_val = THIS->GetGlobal(varname);
|
||||
|
||||
RETVAL = ret_val.c_str();
|
||||
sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_SetGlobal);
|
||||
XS(XS_Mob_SetGlobal)
|
||||
{
|
||||
@@ -8660,11 +8650,11 @@ XS(boot_Mob)
|
||||
newXSproto(strcpy(buf, "SendIllusion"), XS_Mob_SendIllusion, file, "$$;$$$$$$$$$$$$");
|
||||
newXSproto(strcpy(buf, "MakeTempPet"), XS_Mob_MakeTempPet, file, "$$;$$$$");
|
||||
newXSproto(strcpy(buf, "TypesTempPet"), XS_Mob_TypesTempPet, file, "$$;$$$$$");
|
||||
newXSproto(strcpy(buf, "QuestReward"), XS_Mob_QuestReward, file, "$$;$$$");
|
||||
newXSproto(strcpy(buf, "CameraEffect"), XS_Mob_CameraEffect, file, "$$;$$$");
|
||||
newXSproto(strcpy(buf, "SpellEffect"), XS_Mob_SpellEffect, file, "$$;$$$$$$");
|
||||
newXSproto(strcpy(buf, "TempName"), XS_Mob_TempName, file, "$:$");
|
||||
newXSproto(strcpy(buf, "GetItemStat"), XS_Mob_GetItemStat, file, "$$$");
|
||||
newXSproto(strcpy(buf, "GetGlobal"), XS_Mob_GetGlobal, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetGlobal"), XS_Mob_SetGlobal, file, "$$$$$;$");
|
||||
newXSproto(strcpy(buf, "TarGlobal"), XS_Mob_TarGlobal, file, "$$$$$$$");
|
||||
newXSproto(strcpy(buf, "DelGlobal"), XS_Mob_DelGlobal, file, "$$");
|
||||
|
||||
+34
-4
@@ -28,6 +28,10 @@
|
||||
#include "pets.h"
|
||||
#include "zonedb.h"
|
||||
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#include <stdlib.h>
|
||||
#include "../common/unix.h"
|
||||
@@ -231,6 +235,10 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);//Client only
|
||||
act_power = CastToClient()->mod_pet_power(act_power, spell_id);
|
||||
}
|
||||
#ifdef BOTS
|
||||
else if (this->IsBot())
|
||||
act_power = CastToBot()->GetBotFocusEffect(Bot::BotfocusPetPower, spell_id);
|
||||
#endif
|
||||
}
|
||||
else if (petpower > 0)
|
||||
act_power = petpower;
|
||||
@@ -260,7 +268,11 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
memcpy(npc_type, base, sizeof(NPCType));
|
||||
|
||||
// If pet power is set to -1 in the DB, use stat scaling
|
||||
if (this->IsClient() && record.petpower == -1)
|
||||
if ((this->IsClient()
|
||||
#ifdef BOTS
|
||||
|| this->IsBot()
|
||||
#endif
|
||||
) && record.petpower == -1)
|
||||
{
|
||||
float scale_power = (float)act_power / 100.0f;
|
||||
if(scale_power > 0)
|
||||
@@ -268,10 +280,10 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
npc_type->max_hp *= (1 + scale_power);
|
||||
npc_type->cur_hp = npc_type->max_hp;
|
||||
npc_type->AC *= (1 + scale_power);
|
||||
npc_type->level += 1 + ((int)act_power / 25); // gains an additional level for every 25 pet power
|
||||
npc_type->level += 1 + ((int)act_power / 25) > npc_type->level + RuleR(Pets, PetPowerLevelCap) ? RuleR(Pets, PetPowerLevelCap) : 1 + ((int)act_power / 25); // gains an additional level for every 25 pet power
|
||||
npc_type->min_dmg = (npc_type->min_dmg * (1 + (scale_power / 2)));
|
||||
npc_type->max_dmg = (npc_type->max_dmg * (1 + (scale_power / 2)));
|
||||
npc_type->size *= (1 + (scale_power / 2));
|
||||
npc_type->size = npc_type->size * (1 + (scale_power / 2)) > npc_type->size * 3 ? npc_type->size * 3 : (1 + (scale_power / 2));
|
||||
}
|
||||
record.petpower = act_power;
|
||||
}
|
||||
@@ -426,7 +438,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
entity_list.AddNPC(npc, true, true);
|
||||
SetPetID(npc->GetID());
|
||||
// We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet
|
||||
|
||||
|
||||
|
||||
if (record.petcontrol == petTargetLock)
|
||||
{
|
||||
@@ -457,6 +469,22 @@ Pet::Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 po
|
||||
// Class should use npc constructor to set light properties
|
||||
}
|
||||
|
||||
void Pet::SetTarget(Mob *mob)
|
||||
{
|
||||
if (mob == GetTarget())
|
||||
return;
|
||||
|
||||
auto owner = GetOwner();
|
||||
if (owner && owner->IsClient() && owner->CastToClient()->GetClientVersionBit() & BIT_UFAndLater) {
|
||||
auto app = new EQApplicationPacket(OP_PetHoTT, sizeof(ClientTarget_Struct));
|
||||
auto ct = (ClientTarget_Struct *)app->pBuffer;
|
||||
ct->new_target = mob ? mob->GetID() : 0;
|
||||
owner->CastToClient()->QueuePacket(app);
|
||||
safe_delete(app);
|
||||
}
|
||||
NPC::SetTarget(mob);
|
||||
}
|
||||
|
||||
bool ZoneDatabase::GetPetEntry(const char *pet_type, PetRecord *into) {
|
||||
return GetPoweredPetEntry(pet_type, 0, into);
|
||||
}
|
||||
@@ -555,6 +583,7 @@ void NPC::GetPetState(SpellBuff_Struct *pet_buffs, uint32 *items, char *name) {
|
||||
pet_buffs[i].level = buffs[i].casterlevel;
|
||||
pet_buffs[i].effect = 10;
|
||||
pet_buffs[i].counters = buffs[i].counters;
|
||||
pet_buffs[i].bard_modifier = buffs[i].instrument_mod;
|
||||
}
|
||||
else {
|
||||
pet_buffs[i].spellid = SPELL_UNKNOWN;
|
||||
@@ -588,6 +617,7 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) {
|
||||
buffs[i].casterid = 0;
|
||||
buffs[i].counters = pet_buffs[i].counters;
|
||||
buffs[i].numhits = spells[pet_buffs[i].spellid].numhits;
|
||||
buffs[i].instrument_mod = pet_buffs[i].bard_modifier;
|
||||
}
|
||||
else {
|
||||
buffs[i].spellid = SPELL_UNKNOWN;
|
||||
|
||||
@@ -39,6 +39,7 @@ struct NPCType;
|
||||
class Pet : public NPC {
|
||||
public:
|
||||
Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 power);
|
||||
virtual void SetTarget(Mob *mob);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
std::vector<EQEmu::Any> *extra_pointers) { return 0; }
|
||||
virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) { return 0; }
|
||||
virtual int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data,
|
||||
virtual int EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) { return 0; }
|
||||
|
||||
virtual bool HasQuestSub(uint32 npcid, QuestEventID evt) { return false; }
|
||||
|
||||
@@ -434,14 +434,14 @@ int QuestParserCollection::EventSpell(QuestEventID evt, NPC* npc, Client *client
|
||||
return 0;
|
||||
}
|
||||
|
||||
int QuestParserCollection::EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data,
|
||||
int QuestParserCollection::EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers) {
|
||||
auto iter = _encounter_quest_status.find(encounter_name);
|
||||
if(iter != _encounter_quest_status.end()) {
|
||||
//loaded or failed to load
|
||||
if(iter->second != QuestFailedToLoad) {
|
||||
std::map<uint32, QuestInterface*>::iterator qiter = _interfaces.find(iter->second);
|
||||
return qiter->second->EventEncounter(evt, encounter_name, extra_data, extra_pointers);
|
||||
return qiter->second->EventEncounter(evt, encounter_name, data, extra_data, extra_pointers);
|
||||
}
|
||||
} else {
|
||||
std::string filename;
|
||||
@@ -449,7 +449,7 @@ int QuestParserCollection::EventEncounter(QuestEventID evt, std::string encounte
|
||||
if(qi) {
|
||||
_encounter_quest_status[encounter_name] = qi->GetIdentifier();
|
||||
qi->LoadEncounterScript(filename, encounter_name);
|
||||
return qi->EventEncounter(evt, encounter_name, extra_data, extra_pointers);
|
||||
return qi->EventEncounter(evt, encounter_name, data, extra_data, extra_pointers);
|
||||
} else {
|
||||
_encounter_quest_status[encounter_name] = QuestFailedToLoad;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "../common/types.h"
|
||||
|
||||
#include "encounter.h"
|
||||
#include "beacon.h"
|
||||
#include "client.h"
|
||||
#include "corpse.h"
|
||||
@@ -71,7 +72,7 @@ public:
|
||||
std::vector<EQEmu::Any> *extra_pointers = nullptr);
|
||||
int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers = nullptr);
|
||||
int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data,
|
||||
int EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data,
|
||||
std::vector<EQEmu::Any> *extra_pointers = nullptr);
|
||||
|
||||
void GetErrors(std::list<std::string> &err);
|
||||
|
||||
+83
-7
@@ -84,6 +84,8 @@ void QuestManager::Process() {
|
||||
if(entity_list.IsMobInZone(cur->mob)) {
|
||||
if(cur->mob->IsNPC()) {
|
||||
parse->EventNPC(EVENT_TIMER, cur->mob->CastToNPC(), nullptr, cur->name, 0);
|
||||
} else if (cur->mob->IsEncounter()) {
|
||||
parse->EventEncounter(EVENT_TIMER, cur->mob->CastToEncounter()->GetEncounterName(), cur->name, 0, nullptr);
|
||||
} else {
|
||||
//this is inheriently unsafe if we ever make it so more than npc/client start timers
|
||||
parse->EventPlayer(EVENT_TIMER, cur->mob->CastToClient(), cur->name, 0);
|
||||
@@ -668,6 +670,79 @@ void QuestManager::repopzone() {
|
||||
}
|
||||
}
|
||||
|
||||
void QuestManager::ConnectNodeToNode(int node1, int node2, int teleport, int doorid) {
|
||||
if (!node1 || !node2)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Quests, "QuestManager::ConnectNodeToNode called without node1 or node2. Probably syntax error in quest file.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!teleport)
|
||||
{
|
||||
teleport = 0;
|
||||
}
|
||||
else if (teleport == 1 || teleport == -1)
|
||||
{
|
||||
teleport = -1;
|
||||
}
|
||||
|
||||
if (!doorid)
|
||||
{
|
||||
doorid = 0;
|
||||
}
|
||||
|
||||
if (!zone->pathing)
|
||||
{
|
||||
// if no pathing bits available, make them available.
|
||||
zone->pathing = new PathManager();
|
||||
}
|
||||
|
||||
if (zone->pathing)
|
||||
{
|
||||
zone->pathing->ConnectNodeToNode(node1, node2, teleport, doorid);
|
||||
Log.Out(Logs::Moderate, Logs::Quests, "QuestManager::ConnectNodeToNode connecting node %i to node %i.", node1, node2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QuestManager::AddNode(float x, float y, float z, float best_z, int32 requested_id)
|
||||
{
|
||||
if (!x || !y || !z)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Quests, "QuestManager::AddNode called without x, y, z. Probably syntax error in quest file.");
|
||||
}
|
||||
|
||||
if (!best_z || best_z == 0)
|
||||
{
|
||||
if (zone->zonemap)
|
||||
{
|
||||
glm::vec3 loc(x, y, z);
|
||||
best_z = zone->zonemap->FindBestZ(loc, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
best_z = z;
|
||||
}
|
||||
}
|
||||
|
||||
if (!requested_id)
|
||||
{
|
||||
requested_id = 0;
|
||||
}
|
||||
|
||||
if (!zone->pathing)
|
||||
{
|
||||
// if no pathing bits available, make them available.
|
||||
zone->pathing = new PathManager();
|
||||
}
|
||||
|
||||
if (zone->pathing)
|
||||
{
|
||||
zone->pathing->AddNode(x, y, z, best_z, requested_id);
|
||||
Log.Out(Logs::Moderate, Logs::Quests, "QuestManager::AddNode adding node at (%i, %i, %i).", x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
void QuestManager::settarget(const char *type, int target_id) {
|
||||
QuestManagerCurrentQuestVars();
|
||||
if (!owner || !owner->IsNPC())
|
||||
@@ -1219,9 +1294,10 @@ void QuestManager::CreateGuild(const char *guild_name, const char *leader) {
|
||||
}
|
||||
}
|
||||
|
||||
void QuestManager::settime(uint8 new_hour, uint8 new_min) {
|
||||
void QuestManager::settime(uint8 new_hour, uint8 new_min, bool update_world /*= true*/)
|
||||
{
|
||||
if (zone)
|
||||
zone->SetTime(new_hour + 1, new_min);
|
||||
zone->SetTime(new_hour + 1, new_min, update_world);
|
||||
}
|
||||
|
||||
void QuestManager::itemlink(int item_id) {
|
||||
@@ -1997,6 +2073,11 @@ bool QuestManager::createBot(const char *name, const char *lastname, uint8 level
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Bot::IsBotNameAvailable((char*)name,&TempErrorMessage)) {
|
||||
initiator->Message(0, "The name %s is already being used or is invalid. Please choose a different name.", (char*)name);
|
||||
return false;
|
||||
}
|
||||
|
||||
NPCType DefaultNPCTypeStruct = Bot::CreateDefaultNPCTypeStructForBot(name, lastname, level, race, botclass, gender);
|
||||
Bot* NewBot = new Bot(DefaultNPCTypeStruct, initiator);
|
||||
|
||||
@@ -2012,11 +2093,6 @@ bool QuestManager::createBot(const char *name, const char *lastname, uint8 level
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!NewBot->IsBotNameAvailable(&TempErrorMessage)) {
|
||||
initiator->Message(0, "The name %s is already being used. Please choose a different name.", NewBot->GetCleanName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!TempErrorMessage.empty()) {
|
||||
initiator->Message(13, "Database Error: %s", TempErrorMessage.c_str());
|
||||
return false;
|
||||
|
||||
+3
-1
@@ -87,6 +87,8 @@ public:
|
||||
void depopall(int npc_type = 0);
|
||||
void depopzone(bool StartSpawnTimer = true);
|
||||
void repopzone();
|
||||
void ConnectNodeToNode(int node1, int node2, int teleport, int doorid);
|
||||
void AddNode(float x, float y, float z, float best_z, int32 requested_id);
|
||||
void settarget(const char *type, int target_id);
|
||||
void follow(int entity_id, int distance);
|
||||
void sfollow();
|
||||
@@ -124,7 +126,7 @@ public:
|
||||
void setsky(uint8 new_sky);
|
||||
void setguild(uint32 new_guild_id, uint8 new_rank);
|
||||
void CreateGuild(const char *guild_name, const char *leader);
|
||||
void settime(uint8 new_hour, uint8 new_min);
|
||||
void settime(uint8 new_hour, uint8 new_min, bool update_world = true);
|
||||
void itemlink(int item_id);
|
||||
void signal(int npc_id, int wait_ms = 0);
|
||||
void signalwith(int npc_id, int signal_id, int wait_ms = 0);
|
||||
|
||||
+5
-5
@@ -624,7 +624,7 @@ void SpawnConditionManager::Process() {
|
||||
|
||||
//get our current time
|
||||
TimeOfDay_Struct tod;
|
||||
zone->zone_time.getEQTimeOfDay(&tod);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(&tod);
|
||||
|
||||
//see if time is past our nearest event.
|
||||
if(EQTime::IsTimeBefore(&next_event, &tod))
|
||||
@@ -673,7 +673,7 @@ void SpawnConditionManager::ExecEvent(SpawnEvent &event, bool send_update) {
|
||||
}
|
||||
|
||||
TimeOfDay_Struct tod;
|
||||
zone->zone_time.getEQTimeOfDay(&tod);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(&tod);
|
||||
if(event.strict && (event.next.hour != tod.hour || event.next.day != tod.day || event.next.month != tod.month || event.next.year != tod.year))
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Spawns, "Event %d: Unable to execute. Condition is strict, and event time has already passed.", event.id);
|
||||
@@ -871,7 +871,7 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
|
||||
//better solution, and I just dont care thats much.
|
||||
//get our current time
|
||||
TimeOfDay_Struct tod;
|
||||
zone->zone_time.getEQTimeOfDay(&tod);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(&tod);
|
||||
|
||||
for(auto cur = spawn_events.begin(); cur != spawn_events.end(); ++cur) {
|
||||
SpawnEvent &cevent = *cur;
|
||||
@@ -1096,7 +1096,7 @@ void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool stri
|
||||
if(reset_base) {
|
||||
Log.Out(Logs::Detail, Logs::Spawns, "Spawn event %d located in this zone. State set. Trigger time reset (period %d).", event_id, cevent.period);
|
||||
//start with the time now
|
||||
zone->zone_time.getEQTimeOfDay(&cevent.next);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(&cevent.next);
|
||||
//advance the next time by our period
|
||||
EQTime::AddMinutes(cevent.period, &cevent.next);
|
||||
} else {
|
||||
@@ -1141,7 +1141,7 @@ void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool stri
|
||||
if(reset_base) {
|
||||
Log.Out(Logs::Detail, Logs::Spawns, "Spawn event %d is in zone %s. State set. Trigger time reset (period %d). Notifying world.", event_id, zone_short_name.c_str(), e.period);
|
||||
//start with the time now
|
||||
zone->zone_time.getEQTimeOfDay(&e.next);
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(&e.next);
|
||||
//advance the next time by our period
|
||||
EQTime::AddMinutes(e.period, &e.next);
|
||||
} else {
|
||||
|
||||
+58
-49
@@ -95,7 +95,7 @@ void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg)
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime,
|
||||
void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime,
|
||||
bool HitChance, bool CanAvoid) {
|
||||
//this really should go through the same code as normal melee damage to
|
||||
//pick up all the special behavior there
|
||||
@@ -119,8 +119,12 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
||||
{
|
||||
hate += item->GetItem()->AC;
|
||||
}
|
||||
|
||||
const ItemData *itm = item->GetItem();
|
||||
hate = hate * (100 + GetFuriousBash(itm->Focus.Effect)) / 100;
|
||||
auto fbash = GetFuriousBash(itm->Focus.Effect);
|
||||
hate = hate * (100 + fbash) / 100;
|
||||
if (fbash)
|
||||
Message_StringID(MT_Spells, GLOWS_RED, itm->Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,6 +185,11 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
return;
|
||||
|
||||
CombatAbility_Struct* ca_atk = (CombatAbility_Struct*) app->pBuffer;
|
||||
pTimerType timer = pTimerCombatAbility;
|
||||
// RoF2+ Tiger Claw is unlinked from other monk skills, if they ever do that for other classes there will need
|
||||
// to be more checks here
|
||||
if (GetClientVersion() >= ClientVersion::RoF2 && ca_atk->m_skill == SkillTigerClaw)
|
||||
timer = pTimerCombatAbility2;
|
||||
|
||||
/* Check to see if actually have skill */
|
||||
if (!MaxSkill(static_cast<SkillUseTypes>(ca_atk->m_skill)))
|
||||
@@ -218,7 +227,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
if(!CombatRange(GetTarget()))
|
||||
return;
|
||||
|
||||
if(!p_timers.Expired(&database, pTimerCombatAbility, false)) {
|
||||
if(!p_timers.Expired(&database, timer, false)) {
|
||||
Message(13,"Ability recovery time not yet met.");
|
||||
return;
|
||||
}
|
||||
@@ -268,7 +277,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
DoSpecialAttackDamage(GetTarget(), SkillBash, dmg, 1, ht, ReuseTime);
|
||||
if(ReuseTime > 0)
|
||||
{
|
||||
p_timers.Start(pTimerCombatAbility, ReuseTime);
|
||||
p_timers.Start(timer, ReuseTime);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -304,7 +313,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
if(ReuseTime > 0) {
|
||||
p_timers.Start(pTimerCombatAbility, ReuseTime);
|
||||
p_timers.Start(timer, ReuseTime);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -390,7 +399,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
|
||||
ReuseTime = (ReuseTime*HasteMod)/100;
|
||||
if(ReuseTime > 0){
|
||||
p_timers.Start(pTimerCombatAbility, ReuseTime);
|
||||
p_timers.Start(timer, ReuseTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,7 +567,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
|
||||
if (level > 54) {
|
||||
|
||||
// Check for double attack with main hand assuming maxed DA Skill (MS)
|
||||
if(IsClient() && CastToClient()->CheckDoubleAttack(false))
|
||||
if(IsClient() && CastToClient()->CheckDoubleAttack(false))
|
||||
if(other->GetHP() > 0)
|
||||
RogueBackstab(other,true, ReuseTime);
|
||||
|
||||
@@ -610,11 +619,11 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
|
||||
|
||||
if(primaryweapondamage > 0){
|
||||
if(level > 25){
|
||||
max_hit = (((2*backstab_dmg) * GetDamageTable(SkillBackstab) / 100) * 10 * GetSkill(SkillBackstab) / 355) + ((level-25)/3) + 1;
|
||||
max_hit = (((((2*backstab_dmg) * GetDamageTable(SkillBackstab) / 100) * 10 * GetSkill(SkillBackstab) / 355) + ((level-25)/3) + 1) * ((100 + RuleI(Combat, BackstabBonus)) / 100));
|
||||
hate = 20 * backstab_dmg * GetSkill(SkillBackstab) / 355;
|
||||
}
|
||||
else{
|
||||
max_hit = (((2*backstab_dmg) * GetDamageTable(SkillBackstab) / 100) * 10 * GetSkill(SkillBackstab) / 355) + 1;;
|
||||
max_hit = (((((2*backstab_dmg) * GetDamageTable(SkillBackstab) / 100) * 10 * GetSkill(SkillBackstab) / 355) + 1) * ((100 + RuleI(Combat, BackstabBonus)) / 100));
|
||||
hate = 20 * backstab_dmg * GetSkill(SkillBackstab) / 355;
|
||||
}
|
||||
|
||||
@@ -650,10 +659,10 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
|
||||
}
|
||||
|
||||
ndamage = mod_backstab_damage(ndamage);
|
||||
|
||||
|
||||
uint32 Assassinate_Dmg = 0;
|
||||
Assassinate_Dmg = TryAssassinate(other, SkillBackstab, ReuseTime);
|
||||
|
||||
|
||||
if (Assassinate_Dmg) {
|
||||
ndamage = Assassinate_Dmg;
|
||||
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName());
|
||||
@@ -797,14 +806,14 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
||||
//EndlessQuiver AA base1 = 100% Chance to avoid consumption arrow.
|
||||
int ChanceAvoidConsume = aabonuses.ConsumeProjectile + itembonuses.ConsumeProjectile + spellbonuses.ConsumeProjectile;
|
||||
|
||||
if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && zone->random.Int(0,99) > ChanceAvoidConsume)){
|
||||
if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && zone->random.Int(0,99) > ChanceAvoidConsume)){
|
||||
DeleteItemInInventory(ammo_slot, 1, true);
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Consumed one arrow from slot %d", ammo_slot);
|
||||
} else {
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Endless Quiver prevented ammo consumption.");
|
||||
}
|
||||
|
||||
CheckIncreaseSkill(SkillArchery, GetTarget(), -15);
|
||||
CheckIncreaseSkill(SkillArchery, GetTarget(), -15);
|
||||
CommonBreakInvisible();
|
||||
}
|
||||
|
||||
@@ -816,7 +825,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
(other->IsClient() && other->CastToClient()->dead)) ||
|
||||
HasDied() ||
|
||||
(!IsAttackAllowed(other)) ||
|
||||
(other->GetInvul() ||
|
||||
(other->GetInvul() ||
|
||||
other->GetSpecialAbility(IMMUNE_MELEE))))
|
||||
{
|
||||
return;
|
||||
@@ -841,12 +850,12 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
LaunchProjectile = true;
|
||||
else{
|
||||
/*
|
||||
Item sync check on projectile landing.
|
||||
Item sync check on projectile landing.
|
||||
Weapon damage is already calculated so this only affects procs!
|
||||
Ammo proc check will use database to find proc if you used up your last ammo.
|
||||
If you change range item mid projectile flight, you loose your chance to proc from bow (Deal with it!).
|
||||
*/
|
||||
|
||||
|
||||
if (!RangeWeapon && !Ammo && range_id && ammo_id){
|
||||
|
||||
ProjectileImpact = true;
|
||||
@@ -858,8 +867,8 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
|
||||
_RangeWeapon = CastToClient()->m_inv[MainRange];
|
||||
if (_RangeWeapon && _RangeWeapon->GetItem() && _RangeWeapon->GetItem()->ID == range_id)
|
||||
RangeWeapon = _RangeWeapon;
|
||||
|
||||
RangeWeapon = _RangeWeapon;
|
||||
|
||||
_Ammo = CastToClient()->m_inv[AmmoSlot];
|
||||
if (_Ammo && _Ammo->GetItem() && _Ammo->GetItem()->ID == ammo_id)
|
||||
Ammo = _Ammo;
|
||||
@@ -985,7 +994,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
other->AddToHateList(this, hate, 0, false);
|
||||
|
||||
other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery);
|
||||
|
||||
|
||||
//Skill Proc Success
|
||||
if (TotalDmg > 0 && HasSkillProcSuccess() && other && !other->HasDied()){
|
||||
if (ReuseTime)
|
||||
@@ -1047,10 +1056,10 @@ bool Mob::TryProjectileAttack(Mob* other, const ItemData *item, SkillUseTypes sk
|
||||
ProjectileAtk[slot].origin_x = GetX();
|
||||
ProjectileAtk[slot].origin_y = GetY();
|
||||
ProjectileAtk[slot].origin_z = GetZ();
|
||||
|
||||
|
||||
if (RangeWeapon && RangeWeapon->GetItem())
|
||||
ProjectileAtk[slot].ranged_id = RangeWeapon->GetItem()->ID;
|
||||
|
||||
|
||||
if (Ammo && Ammo->GetItem())
|
||||
ProjectileAtk[slot].ammo_id = Ammo->GetItem()->ID;
|
||||
|
||||
@@ -1085,7 +1094,7 @@ void Mob::ProjectileAttack()
|
||||
|
||||
disable = false;
|
||||
Mob* target = entity_list.GetMobID(ProjectileAtk[i].target_id);
|
||||
|
||||
|
||||
if (target && target->IsMoving()){ //Only recalculate hit increment if target moving
|
||||
//Due to frequency that we need to check increment the targets position variables may not be updated even if moving. Do a simple check before calculating distance.
|
||||
if (ProjectileAtk[i].tlast_x != target->GetX() || ProjectileAtk[i].tlast_y != target->GetY()){
|
||||
@@ -1109,7 +1118,7 @@ void Mob::ProjectileAttack()
|
||||
else
|
||||
CastToNPC()->DoRangedAttackDmg(target, false, ProjectileAtk[i].wpn_dmg,0, static_cast<SkillUseTypes>(ProjectileAtk[i].skill));
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
{
|
||||
if (ProjectileAtk[i].skill == SkillArchery)
|
||||
@@ -1120,7 +1129,7 @@ void Mob::ProjectileAttack()
|
||||
SpellOnTarget(ProjectileAtk[i].wpn_dmg, target, false, true, spells[ProjectileAtk[i].wpn_dmg].ResistDiff, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ProjectileAtk[i].increment = 0;
|
||||
ProjectileAtk[i].target_id = 0;
|
||||
ProjectileAtk[i].wpn_dmg = 0;
|
||||
@@ -1180,7 +1189,7 @@ float Mob::GetRangeDistTargetSizeMod(Mob* other)
|
||||
mod = 42.0f + (5.8f * (tsize - 15.0f));
|
||||
else
|
||||
mod = 75.0f;
|
||||
|
||||
|
||||
return (mod + 2.0f); //Add 2.0f as buffer to prevent any chance of failures, client enforce range check regardless.
|
||||
}
|
||||
|
||||
@@ -1210,7 +1219,7 @@ void NPC::RangedAttack(Mob* other)
|
||||
|
||||
float min_range = static_cast<float>(RuleI(Combat, MinRangedAttackDist));
|
||||
float max_range = 250; // needs to be longer than 200(most spells)
|
||||
|
||||
|
||||
if (sa_max_range)
|
||||
max_range = static_cast<float>(sa_max_range);
|
||||
|
||||
@@ -1242,12 +1251,12 @@ void NPC::RangedAttack(Mob* other)
|
||||
}
|
||||
|
||||
void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 chance_mod, SkillUseTypes skill, float speed, const char *IDFile) {
|
||||
|
||||
if ((other == nullptr ||
|
||||
(other->HasDied())) ||
|
||||
HasDied() ||
|
||||
|
||||
if ((other == nullptr ||
|
||||
(other->HasDied())) ||
|
||||
HasDied() ||
|
||||
(!IsAttackAllowed(other)) ||
|
||||
(other->GetInvul() ||
|
||||
(other->GetInvul() ||
|
||||
other->GetSpecialAbility(IMMUNE_MELEE)))
|
||||
{
|
||||
return;
|
||||
@@ -1268,7 +1277,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha
|
||||
ammo = GetAmmoIDfile();
|
||||
|
||||
ProjectileAnimation(other, 0,false,speed,0,0,0,ammo,skillInUse);
|
||||
|
||||
|
||||
if (RuleB(Combat, ProjectileDmgOnImpact))
|
||||
{
|
||||
TryProjectileAttack(other, nullptr, skillInUse, damage_mod, nullptr, nullptr, 0, speed);
|
||||
@@ -1276,7 +1285,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha
|
||||
}
|
||||
}
|
||||
|
||||
if (!chance_mod)
|
||||
if (!chance_mod)
|
||||
chance_mod = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 2);
|
||||
|
||||
if (!other->CheckHitChance(this, skillInUse, MainRange, chance_mod))
|
||||
@@ -1298,11 +1307,11 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha
|
||||
if (!damage_mod)
|
||||
damage_mod = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 3);//Damage modifier
|
||||
|
||||
TotalDmg += TotalDmg * damage_mod / 100;
|
||||
TotalDmg += TotalDmg * damage_mod / 100;
|
||||
|
||||
other->AvoidDamage(this, TotalDmg, false);
|
||||
other->MeleeMitigation(this, TotalDmg, MinDmg);
|
||||
|
||||
|
||||
if (TotalDmg > 0)
|
||||
CommonOutgoingHitSuccess(other, TotalDmg, skillInUse);
|
||||
else if (TotalDmg < -4)
|
||||
@@ -1432,18 +1441,18 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
|
||||
|
||||
//consume ammo
|
||||
DeleteItemInInventory(ammo_slot, 1, true);
|
||||
CheckIncreaseSkill(SkillThrowing, GetTarget());
|
||||
CheckIncreaseSkill(SkillThrowing, GetTarget());
|
||||
CommonBreakInvisible();
|
||||
}
|
||||
|
||||
void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemData* AmmoItem, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime, uint32 range_id, int AmmoSlot, float speed)
|
||||
{
|
||||
if ((other == nullptr ||
|
||||
((IsClient() && CastToClient()->dead) ||
|
||||
(other->IsClient() && other->CastToClient()->dead)) ||
|
||||
HasDied() ||
|
||||
if ((other == nullptr ||
|
||||
((IsClient() && CastToClient()->dead) ||
|
||||
(other->IsClient() && other->CastToClient()->dead)) ||
|
||||
HasDied() ||
|
||||
(!IsAttackAllowed(other)) ||
|
||||
(other->GetInvul() ||
|
||||
(other->GetInvul() ||
|
||||
other->GetSpecialAbility(IMMUNE_MELEE))))
|
||||
{
|
||||
return;
|
||||
@@ -1511,7 +1520,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
WDmg = weapon_damage;
|
||||
|
||||
if (focus) //From FcBaseEffects
|
||||
@@ -1535,7 +1544,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg);
|
||||
if (!Assassinate_Dmg)
|
||||
other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks.
|
||||
|
||||
|
||||
other->MeleeMitigation(this, TotalDmg, minDmg);
|
||||
if(TotalDmg > 0)
|
||||
CommonOutgoingHitSuccess(other, TotalDmg, SkillThrowing);
|
||||
@@ -1620,7 +1629,7 @@ void Mob::SendItemAnimation(Mob *to, const ItemData *item, SkillUseTypes skillIn
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) {
|
||||
void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) {
|
||||
if (!to)
|
||||
return;
|
||||
|
||||
@@ -2092,7 +2101,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
}
|
||||
|
||||
ReuseTime = ReuseTime / HasteMod;
|
||||
if(ReuseTime > 0 && !IsRiposte){
|
||||
if(ReuseTime > 0 && !IsRiposte){
|
||||
p_timers.Start(pTimerCombatAbility, ReuseTime);
|
||||
}
|
||||
}
|
||||
@@ -2270,7 +2279,7 @@ float Mob::GetSpecialProcChances(uint16 hand)
|
||||
|
||||
if (RuleB(Combat, AdjustSpecialProcPerMinute)) {
|
||||
ProcChance = (static_cast<float>(weapon_speed) *
|
||||
RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f);
|
||||
RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f);
|
||||
ProcBonus += static_cast<float>(mydex/35) + static_cast<float>(itembonuses.HeroicDEX / 25);
|
||||
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||
} else {
|
||||
@@ -2363,7 +2372,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
int Hand = MainPrimary;
|
||||
if (hate == 0 && weapon_damage > 1) hate = weapon_damage;
|
||||
|
||||
if(weapon_damage > 0){
|
||||
if(weapon_damage > 0){
|
||||
if (focus) //From FcBaseEffects
|
||||
weapon_damage += weapon_damage*focus/100;
|
||||
|
||||
@@ -2411,7 +2420,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
} else {
|
||||
other->AvoidDamage(this, damage, CanRiposte);
|
||||
other->MeleeMitigation(this, damage, min_hit);
|
||||
if(damage > 0)
|
||||
if(damage > 0)
|
||||
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
||||
}
|
||||
|
||||
@@ -2449,7 +2458,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
|
||||
if (CanSkillProc && HasSkillProcs())
|
||||
TrySkillProc(other, skillinuse, ReuseTime);
|
||||
|
||||
|
||||
if (CanSkillProc && (damage > 0) && HasSkillProcSuccess())
|
||||
TrySkillProc(other, skillinuse, ReuseTime, true);
|
||||
}
|
||||
|
||||
+487
-485
File diff suppressed because it is too large
Load Diff
+167
-118
@@ -82,6 +82,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <stdlib.h>
|
||||
@@ -369,6 +370,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
// and a target wasn't provided, then it's us; unless TGB is on and this
|
||||
// is a TGB compatible spell.
|
||||
if((IsGroupSpell(spell_id) ||
|
||||
spell.targettype == ST_AEClientV1 ||
|
||||
spell.targettype == ST_Self ||
|
||||
spell.targettype == ST_AECaster ||
|
||||
spell.targettype == ST_Ring ||
|
||||
@@ -392,7 +394,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
|
||||
// we checked for spells not requiring targets above
|
||||
if(target_id == 0) {
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Spell Error: no target. spell=%d\n", GetName(), spell_id);
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Spell Error: no target. spell=%d", spell_id);
|
||||
if(IsClient()) {
|
||||
//clients produce messages... npcs should not for this case
|
||||
Message_StringID(13, SPELL_NEED_TAR);
|
||||
@@ -488,6 +490,12 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
safe_delete(outapp);
|
||||
outapp = nullptr;
|
||||
|
||||
if (IsClient() && slot == USE_ITEM_SPELL_SLOT &&item_slot != 0xFFFFFFFF) {
|
||||
auto item = CastToClient()->GetInv().GetItem(item_slot);
|
||||
if (item && item->GetItem())
|
||||
Message_StringID(MT_Spells, BEGINS_TO_GLOW, item->GetItem()->Name);
|
||||
}
|
||||
|
||||
if (!DoCastingChecks()) {
|
||||
InterruptSpell();
|
||||
return false;
|
||||
@@ -1164,12 +1172,14 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
||||
}
|
||||
else if (!bard_song_mode)
|
||||
{
|
||||
int noexpend;
|
||||
for(int t_count = 0; t_count < 4; t_count++) {
|
||||
component = spells[spell_id].components[t_count];
|
||||
if (component == -1)
|
||||
noexpend = spells[spell_id].NoexpendReagent[t_count];
|
||||
if (component == -1 || noexpend == component)
|
||||
continue;
|
||||
component_count = spells[spell_id].component_counts[t_count];
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Consuming %d of spell component item id %d", spell_id, component, component_count);
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Consuming %d of spell component item id %d", spell_id, component_count, component);
|
||||
// Components found, Deleting
|
||||
// now we go looking for and deleting the items one by one
|
||||
for(int s = 0; s < component_count; s++)
|
||||
@@ -1477,7 +1487,10 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
{
|
||||
//invalid target
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Spell %d canceled: invalid target of body type %d (undead)", spell_id, mob_body);
|
||||
Message_StringID(13,SPELL_NEED_TAR);
|
||||
if(!spell_target)
|
||||
Message_StringID(13,SPELL_NEED_TAR);
|
||||
else
|
||||
Message_StringID(13,CANNOT_AFFECT_NPC);
|
||||
return false;
|
||||
}
|
||||
CastAction = SingleTarget;
|
||||
@@ -1606,6 +1619,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
|
||||
case ST_AEBard:
|
||||
case ST_AECaster:
|
||||
case ST_AEClientV1:
|
||||
{
|
||||
spell_target = nullptr;
|
||||
ae_center = this;
|
||||
@@ -1891,7 +1905,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
// we can't interrupt in this, or anything called from this!
|
||||
// if you need to abort the casting, return false
|
||||
bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 mana_used,
|
||||
uint32 inventory_slot, int16 resist_adjust, bool isproc)
|
||||
uint32 inventory_slot, int16 resist_adjust, bool isproc, int level_override)
|
||||
{
|
||||
//EQApplicationPacket *outapp = nullptr;
|
||||
Mob *ae_center = nullptr;
|
||||
@@ -1933,6 +1947,12 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
}
|
||||
}
|
||||
|
||||
if (IsClient() && CastToClient()->GetGM()){
|
||||
if (zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))){
|
||||
Log.Out(Logs::Detail, Logs::Spells, "GM Cast Blocked Spell: %s (ID %i)", GetSpellName(spell_id), spell_id);
|
||||
}
|
||||
}
|
||||
|
||||
if
|
||||
(
|
||||
this->IsClient() &&
|
||||
@@ -2048,14 +2068,14 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
return(false);
|
||||
}
|
||||
if (isproc) {
|
||||
SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, true);
|
||||
SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, true, level_override);
|
||||
} else {
|
||||
if (spells[spell_id].targettype == ST_TargetOptional){
|
||||
if (!TrySpellProjectile(spell_target, spell_id))
|
||||
return false;
|
||||
}
|
||||
|
||||
else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false)) {
|
||||
else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false, level_override)) {
|
||||
if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) {
|
||||
// Prevent mana usage/timers being set for beneficial buffs
|
||||
if(casting_spell_type == 1)
|
||||
@@ -2149,7 +2169,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
// caster if they're not using TGB
|
||||
// NOTE: this will always hit the caster, plus the target's group so
|
||||
// it can affect up to 7 people if the targeted group is not our own
|
||||
|
||||
|
||||
// Allow pets who cast group spells to affect the group.
|
||||
if (spell_target->IsPetOwnerClient() && IsPetOwnerClient()){
|
||||
Mob* owner = spell_target->GetOwner();
|
||||
@@ -2157,7 +2177,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
if (owner)
|
||||
spell_target = owner;
|
||||
}
|
||||
|
||||
|
||||
if(spell_target->IsGrouped())
|
||||
{
|
||||
Group *target_group = entity_list.GetGroupByMob(spell_target);
|
||||
@@ -2252,7 +2272,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
}
|
||||
|
||||
//set our reuse timer on long ass reuse_time spells...
|
||||
if(IsClient())
|
||||
if(IsClient() && !isproc)
|
||||
{
|
||||
if(spell_id == casting_spell_id && casting_spell_timer != 0xFFFFFFFF)
|
||||
{
|
||||
@@ -2560,7 +2580,7 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) {
|
||||
cd->source = action->source;
|
||||
cd->type = DamageTypeSpell;
|
||||
cd->spellid = action->spell;
|
||||
cd->sequence = action->sequence;
|
||||
cd->meleepush_xy = action->sequence;
|
||||
cd->damage = 0;
|
||||
if(!IsEffectInSpell(spell_id, SE_BindAffinity))
|
||||
{
|
||||
@@ -2612,84 +2632,85 @@ int Mob::CalcBuffDuration(Mob *caster, Mob *target, uint16 spell_id, int32 caste
|
||||
castlevel = caster_level_override;
|
||||
|
||||
int res = CalcBuffDuration_formula(castlevel, formula, duration);
|
||||
if (caster == target && (target->aabonuses.IllusionPersistence || target->spellbonuses.IllusionPersistence ||
|
||||
target->itembonuses.IllusionPersistence) &&
|
||||
IsEffectInSpell(spell_id, SE_Illusion))
|
||||
res = 10000; // ~16h override
|
||||
|
||||
res = mod_buff_duration(res, caster, target, spell_id);
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Casting level %d, formula %d, base_duration %d: result %d",
|
||||
spell_id, castlevel, formula, duration, res);
|
||||
|
||||
return(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// the generic formula calculations
|
||||
int CalcBuffDuration_formula(int level, int formula, int duration)
|
||||
{
|
||||
int i; // temp variable
|
||||
int temp;
|
||||
|
||||
switch(formula)
|
||||
{
|
||||
case 0: // not a buff
|
||||
return 0;
|
||||
|
||||
case 1:
|
||||
i = (int)ceil(level / 2.0f);
|
||||
return i < duration ? (i < 1 ? 1 : i) : duration;
|
||||
|
||||
case 2:
|
||||
i = (int)ceil(duration / 5.0f * 3);
|
||||
return i < duration ? (i < 1 ? 1 : i) : duration;
|
||||
|
||||
case 3:
|
||||
i = level * 30;
|
||||
return i < duration ? (i < 1 ? 1 : i) : duration;
|
||||
|
||||
case 4: // only used by 'LowerElement'
|
||||
return ((duration != 0) ? duration : 50);
|
||||
|
||||
case 5:
|
||||
i = duration;
|
||||
// 0 value results in a 3 tick spell, else its between 1-3 ticks.
|
||||
return i < 3 ? (i < 1 ? 3 : i) : 3;
|
||||
|
||||
case 6:
|
||||
i = (int)ceil(level / 2.0f);
|
||||
return i < duration ? (i < 1 ? 1 : i) : duration;
|
||||
|
||||
case 7:
|
||||
i = level;
|
||||
return (duration == 0) ? (i < 1 ? 1 : i) : duration;
|
||||
|
||||
case 8:
|
||||
i = level + 10;
|
||||
return i < duration ? (i < 1 ? 1 : i) : duration;
|
||||
|
||||
case 9:
|
||||
i = level * 2 + 10;
|
||||
return i < duration ? (i < 1 ? 1 : i) : duration;
|
||||
|
||||
case 10:
|
||||
i = level * 3 + 10;
|
||||
return i < duration ? (i < 1 ? 1 : i) : duration;
|
||||
|
||||
case 11:
|
||||
return std::min((level + 3) * 30, duration);
|
||||
|
||||
case 12:
|
||||
return duration;
|
||||
|
||||
case 15: // Don't know what the real formula for this should be. Used by Skinspikes potion.
|
||||
return duration;
|
||||
|
||||
case 50: // lucy says this is unlimited?
|
||||
return 72000; // 5 days
|
||||
|
||||
case 3600:
|
||||
return duration ? duration : 3600;
|
||||
|
||||
default:
|
||||
Log.Out(Logs::General, Logs::None, "CalcBuffDuration_formula: unknown formula %d", formula);
|
||||
switch (formula) {
|
||||
case 1:
|
||||
temp = level > 3 ? level / 2 : 1;
|
||||
break;
|
||||
case 2:
|
||||
temp = level > 3 ? level / 2 + 5 : 6;
|
||||
break;
|
||||
case 3:
|
||||
temp = 30 * level;
|
||||
break;
|
||||
case 4: // only used by 'LowerElement'
|
||||
temp = 50;
|
||||
break;
|
||||
case 5:
|
||||
temp = 2;
|
||||
break;
|
||||
case 6:
|
||||
temp = level / 2 + 2;
|
||||
break;
|
||||
case 7:
|
||||
temp = level;
|
||||
break;
|
||||
case 8:
|
||||
temp = level + 10;
|
||||
break;
|
||||
case 9:
|
||||
temp = 2 * level + 10;
|
||||
break;
|
||||
case 10:
|
||||
temp = 3 * level + 10;
|
||||
break;
|
||||
case 11:
|
||||
temp = 30 * (level + 3);
|
||||
break;
|
||||
case 12:
|
||||
temp = level > 7 ? level / 4 : 1;
|
||||
break;
|
||||
case 13:
|
||||
temp = 4 * level + 10;
|
||||
break;
|
||||
case 14:
|
||||
temp = 5 * (level + 2);
|
||||
break;
|
||||
case 15:
|
||||
temp = 10 * (level + 10);
|
||||
break;
|
||||
case 50: // Permanent. Cancelled by casting/combat for perm invis, non-lev zones for lev, curing poison/curse
|
||||
// counters, etc.
|
||||
return -1;
|
||||
case 51: // Permanent. Cancelled when out of range of aura.
|
||||
return -4;
|
||||
default:
|
||||
// the client function has another bool parameter that if true returns -2 -- unsure
|
||||
if (formula < 200)
|
||||
return 0;
|
||||
temp = formula;
|
||||
break;
|
||||
}
|
||||
if (duration && duration < temp)
|
||||
temp = duration;
|
||||
return temp;
|
||||
}
|
||||
|
||||
// helper function for AddBuff to determine stacking
|
||||
@@ -3052,7 +3073,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
if (duration == 0) {
|
||||
duration = CalcBuffDuration(caster, this, spell_id);
|
||||
|
||||
if (caster)
|
||||
if (caster && duration > 0) // negatives are perma buffs
|
||||
duration = caster->GetActSpellDuration(spell_id, duration);
|
||||
}
|
||||
|
||||
@@ -3175,6 +3196,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
buffs[emptyslot].dot_rune = 0;
|
||||
buffs[emptyslot].ExtraDIChance = 0;
|
||||
buffs[emptyslot].RootBreakChance = 0;
|
||||
buffs[emptyslot].instrument_mod = caster ? caster->GetInstrumentMod(spell_id) : 10;
|
||||
|
||||
if (level_override > 0) {
|
||||
buffs[emptyslot].UpdateClient = true;
|
||||
@@ -3278,7 +3300,8 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite)
|
||||
// and if you don't want effects just return false. interrupting here will
|
||||
// break stuff
|
||||
//
|
||||
bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc)
|
||||
bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust,
|
||||
bool isproc, int level_override)
|
||||
{
|
||||
|
||||
// well we can't cast a spell on target without a target
|
||||
@@ -3310,7 +3333,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
if(!IsValidSpell(spell_id))
|
||||
return false;
|
||||
|
||||
uint16 caster_level = GetCasterLevel(spell_id);
|
||||
uint16 caster_level = level_override > 0 ? level_override : GetCasterLevel(spell_id);
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Casting spell %d on %s with effective caster level %d", spell_id, spelltar->GetName(), caster_level);
|
||||
|
||||
@@ -3650,9 +3673,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
if(IsResistableSpell(spell_id))
|
||||
{
|
||||
if (IsCharmSpell(spell_id) || IsMezSpell(spell_id) || IsFearSpell(spell_id))
|
||||
spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust,true);
|
||||
spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust, true, false, false, level_override);
|
||||
else
|
||||
spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust);
|
||||
spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust, false, false, false, level_override);
|
||||
|
||||
if(spell_effectiveness < 100)
|
||||
{
|
||||
@@ -3669,22 +3692,16 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
spelltar->Message_StringID(MT_SpellFailure, YOU_RESIST, spells[spell_id].name);
|
||||
}
|
||||
|
||||
if(spelltar->IsAIControlled()){
|
||||
if (spelltar->IsAIControlled()) {
|
||||
int32 aggro = CheckAggroAmount(spell_id);
|
||||
if(aggro > 0) {
|
||||
if(!IsHarmonySpell(spell_id))
|
||||
spelltar->AddToHateList(this, aggro);
|
||||
else
|
||||
if(!spelltar->PassCharismaCheck(this, spell_id))
|
||||
spelltar->AddToHateList(this, aggro);
|
||||
}
|
||||
else{
|
||||
uint32 newhate = spelltar->GetHateAmount(this) + aggro;
|
||||
if (newhate < 1) {
|
||||
spelltar->SetHateAmountOnEnt(this,1);
|
||||
} else {
|
||||
spelltar->SetHateAmountOnEnt(this,newhate);
|
||||
}
|
||||
if (aggro > 0) {
|
||||
if (!IsHarmonySpell(spell_id))
|
||||
spelltar->AddToHateList(this, aggro);
|
||||
else if (!spelltar->PassCharismaCheck(this, spell_id))
|
||||
spelltar->AddToHateList(this, aggro);
|
||||
} else {
|
||||
int newhate = spelltar->GetHateAmount(this) + aggro;
|
||||
spelltar->SetHateAmountOnEnt(this, std::max(1, newhate));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3731,7 +3748,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
}
|
||||
|
||||
// cause the effects to the target
|
||||
if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness))
|
||||
if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness, level_override))
|
||||
{
|
||||
// if SpellEffect returned false there's a problem applying the
|
||||
// spell. It's most likely a buff that can't stack.
|
||||
@@ -3830,7 +3847,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
cd->source = action->source;
|
||||
cd->type = action->type;
|
||||
cd->spellid = action->spell;
|
||||
cd->sequence = action->sequence;
|
||||
cd->meleepush_xy = action->sequence;
|
||||
cd->damage = 0;
|
||||
if(!IsEffectInSpell(spell_id, SE_BindAffinity))
|
||||
{
|
||||
@@ -4199,7 +4216,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
||||
// pvp_resist_base
|
||||
// pvp_resist_calc
|
||||
// pvp_resist_cap
|
||||
float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override, int resist_override, bool CharismaCheck, bool CharmTick, bool IsRoot)
|
||||
float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override, int resist_override, bool CharismaCheck, bool CharmTick, bool IsRoot, int level_override)
|
||||
{
|
||||
|
||||
if(!caster)
|
||||
@@ -4342,18 +4359,19 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
int level_mod = 0;
|
||||
|
||||
//Adjust our resist chance based on level modifiers
|
||||
int temp_level_diff = GetLevel() - caster->GetLevel();
|
||||
uint8 caster_level = level_override > 0 ? level_override : caster->GetLevel();
|
||||
int temp_level_diff = GetLevel() - caster_level;
|
||||
|
||||
//Physical Resists are calclated using their own formula derived from extensive parsing.
|
||||
if (resist_type == RESIST_PHYSICAL) {
|
||||
level_mod = ResistPhysical(temp_level_diff, caster->GetLevel());
|
||||
level_mod = ResistPhysical(temp_level_diff, caster_level);
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
if(IsNPC() && GetLevel() >= RuleI(Casting,ResistFalloff))
|
||||
{
|
||||
int a = (RuleI(Casting,ResistFalloff)-1) - caster->GetLevel();
|
||||
int a = (RuleI(Casting,ResistFalloff)-1) - caster_level;
|
||||
if(a > 0)
|
||||
{
|
||||
temp_level_diff = a;
|
||||
@@ -4380,7 +4398,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
level_mod = -level_mod;
|
||||
}
|
||||
|
||||
if(IsNPC() && (caster->GetLevel() - GetLevel()) < -20)
|
||||
if(IsNPC() && (caster_level - GetLevel()) < -20)
|
||||
{
|
||||
level_mod = 1000;
|
||||
}
|
||||
@@ -4391,7 +4409,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
int level_diff;
|
||||
if(GetLevel() >= RuleI(Casting,ResistFalloff))
|
||||
{
|
||||
level_diff = (RuleI(Casting,ResistFalloff)-1) - caster->GetLevel();
|
||||
level_diff = (RuleI(Casting,ResistFalloff)-1) - caster_level;
|
||||
if(level_diff < 0)
|
||||
{
|
||||
level_diff = 0;
|
||||
@@ -4399,12 +4417,12 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
}
|
||||
else
|
||||
{
|
||||
level_diff = GetLevel() - caster->GetLevel();
|
||||
level_diff = GetLevel() - caster_level;
|
||||
}
|
||||
level_mod += (2 * level_diff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (CharismaCheck)
|
||||
{
|
||||
/*
|
||||
@@ -4510,14 +4528,14 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
|
||||
if(IsNPC())
|
||||
{
|
||||
if(GetLevel() > caster->GetLevel() && GetLevel() >= 17 && caster->GetLevel() <= 50)
|
||||
if(GetLevel() > caster_level && GetLevel() >= 17 && caster_level <= 50)
|
||||
{
|
||||
partial_modifier += 5;
|
||||
}
|
||||
|
||||
if(GetLevel() >= 30 && caster->GetLevel() < 50)
|
||||
if(GetLevel() >= 30 && caster_level < 50)
|
||||
{
|
||||
partial_modifier += (caster->GetLevel() - 25);
|
||||
partial_modifier += (caster_level - 25);
|
||||
}
|
||||
|
||||
if(GetLevel() < 15)
|
||||
@@ -4528,9 +4546,9 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
|
||||
if(caster->IsNPC())
|
||||
{
|
||||
if((GetLevel() - caster->GetLevel()) >= 20)
|
||||
if((GetLevel() - caster_level) >= 20)
|
||||
{
|
||||
partial_modifier += (GetLevel() - caster->GetLevel()) * 1.5;
|
||||
partial_modifier += (GetLevel() - caster_level) * 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4708,7 +4726,7 @@ void Mob::Stun(int duration)
|
||||
{
|
||||
stunned = true;
|
||||
stunned_timer.Start(duration);
|
||||
SendStunAppearance();
|
||||
SendAddPlayerState(PlayerState::Stunned);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4716,6 +4734,7 @@ void Mob::UnStun() {
|
||||
if(stunned && stunned_timer.Enabled()) {
|
||||
stunned = false;
|
||||
stunned_timer.Disable();
|
||||
SendRemovePlayerState(PlayerState::Stunned);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4745,14 +4764,12 @@ void Client::UnStun() {
|
||||
|
||||
void NPC::Stun(int duration) {
|
||||
Mob::Stun(duration);
|
||||
SetRunAnimSpeed(0);
|
||||
SendPosition();
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
|
||||
void NPC::UnStun() {
|
||||
Mob::UnStun();
|
||||
SetRunAnimSpeed(static_cast<int8>(GetRunspeed()));
|
||||
SendPosition();
|
||||
SetCurrentSpeed(GetRunspeed());
|
||||
}
|
||||
|
||||
void Mob::Mesmerize()
|
||||
@@ -5053,7 +5070,7 @@ bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) {
|
||||
spells[buffs[i].spellid].base[j],
|
||||
spells[buffs[i].spellid].max[j],
|
||||
buffs[i].casterlevel, buffs[i].spellid);
|
||||
Log.Out(Logs::General, Logs::Normal,
|
||||
Log.Out(Logs::General, Logs::Normal,
|
||||
"FindType: type = %d; value = %d; threshold = %d",
|
||||
type, value, threshold);
|
||||
if (value < threshold)
|
||||
@@ -5091,7 +5108,7 @@ bool Mob::IsCombatProc(uint16 spell_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id) {
|
||||
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id, int level_override) {
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
return(false);
|
||||
|
||||
@@ -5102,6 +5119,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b
|
||||
PermaProcs[i].spellID = spell_id;
|
||||
PermaProcs[i].chance = iChance;
|
||||
PermaProcs[i].base_spellID = base_spell_id;
|
||||
PermaProcs[i].level_override = level_override;
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Added permanent proc spell %d with chance %d to slot %d", spell_id, iChance, i);
|
||||
|
||||
return true;
|
||||
@@ -5114,6 +5132,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b
|
||||
SpellProcs[i].spellID = spell_id;
|
||||
SpellProcs[i].chance = iChance;
|
||||
SpellProcs[i].base_spellID = base_spell_id;;
|
||||
SpellProcs[i].level_override = level_override;
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Added spell-granted proc spell %d with chance %d to slot %d", spell_id, iChance, i);
|
||||
return true;
|
||||
}
|
||||
@@ -5129,6 +5148,7 @@ bool Mob::RemoveProcFromWeapon(uint16 spell_id, bool bAll) {
|
||||
SpellProcs[i].spellID = SPELL_UNKNOWN;
|
||||
SpellProcs[i].chance = 0;
|
||||
SpellProcs[i].base_spellID = SPELL_UNKNOWN;
|
||||
SpellProcs[i].level_override = -1;
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Removed proc %d from slot %d", spell_id, i);
|
||||
}
|
||||
}
|
||||
@@ -5254,8 +5274,31 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff)
|
||||
sbf->slot = 2;
|
||||
sbf->spellid = buff.spellid;
|
||||
sbf->slotid = 0;
|
||||
sbf->effect = 255;
|
||||
sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
|
||||
|
||||
if (IsEffectInSpell(buff.spellid, SE_TotalHP))
|
||||
{
|
||||
// If any of the lower 6 bits are set, the GUI changes MAX_HP AGAIN.
|
||||
// If its set to 0 the effect is cancelled.
|
||||
// 128 seems to work (ie: change only duration).
|
||||
sbf->effect = 128;
|
||||
}
|
||||
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);
|
||||
sbf->effect = abs(spells[buff.spellid].base[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to what old code did until we find a better fix for
|
||||
// other spell lines.
|
||||
sbf->effect=sbf->level;
|
||||
}
|
||||
|
||||
sbf->bufffade = 0;
|
||||
sbf->duration = buff.ticsremaining;
|
||||
sbf->num_hits = buff.numhits;
|
||||
@@ -5353,6 +5396,12 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
|
||||
buff->entity_id = GetID();
|
||||
buff->count = count;
|
||||
buff->all_buffs = 1;
|
||||
// there are more types, the client doesn't seem to really care though. The others are also currently hard to fill in here ...
|
||||
// (see comment in common/eq_packet_structs.h)
|
||||
if (for_target)
|
||||
buff->type = IsClient() ? 5 : 7;
|
||||
else
|
||||
buff->type = 0;
|
||||
|
||||
uint32 index = 0;
|
||||
for(unsigned int i = 0; i < buff_count; ++i)
|
||||
|
||||
@@ -231,6 +231,17 @@
|
||||
#define MISSED_NOTE_OTHER 1219 //A missed note brings %1's song to a close!
|
||||
#define SPELL_LEVEL_REQ 1226 //This spell only works on people who are level %1 and under.
|
||||
#define CORPSE_DECAY_NOW 1227 //This corpse is waiting to expire.
|
||||
#define CORPSE_ITEM_LOST 1228 //Your items will no longer stay with you when you respawn on death. You will now need to return to your corpse for your items.
|
||||
#define CORPSE_EXP_LOST 1229 //You will now lose experience when you die.
|
||||
#define FLICKERS_PALE_LIGHT 1230 //Your %1 flickers with a pale light.
|
||||
#define PULSES_WITH_LIGHT 1231 //Your %1 pulses with light as your vision sharpens.
|
||||
#define FEEDS_WITH_POWER 1232 //Your %1 feeds you with power.
|
||||
#define POWER_DRAIN_INTO 1233 //You feel your power drain into your %1.
|
||||
#define SEEMS_DRAINED 1234 //Your %1 seems drained of power.
|
||||
#define ALIVE_WITH_POWER 1235 //Your %1 feels alive with power.
|
||||
#define SPARKLES 1236 //Your %1 sparkles.
|
||||
#define GROWS_DIM 1237 //Your %1 grows dim.
|
||||
#define BEGINS_TO_SHINE 1238 //Your %1 begins to shine.
|
||||
#define SURNAME_REJECTED 1374 //Your new surname was rejected. Please try a different name.
|
||||
#define DUEL_DECLINE 1383 //%1 has declined your challenge to duel to the death.
|
||||
#define DUEL_ACCEPTED 1384 //%1 has already accepted a duel with someone else.
|
||||
@@ -339,6 +350,8 @@
|
||||
#define YOU_HEAL 9068 //You have healed %1 for %2 points of damage.
|
||||
#define YOUR_HIT_DOT 9072 //%1 has taken %2 damage from your %3.
|
||||
#define HIT_NON_MELEE 9073 //%1 hit %2 for %3 points of non-melee damage.
|
||||
#define GLOWS_BLUE 9074 //Your %1 glows blue.
|
||||
#define GLOWS_RED 9075 //Your %1 glows red.
|
||||
#define SHAKE_OFF_STUN 9077
|
||||
#define STRIKETHROUGH_STRING 9078 //You strike through your opponent's defenses!
|
||||
#define SPELL_REFLECT 9082 //%1's spell has been reflected by %2.
|
||||
@@ -373,6 +386,7 @@
|
||||
#define GROUP_INVITEE_SELF 12270 //12270 You cannot invite yourself.
|
||||
#define NOT_IN_CONTROL 12368 //You do not have control of yourself right now.
|
||||
#define ALREADY_CASTING 12442 //You are already casting a spell!
|
||||
#define SHIMMERS_BRIEFLY 12444 //Your %1 shimmers briefly.
|
||||
#define SENSE_CORPSE_NOT_NAME 12446 //You don't sense any corpses of that name.
|
||||
#define SENSE_CORPSE_NONE 12447 //You don't sense any corpses.
|
||||
#define SCREECH_BUFF_BLOCK 12448 //Your immunity buff protected you from the spell %1!
|
||||
|
||||
@@ -1561,6 +1561,8 @@ bool ZoneDatabase::EnableRecipe(uint32 recipe_id)
|
||||
if (!results.Success())
|
||||
|
||||
return results.RowsAffected() > 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::DisableRecipe(uint32 recipe_id)
|
||||
@@ -1571,4 +1573,6 @@ bool ZoneDatabase::DisableRecipe(uint32 recipe_id)
|
||||
if (!results.Success())
|
||||
|
||||
return results.RowsAffected() > 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
+1
-1
@@ -192,7 +192,7 @@ void Trap::Trigger(Mob* trigger)
|
||||
int dmg = zone->random.Int(effectvalue, effectvalue2);
|
||||
trigger->SetHP(trigger->GetHP() - dmg);
|
||||
a->damage = dmg;
|
||||
a->sequence = zone->random.Int(0, 1234567);
|
||||
a->meleepush_xy = zone->random.Int(0, 1234567);
|
||||
a->source = GetHiddenTrigger()!=nullptr ? GetHiddenTrigger()->GetID() : trigger->GetID();
|
||||
a->spellid = 0;
|
||||
a->target = trigger->GetID();
|
||||
|
||||
+38
-26
@@ -394,6 +394,7 @@ void NPC::SetWaypointPause()
|
||||
|
||||
if (cur_wp_pause == 0) {
|
||||
AIwalking_timer->Start(100);
|
||||
AIwalking_timer->Trigger();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -436,9 +437,8 @@ void NPC::NextGuardPosition() {
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
moved=false;
|
||||
SetMoving(false);
|
||||
SendPosition();
|
||||
moved = false;
|
||||
SetCurrentSpeed(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -489,10 +489,16 @@ float Mob::CalculateHeadingToTarget(float in_x, float in_y) {
|
||||
return (256*(360-angle)/360.0f);
|
||||
}
|
||||
|
||||
bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool checkZ) {
|
||||
bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ) {
|
||||
if(GetID()==0)
|
||||
return true;
|
||||
|
||||
if(speed <= 0)
|
||||
{
|
||||
SetCurrentSpeed(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((m_Position.x-x == 0) && (m_Position.y-y == 0)) {//spawn is at target coords
|
||||
if(m_Position.z-z != 0) {
|
||||
m_Position.z = z;
|
||||
@@ -514,6 +520,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
return true;
|
||||
}
|
||||
|
||||
bool send_update = false;
|
||||
int compare_steps = IsBoat() ? 1 : 20;
|
||||
if(tar_ndx < compare_steps && m_TargetLocation.x==x && m_TargetLocation.y==y) {
|
||||
|
||||
@@ -586,7 +593,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
m_TargetV.x = x - nx;
|
||||
m_TargetV.y = y - ny;
|
||||
m_TargetV.z = z - nz;
|
||||
|
||||
SetCurrentSpeed((int8)speed);
|
||||
pRunAnimSpeed = speed;
|
||||
if(IsClient())
|
||||
{
|
||||
animation = speed;
|
||||
}
|
||||
//pRunAnimSpeed = (int8)(speed*NPC_RUNANIM_RATIO);
|
||||
//speed *= NPC_SPEED_MULTIPLIER;
|
||||
|
||||
@@ -596,10 +608,10 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
// 2: get unit vector
|
||||
// --------------------------------------------------------------------------
|
||||
float mag = sqrtf (m_TargetV.x*m_TargetV.x + m_TargetV.y*m_TargetV.y + m_TargetV.z*m_TargetV.z);
|
||||
tar_vector = speed / mag;
|
||||
tar_vector = (float)speed / mag;
|
||||
|
||||
// mob move fix
|
||||
int numsteps = (int) ( mag * 20 / speed) + 1;
|
||||
int numsteps = (int) ( mag * 16.0f / (float)speed);
|
||||
|
||||
|
||||
// mob move fix
|
||||
@@ -609,9 +621,9 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
if (numsteps>1)
|
||||
{
|
||||
tar_vector=1.0f ;
|
||||
m_TargetV.x = m_TargetV.x/numsteps;
|
||||
m_TargetV.y = m_TargetV.y/numsteps;
|
||||
m_TargetV.z = m_TargetV.z/numsteps;
|
||||
m_TargetV.x = 1.25f * m_TargetV.x/(float)numsteps;
|
||||
m_TargetV.y = 1.25f * m_TargetV.y/(float)numsteps;
|
||||
m_TargetV.z = 1.25f *m_TargetV.z/(float)numsteps;
|
||||
|
||||
float new_x = m_Position.x + m_TargetV.x;
|
||||
float new_y = m_Position.y + m_TargetV.y;
|
||||
@@ -643,7 +655,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
}
|
||||
|
||||
else {
|
||||
tar_vector/=20;
|
||||
tar_vector/=16.0f;
|
||||
|
||||
float new_x = m_Position.x + m_TargetV.x*tar_vector;
|
||||
float new_y = m_Position.y + m_TargetV.y*tar_vector;
|
||||
@@ -699,25 +711,27 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
||||
m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f);
|
||||
|
||||
if (IsClient())
|
||||
{
|
||||
SendPosUpdate(1);
|
||||
CastToClient()->ResetPositionTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
// force an update now
|
||||
move_tic_count = RuleI(Zone, NPCPositonUpdateTicCount);
|
||||
SendPosUpdate();
|
||||
SetAppearance(eaStanding, false);
|
||||
}
|
||||
|
||||
SetAppearance(eaStanding, false);
|
||||
pLastChange = Timer::GetCurrentTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mob::CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ) {
|
||||
if(IsNPC() || IsClient() || IsPet()) {
|
||||
pRunAnimSpeed = (int8)(speed*NPC_RUNANIM_RATIO);
|
||||
speed *= NPC_SPEED_MULTIPLIER;
|
||||
}
|
||||
|
||||
bool Mob::CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ, bool calcHeading) {
|
||||
return MakeNewPositionAndSendUpdate(x, y, z, speed, checkZ);
|
||||
}
|
||||
|
||||
bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool checkZ) {
|
||||
bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ, bool calcHeading) {
|
||||
if(GetID()==0)
|
||||
return true;
|
||||
|
||||
@@ -726,14 +740,12 @@ bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool chec
|
||||
float nz = m_Position.z;
|
||||
|
||||
// if NPC is rooted
|
||||
if (speed == 0.0) {
|
||||
if (speed == 0) {
|
||||
SetHeading(CalculateHeadingToTarget(x, y));
|
||||
if(moved){
|
||||
SendPosition();
|
||||
SetMoving(false);
|
||||
SetCurrentSpeed(0);
|
||||
moved=false;
|
||||
}
|
||||
SetRunAnimSpeed(0);
|
||||
Log.Out(Logs::Detail, Logs::AI, "Rooted while calculating new position to (%.3f, %.3f, %.3f)", x, y, z);
|
||||
return true;
|
||||
}
|
||||
@@ -745,8 +757,8 @@ bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool chec
|
||||
|
||||
if (m_TargetV.x == 0 && m_TargetV.y == 0)
|
||||
return false;
|
||||
pRunAnimSpeed = (uint8)(speed*NPC_RUNANIM_RATIO);
|
||||
speed *= NPC_SPEED_MULTIPLIER;
|
||||
SetCurrentSpeed((int8)(speed)); //*NPC_RUNANIM_RATIO);
|
||||
//speed *= NPC_SPEED_MULTIPLIER;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::AI, "Calculating new position to (%.3f, %.3f, %.3f) vector (%.3f, %.3f, %.3f) rate %.3f RAS %d", x, y, z, m_TargetV.x, m_TargetV.y, m_TargetV.z, speed, pRunAnimSpeed);
|
||||
|
||||
@@ -1039,7 +1051,7 @@ void ZoneDatabase::AssignGrid(Client *client, int grid, int spawn2id) {
|
||||
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
|
||||
if (results.RowsAffected() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
+30
-27
@@ -742,32 +742,36 @@ void WorldServer::Process() {
|
||||
break;
|
||||
}
|
||||
case ServerOP_SyncWorldTime: {
|
||||
if(zone!=0) {
|
||||
if (zone != 0 && !zone->is_zone_time_localized) {
|
||||
Log.Out(Logs::Moderate, Logs::Zone_Server, "%s Received Message SyncWorldTime", __FUNCTION__);
|
||||
eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer;
|
||||
zone->zone_time.setEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime);
|
||||
|
||||
eqTimeOfDay* newtime = (eqTimeOfDay*)pack->pBuffer;
|
||||
zone->zone_time.SetCurrentEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime);
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct));
|
||||
TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer;
|
||||
zone->zone_time.getEQTimeOfDay(time(0), tod);
|
||||
TimeOfDay_Struct* time_of_day = (TimeOfDay_Struct*)outapp->pBuffer;
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(time(0), time_of_day);
|
||||
entity_list.QueueClients(0, outapp, false);
|
||||
safe_delete(outapp);
|
||||
//TEST
|
||||
char timeMessage[255];
|
||||
time_t timeCurrent = time(nullptr);
|
||||
TimeOfDay_Struct eqTime;
|
||||
zone->zone_time.getEQTimeOfDay( timeCurrent, &eqTime);
|
||||
//if ( eqTime.hour >= 0 && eqTime.minute >= 0 )
|
||||
//{
|
||||
sprintf(timeMessage,"EQTime [%02d:%s%d %s]",
|
||||
((eqTime.hour - 1) % 12) == 0 ? 12 : ((eqTime.hour - 1) % 12),
|
||||
(eqTime.minute < 10) ? "0" : "",
|
||||
eqTime.minute,
|
||||
(eqTime.hour >= 13) ? "pm" : "am"
|
||||
);
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Time Broadcast Packet: %s", timeMessage);
|
||||
zone->GotCurTime(true);
|
||||
//}
|
||||
//Test
|
||||
|
||||
/* Buffer garbage to generate debug message */
|
||||
char time_message[255];
|
||||
time_t current_time = time(nullptr);
|
||||
TimeOfDay_Struct eq_time;
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(current_time, &eq_time);
|
||||
|
||||
sprintf(time_message, "EQTime [%02d:%s%d %s]",
|
||||
((eq_time.hour - 1) % 12) == 0 ? 12 : ((eq_time.hour - 1) % 12),
|
||||
(eq_time.minute < 10) ? "0" : "",
|
||||
eq_time.minute,
|
||||
(eq_time.hour >= 13) ? "pm" : "am"
|
||||
);
|
||||
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Time Broadcast Packet: %s", time_message);
|
||||
zone->SetZoneHasCurrentTime(true);
|
||||
|
||||
}
|
||||
if (zone->is_zone_time_localized){
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Received request to sync time from world, but our time is localized currently");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1406,17 +1410,16 @@ void WorldServer::Process() {
|
||||
// CONSENT_INVALID_NAME = 397
|
||||
// TARGET_NOT_FOUND = 101
|
||||
|
||||
safe_delete(pack);
|
||||
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
|
||||
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
|
||||
ServerPacket *scs_pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
|
||||
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)scs_pack->pBuffer;
|
||||
strcpy(scs->grantname, s->grantname);
|
||||
strcpy(scs->ownername, s->ownername);
|
||||
scs->permission = s->permission;
|
||||
scs->zone_id = s->zone_id;
|
||||
scs->instance_id = s->instance_id;
|
||||
scs->message_string_id = TARGET_NOT_FOUND;
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
worldserver.SendPacket(scs_pack);
|
||||
safe_delete(scs_pack);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+43
-16
@@ -241,8 +241,8 @@ bool Zone::LoadZoneObjects() {
|
||||
data.object_type = type;
|
||||
data.linked_list_addr[0] = 0;
|
||||
data.linked_list_addr[1] = 0;
|
||||
data.unknown008 = (uint32)atoi(row[11]);
|
||||
data.unknown010 = (uint32)atoi(row[12]);
|
||||
data.size = (uint32)atoi(row[11]);
|
||||
data.solidtype = (uint32)atoi(row[12]);
|
||||
data.unknown020 = (uint32)atoi(row[13]);
|
||||
data.unknown024 = (uint32)atoi(row[14]);
|
||||
data.unknown076 = (uint32)atoi(row[15]);
|
||||
@@ -697,7 +697,7 @@ void Zone::Shutdown(bool quite)
|
||||
|
||||
Log.Out(Logs::General, Logs::Status, "Zone Shutdown: %s (%i)", zone->GetShortName(), zone->GetZoneID());
|
||||
petition_list.ClearPetitions();
|
||||
zone->GotCurTime(false);
|
||||
zone->SetZoneHasCurrentTime(false);
|
||||
if (!quite)
|
||||
Log.Out(Logs::General, Logs::Normal, "Zone shutdown: going to sleep");
|
||||
ZoneLoaded = false;
|
||||
@@ -760,6 +760,8 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
||||
qGlobals = nullptr;
|
||||
default_ruleset = 0;
|
||||
|
||||
is_zone_time_localized = false;
|
||||
|
||||
loglevelvar = 0;
|
||||
merchantvar = 0;
|
||||
tradevar = 0;
|
||||
@@ -805,7 +807,7 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
||||
totalBS = 0;
|
||||
aas = nullptr;
|
||||
totalAAs = 0;
|
||||
gottime = false;
|
||||
zone_has_current_time = false;
|
||||
|
||||
Instance_Shutdown_Timer = nullptr;
|
||||
bool is_perma = false;
|
||||
@@ -1484,7 +1486,7 @@ void Zone::Repop(uint32 delay) {
|
||||
|
||||
void Zone::GetTimeSync()
|
||||
{
|
||||
if (worldserver.Connected() && !gottime) {
|
||||
if (worldserver.Connected() && !zone_has_current_time) {
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_GetWorldTime, 0);
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
@@ -1508,17 +1510,42 @@ void Zone::SetDate(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute
|
||||
}
|
||||
}
|
||||
|
||||
void Zone::SetTime(uint8 hour, uint8 minute)
|
||||
void Zone::SetTime(uint8 hour, uint8 minute, bool update_world /*= true*/)
|
||||
{
|
||||
if (worldserver.Connected()) {
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_SetWorldTime, sizeof(eqTimeOfDay));
|
||||
eqTimeOfDay* eqtod = (eqTimeOfDay*)pack->pBuffer;
|
||||
zone_time.getEQTimeOfDay(time(0), &eqtod->start_eqtime);
|
||||
eqtod->start_eqtime.minute=minute;
|
||||
eqtod->start_eqtime.hour=hour;
|
||||
eqtod->start_realtime=time(0);
|
||||
printf("Setting master time on world server to: %d:%d (%d)\n", hour, minute, (int)eqtod->start_realtime);
|
||||
worldserver.SendPacket(pack);
|
||||
eqTimeOfDay* eq_time_of_day = (eqTimeOfDay*)pack->pBuffer;
|
||||
|
||||
zone_time.GetCurrentEQTimeOfDay(time(0), &eq_time_of_day->start_eqtime);
|
||||
|
||||
eq_time_of_day->start_eqtime.minute = minute;
|
||||
eq_time_of_day->start_eqtime.hour = hour;
|
||||
eq_time_of_day->start_realtime = time(0);
|
||||
|
||||
/* By Default we update worlds time, but we can optionally no update world which updates the rest of the zone servers */
|
||||
if (update_world){
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Setting master time on world server to: %d:%d (%d)\n", hour, minute, (int)eq_time_of_day->start_realtime);
|
||||
worldserver.SendPacket(pack);
|
||||
|
||||
/* Set Time Localization Flag */
|
||||
zone->is_zone_time_localized = false;
|
||||
}
|
||||
/* When we don't update world, we are localizing ourselves, we become disjointed from normal syncs and set time locally */
|
||||
else{
|
||||
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Setting zone localized time...");
|
||||
|
||||
zone->zone_time.SetCurrentEQTimeOfDay(eq_time_of_day->start_eqtime, eq_time_of_day->start_realtime);
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct));
|
||||
TimeOfDay_Struct* time_of_day = (TimeOfDay_Struct*)outapp->pBuffer;
|
||||
zone->zone_time.GetCurrentEQTimeOfDay(time(0), time_of_day);
|
||||
entity_list.QueueClients(0, outapp, false);
|
||||
safe_delete(outapp);
|
||||
|
||||
/* Set Time Localization Flag */
|
||||
zone->is_zone_time_localized = true;
|
||||
}
|
||||
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
@@ -1900,7 +1927,7 @@ bool Zone::IsSpellBlocked(uint32 spell_id, const glm::vec3& location)
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (!IsWithinAxisAlignedBox(location, blocked_spells[x].m_Location - blocked_spells[x].m_Difference, blocked_spells[x].m_Location + blocked_spells[x].m_Difference))
|
||||
if (IsWithinAxisAlignedBox(location, blocked_spells[x].m_Location - blocked_spells[x].m_Difference, blocked_spells[x].m_Location + blocked_spells[x].m_Difference))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
@@ -1934,7 +1961,7 @@ const char* Zone::GetSpellBlockedMessage(uint32 spell_id, const glm::vec3& locat
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if(!IsWithinAxisAlignedBox(location, blocked_spells[x].m_Location - blocked_spells[x].m_Difference, blocked_spells[x].m_Location + blocked_spells[x].m_Difference))
|
||||
if(IsWithinAxisAlignedBox(location, blocked_spells[x].m_Location - blocked_spells[x].m_Difference, blocked_spells[x].m_Location + blocked_spells[x].m_Difference))
|
||||
return blocked_spells[x].message;
|
||||
break;
|
||||
}
|
||||
@@ -2209,9 +2236,9 @@ void Zone::ReloadWorld(uint32 Option){
|
||||
entity_list.ClearAreas();
|
||||
parse->ReloadQuests();
|
||||
} else if(Option == 1) {
|
||||
zone->Repop(0);
|
||||
entity_list.ClearAreas();
|
||||
parse->ReloadQuests();
|
||||
zone->Repop(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -43,6 +43,7 @@ struct ZonePoint
|
||||
int32 target_zone_instance;
|
||||
uint32 client_version_mask;
|
||||
};
|
||||
|
||||
struct ZoneClientAuth_Struct {
|
||||
uint32 ip; // client's IP address
|
||||
uint32 wid; // client's WorldID#
|
||||
@@ -85,6 +86,10 @@ public:
|
||||
|
||||
Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name);
|
||||
~Zone();
|
||||
|
||||
/* When zone has its own version of time */
|
||||
bool is_zone_time_localized;
|
||||
|
||||
bool Init(bool iStaticZone);
|
||||
bool LoadZoneCFG(const char* filename, uint16 instance_id, bool DontLoadDefault = false);
|
||||
bool SaveZoneCFG();
|
||||
@@ -153,7 +158,7 @@ public:
|
||||
inline bool InstantGrids() { return(!initgrids_timer.Enabled()); }
|
||||
void SetStaticZone(bool sz) { staticzone = sz; }
|
||||
inline bool IsStaticZone() { return staticzone; }
|
||||
inline void GotCurTime(bool time) { gottime = time; }
|
||||
inline void SetZoneHasCurrentTime(bool time) { zone_has_current_time = time; }
|
||||
|
||||
void SpawnConditionChanged(const SpawnCondition &c, int16 old_value);
|
||||
|
||||
@@ -206,7 +211,7 @@ public:
|
||||
EQTime zone_time;
|
||||
void GetTimeSync();
|
||||
void SetDate(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute);
|
||||
void SetTime(uint8 hour, uint8 minute);
|
||||
void SetTime(uint8 hour, uint8 minute, bool update_world = true);
|
||||
|
||||
void weatherSend();
|
||||
bool CanBind() const { return(can_bind); }
|
||||
@@ -319,7 +324,7 @@ private:
|
||||
|
||||
|
||||
bool staticzone;
|
||||
bool gottime;
|
||||
bool zone_has_current_time;
|
||||
|
||||
uint32 pQueuedMerchantsWorkID;
|
||||
uint32 pQueuedTempMerchantsWorkID;
|
||||
|
||||
+155
-146
@@ -196,7 +196,7 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct
|
||||
zone_data->time_type = atoi(row[30]);
|
||||
|
||||
//not in the DB yet:
|
||||
zone_data->gravity = atof(row[56]);
|
||||
zone_data->gravity = atof(row[56]);
|
||||
Log.Out(Logs::General, Logs::Debug, "Zone Gravity is %f", zone_data->gravity);
|
||||
allow_mercs = true;
|
||||
|
||||
@@ -248,7 +248,7 @@ void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint3
|
||||
|
||||
if(time_left == 0) {
|
||||
std::string query = StringFormat("DELETE FROM `respawn_times` WHERE `id` = %u AND `instance_id` = %u", spawn2_id, instance_id);
|
||||
QueryDatabase(query);
|
||||
QueryDatabase(query);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -258,14 +258,14 @@ void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint3
|
||||
"start, "
|
||||
"duration, "
|
||||
"instance_id) "
|
||||
"VALUES "
|
||||
"VALUES "
|
||||
"(%u, "
|
||||
"%u, "
|
||||
"%u, "
|
||||
"%u)",
|
||||
spawn2_id,
|
||||
spawn2_id,
|
||||
current_time,
|
||||
time_left,
|
||||
time_left,
|
||||
instance_id
|
||||
);
|
||||
QueryDatabase(query);
|
||||
@@ -1054,8 +1054,8 @@ bool ZoneDatabase::LoadCharacterLanguages(uint32 character_id, PlayerProfile_Str
|
||||
for (i = 0; i < MAX_PP_LANGUAGE; ++i)
|
||||
pp->languages[i] = 0;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]);
|
||||
if (i < MAX_PP_LANGUAGE){
|
||||
pp->languages[i] = atoi(row[1]);
|
||||
}
|
||||
@@ -1102,14 +1102,14 @@ bool ZoneDatabase::LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct
|
||||
"FROM "
|
||||
"`character_skills` "
|
||||
"WHERE `id` = %u ORDER BY `skill_id`", character_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
auto results = database.QueryDatabase(query);
|
||||
int i = 0;
|
||||
/* Initialize Skill */
|
||||
for (i = 0; i < MAX_PP_SKILL; ++i)
|
||||
pp->skills[i] = 0;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]);
|
||||
if (i < MAX_PP_SKILL)
|
||||
pp->skills[i] = atoi(row[1]);
|
||||
}
|
||||
@@ -1260,7 +1260,7 @@ bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struc
|
||||
|
||||
bool ZoneDatabase::LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `is_home` FROM `character_bind` WHERE `id` = %u LIMIT 2", character_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
|
||||
@@ -1706,15 +1706,15 @@ bool ZoneDatabase::SaveCharacterCurrency(uint32 character_id, PlayerProfile_Stru
|
||||
pp->careerRadCrystals,
|
||||
pp->currentEbonCrystals,
|
||||
pp->careerEbonCrystals);
|
||||
auto results = database.QueryDatabase(query);
|
||||
Log.Out(Logs::General, Logs::None, "Saving Currency for character ID: %i, done", character_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
Log.Out(Logs::General, Logs::None, "Saving Currency for character ID: %i, done", character_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level){
|
||||
std::string rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value)"
|
||||
" VALUES (%u, %u, %u)",
|
||||
character_id, aa_id, current_level);
|
||||
bool ZoneDatabase::SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level, uint32 charges){
|
||||
std::string rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value, charges)"
|
||||
" VALUES (%u, %u, %u, %u)",
|
||||
character_id, aa_id, current_level, charges);
|
||||
auto results = QueryDatabase(rquery);
|
||||
Log.Out(Logs::General, Logs::None, "Saving AA for character ID: %u, aa_id: %u current_level: %u", character_id, aa_id, current_level);
|
||||
return true;
|
||||
@@ -1803,7 +1803,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
|
||||
std::string where_condition = "";
|
||||
|
||||
if (bulk_load){
|
||||
Log.Out(Logs::General, Logs::Debug, "Performing bulk NPC Types load");
|
||||
Log.Out(Logs::General, Logs::Debug, "Performing bulk NPC Types load");
|
||||
where_condition = StringFormat(
|
||||
"INNER JOIN spawnentry ON npc_types.id = spawnentry.npcID "
|
||||
"INNER JOIN spawn2 ON spawnentry.spawngroupID = spawn2.spawngroupID "
|
||||
@@ -1911,7 +1911,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
|
||||
"npc_types.handtexture, "
|
||||
"npc_types.legtexture, "
|
||||
"npc_types.feettexture "
|
||||
"FROM npc_types %s",
|
||||
"FROM npc_types %s",
|
||||
where_condition.c_str()
|
||||
);
|
||||
|
||||
@@ -2184,7 +2184,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const NPCType *npc;
|
||||
const NPCType *npc = nullptr;
|
||||
|
||||
// Process each row returned.
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
@@ -2370,7 +2370,7 @@ bool ZoneDatabase::LoadCurrentMerc(Client *client) {
|
||||
|
||||
if(!results.Success())
|
||||
return false;
|
||||
|
||||
|
||||
if(results.RowCount() == 0)
|
||||
return false;
|
||||
|
||||
@@ -2505,7 +2505,7 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) {
|
||||
"TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, "
|
||||
"CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, "
|
||||
"caston_x, Persistent, caston_y, caston_z, ExtraDIChance) "
|
||||
"VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);",
|
||||
"VALUES (%u, %u, %u, %u, %u, %d, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);",
|
||||
merc->GetMercID(), buffs[buffCount].spellid, buffs[buffCount].casterlevel,
|
||||
spells[buffs[buffCount].spellid].buffdurationformula, buffs[buffCount].ticsremaining,
|
||||
CalculatePoisonCounters(buffs[buffCount].spellid) > 0 ? buffs[buffCount].counters : 0,
|
||||
@@ -2981,47 +2981,50 @@ void ZoneDatabase::SaveBuffs(Client *client) {
|
||||
|
||||
query = StringFormat("INSERT INTO `character_buffs` (character_id, slot_id, spell_id, "
|
||||
"caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, "
|
||||
"magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z, ExtraDIChance) "
|
||||
"VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', "
|
||||
"'%i', '%i', '%i', '%i')", client->CharacterID(), index, buffs[index].spellid,
|
||||
"magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z, ExtraDIChance, "
|
||||
"instrument_mod) "
|
||||
"VALUES('%u', '%u', '%u', '%u', '%s', '%d', '%u', '%u', '%u', '%u', '%u', '%u', "
|
||||
"'%i', '%i', '%i', '%i', '%i')", client->CharacterID(), index, buffs[index].spellid,
|
||||
buffs[index].casterlevel, buffs[index].caster_name, buffs[index].ticsremaining,
|
||||
buffs[index].counters, buffs[index].numhits, buffs[index].melee_rune,
|
||||
buffs[index].magic_rune, buffs[index].persistant_buff, buffs[index].dot_rune,
|
||||
buffs[index].caston_x, buffs[index].caston_y, buffs[index].caston_z,
|
||||
buffs[index].ExtraDIChance);
|
||||
buffs[index].ExtraDIChance, buffs[index].instrument_mod);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneDatabase::LoadBuffs(Client *client) {
|
||||
void ZoneDatabase::LoadBuffs(Client *client)
|
||||
{
|
||||
|
||||
Buffs_Struct *buffs = client->GetBuffs();
|
||||
uint32 max_slots = client->GetMaxBuffSlots();
|
||||
|
||||
for(int index = 0; index < max_slots; ++index)
|
||||
for (int index = 0; index < max_slots; ++index)
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
|
||||
std::string query = StringFormat("SELECT spell_id, slot_id, caster_level, caster_name, ticsremaining, "
|
||||
"counters, numhits, melee_rune, magic_rune, persistent, dot_rune, "
|
||||
"caston_x, caston_y, caston_z, ExtraDIChance "
|
||||
"FROM `character_buffs` WHERE `character_id` = '%u'", client->CharacterID());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
"counters, numhits, melee_rune, magic_rune, persistent, dot_rune, "
|
||||
"caston_x, caston_y, caston_z, ExtraDIChance, instrument_mod "
|
||||
"FROM `character_buffs` WHERE `character_id` = '%u'",
|
||||
client->CharacterID());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 slot_id = atoul(row[1]);
|
||||
if(slot_id >= client->GetMaxBuffSlots())
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 slot_id = atoul(row[1]);
|
||||
if (slot_id >= client->GetMaxBuffSlots())
|
||||
continue;
|
||||
|
||||
uint32 spell_id = atoul(row[0]);
|
||||
if(!IsValidSpell(spell_id))
|
||||
continue;
|
||||
uint32 spell_id = atoul(row[0]);
|
||||
if (!IsValidSpell(spell_id))
|
||||
continue;
|
||||
|
||||
Client *caster = entity_list.GetClientByName(row[3]);
|
||||
Client *caster = entity_list.GetClientByName(row[3]);
|
||||
uint32 caster_level = atoi(row[2]);
|
||||
uint32 ticsremaining = atoul(row[4]);
|
||||
int32 ticsremaining = atoi(row[4]);
|
||||
uint32 counters = atoul(row[5]);
|
||||
uint32 numhits = atoul(row[6]);
|
||||
uint32 melee_rune = atoul(row[7]);
|
||||
@@ -3032,53 +3035,54 @@ void ZoneDatabase::LoadBuffs(Client *client) {
|
||||
int32 caston_y = atoul(row[12]);
|
||||
int32 caston_z = atoul(row[13]);
|
||||
int32 ExtraDIChance = atoul(row[14]);
|
||||
uint32 instrument_mod = atoul(row[15]);
|
||||
|
||||
buffs[slot_id].spellid = spell_id;
|
||||
buffs[slot_id].casterlevel = caster_level;
|
||||
buffs[slot_id].casterlevel = caster_level;
|
||||
|
||||
if(caster) {
|
||||
buffs[slot_id].casterid = caster->GetID();
|
||||
strcpy(buffs[slot_id].caster_name, caster->GetName());
|
||||
buffs[slot_id].client = true;
|
||||
} else {
|
||||
buffs[slot_id].casterid = 0;
|
||||
if (caster) {
|
||||
buffs[slot_id].casterid = caster->GetID();
|
||||
strcpy(buffs[slot_id].caster_name, caster->GetName());
|
||||
buffs[slot_id].client = true;
|
||||
} else {
|
||||
buffs[slot_id].casterid = 0;
|
||||
strcpy(buffs[slot_id].caster_name, "");
|
||||
buffs[slot_id].client = false;
|
||||
}
|
||||
}
|
||||
|
||||
buffs[slot_id].ticsremaining = ticsremaining;
|
||||
buffs[slot_id].ticsremaining = ticsremaining;
|
||||
buffs[slot_id].counters = counters;
|
||||
buffs[slot_id].numhits = numhits;
|
||||
buffs[slot_id].melee_rune = melee_rune;
|
||||
buffs[slot_id].magic_rune = magic_rune;
|
||||
buffs[slot_id].persistant_buff = persistent? true: false;
|
||||
buffs[slot_id].persistant_buff = persistent ? true : false;
|
||||
buffs[slot_id].dot_rune = dot_rune;
|
||||
buffs[slot_id].caston_x = caston_x;
|
||||
buffs[slot_id].caston_y = caston_y;
|
||||
buffs[slot_id].caston_z = caston_z;
|
||||
buffs[slot_id].ExtraDIChance = ExtraDIChance;
|
||||
buffs[slot_id].RootBreakChance = 0;
|
||||
buffs[slot_id].UpdateClient = false;
|
||||
|
||||
}
|
||||
buffs[slot_id].caston_y = caston_y;
|
||||
buffs[slot_id].caston_z = caston_z;
|
||||
buffs[slot_id].ExtraDIChance = ExtraDIChance;
|
||||
buffs[slot_id].RootBreakChance = 0;
|
||||
buffs[slot_id].UpdateClient = false;
|
||||
buffs[slot_id].instrument_mod = instrument_mod;
|
||||
}
|
||||
|
||||
max_slots = client->GetMaxBuffSlots();
|
||||
for(int index = 0; index < max_slots; ++index) {
|
||||
if(!IsValidSpell(buffs[index].spellid))
|
||||
for (int index = 0; index < max_slots; ++index) {
|
||||
if (!IsValidSpell(buffs[index].spellid))
|
||||
continue;
|
||||
|
||||
for(int effectIndex = 0; effectIndex < 12; ++effectIndex) {
|
||||
for (int effectIndex = 0; effectIndex < 12; ++effectIndex) {
|
||||
|
||||
if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Charm) {
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Illusion) {
|
||||
if(buffs[index].persistant_buff)
|
||||
break;
|
||||
if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Illusion) {
|
||||
if (buffs[index].persistant_buff)
|
||||
break;
|
||||
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3124,16 +3128,16 @@ void ZoneDatabase::SavePetInfo(Client *client)
|
||||
if (query.length() == 0)
|
||||
query = StringFormat("INSERT INTO `character_pet_buffs` "
|
||||
"(`char_id`, `pet`, `slot`, `spell_id`, `caster_level`, "
|
||||
"`ticsremaining`, `counters`) "
|
||||
"VALUES (%u, %u, %u, %u, %u, %u, %d)",
|
||||
"`ticsremaining`, `counters`, `instrument_mod`) "
|
||||
"VALUES (%u, %u, %u, %u, %u, %d, %d, %u)",
|
||||
client->CharacterID(), pet, index, petinfo->Buffs[index].spellid,
|
||||
petinfo->Buffs[index].level, petinfo->Buffs[index].duration,
|
||||
petinfo->Buffs[index].counters);
|
||||
petinfo->Buffs[index].counters, petinfo->Buffs[index].bard_modifier);
|
||||
else
|
||||
query += StringFormat(", (%u, %u, %u, %u, %u, %u, %d)",
|
||||
query += StringFormat(", (%u, %u, %u, %u, %u, %d, %d, %u)",
|
||||
client->CharacterID(), pet, index, petinfo->Buffs[index].spellid,
|
||||
petinfo->Buffs[index].level, petinfo->Buffs[index].duration,
|
||||
petinfo->Buffs[index].counters);
|
||||
petinfo->Buffs[index].counters, petinfo->Buffs[index].bard_modifier);
|
||||
}
|
||||
database.QueryDatabase(query);
|
||||
query.clear();
|
||||
@@ -3171,7 +3175,8 @@ void ZoneDatabase::UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ZoneDatabase::LoadPetInfo(Client *client) {
|
||||
void ZoneDatabase::LoadPetInfo(Client *client)
|
||||
{
|
||||
|
||||
// Load current pet and suspended pet
|
||||
PetInfo *petinfo = client->GetPetInfo(0);
|
||||
@@ -3180,17 +3185,18 @@ void ZoneDatabase::LoadPetInfo(Client *client) {
|
||||
memset(petinfo, 0, sizeof(PetInfo));
|
||||
memset(suspended, 0, sizeof(PetInfo));
|
||||
|
||||
std::string query = StringFormat("SELECT `pet`, `petname`, `petpower`, `spell_id`, "
|
||||
"`hp`, `mana`, `size` FROM `character_pet_info` "
|
||||
"WHERE `char_id` = %u", client->CharacterID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
std::string query = StringFormat("SELECT `pet`, `petname`, `petpower`, `spell_id`, "
|
||||
"`hp`, `mana`, `size` FROM `character_pet_info` "
|
||||
"WHERE `char_id` = %u",
|
||||
client->CharacterID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PetInfo *pi;
|
||||
PetInfo *pi;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint16 pet = atoi(row[0]);
|
||||
uint16 pet = atoi(row[0]);
|
||||
|
||||
if (pet == 0)
|
||||
pi = petinfo;
|
||||
@@ -3199,7 +3205,7 @@ void ZoneDatabase::LoadPetInfo(Client *client) {
|
||||
else
|
||||
continue;
|
||||
|
||||
strncpy(pi->Name,row[1],64);
|
||||
strncpy(pi->Name, row[1], 64);
|
||||
pi->petpower = atoi(row[2]);
|
||||
pi->SpellID = atoi(row[3]);
|
||||
pi->HP = atoul(row[4]);
|
||||
@@ -3207,56 +3213,60 @@ void ZoneDatabase::LoadPetInfo(Client *client) {
|
||||
pi->size = atof(row[6]);
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT `pet`, `slot`, `spell_id`, `caster_level`, `castername`, "
|
||||
"`ticsremaining`, `counters` FROM `character_pet_buffs` "
|
||||
"WHERE `char_id` = %u", client->CharacterID());
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint16 pet = atoi(row[0]);
|
||||
if (pet == 0)
|
||||
pi = petinfo;
|
||||
else if (pet == 1)
|
||||
pi = suspended;
|
||||
else
|
||||
continue;
|
||||
|
||||
uint32 slot_id = atoul(row[1]);
|
||||
if(slot_id >= RuleI(Spells, MaxTotalSlotsPET))
|
||||
continue;
|
||||
|
||||
uint32 spell_id = atoul(row[2]);
|
||||
if(!IsValidSpell(spell_id))
|
||||
continue;
|
||||
|
||||
uint32 caster_level = atoi(row[3]);
|
||||
int caster_id = 0;
|
||||
// The castername field is currently unused
|
||||
uint32 ticsremaining = atoul(row[5]);
|
||||
uint32 counters = atoul(row[6]);
|
||||
|
||||
pi->Buffs[slot_id].spellid = spell_id;
|
||||
pi->Buffs[slot_id].level = caster_level;
|
||||
pi->Buffs[slot_id].player_id = caster_id;
|
||||
pi->Buffs[slot_id].slotid = 2; // Always 2 in buffs struct for real buffs
|
||||
|
||||
pi->Buffs[slot_id].duration = ticsremaining;
|
||||
pi->Buffs[slot_id].counters = counters;
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT `pet`, `slot`, `item_id` "
|
||||
"FROM `character_pet_inventory` "
|
||||
"WHERE `char_id`=%u",client->CharacterID());
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
query = StringFormat("SELECT `pet`, `slot`, `spell_id`, `caster_level`, `castername`, "
|
||||
"`ticsremaining`, `counters`, `instrument_mod` FROM `character_pet_buffs` "
|
||||
"WHERE `char_id` = %u",
|
||||
client->CharacterID());
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint16 pet = atoi(row[0]);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint16 pet = atoi(row[0]);
|
||||
if (pet == 0)
|
||||
pi = petinfo;
|
||||
else if (pet == 1)
|
||||
pi = suspended;
|
||||
else
|
||||
continue;
|
||||
|
||||
uint32 slot_id = atoul(row[1]);
|
||||
if (slot_id >= RuleI(Spells, MaxTotalSlotsPET))
|
||||
continue;
|
||||
|
||||
uint32 spell_id = atoul(row[2]);
|
||||
if (!IsValidSpell(spell_id))
|
||||
continue;
|
||||
|
||||
uint32 caster_level = atoi(row[3]);
|
||||
int caster_id = 0;
|
||||
// The castername field is currently unused
|
||||
int32 ticsremaining = atoi(row[5]);
|
||||
uint32 counters = atoul(row[6]);
|
||||
uint8 bard_mod = atoul(row[7]);
|
||||
|
||||
pi->Buffs[slot_id].spellid = spell_id;
|
||||
pi->Buffs[slot_id].level = caster_level;
|
||||
pi->Buffs[slot_id].player_id = caster_id;
|
||||
pi->Buffs[slot_id].slotid = 2; // Always 2 in buffs struct for real buffs
|
||||
|
||||
pi->Buffs[slot_id].duration = ticsremaining;
|
||||
pi->Buffs[slot_id].counters = counters;
|
||||
pi->Buffs[slot_id].bard_modifier = bard_mod;
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT `pet`, `slot`, `item_id` "
|
||||
"FROM `character_pet_inventory` "
|
||||
"WHERE `char_id`=%u",
|
||||
client->CharacterID());
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint16 pet = atoi(row[0]);
|
||||
if (pet == 0)
|
||||
pi = petinfo;
|
||||
else if (pet == 1)
|
||||
@@ -3266,11 +3276,10 @@ void ZoneDatabase::LoadPetInfo(Client *client) {
|
||||
|
||||
int slot = atoi(row[1]);
|
||||
if (slot < EmuConstants::EQUIPMENT_BEGIN || slot > EmuConstants::EQUIPMENT_END)
|
||||
continue;
|
||||
|
||||
pi->Items[slot] = atoul(row[2]);
|
||||
}
|
||||
continue;
|
||||
|
||||
pi->Items[slot] = atoul(row[2]);
|
||||
}
|
||||
}
|
||||
|
||||
bool ZoneDatabase::GetFactionData(FactionMods* fm, uint32 class_mod, uint32 race_mod, uint32 deity_mod, int32 faction_id) {
|
||||
@@ -3390,7 +3399,7 @@ bool ZoneDatabase::SetCharacterFactionLevel(uint32 char_id, int32 faction_id, in
|
||||
"ON DUPLICATE KEY UPDATE `current_value`=%i,`temp`=%i",
|
||||
char_id, faction_id, value, temp, value, temp);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
|
||||
if (!results.Success())
|
||||
return false;
|
||||
else
|
||||
@@ -3535,7 +3544,7 @@ uint32 ZoneDatabase::GetCharacterCorpseDecayTimer(uint32 corpse_db_id){
|
||||
auto results = QueryDatabase(query);
|
||||
auto row = results.begin();
|
||||
if (results.Success() && results.RowsAffected() != 0)
|
||||
return atoul(row[0]);
|
||||
return atoul(row[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3622,8 +3631,8 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
|
||||
"`wc_6` = %u, "
|
||||
"`wc_7` = %u, "
|
||||
"`wc_8` = %u, "
|
||||
"`wc_9` = %u ",
|
||||
EscapeString(charname).c_str(),
|
||||
"`wc_9` = %u ",
|
||||
EscapeString(charname).c_str(),
|
||||
zoneid,
|
||||
instanceid,
|
||||
charid,
|
||||
@@ -3676,21 +3685,21 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
|
||||
corpse_items_query = StringFormat("REPLACE INTO `character_corpse_items` \n"
|
||||
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
|
||||
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
|
||||
last_insert_id,
|
||||
last_insert_id,
|
||||
dbpc->items[i].equip_slot,
|
||||
dbpc->items[i].item_id,
|
||||
dbpc->items[i].charges,
|
||||
dbpc->items[i].aug_1,
|
||||
dbpc->items[i].aug_2,
|
||||
dbpc->items[i].aug_3,
|
||||
dbpc->items[i].aug_4,
|
||||
dbpc->items[i].item_id,
|
||||
dbpc->items[i].charges,
|
||||
dbpc->items[i].aug_1,
|
||||
dbpc->items[i].aug_2,
|
||||
dbpc->items[i].aug_3,
|
||||
dbpc->items[i].aug_4,
|
||||
dbpc->items[i].aug_5,
|
||||
dbpc->items[i].aug_6,
|
||||
dbpc->items[i].attuned
|
||||
);
|
||||
first_entry = 1;
|
||||
}
|
||||
else{
|
||||
else{
|
||||
corpse_items_query = corpse_items_query + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
|
||||
last_insert_id,
|
||||
dbpc->items[i].equip_slot,
|
||||
|
||||
+1
-1
@@ -278,7 +278,7 @@ public:
|
||||
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, const glm::vec4& position, uint8 is_home);
|
||||
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp);
|
||||
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
|
||||
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level, uint32 charges);
|
||||
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
|
||||
|
||||
Reference in New Issue
Block a user