mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-21 14:48:20 +00:00
Merge branch 'master' into web_interface
This commit is contained in:
+3
-3
@@ -525,7 +525,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
|
||||
|
||||
NPCType *made_npc = nullptr;
|
||||
|
||||
const NPCType *npc_type = database.GetNPCType(pet.npc_id);
|
||||
const NPCType *npc_type = database.LoadNPCTypesData(pet.npc_id);
|
||||
if(npc_type == nullptr) {
|
||||
//log write
|
||||
Log.Out(Logs::General, Logs::Error, "Unknown npc type for swarm pet spell id: %d", spell_id);
|
||||
@@ -622,7 +622,7 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
|
||||
|
||||
NPCType *made_npc = nullptr;
|
||||
|
||||
const NPCType *npc_type = database.GetNPCType(typesid);
|
||||
const NPCType *npc_type = database.LoadNPCTypesData(typesid);
|
||||
if(npc_type == nullptr) {
|
||||
//log write
|
||||
Log.Out(Logs::General, Logs::Error, "Unknown npc type for swarm pet type id: %d", typesid);
|
||||
@@ -715,7 +715,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
return;
|
||||
|
||||
//assuming we have pets in our table; we take the first pet as a base type.
|
||||
const NPCType *base_type = database.GetNPCType(500);
|
||||
const NPCType *base_type = database.LoadNPCTypesData(500);
|
||||
NPCType *make_npc = new NPCType;
|
||||
memcpy(make_npc, base_type, sizeof(NPCType));
|
||||
|
||||
|
||||
+73
-52
@@ -363,13 +363,40 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
|
||||
//garunteed hit
|
||||
bool ghit = false;
|
||||
if((attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500)
|
||||
if((attacker->aabonuses.MeleeSkillCheck + attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500)
|
||||
ghit = true;
|
||||
|
||||
bool InFront = false;
|
||||
|
||||
if (attacker->InFrontMob(this, attacker->GetX(), attacker->GetY()))
|
||||
InFront = true;
|
||||
|
||||
/*
|
||||
This special ability adds a negative modifer to the defenders riposte/block/parry/chance
|
||||
therefore reducing the defenders chance to successfully avoid the melee attack. At present
|
||||
time this is the only way to fine tune counter these mods on players. This may
|
||||
ultimately end up being more useful as fields in npc_types.
|
||||
*/
|
||||
|
||||
int counter_all = 0;
|
||||
int counter_riposte = 0;
|
||||
int counter_block = 0;
|
||||
int counter_parry = 0;
|
||||
int counter_dodge = 0;
|
||||
|
||||
if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)){
|
||||
|
||||
counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0);
|
||||
counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE,1);
|
||||
counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2);
|
||||
counter_parry = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 3);
|
||||
counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// make enrage same as riposte
|
||||
/////////////////////////////////////////////////////////
|
||||
if (IsEnraged() && other->InFrontMob(this, other->GetX(), other->GetY())) {
|
||||
if (IsEnraged() && InFront) {
|
||||
damage = -3;
|
||||
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
||||
}
|
||||
@@ -378,9 +405,10 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
// riposte
|
||||
/////////////////////////////////////////////////////////
|
||||
float riposte_chance = 0.0f;
|
||||
if (CanRiposte && damage > 0 && CanThisClassRiposte() && other->InFrontMob(this, other->GetX(), other->GetY()))
|
||||
if (CanRiposte && damage > 0 && CanThisClassRiposte() && InFront)
|
||||
{
|
||||
riposte_chance = (100.0f + (float)defender->aabonuses.RiposteChance + (float)defender->spellbonuses.RiposteChance + (float)defender->itembonuses.RiposteChance) / 100.0f;
|
||||
riposte_chance = (100.0f + static_cast<float>(aabonuses.RiposteChance + spellbonuses.RiposteChance +
|
||||
itembonuses.RiposteChance - counter_riposte - counter_all)) / 100.0f;
|
||||
skill = GetSkill(SkillRiposte);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10);
|
||||
@@ -399,28 +427,19 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
bool bBlockFromRear = false;
|
||||
bool bShieldBlockFromRear = false;
|
||||
|
||||
if (this->IsClient()) {
|
||||
int aaChance = 0;
|
||||
// a successful roll on this does not mean a successful block is forthcoming. only that a chance to block
|
||||
// from a direction other than the rear is granted.
|
||||
|
||||
// a successful roll on this does not mean a successful block is forthcoming. only that a chance to block
|
||||
// from a direction other than the rear is granted.
|
||||
int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind;
|
||||
|
||||
//Live AA - HightenedAwareness
|
||||
int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind;
|
||||
|
||||
if (BlockBehindChance && zone->random.Roll(BlockBehindChance)) {
|
||||
bBlockFromRear = true;
|
||||
|
||||
if (spellbonuses.BlockBehind || itembonuses.BlockBehind)
|
||||
bShieldBlockFromRear = true; //This bonus should allow a chance to Shield Block from behind.
|
||||
}
|
||||
}
|
||||
if (BlockBehindChance && zone->random.Roll(BlockBehindChance))
|
||||
bBlockFromRear = true;
|
||||
|
||||
float block_chance = 0.0f;
|
||||
if (damage > 0 && CanThisClassBlock() && (other->InFrontMob(this, other->GetX(), other->GetY()) || bBlockFromRear)) {
|
||||
block_chance = (100.0f + (float)spellbonuses.IncreaseBlockChance + (float)itembonuses.IncreaseBlockChance) / 100.0f;
|
||||
if (damage > 0 && CanThisClassBlock() && (InFront || bBlockFromRear)) {
|
||||
block_chance = (100.0f + static_cast<float>(aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance +
|
||||
itembonuses.IncreaseBlockChance - counter_block - counter_all)) / 100.0f;
|
||||
skill = CastToClient()->GetSkill(SkillBlock);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10);
|
||||
@@ -436,32 +455,20 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
RollTable[1] = RollTable[0];
|
||||
}
|
||||
|
||||
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock)
|
||||
&& (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) {
|
||||
|
||||
float bonusShieldBlock = 0.0f;
|
||||
bonusShieldBlock = static_cast<float>(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock);
|
||||
RollTable[1] += bonusShieldBlock;
|
||||
}
|
||||
|
||||
if(IsClient() && damage > 0 && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock)
|
||||
&& (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) {
|
||||
if(CastToClient()->m_inv.GetItem(MainPrimary)) {
|
||||
float bonusStaffBlock = 0.0f;
|
||||
if (CastToClient()->m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HBlunt){
|
||||
bonusStaffBlock = static_cast<float>(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock);
|
||||
RollTable[1] += bonusStaffBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Try Shield Block OR TwoHandBluntBlockCheck
|
||||
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear))
|
||||
RollTable[1] += static_cast<float>(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock - counter_block - counter_all);
|
||||
|
||||
else if(damage > 0 && HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear))
|
||||
RollTable[1] += static_cast<float>(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock - counter_block - counter_all);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// parry
|
||||
//////////////////////////////////////////////////////
|
||||
float parry_chance = 0.0f;
|
||||
if (damage > 0 && CanThisClassParry() && other->InFrontMob(this, other->GetX(), other->GetY()))
|
||||
{
|
||||
parry_chance = (100.0f + (float)defender->spellbonuses.ParryChance + (float)defender->itembonuses.ParryChance) / 100.0f;
|
||||
if (damage > 0 && CanThisClassParry() && InFront){
|
||||
parry_chance = (100.0f + static_cast<float>(aabonuses.ParryChance + itembonuses.ParryChance +
|
||||
itembonuses.ParryChance - counter_parry - counter_all)) / 100.0f;
|
||||
skill = CastToClient()->GetSkill(SkillParry);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillParry, other, -10);
|
||||
@@ -482,9 +489,11 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
// dodge
|
||||
////////////////////////////////////////////////////////
|
||||
float dodge_chance = 0.0f;
|
||||
if (damage > 0 && CanThisClassDodge() && other->InFrontMob(this, other->GetX(), other->GetY()))
|
||||
{
|
||||
dodge_chance = (100.0f + (float)defender->spellbonuses.DodgeChance + (float)defender->itembonuses.DodgeChance) / 100.0f;
|
||||
if (damage > 0 && CanThisClassDodge() && InFront){
|
||||
|
||||
dodge_chance = (100.0f + static_cast<float>(aabonuses.DodgeChance + spellbonuses.DodgeChance +
|
||||
itembonuses.DodgeChance - counter_dodge - counter_all)) / 100.0f;
|
||||
|
||||
skill = CastToClient()->GetSkill(SkillDodge);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10);
|
||||
@@ -909,6 +918,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
|
||||
{
|
||||
int dmg = 0;
|
||||
int banedmg = 0;
|
||||
int x = 0;
|
||||
|
||||
if(!against || against->GetInvul() || against->GetSpecialAbility(IMMUNE_MELEE)){
|
||||
return 0;
|
||||
@@ -937,10 +947,20 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
|
||||
bool MagicWeapon = false;
|
||||
if(weapon_item->GetItem() && weapon_item->GetItem()->Magic)
|
||||
MagicWeapon = true;
|
||||
else {
|
||||
else
|
||||
if(spellbonuses.MagicWeapon || itembonuses.MagicWeapon)
|
||||
MagicWeapon = true;
|
||||
}
|
||||
else
|
||||
// An augment on the weapon that is marked magic makes
|
||||
// the item magical.
|
||||
for(x = 0; MagicWeapon == false && x < EmuConstants::ITEM_COMMON_SIZE; x++)
|
||||
{
|
||||
if(weapon_item->GetAugment(x) && weapon_item->GetAugment(x)->GetItem())
|
||||
{
|
||||
if (weapon_item->GetAugment(x)->GetItem()->Magic)
|
||||
MagicWeapon = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(MagicWeapon) {
|
||||
|
||||
@@ -2410,8 +2430,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
|
||||
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
|
||||
{
|
||||
|
||||
assert(other != nullptr);
|
||||
if(!other)
|
||||
return;
|
||||
|
||||
if (other == this)
|
||||
return;
|
||||
@@ -3536,6 +3556,10 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Melee Damage reduced to %d", damage);
|
||||
damage = ReduceAllDamage(damage);
|
||||
TryTriggerThreshHold(damage, SE_TriggerMeleeThreshold, attacker);
|
||||
|
||||
if (skill_used)
|
||||
CheckNumHitsRemaining(NumHit::IncomingHitSuccess);
|
||||
|
||||
} else {
|
||||
int32 origdmg = damage;
|
||||
damage = AffectMagicalDamage(damage, spell_id, iBuffTic, attacker);
|
||||
@@ -3551,9 +3575,6 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
TryTriggerThreshHold(damage, SE_TriggerSpellThreshold, attacker);
|
||||
}
|
||||
|
||||
if (skill_used)
|
||||
CheckNumHitsRemaining(NumHit::IncomingHitSuccess);
|
||||
|
||||
if(IsClient() && CastToClient()->sneaking){
|
||||
CastToClient()->sneaking = false;
|
||||
SendAppearancePacket(AT_Sneak, 0);
|
||||
|
||||
+133
-68
@@ -81,6 +81,8 @@ void Client::CalcBonuses()
|
||||
CalcAABonuses(&aabonuses); //we're not quite ready for this
|
||||
Log.Out(Logs::Detail, Logs::AA, "Finished calculating AA Bonuses for %s.", this->GetCleanName());
|
||||
|
||||
ProcessItemCaps(); // caps that depend on spell/aa bonuses
|
||||
|
||||
RecalcWeight();
|
||||
|
||||
CalcAC();
|
||||
@@ -139,7 +141,8 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
|
||||
// Clear item faction mods
|
||||
ClearItemFactionBonuses();
|
||||
ShieldEquiped(false);
|
||||
SetShieldEquiped(false);
|
||||
SetTwoHandBluntEquiped(false);
|
||||
|
||||
unsigned int i;
|
||||
//should not include 21 (SLOT_AMMO)
|
||||
@@ -149,9 +152,12 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
continue;
|
||||
AddItemBonuses(inst, newbon);
|
||||
|
||||
//Check if item is secondary slot is a 'shield'. Required for multiple spelll effects.
|
||||
if (i == MainSecondary && (m_inv.GetItem(MainSecondary)->GetItem()->ItemType == ItemTypeShield))
|
||||
ShieldEquiped(true);
|
||||
//These are given special flags due to how often they are checked for various spell effects.
|
||||
const Item_Struct *item = inst->GetItem();
|
||||
if (i == MainSecondary && (item && item->ItemType == ItemTypeShield))
|
||||
SetShieldEquiped(true);
|
||||
else if (i == MainPrimary && (item && item->ItemType == ItemType2HBlunt))
|
||||
SetTwoHandBluntEquiped(true);
|
||||
}
|
||||
|
||||
//Power Source Slot
|
||||
@@ -169,15 +175,34 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
continue;
|
||||
AddItemBonuses(inst, newbon, false, true);
|
||||
}
|
||||
// Caps
|
||||
if(newbon->HPRegen > CalcHPRegenCap())
|
||||
newbon->HPRegen = CalcHPRegenCap();
|
||||
|
||||
if(newbon->ManaRegen > CalcManaRegenCap())
|
||||
newbon->ManaRegen = CalcManaRegenCap();
|
||||
//Optional ability to have worn effects calculate as an addititive bonus instead of highest value
|
||||
if (RuleI(Spells, AdditiveBonusWornType) && RuleI(Spells, AdditiveBonusWornType) != ET_WornEffect){
|
||||
for (i = MainCharm; i < MainAmmo; i++) {
|
||||
const ItemInst* inst = m_inv[i];
|
||||
if(inst == 0)
|
||||
continue;
|
||||
AdditiveWornBonuses(inst, newbon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(newbon->EnduranceRegen > CalcEnduranceRegenCap())
|
||||
newbon->EnduranceRegen = CalcEnduranceRegenCap();
|
||||
// These item stat caps depend on spells/AAs so we process them after those are processed
|
||||
void Client::ProcessItemCaps()
|
||||
{
|
||||
itembonuses.HPRegen = std::min(itembonuses.HPRegen, CalcHPRegenCap());
|
||||
itembonuses.ManaRegen = std::min(itembonuses.ManaRegen, CalcManaRegenCap());
|
||||
itembonuses.EnduranceRegen = std::min(itembonuses.EnduranceRegen, CalcEnduranceRegenCap());
|
||||
|
||||
// The Sleeper Tomb Avatar proc counts towards item ATK
|
||||
// The client uses a 100 here, so using a 100 here the client and server will agree
|
||||
// For example, if you set the effect to be 200 it will get 100 item ATK and 100 spell ATK
|
||||
if (IsValidSpell(2434) && FindBuff(2434)) {
|
||||
itembonuses.ATK += 100;
|
||||
spellbonuses.ATK -= 100;
|
||||
}
|
||||
|
||||
itembonuses.ATK = std::min(itembonuses.ATK, CalcItemATKCap());
|
||||
}
|
||||
|
||||
void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug, bool isTribute) {
|
||||
@@ -210,6 +235,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
newbon->HP += item->HP;
|
||||
newbon->Mana += item->Mana;
|
||||
newbon->Endurance += item->Endur;
|
||||
newbon->ATK += item->Attack;
|
||||
newbon->STR += (item->AStr + item->HeroicStr);
|
||||
newbon->STA += (item->ASta + item->HeroicSta);
|
||||
newbon->DEX += (item->ADex + item->HeroicDex);
|
||||
@@ -263,6 +289,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
newbon->HP += CalcRecommendedLevelBonus( lvl, reclvl, item->HP );
|
||||
newbon->Mana += CalcRecommendedLevelBonus( lvl, reclvl, item->Mana );
|
||||
newbon->Endurance += CalcRecommendedLevelBonus( lvl, reclvl, item->Endur );
|
||||
newbon->ATK += CalcRecommendedLevelBonus( lvl, reclvl, item->Attack );
|
||||
newbon->STR += CalcRecommendedLevelBonus( lvl, reclvl, (item->AStr + item->HeroicStr) );
|
||||
newbon->STA += CalcRecommendedLevelBonus( lvl, reclvl, (item->ASta + item->HeroicSta) );
|
||||
newbon->DEX += CalcRecommendedLevelBonus( lvl, reclvl, (item->ADex + item->HeroicDex) );
|
||||
@@ -320,16 +347,6 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
if(item->EnduranceRegen > 0)
|
||||
newbon->EnduranceRegen += item->EnduranceRegen;
|
||||
|
||||
if(item->Attack > 0) {
|
||||
|
||||
int cap = RuleI(Character, ItemATKCap);
|
||||
cap += itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
||||
|
||||
if((newbon->ATK + item->Attack) > cap)
|
||||
newbon->ATK = RuleI(Character, ItemATKCap);
|
||||
else
|
||||
newbon->ATK += item->Attack;
|
||||
}
|
||||
if(item->DamageShield > 0) {
|
||||
if((newbon->DamageShield + item->DamageShield) > RuleI(Character, ItemDamageShieldCap))
|
||||
newbon->DamageShield = RuleI(Character, ItemDamageShieldCap);
|
||||
@@ -410,12 +427,12 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
else
|
||||
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, true);
|
||||
if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
}
|
||||
|
||||
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true);
|
||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0);
|
||||
}
|
||||
|
||||
switch(item->BardType)
|
||||
@@ -537,6 +554,45 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
|
||||
}
|
||||
|
||||
void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug) {
|
||||
|
||||
/*
|
||||
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.
|
||||
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
|
||||
which will also stack with regular (worntype 2) effects. [Ie set rule = 3 and item worntype = 3]
|
||||
*/
|
||||
|
||||
if(!inst || !inst->IsType(ItemClassCommon))
|
||||
return;
|
||||
|
||||
if(inst->GetAugmentType()==0 && isAug == true)
|
||||
return;
|
||||
|
||||
const Item_Struct *item = inst->GetItem();
|
||||
|
||||
if(!inst->IsEquipable(GetBaseRace(),GetClass()))
|
||||
return;
|
||||
|
||||
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
|
||||
|
||||
|
||||
if (!isAug)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||
AdditiveWornBonuses(inst->GetAugment(i),newbon,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::CalcEdibleBonuses(StatBonuses* newbon) {
|
||||
uint32 i;
|
||||
|
||||
@@ -639,7 +695,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
uint8 focus = IsFocusEffect(0, 0, true,effect);
|
||||
if (focus)
|
||||
{
|
||||
newbon->FocusEffects[focus] = effect;
|
||||
newbon->FocusEffects[focus] = static_cast<uint8>(effect);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -647,7 +703,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
{
|
||||
//Note: AA effects that use accuracy are skill limited, while spell effect is not.
|
||||
case SE_Accuracy:
|
||||
if ((base2 == -1) && (newbon->Accuracy[HIGHEST_SKILL+1] < base1))
|
||||
if ((base2 == ALL_SKILLS) && (newbon->Accuracy[HIGHEST_SKILL+1] < base1))
|
||||
newbon->Accuracy[HIGHEST_SKILL+1] = base1;
|
||||
else if (newbon->Accuracy[base2] < base1)
|
||||
newbon->Accuracy[base2] += base1;
|
||||
@@ -989,7 +1045,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_HitChance:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
newbon->HitChanceEffect[HIGHEST_SKILL+1] += base1;
|
||||
else
|
||||
newbon->HitChanceEffect[base2] += base1;
|
||||
@@ -1045,7 +1101,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_CriticalHitChance:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
newbon->CriticalHitChance[HIGHEST_SKILL+1] += base1;
|
||||
else
|
||||
newbon->CriticalHitChance[base2] += base1;
|
||||
@@ -1055,7 +1111,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
case SE_CriticalDamageMob:
|
||||
{
|
||||
// base1 = effect value, base2 = skill restrictions(-1 for all)
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
newbon->CritDmgMob[HIGHEST_SKILL+1] += base1;
|
||||
else
|
||||
newbon->CritDmgMob[base2] += base1;
|
||||
@@ -1083,7 +1139,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_SkillDamageAmount:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
newbon->SkillDamageAmount[HIGHEST_SKILL+1] += base1;
|
||||
else
|
||||
newbon->SkillDamageAmount[base2] += base1;
|
||||
@@ -1100,7 +1156,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_DamageModifier:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
newbon->DamageModifier[HIGHEST_SKILL+1] += base1;
|
||||
else
|
||||
newbon->DamageModifier[base2] += base1;
|
||||
@@ -1109,7 +1165,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_DamageModifier2:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
newbon->DamageModifier2[HIGHEST_SKILL+1] += base1;
|
||||
else
|
||||
newbon->DamageModifier2[base2] += base1;
|
||||
@@ -1393,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, false, buffs[i].ticsremaining,i);
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining,i);
|
||||
|
||||
if (buffs[i].numhits > 0)
|
||||
Numhits(true);
|
||||
@@ -1416,10 +1472,11 @@ 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, bool item_bonus, uint32 ticsremaining, int buffslot,
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, uint8 WornType, uint32 ticsremaining, int buffslot,
|
||||
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
||||
{
|
||||
int i, effect_value, base2, max, effectid;
|
||||
bool AdditiveWornBonus = false;
|
||||
Mob *caster = nullptr;
|
||||
|
||||
if(!IsAISpellEffect && !IsValidSpell(spell_id))
|
||||
@@ -1439,10 +1496,19 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
uint8 focus = IsFocusEffect(spell_id, i);
|
||||
if (focus)
|
||||
{
|
||||
new_bonus->FocusEffects[focus] = spells[spell_id].effectid[i];
|
||||
if (WornType){
|
||||
if (RuleB(Spells, UseAdditiveFocusFromWornSlot))
|
||||
new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i];
|
||||
}
|
||||
|
||||
else
|
||||
new_bonus->FocusEffects[focus] = static_cast<uint8>(spells[spell_id].effectid[i]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType))
|
||||
AdditiveWornBonus = true;
|
||||
|
||||
effectid = spells[spell_id].effectid[i];
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining);
|
||||
@@ -1808,8 +1874,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_CriticalHitChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus) {
|
||||
if(base2 == -1)
|
||||
if (AdditiveWornBonus) {
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
new_bonus->CriticalHitChance[base2] += effect_value;
|
||||
@@ -1817,16 +1883,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
else if(effect_value < 0) {
|
||||
|
||||
if(base2 == -1 && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] > effect_value)
|
||||
if(base2 == ALL_SKILLS && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] > effect_value)
|
||||
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value;
|
||||
else if(base2 != -1 && new_bonus->CriticalHitChance[base2] > effect_value)
|
||||
else if(base2 != ALL_SKILLS && new_bonus->CriticalHitChance[base2] > effect_value)
|
||||
new_bonus->CriticalHitChance[base2] = effect_value;
|
||||
}
|
||||
|
||||
|
||||
else if(base2 == -1 && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] < effect_value)
|
||||
else if(base2 == ALL_SKILLS && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] < effect_value)
|
||||
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value;
|
||||
else if(base2 != -1 && new_bonus->CriticalHitChance[base2] < effect_value)
|
||||
else if(base2 != ALL_SKILLS && new_bonus->CriticalHitChance[base2] < effect_value)
|
||||
new_bonus->CriticalHitChance[base2] = effect_value;
|
||||
|
||||
break;
|
||||
@@ -1834,7 +1900,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_CrippBlowChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->CrippBlowChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->CrippBlowChance > effect_value))
|
||||
@@ -1848,7 +1914,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_AvoidMeleeChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->AvoidMeleeChanceEffect += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->AvoidMeleeChanceEffect > effect_value))
|
||||
@@ -1861,7 +1927,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_RiposteChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->RiposteChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->RiposteChance > effect_value))
|
||||
@@ -1874,7 +1940,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_DodgeChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->DodgeChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->DodgeChance > effect_value))
|
||||
@@ -1887,7 +1953,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_ParryChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->ParryChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->ParryChance > effect_value))
|
||||
@@ -1900,7 +1966,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_DualWieldChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->DualWieldChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->DualWieldChance > effect_value))
|
||||
@@ -1914,7 +1980,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_DoubleAttackChance:
|
||||
{
|
||||
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->DoubleAttackChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->DoubleAttackChance > effect_value))
|
||||
@@ -1928,7 +1994,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_TripleAttackChance:
|
||||
{
|
||||
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->TripleAttackChance += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->TripleAttackChance > effect_value))
|
||||
@@ -1941,7 +2007,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_MeleeLifetap:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->MeleeLifetap += spells[spell_id].base[i];
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->MeleeLifetap > effect_value))
|
||||
@@ -1990,7 +2056,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_HundredHands:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->HundredHands += effect_value;
|
||||
|
||||
if (effect_value > 0 && effect_value > new_bonus->HundredHands)
|
||||
@@ -2004,7 +2070,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
{
|
||||
if(new_bonus->MeleeSkillCheck < effect_value) {
|
||||
new_bonus->MeleeSkillCheck = effect_value;
|
||||
new_bonus->MeleeSkillCheckSkill = base2==-1?255:base2;
|
||||
new_bonus->MeleeSkillCheckSkill = base2==ALL_SKILLS?255:base2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2012,14 +2078,14 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_HitChance:
|
||||
{
|
||||
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus){
|
||||
if(base2 == -1)
|
||||
if (AdditiveWornBonus){
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->HitChanceEffect[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
new_bonus->HitChanceEffect[base2] += effect_value;
|
||||
}
|
||||
|
||||
else if(base2 == -1){
|
||||
else if(base2 == ALL_SKILLS){
|
||||
|
||||
if ((effect_value < 0) && (new_bonus->HitChanceEffect[HIGHEST_SKILL+1] > effect_value))
|
||||
new_bonus->HitChanceEffect[HIGHEST_SKILL+1] = effect_value;
|
||||
@@ -2045,7 +2111,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_DamageModifier:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->DamageModifier[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
new_bonus->DamageModifier[base2] += effect_value;
|
||||
@@ -2054,7 +2120,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_DamageModifier2:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->DamageModifier2[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
new_bonus->DamageModifier2[base2] += effect_value;
|
||||
@@ -2063,7 +2129,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_MinDamageModifier:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->MinDamageModifier[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
new_bonus->MinDamageModifier[base2] += effect_value;
|
||||
@@ -2079,7 +2145,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_ProcChance:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->ProcChanceSPA += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (new_bonus->ProcChanceSPA > effect_value))
|
||||
@@ -2117,7 +2183,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_DivineSave:
|
||||
{
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus) {
|
||||
if (AdditiveWornBonus) {
|
||||
new_bonus->DivineSaveChance[0] += effect_value;
|
||||
new_bonus->DivineSaveChance[1] = 0;
|
||||
}
|
||||
@@ -2126,7 +2192,6 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
{
|
||||
new_bonus->DivineSaveChance[0] = effect_value;
|
||||
new_bonus->DivineSaveChance[1] = base2;
|
||||
//SetDeathSaveChance(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2162,14 +2227,14 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
{
|
||||
//When using npc_spells_effects if MAX value set, use stackable quest based modifier.
|
||||
if (IsAISpellEffect && max){
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
SkillDmgTaken_Mod[HIGHEST_SKILL+1] = effect_value;
|
||||
else
|
||||
SkillDmgTaken_Mod[base2] = effect_value;
|
||||
}
|
||||
else {
|
||||
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->SkillDmgTaken[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
new_bonus->SkillDmgTaken[base2] += effect_value;
|
||||
@@ -2278,7 +2343,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_CriticalDamageMob:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->CritDmgMob[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
new_bonus->CritDmgMob[base2] += effect_value;
|
||||
@@ -2294,7 +2359,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_SkillDamageAmount:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->SkillDamageAmount[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
new_bonus->SkillDamageAmount[base2] += effect_value;
|
||||
@@ -2399,7 +2464,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_SkillDamageAmount2:
|
||||
{
|
||||
if(base2 == -1)
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->SkillDamageAmount2[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
new_bonus->SkillDamageAmount2[base2] += effect_value;
|
||||
@@ -3046,12 +3111,12 @@ void NPC::CalcItemBonuses(StatBonuses *newbon)
|
||||
newbon->ProcChance += cur->CombatEffects;
|
||||
}
|
||||
if (cur->Worn.Effect>0 && (cur->Worn.Type == ET_WornEffect)) { // latent effects
|
||||
ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon);
|
||||
ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon, 0, cur->Worn.Type);
|
||||
}
|
||||
|
||||
if (RuleB(Spells, NPC_UseFocusFromItems)){
|
||||
if (cur->Focus.Effect>0 && (cur->Focus.Type == ET_Focus)){ // focus effects
|
||||
ApplySpellsBonuses(cur->Focus.Effect, cur->Focus.Level, newbon, 0, true);
|
||||
ApplySpellsBonuses(cur->Focus.Effect, cur->Focus.Level, newbon);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-31
@@ -97,7 +97,7 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm
|
||||
|
||||
strcpy(this->name, this->GetCleanName());
|
||||
|
||||
active_light = spell_light = equip_light = innate_light = NOT_USED;
|
||||
memset(&m_Light, 0, sizeof(LightProfile_Struct));
|
||||
}
|
||||
|
||||
// This constructor is used when the bot is loaded out of the database
|
||||
@@ -213,8 +213,6 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
||||
if(cur_mana > max_mana)
|
||||
cur_mana = max_mana;
|
||||
cur_end = max_end;
|
||||
|
||||
active_light = spell_light = equip_light = innate_light = NOT_USED;
|
||||
}
|
||||
|
||||
Bot::~Bot() {
|
||||
@@ -4121,8 +4119,8 @@ void Bot::Spawn(Client* botCharacterOwner, std::string* errorMessage) {
|
||||
// Level the bot to the same level as the bot owner
|
||||
//this->SetLevel(botCharacterOwner->GetLevel());
|
||||
|
||||
UpdateEquipLightValue();
|
||||
UpdateActiveLightValue();
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
|
||||
entity_list.AddBot(this, true, true);
|
||||
|
||||
@@ -4132,7 +4130,7 @@ void Bot::Spawn(Client* botCharacterOwner, std::string* errorMessage) {
|
||||
this->SendPosition();
|
||||
|
||||
// there is something askew with spawn struct appearance fields...
|
||||
// I re-enabled this until I can sort it out -U
|
||||
// I re-enabled this until I can sort it out
|
||||
uint32 itemID = 0;
|
||||
uint8 materialFromSlot = 0xFF;
|
||||
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) {
|
||||
@@ -4187,7 +4185,7 @@ void Bot::RemoveBotItemBySlot(uint32 slotID, std::string *errorMessage) {
|
||||
*errorMessage = std::string(results.ErrorMessage());
|
||||
|
||||
m_inv.DeleteItem(slotID);
|
||||
UpdateEquipLightValue();
|
||||
UpdateEquipmentLight();
|
||||
}
|
||||
|
||||
// Retrieves all the inventory records from the database for this bot.
|
||||
@@ -4249,7 +4247,7 @@ void Bot::GetBotItems(std::string* errorMessage, Inventory &inv) {
|
||||
|
||||
}
|
||||
|
||||
UpdateEquipLightValue();
|
||||
UpdateEquipmentLight();
|
||||
}
|
||||
|
||||
// Returns the inventory record for this bot from the database for the specified equipment slot.
|
||||
@@ -4375,8 +4373,8 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
||||
ns->spawn.size = 0;
|
||||
ns->spawn.NPC = 0; // 0=player,1=npc,2=pc corpse,3=npc corpse
|
||||
|
||||
UpdateActiveLightValue();
|
||||
ns->spawn.light = active_light;
|
||||
UpdateActiveLight();
|
||||
ns->spawn.light = m_Light.Type.Active;
|
||||
|
||||
ns->spawn.helm = helmtexture; //0xFF;
|
||||
ns->spawn.equip_chest2 = texture; //0xFF;
|
||||
@@ -4395,24 +4393,24 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
||||
item = inst->GetItem();
|
||||
if (item != 0)
|
||||
{
|
||||
ns->spawn.equipment[i].material = item->Material;
|
||||
ns->spawn.equipment[i].elitematerial = item->EliteMaterial;
|
||||
ns->spawn.equipment[i].heroforgemodel = item->HerosForgeModel;
|
||||
ns->spawn.equipment[i].Material = item->Material;
|
||||
ns->spawn.equipment[i].EliteMaterial = item->EliteMaterial;
|
||||
ns->spawn.equipment[i].HeroForgeModel = item->HerosForgeModel;
|
||||
if (armor_tint[i])
|
||||
{
|
||||
ns->spawn.colors[i].color = armor_tint[i];
|
||||
ns->spawn.colors[i].Color = armor_tint[i];
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ns->spawn.colors[i].color = item->Color;
|
||||
ns->spawn.colors[i].Color = item->Color;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (armor_tint[i])
|
||||
{
|
||||
ns->spawn.colors[i].color = armor_tint[i];
|
||||
ns->spawn.colors[i].Color = armor_tint[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4426,9 +4424,9 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
||||
{
|
||||
if(strlen(item->IDFile) > 2)
|
||||
{
|
||||
ns->spawn.equipment[MaterialPrimary].material = atoi(&item->IDFile[2]);
|
||||
ns->spawn.equipment[MaterialPrimary].Material = atoi(&item->IDFile[2]);
|
||||
}
|
||||
ns->spawn.colors[MaterialPrimary].color = GetEquipmentColor(MaterialPrimary);
|
||||
ns->spawn.colors[MaterialPrimary].Color = GetEquipmentColor(MaterialPrimary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4440,9 +4438,9 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
||||
{
|
||||
if(strlen(item->IDFile) > 2)
|
||||
{
|
||||
ns->spawn.equipment[MaterialSecondary].material = atoi(&item->IDFile[2]);
|
||||
ns->spawn.equipment[MaterialSecondary].Material = atoi(&item->IDFile[2]);
|
||||
}
|
||||
ns->spawn.colors[MaterialSecondary].color = GetEquipmentColor(MaterialSecondary);
|
||||
ns->spawn.colors[MaterialSecondary].Color = GetEquipmentColor(MaterialSecondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5061,7 +5059,7 @@ void Bot::SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32
|
||||
|
||||
wc->spawn_id = GetID();
|
||||
wc->material = material;
|
||||
wc->color.color = color;
|
||||
wc->color.Color = color;
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
@@ -5088,9 +5086,9 @@ void Bot::BotAddEquipItem(int slot, uint32 id) {
|
||||
SendWearChange(materialFromSlot);
|
||||
}
|
||||
|
||||
UpdateEquipLightValue();
|
||||
if (UpdateActiveLightValue())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5106,9 +5104,9 @@ void Bot::BotRemoveEquipItem(int slot) {
|
||||
SendWearChange(MaterialArms);
|
||||
}
|
||||
|
||||
UpdateEquipLightValue();
|
||||
if (UpdateActiveLightValue())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8407,7 +8405,7 @@ void Bot::EquipBot(std::string* errorMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
UpdateEquipLightValue();
|
||||
UpdateEquipmentLight();
|
||||
}
|
||||
|
||||
//// This method is meant to be called by zone or client methods to clean up objects when a client camps, goes LD, zones out or something like that.
|
||||
@@ -10823,7 +10821,7 @@ void Bot::ProcessBotInspectionRequest(Bot* inspectedBot, Client* client) {
|
||||
|
||||
// Modded to display power source items (will only show up on SoF+ client inspect windows though.)
|
||||
// I don't think bots are currently coded to use them..but, you'll have to use '#bot inventory list'
|
||||
// to see them on a Titanium client when/if they are activated. -U
|
||||
// to see them on a Titanium client when/if they are activated.
|
||||
for(int16 L = EmuConstants::EQUIPMENT_BEGIN; L <= MainWaist; L++) {
|
||||
inst = inspectedBot->GetBotItem(L);
|
||||
|
||||
@@ -10959,7 +10957,7 @@ void Bot::CalcItemBonuses()
|
||||
}
|
||||
}
|
||||
if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects
|
||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses);
|
||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11043,7 +11041,7 @@ void Bot::CalcItemBonuses()
|
||||
}
|
||||
}
|
||||
if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects
|
||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses);
|
||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -332,7 +332,7 @@ public:
|
||||
void EquipBot(std::string* errorMessage);
|
||||
bool CheckLoreConflict(const Item_Struct* item);
|
||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
virtual void UpdateEquipLightValue() { equip_light = m_inv.FindHighestLightValue(); }
|
||||
virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = m_inv.FindBrightestLightType(); m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); }
|
||||
|
||||
// Static Class Methods
|
||||
static void SaveBotGroup(Group* botGroup, std::string botGroupName, std::string* errorMessage);
|
||||
|
||||
+121
-51
@@ -141,6 +141,10 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
merc_timer(RuleI(Mercs, UpkeepIntervalMS)),
|
||||
ItemTickTimer(10000),
|
||||
ItemQuestTimer(500),
|
||||
anon_toggle_timer(250),
|
||||
afk_toggle_timer(250),
|
||||
helm_toggle_timer(250),
|
||||
light_update_timer(600),
|
||||
m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number
|
||||
m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f),
|
||||
m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f),
|
||||
@@ -161,6 +165,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
Trader=false;
|
||||
Buyer = false;
|
||||
CustomerID = 0;
|
||||
TraderID = 0;
|
||||
TrackingID = 0;
|
||||
WID = 0;
|
||||
account_id = 0;
|
||||
@@ -245,7 +250,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
AttemptedMessages = 0;
|
||||
TotalKarma = 0;
|
||||
m_ClientVersion = ClientVersion::Unknown;
|
||||
ClientVersionBit = 0;
|
||||
m_ClientVersionBit = 0;
|
||||
AggroCount = 0;
|
||||
RestRegenHP = 0;
|
||||
RestRegenMana = 0;
|
||||
@@ -303,9 +308,6 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
|
||||
interrogateinv_flag = false;
|
||||
|
||||
active_light = innate_light;
|
||||
spell_light = equip_light = NOT_USED;
|
||||
|
||||
AI_Init();
|
||||
}
|
||||
|
||||
@@ -409,6 +411,69 @@ Client::~Client() {
|
||||
UninitializeBuffSlots();
|
||||
}
|
||||
|
||||
void Client::SendZoneInPackets()
|
||||
{
|
||||
//////////////////////////////////////////////////////
|
||||
// Spawn Appearance Packet
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
||||
sa->parameter = GetID(); // Four bytes for this parameter...
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// Inform the world about the client
|
||||
outapp = new EQApplicationPacket();
|
||||
|
||||
CreateSpawnPacket(outapp);
|
||||
outapp->priority = 6;
|
||||
if (!GetHideMe()) entity_list.QueueClients(this, outapp, true);
|
||||
safe_delete(outapp);
|
||||
if (GetPVP()) //force a PVP update until we fix the spawn struct
|
||||
SendAppearancePacket(AT_PVP, GetPVP(), true, false);
|
||||
|
||||
//Send AA Exp packet:
|
||||
if (GetLevel() >= 51)
|
||||
SendAAStats();
|
||||
|
||||
// Send exp packets
|
||||
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
||||
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
|
||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1);
|
||||
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
|
||||
|
||||
// Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
|
||||
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
|
||||
float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2);
|
||||
eu->exp = (uint32)(330.0f * tmpxp);
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
}
|
||||
safe_delete(outapp);
|
||||
|
||||
SendAATimers();
|
||||
|
||||
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
||||
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
||||
strcpy(zonesendname->name, m_pp.name);
|
||||
strcpy(zonesendname->name2, m_pp.name);
|
||||
zonesendname->unknown0 = 0x0A;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (IsInAGuild()) {
|
||||
SendGuildMembers();
|
||||
SendGuildURL();
|
||||
SendGuildChannel();
|
||||
SendGuildLFGuildStatus();
|
||||
}
|
||||
SendLFGuildStatus();
|
||||
|
||||
//No idea why live sends this if even were not in a guild
|
||||
SendGuildMOTD();
|
||||
}
|
||||
|
||||
void Client::SendLogoutPackets() {
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_CancelTrade, sizeof(CancelTrade_Struct));
|
||||
@@ -1801,9 +1866,9 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.runspeed = (gmspeed == 0) ? runspeed : 3.125f;
|
||||
ns->spawn.showhelm = m_pp.showhelm ? 1 : 0;
|
||||
|
||||
UpdateEquipLightValue();
|
||||
UpdateActiveLightValue();
|
||||
ns->spawn.light = active_light;
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
ns->spawn.light = m_Light.Type.Active;
|
||||
}
|
||||
|
||||
bool Client::GMHideMe(Client* client) {
|
||||
@@ -2471,11 +2536,13 @@ 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);
|
||||
if (bslot == INVALID_INDEX) {
|
||||
@@ -2521,7 +2588,9 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){
|
||||
; // Binding self
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else if (bindwound_timer.Check()) // Did the timer finish?
|
||||
{
|
||||
// finish bind
|
||||
// disable complete timer
|
||||
bindwound_timer.Disable();
|
||||
@@ -2967,7 +3036,7 @@ void Client::Tell_StringID(uint32 string_id, const char *who, const char *messag
|
||||
|
||||
void Client::SetTint(int16 in_slot, uint32 color) {
|
||||
Color_Struct new_color;
|
||||
new_color.color = color;
|
||||
new_color.Color = color;
|
||||
SetTint(in_slot, new_color);
|
||||
database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color);
|
||||
}
|
||||
@@ -2978,8 +3047,8 @@ void Client::SetTint(int16 in_slot, Color_Struct& color) {
|
||||
uint8 matslot = Inventory::CalcMaterialFromSlot(in_slot);
|
||||
if (matslot != _MaterialInvalid)
|
||||
{
|
||||
m_pp.item_tint[matslot].color = color.color;
|
||||
database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color.color);
|
||||
m_pp.item_tint[matslot].Color = color.Color;
|
||||
database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color.Color);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5290,35 +5359,35 @@ void Client::SendRewards()
|
||||
FastQueuePacket(&vetapp);
|
||||
}
|
||||
|
||||
bool Client::TryReward(uint32 claim_id) {
|
||||
//Make sure we have an open spot
|
||||
//Make sure we have it in our acct and count > 0
|
||||
//Make sure the entry was found
|
||||
//If we meet all the criteria:
|
||||
//Decrement our count by 1 if it > 1 delete if it == 1
|
||||
//Create our item in bag if necessary at the free inv slot
|
||||
//save
|
||||
bool Client::TryReward(uint32 claim_id)
|
||||
{
|
||||
// Make sure we have an open spot
|
||||
// Make sure we have it in our acct and count > 0
|
||||
// Make sure the entry was found
|
||||
// If we meet all the criteria:
|
||||
// Decrement our count by 1 if it > 1 delete if it == 1
|
||||
// Create our item in bag if necessary at the free inv slot
|
||||
// save
|
||||
uint32 free_slot = 0xFFFFFFFF;
|
||||
|
||||
for(int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; ++i) {
|
||||
for (int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; ++i) {
|
||||
ItemInst *item = GetInv().GetItem(i);
|
||||
if(!item) {
|
||||
if (!item) {
|
||||
free_slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(free_slot == 0xFFFFFFFF)
|
||||
if (free_slot == 0xFFFFFFFF)
|
||||
return false;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
std::string query = StringFormat("SELECT amount FROM account_rewards "
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
if (!results.Success())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return false;
|
||||
@@ -5326,58 +5395,57 @@ bool Client::TryReward(uint32 claim_id) {
|
||||
auto row = results.begin();
|
||||
|
||||
uint32 amt = atoi(row[0]);
|
||||
if(amt == 0)
|
||||
if (amt == 0)
|
||||
return false;
|
||||
|
||||
std::list<InternalVeteranReward>::iterator iter = zone->VeteranRewards.begin();
|
||||
for (; iter != zone->VeteranRewards.end(); ++row)
|
||||
if((*iter).claim_id == claim_id)
|
||||
break;
|
||||
auto iter = std::find_if(zone->VeteranRewards.begin(), zone->VeteranRewards.end(),
|
||||
[claim_id](const InternalVeteranReward &a) { return a.claim_id == claim_id; });
|
||||
|
||||
if(iter == zone->VeteranRewards.end())
|
||||
if (iter == zone->VeteranRewards.end())
|
||||
return false;
|
||||
|
||||
if(amt == 1) {
|
||||
if (amt == 1) {
|
||||
query = StringFormat("DELETE FROM account_rewards "
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
query = StringFormat("UPDATE account_rewards SET amount = (amount-1) "
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
"WHERE account_id = %i AND reward_id = %i",
|
||||
AccountID(), claim_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
InternalVeteranReward ivr = (*iter);
|
||||
auto &ivr = (*iter);
|
||||
ItemInst *claim = database.CreateItem(ivr.items[0].item_id, ivr.items[0].charges);
|
||||
if(!claim) {
|
||||
if (!claim) {
|
||||
Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lore_conflict = CheckLoreConflict(claim->GetItem());
|
||||
|
||||
for(int y = 1; y < 8; y++)
|
||||
if(ivr.items[y].item_id && claim->GetItem()->ItemClass == 1) {
|
||||
for (int y = 1; y < 8; y++)
|
||||
if (ivr.items[y].item_id && claim->GetItem()->ItemClass == 1) {
|
||||
ItemInst *item_temp = database.CreateItem(ivr.items[y].item_id, ivr.items[y].charges);
|
||||
if(item_temp) {
|
||||
if(CheckLoreConflict(item_temp->GetItem())) {
|
||||
if (item_temp) {
|
||||
if (CheckLoreConflict(item_temp->GetItem())) {
|
||||
lore_conflict = true;
|
||||
DuplicateLoreMessage(ivr.items[y].item_id);
|
||||
}
|
||||
claim->PutItem(y-1, *item_temp);
|
||||
claim->PutItem(y - 1, *item_temp);
|
||||
safe_delete(item_temp);
|
||||
}
|
||||
}
|
||||
|
||||
if(lore_conflict) {
|
||||
if (lore_conflict) {
|
||||
safe_delete(claim);
|
||||
return true;
|
||||
}
|
||||
|
||||
PutItemInInventory(free_slot, *claim);
|
||||
SendItemPacket(free_slot, claim, ItemPacketTrade);
|
||||
safe_delete(claim);
|
||||
|
||||
Save();
|
||||
return true;
|
||||
@@ -6149,6 +6217,8 @@ void Client::DragCorpses()
|
||||
!corpse->CastToCorpse()->Summon(this, false, false)) {
|
||||
Message_StringID(MT_DefaultText, CORPSEDRAG_STOP);
|
||||
It = DraggedCorpses.erase(It);
|
||||
if (It == DraggedCorpses.end())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6173,7 +6243,7 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
|
||||
|
||||
NPCType *made_npc = nullptr;
|
||||
|
||||
const NPCType *npc_type = database.GetNPCType(pet.npc_id);
|
||||
const NPCType *npc_type = database.LoadNPCTypesData(pet.npc_id);
|
||||
if(npc_type == nullptr) {
|
||||
Log.Out(Logs::General, Logs::Error, "Unknown npc type for doppelganger spell id: %d", spell_id);
|
||||
Message(0,"Unable to find pet!");
|
||||
@@ -7396,7 +7466,7 @@ void Client::SendClearMercInfo()
|
||||
|
||||
void Client::DuplicateLoreMessage(uint32 ItemID)
|
||||
{
|
||||
if(!(ClientVersionBit & BIT_RoFAndLater))
|
||||
if (!(m_ClientVersionBit & BIT_RoFAndLater))
|
||||
{
|
||||
Message_StringID(0, PICK_LORE);
|
||||
return;
|
||||
|
||||
+16
-6
@@ -266,10 +266,11 @@ public:
|
||||
void SendBazaarResults(uint32 trader_id,uint32 class_,uint32 race,uint32 stat,uint32 slot,uint32 type,char name[64],uint32 minprice,uint32 maxprice);
|
||||
void SendTraderItem(uint32 item_id,uint16 quantity);
|
||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
||||
uint32 FindTraderItemSerialNumber(int32 ItemID);
|
||||
ItemInst* FindTraderItemBySerialNumber(int32 SerialNumber);
|
||||
void FindAndNukeTraderItem(int32 item_id,uint16 quantity,Client* customer,uint16 traderslot);
|
||||
void NukeTraderItem(uint16 slot,int16 charges,uint16 quantity,Client* customer,uint16 traderslot, int uniqueid);
|
||||
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges);
|
||||
void NukeTraderItem(uint16 slot, int16 charges, uint16 quantity, Client* customer, uint16 traderslot, int32 uniqueid, int32 itemid = 0);
|
||||
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
||||
void TradeRequestFailed(const EQApplicationPacket* app);
|
||||
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
|
||||
void TraderUpdate(uint16 slot_id,uint32 trader_id);
|
||||
@@ -730,7 +731,7 @@ public:
|
||||
#endif
|
||||
uint32 GetEquipment(uint8 material_slot) const; // returns item id
|
||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
virtual void UpdateEquipLightValue() { equip_light = m_inv.FindHighestLightValue(); }
|
||||
virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = m_inv.FindBrightestLightType(); m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); }
|
||||
|
||||
inline bool AutoSplitEnabled() { return m_pp.autosplit != 0; }
|
||||
|
||||
@@ -1021,7 +1022,7 @@ public:
|
||||
inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); }
|
||||
|
||||
inline const ClientVersion GetClientVersion() const { return m_ClientVersion; }
|
||||
inline const uint32 GetClientVersionBit() const { return ClientVersionBit; }
|
||||
inline const uint32 GetClientVersionBit() const { return m_ClientVersionBit; }
|
||||
inline void SetClientVersion(ClientVersion in) { m_ClientVersion = in; }
|
||||
|
||||
/** Adventure Stuff **/
|
||||
@@ -1139,7 +1140,7 @@ public:
|
||||
void HandleLFGuildResponse(ServerPacket *pack);
|
||||
void SendLFGuildStatus();
|
||||
void SendGuildLFGuildStatus();
|
||||
inline bool XTargettingAvailable() const { return ((ClientVersionBit & BIT_UFAndLater) && RuleB(Character, EnableXTargetting)); }
|
||||
inline bool XTargettingAvailable() const { return ((m_ClientVersionBit & BIT_UFAndLater) && RuleB(Character, EnableXTargetting)); }
|
||||
inline uint8 GetMaxXTargets() const { return MaxXTargets; }
|
||||
void SetMaxXTargets(uint8 NewMax);
|
||||
bool IsXTarget(const Mob *m) const;
|
||||
@@ -1257,10 +1258,12 @@ protected:
|
||||
friend class Mob;
|
||||
void CalcItemBonuses(StatBonuses* newbon);
|
||||
void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false);
|
||||
void AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false);
|
||||
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
|
||||
void CalcEdibleBonuses(StatBonuses* newbon);
|
||||
void CalcAABonuses(StatBonuses* newbon);
|
||||
void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon);
|
||||
void ProcessItemCaps();
|
||||
void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true);
|
||||
bool client_data_loaded;
|
||||
|
||||
@@ -1314,6 +1317,7 @@ private:
|
||||
int32 GetACMit();
|
||||
int32 GetACAvoid();
|
||||
int32 CalcATK();
|
||||
int32 CalcItemATKCap();
|
||||
int32 CalcHaste();
|
||||
|
||||
int32 CalcAlcoholPhysicalEffect();
|
||||
@@ -1387,6 +1391,7 @@ private:
|
||||
uint16 BoatID;
|
||||
uint16 TrackingID;
|
||||
uint16 CustomerID;
|
||||
uint16 TraderID;
|
||||
uint32 account_creation;
|
||||
uint8 firstlogon;
|
||||
uint32 mercid; // current merc
|
||||
@@ -1414,6 +1419,7 @@ private:
|
||||
|
||||
bool CanBeInZone();
|
||||
void SendLogoutPackets();
|
||||
void SendZoneInPackets();
|
||||
bool AddPacket(const EQApplicationPacket *, bool);
|
||||
bool AddPacket(EQApplicationPacket**, bool);
|
||||
bool SendAllPackets();
|
||||
@@ -1464,6 +1470,10 @@ private:
|
||||
Timer TrackingTimer;
|
||||
Timer RespawnFromHoverTimer;
|
||||
Timer merc_timer;
|
||||
Timer anon_toggle_timer;
|
||||
Timer afk_toggle_timer;
|
||||
Timer helm_toggle_timer;
|
||||
Timer light_update_timer;
|
||||
|
||||
glm::vec3 m_Proximity;
|
||||
|
||||
@@ -1509,7 +1519,7 @@ private:
|
||||
uint32 AttemptedMessages;
|
||||
|
||||
ClientVersion m_ClientVersion;
|
||||
uint32 ClientVersionBit;
|
||||
uint32 m_ClientVersionBit;
|
||||
|
||||
int XPRate;
|
||||
|
||||
|
||||
@@ -2148,6 +2148,12 @@ int32 Client::CalcEnduranceRegenCap()
|
||||
return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
||||
}
|
||||
|
||||
int32 Client::CalcItemATKCap()
|
||||
{
|
||||
int cap = RuleI(Character, ItemATKCap) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
||||
return cap;
|
||||
}
|
||||
|
||||
int Client::GetRawACNoShield(int &shield_ac) const
|
||||
{
|
||||
int ac = itembonuses.AC + spellbonuses.AC + aabonuses.AC;
|
||||
|
||||
+296
-273
@@ -335,7 +335,13 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_Save] = &Client::Handle_OP_Save;
|
||||
ConnectedOpcodes[OP_SaveOnZoneReq] = &Client::Handle_OP_SaveOnZoneReq;
|
||||
ConnectedOpcodes[OP_SelectTribute] = &Client::Handle_OP_SelectTribute;
|
||||
ConnectedOpcodes[OP_SenseHeading] = &Client::Handle_OP_Ignore;
|
||||
|
||||
// Use or Ignore sense heading based on rule.
|
||||
bool train=RuleB(Skills, TrainSenseHeading);
|
||||
|
||||
ConnectedOpcodes[OP_SenseHeading] =
|
||||
(train) ? &Client::Handle_OP_SenseHeading : &Client::Handle_OP_Ignore;
|
||||
|
||||
ConnectedOpcodes[OP_SenseTraps] = &Client::Handle_OP_SenseTraps;
|
||||
ConnectedOpcodes[OP_SetGuildMOTD] = &Client::Handle_OP_SetGuildMOTD;
|
||||
ConnectedOpcodes[OP_SetRunMode] = &Client::Handle_OP_SetRunMode;
|
||||
@@ -728,8 +734,8 @@ void Client::CompleteConnect()
|
||||
SendWearChange(x);
|
||||
}
|
||||
// added due to wear change above
|
||||
UpdateActiveLightValue();
|
||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
||||
UpdateActiveLight();
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
|
||||
Mob *pet = GetPet();
|
||||
if (pet != nullptr) {
|
||||
@@ -737,8 +743,8 @@ void Client::CompleteConnect()
|
||||
pet->SendWearChange(x);
|
||||
}
|
||||
// added due to wear change above
|
||||
pet->UpdateActiveLightValue();
|
||||
pet->SendAppearancePacket(AT_Light, pet->GetActiveLightValue());
|
||||
pet->UpdateActiveLight();
|
||||
pet->SendAppearancePacket(AT_Light, pet->GetActiveLightType());
|
||||
}
|
||||
|
||||
entity_list.SendTraders(this);
|
||||
@@ -1092,76 +1098,15 @@ void Client::Handle_Connect_OP_SendAATable(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_Connect_OP_SendExpZonein(const EQApplicationPacket *app)
|
||||
{
|
||||
//////////////////////////////////////////////////////
|
||||
// Spawn Appearance Packet
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
||||
sa->parameter = GetID(); // Four bytes for this parameter...
|
||||
outapp->priority = 6;
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendExpZonein, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// Inform the world about the client
|
||||
outapp = new EQApplicationPacket();
|
||||
|
||||
CreateSpawnPacket(outapp);
|
||||
outapp->priority = 6;
|
||||
if (!GetHideMe()) entity_list.QueueClients(this, outapp, true);
|
||||
safe_delete(outapp);
|
||||
if (GetPVP()) //force a PVP update until we fix the spawn struct
|
||||
SendAppearancePacket(AT_PVP, GetPVP(), true, false);
|
||||
|
||||
//Send AA Exp packet:
|
||||
if (GetLevel() >= 51)
|
||||
SendAAStats();
|
||||
|
||||
// Send exp packets
|
||||
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
||||
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
|
||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1);
|
||||
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
|
||||
|
||||
// Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
|
||||
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
|
||||
float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2);
|
||||
eu->exp = (uint32)(330.0f * tmpxp);
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
// SoF+ Gets Zone-In packets after sending OP_WorldObjectsSent
|
||||
if (GetClientVersion() < ClientVersion::SoF)
|
||||
{
|
||||
SendZoneInPackets();
|
||||
}
|
||||
safe_delete(outapp);
|
||||
|
||||
SendAATimers();
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SendExpZonein, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
||||
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
||||
strcpy(zonesendname->name, m_pp.name);
|
||||
strcpy(zonesendname->name2, m_pp.name);
|
||||
zonesendname->unknown0 = 0x0A;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
/* this is actually the guild MOTD
|
||||
outapp = new EQApplicationPacket(OP_ZoneInSendName2, sizeof(ZoneInSendName_Struct2));
|
||||
ZoneInSendName_Struct2* zonesendname2=(ZoneInSendName_Struct2*)outapp->pBuffer;
|
||||
strcpy(zonesendname2->name,m_pp.name);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);*/
|
||||
|
||||
if (IsInAGuild()) {
|
||||
SendGuildMembers();
|
||||
SendGuildURL();
|
||||
SendGuildChannel();
|
||||
SendGuildLFGuildStatus();
|
||||
}
|
||||
SendLFGuildStatus();
|
||||
|
||||
//No idea why live sends this if even were not in a guild
|
||||
SendGuildMOTD();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1219,72 +1164,13 @@ void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app)
|
||||
{
|
||||
//This is a copy of SendExpZonein created for SoF+ due to packet order change
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Spawn Appearance Packet
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
||||
sa->parameter = GetID(); // Four bytes for this parameter...
|
||||
outapp->priority = 6;
|
||||
// New for SoF+
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// Inform the world about the client
|
||||
outapp = new EQApplicationPacket();
|
||||
|
||||
CreateSpawnPacket(outapp);
|
||||
outapp->priority = 6;
|
||||
if (!GetHideMe()) entity_list.QueueClients(this, outapp, true);
|
||||
safe_delete(outapp);
|
||||
if (GetPVP()) //force a PVP update until we fix the spawn struct
|
||||
SendAppearancePacket(AT_PVP, GetPVP(), true, false);
|
||||
|
||||
//Send AA Exp packet:
|
||||
if (GetLevel() >= 51)
|
||||
SendAAStats();
|
||||
|
||||
// Send exp packets
|
||||
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
||||
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
|
||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1);
|
||||
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
|
||||
|
||||
// Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
|
||||
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
|
||||
float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2);
|
||||
eu->exp = (uint32)(330.0f * tmpxp);
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
}
|
||||
safe_delete(outapp);
|
||||
|
||||
SendAATimers();
|
||||
|
||||
// New for Secrets of Faydwer - Used in Place of OP_SendExpZonein
|
||||
outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
||||
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
||||
strcpy(zonesendname->name, m_pp.name);
|
||||
strcpy(zonesendname->name2, m_pp.name);
|
||||
zonesendname->unknown0 = 0x0A;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (IsInAGuild()) {
|
||||
SendGuildMembers();
|
||||
SendGuildURL();
|
||||
SendGuildChannel();
|
||||
SendGuildLFGuildStatus();
|
||||
}
|
||||
SendLFGuildStatus();
|
||||
|
||||
//No idea why live sends this if even were not in a guild
|
||||
SendGuildMOTD();
|
||||
// Packet order changed for SoF+, so below is sent here instead of OP_SendExpLogin
|
||||
SendZoneInPackets();
|
||||
|
||||
if (RuleB(Mercs, AllowMercs))
|
||||
{
|
||||
@@ -1314,8 +1200,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
conn_state = ReceivedZoneEntry;
|
||||
|
||||
SetClientVersion(Connection()->GetClientVersion());
|
||||
if (m_ClientVersion != ClientVersion::Unknown)
|
||||
ClientVersionBit = 1 << (static_cast<unsigned int>(m_ClientVersion) - 1);
|
||||
m_ClientVersionBit = ClientBitFromVersion(Connection()->GetClientVersion());
|
||||
|
||||
bool siv = m_inv.SetInventoryVersion(m_ClientVersion);
|
||||
Log.Out(Logs::General, Logs::None, "%s inventory version to %s(%i)", (siv ? "Succeeded in setting" : "Failed to set"), ClientVersionName(m_ClientVersion), m_ClientVersion);
|
||||
@@ -1430,9 +1315,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
/* Set item material tint */
|
||||
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++)
|
||||
{
|
||||
if (m_pp.item_tint[i].rgb.use_tint == 1 || m_pp.item_tint[i].rgb.use_tint == 255)
|
||||
if (m_pp.item_tint[i].RGB.UseTint == 1 || m_pp.item_tint[i].RGB.UseTint == 255)
|
||||
{
|
||||
m_pp.item_tint[i].rgb.use_tint = 0xFF;
|
||||
m_pp.item_tint[i].RGB.UseTint = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1555,10 +1440,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000){ m_pp.ldon_points_tak = 0; }
|
||||
if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; }
|
||||
|
||||
/* Set Swimming Skill 100 by default if under 100 */
|
||||
if (GetSkill(SkillSwimming) < 100)
|
||||
SetSkill(SkillSwimming, 100);
|
||||
|
||||
/* Initialize AA's : Move to function eventually */
|
||||
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ aa[a] = &m_pp.aa_array[a]; }
|
||||
query = StringFormat(
|
||||
@@ -1841,9 +1722,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
if (loaditems) { /* Dont load if a length error occurs */
|
||||
BulkSendInventoryItems();
|
||||
/* Send stuff on the cursor which isnt sent in bulk */
|
||||
for (auto iter = m_inv.cursor_begin(); iter != m_inv.cursor_end(); ++iter) {
|
||||
for (auto iter = m_inv.cursor_cbegin(); iter != m_inv.cursor_cend(); ++iter) {
|
||||
/* First item cursor is sent in bulk inventory packet */
|
||||
if (iter == m_inv.cursor_begin())
|
||||
if (iter == m_inv.cursor_cbegin())
|
||||
continue;
|
||||
const ItemInst *inst = *iter;
|
||||
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
|
||||
@@ -1859,7 +1740,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
if (ClientVersionBit & BIT_UFAndLater) {
|
||||
if (m_ClientVersionBit & BIT_UFAndLater) {
|
||||
outapp = new EQApplicationPacket(OP_XTargetResponse, 8);
|
||||
outapp->WriteUInt32(GetMaxXTargets());
|
||||
outapp->WriteUInt32(0);
|
||||
@@ -3309,7 +3190,6 @@ void Client::Handle_OP_AutoFire(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_Bandolier(const EQApplicationPacket *app)
|
||||
{
|
||||
|
||||
// Although there are three different structs for OP_Bandolier, they are all the same size.
|
||||
//
|
||||
if (app->size != sizeof(BandolierCreate_Struct)) {
|
||||
@@ -3321,19 +3201,20 @@ void Client::Handle_OP_Bandolier(const EQApplicationPacket *app)
|
||||
|
||||
BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer;
|
||||
|
||||
switch (bs->action) {
|
||||
case BandolierCreate:
|
||||
switch (bs->Action)
|
||||
{
|
||||
case bandolierCreate:
|
||||
CreateBandolier(app);
|
||||
break;
|
||||
case BandolierRemove:
|
||||
case bandolierRemove:
|
||||
RemoveBandolier(app);
|
||||
break;
|
||||
case BandolierSet:
|
||||
case bandolierSet:
|
||||
SetBandolier(app);
|
||||
break;
|
||||
default:
|
||||
Log.Out(Logs::General, Logs::None, "Uknown Bandolier action %i", bs->action);
|
||||
|
||||
Log.Out(Logs::General, Logs::None, "Unknown Bandolier action %i", bs->Action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4038,7 +3919,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
||||
}
|
||||
else if (m_inv.SupportsClickCasting(castspell->inventoryslot) || (castspell->slot == POTION_BELT_SPELL_SLOT) || (castspell->slot == TARGET_RING_SPELL_SLOT)) // sanity check
|
||||
{
|
||||
// packet field types will be reviewed as packet transistions occur -U
|
||||
// packet field types will be reviewed as packet transistions occur
|
||||
const ItemInst* inst = m_inv[castspell->inventoryslot]; //slot values are int16, need to check packet on this field
|
||||
//bool cancast = true;
|
||||
if (inst && inst->IsType(ItemClassCommon))
|
||||
@@ -5230,6 +5111,7 @@ void Client::Handle_OP_DeleteSpell(const EQApplicationPacket *app)
|
||||
|
||||
if (m_pp.spell_book[dss->spell_slot] != SPELLBOOK_UNKNOWN) {
|
||||
m_pp.spell_book[dss->spell_slot] = SPELLBOOK_UNKNOWN;
|
||||
database.DeleteCharacterSpell(this->CharacterID(), m_pp.spell_book[dss->spell_slot], dss->spell_slot);
|
||||
dss->success = 1;
|
||||
}
|
||||
else
|
||||
@@ -5547,7 +5429,7 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
||||
if (damage < 0)
|
||||
damage = 31337;
|
||||
|
||||
if (admin >= minStatusToAvoidFalling && GetGM()){
|
||||
if (admin >= minStatusToAvoidFalling && GetGM()) {
|
||||
Message(13, "Your GM status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
|
||||
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
||||
return;
|
||||
@@ -5557,11 +5439,11 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
||||
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
||||
return;
|
||||
}
|
||||
|
||||
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184){
|
||||
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184) {
|
||||
// Hard coded tutorial and load zones for no fall damage
|
||||
return;
|
||||
}
|
||||
else{
|
||||
else {
|
||||
SetHP(GetHP() - (damage * RuleR(Character, EnvironmentDamageMulipliter)));
|
||||
|
||||
/* EVENT_ENVIRONMENTAL_DAMAGE */
|
||||
@@ -7391,6 +7273,16 @@ void Client::Handle_OP_GuildInvite(const EQApplicationPacket *app)
|
||||
if (gc->guildeqid == 0)
|
||||
gc->guildeqid = GuildID();
|
||||
|
||||
// Convert Membership Level between RoF and previous clients.
|
||||
if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
gc->officer = 0;
|
||||
}
|
||||
if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF)
|
||||
{
|
||||
gc->officer = 8;
|
||||
}
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Guilds, "Sending OP_GuildInvite for invite to %s, length %d", client->GetName(), app->size);
|
||||
client->SetPendingGuildInvitation(true);
|
||||
client->QueuePacket(app);
|
||||
@@ -7425,6 +7317,8 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app)
|
||||
|
||||
GuildInviteAccept_Struct* gj = (GuildInviteAccept_Struct*)app->pBuffer;
|
||||
|
||||
uint32 guildrank = gj->response;
|
||||
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
if (gj->response > 9)
|
||||
@@ -7453,9 +7347,25 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app)
|
||||
Log.Out(Logs::Detail, Logs::Guilds, "Guild Invite Accept: guild %d, response %d, inviter %s, person %s",
|
||||
gj->guildeqid, gj->response, gj->inviter, gj->newmember);
|
||||
|
||||
//ok, the invite is also used for changing rank as well.
|
||||
Mob* inviter = entity_list.GetMob(gj->inviter);
|
||||
|
||||
if (inviter && inviter->IsClient())
|
||||
{
|
||||
Client* client = inviter->CastToClient();
|
||||
// Convert Membership Level between RoF and previous clients.
|
||||
if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
guildrank = 0;
|
||||
}
|
||||
if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF)
|
||||
{
|
||||
guildrank = 8;
|
||||
}
|
||||
}
|
||||
//we dont really care a lot about what this packet means, as long as
|
||||
//it has been authorized with the guild manager
|
||||
if (!guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, gj->response)) {
|
||||
if (!guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, guildrank)) {
|
||||
worldserver.SendEmoteMessage(gj->inviter, 0, 0, "%s has sent an invalid response to your invite!", GetName());
|
||||
Message(13, "Invalid invite response packet!");
|
||||
return;
|
||||
@@ -7483,7 +7393,7 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app)
|
||||
|
||||
//change guild and rank
|
||||
|
||||
uint32 guildrank = gj->response;
|
||||
guildrank = gj->response;
|
||||
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
@@ -9893,6 +9803,9 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mypet->GetPetType() == petTargetLock && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST))
|
||||
return;
|
||||
|
||||
if (mypet->GetPetType() == petAnimation && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST) && !GetAA(aaAnimationEmpathy))
|
||||
return;
|
||||
|
||||
@@ -10562,16 +10475,16 @@ void Client::Handle_OP_PotionBelt(const EQApplicationPacket *app)
|
||||
if (mptbs->Action == 0) {
|
||||
const Item_Struct *BaseItem = database.GetItem(mptbs->ItemID);
|
||||
if (BaseItem) {
|
||||
m_pp.potionbelt.items[mptbs->SlotNumber].item_id = BaseItem->ID;
|
||||
m_pp.potionbelt.items[mptbs->SlotNumber].icon = BaseItem->Icon;
|
||||
strn0cpy(m_pp.potionbelt.items[mptbs->SlotNumber].item_name, BaseItem->Name, sizeof(BaseItem->Name));
|
||||
database.SaveCharacterPotionBelt(this->CharacterID(), mptbs->SlotNumber, m_pp.potionbelt.items[mptbs->SlotNumber].item_id, m_pp.potionbelt.items[mptbs->SlotNumber].icon);
|
||||
m_pp.potionbelt.Items[mptbs->SlotNumber].ID = BaseItem->ID;
|
||||
m_pp.potionbelt.Items[mptbs->SlotNumber].Icon = BaseItem->Icon;
|
||||
strn0cpy(m_pp.potionbelt.Items[mptbs->SlotNumber].Name, BaseItem->Name, sizeof(BaseItem->Name));
|
||||
database.SaveCharacterPotionBelt(this->CharacterID(), mptbs->SlotNumber, m_pp.potionbelt.Items[mptbs->SlotNumber].ID, m_pp.potionbelt.Items[mptbs->SlotNumber].Icon);
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_pp.potionbelt.items[mptbs->SlotNumber].item_id = 0;
|
||||
m_pp.potionbelt.items[mptbs->SlotNumber].icon = 0;
|
||||
strncpy(m_pp.potionbelt.items[mptbs->SlotNumber].item_name, "\0", 1);
|
||||
m_pp.potionbelt.Items[mptbs->SlotNumber].ID = 0;
|
||||
m_pp.potionbelt.Items[mptbs->SlotNumber].Icon = 0;
|
||||
m_pp.potionbelt.Items[mptbs->SlotNumber].Name[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11773,6 +11686,27 @@ void Client::Handle_OP_SelectTribute(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_SenseHeading(const EQApplicationPacket *app)
|
||||
{
|
||||
if (!HasSkill(SkillSenseHeading))
|
||||
return;
|
||||
|
||||
int chancemod=0;
|
||||
|
||||
// The client seems to limit sense heading packets based on skill
|
||||
// level. So if we're really low, we don't hit this routine very often.
|
||||
// I think it's the GUI deciding when to skill you up.
|
||||
// So, I'm adding a mod here which is larger at lower levels so
|
||||
// very low levels get a much better chance to skill up when the GUI
|
||||
// eventually sends a message.
|
||||
if (GetLevel() <= 8)
|
||||
chancemod += (9-level) * 10;
|
||||
|
||||
CheckIncreaseSkill(SkillSenseHeading, nullptr, chancemod);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_SenseTraps(const EQApplicationPacket *app)
|
||||
{
|
||||
if (!HasSkill(SkillSenseTraps))
|
||||
@@ -12072,12 +12006,6 @@ void Client::Handle_OP_ShopEnd(const EQApplicationPacket *app)
|
||||
{
|
||||
EQApplicationPacket empty(OP_ShopEndConfirm);
|
||||
QueuePacket(&empty);
|
||||
//EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopEndConfirm, 2);
|
||||
//outapp->pBuffer[0] = 0x0a;
|
||||
//outapp->pBuffer[1] = 0x66;
|
||||
//QueuePacket(outapp);
|
||||
//safe_delete(outapp);
|
||||
//Save();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12173,6 +12101,10 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
|
||||
mp->quantity = prevcharges;
|
||||
}
|
||||
|
||||
// Item's stackable, but the quantity they want to buy exceeds the max stackable quantity.
|
||||
if (item->Stackable && mp->quantity > item->StackSize)
|
||||
mp->quantity = item->StackSize;
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerBuy, sizeof(Merchant_Sell_Struct));
|
||||
Merchant_Sell_Struct* mpo = (Merchant_Sell_Struct*)outapp->pBuffer;
|
||||
mpo->quantity = mp->quantity;
|
||||
@@ -12199,6 +12131,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
|
||||
mpo->price = SinglePrice;
|
||||
else
|
||||
mpo->price = SinglePrice * mp->quantity;
|
||||
|
||||
if (mpo->price < 0)
|
||||
{
|
||||
safe_delete(outapp);
|
||||
@@ -12668,6 +12601,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
else if (sa->type == AT_Anim) {
|
||||
if (IsAIControlled())
|
||||
return;
|
||||
|
||||
if (sa->parameter == ANIM_STAND) {
|
||||
SetAppearance(eaStanding);
|
||||
playeraction = 0;
|
||||
@@ -12701,15 +12635,6 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
SetFeigned(false);
|
||||
}
|
||||
|
||||
// This is from old code
|
||||
// I have no clue what it's for
|
||||
/*
|
||||
else if (sa->parameter == 0x05) {
|
||||
// Illusion
|
||||
std::cout << "Illusion packet recv'd:" << std::endl;
|
||||
DumpPacket(app);
|
||||
}
|
||||
*/
|
||||
else {
|
||||
std::cerr << "Client " << name << " unknown apperance " << (int)sa->parameter << std::endl;
|
||||
return;
|
||||
@@ -12718,6 +12643,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
else if (sa->type == AT_Anon) {
|
||||
if(!anon_toggle_timer.Check()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For Anon/Roleplay
|
||||
if (sa->parameter == 1) { // Anon
|
||||
m_pp.anon = 1;
|
||||
@@ -12739,13 +12668,18 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
else if (sa->type == AT_AFK) {
|
||||
this->AFK = (sa->parameter == 1);
|
||||
entity_list.QueueClients(this, app, true);
|
||||
if(afk_toggle_timer.Check()) {
|
||||
AFK = (sa->parameter == 1);
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
}
|
||||
else if (sa->type == AT_Split) {
|
||||
m_pp.autosplit = (sa->parameter == 1);
|
||||
}
|
||||
else if (sa->type == AT_Sneak) {
|
||||
if(sneaking == 0)
|
||||
return;
|
||||
|
||||
if (sa->parameter != 0)
|
||||
{
|
||||
if (!HasSkill(SkillSneak))
|
||||
@@ -12757,7 +12691,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
}
|
||||
return;
|
||||
}
|
||||
this->sneaking = 0;
|
||||
sneaking = 0;
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
else if (sa->type == AT_Size)
|
||||
@@ -12769,7 +12703,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
}
|
||||
else if (sa->type == AT_Light) // client emitting light (lightstone, shiny shield)
|
||||
{
|
||||
entity_list.QueueClients(this, app, false);
|
||||
//don't do anything with this
|
||||
}
|
||||
else if (sa->type == AT_Levitate)
|
||||
{
|
||||
@@ -12778,8 +12712,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
||||
}
|
||||
else if (sa->type == AT_ShowHelm)
|
||||
{
|
||||
m_pp.showhelm = (sa->parameter == 1);
|
||||
entity_list.QueueClients(this, app, true);
|
||||
if(helm_toggle_timer.Check()) {
|
||||
m_pp.showhelm = (sa->parameter == 1);
|
||||
entity_list.QueueClients(this, app, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "Unknown SpawnAppearance type: 0x" << std::hex << std::setw(4) << std::setfill('0') << sa->type << std::dec
|
||||
@@ -13390,7 +13326,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
||||
|
||||
/*
|
||||
if (GetClientVersion() >= EQClientRoF)
|
||||
max_items = 200;
|
||||
max_items = 200;
|
||||
*/
|
||||
|
||||
//Show Items
|
||||
@@ -13402,20 +13338,25 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
||||
{
|
||||
case BazaarTrader_EndTraderMode: {
|
||||
Trader_EndTrader();
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Trader Session");
|
||||
break;
|
||||
}
|
||||
case BazaarTrader_EndTransaction: {
|
||||
|
||||
Client* c = entity_list.GetClientByID(sis->TraderID);
|
||||
if (c)
|
||||
{
|
||||
c->WithCustomer(0);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Transaction");
|
||||
}
|
||||
else
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer");
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Null Client Pointer");
|
||||
|
||||
break;
|
||||
}
|
||||
case BazaarTrader_ShowItems: {
|
||||
Trader_ShowItems();
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Show Trader Items");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -13438,6 +13379,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
||||
{
|
||||
GetItems_Struct* gis = GetTraderItems();
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Start Trader Mode");
|
||||
// Verify there are no NODROP or items with a zero price
|
||||
bool TradeItemsValid = true;
|
||||
|
||||
@@ -13484,7 +13426,8 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
||||
safe_delete(gis);
|
||||
|
||||
this->Trader_StartTrader();
|
||||
|
||||
|
||||
// This refreshes the Trader window to display the End Trader button
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderStatus_Struct));
|
||||
@@ -13494,15 +13437,6 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
||||
safe_delete(outapp);
|
||||
}
|
||||
}
|
||||
else if (app->size == sizeof(TraderStatus_Struct))
|
||||
{
|
||||
TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer;
|
||||
|
||||
if (tss->Code == BazaarTrader_ShowItems)
|
||||
{
|
||||
Trader_ShowItems();
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Unknown TraderStruct code of: %i\n",
|
||||
ints->Code);
|
||||
@@ -13510,9 +13444,35 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
||||
Log.Out(Logs::General, Logs::Error, "Unknown TraderStruct code of: %i\n", ints->Code);
|
||||
}
|
||||
}
|
||||
else if (app->size == sizeof(TraderStatus_Struct))
|
||||
{
|
||||
TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Trader Status Code: %d", tss->Code);
|
||||
|
||||
switch (tss->Code)
|
||||
{
|
||||
case BazaarTrader_EndTraderMode: {
|
||||
Trader_EndTrader();
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Trader Session");
|
||||
break;
|
||||
}
|
||||
case BazaarTrader_ShowItems: {
|
||||
Trader_ShowItems();
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Show Trader Items");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Unhandled action code in OP_Trader ShowItems_Struct");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (app->size == sizeof(TraderPriceUpdate_Struct))
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Trader Price Update");
|
||||
HandleTraderPriceUpdate(app);
|
||||
}
|
||||
else {
|
||||
@@ -13531,23 +13491,22 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
||||
//
|
||||
// Client has elected to buy an item from a Trader
|
||||
//
|
||||
if (app->size != sizeof(TraderBuy_Struct)) {
|
||||
Log.Out(Logs::General, Logs::Error, "Wrong size: OP_TraderBuy, size=%i, expected %i", app->size, sizeof(TraderBuy_Struct));
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->size == sizeof(TraderBuy_Struct)){
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)){
|
||||
|
||||
BuyTraderItem(tbs, Trader, app);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer");
|
||||
}
|
||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)){
|
||||
BuyTraderItem(tbs, Trader, app);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Buy Trader Item ");
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Struct size mismatch");
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer");
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13609,51 +13568,124 @@ void Client::Handle_OP_TradeRequestAck(const EQApplicationPacket *app)
|
||||
void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
||||
{
|
||||
// Bazaar Trader:
|
||||
//
|
||||
// This is when a potential purchaser right clicks on this client who is in Trader mode to
|
||||
// browse their goods.
|
||||
//
|
||||
|
||||
TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer;
|
||||
if (app->size == sizeof(TraderClick_Struct))
|
||||
{
|
||||
|
||||
TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer;
|
||||
|
||||
if (app->size != sizeof(TraderClick_Struct)) {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Handle_OP_TraderShop: TraderClick_Struct TraderID %d, Code %d, Unknown008 %d, Approval %d",
|
||||
tcs->TraderID, tcs->Code, tcs->Unknown008, tcs->Approval);
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Returning due to struct size mismatch");
|
||||
if (tcs->Code == BazaarWelcome)
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info");
|
||||
SendBazaarWelcome();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is when a potential purchaser right clicks on this client who is in Trader mode to
|
||||
// browse their goods.
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct));
|
||||
|
||||
TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer;
|
||||
|
||||
Client* Trader = entity_list.GetClientByID(tcs->TraderID);
|
||||
|
||||
if (Trader)
|
||||
{
|
||||
outtcs->Approval = Trader->WithCustomer(GetID());
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Shop Request (%s) to (%s) with Approval: %d", GetCleanName(), Trader->GetCleanName(), outtcs->Approval);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
||||
" returned a nullptr pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
outtcs->TraderID = tcs->TraderID;
|
||||
|
||||
outtcs->Unknown008 = 0x3f800000;
|
||||
|
||||
QueuePacket(outapp);
|
||||
|
||||
|
||||
if (outtcs->Approval) {
|
||||
this->BulkSendTraderInventory(Trader->CharacterID());
|
||||
Trader->Trader_CustomerBrowsing(this);
|
||||
TraderID = tcs->TraderID;
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Inventory Sent");
|
||||
}
|
||||
else
|
||||
{
|
||||
Message_StringID(clientMessageYellow, TRADER_BUSY);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Busy");
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct));
|
||||
|
||||
TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer;
|
||||
|
||||
Client* Customer = entity_list.GetClientByID(tcs->TraderID);
|
||||
|
||||
if (Customer)
|
||||
outtcs->Approval = Customer->WithCustomer(GetID());
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
||||
" returned a nullptr pointer");
|
||||
return;
|
||||
else if (app->size == sizeof(BazaarWelcome_Struct))
|
||||
{
|
||||
// RoF+
|
||||
// Client requested Bazaar Welcome Info (Trader and Item Total Counts)
|
||||
SendBazaarWelcome();
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info");
|
||||
}
|
||||
else if (app->size == sizeof(TraderBuy_Struct))
|
||||
{
|
||||
// RoF+
|
||||
// Customer has purchased an item from the Trader
|
||||
|
||||
outtcs->TraderID = tcs->TraderID;
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
outtcs->Unknown008 = 0x3f800000;
|
||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID))
|
||||
{
|
||||
BuyTraderItem(tbs, Trader, app);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Handle_OP_TraderShop: Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
|
||||
tbs->Action, tbs->Price, tbs->TraderID, tbs->ItemID, tbs->Quantity, tbs->ItemName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "OP_TraderShop: Null Client Pointer");
|
||||
}
|
||||
}
|
||||
else if (app->size == 4)
|
||||
{
|
||||
// RoF+
|
||||
// Customer has closed the trade window
|
||||
uint32 Command = *((uint32 *)app->pBuffer);
|
||||
|
||||
QueuePacket(outapp);
|
||||
|
||||
|
||||
if (outtcs->Approval) {
|
||||
this->BulkSendTraderInventory(Customer->CharacterID());
|
||||
Customer->Trader_CustomerBrowsing(this);
|
||||
if (Command == 4)
|
||||
{
|
||||
Client* c = entity_list.GetClientByID(TraderID);
|
||||
TraderID = 0;
|
||||
if (c)
|
||||
{
|
||||
c->WithCustomer(0);
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Transaction - Code %d", Command);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Null Client Pointer for Trader - Code %d", Command);
|
||||
}
|
||||
EQApplicationPacket empty(OP_ShopEndConfirm);
|
||||
QueuePacket(&empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Unhandled Code %d", Command);
|
||||
}
|
||||
}
|
||||
else
|
||||
Message_StringID(clientMessageYellow, TRADER_BUSY);
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
return;
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Unknown size for OP_TraderShop: %i\n", app->size);
|
||||
Log.Out(Logs::General, Logs::Error, "Unknown size for OP_TraderShop: %i\n", app->size);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_TradeSkillCombine(const EQApplicationPacket *app)
|
||||
@@ -13816,41 +13848,32 @@ void Client::Handle_OP_TributeUpdate(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_VetClaimRequest(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size < sizeof(VeteranClaimRequest))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::None, "OP_VetClaimRequest size lower than expected: got %u expected at least %u", app->size, sizeof(VeteranClaimRequest));
|
||||
if (app->size < sizeof(VeteranClaim)) {
|
||||
Log.Out(Logs::General, Logs::None,
|
||||
"OP_VetClaimRequest size lower than expected: got %u expected at least %u", app->size,
|
||||
sizeof(VeteranClaim));
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
VeteranClaimRequest *vcr = (VeteranClaimRequest*)app->pBuffer;
|
||||
VeteranClaim *vcr = (VeteranClaim *)app->pBuffer;
|
||||
|
||||
if (vcr->claim_id == 0xFFFFFFFF) //request update packet
|
||||
{
|
||||
if (vcr->claim_id == 0xFFFFFFFF) { // request update packet
|
||||
SendRewards();
|
||||
return;
|
||||
}
|
||||
else //try to claim something!
|
||||
{
|
||||
if (!TryReward(vcr->claim_id))
|
||||
{
|
||||
Message(13, "Your claim has been rejected.");
|
||||
EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaimReply));
|
||||
VeteranClaimReply * cr = (VeteranClaimReply*)vetapp->pBuffer;
|
||||
strcpy(cr->name, GetName());
|
||||
cr->claim_id = vcr->claim_id;
|
||||
cr->reject_field = -1;
|
||||
FastQueuePacket(&vetapp);
|
||||
}
|
||||
else
|
||||
{
|
||||
EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaimReply));
|
||||
VeteranClaimReply * cr = (VeteranClaimReply*)vetapp->pBuffer;
|
||||
strcpy(cr->name, GetName());
|
||||
cr->claim_id = vcr->claim_id;
|
||||
cr->reject_field = 0;
|
||||
FastQueuePacket(&vetapp);
|
||||
}
|
||||
}
|
||||
// try to claim something!
|
||||
EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaim));
|
||||
VeteranClaim *cr = (VeteranClaim *)vetapp->pBuffer;
|
||||
strcpy(cr->name, GetName());
|
||||
cr->claim_id = vcr->claim_id;
|
||||
|
||||
if (!TryReward(vcr->claim_id))
|
||||
cr->action = 1;
|
||||
else
|
||||
cr->action = 0;
|
||||
|
||||
FastQueuePacket(&vetapp);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_VoiceMacroIn(const EQApplicationPacket *app)
|
||||
|
||||
+15
-6
@@ -239,7 +239,8 @@ bool Client::Process() {
|
||||
if(IsAIControlled())
|
||||
AI_Process();
|
||||
|
||||
if (bindwound_timer.Check() && bindwound_target != 0) {
|
||||
// Don't reset the bindwound timer so we can check it in BindWound as well.
|
||||
if (bindwound_timer.Check(false) && bindwound_target != 0) {
|
||||
BindWound(bindwound_target, false);
|
||||
}
|
||||
|
||||
@@ -260,6 +261,14 @@ bool Client::Process() {
|
||||
}
|
||||
}
|
||||
|
||||
if(light_update_timer.Check()) {
|
||||
|
||||
UpdateEquipmentLight();
|
||||
if(UpdateActiveLight()) {
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
}
|
||||
}
|
||||
|
||||
bool may_use_attacks = false;
|
||||
/*
|
||||
Things which prevent us from attacking:
|
||||
@@ -808,14 +817,14 @@ void Client::OnDisconnect(bool hard_disconnect) {
|
||||
|
||||
// Sends the client complete inventory used in character login
|
||||
|
||||
// DO WE STILL NEED THE 'ITEMCOMBINED' CONDITIONAL CODE? -U
|
||||
// DO WE STILL NEED THE 'ITEMCOMBINED' CONDITIONAL CODE?
|
||||
|
||||
//#ifdef ITEMCOMBINED
|
||||
void Client::BulkSendInventoryItems() {
|
||||
int16 slot_id = 0;
|
||||
|
||||
// LINKDEAD TRADE ITEMS
|
||||
// Move trade slot items back into normal inventory..need them there now for the proceeding validity checks -U
|
||||
// Move trade slot items back into normal inventory..need them there now for the proceeding validity checks
|
||||
for(slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_END; slot_id++) {
|
||||
ItemInst* inst = m_inv.PopItem(slot_id);
|
||||
if(inst) {
|
||||
@@ -834,7 +843,7 @@ void Client::BulkSendInventoryItems() {
|
||||
RemoveDuplicateLore(false);
|
||||
MoveSlotNotAllowed(false);
|
||||
|
||||
// The previous three method calls took care of moving/removing expired/illegal item placements -U
|
||||
// The previous three method calls took care of moving/removing expired/illegal item placements
|
||||
|
||||
//TODO: this function is just retarded... it re-allocates the buffer for every
|
||||
//new item. It should be changed to loop through once, gather the
|
||||
@@ -960,7 +969,7 @@ void Client::BulkSendInventoryItems()
|
||||
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
const Item_Struct* handyitem = nullptr;
|
||||
uint32 numItemSlots = 80; //The max number of items passed in the transaction.
|
||||
if (ClientVersionBit & BIT_RoFAndLater) { // RoF+ can send 200 items
|
||||
if (m_ClientVersionBit & BIT_RoFAndLater) { // RoF+ can send 200 items
|
||||
numItemSlots = 200;
|
||||
}
|
||||
const Item_Struct *item;
|
||||
@@ -1886,7 +1895,7 @@ void Client::DoHPRegen() {
|
||||
}
|
||||
|
||||
void Client::DoManaRegen() {
|
||||
if (GetMana() >= max_mana)
|
||||
if (GetMana() >= max_mana && spellbonuses.ManaRegen >= 0)
|
||||
return;
|
||||
|
||||
SetMana(GetMana() + CalcManaRegen() + RestRegenMana);
|
||||
|
||||
+48
-30
@@ -28,7 +28,7 @@
|
||||
set to nullptr and 0 respectively since they aren't used when adding
|
||||
an alias. The function pointers being equal is makes it an alias.
|
||||
The access level you set with command_add is only a default if
|
||||
the command isn't listed in the addon.ini file.
|
||||
the command isn't listed in the commands db table.
|
||||
|
||||
*/
|
||||
|
||||
@@ -2461,7 +2461,7 @@ void command_npctypespawn(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->IsNumber(1)) {
|
||||
const NPCType* tmp = 0;
|
||||
if ((tmp = database.GetNPCType(atoi(sep->arg[1])))) {
|
||||
if ((tmp = database.LoadNPCTypesData(atoi(sep->arg[1])))) {
|
||||
//tmp->fixedZ = 1;
|
||||
NPC* npc = new NPC(tmp, 0, c->GetPosition(), FlyMode3);
|
||||
if (npc && sep->IsNumber(2))
|
||||
@@ -2618,7 +2618,7 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
}
|
||||
else {
|
||||
int cursorDepth = 0;
|
||||
for (auto it = targetClient->GetInv().cursor_begin(); (it != targetClient->GetInv().cursor_end()); ++it, ++cursorDepth) {
|
||||
for (auto it = targetClient->GetInv().cursor_cbegin(); (it != targetClient->GetInv().cursor_cend()); ++it, ++cursorDepth) {
|
||||
inst_main = *it;
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
@@ -2923,7 +2923,7 @@ void command_viewnpctype(Client *c, const Seperator *sep)
|
||||
else
|
||||
{
|
||||
uint32 npctypeid=atoi(sep->arg[1]);
|
||||
const NPCType* npct = database.GetNPCType(npctypeid);
|
||||
const NPCType* npct = database.LoadNPCTypesData(npctypeid);
|
||||
if (npct) {
|
||||
c->Message(0, " NPCType Info, ");
|
||||
c->Message(0, " NPCTypeID: %u", npct->npc_id);
|
||||
@@ -4284,31 +4284,49 @@ void command_goto(Client *c, const Seperator *sep)
|
||||
|
||||
void command_iteminfo(Client *c, const Seperator *sep)
|
||||
{
|
||||
const ItemInst* inst = c->GetInv()[MainCursor];
|
||||
|
||||
if (!inst)
|
||||
c->Message(13, "Error: You need an item on your cursor for this command");
|
||||
else {
|
||||
const Item_Struct* item = inst->GetItem();
|
||||
c->Message(0, "ID: %i Name: %s", item->ID, item->Name);
|
||||
c->Message(0, " Lore: %s ND: %i NS: %i Type: %i", (item->LoreFlag) ? "true":"false", item->NoDrop, item->NoRent, item->ItemClass);
|
||||
c->Message(0, " IDF: %s Size: %i Weight: %i icon_id: %i Price: %i", item->IDFile, item->Size, item->Weight, item->Icon, item->Price);
|
||||
if (c->Admin() >= 200)
|
||||
c->Message(0, "MinStatus: %i", item->MinStatus);
|
||||
if (item->ItemClass==ItemClassBook)
|
||||
c->Message(0, " This item is a Book: %s", item->Filename);
|
||||
else if (item->ItemClass==ItemClassContainer)
|
||||
c->Message(0, " This item is a container with %i slots", item->BagSlots);
|
||||
else {
|
||||
c->Message(0, " equipableSlots: %u equipable Classes: %u", item->Slots, item->Classes);
|
||||
c->Message(0, " Magic: %i SpellID: %i Proc Level: %i DBCharges: %i CurCharges: %i", item->Magic, item->Click.Effect, item->Click.Level, item->MaxCharges, inst->GetCharges());
|
||||
c->Message(0, " EffectType: 0x%02x CastTime: %.2f", (uint8) item->Click.Type, (double) item->CastTime/1000);
|
||||
c->Message(0, " Material: 0x%02x Color: 0x%08x Skill: %i", item->Material, item->Color, item->ItemType);
|
||||
c->Message(0, " Required level: %i Required skill: %i Recommended level:%i", item->ReqLevel, item->RecSkill, item->RecLevel);
|
||||
c->Message(0, " Skill mod: %i percent: %i", item->SkillModType, item->SkillModValue);
|
||||
c->Message(0, " BaneRace: %i BaneBody: %i BaneDMG: %i", item->BaneDmgRace, item->BaneDmgBody, item->BaneDmgAmt);
|
||||
}
|
||||
auto inst = c->GetInv()[MainCursor];
|
||||
if (!inst) { c->Message(13, "Error: You need an item on your cursor for this command"); }
|
||||
auto item = inst->GetItem();
|
||||
if (!item) {
|
||||
Log.Out(Logs::General, Logs::Inventory, "(%s) Command #iteminfo processed an item with no data pointer");
|
||||
c->Message(13, "Error: This item has no data reference");
|
||||
}
|
||||
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemInst);
|
||||
linker.SetItemInst(inst);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
c->Message(0, "*** Item Info for [%s] ***", item_link.c_str());
|
||||
c->Message(0, ">> ID: %u, ItemUseType: %u, ItemClassType: %u", item->ID, item->ItemType, item->ItemClass);
|
||||
c->Message(0, ">> IDFile: '%s', IconID: %u", item->IDFile, item->Icon);
|
||||
c->Message(0, ">> Size: %u, Weight: %u, Price: %u, LDoNPrice: %u", item->Size, item->Weight, item->Price, item->LDoNPrice);
|
||||
c->Message(0, ">> Material: 0x%02X, Color: 0x%08X, Tint: 0x%08X, Light: 0x%02X", item->Material, item->Color, inst->GetColor(), item->Light);
|
||||
c->Message(0, ">> IsLore: %s, LoreGroup: %u, Lore: '%s'", (item->LoreFlag ? "TRUE" : "FALSE"), item->LoreGroup, item->Lore);
|
||||
c->Message(0, ">> NoDrop: %u, NoRent: %u, NoPet: %u, NoTransfer: %u, FVNoDrop: %u",
|
||||
item->NoDrop, item->NoRent, (uint8)item->NoPet, (uint8)item->NoTransfer, item->FVNoDrop);
|
||||
|
||||
if (item->ItemClass == ItemClassBook) {
|
||||
c->Message(0, "*** This item is a Book (filename:'%s') ***", item->Filename);
|
||||
}
|
||||
else if (item->ItemClass == ItemClassContainer) {
|
||||
c->Message(0, "*** This item is a Container (%u slots) ***", item->BagSlots);
|
||||
}
|
||||
else {
|
||||
c->Message(0, "*** This item is Common ***");
|
||||
c->Message(0, ">> Classes: %u, Races: %u, Slots: %u", item->Classes, item->Races, item->Slots);
|
||||
c->Message(0, ">> ReqSkill: %u, ReqLevel: %u, RecLevel: %u", item->RecSkill, item->ReqLevel, item->RecLevel);
|
||||
c->Message(0, ">> SkillModType: %u, SkillModValue: %i", item->SkillModType, item->SkillModValue);
|
||||
c->Message(0, ">> BaneRaceType: %u, BaneRaceDamage: %u, BaneBodyType: %u, BaneBodyDamage: %i",
|
||||
item->BaneDmgRace, item->BaneDmgRaceAmt, item->BaneDmgBody, item->BaneDmgAmt);
|
||||
c->Message(0, ">> Magic: %s, SpellID: %i, ProcLevel: %u, Charges: %u, MaxCharges: %u",
|
||||
(item->Magic ? "TRUE" : "FALSE"), item->Click.Effect, item->Click.Level, inst->GetCharges(), item->MaxCharges);
|
||||
c->Message(0, ">> EffectType: 0x%02X, CastTime: %.2f", (uint8)item->Click.Type, ((double)item->CastTime / 1000));
|
||||
}
|
||||
|
||||
if (c->Admin() >= 200)
|
||||
c->Message(0, ">> MinStatus: %u", item->MinStatus);
|
||||
}
|
||||
|
||||
void command_uptime(Client *c, const Seperator *sep)
|
||||
@@ -6669,7 +6687,7 @@ void command_qglobal(Client *c, const Seperator *sep) {
|
||||
}
|
||||
|
||||
if(!strcasecmp(sep->arg[1], "view")) {
|
||||
const NPCType *type = database.GetNPCType(target->GetNPCTypeID());
|
||||
const NPCType *type = database.LoadNPCTypesData(target->GetNPCTypeID());
|
||||
if(!type)
|
||||
c->Message(15, "Invalid NPC type.");
|
||||
else if(type->qglobal)
|
||||
@@ -7002,7 +7020,7 @@ void Client::Undye() {
|
||||
database.SaveInventory(CharacterID(), inst, slot2);
|
||||
}
|
||||
|
||||
m_pp.item_tint[cur_slot].color = 0;
|
||||
m_pp.item_tint[cur_slot].Color = 0;
|
||||
SendWearChange(cur_slot);
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -136,7 +136,8 @@ enum {
|
||||
ALLOW_TO_TANK = 41,
|
||||
IGNORE_ROOT_AGGRO_RULES = 42,
|
||||
CASTING_RESIST_DIFF = 43,
|
||||
MAX_SPECIAL_ATTACK = 44
|
||||
COUNTER_AVOID_DAMAGE = 44,
|
||||
MAX_SPECIAL_ATTACK = 45
|
||||
};
|
||||
|
||||
typedef enum { //fear states
|
||||
@@ -350,7 +351,8 @@ struct StatBonuses {
|
||||
int32 CharmBreakChance; // chance to break charm
|
||||
int32 SongRange; // increases range of beneficial bard songs
|
||||
uint32 HPToManaConvert; // Uses HP to cast spells at specific conversion
|
||||
uint32 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
||||
uint8 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
||||
int16 FocusEffectsWorn[HIGHEST_FOCUS+1]; // Optional to allow focus effects to be applied additively from worn slot
|
||||
bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses)
|
||||
int32 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage
|
||||
uint32 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit
|
||||
@@ -505,7 +507,7 @@ typedef enum {
|
||||
petOther,
|
||||
petCharmed,
|
||||
petNPCFollow,
|
||||
petHatelist //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
|
||||
} PetType;
|
||||
|
||||
typedef enum {
|
||||
|
||||
+65
-50
@@ -114,15 +114,15 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std:
|
||||
pc->Lock();
|
||||
|
||||
/* Load Item Tints */
|
||||
pc->item_tint[0].color = pcs->item_tint[0].color;
|
||||
pc->item_tint[1].color = pcs->item_tint[1].color;
|
||||
pc->item_tint[2].color = pcs->item_tint[2].color;
|
||||
pc->item_tint[3].color = pcs->item_tint[3].color;
|
||||
pc->item_tint[4].color = pcs->item_tint[4].color;
|
||||
pc->item_tint[5].color = pcs->item_tint[5].color;
|
||||
pc->item_tint[6].color = pcs->item_tint[6].color;
|
||||
pc->item_tint[7].color = pcs->item_tint[7].color;
|
||||
pc->item_tint[8].color = pcs->item_tint[8].color;
|
||||
pc->item_tint[0].Color = pcs->item_tint[0].Color;
|
||||
pc->item_tint[1].Color = pcs->item_tint[1].Color;
|
||||
pc->item_tint[2].Color = pcs->item_tint[2].Color;
|
||||
pc->item_tint[3].Color = pcs->item_tint[3].Color;
|
||||
pc->item_tint[4].Color = pcs->item_tint[4].Color;
|
||||
pc->item_tint[5].Color = pcs->item_tint[5].Color;
|
||||
pc->item_tint[6].Color = pcs->item_tint[6].Color;
|
||||
pc->item_tint[7].Color = pcs->item_tint[7].Color;
|
||||
pc->item_tint[8].Color = pcs->item_tint[8].Color;
|
||||
|
||||
/* Load Physical Appearance */
|
||||
pc->haircolor = pcs->haircolor;
|
||||
@@ -138,9 +138,9 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std:
|
||||
pc->IsRezzed(rezzed);
|
||||
pc->become_npc = false;
|
||||
|
||||
pc->spell_light = pc->innate_light = NOT_USED;
|
||||
pc->UpdateEquipLightValue();
|
||||
//pc->UpdateActiveLightValue();
|
||||
pc->m_Light.Level.Innate = pc->m_Light.Type.Innate = 0;
|
||||
pc->UpdateEquipmentLight(); // itemlist populated above..need to determine actual values
|
||||
pc->m_Light.Level.Spell = pc->m_Light.Type.Spell = 0;
|
||||
|
||||
safe_delete_array(pcs);
|
||||
|
||||
@@ -151,7 +151,7 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP
|
||||
// vesuvias - appearence fix
|
||||
: Mob("Unnamed_Corpse","",0,0,in_npc->GetGender(),in_npc->GetRace(),in_npc->GetClass(),BT_Humanoid,//bodytype added
|
||||
in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),in_npc->GetSize(),0,
|
||||
in_npc->GetPosition(), in_npc->GetInnateLightValue(), in_npc->GetTexture(),in_npc->GetHelmTexture(),
|
||||
in_npc->GetPosition(), in_npc->GetInnateLightType(), in_npc->GetTexture(),in_npc->GetHelmTexture(),
|
||||
0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0xff,0,0,0,0,0,0,0,0,0),
|
||||
corpse_decay_timer(in_decaytime),
|
||||
@@ -203,9 +203,8 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP
|
||||
}
|
||||
this->rez_experience = 0;
|
||||
|
||||
UpdateEquipLightValue();
|
||||
spell_light = NOT_USED;
|
||||
UpdateActiveLightValue();
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
}
|
||||
|
||||
Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
@@ -223,7 +222,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
client->GetSize(), // float in_size,
|
||||
0, // float in_runspeed,
|
||||
client->GetPosition(),
|
||||
0, // uint8 in_light, - verified for client innate_light value
|
||||
client->GetInnateLightType(), // uint8 in_light, - verified for client innate_light value
|
||||
client->GetTexture(), // uint8 in_texture,
|
||||
client->GetHelmTexture(), // uint8 in_helmtexture,
|
||||
0, // uint16 in_ac,
|
||||
@@ -341,7 +340,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
|
||||
database.TransactionBegin();
|
||||
|
||||
// I have an untested process that avoids this snarl up when all possessions inventory is removed..but this isn't broke -U
|
||||
// I have an untested process that avoids this snarl up when all possessions inventory is removed..but this isn't broke
|
||||
if (!removed_list.empty()) {
|
||||
std::stringstream ss("");
|
||||
ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
|
||||
@@ -362,8 +361,8 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
database.QueryDatabase(ss.str().c_str());
|
||||
}
|
||||
|
||||
auto start = client->GetInv().cursor_begin();
|
||||
auto finish = client->GetInv().cursor_end();
|
||||
auto start = client->GetInv().cursor_cbegin();
|
||||
auto finish = client->GetInv().cursor_cend();
|
||||
database.SaveCursor(client->CharacterID(), start, finish);
|
||||
|
||||
client->CalcBonuses();
|
||||
@@ -374,16 +373,14 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
|
||||
database.TransactionCommit();
|
||||
|
||||
UpdateEquipLightValue();
|
||||
spell_light = NOT_USED;
|
||||
UpdateActiveLightValue();
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
|
||||
return;
|
||||
} //end "not leaving naked corpses"
|
||||
|
||||
UpdateEquipLightValue();
|
||||
spell_light = NOT_USED;
|
||||
UpdateActiveLightValue();
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
|
||||
IsRezzed(false);
|
||||
Save();
|
||||
@@ -522,9 +519,9 @@ in_helmtexture,
|
||||
}
|
||||
SetPlayerKillItemID(0);
|
||||
|
||||
UpdateEquipLightValue();
|
||||
spell_light = NOT_USED;
|
||||
UpdateActiveLightValue();
|
||||
UpdateEquipmentLight();
|
||||
m_Light.Level.Spell = m_Light.Type.Spell = 0;
|
||||
UpdateActiveLight();
|
||||
}
|
||||
|
||||
Corpse::~Corpse() {
|
||||
@@ -675,7 +672,7 @@ void Corpse::AddItem(uint32 itemnum, uint16 charges, int16 slot, uint32 aug1, ui
|
||||
item->attuned=attuned;
|
||||
itemlist.push_back(item);
|
||||
|
||||
UpdateEquipLightValue();
|
||||
UpdateEquipmentLight();
|
||||
}
|
||||
|
||||
ServerLootItem_Struct* Corpse::GetItem(uint16 lootslot, ServerLootItem_Struct** bag_item_data) {
|
||||
@@ -750,9 +747,9 @@ void Corpse::RemoveItem(ServerLootItem_Struct* item_data)
|
||||
if (material != _MaterialInvalid)
|
||||
SendWearChange(material);
|
||||
|
||||
UpdateEquipLightValue();
|
||||
if (UpdateActiveLightValue())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
|
||||
safe_delete(sitem);
|
||||
return;
|
||||
@@ -1228,9 +1225,9 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
|
||||
linker.SetLinkType(linker.linkItemInst);
|
||||
linker.SetItemInst(inst);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
|
||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
|
||||
|
||||
if (!IsPlayerCorpse()) {
|
||||
Group *g = client->GetGroup();
|
||||
@@ -1279,14 +1276,10 @@ void Corpse::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
||||
Mob::FillSpawnStruct(ns, ForWho);
|
||||
|
||||
ns->spawn.max_hp = 120;
|
||||
ns->spawn.NPC = 2;
|
||||
|
||||
if (IsPlayerCorpse())
|
||||
ns->spawn.NPC = 3;
|
||||
else
|
||||
ns->spawn.NPC = 2;
|
||||
|
||||
UpdateActiveLightValue();
|
||||
ns->spawn.light = active_light;
|
||||
UpdateActiveLight();
|
||||
ns->spawn.light = m_Light.Type.Active;
|
||||
}
|
||||
|
||||
void Corpse::QueryLoot(Client* to) {
|
||||
@@ -1425,26 +1418,48 @@ uint32 Corpse::GetEquipmentColor(uint8 material_slot) const {
|
||||
|
||||
item = database.GetItem(GetEquipment(material_slot));
|
||||
if(item != NO_ITEM) {
|
||||
return item_tint[material_slot].rgb.use_tint ?
|
||||
item_tint[material_slot].color :
|
||||
return item_tint[material_slot].RGB.UseTint ?
|
||||
item_tint[material_slot].Color :
|
||||
item->Color;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Corpse::UpdateEquipLightValue()
|
||||
void Corpse::UpdateEquipmentLight()
|
||||
{
|
||||
equip_light = NOT_USED;
|
||||
m_Light.Type.Equipment = 0;
|
||||
m_Light.Level.Equipment = 0;
|
||||
|
||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||
if (((*iter)->equip_slot < EmuConstants::EQUIPMENT_BEGIN || (*iter)->equip_slot > EmuConstants::GENERAL_END) && (*iter)->equip_slot != MainPowerSource) { continue; }
|
||||
if (((*iter)->equip_slot < EmuConstants::EQUIPMENT_BEGIN || (*iter)->equip_slot > EmuConstants::EQUIPMENT_END) && (*iter)->equip_slot != MainPowerSource) { continue; }
|
||||
if ((*iter)->equip_slot == MainAmmo) { continue; }
|
||||
|
||||
auto item = database.GetItem((*iter)->item_id);
|
||||
if (item == nullptr) { continue; }
|
||||
if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight) { continue; }
|
||||
if (item->Light & 0xF0) { continue; }
|
||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
||||
|
||||
if (m_Light.IsLevelGreater(item->Light, m_Light.Type.Equipment))
|
||||
m_Light.Type.Equipment = item->Light;
|
||||
}
|
||||
|
||||
uint8 general_light_type = 0;
|
||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||
if ((*iter)->equip_slot < EmuConstants::GENERAL_BEGIN || (*iter)->equip_slot > EmuConstants::GENERAL_END) { continue; }
|
||||
|
||||
auto item = database.GetItem((*iter)->item_id);
|
||||
if (item == nullptr) { continue; }
|
||||
|
||||
if (item->ItemClass != ItemClassCommon) { continue; }
|
||||
if (item->Light < 9 || item->Light > 13) { continue; }
|
||||
|
||||
if (m_Light.TypeToLevel(item->Light))
|
||||
general_light_type = item->Light;
|
||||
}
|
||||
|
||||
if (m_Light.IsLevelGreater(general_light_type, m_Light.Type.Equipment))
|
||||
m_Light.Type.Equipment = general_light_type;
|
||||
|
||||
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||
}
|
||||
|
||||
void Corpse::AddLooter(Mob* who) {
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ class Corpse : public Mob {
|
||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
inline int GetRezExp() { return rez_experience; }
|
||||
|
||||
virtual void UpdateEquipLightValue();
|
||||
virtual void UpdateEquipmentLight();
|
||||
|
||||
protected:
|
||||
void MoveItemToCorpse(Client *client, ItemInst *inst, int16 equipSlot, std::list<uint32> &removedList);
|
||||
|
||||
+16
-14
@@ -41,14 +41,14 @@ extern EntityList entity_list;
|
||||
extern WorldServer worldserver;
|
||||
|
||||
Doors::Doors(const Door* door) :
|
||||
close_timer(5000),
|
||||
m_Position(door->pos_x, door->pos_y, door->pos_z, door->heading),
|
||||
m_Destination(door->dest_x, door->dest_y, door->dest_z, door->dest_heading)
|
||||
close_timer(5000),
|
||||
m_Position(door->pos_x, door->pos_y, door->pos_z, door->heading),
|
||||
m_Destination(door->dest_x, door->dest_y, door->dest_z, door->dest_heading)
|
||||
{
|
||||
db_id = door->db_id;
|
||||
door_id = door->door_id;
|
||||
strn0cpy(zone_name,door->zone_name,32);
|
||||
strn0cpy(door_name,door->door_name,32);
|
||||
strn0cpy(zone_name, door->zone_name, 32);
|
||||
strn0cpy(door_name, door->door_name, 32);
|
||||
incline = door->incline;
|
||||
opentype = door->opentype;
|
||||
guild_id = door->guild_id;
|
||||
@@ -57,7 +57,7 @@ Doors::Doors(const Door* door) :
|
||||
nokeyring = door->nokeyring;
|
||||
trigger_door = door->trigger_door;
|
||||
trigger_type = door->trigger_type;
|
||||
triggered=false;
|
||||
triggered = false;
|
||||
door_param = door->door_param;
|
||||
size = door->size;
|
||||
invert_state = door->invert_state;
|
||||
@@ -65,7 +65,7 @@ Doors::Doors(const Door* door) :
|
||||
|
||||
close_timer.Disable();
|
||||
|
||||
strn0cpy(dest_zone,door->dest_zone,16);
|
||||
strn0cpy(dest_zone, door->dest_zone, 16);
|
||||
dest_instance_id = door->dest_instance_id;
|
||||
|
||||
is_ldon_door = door->is_ldon_door;
|
||||
@@ -73,14 +73,14 @@ Doors::Doors(const Door* door) :
|
||||
}
|
||||
|
||||
Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uint16 dsize) :
|
||||
close_timer(5000),
|
||||
m_Position(position),
|
||||
m_Destination(glm::vec4())
|
||||
close_timer(5000),
|
||||
m_Position(position),
|
||||
m_Destination(glm::vec4())
|
||||
{
|
||||
db_id = database.GetDoorsCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion());
|
||||
door_id = database.GetDoorsDBCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion());
|
||||
strn0cpy(zone_name,zone->GetShortName(),32);
|
||||
strn0cpy(door_name,dmodel,32);
|
||||
strn0cpy(zone_name, zone->GetShortName(), 32);
|
||||
strn0cpy(door_name, dmodel, 32);
|
||||
incline = 0;
|
||||
opentype = dopentype;
|
||||
guild_id = 0;
|
||||
@@ -89,7 +89,7 @@ Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uin
|
||||
nokeyring = 0;
|
||||
trigger_door = 0;
|
||||
trigger_type = 0;
|
||||
triggered=false;
|
||||
triggered = false;
|
||||
door_param = 0;
|
||||
size = dsize;
|
||||
invert_state = 0;
|
||||
@@ -97,7 +97,7 @@ Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uin
|
||||
|
||||
close_timer.Disable();
|
||||
|
||||
strn0cpy(dest_zone,"NONE",32);
|
||||
strn0cpy(dest_zone, "NONE", 32);
|
||||
dest_instance_id = 0;
|
||||
|
||||
is_ldon_door = 0;
|
||||
@@ -655,6 +655,8 @@ bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name
|
||||
into[rowIndex].db_id = atoi(row[0]);
|
||||
into[rowIndex].door_id = atoi(row[1]);
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Doors, "Door Load: db id: %u, door_id %u", into[rowIndex].db_id, into[rowIndex].door_id);
|
||||
|
||||
strn0cpy(into[rowIndex].zone_name,row[2],32);
|
||||
strn0cpy(into[rowIndex].door_name,row[3],32);
|
||||
|
||||
|
||||
+1
-1
@@ -756,7 +756,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
} else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies...
|
||||
// This does not check faction for beneficial AE buffs..only agro and attackable.
|
||||
// I've tested for spells that I can find without problem, but a faction-based
|
||||
// check may still be needed. Any changes here should also reflect in BardAEPulse() -U
|
||||
// check may still be needed. Any changes here should also reflect in BardAEPulse()
|
||||
if (caster->IsAttackAllowed(curmob, true))
|
||||
continue;
|
||||
if (caster->CheckAggro(curmob))
|
||||
|
||||
+3
-3
@@ -863,7 +863,7 @@ void PerlembParser::GetQuestPackageName(bool &isPlayerQuest, bool &isGlobalPlaye
|
||||
}
|
||||
}
|
||||
else if(isItemQuest) {
|
||||
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
|
||||
// need a valid ItemInst pointer check here..unsure how to cancel this process
|
||||
const Item_Struct* item = iteminst->GetItem();
|
||||
package_name = "qst_item_";
|
||||
package_name += itoa(item->ID);
|
||||
@@ -1308,7 +1308,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
|
||||
case EVENT_SCALE_CALC:
|
||||
case EVENT_ITEM_ENTER_ZONE: {
|
||||
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
|
||||
// need a valid ItemInst pointer check here..unsure how to cancel this process
|
||||
ExportVar(package_name.c_str(), "itemid", objid);
|
||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||
break;
|
||||
@@ -1316,7 +1316,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
|
||||
case EVENT_ITEM_CLICK_CAST:
|
||||
case EVENT_ITEM_CLICK: {
|
||||
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
|
||||
// need a valid ItemInst pointer check here..unsure how to cancel this process
|
||||
ExportVar(package_name.c_str(), "itemid", objid);
|
||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||
ExportVar(package_name.c_str(), "slotid", extradata);
|
||||
|
||||
+4
-3
@@ -2767,7 +2767,7 @@ void EntityList::WriteEntityIDs()
|
||||
|
||||
BulkZoneSpawnPacket::BulkZoneSpawnPacket(Client *iSendTo, uint32 iMaxSpawnsPerPacket)
|
||||
{
|
||||
data = 0;
|
||||
data = nullptr;
|
||||
pSendTo = iSendTo;
|
||||
pMaxSpawnsPerPacket = iMaxSpawnsPerPacket;
|
||||
}
|
||||
@@ -2775,7 +2775,7 @@ BulkZoneSpawnPacket::BulkZoneSpawnPacket(Client *iSendTo, uint32 iMaxSpawnsPerPa
|
||||
BulkZoneSpawnPacket::~BulkZoneSpawnPacket()
|
||||
{
|
||||
SendBuffer();
|
||||
safe_delete_array(data)
|
||||
safe_delete_array(data);
|
||||
}
|
||||
|
||||
bool BulkZoneSpawnPacket::AddSpawn(NewSpawn_Struct *ns)
|
||||
@@ -2794,7 +2794,8 @@ bool BulkZoneSpawnPacket::AddSpawn(NewSpawn_Struct *ns)
|
||||
return false;
|
||||
}
|
||||
|
||||
void BulkZoneSpawnPacket::SendBuffer() {
|
||||
void BulkZoneSpawnPacket::SendBuffer()
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
|
||||
+1
-1
@@ -270,7 +270,7 @@ void Client::GoFish()
|
||||
//check for add NPC
|
||||
if(npc_chance > 0 && npc_id) {
|
||||
if(npc_chance < zone->random.Int(0, 99)) {
|
||||
const NPCType* tmp = database.GetNPCType(npc_id);
|
||||
const NPCType* tmp = database.LoadNPCTypesData(npc_id);
|
||||
if(tmp != nullptr) {
|
||||
auto positionNPC = GetPosition();
|
||||
positionNPC.x = positionNPC.x + 3;
|
||||
|
||||
+2
-2
@@ -72,8 +72,8 @@ public:
|
||||
uint32 GetTotalGroupDamage(Mob* other);
|
||||
void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr);
|
||||
inline void SetLeader(Mob* newleader){ leader=newleader; };
|
||||
inline Mob* GetLeader(){ return leader; };
|
||||
char* GetLeaderName() { return membername[0]; };
|
||||
inline Mob* GetLeader() { return leader; };
|
||||
const char* GetLeaderName() { return membername[0]; };
|
||||
void SendHPPacketsTo(Mob* newmember);
|
||||
void SendHPPacketsFrom(Mob* newmember);
|
||||
bool UpdatePlayer(Mob* update);
|
||||
|
||||
+8
-8
@@ -219,17 +219,17 @@ bool HateList::RemoveEntFromHateList(Mob *in_entity)
|
||||
{
|
||||
if ((*iterator)->entity_on_hatelist == in_entity)
|
||||
{
|
||||
if (in_entity)
|
||||
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0);
|
||||
is_found = true;
|
||||
|
||||
|
||||
if (in_entity && in_entity->IsClient())
|
||||
in_entity->CastToClient()->DecrementAggroCount();
|
||||
|
||||
delete (*iterator);
|
||||
iterator = list.erase(iterator);
|
||||
|
||||
if (in_entity)
|
||||
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0);
|
||||
|
||||
}
|
||||
else
|
||||
++iterator;
|
||||
@@ -282,14 +282,14 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center)
|
||||
return nullptr;
|
||||
|
||||
Mob* top_hate = nullptr;
|
||||
int32 hate = -1;
|
||||
int64 hate = -1;
|
||||
|
||||
if (center == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (RuleB(Aggro, SmartAggroList)){
|
||||
Mob* top_client_type_in_range = nullptr;
|
||||
int32 hate_client_type_in_range = -1;
|
||||
int64 hate_client_type_in_range = -1;
|
||||
int skipped_count = 0;
|
||||
|
||||
auto iterator = list.begin();
|
||||
@@ -337,7 +337,7 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center)
|
||||
continue;
|
||||
}
|
||||
|
||||
int32 current_hate = cur->stored_hate_amount;
|
||||
int64 current_hate = cur->stored_hate_amount;
|
||||
|
||||
if (cur->entity_on_hatelist->IsClient()){
|
||||
|
||||
@@ -459,13 +459,13 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center)
|
||||
|
||||
Mob *HateList::GetEntWithMostHateOnList(){
|
||||
Mob* top = nullptr;
|
||||
int32 hate = -1;
|
||||
int64 hate = -1;
|
||||
|
||||
auto iterator = list.begin();
|
||||
while (iterator != list.end())
|
||||
{
|
||||
struct_HateList *cur = (*iterator);
|
||||
if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
|
||||
if (cur && cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
|
||||
{
|
||||
top = cur->entity_on_hatelist;
|
||||
hate = cur->stored_hate_amount;
|
||||
|
||||
+180
-102
@@ -177,16 +177,16 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
|
||||
}
|
||||
|
||||
|
||||
bool Client::CheckLoreConflict(const Item_Struct* item) {
|
||||
if (!item)
|
||||
return false;
|
||||
if (!(item->LoreFlag))
|
||||
return false;
|
||||
bool Client::CheckLoreConflict(const Item_Struct* item)
|
||||
{
|
||||
if (!item) { return false; }
|
||||
if (!item->LoreFlag) { return false; }
|
||||
if (item->LoreGroup == 0) { return false; }
|
||||
|
||||
if (item->LoreGroup == -1) // Standard lore items; look everywhere except the shared bank, return the result
|
||||
if (item->LoreGroup == 0xFFFFFFFF) // Standard lore items; look everywhere except the shared bank, return the result
|
||||
return (m_inv.HasItem(item->ID, 0, ~invWhereSharedBank) != INVALID_INDEX);
|
||||
|
||||
//If the item has a lore group, we check for other items with the same group and return the result
|
||||
// If the item has a lore group, we check for other items with the same group and return the result
|
||||
return (m_inv.HasItemByLoreGroup(item->LoreGroup, ~invWhereSharedBank) != INVALID_INDEX);
|
||||
}
|
||||
|
||||
@@ -619,7 +619,7 @@ void Client::DropItem(int16 slot_id)
|
||||
// Save client inventory change to database
|
||||
if (slot_id == MainCursor) {
|
||||
SendCursorBuffer();
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
database.SaveCursor(CharacterID(), s, e);
|
||||
} else {
|
||||
database.SaveInventory(CharacterID(), nullptr, slot_id);
|
||||
@@ -680,20 +680,37 @@ int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) {
|
||||
return INVALID_ID;
|
||||
}
|
||||
|
||||
void Client::SendCursorBuffer() {
|
||||
void Client::SendCursorBuffer()
|
||||
{
|
||||
// Temporary work-around for the RoF+ Client Buffer
|
||||
// Instead of dealing with client moving items in cursor buffer,
|
||||
// we can just send the next item in the cursor buffer to the cursor.
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
if (!GetInv().CursorEmpty())
|
||||
{
|
||||
const ItemInst* inst = GetInv().GetCursorItem();
|
||||
if (inst)
|
||||
{
|
||||
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
|
||||
}
|
||||
}
|
||||
if (GetClientVersion() < ClientVersion::RoF) { return; }
|
||||
if (GetInv().CursorEmpty()) { return; }
|
||||
|
||||
auto test_inst = GetInv().GetCursorItem();
|
||||
if (test_inst == nullptr) { return; }
|
||||
auto test_item = test_inst->GetItem();
|
||||
if (test_item == nullptr) { return; }
|
||||
|
||||
bool lore_pass = true;
|
||||
if (test_item->LoreGroup == 0xFFFFFFFF) {
|
||||
lore_pass = (m_inv.HasItem(test_item->ID, 0, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
|
||||
}
|
||||
else if (test_item->LoreGroup != 0) {
|
||||
lore_pass = (m_inv.HasItemByLoreGroup(test_item->LoreGroup, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
|
||||
}
|
||||
|
||||
if (!lore_pass) {
|
||||
Log.Out(Logs::General, Logs::Inventory, "(%s) Duplicate lore items are not allowed - destroying item %s(id:%u) on cursor",
|
||||
GetName(), test_item->Name, test_item->ID);
|
||||
Message_StringID(MT_LootMessages, 290);
|
||||
parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0);
|
||||
DeleteItemInInventory(MainCursor);
|
||||
SendCursorBuffer();
|
||||
}
|
||||
else {
|
||||
SendItemPacket(MainCursor, test_inst, ItemPacketSummonItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,7 +789,7 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd
|
||||
|
||||
const ItemInst* inst = nullptr;
|
||||
if (slot_id == MainCursor) {
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
if(update_db)
|
||||
database.SaveCursor(character_id, s, e);
|
||||
}
|
||||
@@ -826,7 +843,7 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
|
||||
SendItemPacket(MainCursor, &inst, ItemPacketSummonItem);
|
||||
}
|
||||
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
return database.SaveCursor(CharacterID(), s, e);
|
||||
}
|
||||
|
||||
@@ -851,7 +868,7 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client
|
||||
}
|
||||
|
||||
if (slot_id == MainCursor) {
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
return database.SaveCursor(this->CharacterID(), s, e);
|
||||
}
|
||||
else {
|
||||
@@ -865,28 +882,64 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client
|
||||
void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data)
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Putting loot item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
|
||||
m_inv.PutItem(slot_id, inst);
|
||||
|
||||
SendLootItemInPacket(&inst, slot_id);
|
||||
bool cursor_empty = m_inv.CursorEmpty();
|
||||
|
||||
if (slot_id == MainCursor) {
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
m_inv.PushCursor(inst);
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
database.SaveCursor(this->CharacterID(), s, e);
|
||||
}
|
||||
else {
|
||||
m_inv.PutItem(slot_id, inst);
|
||||
database.SaveInventory(this->CharacterID(), &inst, slot_id);
|
||||
}
|
||||
|
||||
if(bag_item_data) { // bag contents
|
||||
int16 interior_slot;
|
||||
// our bag went into slot_id, now let's pack the contents in
|
||||
for(int i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) {
|
||||
if(bag_item_data[i] == nullptr)
|
||||
// Subordinate items in cursor buffer must be sent via ItemPacketSummonItem or we just overwrite the visible cursor and desync the client
|
||||
if (slot_id == MainCursor && !cursor_empty) {
|
||||
// RoF+ currently has a specialized cursor handler
|
||||
if (GetClientVersion() < ClientVersion::RoF)
|
||||
SendItemPacket(slot_id, &inst, ItemPacketSummonItem);
|
||||
}
|
||||
else {
|
||||
SendLootItemInPacket(&inst, slot_id);
|
||||
}
|
||||
|
||||
if (bag_item_data) {
|
||||
for (int index = 0; index < EmuConstants::ITEM_CONTAINER_SIZE; ++index) {
|
||||
if (bag_item_data[index] == nullptr)
|
||||
continue;
|
||||
const ItemInst *bagitem = database.CreateItem(bag_item_data[i]->item_id, bag_item_data[i]->charges, bag_item_data[i]->aug_1, bag_item_data[i]->aug_2, bag_item_data[i]->aug_3, bag_item_data[i]->aug_4, bag_item_data[i]->aug_5, bag_item_data[i]->aug_6, bag_item_data[i]->attuned);
|
||||
interior_slot = Inventory::CalcSlotId(slot_id, i);
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Putting bag loot item %s (%d) into slot %d (bag slot %d)", inst.GetItem()->Name, inst.GetItem()->ID, interior_slot, i);
|
||||
PutLootInInventory(interior_slot, *bagitem);
|
||||
|
||||
const ItemInst *bagitem = database.CreateItem(
|
||||
bag_item_data[index]->item_id,
|
||||
bag_item_data[index]->charges,
|
||||
bag_item_data[index]->aug_1,
|
||||
bag_item_data[index]->aug_2,
|
||||
bag_item_data[index]->aug_3,
|
||||
bag_item_data[index]->aug_4,
|
||||
bag_item_data[index]->aug_5,
|
||||
bag_item_data[index]->aug_6,
|
||||
bag_item_data[index]->attuned
|
||||
);
|
||||
|
||||
// Dump bag contents to cursor in the event that owning bag is not the first cursor item
|
||||
// (This assumes that the data passed is correctly associated..no safety checks are implemented)
|
||||
if (slot_id == MainCursor && !cursor_empty) {
|
||||
Log.Out(Logs::Detail, Logs::Inventory,
|
||||
"Putting bag loot item %s (%d) into slot %d (non-empty cursor override)",
|
||||
inst.GetItem()->Name, inst.GetItem()->ID, MainCursor);
|
||||
|
||||
PutLootInInventory(MainCursor, *bagitem);
|
||||
}
|
||||
else {
|
||||
auto bag_slot = Inventory::CalcSlotId(slot_id, index);
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Inventory,
|
||||
"Putting bag loot item %s (%d) into slot %d (bag slot %d)",
|
||||
inst.GetItem()->Name, inst.GetItem()->ID, bag_slot, index);
|
||||
|
||||
PutLootInInventory(bag_slot, *bagitem);
|
||||
}
|
||||
safe_delete(bagitem);
|
||||
}
|
||||
}
|
||||
@@ -1009,7 +1062,7 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type)
|
||||
from.SetCharges(from.GetCharges() - charges_to_move);
|
||||
SendLootItemInPacket(tmp_inst, to_slot);
|
||||
if (to_slot == MainCursor) {
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
database.SaveCursor(this->CharacterID(), s, e);
|
||||
}
|
||||
else {
|
||||
@@ -1050,12 +1103,12 @@ bool MakeItemLink(char* &ret_link, const Item_Struct *item, uint32 aug0, uint32
|
||||
// Currently, enabling them causes misalignments in what the client expects. I haven't looked
|
||||
// into it further to determine the cause..but, the function is setup to accept the parameters.
|
||||
// Note: some links appear with '00000' in front of the name..so, it's likely we need to send
|
||||
// some additional information when certain parameters are true -U
|
||||
// some additional information when certain parameters are true
|
||||
//switch (GetClientVersion()) {
|
||||
switch (0) {
|
||||
case EQClientRoF2:
|
||||
// This operator contains 14 parameter masks..but, only 13 parameter values.
|
||||
// Even so, the client link appears ok... Need to figure out the discrepancy -U
|
||||
// Even so, the client link appears ok... Need to figure out the discrepancy
|
||||
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X",
|
||||
0,
|
||||
item->ID,
|
||||
@@ -1320,10 +1373,33 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This could be expounded upon at some point to let the server know that
|
||||
// the client has moved a buffered cursor item onto the active cursor -U
|
||||
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed
|
||||
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
|
||||
if (GetClientVersion() >= ClientVersion::RoF) { return true; } // Can't do RoF+
|
||||
|
||||
if (move_in->to_slot == MainCursor) {
|
||||
auto test_inst = m_inv.GetItem(MainCursor);
|
||||
if (test_inst == nullptr) { return true; }
|
||||
auto test_item = test_inst->GetItem();
|
||||
if (test_item == nullptr) { return true; }
|
||||
if (!test_item->LoreFlag) { return true; }
|
||||
|
||||
bool lore_pass = true;
|
||||
if (test_item->LoreGroup == 0xFFFFFFFF) {
|
||||
lore_pass = (m_inv.HasItem(test_item->ID, 0, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
|
||||
}
|
||||
else if (test_item->LoreGroup != 0) {
|
||||
lore_pass = (m_inv.HasItemByLoreGroup(test_item->LoreGroup, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
|
||||
}
|
||||
|
||||
if (!lore_pass) {
|
||||
Log.Out(Logs::General, Logs::Inventory, "(%s) Duplicate lore items are not allowed - destroying item %s(id:%u) on cursor",
|
||||
GetName(), test_item->Name, test_item->ID);
|
||||
Message_StringID(MT_LootMessages, 290);
|
||||
parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0);
|
||||
DeleteItemInInventory(MainCursor, 0, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1567,7 +1643,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
{
|
||||
SendCursorBuffer();
|
||||
}
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
database.SaveCursor(character_id, s, e);
|
||||
}
|
||||
else
|
||||
@@ -1726,7 +1802,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
{
|
||||
SendCursorBuffer();
|
||||
}
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
database.SaveCursor(character_id, s, e);
|
||||
}
|
||||
else {
|
||||
@@ -1734,7 +1810,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
}
|
||||
|
||||
if (dst_slot_id == MainCursor) {
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
database.SaveCursor(character_id, s, e);
|
||||
}
|
||||
else {
|
||||
@@ -1753,14 +1829,14 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) {
|
||||
// with any luck..this won't be needed in the future
|
||||
|
||||
// resync the 'from' and 'to' slots on an as-needed basis
|
||||
// Not as effective as the full process, but less intrusive to gameplay -U
|
||||
// Not as effective as the full process, but less intrusive to gameplay
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Inventory desyncronization. (charname: %s, source: %i, destination: %i)", GetName(), move_slots->from_slot, move_slots->to_slot);
|
||||
Message(15, "Inventory Desyncronization detected: Resending slot data...");
|
||||
|
||||
if((move_slots->from_slot >= EmuConstants::EQUIPMENT_BEGIN && move_slots->from_slot <= EmuConstants::CURSOR_BAG_END) || move_slots->from_slot == MainPowerSource) {
|
||||
int16 resync_slot = (Inventory::CalcSlotId(move_slots->from_slot) == INVALID_INDEX) ? move_slots->from_slot : Inventory::CalcSlotId(move_slots->from_slot);
|
||||
if (IsValidSlot(resync_slot) && resync_slot != INVALID_INDEX) {
|
||||
// This prevents the client from crashing when closing any 'phantom' bags -U
|
||||
// This prevents the client from crashing when closing any 'phantom' bags
|
||||
const Item_Struct* token_struct = database.GetItem(22292); // 'Copper Coin'
|
||||
ItemInst* token_inst = database.CreateItem(token_struct, 1);
|
||||
|
||||
@@ -1944,9 +2020,9 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) {
|
||||
void Client::DyeArmor(DyeStruct* dye){
|
||||
int16 slot=0;
|
||||
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_TINT_END; i++) {
|
||||
if (m_pp.item_tint[i].rgb.blue != dye->dye[i].rgb.blue ||
|
||||
m_pp.item_tint[i].rgb.red != dye->dye[i].rgb.red ||
|
||||
m_pp.item_tint[i].rgb.green != dye->dye[i].rgb.green
|
||||
if (m_pp.item_tint[i].RGB.Blue != dye->dye[i].RGB.Blue ||
|
||||
m_pp.item_tint[i].RGB.Red != dye->dye[i].RGB.Red ||
|
||||
m_pp.item_tint[i].RGB.Green != dye->dye[i].RGB.Green
|
||||
) {
|
||||
slot = m_inv.HasItem(32557, 1, invWherePersonal);
|
||||
if (slot != INVALID_INDEX){
|
||||
@@ -1954,18 +2030,18 @@ void Client::DyeArmor(DyeStruct* dye){
|
||||
uint8 slot2=SlotConvert(i);
|
||||
ItemInst* inst = this->m_inv.GetItem(slot2);
|
||||
if(inst){
|
||||
uint32 armor_color = ((uint32)dye->dye[i].rgb.red << 16) | ((uint32)dye->dye[i].rgb.green << 8) | ((uint32)dye->dye[i].rgb.blue);
|
||||
uint32 armor_color = ((uint32)dye->dye[i].RGB.Red << 16) | ((uint32)dye->dye[i].RGB.Green << 8) | ((uint32)dye->dye[i].RGB.Blue);
|
||||
inst->SetColor(armor_color);
|
||||
database.SaveCharacterMaterialColor(this->CharacterID(), i, armor_color);
|
||||
database.SaveInventory(CharacterID(),inst,slot2);
|
||||
if(dye->dye[i].rgb.use_tint)
|
||||
m_pp.item_tint[i].rgb.use_tint = 0xFF;
|
||||
if(dye->dye[i].RGB.UseTint)
|
||||
m_pp.item_tint[i].RGB.UseTint = 0xFF;
|
||||
else
|
||||
m_pp.item_tint[i].rgb.use_tint=0x00;
|
||||
m_pp.item_tint[i].RGB.UseTint=0x00;
|
||||
}
|
||||
m_pp.item_tint[i].rgb.blue=dye->dye[i].rgb.blue;
|
||||
m_pp.item_tint[i].rgb.red=dye->dye[i].rgb.red;
|
||||
m_pp.item_tint[i].rgb.green=dye->dye[i].rgb.green;
|
||||
m_pp.item_tint[i].RGB.Blue=dye->dye[i].RGB.Blue;
|
||||
m_pp.item_tint[i].RGB.Red=dye->dye[i].RGB.Red;
|
||||
m_pp.item_tint[i].RGB.Green=dye->dye[i].RGB.Green;
|
||||
SendWearChange(i);
|
||||
}
|
||||
else{
|
||||
@@ -2170,7 +2246,7 @@ void Client::RemoveNoRent(bool client_update)
|
||||
}
|
||||
local.clear();
|
||||
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
database.SaveCursor(this->CharacterID(), s, e);
|
||||
}
|
||||
}
|
||||
@@ -2257,7 +2333,7 @@ void Client::RemoveDuplicateLore(bool client_update)
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
// Shared Bank and Shared Bank Containers are not checked due to their allowing duplicate lore items -U
|
||||
// Shared Bank and Shared Bank Containers are not checked due to their allowing duplicate lore items
|
||||
|
||||
if (!m_inv.CursorEmpty()) {
|
||||
std::list<ItemInst*> local_1;
|
||||
@@ -2298,7 +2374,7 @@ void Client::RemoveDuplicateLore(bool client_update)
|
||||
}
|
||||
local_2.clear();
|
||||
|
||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||
database.SaveCursor(this->CharacterID(), s, e);
|
||||
}
|
||||
}
|
||||
@@ -2327,7 +2403,7 @@ void Client::MoveSlotNotAllowed(bool client_update)
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
// No need to check inventory, cursor, bank or shared bank since they allow max item size and containers -U
|
||||
// No need to check inventory, cursor, bank or shared bank since they allow max item size and containers
|
||||
// Code can be added to check item size vs. container size, but it is left to attrition for now.
|
||||
}
|
||||
|
||||
@@ -2380,7 +2456,7 @@ uint32 Client::GetEquipmentColor(uint8 material_slot) const
|
||||
|
||||
const Item_Struct *item = database.GetItem(GetEquipment(material_slot));
|
||||
if(item != nullptr)
|
||||
return ((m_pp.item_tint[material_slot].rgb.use_tint) ? m_pp.item_tint[material_slot].color : item->Color);
|
||||
return ((m_pp.item_tint[material_slot].RGB.UseTint) ? m_pp.item_tint[material_slot].Color : item->Color);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2436,97 +2512,99 @@ EQApplicationPacket* Client::ReturnItemPacket(int16 slot_id, const ItemInst* ins
|
||||
return outapp;
|
||||
}
|
||||
|
||||
static int16 BandolierSlotToWeaponSlot(int BandolierSlot) {
|
||||
|
||||
switch(BandolierSlot) {
|
||||
case bandolierMainHand:
|
||||
return MainPrimary;
|
||||
case bandolierOffHand:
|
||||
return MainSecondary;
|
||||
case bandolierRange:
|
||||
return MainRange;
|
||||
default:
|
||||
return MainAmmo;
|
||||
static int16 BandolierSlotToWeaponSlot(int BandolierSlot)
|
||||
{
|
||||
switch (BandolierSlot)
|
||||
{
|
||||
case bandolierPrimary:
|
||||
return MainPrimary;
|
||||
case bandolierSecondary:
|
||||
return MainSecondary;
|
||||
case bandolierRange:
|
||||
return MainRange;
|
||||
default:
|
||||
return MainAmmo;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::CreateBandolier(const EQApplicationPacket *app) {
|
||||
|
||||
void Client::CreateBandolier(const EQApplicationPacket *app)
|
||||
{
|
||||
// Store bandolier set with the number and name passed by the client, along with the items that are currently
|
||||
// in the players weapon slots.
|
||||
|
||||
BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->number, bs->name);
|
||||
strcpy(m_pp.bandoliers[bs->number].name, bs->name);
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->Number, bs->Name);
|
||||
strcpy(m_pp.bandoliers[bs->Number].Name, bs->Name);
|
||||
|
||||
const ItemInst* InvItem = nullptr;
|
||||
const Item_Struct *BaseItem = nullptr;
|
||||
int16 WeaponSlot;
|
||||
int16 WeaponSlot = 0;
|
||||
|
||||
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||
for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||
WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot);
|
||||
InvItem = GetInv()[WeaponSlot];
|
||||
if(InvItem) {
|
||||
BaseItem = InvItem->GetItem();
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s adding item %s to slot %i", GetName(),BaseItem->Name, WeaponSlot);
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].item_id = BaseItem->ID;
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].icon = BaseItem->Icon;
|
||||
database.SaveCharacterBandolier(this->CharacterID(), bs->number, BandolierSlot, m_pp.bandoliers[bs->number].items[BandolierSlot].item_id, m_pp.bandoliers[bs->number].items[BandolierSlot].icon, bs->name);
|
||||
m_pp.bandoliers[bs->Number].Items[BandolierSlot].ID = BaseItem->ID;
|
||||
m_pp.bandoliers[bs->Number].Items[BandolierSlot].Icon = BaseItem->Icon;
|
||||
database.SaveCharacterBandolier(this->CharacterID(), bs->Number, BandolierSlot, m_pp.bandoliers[bs->Number].Items[BandolierSlot].ID, m_pp.bandoliers[bs->Number].Items[BandolierSlot].Icon, bs->Name);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s no item in slot %i", GetName(), WeaponSlot);
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].item_id = 0;
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].icon = 0;
|
||||
m_pp.bandoliers[bs->Number].Items[BandolierSlot].ID = 0;
|
||||
m_pp.bandoliers[bs->Number].Items[BandolierSlot].Icon = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::RemoveBandolier(const EQApplicationPacket *app) {
|
||||
void Client::RemoveBandolier(const EQApplicationPacket *app)
|
||||
{
|
||||
BandolierDelete_Struct *bds = (BandolierDelete_Struct*)app->pBuffer;
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s removing set", GetName(), bds->number);
|
||||
memset(m_pp.bandoliers[bds->number].name, 0, 32);
|
||||
for(int i = bandolierMainHand; i <= bandolierAmmo; i++) {
|
||||
m_pp.bandoliers[bds->number].items[i].item_id = 0;
|
||||
m_pp.bandoliers[bds->number].items[i].icon = 0;
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s removing set", GetName(), bds->Number);
|
||||
memset(m_pp.bandoliers[bds->Number].Name, 0, 32);
|
||||
for(int i = bandolierPrimary; i <= bandolierAmmo; i++) {
|
||||
m_pp.bandoliers[bds->Number].Items[i].ID = 0;
|
||||
m_pp.bandoliers[bds->Number].Items[i].Icon = 0;
|
||||
}
|
||||
database.DeleteCharacterBandolier(this->CharacterID(), bds->number);
|
||||
database.DeleteCharacterBandolier(this->CharacterID(), bds->Number);
|
||||
}
|
||||
|
||||
void Client::SetBandolier(const EQApplicationPacket *app) {
|
||||
|
||||
void Client::SetBandolier(const EQApplicationPacket *app)
|
||||
{
|
||||
// Swap the weapons in the given bandolier set into the character's weapon slots and return
|
||||
// any items currently in the weapon slots to inventory.
|
||||
|
||||
BandolierSet_Struct *bss = (BandolierSet_Struct*)app->pBuffer;
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s activating set %i", GetName(), bss->number);
|
||||
int16 slot;
|
||||
int16 WeaponSlot;
|
||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s activating set %i", GetName(), bss->Number);
|
||||
int16 slot = 0;
|
||||
int16 WeaponSlot = 0;
|
||||
ItemInst *BandolierItems[4]; // Temporary holding area for the weapons we pull out of their inventory
|
||||
|
||||
// First we pull the items for this bandolier set out of their inventory, this makes space to put the
|
||||
// currently equipped items back.
|
||||
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||
for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||
// If this bandolier set has an item in this position
|
||||
if(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id) {
|
||||
if(m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID) {
|
||||
WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot);
|
||||
|
||||
// Check if the player has the item specified in the bandolier set on them.
|
||||
//
|
||||
slot = m_inv.HasItem(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id, 1,
|
||||
slot = m_inv.HasItem(m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID, 1,
|
||||
invWhereWorn|invWherePersonal);
|
||||
|
||||
// removed 'invWhereCursor' argument from above and implemented slots 30, 331-340 checks here
|
||||
if (slot == INVALID_INDEX) {
|
||||
if (m_inv.GetItem(MainCursor)) {
|
||||
if (m_inv.GetItem(MainCursor)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id &&
|
||||
if (m_inv.GetItem(MainCursor)->GetItem()->ID == m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID &&
|
||||
m_inv.GetItem(MainCursor)->GetCharges() >= 1) { // '> 0' the same, but this matches Inventory::_HasItem conditional check
|
||||
slot = MainCursor;
|
||||
}
|
||||
else if (m_inv.GetItem(MainCursor)->GetItem()->ItemClass == 1) {
|
||||
for(int16 CursorBagSlot = EmuConstants::CURSOR_BAG_BEGIN; CursorBagSlot <= EmuConstants::CURSOR_BAG_END; CursorBagSlot++) {
|
||||
if (m_inv.GetItem(CursorBagSlot)) {
|
||||
if (m_inv.GetItem(CursorBagSlot)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id &&
|
||||
if (m_inv.GetItem(CursorBagSlot)->GetItem()->ID == m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID &&
|
||||
m_inv.GetItem(CursorBagSlot)->GetCharges() >= 1) { // ditto
|
||||
slot = CursorBagSlot;
|
||||
break;
|
||||
@@ -2590,14 +2668,14 @@ void Client::SetBandolier(const EQApplicationPacket *app) {
|
||||
// Now we move the required weapons into the character weapon slots, and return any items we are replacing
|
||||
// back to inventory.
|
||||
//
|
||||
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||
for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||
|
||||
// Find the inventory slot corresponding to this bandolier slot
|
||||
|
||||
WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot);
|
||||
|
||||
// if there is an item in this Bandolier slot ?
|
||||
if(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id) {
|
||||
if(m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID) {
|
||||
// if the player has this item in their inventory, and it is not already where it needs to be
|
||||
if(BandolierItems[BandolierSlot]) {
|
||||
// Pull the item that we are going to replace
|
||||
@@ -2826,9 +2904,9 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool
|
||||
}
|
||||
|
||||
int limbo = 0;
|
||||
for (auto cursor_itr = m_inv.cursor_begin(); cursor_itr != m_inv.cursor_end(); ++cursor_itr, ++limbo) {
|
||||
for (auto cursor_itr = m_inv.cursor_cbegin(); cursor_itr != m_inv.cursor_cend(); ++cursor_itr, ++limbo) {
|
||||
// m_inv.cursor_begin() is referenced as MainCursor in MapPossessions above
|
||||
if (cursor_itr == m_inv.cursor_begin())
|
||||
if (cursor_itr == m_inv.cursor_cbegin())
|
||||
continue;
|
||||
|
||||
instmap[8000 + limbo] = *cursor_itr;
|
||||
|
||||
+104
-94
@@ -19,6 +19,7 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/loottable.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/data_verification.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
@@ -35,7 +36,7 @@
|
||||
|
||||
// Queries the loottable: adds item & coin to the npc
|
||||
void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) {
|
||||
const LootTable_Struct* lts = 0;
|
||||
const LootTable_Struct* lts = nullptr;
|
||||
*copper = 0;
|
||||
*silver = 0;
|
||||
*gold = 0;
|
||||
@@ -45,44 +46,39 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
|
||||
if (!lts)
|
||||
return;
|
||||
|
||||
// do coin
|
||||
if (lts->mincash > lts->maxcash) {
|
||||
std::cerr << "Error in loottable #" << loottable_id << ": mincash > maxcash" << std::endl;
|
||||
uint32 min_cash = lts->mincash;
|
||||
uint32 max_cash = lts->maxcash;
|
||||
if(min_cash > max_cash) {
|
||||
uint32 t = min_cash;
|
||||
min_cash = max_cash;
|
||||
max_cash = t;
|
||||
}
|
||||
else if (lts->maxcash != 0) {
|
||||
uint32 cash = 0;
|
||||
if (lts->mincash == lts->maxcash)
|
||||
cash = lts->mincash;
|
||||
else
|
||||
cash = zone->random.Int(lts->mincash, lts->maxcash);
|
||||
if (cash != 0) {
|
||||
if (lts->avgcoin != 0) {
|
||||
//this is some crazy ass stuff... and makes very little sense... dont use it, k?
|
||||
uint32 mincoin = (uint32) (lts->avgcoin * 0.75 + 1);
|
||||
uint32 maxcoin = (uint32) (lts->avgcoin * 1.25 + 1);
|
||||
*copper = zone->random.Int(mincoin, maxcoin);
|
||||
*silver = zone->random.Int(mincoin, maxcoin);
|
||||
*gold = zone->random.Int(mincoin, maxcoin);
|
||||
if(*copper > cash) { *copper = cash; }
|
||||
cash -= *copper;
|
||||
if(*silver>(cash/10)) { *silver = (cash/10); }
|
||||
cash -= *silver*10;
|
||||
if(*gold > (cash/100)) { *gold = (cash/100); }
|
||||
cash -= *gold*100;
|
||||
}
|
||||
if (cash < 0) {
|
||||
cash = 0;
|
||||
}
|
||||
*plat = cash / 1000;
|
||||
cash -= *plat * 1000;
|
||||
uint32 gold2 = cash / 100;
|
||||
cash -= gold2 * 100;
|
||||
uint32 silver2 = cash / 10;
|
||||
cash -= silver2 * 10;
|
||||
*gold += gold2;
|
||||
*silver += silver2;
|
||||
*copper += cash;
|
||||
|
||||
uint32 cash = 0;
|
||||
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 {
|
||||
cash = zone->random.Int(min_cash, lts->avgcoin);
|
||||
}
|
||||
} else {
|
||||
cash = zone->random.Int(min_cash, max_cash);
|
||||
}
|
||||
|
||||
if(cash != 0) {
|
||||
*plat = cash / 1000;
|
||||
cash -= *plat * 1000;
|
||||
|
||||
*gold = cash / 100;
|
||||
cash -= *gold * 100;
|
||||
|
||||
*silver = cash / 10;
|
||||
cash -= *silver * 10;
|
||||
|
||||
*copper = cash;
|
||||
}
|
||||
|
||||
// Do items
|
||||
@@ -97,11 +93,11 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
|
||||
|
||||
float drop_chance = 0.0f;
|
||||
if(ltchance > 0.0 && ltchance < 100.0) {
|
||||
drop_chance = zone->random.Real(0.0, 100.0);
|
||||
drop_chance = (float)zone->random.Real(0.0, 100.0);
|
||||
}
|
||||
|
||||
if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance < ltchance)) {
|
||||
AddLootDropToNPC(npc,lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop);
|
||||
if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance <= ltchance)) {
|
||||
AddLootDropToNPC(npc, lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,68 +110,81 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml
|
||||
if (!lds) {
|
||||
return;
|
||||
}
|
||||
if(lds->NumEntries == 0) //nothing possible to add
|
||||
|
||||
if(lds->NumEntries == 0)
|
||||
return;
|
||||
|
||||
// Too long a list needs to be limited.
|
||||
if(lds->NumEntries > 99 && droplimit < 1)
|
||||
droplimit = lds->NumEntries/100;
|
||||
|
||||
uint8 limit = 0;
|
||||
// Start at a random point in itemlist.
|
||||
uint32 item = zone->random.Int(0, lds->NumEntries-1);
|
||||
// Main loop.
|
||||
for (uint32 i=0; i<lds->NumEntries;)
|
||||
{
|
||||
//Force the itemlist back to beginning.
|
||||
if (item > (lds->NumEntries-1))
|
||||
item = 0;
|
||||
|
||||
uint8 charges = lds->Entries[item].multiplier;
|
||||
uint8 pickedcharges = 0;
|
||||
// Loop to check multipliers.
|
||||
for (uint32 x=1; x<=charges; x++)
|
||||
{
|
||||
// Actual roll.
|
||||
float thischance = 0.0;
|
||||
thischance = lds->Entries[item].chance;
|
||||
|
||||
float drop_chance = 0.0;
|
||||
if(thischance != 100.0)
|
||||
drop_chance = zone->random.Real(0.0, 100.0);
|
||||
|
||||
#if EQDEBUG>=11
|
||||
Log.Out(Logs::General, Logs::None, "Drop chance for npc: %s, this chance:%f, drop roll:%f", npc->GetName(), thischance, drop_chance);
|
||||
#endif
|
||||
if (thischance == 100.0 || drop_chance < thischance)
|
||||
{
|
||||
uint32 itemid = lds->Entries[item].item_id;
|
||||
|
||||
const Item_Struct* dbitem = GetItem(itemid);
|
||||
npc->AddLootDrop(dbitem, itemlist, lds->Entries[item].item_charges, lds->Entries[item].minlevel, lds->Entries[item].maxlevel, lds->Entries[item].equip_item, false);
|
||||
pickedcharges++;
|
||||
if(droplimit == 0 && mindrop == 0) {
|
||||
for(uint32 i = 0; i < lds->NumEntries; ++i) {
|
||||
int charges = lds->Entries[i].multiplier;
|
||||
for(int j = 0; j < charges; ++j) {
|
||||
if(zone->random.Real(0.0, 100.0) <= lds->Entries[i].chance) {
|
||||
const Item_Struct* dbitem = GetItem(lds->Entries[i].item_id);
|
||||
npc->AddLootDrop(dbitem, itemlist, lds->Entries[i].item_charges, lds->Entries[i].minlevel,
|
||||
lds->Entries[i].maxlevel, lds->Entries[i].equip_item > 0 ? true : false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Items with multipliers only count as 1 towards the limit.
|
||||
if(pickedcharges > 0)
|
||||
limit++;
|
||||
return;
|
||||
}
|
||||
|
||||
// If true, limit reached.
|
||||
if(limit >= droplimit && droplimit > 0)
|
||||
break;
|
||||
if(lds->NumEntries > 100 && droplimit == 0) {
|
||||
droplimit = 10;
|
||||
}
|
||||
|
||||
item++;
|
||||
i++;
|
||||
if(droplimit < mindrop) {
|
||||
droplimit = mindrop;
|
||||
}
|
||||
|
||||
// We didn't reach our minimium, run loop again.
|
||||
if(i == lds->NumEntries){
|
||||
if(limit < mindrop){
|
||||
i = 0;
|
||||
float roll_t = 0.0f;
|
||||
bool active_item_list = false;
|
||||
for(uint32 i = 0; i < lds->NumEntries; ++i) {
|
||||
const Item_Struct* db_item = GetItem(lds->Entries[i].item_id);
|
||||
if(db_item) {
|
||||
roll_t += lds->Entries[i].chance;
|
||||
active_item_list = true;
|
||||
}
|
||||
}
|
||||
|
||||
roll_t = EQEmu::ClampLower(roll_t, 100.0f);
|
||||
|
||||
if(!active_item_list) {
|
||||
return;
|
||||
}
|
||||
|
||||
mindrop = EQEmu::ClampLower(mindrop, (uint8)1);
|
||||
int item_count = zone->random.Int(mindrop, droplimit);
|
||||
for(int i = 0; i < item_count; ++i) {
|
||||
float roll = (float)zone->random.Real(0.0, roll_t);
|
||||
for(uint32 j = 0; j < lds->NumEntries; ++j) {
|
||||
const Item_Struct* db_item = GetItem(lds->Entries[j].item_id);
|
||||
if(db_item) {
|
||||
if(roll < lds->Entries[j].chance) {
|
||||
npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel,
|
||||
lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false);
|
||||
|
||||
int charges = (int)lds->Entries[i].multiplier;
|
||||
charges = EQEmu::ClampLower(charges, 1);
|
||||
|
||||
for(int k = 1; k < charges; ++k) {
|
||||
float c_roll = (float)zone->random.Real(0.0, 100.0);
|
||||
if(c_roll <= lds->Entries[i].chance) {
|
||||
npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel,
|
||||
lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false);
|
||||
}
|
||||
}
|
||||
|
||||
j = lds->NumEntries;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
roll -= lds->Entries[j].chance;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // We either ran out of items or reached our limit.
|
||||
|
||||
npc->UpdateEquipLightValue();
|
||||
npc->UpdateEquipmentLight();
|
||||
// no wearchange associated with this function..so, this should not be needed
|
||||
//if (npc->UpdateActiveLightValue())
|
||||
// npc->SendAppearancePacket(AT_Light, npc->GetActiveLightValue());
|
||||
@@ -215,6 +224,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
|
||||
item->attuned = 0;
|
||||
item->min_level = minlevel;
|
||||
item->max_level = maxlevel;
|
||||
|
||||
if (equipit) {
|
||||
uint8 eslot = 0xFF;
|
||||
char newid[20];
|
||||
@@ -365,9 +375,9 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
UpdateEquipLightValue();
|
||||
if (UpdateActiveLightValue())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
}
|
||||
|
||||
void NPC::AddItem(const Item_Struct* item, uint16 charges, bool equipitem) {
|
||||
|
||||
+29
-15
@@ -449,11 +449,11 @@ void Merc::AddItemBonuses(const Item_Struct *item, StatBonuses* newbon) {
|
||||
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, true);
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
}
|
||||
|
||||
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true);
|
||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0);
|
||||
}
|
||||
|
||||
switch(item->BardType)
|
||||
@@ -1201,8 +1201,8 @@ void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
||||
ns->spawn.NPC = 1; // 0=player,1=npc,2=pc corpse,3=npc corpse
|
||||
ns->spawn.IsMercenary = 1;
|
||||
|
||||
UpdateActiveLightValue();
|
||||
ns->spawn.light = active_light;
|
||||
UpdateActiveLight();
|
||||
ns->spawn.light = m_Light.Type.Active;
|
||||
|
||||
/*
|
||||
// Wear Slots are not setup for Mercs yet
|
||||
@@ -5028,34 +5028,48 @@ void Merc::UpdateMercAppearance() {
|
||||
}
|
||||
}
|
||||
|
||||
if (UpdateActiveLightValue())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
||||
if (UpdateActiveLight())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
}
|
||||
|
||||
void Merc::UpdateEquipLightValue()
|
||||
void Merc::UpdateEquipmentLight()
|
||||
{
|
||||
equip_light = NOT_USED;
|
||||
m_Light.Type.Equipment = 0;
|
||||
m_Light.Level.Equipment = 0;
|
||||
|
||||
for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) {
|
||||
if (equipment[index] == NOT_USED) { continue; }
|
||||
if (index == MainAmmo) { continue; }
|
||||
|
||||
auto item = database.GetItem(equipment[index]);
|
||||
if (item == nullptr) { continue; }
|
||||
if (item->Light & 0xF0) { continue; }
|
||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
||||
|
||||
if (m_Light.IsLevelGreater(item->Light, m_Light.Type.Equipment)) {
|
||||
m_Light.Type.Equipment = item->Light;
|
||||
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 general_light_type = 0;
|
||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||
auto item = database.GetItem((*iter)->item_id);
|
||||
if (item == nullptr) { continue; }
|
||||
if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight) { continue; }
|
||||
if (item->Light & 0xF0) { continue; }
|
||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
||||
|
||||
if (item->ItemClass != ItemClassCommon) { continue; }
|
||||
if (item->Light < 9 || item->Light > 13) { continue; }
|
||||
|
||||
if (m_Light.TypeToLevel(item->Light))
|
||||
general_light_type = item->Light;
|
||||
}
|
||||
|
||||
if (m_Light.IsLevelGreater(general_light_type, m_Light.Type.Equipment))
|
||||
m_Light.Type.Equipment = general_light_type;
|
||||
|
||||
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||
}
|
||||
|
||||
void Merc::AddItem(uint8 slot, uint32 item_id) {
|
||||
equipment[slot] = item_id;
|
||||
UpdateEquipLightValue();
|
||||
UpdateEquipmentLight();
|
||||
}
|
||||
|
||||
bool Merc::Spawn(Client *owner) {
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ public:
|
||||
void UpdateMercInfo(Client *c);
|
||||
void UpdateMercStats(Client *c, bool setmax = false);
|
||||
void UpdateMercAppearance();
|
||||
virtual void UpdateEquipLightValue();
|
||||
virtual void UpdateEquipmentLight();
|
||||
void AddItem(uint8 slot, uint32 item_id);
|
||||
static const char *GetRandomName();
|
||||
bool Spawn(Client *owner);
|
||||
|
||||
+66
-58
@@ -149,9 +149,13 @@ Mob::Mob(const char* in_name,
|
||||
if (runspeed < 0 || runspeed > 20)
|
||||
runspeed = 1.25f;
|
||||
|
||||
active_light = innate_light = in_light;
|
||||
spell_light = equip_light = NOT_USED;
|
||||
|
||||
m_Light.Type.Innate = in_light;
|
||||
m_Light.Level.Innate = m_Light.TypeToLevel(m_Light.Type.Innate);
|
||||
m_Light.Level.Equipment = m_Light.Type.Equipment = 0;
|
||||
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;
|
||||
haircolor = in_haircolor;
|
||||
@@ -170,6 +174,7 @@ Mob::Mob(const char* in_name,
|
||||
findable = false;
|
||||
trackable = true;
|
||||
has_shieldequiped = false;
|
||||
has_twohandbluntequiped = false;
|
||||
has_numhits = false;
|
||||
has_MGB = false;
|
||||
has_ProjectIllusion = false;
|
||||
@@ -300,6 +305,7 @@ Mob::Mob(const char* in_name,
|
||||
focused = false;
|
||||
_IsTempPet = false;
|
||||
pet_owner_client = false;
|
||||
pet_targetlock_id = 0;
|
||||
|
||||
attacked_count = 0;
|
||||
mezzed = false;
|
||||
@@ -901,8 +907,8 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.animation = 0;
|
||||
ns->spawn.findable = findable?1:0;
|
||||
|
||||
UpdateActiveLightValue();
|
||||
ns->spawn.light = active_light;
|
||||
UpdateActiveLight();
|
||||
ns->spawn.light = m_Light.Type.Active;
|
||||
|
||||
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
|
||||
|
||||
@@ -959,10 +965,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
// Only Player Races Wear Armor
|
||||
if (Mob::IsPlayerRace(race) || i > 6)
|
||||
{
|
||||
ns->spawn.equipment[i].material = GetEquipmentMaterial(i);
|
||||
ns->spawn.equipment[i].elitematerial = IsEliteMaterialItem(i);
|
||||
ns->spawn.equipment[i].heroforgemodel = GetHerosForgeModel(i);
|
||||
ns->spawn.colors[i].color = GetEquipmentColor(i);
|
||||
ns->spawn.equipment[i].Material = GetEquipmentMaterial(i);
|
||||
ns->spawn.equipment[i].EliteMaterial = IsEliteMaterialItem(i);
|
||||
ns->spawn.equipment[i].HeroForgeModel = GetHerosForgeModel(i);
|
||||
ns->spawn.colors[i].Color = GetEquipmentColor(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1999,9 +2005,10 @@ void Mob::TempName(const char *newname)
|
||||
strn0cpy(temp_name, GetCleanName(), 64);
|
||||
}
|
||||
|
||||
// Remove Numbers before making name unique
|
||||
EntityList::RemoveNumbers(temp_name);
|
||||
// Make the new name unique and set it
|
||||
strn0cpy(temp_name, entity_list.MakeNameUnique(temp_name), 64);
|
||||
|
||||
entity_list.MakeNameUnique(temp_name);
|
||||
|
||||
// Send the new name to all clients
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_MobRename, sizeof(MobRename_Struct));
|
||||
@@ -2047,37 +2054,20 @@ void Mob::SetAppearance(EmuAppearance app, bool iIgnoreSelf) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::UpdateActiveLightValue()
|
||||
bool Mob::UpdateActiveLight()
|
||||
{
|
||||
/* This is old information...
|
||||
0 - "None"
|
||||
1 - "Candle"
|
||||
2 - "Torch"
|
||||
3 - "Tiny Glowing Skull"
|
||||
4 - "Small Lantern"
|
||||
5 - "Stein of Moggok"
|
||||
6 - "Large Lantern"
|
||||
7 - "Flameless Lantern"
|
||||
8 - "Globe of Stars"
|
||||
9 - "Light Globe"
|
||||
10 - "Lightstone"
|
||||
11 - "Greater Lightstone"
|
||||
12 - "Fire Beatle Eye"
|
||||
13 - "Coldlight"
|
||||
14 - "Unknown"
|
||||
15 - "Unknown"
|
||||
*/
|
||||
|
||||
uint8 old_light = (active_light & 0x0F);
|
||||
active_light = (innate_light & 0x0F);
|
||||
uint8 old_light_level = m_Light.Level.Active;
|
||||
|
||||
if (equip_light > active_light) { active_light = equip_light; } // limiter in property handler
|
||||
if (spell_light > active_light) { active_light = spell_light; } // limiter in property handler
|
||||
m_Light.Type.Active = 0;
|
||||
m_Light.Level.Active = 0;
|
||||
|
||||
if (active_light != old_light)
|
||||
return true;
|
||||
if (m_Light.IsLevelGreater((m_Light.Type.Innate & 0x0F), m_Light.Type.Active)) { m_Light.Type.Active = m_Light.Type.Innate; }
|
||||
if (m_Light.Level.Equipment > m_Light.Level.Active) { m_Light.Type.Active = m_Light.Type.Equipment; } // limiter in property handler
|
||||
if (m_Light.Level.Spell > m_Light.Level.Active) { m_Light.Type.Active = m_Light.Type.Spell; } // limiter in property handler
|
||||
|
||||
return false;
|
||||
m_Light.Level.Active = m_Light.TypeToLevel(m_Light.Type.Active);
|
||||
|
||||
return (m_Light.Level.Active != old_light_level);
|
||||
}
|
||||
|
||||
void Mob::ChangeSize(float in_size = 0, bool bNoRestriction) {
|
||||
@@ -2577,7 +2567,7 @@ void Mob::SendWearChange(uint8 material_slot)
|
||||
wc->material = GetEquipmentMaterial(material_slot);
|
||||
wc->elite_material = IsEliteMaterialItem(material_slot);
|
||||
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
||||
wc->color.color = GetEquipmentColor(material_slot);
|
||||
wc->color.Color = GetEquipmentColor(material_slot);
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
@@ -2592,9 +2582,9 @@ void Mob::SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model, uin
|
||||
wc->spawn_id = this->GetID();
|
||||
wc->material = texture;
|
||||
if (this->IsClient())
|
||||
wc->color.color = GetEquipmentColor(slot);
|
||||
wc->color.Color = GetEquipmentColor(slot);
|
||||
else
|
||||
wc->color.color = this->GetArmorTint(slot);
|
||||
wc->color.Color = this->GetArmorTint(slot);
|
||||
wc->wear_slot_id = slot;
|
||||
|
||||
wc->unknown06 = unknown06;
|
||||
@@ -2622,7 +2612,7 @@ void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uin
|
||||
wc->spawn_id = this->GetID();
|
||||
wc->material = GetEquipmentMaterial(material_slot);
|
||||
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
||||
wc->color.color = color;
|
||||
wc->color.Color = color;
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
@@ -2639,7 +2629,7 @@ void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 h
|
||||
wc->spawn_id = this->GetID();
|
||||
wc->material = texture;
|
||||
wc->hero_forge_model = hero_forge_model;
|
||||
wc->color.color = color;
|
||||
wc->color.Color = color;
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
@@ -3578,17 +3568,14 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)
|
||||
{
|
||||
int skilldmg_mod = 0;
|
||||
|
||||
int16 MeleeVuln = spellbonuses.MeleeVulnerability + itembonuses.MeleeVulnerability + aabonuses.MeleeVulnerability;
|
||||
|
||||
// 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];
|
||||
|
||||
|
||||
//Innate SetSkillDamgeTaken(skill,value)
|
||||
if ((SkillDmgTaken_Mod[skill_used]) || (SkillDmgTaken_Mod[HIGHEST_SKILL+1]))
|
||||
skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1];
|
||||
skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1];
|
||||
|
||||
skilldmg_mod += MeleeVuln;
|
||||
skilldmg_mod += spellbonuses.MeleeVulnerability + itembonuses.MeleeVulnerability + aabonuses.MeleeVulnerability;
|
||||
|
||||
if(skilldmg_mod < -100)
|
||||
skilldmg_mod = -100;
|
||||
@@ -4671,22 +4658,21 @@ void Mob::SetBodyType(bodyType new_body, bool overwrite_orig) {
|
||||
|
||||
void Mob::ModSkillDmgTaken(SkillUseTypes skill_num, int value)
|
||||
{
|
||||
if (skill_num <= HIGHEST_SKILL)
|
||||
SkillDmgTaken_Mod[skill_num] = value;
|
||||
|
||||
|
||||
else if (skill_num == 255 || skill_num == -1)
|
||||
if (skill_num == ALL_SKILLS)
|
||||
SkillDmgTaken_Mod[HIGHEST_SKILL+1] = value;
|
||||
|
||||
else if (skill_num >= 0 && skill_num <= HIGHEST_SKILL)
|
||||
SkillDmgTaken_Mod[skill_num] = value;
|
||||
}
|
||||
|
||||
int16 Mob::GetModSkillDmgTaken(const SkillUseTypes skill_num)
|
||||
{
|
||||
if (skill_num <= HIGHEST_SKILL)
|
||||
return SkillDmgTaken_Mod[skill_num];
|
||||
|
||||
else if (skill_num == 255 || skill_num == -1)
|
||||
if (skill_num == ALL_SKILLS)
|
||||
return SkillDmgTaken_Mod[HIGHEST_SKILL+1];
|
||||
|
||||
else if (skill_num >= 0 && skill_num <= HIGHEST_SKILL)
|
||||
return SkillDmgTaken_Mod[skill_num];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5380,3 +5366,25 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool Mob::CanClassEquipItem(uint32 item_id)
|
||||
{
|
||||
const Item_Struct* itm = nullptr;
|
||||
itm = database.GetItem(item_id);
|
||||
|
||||
if (!itm)
|
||||
return false;
|
||||
|
||||
if(itm->Classes == 65535 )
|
||||
return true;
|
||||
|
||||
if (GetClass() > 16)
|
||||
return false;
|
||||
|
||||
int bitmask = 1;
|
||||
bitmask = bitmask << (GetClass() - 1);
|
||||
|
||||
if(!(itm->Classes & bitmask))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
+22
-14
@@ -194,7 +194,7 @@ public:
|
||||
bool IsBeneficialAllowed(Mob *target);
|
||||
virtual int GetCasterLevel(uint16 spell_id);
|
||||
void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0,
|
||||
bool item_bonus = false, uint32 ticsremaining = 0, int buffslot = -1,
|
||||
uint8 WornType = 0, uint32 ticsremaining = 0, int buffslot = -1,
|
||||
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);
|
||||
@@ -308,13 +308,16 @@ public:
|
||||
void SetTargetable(bool on);
|
||||
bool IsTargetable() const { return m_targetable; }
|
||||
bool HasShieldEquiped() const { return has_shieldequiped; }
|
||||
inline void ShieldEquiped(bool val) { has_shieldequiped = val; }
|
||||
inline void SetShieldEquiped(bool val) { has_shieldequiped = val; }
|
||||
bool HasTwoHandBluntEquiped() const { return has_twohandbluntequiped; }
|
||||
inline void SetTwoHandBluntEquiped(bool val) { has_twohandbluntequiped = val; }
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_num) const { return 0; }
|
||||
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
|
||||
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||
virtual int32 GetHerosForgeModel(uint8 material_slot) const;
|
||||
virtual uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
virtual uint32 IsEliteMaterialItem(uint8 material_slot) const;
|
||||
bool CanClassEquipItem(uint32 item_id);
|
||||
bool AffectedBySpellExcludingSlot(int slot, int effect);
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) = 0;
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill,
|
||||
@@ -621,7 +624,7 @@ public:
|
||||
bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true);
|
||||
bool ImprovedTaunt();
|
||||
bool TryRootFadeByDamage(int buffslot, Mob* attacker);
|
||||
int16 GetSlowMitigation() const {return slow_mitigation;}
|
||||
float GetSlowMitigation() const { return slow_mitigation; }
|
||||
void CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster = nullptr);
|
||||
inline int16 GetSpellPowerDistanceMod() const { return SpellPowerDistanceMod; };
|
||||
inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; };
|
||||
@@ -652,14 +655,17 @@ public:
|
||||
bool IsDestructibleObject() { return destructibleobject; }
|
||||
void SetDestructibleObject(bool in) { destructibleobject = in; }
|
||||
|
||||
inline uint8 GetInnateLightValue() { return innate_light; }
|
||||
inline uint8 GetEquipLightValue() { return equip_light; }
|
||||
inline uint8 GetSpellLightValue() { return spell_light; }
|
||||
virtual void UpdateEquipLightValue() { equip_light = NOT_USED; }
|
||||
inline void SetSpellLightValue(uint8 light_value) { spell_light = (light_value & 0x0F); }
|
||||
inline uint8 GetInnateLightType() { return m_Light.Type.Innate; }
|
||||
inline uint8 GetEquipmentLightType() { return m_Light.Type.Equipment; }
|
||||
inline uint8 GetSpellLightType() { return m_Light.Type.Spell; }
|
||||
|
||||
inline uint8 GetActiveLightValue() { return active_light; }
|
||||
bool UpdateActiveLightValue(); // returns true if change, false if no change
|
||||
virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = 0; m_Light.Level.Equipment = 0; }
|
||||
inline void SetSpellLightType(uint8 lightType) { m_Light.Type.Spell = (lightType & 0x0F); m_Light.Level.Spell = m_Light.TypeToLevel(m_Light.Type.Spell); }
|
||||
|
||||
inline uint8 GetActiveLightType() { return m_Light.Type.Active; }
|
||||
bool UpdateActiveLight(); // returns true if change, false if no change
|
||||
|
||||
LightProfile_Struct* GetLightProfile() { return &m_Light; }
|
||||
|
||||
Mob* GetPet();
|
||||
void SetPet(Mob* newpet);
|
||||
@@ -675,6 +681,9 @@ public:
|
||||
bool IsFamiliar() const { return(typeofpet == petFamiliar); }
|
||||
bool IsAnimation() const { return(typeofpet == petAnimation); }
|
||||
bool IsCharmed() const { return(typeofpet == petCharmed); }
|
||||
bool IsTargetLockPet() const { return(typeofpet == petTargetLock); }
|
||||
inline uint32 GetPetTargetLockID() { return pet_targetlock_id; };
|
||||
inline void SetPetTargetLockID(uint32 value) { pet_targetlock_id = value; };
|
||||
void SetOwnerID(uint16 NewOwnerID);
|
||||
inline uint16 GetOwnerID() const { return ownerid; }
|
||||
inline virtual bool HasOwner() { if(GetOwnerID()==0){return false;} return( entity_list.GetMob(GetOwnerID()) != 0); }
|
||||
@@ -1068,10 +1077,7 @@ protected:
|
||||
|
||||
glm::vec4 m_Delta;
|
||||
|
||||
uint8 innate_light; // defined by db field `npc_types`.`light` - where appropriate
|
||||
uint8 equip_light; // highest value of equipped/carried light-producing items
|
||||
uint8 spell_light; // set value of any light-producing spell (can be modded to mimic equip_light behavior)
|
||||
uint8 active_light; // highest value of all light sources
|
||||
LightProfile_Struct m_Light;
|
||||
|
||||
float fixedZ;
|
||||
EmuAppearance _appearance;
|
||||
@@ -1146,6 +1152,7 @@ protected:
|
||||
uint16 viral_spells[MAX_SPELL_TRIGGER*2]; // Stores the spell ids of the viruses on target and caster ids
|
||||
bool offhand;
|
||||
bool has_shieldequiped;
|
||||
bool has_twohandbluntequiped;
|
||||
bool has_numhits;
|
||||
bool has_MGB;
|
||||
bool has_ProjectIllusion;
|
||||
@@ -1244,6 +1251,7 @@ protected:
|
||||
bool _IsTempPet;
|
||||
int16 count_TempPet;
|
||||
bool pet_owner_client; //Flags regular and pets as belonging to a client
|
||||
uint32 pet_targetlock_id;
|
||||
|
||||
EGNode *_egnode; //the EG node we are in
|
||||
glm::vec3 m_TargetLocation;
|
||||
|
||||
+1
-1
@@ -2579,7 +2579,7 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
|
||||
|
||||
for(int i=0; i < AIspellsEffects.size(); i++)
|
||||
{
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, false, 0,-1,
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, 0, 0,-1,
|
||||
true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
|
||||
}
|
||||
|
||||
|
||||
+67
-23
@@ -352,9 +352,6 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
InitializeBuffSlots();
|
||||
CalcBonuses();
|
||||
raid_target = d->raid_target;
|
||||
|
||||
active_light = d->light;
|
||||
spell_light = equip_light = NOT_USED;
|
||||
}
|
||||
|
||||
NPC::~NPC()
|
||||
@@ -439,15 +436,15 @@ void NPC::RemoveItem(uint32 item_id, uint16 quantity, uint16 slot) {
|
||||
ServerLootItem_Struct* item = *cur;
|
||||
if (item->item_id == item_id && slot <= 0 && quantity <= 0) {
|
||||
itemlist.erase(cur);
|
||||
UpdateEquipLightValue();
|
||||
if (UpdateActiveLightValue()) { SendAppearancePacket(AT_Light, GetActiveLightValue()); }
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight()) { SendAppearancePacket(AT_Light, GetActiveLightType()); }
|
||||
return;
|
||||
}
|
||||
else if (item->item_id == item_id && item->equip_slot == slot && quantity >= 1) {
|
||||
if (item->charges <= quantity) {
|
||||
itemlist.erase(cur);
|
||||
UpdateEquipLightValue();
|
||||
if (UpdateActiveLightValue()) { SendAppearancePacket(AT_Light, GetActiveLightValue()); }
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight()) { SendAppearancePacket(AT_Light, GetActiveLightType()); }
|
||||
}
|
||||
else {
|
||||
item->charges -= quantity;
|
||||
@@ -483,9 +480,9 @@ void NPC::CheckMinMaxLevel(Mob *them)
|
||||
++cur;
|
||||
}
|
||||
|
||||
UpdateEquipLightValue();
|
||||
if (UpdateActiveLightValue())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
}
|
||||
|
||||
void NPC::ClearItemList() {
|
||||
@@ -498,9 +495,9 @@ void NPC::ClearItemList() {
|
||||
}
|
||||
itemlist.clear();
|
||||
|
||||
UpdateEquipLightValue();
|
||||
if (UpdateActiveLightValue())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight())
|
||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||
}
|
||||
|
||||
void NPC::QueryLoot(Client* to)
|
||||
@@ -718,25 +715,39 @@ uint32 NPC::CountLoot() {
|
||||
return(itemlist.size());
|
||||
}
|
||||
|
||||
void NPC::UpdateEquipLightValue()
|
||||
void NPC::UpdateEquipmentLight()
|
||||
{
|
||||
equip_light = NOT_USED;
|
||||
m_Light.Type.Equipment = 0;
|
||||
m_Light.Level.Equipment = 0;
|
||||
|
||||
for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) {
|
||||
if (equipment[index] == NOT_USED) { continue; }
|
||||
if (index == MainAmmo) { continue; }
|
||||
|
||||
auto item = database.GetItem(equipment[index]);
|
||||
if (item == nullptr) { continue; }
|
||||
if (item->Light & 0xF0) { continue; }
|
||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
||||
|
||||
if (m_Light.IsLevelGreater(item->Light, m_Light.Type.Equipment)) {
|
||||
m_Light.Type.Equipment = item->Light;
|
||||
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 general_light_type = 0;
|
||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||
auto item = database.GetItem((*iter)->item_id);
|
||||
if (item == nullptr) { continue; }
|
||||
if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight) { continue; }
|
||||
if (item->Light & 0xF0) { continue; }
|
||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
||||
|
||||
if (item->ItemClass != ItemClassCommon) { continue; }
|
||||
if (item->Light < 9 || item->Light > 13) { continue; }
|
||||
|
||||
if (m_Light.TypeToLevel(item->Light))
|
||||
general_light_type = item->Light;
|
||||
}
|
||||
|
||||
if (m_Light.IsLevelGreater(general_light_type, m_Light.Type.Equipment))
|
||||
m_Light.Type.Equipment = general_light_type;
|
||||
|
||||
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||
}
|
||||
|
||||
void NPC::Depop(bool StartSpawnTimer) {
|
||||
@@ -1810,8 +1821,8 @@ void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
Mob::FillSpawnStruct(ns, ForWho);
|
||||
PetOnSpawn(ns);
|
||||
ns->spawn.is_npc = 1;
|
||||
UpdateActiveLightValue();
|
||||
ns->spawn.light = GetActiveLightValue();
|
||||
UpdateActiveLight();
|
||||
ns->spawn.light = GetActiveLightType();
|
||||
}
|
||||
|
||||
void NPC::PetOnSpawn(NewSpawn_Struct* ns)
|
||||
@@ -2394,6 +2405,29 @@ void NPC::DoQuestPause(Mob *other) {
|
||||
|
||||
}
|
||||
|
||||
void NPC::ChangeLastName(const char* in_lastname)
|
||||
{
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct));
|
||||
GMLastName_Struct* gmn = (GMLastName_Struct*)outapp->pBuffer;
|
||||
strcpy(gmn->name, GetName());
|
||||
strcpy(gmn->gmname, GetName());
|
||||
strcpy(gmn->lastname, in_lastname);
|
||||
gmn->unknown[0]=1;
|
||||
gmn->unknown[1]=1;
|
||||
gmn->unknown[2]=1;
|
||||
gmn->unknown[3]=1;
|
||||
entity_list.QueueClients(this, outapp, false);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void NPC::ClearLastName()
|
||||
{
|
||||
std::string WT;
|
||||
WT = '\0'; //Clear Last Name
|
||||
ChangeLastName( WT.c_str());
|
||||
}
|
||||
|
||||
void NPC::DepopSwarmPets()
|
||||
{
|
||||
if (GetSwarmInfo()) {
|
||||
@@ -2419,4 +2453,14 @@ void NPC::DepopSwarmPets()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()){
|
||||
|
||||
Mob *targMob = entity_list.GetMob(GetPetTargetLockID());
|
||||
|
||||
if(!targMob || (targMob && targMob->IsCorpse())){
|
||||
Kill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -187,7 +187,7 @@ public:
|
||||
void QueryLoot(Client* to);
|
||||
uint32 CountLoot();
|
||||
inline uint32 GetLoottableID() const { return loottable_id; }
|
||||
virtual void UpdateEquipLightValue();
|
||||
virtual void UpdateEquipmentLight();
|
||||
|
||||
inline uint32 GetCopper() const { return copper; }
|
||||
inline uint32 GetSilver() const { return silver; }
|
||||
@@ -253,7 +253,7 @@ public:
|
||||
|
||||
uint32 GetMaxDMG() const {return max_dmg;}
|
||||
uint32 GetMinDMG() const {return min_dmg;}
|
||||
int16 GetSlowMitigation() const {return slow_mitigation;}
|
||||
float GetSlowMitigation() const { return slow_mitigation; }
|
||||
float GetAttackSpeed() const {return attack_speed;}
|
||||
uint8 GetAttackDelay() const {return attack_delay;}
|
||||
bool IsAnimal() const { return(bodytype == BT_Animal); }
|
||||
@@ -361,6 +361,9 @@ public:
|
||||
const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; }
|
||||
const char* GetRawNPCTypeName() const { return NPCTypedata->name; }
|
||||
|
||||
void ChangeLastName(const char* in_lastname);
|
||||
void ClearLastName();
|
||||
|
||||
bool GetDepop() { return p_depop; }
|
||||
|
||||
void NPCSlotTexture(uint8 slot, uint16 texture); // Sets new material values for slots
|
||||
|
||||
@@ -342,8 +342,8 @@ XS(XS_Group_GetLeaderName)
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Group::GetLeaderName(THIS)");
|
||||
{
|
||||
Group * THIS;
|
||||
char * RETVAL;
|
||||
Group * THIS;
|
||||
const char * RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Group")) {
|
||||
|
||||
+30
-2
@@ -7783,7 +7783,7 @@ XS(XS_Mob_GetModSkillDmgTaken)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetModSkillDmgTaken(THIS, skill_num)");
|
||||
{
|
||||
Mob * THIS;
|
||||
uint32 RETVAL;
|
||||
int16 RETVAL;
|
||||
dXSTARG;
|
||||
SkillUseTypes skill_num = (SkillUseTypes)SvUV(ST(1));
|
||||
|
||||
@@ -7797,7 +7797,7 @@ XS(XS_Mob_GetModSkillDmgTaken)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetModSkillDmgTaken(skill_num);
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@@ -8367,6 +8367,33 @@ XS(XS_Mob_ProcessSpecialAbilities)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_CanClassEquipItem); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_CanClassEquipItem)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::CanClassEquipItem(THIS, item_id)");
|
||||
{
|
||||
Mob * THIS;
|
||||
bool RETVAL;
|
||||
uint32 item_id = (uint32)SvUV(ST(1));
|
||||
|
||||
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.");
|
||||
|
||||
RETVAL = THIS->CanClassEquipItem(item_id);
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
@@ -8675,6 +8702,7 @@ XS(boot_Mob)
|
||||
newXSproto(strcpy(buf, "SetSpecialAbilityParam"), XS_Mob_SetSpecialAbilityParam, file, "$$$$");
|
||||
newXSproto(strcpy(buf, "ClearSpecialAbilities"), XS_Mob_ClearSpecialAbilities, file, "$");
|
||||
newXSproto(strcpy(buf, "ProcessSpecialAbilities"), XS_Mob_ProcessSpecialAbilities, file, "$$");
|
||||
newXSproto(strcpy(buf, "CanClassEquipItem"), XS_Mob_CanClassEquipItem, file, "$$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
+167
-4
@@ -795,6 +795,42 @@ XS(XS_NPC_IsOnHatelist)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_NPC_RemoveFromHateList); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_RemoveFromHateList)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: NPC::RemoveFromHateList(THIS, ent)");
|
||||
{
|
||||
NPC * THIS;
|
||||
Mob* ent;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
ent = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "ent is not of type Mob");
|
||||
if(ent == nullptr)
|
||||
Perl_croak(aTHX_ "ent is nullptr, avoiding crash.");
|
||||
|
||||
THIS->RemoveFromHateList(ent);
|
||||
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
XS(XS_NPC_SetNPCFactionID); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_SetNPCFactionID)
|
||||
{
|
||||
@@ -2076,7 +2112,7 @@ XS(XS_NPC_GetSlowMitigation)
|
||||
Perl_croak(aTHX_ "Usage: NPC::GetSlowMitigation(THIS)");
|
||||
{
|
||||
NPC * THIS;
|
||||
int16 RETVAL;
|
||||
float RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
@@ -2089,7 +2125,7 @@ XS(XS_NPC_GetSlowMitigation)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetSlowMitigation();
|
||||
XSprePUSH; PUSHn((UV)RETVAL);
|
||||
XSprePUSH; PUSHn((double)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@@ -2343,7 +2379,7 @@ XS(XS_NPC_AddRangedProc) {
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
THIS->AddDefensiveProc(spell_id,chance);
|
||||
THIS->AddRangedProc(spell_id,chance);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@@ -2368,7 +2404,128 @@ XS(XS_NPC_AddDefensiveProc) {
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
THIS->AddProcToWeapon(spell_id, true, chance);
|
||||
THIS->AddDefensiveProc(spell_id,chance);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_NPC_RemoveMeleeProc);
|
||||
XS(XS_NPC_RemoveMeleeProc) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: NPC::RemoveMeleeProc(THIS,spellid)");
|
||||
{
|
||||
NPC * THIS;
|
||||
int spell_id = (int)SvIV(ST(1));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
THIS->RemoveProcFromWeapon(spell_id, false);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_NPC_RemoveRangedProc);
|
||||
XS(XS_NPC_RemoveRangedProc) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: NPC::RemoveRangedProc(THIS,spellid)");
|
||||
{
|
||||
NPC * THIS;
|
||||
int spell_id = (int)SvIV(ST(1));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
THIS->RemoveRangedProc(spell_id, false);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_NPC_RemoveDefensiveProc);
|
||||
XS(XS_NPC_RemoveDefensiveProc) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: NPC::RemoveDefensiveProc(THIS,spellid)");
|
||||
{
|
||||
NPC * THIS;
|
||||
int spell_id = (int)SvIV(ST(1));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
THIS->RemoveDefensiveProc(spell_id, false);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_NPC_ChangeLastName); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_ChangeLastName)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 1 || items > 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::ChangeLastName(THIS, name)");
|
||||
{
|
||||
NPC * THIS;
|
||||
char * name = nullptr;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items > 1) { name = (char *)SvPV_nolen(ST(1)); }
|
||||
|
||||
THIS->ChangeLastName(name);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_NPC_ClearLastName); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_ClearLastName)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::ClearLastName(THIS)");
|
||||
{
|
||||
NPC * THIS;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->ClearLastName();
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@@ -2420,6 +2577,7 @@ XS(boot_NPC)
|
||||
newXSproto(strcpy(buf, "GetPrimaryFaction"), XS_NPC_GetPrimaryFaction, file, "$");
|
||||
newXSproto(strcpy(buf, "GetNPCHate"), XS_NPC_GetNPCHate, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsOnHatelist"), XS_NPC_IsOnHatelist, file, "$$");
|
||||
newXSproto(strcpy(buf, "RemoveFromHateList"), XS_NPC_RemoveFromHateList, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetNPCFactionID"), XS_NPC_SetNPCFactionID, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetMaxDMG"), XS_NPC_GetMaxDMG, file, "$");
|
||||
newXSproto(strcpy(buf, "GetMinDMG"), XS_NPC_GetMinDMG, file, "$");
|
||||
@@ -2480,6 +2638,11 @@ XS(boot_NPC)
|
||||
newXSproto(strcpy(buf, "AddMeleeProc"), XS_NPC_AddMeleeProc, file, "$$$");
|
||||
newXSproto(strcpy(buf, "AddRangedProc"), XS_NPC_AddRangedProc, file, "$$$");
|
||||
newXSproto(strcpy(buf, "AddDefensiveProc"), XS_NPC_AddDefensiveProc, file, "$$$");
|
||||
newXSproto(strcpy(buf, "RemoveMeleeProc"), XS_NPC_RemoveMeleeProc, file, "$$");
|
||||
newXSproto(strcpy(buf, "RemoveRangedProc"), XS_NPC_RemoveRangedProc, file, "$$");
|
||||
newXSproto(strcpy(buf, "RemoveDefensiveProc"), XS_NPC_RemoveDefensiveProc, file, "$$");
|
||||
newXSproto(strcpy(buf, "ChangeLastName"), XS_NPC_ChangeLastName, file, "$:$");
|
||||
newXSproto(strcpy(buf, "ClearLastName"), XS_NPC_ClearLastName, file, "$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
+17
-3
@@ -248,7 +248,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
}
|
||||
|
||||
//find the NPC data for the specified NPC type
|
||||
const NPCType *base = database.GetNPCType(record.npc_type);
|
||||
const NPCType *base = database.LoadNPCTypesData(record.npc_type);
|
||||
if(base == nullptr) {
|
||||
Message(13, "Unable to load NPC data for pet %s", pettype);
|
||||
Log.Out(Logs::General, Logs::Error, "Unable to load NPC data for pet %s (NPC ID %d), check pets and npc_types tables.", pettype, record.npc_type);
|
||||
@@ -384,7 +384,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
monsterid = 567;
|
||||
|
||||
// give the summoned pet the attributes of the monster we found
|
||||
const NPCType* monster = database.GetNPCType(monsterid);
|
||||
const NPCType* monster = database.LoadNPCTypesData(monsterid);
|
||||
if(monster) {
|
||||
npc_type->race = monster->race;
|
||||
npc_type->size = monster->size;
|
||||
@@ -417,7 +417,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
}
|
||||
}
|
||||
|
||||
npc->UpdateEquipLightValue();
|
||||
npc->UpdateEquipmentLight();
|
||||
|
||||
// finally, override size if one was provided
|
||||
if (in_size > 0.0f)
|
||||
@@ -426,6 +426,20 @@ 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)
|
||||
{
|
||||
Mob* target = GetTarget();
|
||||
|
||||
if (target){
|
||||
npc->AddToHateList(target, 1);
|
||||
npc->SetPetTargetLockID(target->GetID());
|
||||
npc->SetSpecialAbility(IMMUNE_AGGRO, 1);
|
||||
}
|
||||
else
|
||||
npc->Kill(); //On live casts spell 892 Unsummon (Kayen - Too limiting to use that for emu since pet can have more than 20k HP)
|
||||
}
|
||||
}
|
||||
/* This is why the pets ghost - pets were being spawned too far away from its npc owner and some
|
||||
into walls or objects (+10), this sometimes creates the "ghost" effect. I changed to +2 (as close as I
|
||||
|
||||
@@ -483,7 +483,7 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string
|
||||
}
|
||||
|
||||
//second look for /quests/zone/npcname.ext (precedence)
|
||||
const NPCType *npc_type = database.GetNPCType(npcid);
|
||||
const NPCType *npc_type = database.LoadNPCTypesData(npcid);
|
||||
if(!npc_type) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
+6
-6
@@ -203,7 +203,7 @@ void QuestManager::write(const char *file, const char *str) {
|
||||
|
||||
Mob* QuestManager::spawn2(int npc_type, int grid, int unused, const glm::vec4& position) {
|
||||
const NPCType* tmp = 0;
|
||||
if (tmp = database.GetNPCType(npc_type))
|
||||
if (tmp = database.LoadNPCTypesData(npc_type))
|
||||
{
|
||||
NPC* npc = new NPC(tmp, nullptr, position, FlyMode3);
|
||||
npc->AddLootTable();
|
||||
@@ -225,7 +225,7 @@ Mob* QuestManager::unique_spawn(int npc_type, int grid, int unused, const glm::v
|
||||
}
|
||||
|
||||
const NPCType* tmp = 0;
|
||||
if (tmp = database.GetNPCType(npc_type))
|
||||
if (tmp = database.LoadNPCTypesData(npc_type))
|
||||
{
|
||||
NPC* npc = new NPC(tmp, nullptr, position, FlyMode3);
|
||||
npc->AddLootTable();
|
||||
@@ -275,7 +275,7 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const NPCType* tmp = database.GetNPCType(npcid);
|
||||
const NPCType* tmp = database.LoadNPCTypesData(npcid);
|
||||
if(!tmp)
|
||||
{
|
||||
return nullptr;
|
||||
@@ -297,7 +297,7 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id)
|
||||
}
|
||||
}
|
||||
|
||||
database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0);
|
||||
database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), 0);
|
||||
found_spawn->SetCurrentNPCID(npcid);
|
||||
|
||||
auto position = glm::vec4(found_spawn->GetX(), found_spawn->GetY(), found_spawn->GetZ(), found_spawn->GetHeading());
|
||||
@@ -1574,7 +1574,7 @@ void QuestManager::respawn(int npcTypeID, int grid) {
|
||||
quests_running_.push(e);
|
||||
|
||||
const NPCType* npcType = nullptr;
|
||||
if ((npcType = database.GetNPCType(npcTypeID)))
|
||||
if ((npcType = database.LoadNPCTypesData(npcTypeID)))
|
||||
{
|
||||
owner = new NPC(npcType, nullptr, owner->GetPosition(), FlyMode3);
|
||||
owner->CastToNPC()->AddLootTable();
|
||||
@@ -2388,7 +2388,7 @@ void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
database.UpdateSpawn2Timeleft(id, 0, (newTime/1000));
|
||||
database.UpdateRespawnTime(id, 0, (newTime/1000));
|
||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements())
|
||||
|
||||
+86
-24
@@ -183,7 +183,7 @@ bool Spawn2::Process() {
|
||||
}
|
||||
|
||||
//try to find our NPC type.
|
||||
const NPCType* tmp = database.GetNPCType(npcid);
|
||||
const NPCType* tmp = database.LoadNPCTypesData(npcid);
|
||||
if (tmp == nullptr) {
|
||||
Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded an invalid NPC type %d", spawn2_id, spawngroup_id_, npcid);
|
||||
Reset(); //try again later
|
||||
@@ -214,9 +214,6 @@ bool Spawn2::Process() {
|
||||
if(IsDespawned)
|
||||
return true;
|
||||
|
||||
if(spawn2_id)
|
||||
database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0);
|
||||
|
||||
currentnpcid = npcid;
|
||||
NPC* npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3);
|
||||
|
||||
@@ -348,7 +345,7 @@ void Spawn2::DeathReset(bool realdeath)
|
||||
//if we have a valid spawn id
|
||||
if(spawn2_id)
|
||||
{
|
||||
database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), (cur/1000));
|
||||
database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), (cur/1000));
|
||||
Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn reset by death, repop in %d ms", spawn2_id, timer.GetRemainingTime());
|
||||
//store it to database too
|
||||
}
|
||||
@@ -356,28 +353,95 @@ void Spawn2::DeathReset(bool realdeath)
|
||||
|
||||
bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay) {
|
||||
|
||||
std::unordered_map<uint32, uint32> spawn_times;
|
||||
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
/* Bulk Load NPC Types Data into the cache */
|
||||
database.LoadNPCTypesData(0, true);
|
||||
|
||||
std::string spawn_query = StringFormat(
|
||||
"SELECT "
|
||||
"respawn_times.id, "
|
||||
"respawn_times.`start`, "
|
||||
"respawn_times.duration "
|
||||
"FROM "
|
||||
"respawn_times "
|
||||
"WHERE instance_id = %u",
|
||||
zone->GetInstanceID()
|
||||
);
|
||||
auto results = QueryDatabase(spawn_query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 start_duration = atoi(row[1]) > 0 ? atoi(row[1]) : 0;
|
||||
uint32 end_duration = atoi(row[2]) > 0 ? atoi(row[2]) : 0;
|
||||
|
||||
/* Our current time was expired */
|
||||
if ((start_duration + end_duration) <= tv.tv_sec) {
|
||||
spawn_times[atoi(row[0])] = 0;
|
||||
}
|
||||
/* We still have time left on this timer */
|
||||
else {
|
||||
spawn_times[atoi(row[0])] = ((start_duration + end_duration) - tv.tv_sec) * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
const char *zone_name = database.GetZoneName(zoneid);
|
||||
std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, "
|
||||
"respawntime, variance, pathgrid, _condition, "
|
||||
"cond_value, enabled, animation FROM spawn2 "
|
||||
"WHERE zone = '%s' AND version = %u",
|
||||
zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"id, "
|
||||
"spawngroupID, "
|
||||
"x, "
|
||||
"y, "
|
||||
"z, "
|
||||
"heading, "
|
||||
"respawntime, "
|
||||
"variance, "
|
||||
"pathgrid, "
|
||||
"_condition, "
|
||||
"cond_value, "
|
||||
"enabled, "
|
||||
"animation "
|
||||
"FROM "
|
||||
"spawn2 "
|
||||
"WHERE zone = '%s' AND version = %u",
|
||||
zone_name,
|
||||
version
|
||||
);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
Spawn2* newSpawn = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
|
||||
bool perl_enabled = atoi(row[11]) == 1? true: false;
|
||||
uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000);
|
||||
newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]),
|
||||
atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]),
|
||||
atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
uint32 spawn_time_left = 0;
|
||||
Spawn2* new_spawn = 0;
|
||||
bool perl_enabled = atoi(row[11]) == 1 ? true : false;
|
||||
|
||||
spawn2_list.Insert(newSpawn);
|
||||
}
|
||||
if (spawn_times.count(atoi(row[0])) != 0)
|
||||
spawn_time_left = spawn_times[atoi(row[0])];
|
||||
|
||||
new_spawn = new Spawn2( //
|
||||
atoi(row[0]), // uint32 in_spawn2_id
|
||||
atoi(row[1]), // uint32 spawngroup_id
|
||||
atof(row[2]), // float in_x
|
||||
atof(row[3]), // float in_y
|
||||
atof(row[4]), // float in_z
|
||||
atof(row[5]), // float in_heading
|
||||
atoi(row[6]), // uint32 respawn
|
||||
atoi(row[7]), // uint32 variance
|
||||
spawn_time_left, // uint32 timeleft
|
||||
atoi(row[8]), // uint32 grid
|
||||
atoi(row[9]), // uint16 in_cond_id
|
||||
atoi(row[10]), // int16 in_min_value
|
||||
perl_enabled, // bool in_enabled
|
||||
(EmuAppearance)atoi(row[12]) // EmuAppearance anim
|
||||
);
|
||||
|
||||
spawn2_list.Insert(new_spawn);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -427,8 +491,6 @@ bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* z
|
||||
if (results.RowsAffected() != 1)
|
||||
return false;
|
||||
|
||||
if(client)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1186,7 +1186,6 @@ float Mob::GetRangeDistTargetSizeMod(Mob* other)
|
||||
|
||||
void NPC::RangedAttack(Mob* other)
|
||||
{
|
||||
|
||||
if (!other)
|
||||
return;
|
||||
//make sure the attack and ranged timers are up
|
||||
@@ -1306,7 +1305,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha
|
||||
|
||||
if (TotalDmg > 0)
|
||||
CommonOutgoingHitSuccess(other, TotalDmg, skillInUse);
|
||||
else
|
||||
else if (TotalDmg < -4)
|
||||
TotalDmg = -5;
|
||||
|
||||
if (TotalDmg > 0)
|
||||
|
||||
@@ -5527,7 +5527,12 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||
//Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected
|
||||
//by reagent conservation for obvious reasons.
|
||||
|
||||
return realTotal + realTotal2 + realTotal3;
|
||||
//Non-Live like feature to allow for an additive focus bonus to be applied from foci that are placed in worn slot. (No limit checks)
|
||||
int16 worneffect_bonus = 0;
|
||||
if (RuleB(Spells, UseAdditiveFocusFromWornSlot))
|
||||
worneffect_bonus = itembonuses.FocusEffectsWorn[type];
|
||||
|
||||
return realTotal + realTotal2 + realTotal3 + worneffect_bonus;
|
||||
}
|
||||
|
||||
int16 NPC::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||
|
||||
+1
-1
@@ -3742,7 +3742,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsValidSpell(spells[spell_id].RecourseLink))
|
||||
if (IsValidSpell(spells[spell_id].RecourseLink) && spells[spell_id].RecourseLink != spell_id)
|
||||
SpellFinished(spells[spell_id].RecourseLink, this, 10, 0, -1, spells[spells[spell_id].RecourseLink].ResistDiff);
|
||||
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
|
||||
+10
-1
@@ -2872,7 +2872,16 @@ int ClientTaskState::GetTaskActivityDoneCountFromTaskID(int TaskID, int Activity
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount;
|
||||
|
||||
if (ActiveTaskIndex == -1)
|
||||
return 0;
|
||||
|
||||
if (ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount){
|
||||
return ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount;
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ClientTaskState::GetTaskStartTime(int index) {
|
||||
|
||||
+176
-83
@@ -108,7 +108,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
|
||||
ItemInst* inst2 = client->GetInv().GetItem(trade_slot_id);
|
||||
|
||||
// it looks like the original code attempted to allow stacking...
|
||||
// (it just didn't handle partial stack move actions -U)
|
||||
// (it just didn't handle partial stack move actions)
|
||||
if (stack_size > 0) {
|
||||
if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) {
|
||||
client->Kick();
|
||||
@@ -800,7 +800,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
// QS code
|
||||
if(RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
||||
// Currently provides only basic functionality. Calling method will also
|
||||
// need to be modified before item returns and rewards can be logged. -U
|
||||
// need to be modified before item returns and rewards can be logged.
|
||||
qs_audit = (QSPlayerLogHandin_Struct*)event_entry;
|
||||
qs_log = true;
|
||||
|
||||
@@ -819,7 +819,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
qs_audit->npc_count = 0;
|
||||
}
|
||||
|
||||
if(qs_log) { // This can be incorporated below when revisions are made -U
|
||||
if(qs_log) { // This can be incorporated below when revisions are made
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_NPC_END; ++trade_slot) {
|
||||
const ItemInst* trade_inst = m_inv[trade_slot];
|
||||
|
||||
@@ -1098,7 +1098,15 @@ void Client::Trader_EndTrader() {
|
||||
for(int i = 0; i < 80; i++) {
|
||||
if(gis->Items[i] != 0) {
|
||||
|
||||
tdis->ItemID = gis->SerialNumber[i];
|
||||
if (Customer->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// RoF+ use Item IDs for now
|
||||
tdis->ItemID = gis->Items[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
tdis->ItemID = gis->SerialNumber[i];
|
||||
}
|
||||
|
||||
Customer->QueuePacket(outapp);
|
||||
}
|
||||
@@ -1138,7 +1146,6 @@ void Client::Trader_EndTrader() {
|
||||
|
||||
QueuePacket(outapp);
|
||||
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
WithCustomer(0);
|
||||
@@ -1221,6 +1228,29 @@ void Client::BulkSendTraderInventory(uint32 char_id) {
|
||||
safe_delete(TraderItems);
|
||||
}
|
||||
|
||||
uint32 Client::FindTraderItemSerialNumber(int32 ItemID) {
|
||||
|
||||
ItemInst* item = nullptr;
|
||||
uint16 SlotID = 0;
|
||||
for (int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++){
|
||||
item = this->GetInv().GetItem(i);
|
||||
if (item && item->GetItem()->ID == 17899){ //Traders Satchel
|
||||
for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; x++) {
|
||||
// we already have the parent bag and a contents iterator..why not just iterate the bag!??
|
||||
SlotID = Inventory::CalcSlotId(i, x);
|
||||
item = this->GetInv().GetItem(SlotID);
|
||||
if (item) {
|
||||
if (item->GetID() == ItemID)
|
||||
return item->GetSerialNumber();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Client::FindTraderItemSerialNumber Couldn't find item! Item ID %i", ItemID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ItemInst* Client::FindTraderItemBySerialNumber(int32 SerialNumber){
|
||||
|
||||
ItemInst* item = nullptr;
|
||||
@@ -1288,9 +1318,9 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){
|
||||
|
||||
item = this->GetInv().GetItem(SlotID);
|
||||
|
||||
if(item && item->GetSerialNumber() == SerialNumber &&
|
||||
(item->GetCharges() >= Quantity || (item->GetCharges() <= 0 && Quantity == 1))){
|
||||
|
||||
if (item && item->GetSerialNumber() == SerialNumber &&
|
||||
(item->GetCharges() >= Quantity || (item->GetCharges() <= 0 && Quantity == 1)))
|
||||
{
|
||||
return SlotID;
|
||||
}
|
||||
}
|
||||
@@ -1302,21 +1332,34 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int SerialNumber) {
|
||||
void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int32 SerialNumber, int32 itemid) {
|
||||
|
||||
if(!Customer)
|
||||
return;
|
||||
|
||||
if(!Customer) return;
|
||||
Log.Out(Logs::Detail, Logs::Trading, "NukeTraderItem(Slot %i, Charges %i, Quantity %i", Slot, Charges, Quantity);
|
||||
if(Quantity < Charges) {
|
||||
|
||||
if(Quantity < Charges)
|
||||
{
|
||||
Customer->SendSingleTraderItem(this->CharacterID(), SerialNumber);
|
||||
m_inv.DeleteItem(Slot, Quantity);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct));
|
||||
TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer;
|
||||
|
||||
tdis->Unknown000 = 0;
|
||||
tdis->TraderID = Customer->GetID();
|
||||
tdis->ItemID = SerialNumber;
|
||||
if (Customer->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// RoF+ use Item IDs for now
|
||||
tdis->ItemID = itemid;
|
||||
}
|
||||
else
|
||||
{
|
||||
tdis->ItemID = SerialNumber;
|
||||
}
|
||||
tdis->Unknown012 = 0;
|
||||
|
||||
|
||||
@@ -1324,7 +1367,6 @@ void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Cu
|
||||
safe_delete(outapp);
|
||||
|
||||
m_inv.DeleteItem(Slot);
|
||||
|
||||
}
|
||||
// This updates the trader. Removes it from his trading bags.
|
||||
//
|
||||
@@ -1375,49 +1417,61 @@ void Client::FindAndNukeTraderItem(int32 SerialNumber, uint16 Quantity, Client*
|
||||
int16 Charges=0;
|
||||
|
||||
uint16 SlotID = FindTraderItem(SerialNumber, Quantity);
|
||||
if(SlotID > 0){
|
||||
|
||||
if(SlotID > 0) {
|
||||
|
||||
item = this->GetInv().GetItem(SlotID);
|
||||
|
||||
if(item) {
|
||||
Charges = this->GetInv().GetItem(SlotID)->GetCharges();
|
||||
|
||||
Stackable = item->IsStackable();
|
||||
|
||||
if(!Stackable)
|
||||
Quantity = (Charges > 0) ? Charges : 1;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "FindAndNuke %s, Charges %i, Quantity %i", item->GetItem()->Name, Charges, Quantity);
|
||||
if (!item)
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Could not find Item: %i on Trader: %s", SerialNumber, Quantity, this->GetName());
|
||||
return;
|
||||
}
|
||||
if(item && (Charges <= Quantity || (Charges <= 0 && Quantity==1) || !Stackable)){
|
||||
|
||||
Charges = this->GetInv().GetItem(SlotID)->GetCharges();
|
||||
|
||||
Stackable = item->IsStackable();
|
||||
|
||||
if (!Stackable)
|
||||
Quantity = (Charges > 0) ? Charges : 1;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Trading, "FindAndNuke %s, Charges %i, Quantity %i", item->GetItem()->Name, Charges, Quantity);
|
||||
|
||||
if (Charges <= Quantity || (Charges <= 0 && Quantity==1) || !Stackable)
|
||||
{
|
||||
this->DeleteItemInInventory(SlotID, Quantity);
|
||||
|
||||
TraderCharges_Struct* GetSlot = database.LoadTraderItemWithCharges(this->CharacterID());
|
||||
TraderCharges_Struct* TraderItems = database.LoadTraderItemWithCharges(this->CharacterID());
|
||||
|
||||
uint8 Count = 0;
|
||||
|
||||
bool TestSlot = true;
|
||||
|
||||
for(int y = 0;y < 80;y++){
|
||||
for(int i = 0;i < 80;i++){
|
||||
|
||||
if(TestSlot && GetSlot->SerialNumber[y] == SerialNumber){
|
||||
|
||||
database.DeleteTraderItem(this->CharacterID(),y);
|
||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, GetSlot->SerialNumber[y]);
|
||||
if(TestSlot && TraderItems->SerialNumber[i] == SerialNumber)
|
||||
{
|
||||
database.DeleteTraderItem(this->CharacterID(),i);
|
||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, TraderItems->SerialNumber[i], TraderItems->ItemID[i]);
|
||||
TestSlot=false;
|
||||
}
|
||||
else if(GetSlot->ItemID[y] > 0)
|
||||
else if (TraderItems->ItemID[i] > 0)
|
||||
{
|
||||
Count++;
|
||||
}
|
||||
}
|
||||
if(Count == 0)
|
||||
if (Count == 0)
|
||||
{
|
||||
Trader_EndTrader();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if(item) {
|
||||
else
|
||||
{
|
||||
database.UpdateTraderItemCharges(this->CharacterID(), item->GetSerialNumber(), Charges-Quantity);
|
||||
|
||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, item->GetSerialNumber());
|
||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, item->GetSerialNumber(), item->GetID());
|
||||
|
||||
return;
|
||||
|
||||
@@ -1427,22 +1481,38 @@ void Client::FindAndNukeTraderItem(int32 SerialNumber, uint16 Quantity, Client*
|
||||
Quantity,this->GetName());
|
||||
}
|
||||
|
||||
void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCharges){
|
||||
void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCharges, uint32 itemid){
|
||||
|
||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct));
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderBuy_Struct));
|
||||
}
|
||||
else
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct));
|
||||
}
|
||||
|
||||
TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer;
|
||||
|
||||
memcpy(outtbs, tbs, app->size);
|
||||
|
||||
outtbs->Price = (tbs->Price * static_cast<uint32>(TraderItemCharges));
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// Convert Serial Number back to Item ID for RoF+
|
||||
outtbs->ItemID = itemid;
|
||||
}
|
||||
else
|
||||
{
|
||||
// RoF+ requires individual price, but older clients require total price
|
||||
outtbs->Price = (tbs->Price * static_cast<uint32>(TraderItemCharges));
|
||||
}
|
||||
|
||||
outtbs->Quantity = TraderItemCharges;
|
||||
|
||||
// This should probably be trader ID, not customer ID as it is below.
|
||||
outtbs->TraderID = this->GetID();
|
||||
|
||||
outtbs->AlreadySold = 0;
|
||||
|
||||
QueuePacket(outapp);
|
||||
@@ -1479,9 +1549,7 @@ static void BazaarAuditTrail(const char *seller, const char *buyer, const char *
|
||||
database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicationPacket* app){
|
||||
void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplicationPacket* app){
|
||||
|
||||
if(!Trader) return;
|
||||
|
||||
@@ -1490,13 +1558,23 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
||||
return;
|
||||
}
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader,sizeof(TraderBuy_Struct));
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct));
|
||||
|
||||
TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer;
|
||||
|
||||
outtbs->ItemID = tbs->ItemID;
|
||||
|
||||
const ItemInst* BuyItem = Trader->FindTraderItemBySerialNumber(tbs->ItemID);
|
||||
const ItemInst* BuyItem = nullptr;
|
||||
uint32 ItemID = 0;
|
||||
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// Convert Item ID to Serial Number for RoF+
|
||||
ItemID = tbs->ItemID;
|
||||
tbs->ItemID = Trader->FindTraderItemSerialNumber(tbs->ItemID);
|
||||
}
|
||||
|
||||
BuyItem = Trader->FindTraderItemBySerialNumber(tbs->ItemID);
|
||||
|
||||
if(!BuyItem) {
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Unable to find item on trader.");
|
||||
@@ -1509,15 +1587,15 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
||||
BuyItem->GetItem()->Name, BuyItem->IsStackable(), tbs->Quantity, BuyItem->GetCharges());
|
||||
// If the item is not stackable, then we can only be buying one of them.
|
||||
if(!BuyItem->IsStackable())
|
||||
outtbs->Quantity = tbs->Quantity;
|
||||
outtbs->Quantity = 1; // normally you can't send more than 1 here
|
||||
else {
|
||||
// Stackable items, arrows, diamonds, etc
|
||||
int ItemCharges = BuyItem->GetCharges();
|
||||
int32 ItemCharges = BuyItem->GetCharges();
|
||||
// ItemCharges for stackables should not be <= 0
|
||||
if(ItemCharges <= 0)
|
||||
outtbs->Quantity = 1;
|
||||
// If the purchaser requested more than is in the stack, just sell them how many are actually in the stack.
|
||||
else if(ItemCharges < (int16)tbs->Quantity)
|
||||
else if(static_cast<uint32>(ItemCharges) < tbs->Quantity)
|
||||
outtbs->Quantity = ItemCharges;
|
||||
else
|
||||
outtbs->Quantity = tbs->Quantity;
|
||||
@@ -1546,12 +1624,10 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
||||
return;
|
||||
}
|
||||
|
||||
ReturnTraderReq(app, outtbs->Quantity);
|
||||
ReturnTraderReq(app, outtbs->Quantity, ItemID);
|
||||
|
||||
outtbs->TraderID = this->GetID();
|
||||
|
||||
outtbs->Action = BazaarBuyItem;
|
||||
|
||||
strn0cpy(outtbs->ItemName, BuyItem->GetItem()->Name, 64);
|
||||
|
||||
int TraderSlot = 0;
|
||||
@@ -1561,55 +1637,50 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
||||
else
|
||||
SendTraderItem(BuyItem->GetItem()->ID, BuyItem->GetCharges());
|
||||
|
||||
|
||||
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoneyUpdate,sizeof(MoneyUpdate_Struct));
|
||||
|
||||
MoneyUpdate_Struct* mus= (MoneyUpdate_Struct*)outapp2->pBuffer;
|
||||
|
||||
// This cannot overflow assuming MAX_TRANSACTION_VALUE, checked above, is the default of 2000000000
|
||||
uint32 TotalCost = tbs->Price * outtbs->Quantity;
|
||||
|
||||
outtbs->Price = TotalCost;
|
||||
if (Trader->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// RoF+ uses individual item price where older clients use total price
|
||||
outtbs->Price = tbs->Price;
|
||||
}
|
||||
else
|
||||
{
|
||||
outtbs->Price = TotalCost;
|
||||
}
|
||||
|
||||
this->TakeMoneyFromPP(TotalCost);
|
||||
|
||||
mus->platinum = TotalCost / 1000;
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Customer Paid: %d in Copper", TotalCost);
|
||||
|
||||
TotalCost -= (mus->platinum * 1000);
|
||||
uint32 platinum = TotalCost / 1000;
|
||||
TotalCost -= (platinum * 1000);
|
||||
uint32 gold = TotalCost / 100;
|
||||
TotalCost -= (gold * 100);
|
||||
uint32 silver = TotalCost / 10;
|
||||
TotalCost -= (silver * 10);
|
||||
uint32 copper = TotalCost;
|
||||
|
||||
mus->gold = TotalCost / 100;
|
||||
Trader->AddMoneyToPP(copper, silver, gold, platinum, true);
|
||||
|
||||
TotalCost -= (mus->gold * 100);
|
||||
|
||||
mus->silver = TotalCost / 10;
|
||||
|
||||
TotalCost -= (mus->silver * 10);
|
||||
|
||||
mus->copper = TotalCost;
|
||||
|
||||
Trader->AddMoneyToPP(mus->copper,mus->silver,mus->gold,mus->platinum,false);
|
||||
|
||||
mus->platinum = Trader->GetPlatinum();
|
||||
mus->gold = Trader->GetGold();
|
||||
mus->silver = Trader->GetSilver();
|
||||
mus->copper = Trader->GetCopper();
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Trader Received: %d Platinum, %d Gold, %d Silver, %d Copper", platinum, gold, silver, copper);
|
||||
|
||||
TraderSlot = Trader->FindTraderItem(tbs->ItemID, outtbs->Quantity);
|
||||
|
||||
Trader->QueuePacket(outapp2);
|
||||
|
||||
|
||||
if(RuleB(Bazaar, AuditTrail))
|
||||
BazaarAuditTrail(Trader->GetName(), GetName(), BuyItem->GetItem()->Name, outtbs->Quantity, outtbs->Price, 0);
|
||||
|
||||
Trader->FindAndNukeTraderItem(tbs->ItemID, outtbs->Quantity, this, 0);
|
||||
|
||||
if (ItemID > 0 && Trader->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// Convert Serial Number back to ItemID for RoF+
|
||||
outtbs->ItemID = ItemID;
|
||||
}
|
||||
|
||||
Trader->QueuePacket(outapp);
|
||||
|
||||
|
||||
safe_delete(outapp);
|
||||
safe_delete(outapp2);
|
||||
|
||||
}
|
||||
|
||||
void Client::SendBazaarWelcome()
|
||||
@@ -1619,7 +1690,15 @@ void Client::SendBazaarWelcome()
|
||||
if (results.Success() && results.RowCount() == 1){
|
||||
auto row = results.begin();
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BazaarWelcome_Struct));
|
||||
}
|
||||
else
|
||||
{
|
||||
outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
|
||||
}
|
||||
|
||||
memset(outapp->pBuffer,0,outapp->size);
|
||||
|
||||
@@ -1630,6 +1709,11 @@ void Client::SendBazaarWelcome()
|
||||
bws->Traders = atoi(row[0]);
|
||||
bws->Items = atoi(row[1]);
|
||||
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
bws->Unknown012 = GetID();
|
||||
}
|
||||
|
||||
QueuePacket(outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
@@ -2000,6 +2084,15 @@ static void UpdateTraderCustomerPriceChanged(uint32 CustomerID, TraderCharges_St
|
||||
for(int i = 0; i < 80; i++) {
|
||||
|
||||
if(gis->ItemID[i] == ItemID) {
|
||||
if (Customer->GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
// RoF+ use Item IDs for now
|
||||
tdis->ItemID = gis->ItemID[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
tdis->ItemID = gis->SerialNumber[i];
|
||||
}
|
||||
tdis->ItemID = gis->SerialNumber[i];
|
||||
Log.Out(Logs::Detail, Logs::Trading, "Telling customer to remove item %i with %i charges and S/N %i",
|
||||
ItemID, Charges, gis->SerialNumber[i]);
|
||||
|
||||
+3
-3
@@ -142,7 +142,7 @@ void Trap::Trigger(Mob* trigger)
|
||||
|
||||
for (i = 0; i < effectvalue2; i++)
|
||||
{
|
||||
if ((tmp = database.GetNPCType(effectvalue)))
|
||||
if ((tmp = database.LoadNPCTypesData(effectvalue)))
|
||||
{
|
||||
auto randomOffset = glm::vec4(zone->random.Int(-5, 5),zone->random.Int(-5, 5),zone->random.Int(-5, 5), zone->random.Int(0, 249));
|
||||
auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f);
|
||||
@@ -165,7 +165,7 @@ void Trap::Trigger(Mob* trigger)
|
||||
|
||||
for (i = 0; i < effectvalue2; i++)
|
||||
{
|
||||
if ((tmp = database.GetNPCType(effectvalue)))
|
||||
if ((tmp = database.LoadNPCTypesData(effectvalue)))
|
||||
{
|
||||
auto randomOffset = glm::vec4(zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(0, 249));
|
||||
auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f);
|
||||
@@ -294,7 +294,7 @@ void Trap::CreateHiddenTrigger()
|
||||
if(hiddenTrigger)
|
||||
return;
|
||||
|
||||
const NPCType *base_type = database.GetNPCType(500);
|
||||
const NPCType *base_type = database.LoadNPCTypesData(500);
|
||||
NPCType *make_npc = new NPCType;
|
||||
memcpy(make_npc, base_type, sizeof(NPCType));
|
||||
make_npc->max_hp = 100000;
|
||||
|
||||
+8
-6
@@ -737,6 +737,7 @@ void Zone::LoadZoneDoors(const char* zone, int16 version)
|
||||
for(r = 0; r < count; r++, d++) {
|
||||
Doors* newdoor = new Doors(d);
|
||||
entity_list.AddDoor(newdoor);
|
||||
Log.Out(Logs::Detail, Logs::Doors, "Door Add to Entity List, index: %u db id: %u, door_id %u", r, dlist[r].db_id, dlist[r].door_id);
|
||||
}
|
||||
delete[] dlist;
|
||||
}
|
||||
@@ -933,6 +934,9 @@ bool Zone::Init(bool iStaticZone) {
|
||||
Log.Out(Logs::General, Logs::Error, "Loading World Objects failed. continuing.");
|
||||
}
|
||||
|
||||
Log.Out(Logs::General, Logs::Status, "Flushing old respawn timers...");
|
||||
database.QueryDatabase("DELETE FROM `respawn_times` WHERE (`start` + `duration`) < UNIX_TIMESTAMP(NOW())");
|
||||
|
||||
//load up the zone's doors (prints inside)
|
||||
zone->LoadZoneDoors(zone->GetShortName(), zone->GetInstanceVersion());
|
||||
zone->LoadBlockedSpells(zone->GetZoneID());
|
||||
@@ -1425,14 +1429,12 @@ bool Zone::Depop(bool StartSpawnTimer) {
|
||||
std::map<uint32,NPCType *>::iterator itr;
|
||||
entity_list.Depop(StartSpawnTimer);
|
||||
|
||||
#ifdef DEPOP_INVALIDATES_NPC_TYPES_CACHE
|
||||
// Refresh npctable, getting current info from database.
|
||||
while(npctable.size()) {
|
||||
itr=npctable.begin();
|
||||
/* Refresh npctable (cache), getting current info from database. */
|
||||
while(npctable.size()) {
|
||||
itr = npctable.begin();
|
||||
delete itr->second;
|
||||
npctable.erase(itr);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2164,7 +2166,7 @@ void Zone::DoAdventureActions()
|
||||
{
|
||||
if(ds->assa_count >= RuleI(Adventure, NumberKillsForBossSpawn))
|
||||
{
|
||||
const NPCType* tmp = database.GetNPCType(ds->data_id);
|
||||
const NPCType* tmp = database.LoadNPCTypesData(ds->data_id);
|
||||
if(tmp)
|
||||
{
|
||||
NPC* npc = new NPC(tmp, nullptr, glm::vec4(ds->assa_x, ds->assa_y, ds->assa_z, ds->assa_h), FlyMode3);
|
||||
|
||||
+458
-304
@@ -97,118 +97,178 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct
|
||||
*map_filename = new char[100];
|
||||
zone_data->zone_id = zoneid;
|
||||
|
||||
std::string query = StringFormat("SELECT ztype, fog_red, fog_green, fog_blue, fog_minclip, fog_maxclip, " // 5
|
||||
"fog_red2, fog_green2, fog_blue2, fog_minclip2, fog_maxclip2, " // 5
|
||||
"fog_red3, fog_green3, fog_blue3, fog_minclip3, fog_maxclip3, " // 5
|
||||
"fog_red4, fog_green4, fog_blue4, fog_minclip4, fog_maxclip4, " // 5
|
||||
"fog_density, sky, zone_exp_multiplier, safe_x, safe_y, safe_z, underworld, " // 7
|
||||
"minclip, maxclip, time_type, canbind, cancombat, canlevitate, " // 6
|
||||
"castoutdoor, hotzone, ruleset, suspendbuffs, map_file_name, short_name, " // 6
|
||||
"rain_chance1, rain_chance2, rain_chance3, rain_chance4, " // 4
|
||||
"rain_duration1, rain_duration2, rain_duration3, rain_duration4, " // 4
|
||||
"snow_chance1, snow_chance2, snow_chance3, snow_chance4, " // 4
|
||||
"snow_duration1, snow_duration2, snow_duration3, snow_duration4 " // 4
|
||||
"FROM zone WHERE zoneidnumber = %i AND version = %i", zoneid, instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
strcpy(*map_filename, "default");
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"ztype, " // 0
|
||||
"fog_red, " // 1
|
||||
"fog_green, " // 2
|
||||
"fog_blue, " // 3
|
||||
"fog_minclip, " // 4
|
||||
"fog_maxclip, " // 5
|
||||
"fog_red2, " // 6
|
||||
"fog_green2, " // 7
|
||||
"fog_blue2, " // 8
|
||||
"fog_minclip2, " // 9
|
||||
"fog_maxclip2, " // 10
|
||||
"fog_red3, " // 11
|
||||
"fog_green3, " // 12
|
||||
"fog_blue3, " // 13
|
||||
"fog_minclip3, " // 14
|
||||
"fog_maxclip3, " // 15
|
||||
"fog_red4, " // 16
|
||||
"fog_green4, " // 17
|
||||
"fog_blue4, " // 18
|
||||
"fog_minclip4, " // 19
|
||||
"fog_maxclip4, " // 20
|
||||
"fog_density, " // 21
|
||||
"sky, " // 22
|
||||
"zone_exp_multiplier, " // 23
|
||||
"safe_x, " // 24
|
||||
"safe_y, " // 25
|
||||
"safe_z, " // 26
|
||||
"underworld, " // 27
|
||||
"minclip, " // 28
|
||||
"maxclip, " // 29
|
||||
"time_type, " // 30
|
||||
"canbind, " // 31
|
||||
"cancombat, " // 32
|
||||
"canlevitate, " // 33
|
||||
"castoutdoor, " // 34
|
||||
"hotzone, " // 35
|
||||
"ruleset, " // 36
|
||||
"suspendbuffs, " // 37
|
||||
"map_file_name, " // 38
|
||||
"short_name, " // 39
|
||||
"rain_chance1, " // 40
|
||||
"rain_chance2, " // 41
|
||||
"rain_chance3, " // 42
|
||||
"rain_chance4, " // 43
|
||||
"rain_duration1, " // 44
|
||||
"rain_duration2, " // 45
|
||||
"rain_duration3, " // 46
|
||||
"rain_duration4, " // 47
|
||||
"snow_chance1, " // 48
|
||||
"snow_chance2, " // 49
|
||||
"snow_chance3, " // 50
|
||||
"snow_chance4, " // 51
|
||||
"snow_duration1, " // 52
|
||||
"snow_duration2, " // 53
|
||||
"snow_duration3, " // 54
|
||||
"snow_duration4, " // 55
|
||||
"gravity " // 56
|
||||
"FROM zone WHERE zoneidnumber = %i AND version = %i",
|
||||
zoneid, instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
strcpy(*map_filename, "default");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
strcpy(*map_filename, "default");
|
||||
return false;
|
||||
}
|
||||
strcpy(*map_filename, "default");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
auto row = results.begin();
|
||||
|
||||
memset(zone_data, 0, sizeof(NewZone_Struct));
|
||||
zone_data->ztype = atoi(row[0]);
|
||||
zone_type = zone_data->ztype;
|
||||
memset(zone_data, 0, sizeof(NewZone_Struct));
|
||||
zone_data->ztype = atoi(row[0]);
|
||||
zone_type = zone_data->ztype;
|
||||
|
||||
int index;
|
||||
for(index = 0; index < 4; index++) {
|
||||
zone_data->fog_red[index]=atoi(row[1 + index * 5]);
|
||||
zone_data->fog_green[index]=atoi(row[2 + index * 5]);
|
||||
zone_data->fog_blue[index]=atoi(row[3 + index * 5]);
|
||||
zone_data->fog_minclip[index]=atof(row[4 + index * 5]);
|
||||
zone_data->fog_maxclip[index]=atof(row[5 + index * 5]);
|
||||
}
|
||||
int index;
|
||||
for (index = 0; index < 4; index++) {
|
||||
zone_data->fog_red[index] = atoi(row[1 + index * 5]);
|
||||
zone_data->fog_green[index] = atoi(row[2 + index * 5]);
|
||||
zone_data->fog_blue[index] = atoi(row[3 + index * 5]);
|
||||
zone_data->fog_minclip[index] = atof(row[4 + index * 5]);
|
||||
zone_data->fog_maxclip[index] = atof(row[5 + index * 5]);
|
||||
}
|
||||
|
||||
zone_data->fog_density = atof(row[21]);
|
||||
zone_data->sky=atoi(row[22]);
|
||||
zone_data->zone_exp_multiplier=atof(row[23]);
|
||||
zone_data->safe_x=atof(row[24]);
|
||||
zone_data->safe_y=atof(row[25]);
|
||||
zone_data->safe_z=atof(row[26]);
|
||||
zone_data->underworld=atof(row[27]);
|
||||
zone_data->minclip=atof(row[28]);
|
||||
zone_data->maxclip=atof(row[29]);
|
||||
zone_data->time_type=atoi(row[30]);
|
||||
zone_data->fog_density = atof(row[21]);
|
||||
zone_data->sky = atoi(row[22]);
|
||||
zone_data->zone_exp_multiplier = atof(row[23]);
|
||||
zone_data->safe_x = atof(row[24]);
|
||||
zone_data->safe_y = atof(row[25]);
|
||||
zone_data->safe_z = atof(row[26]);
|
||||
zone_data->underworld = atof(row[27]);
|
||||
zone_data->minclip = atof(row[28]);
|
||||
zone_data->maxclip = atof(row[29]);
|
||||
zone_data->time_type = atoi(row[30]);
|
||||
|
||||
//not in the DB yet:
|
||||
zone_data->gravity = 0.4;
|
||||
allow_mercs = true;
|
||||
//not in the DB yet:
|
||||
zone_data->gravity = atof(row[56]);
|
||||
Log.Out(Logs::General, Logs::Debug, "Zone Gravity is %f", zone_data->gravity);
|
||||
allow_mercs = true;
|
||||
|
||||
int bindable = 0;
|
||||
bindable = atoi(row[31]);
|
||||
int bindable = 0;
|
||||
bindable = atoi(row[31]);
|
||||
|
||||
can_bind = bindable == 0? false: true;
|
||||
is_city = bindable == 2? true: false;
|
||||
can_combat = atoi(row[32]) == 0? false: true;
|
||||
can_levitate = atoi(row[33]) == 0? false: true;
|
||||
can_castoutdoor = atoi(row[34]) == 0? false: true;
|
||||
is_hotzone = atoi(row[35]) == 0? false: true;
|
||||
can_bind = bindable == 0 ? false : true;
|
||||
is_city = bindable == 2 ? true : false;
|
||||
can_combat = atoi(row[32]) == 0 ? false : true;
|
||||
can_levitate = atoi(row[33]) == 0 ? false : true;
|
||||
can_castoutdoor = atoi(row[34]) == 0 ? false : true;
|
||||
is_hotzone = atoi(row[35]) == 0 ? false : true;
|
||||
|
||||
|
||||
ruleset = atoi(row[36]);
|
||||
zone_data->SuspendBuffs = atoi(row[37]);
|
||||
ruleset = atoi(row[36]);
|
||||
zone_data->SuspendBuffs = atoi(row[37]);
|
||||
|
||||
char *file = row[38];
|
||||
if(file)
|
||||
strcpy(*map_filename, file);
|
||||
else
|
||||
strcpy(*map_filename, row[39]);
|
||||
char *file = row[38];
|
||||
if (file)
|
||||
strcpy(*map_filename, file);
|
||||
else
|
||||
strcpy(*map_filename, row[39]);
|
||||
|
||||
for(index = 0; index < 4; index++)
|
||||
zone_data->rain_chance[index]=atoi(row[40 + index]);
|
||||
for (index = 0; index < 4; index++)
|
||||
zone_data->rain_chance[index] = atoi(row[40 + index]);
|
||||
|
||||
for(index = 0; index < 4; index++)
|
||||
zone_data->rain_duration[index]=atoi(row[44 + index]);
|
||||
for (index = 0; index < 4; index++)
|
||||
zone_data->rain_duration[index] = atoi(row[44 + index]);
|
||||
|
||||
for(index = 0; index < 4; index++)
|
||||
zone_data->snow_chance[index]=atoi(row[48 + index]);
|
||||
for (index = 0; index < 4; index++)
|
||||
zone_data->snow_chance[index] = atoi(row[48 + index]);
|
||||
|
||||
for(index = 0; index < 4; index++)
|
||||
zone_data->snow_duration[index]=atof(row[52 + index]);
|
||||
for (index = 0; index < 4; index++)
|
||||
zone_data->snow_duration[index] = atof(row[52 + index]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//updates or clears the respawn time in the database for the current spawn id
|
||||
void ZoneDatabase::UpdateSpawn2Timeleft(uint32 id, uint16 instance_id, uint32 timeleft)
|
||||
void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint32 time_left)
|
||||
{
|
||||
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
uint32 cur = tv.tv_sec;
|
||||
uint32 current_time = tv.tv_sec;
|
||||
|
||||
//if we pass timeleft as 0 that means we clear from respawn time
|
||||
//otherwise we update with a REPLACE INTO
|
||||
if(timeleft == 0) {
|
||||
std::string query = StringFormat("DELETE FROM respawn_times WHERE id=%lu "
|
||||
"AND instance_id = %lu",(unsigned long)id, (unsigned long)instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
/* If we pass timeleft as 0 that means we clear from respawn time
|
||||
otherwise we update with a REPLACE INTO
|
||||
*/
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string query = StringFormat("REPLACE INTO respawn_times (id, start, duration, instance_id) "
|
||||
"VALUES (%lu, %lu, %lu, %lu)",
|
||||
(unsigned long)id, (unsigned long)cur,
|
||||
(unsigned long)timeleft, (unsigned long)instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `respawn_times` "
|
||||
"(id, "
|
||||
"start, "
|
||||
"duration, "
|
||||
"instance_id) "
|
||||
"VALUES "
|
||||
"(%u, "
|
||||
"%u, "
|
||||
"%u, "
|
||||
"%u)",
|
||||
spawn2_id,
|
||||
current_time,
|
||||
time_left,
|
||||
instance_id
|
||||
);
|
||||
QueryDatabase(query);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1107,29 +1167,47 @@ bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
r = 0;
|
||||
i = atoi(row[r]); /* Slot */ r++;
|
||||
pp->item_tint[i].rgb.blue = atoi(row[r]); r++;
|
||||
pp->item_tint[i].rgb.green = atoi(row[r]); r++;
|
||||
pp->item_tint[i].rgb.red = atoi(row[r]); r++;
|
||||
pp->item_tint[i].rgb.use_tint = atoi(row[r]);
|
||||
pp->item_tint[i].RGB.Blue = atoi(row[r]); r++;
|
||||
pp->item_tint[i].RGB.Green = atoi(row[r]); r++;
|
||||
pp->item_tint[i].RGB.Red = atoi(row[r]); r++;
|
||||
pp->item_tint[i].RGB.UseTint = atoi(row[r]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT 16", character_id);
|
||||
bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp)
|
||||
{
|
||||
std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT %u",
|
||||
character_id, EmuConstants::BANDOLIERS_SIZE);
|
||||
auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0;
|
||||
for (i = 0; i < EmuConstants::BANDOLIERS_COUNT; i++)
|
||||
for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++)
|
||||
pp->bandoliers[i].items[si].icon = 0;
|
||||
for (i = 0; i < EmuConstants::BANDOLIERS_SIZE; i++) {
|
||||
pp->bandoliers[i].Name[0] = '\0';
|
||||
for (int si = 0; si < EmuConstants::BANDOLIER_ITEM_COUNT; si++) {
|
||||
pp->bandoliers[i].Items[si].ID = 0;
|
||||
pp->bandoliers[i].Items[si].Icon = 0;
|
||||
pp->bandoliers[i].Items[si].Name[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
r = 0;
|
||||
i = atoi(row[r]); /* Bandolier ID */ r++;
|
||||
si = atoi(row[r]); /* Bandolier Slot */ r++;
|
||||
pp->bandoliers[i].items[si].item_id = atoi(row[r]); r++;
|
||||
pp->bandoliers[i].items[si].icon = atoi(row[r]); r++;
|
||||
strcpy(pp->bandoliers[i].name, row[r]); r++;
|
||||
si++;
|
||||
|
||||
const Item_Struct* item_data = database.GetItem(atoi(row[r]));
|
||||
if (item_data) {
|
||||
pp->bandoliers[i].Items[si].ID = item_data->ID; r++;
|
||||
pp->bandoliers[i].Items[si].Icon = atoi(row[r]); r++; // Must use db value in case an Ornamentation is assigned
|
||||
strncpy(pp->bandoliers[i].Items[si].Name, item_data->Name, 64);
|
||||
}
|
||||
else {
|
||||
pp->bandoliers[i].Items[si].ID = 0; r++;
|
||||
pp->bandoliers[i].Items[si].Icon = 0; r++;
|
||||
pp->bandoliers[i].Items[si].Name[0] = '\0';
|
||||
}
|
||||
strcpy(pp->bandoliers[i].Name, row[r]); r++;
|
||||
|
||||
si++; // What is this for!?
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1153,26 +1231,27 @@ bool ZoneDatabase::LoadCharacterTribute(uint32 character_id, PlayerProfile_Struc
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT 4", character_id);
|
||||
auto results = database.QueryDatabase(query); int i = 0;
|
||||
for (i = 0; i < EmuConstants::POTION_BELT_SIZE; i++){
|
||||
pp->potionbelt.items[i].icon = 0;
|
||||
pp->potionbelt.items[i].item_id = 0;
|
||||
strncpy(pp->potionbelt.items[i].item_name, "\0", 1);
|
||||
bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct *pp)
|
||||
{
|
||||
std::string query =
|
||||
StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT %u",
|
||||
character_id, EmuConstants::POTION_BELT_ITEM_COUNT);
|
||||
auto results = database.QueryDatabase(query);
|
||||
int i = 0;
|
||||
for (i = 0; i < EmuConstants::POTION_BELT_ITEM_COUNT; i++) {
|
||||
pp->potionbelt.Items[i].Icon = 0;
|
||||
pp->potionbelt.Items[i].ID = 0;
|
||||
pp->potionbelt.Items[i].Name[0] = '\0';
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]); /* Potion belt slot number */
|
||||
uint32 item_id = atoi(row[1]);
|
||||
const Item_Struct *item = database.GetItem(item_id);
|
||||
|
||||
if(!item)
|
||||
i = atoi(row[0]);
|
||||
const Item_Struct *item_data = database.GetItem(atoi(row[1]));
|
||||
if (!item_data)
|
||||
continue;
|
||||
|
||||
pp->potionbelt.items[i].item_id = item_id;
|
||||
pp->potionbelt.items[i].icon = atoi(row[2]);
|
||||
strncpy(pp->potionbelt.items[i].item_name, item->Name, 64);
|
||||
pp->potionbelt.Items[i].ID = item_data->ID;
|
||||
pp->potionbelt.Items[i].Icon = atoi(row[2]);
|
||||
strncpy(pp->potionbelt.Items[i].Name, item_data->Name, 64);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1266,7 +1345,8 @@ bool ZoneDatabase::SaveCharacterTribute(uint32 character_id, PlayerProfile_Struc
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name){
|
||||
bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name)
|
||||
{
|
||||
char bandolier_name_esc[64];
|
||||
DoEscapeString(bandolier_name_esc, bandolier_name, strlen(bandolier_name));
|
||||
std::string query = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%u, %u, %u, %u, %u,'%s')", character_id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name_esc);
|
||||
@@ -1275,7 +1355,8 @@ bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_i
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon) {
|
||||
bool ZoneDatabase::SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon)
|
||||
{
|
||||
std::string query = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%u, %u, %u, %u)", character_id, potion_id, item_id, icon);
|
||||
auto results = QueryDatabase(query);
|
||||
return true;
|
||||
@@ -1709,166 +1790,240 @@ bool ZoneDatabase::NoRentExpired(const char* name){
|
||||
return (seconds>1800);
|
||||
}
|
||||
|
||||
/* Searches npctable for matching id, and returns the item if found,
|
||||
* or nullptr otherwise. If id passed is 0, loads all npc_types for
|
||||
* the current zone, returning the last item added.
|
||||
*/
|
||||
const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
const NPCType *npc=nullptr;
|
||||
const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/)
|
||||
{
|
||||
const NPCType *npc = nullptr;
|
||||
|
||||
// If NPC is already in tree, return it.
|
||||
auto itr = zone->npctable.find(id);
|
||||
/* If there is a cached NPC entry, load it */
|
||||
auto itr = zone->npctable.find(npc_type_id);
|
||||
if(itr != zone->npctable.end())
|
||||
return itr->second;
|
||||
|
||||
// Otherwise, get NPCs from database.
|
||||
std::string where_condition = "";
|
||||
|
||||
if (bulk_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 "
|
||||
"WHERE spawn2.zone = '%s' and spawn2.version = %u GROUP BY npc_types.id", zone->GetShortName(), zone->GetInstanceVersion());
|
||||
}
|
||||
else{
|
||||
where_condition = StringFormat("WHERE id = %u", npc_type_id);
|
||||
}
|
||||
|
||||
// If id is 0, load all npc_types for the current zone,
|
||||
// according to spawn2.
|
||||
std::string query = StringFormat("SELECT npc_types.id, npc_types.name, npc_types.level, npc_types.race, "
|
||||
"npc_types.class, npc_types.hp, npc_types.mana, npc_types.gender, "
|
||||
"npc_types.texture, npc_types.helmtexture, npc_types.herosforgemodel, npc_types.size, "
|
||||
"npc_types.loottable_id, npc_types.merchant_id, npc_types.alt_currency_id, "
|
||||
"npc_types.adventure_template_id, npc_types.trap_template, npc_types.attack_speed, "
|
||||
"npc_types.STR, npc_types.STA, npc_types.DEX, npc_types.AGI, npc_types._INT, "
|
||||
"npc_types.WIS, npc_types.CHA, npc_types.MR, npc_types.CR, npc_types.DR, "
|
||||
"npc_types.FR, npc_types.PR, npc_types.Corrup, npc_types.PhR, "
|
||||
"npc_types.mindmg, npc_types.maxdmg, npc_types.attack_count, npc_types.special_abilities, "
|
||||
"npc_types.npc_spells_id, npc_types.npc_spells_effects_id, npc_types.d_melee_texture1, "
|
||||
"npc_types.d_melee_texture2, npc_types.ammo_idfile, npc_types.prim_melee_type, "
|
||||
"npc_types.sec_melee_type, npc_types.ranged_type, npc_types.runspeed, npc_types.findable, "
|
||||
"npc_types.trackable, npc_types.hp_regen_rate, npc_types.mana_regen_rate, "
|
||||
"npc_types.aggroradius, npc_types.assistradius, npc_types.bodytype, npc_types.npc_faction_id, "
|
||||
"npc_types.face, npc_types.luclin_hairstyle, npc_types.luclin_haircolor, "
|
||||
"npc_types.luclin_eyecolor, npc_types.luclin_eyecolor2, npc_types.luclin_beardcolor,"
|
||||
"npc_types.luclin_beard, npc_types.drakkin_heritage, npc_types.drakkin_tattoo, "
|
||||
"npc_types.drakkin_details, npc_types.armortint_id, "
|
||||
"npc_types.armortint_red, npc_types.armortint_green, npc_types.armortint_blue, "
|
||||
"npc_types.see_invis, npc_types.see_invis_undead, npc_types.lastname, "
|
||||
"npc_types.qglobal, npc_types.AC, npc_types.npc_aggro, npc_types.spawn_limit, "
|
||||
"npc_types.see_hide, npc_types.see_improved_hide, npc_types.ATK, npc_types.Accuracy, "
|
||||
"npc_types.Avoidance, npc_types.slow_mitigation, npc_types.maxlevel, npc_types.scalerate, "
|
||||
"npc_types.private_corpse, npc_types.unique_spawn_by_name, npc_types.underwater, "
|
||||
"npc_types.emoteid, npc_types.spellscale, npc_types.healscale, npc_types.no_target_hotkey, "
|
||||
"npc_types.raid_target, npc_types.attack_delay, npc_types.light FROM npc_types WHERE id = %d", id);
|
||||
std::string query = StringFormat("SELECT "
|
||||
"npc_types.id, "
|
||||
"npc_types.name, "
|
||||
"npc_types.level, "
|
||||
"npc_types.race, "
|
||||
"npc_types.class, "
|
||||
"npc_types.hp, "
|
||||
"npc_types.mana, "
|
||||
"npc_types.gender, "
|
||||
"npc_types.texture, "
|
||||
"npc_types.helmtexture, "
|
||||
"npc_types.herosforgemodel, "
|
||||
"npc_types.size, "
|
||||
"npc_types.loottable_id, "
|
||||
"npc_types.merchant_id, "
|
||||
"npc_types.alt_currency_id, "
|
||||
"npc_types.adventure_template_id, "
|
||||
"npc_types.trap_template, "
|
||||
"npc_types.attack_speed, "
|
||||
"npc_types.STR, "
|
||||
"npc_types.STA, "
|
||||
"npc_types.DEX, "
|
||||
"npc_types.AGI, "
|
||||
"npc_types._INT, "
|
||||
"npc_types.WIS, "
|
||||
"npc_types.CHA, "
|
||||
"npc_types.MR, "
|
||||
"npc_types.CR, "
|
||||
"npc_types.DR, "
|
||||
"npc_types.FR, "
|
||||
"npc_types.PR, "
|
||||
"npc_types.Corrup, "
|
||||
"npc_types.PhR, "
|
||||
"npc_types.mindmg, "
|
||||
"npc_types.maxdmg, "
|
||||
"npc_types.attack_count, "
|
||||
"npc_types.special_abilities, "
|
||||
"npc_types.npc_spells_id, "
|
||||
"npc_types.npc_spells_effects_id, "
|
||||
"npc_types.d_melee_texture1, "
|
||||
"npc_types.d_melee_texture2, "
|
||||
"npc_types.ammo_idfile, "
|
||||
"npc_types.prim_melee_type, "
|
||||
"npc_types.sec_melee_type, "
|
||||
"npc_types.ranged_type, "
|
||||
"npc_types.runspeed, "
|
||||
"npc_types.findable, "
|
||||
"npc_types.trackable, "
|
||||
"npc_types.hp_regen_rate, "
|
||||
"npc_types.mana_regen_rate, "
|
||||
"npc_types.aggroradius, "
|
||||
"npc_types.assistradius, "
|
||||
"npc_types.bodytype, "
|
||||
"npc_types.npc_faction_id, "
|
||||
"npc_types.face, "
|
||||
"npc_types.luclin_hairstyle, "
|
||||
"npc_types.luclin_haircolor, "
|
||||
"npc_types.luclin_eyecolor, "
|
||||
"npc_types.luclin_eyecolor2, "
|
||||
"npc_types.luclin_beardcolor, "
|
||||
"npc_types.luclin_beard, "
|
||||
"npc_types.drakkin_heritage, "
|
||||
"npc_types.drakkin_tattoo, "
|
||||
"npc_types.drakkin_details, "
|
||||
"npc_types.armortint_id, "
|
||||
"npc_types.armortint_red, "
|
||||
"npc_types.armortint_green, "
|
||||
"npc_types.armortint_blue, "
|
||||
"npc_types.see_invis, "
|
||||
"npc_types.see_invis_undead, "
|
||||
"npc_types.lastname, "
|
||||
"npc_types.qglobal, "
|
||||
"npc_types.AC, "
|
||||
"npc_types.npc_aggro, "
|
||||
"npc_types.spawn_limit, "
|
||||
"npc_types.see_hide, "
|
||||
"npc_types.see_improved_hide, "
|
||||
"npc_types.ATK, "
|
||||
"npc_types.Accuracy, "
|
||||
"npc_types.Avoidance, "
|
||||
"npc_types.slow_mitigation, "
|
||||
"npc_types.maxlevel, "
|
||||
"npc_types.scalerate, "
|
||||
"npc_types.private_corpse, "
|
||||
"npc_types.unique_spawn_by_name, "
|
||||
"npc_types.underwater, "
|
||||
"npc_types.emoteid, "
|
||||
"npc_types.spellscale, "
|
||||
"npc_types.healscale, "
|
||||
"npc_types.no_target_hotkey, "
|
||||
"npc_types.raid_target, "
|
||||
"npc_types.attack_delay, "
|
||||
"npc_types.light "
|
||||
"FROM npc_types %s",
|
||||
where_condition.c_str()
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
NPCType *tmpNPCType;
|
||||
tmpNPCType = new NPCType;
|
||||
memset (tmpNPCType, 0, sizeof *tmpNPCType);
|
||||
NPCType *temp_npctype_data;
|
||||
temp_npctype_data = new NPCType;
|
||||
memset (temp_npctype_data, 0, sizeof *temp_npctype_data);
|
||||
|
||||
tmpNPCType->npc_id = atoi(row[0]);
|
||||
temp_npctype_data->npc_id = atoi(row[0]);
|
||||
|
||||
strn0cpy(tmpNPCType->name, row[1], 50);
|
||||
strn0cpy(temp_npctype_data->name, row[1], 50);
|
||||
|
||||
tmpNPCType->level = atoi(row[2]);
|
||||
tmpNPCType->race = atoi(row[3]);
|
||||
tmpNPCType->class_ = atoi(row[4]);
|
||||
tmpNPCType->max_hp = atoi(row[5]);
|
||||
tmpNPCType->cur_hp = tmpNPCType->max_hp;
|
||||
tmpNPCType->Mana = atoi(row[6]);
|
||||
tmpNPCType->gender = atoi(row[7]);
|
||||
tmpNPCType->texture = atoi(row[8]);
|
||||
tmpNPCType->helmtexture = atoi(row[9]);
|
||||
tmpNPCType->herosforgemodel = atoul(row[10]);
|
||||
tmpNPCType->size = atof(row[11]);
|
||||
tmpNPCType->loottable_id = atoi(row[12]);
|
||||
tmpNPCType->merchanttype = atoi(row[13]);
|
||||
tmpNPCType->alt_currency_type = atoi(row[14]);
|
||||
tmpNPCType->adventure_template = atoi(row[15]);
|
||||
tmpNPCType->trap_template = atoi(row[16]);
|
||||
tmpNPCType->attack_speed = atof(row[17]);
|
||||
tmpNPCType->STR = atoi(row[18]);
|
||||
tmpNPCType->STA = atoi(row[19]);
|
||||
tmpNPCType->DEX = atoi(row[20]);
|
||||
tmpNPCType->AGI = atoi(row[21]);
|
||||
tmpNPCType->INT = atoi(row[22]);
|
||||
tmpNPCType->WIS = atoi(row[23]);
|
||||
tmpNPCType->CHA = atoi(row[24]);
|
||||
tmpNPCType->MR = atoi(row[25]);
|
||||
tmpNPCType->CR = atoi(row[26]);
|
||||
tmpNPCType->DR = atoi(row[27]);
|
||||
tmpNPCType->FR = atoi(row[28]);
|
||||
tmpNPCType->PR = atoi(row[29]);
|
||||
tmpNPCType->Corrup = atoi(row[30]);
|
||||
tmpNPCType->PhR = atoi(row[31]);
|
||||
tmpNPCType->min_dmg = atoi(row[32]);
|
||||
tmpNPCType->max_dmg = atoi(row[33]);
|
||||
tmpNPCType->attack_count = atoi(row[34]);
|
||||
temp_npctype_data->level = atoi(row[2]);
|
||||
temp_npctype_data->race = atoi(row[3]);
|
||||
temp_npctype_data->class_ = atoi(row[4]);
|
||||
temp_npctype_data->max_hp = atoi(row[5]);
|
||||
temp_npctype_data->cur_hp = temp_npctype_data->max_hp;
|
||||
temp_npctype_data->Mana = atoi(row[6]);
|
||||
temp_npctype_data->gender = atoi(row[7]);
|
||||
temp_npctype_data->texture = atoi(row[8]);
|
||||
temp_npctype_data->helmtexture = atoi(row[9]);
|
||||
temp_npctype_data->herosforgemodel = atoul(row[10]);
|
||||
temp_npctype_data->size = atof(row[11]);
|
||||
temp_npctype_data->loottable_id = atoi(row[12]);
|
||||
temp_npctype_data->merchanttype = atoi(row[13]);
|
||||
temp_npctype_data->alt_currency_type = atoi(row[14]);
|
||||
temp_npctype_data->adventure_template = atoi(row[15]);
|
||||
temp_npctype_data->trap_template = atoi(row[16]);
|
||||
temp_npctype_data->attack_speed = atof(row[17]);
|
||||
temp_npctype_data->STR = atoi(row[18]);
|
||||
temp_npctype_data->STA = atoi(row[19]);
|
||||
temp_npctype_data->DEX = atoi(row[20]);
|
||||
temp_npctype_data->AGI = atoi(row[21]);
|
||||
temp_npctype_data->INT = atoi(row[22]);
|
||||
temp_npctype_data->WIS = atoi(row[23]);
|
||||
temp_npctype_data->CHA = atoi(row[24]);
|
||||
temp_npctype_data->MR = atoi(row[25]);
|
||||
temp_npctype_data->CR = atoi(row[26]);
|
||||
temp_npctype_data->DR = atoi(row[27]);
|
||||
temp_npctype_data->FR = atoi(row[28]);
|
||||
temp_npctype_data->PR = atoi(row[29]);
|
||||
temp_npctype_data->Corrup = atoi(row[30]);
|
||||
temp_npctype_data->PhR = atoi(row[31]);
|
||||
temp_npctype_data->min_dmg = atoi(row[32]);
|
||||
temp_npctype_data->max_dmg = atoi(row[33]);
|
||||
temp_npctype_data->attack_count = atoi(row[34]);
|
||||
|
||||
if (row[35] != nullptr)
|
||||
strn0cpy(tmpNPCType->special_abilities, row[35], 512);
|
||||
strn0cpy(temp_npctype_data->special_abilities, row[35], 512);
|
||||
else
|
||||
tmpNPCType->special_abilities[0] = '\0';
|
||||
temp_npctype_data->special_abilities[0] = '\0';
|
||||
|
||||
tmpNPCType->npc_spells_id = atoi(row[36]);
|
||||
tmpNPCType->npc_spells_effects_id = atoi(row[37]);
|
||||
tmpNPCType->d_melee_texture1 = atoi(row[38]);
|
||||
tmpNPCType->d_melee_texture2 = atoi(row[39]);
|
||||
strn0cpy(tmpNPCType->ammo_idfile, row[40], 30);
|
||||
tmpNPCType->prim_melee_type = atoi(row[41]);
|
||||
tmpNPCType->sec_melee_type = atoi(row[42]);
|
||||
tmpNPCType->ranged_type = atoi(row[43]);
|
||||
tmpNPCType->runspeed= atof(row[44]);
|
||||
tmpNPCType->findable = atoi(row[45]) == 0? false : true;
|
||||
tmpNPCType->trackable = atoi(row[46]) == 0? false : true;
|
||||
tmpNPCType->hp_regen = atoi(row[47]);
|
||||
tmpNPCType->mana_regen = atoi(row[48]);
|
||||
temp_npctype_data->npc_spells_id = atoi(row[36]);
|
||||
temp_npctype_data->npc_spells_effects_id = atoi(row[37]);
|
||||
temp_npctype_data->d_melee_texture1 = atoi(row[38]);
|
||||
temp_npctype_data->d_melee_texture2 = atoi(row[39]);
|
||||
strn0cpy(temp_npctype_data->ammo_idfile, row[40], 30);
|
||||
temp_npctype_data->prim_melee_type = atoi(row[41]);
|
||||
temp_npctype_data->sec_melee_type = atoi(row[42]);
|
||||
temp_npctype_data->ranged_type = atoi(row[43]);
|
||||
temp_npctype_data->runspeed= atof(row[44]);
|
||||
temp_npctype_data->findable = atoi(row[45]) == 0? false : true;
|
||||
temp_npctype_data->trackable = atoi(row[46]) == 0? false : true;
|
||||
temp_npctype_data->hp_regen = atoi(row[47]);
|
||||
temp_npctype_data->mana_regen = atoi(row[48]);
|
||||
|
||||
// set default value for aggroradius
|
||||
tmpNPCType->aggroradius = (int32)atoi(row[49]);
|
||||
if (tmpNPCType->aggroradius <= 0)
|
||||
tmpNPCType->aggroradius = 70;
|
||||
temp_npctype_data->aggroradius = (int32)atoi(row[49]);
|
||||
if (temp_npctype_data->aggroradius <= 0)
|
||||
temp_npctype_data->aggroradius = 70;
|
||||
|
||||
tmpNPCType->assistradius = (int32)atoi(row[50]);
|
||||
if (tmpNPCType->assistradius <= 0)
|
||||
tmpNPCType->assistradius = tmpNPCType->aggroradius;
|
||||
temp_npctype_data->assistradius = (int32)atoi(row[50]);
|
||||
if (temp_npctype_data->assistradius <= 0)
|
||||
temp_npctype_data->assistradius = temp_npctype_data->aggroradius;
|
||||
|
||||
if (row[51] && strlen(row[51]))
|
||||
tmpNPCType->bodytype = (uint8)atoi(row[51]);
|
||||
temp_npctype_data->bodytype = (uint8)atoi(row[51]);
|
||||
else
|
||||
tmpNPCType->bodytype = 0;
|
||||
temp_npctype_data->bodytype = 0;
|
||||
|
||||
tmpNPCType->npc_faction_id = atoi(row[52]);
|
||||
temp_npctype_data->npc_faction_id = atoi(row[52]);
|
||||
|
||||
tmpNPCType->luclinface = atoi(row[53]);
|
||||
tmpNPCType->hairstyle = atoi(row[54]);
|
||||
tmpNPCType->haircolor = atoi(row[55]);
|
||||
tmpNPCType->eyecolor1 = atoi(row[56]);
|
||||
tmpNPCType->eyecolor2 = atoi(row[57]);
|
||||
tmpNPCType->beardcolor = atoi(row[58]);
|
||||
tmpNPCType->beard = atoi(row[59]);
|
||||
tmpNPCType->drakkin_heritage = atoi(row[60]);
|
||||
tmpNPCType->drakkin_tattoo = atoi(row[61]);
|
||||
tmpNPCType->drakkin_details = atoi(row[62]);
|
||||
temp_npctype_data->luclinface = atoi(row[53]);
|
||||
temp_npctype_data->hairstyle = atoi(row[54]);
|
||||
temp_npctype_data->haircolor = atoi(row[55]);
|
||||
temp_npctype_data->eyecolor1 = atoi(row[56]);
|
||||
temp_npctype_data->eyecolor2 = atoi(row[57]);
|
||||
temp_npctype_data->beardcolor = atoi(row[58]);
|
||||
temp_npctype_data->beard = atoi(row[59]);
|
||||
temp_npctype_data->drakkin_heritage = atoi(row[60]);
|
||||
temp_npctype_data->drakkin_tattoo = atoi(row[61]);
|
||||
temp_npctype_data->drakkin_details = atoi(row[62]);
|
||||
|
||||
uint32 armor_tint_id = atoi(row[63]);
|
||||
|
||||
tmpNPCType->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16;
|
||||
tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8;
|
||||
tmpNPCType->armor_tint[0] |= (atoi(row[66]) & 0xFF);
|
||||
tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0;
|
||||
temp_npctype_data->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16;
|
||||
temp_npctype_data->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8;
|
||||
temp_npctype_data->armor_tint[0] |= (atoi(row[66]) & 0xFF);
|
||||
temp_npctype_data->armor_tint[0] |= (temp_npctype_data->armor_tint[0]) ? (0xFF << 24) : 0;
|
||||
|
||||
if (armor_tint_id != 0)
|
||||
{
|
||||
std::string armortint_query = StringFormat("SELECT red1h, grn1h, blu1h, "
|
||||
"red2c, grn2c, blu2c, "
|
||||
"red3a, grn3a, blu3a, "
|
||||
"red4b, grn4b, blu4b, "
|
||||
"red5g, grn5g, blu5g, "
|
||||
"red6l, grn6l, blu6l, "
|
||||
"red7f, grn7f, blu7f, "
|
||||
"red8x, grn8x, blu8x, "
|
||||
"red9x, grn9x, blu9x "
|
||||
"FROM npc_types_tint WHERE id = %d",
|
||||
armor_tint_id);
|
||||
if (armor_tint_id != 0) {
|
||||
std::string armortint_query = StringFormat(
|
||||
"SELECT red1h, grn1h, blu1h, "
|
||||
"red2c, grn2c, blu2c, "
|
||||
"red3a, grn3a, blu3a, "
|
||||
"red4b, grn4b, blu4b, "
|
||||
"red5g, grn5g, blu5g, "
|
||||
"red6l, grn6l, blu6l, "
|
||||
"red7f, grn7f, blu7f, "
|
||||
"red8x, grn8x, blu8x, "
|
||||
"red9x, grn9x, blu9x "
|
||||
"FROM npc_types_tint WHERE id = %d",
|
||||
armor_tint_id);
|
||||
auto armortint_results = QueryDatabase(armortint_query);
|
||||
if (!armortint_results.Success() || armortint_results.RowCount() == 0)
|
||||
armor_tint_id = 0;
|
||||
@@ -1876,60 +2031,59 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
auto armorTint_row = armortint_results.begin();
|
||||
|
||||
for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) {
|
||||
tmpNPCType->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16;
|
||||
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8;
|
||||
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]);
|
||||
tmpNPCType->armor_tint[index] |= (tmpNPCType->armor_tint[index]) ? (0xFF << 24) : 0;
|
||||
temp_npctype_data->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16;
|
||||
temp_npctype_data->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8;
|
||||
temp_npctype_data->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]);
|
||||
temp_npctype_data->armor_tint[index] |= (temp_npctype_data->armor_tint[index]) ? (0xFF << 24) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Try loading npc_types tint fields if armor tint is 0 or query failed to get results
|
||||
if (armor_tint_id == 0)
|
||||
{
|
||||
for (int index = MaterialChest; index < _MaterialCount; index++)
|
||||
{
|
||||
tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0];
|
||||
if (armor_tint_id == 0) {
|
||||
for (int index = MaterialChest; index < _MaterialCount; index++) {
|
||||
temp_npctype_data->armor_tint[index] = temp_npctype_data->armor_tint[0];
|
||||
}
|
||||
}
|
||||
|
||||
tmpNPCType->see_invis = atoi(row[67]);
|
||||
tmpNPCType->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag
|
||||
if (row[69] != nullptr)
|
||||
strn0cpy(tmpNPCType->lastname, row[69], 32);
|
||||
temp_npctype_data->see_invis = atoi(row[67]);
|
||||
temp_npctype_data->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag
|
||||
|
||||
tmpNPCType->qglobal = atoi(row[70]) == 0? false: true; // qglobal
|
||||
tmpNPCType->AC = atoi(row[71]);
|
||||
tmpNPCType->npc_aggro = atoi(row[72]) == 0? false: true;
|
||||
tmpNPCType->spawn_limit = atoi(row[73]);
|
||||
tmpNPCType->see_hide = atoi(row[74]) == 0? false: true;
|
||||
tmpNPCType->see_improved_hide = atoi(row[75]) == 0? false: true;
|
||||
tmpNPCType->ATK = atoi(row[76]);
|
||||
tmpNPCType->accuracy_rating = atoi(row[77]);
|
||||
tmpNPCType->avoidance_rating = atoi(row[78]);
|
||||
tmpNPCType->slow_mitigation = atoi(row[79]);
|
||||
tmpNPCType->maxlevel = atoi(row[80]);
|
||||
tmpNPCType->scalerate = atoi(row[81]);
|
||||
tmpNPCType->private_corpse = atoi(row[82]) == 1 ? true: false;
|
||||
tmpNPCType->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false;
|
||||
tmpNPCType->underwater = atoi(row[84]) == 1 ? true: false;
|
||||
tmpNPCType->emoteid = atoi(row[85]);
|
||||
tmpNPCType->spellscale = atoi(row[86]);
|
||||
tmpNPCType->healscale = atoi(row[87]);
|
||||
tmpNPCType->no_target_hotkey = atoi(row[88]) == 1 ? true: false;
|
||||
tmpNPCType->raid_target = atoi(row[89]) == 0 ? false: true;
|
||||
tmpNPCType->attack_delay = atoi(row[90]);
|
||||
tmpNPCType->light = (atoi(row[91]) & 0x0F);
|
||||
if (row[69] != nullptr)
|
||||
strn0cpy(temp_npctype_data->lastname, row[69], 32);
|
||||
|
||||
temp_npctype_data->qglobal = atoi(row[70]) == 0? false: true; // qglobal
|
||||
temp_npctype_data->AC = atoi(row[71]);
|
||||
temp_npctype_data->npc_aggro = atoi(row[72]) == 0? false: true;
|
||||
temp_npctype_data->spawn_limit = atoi(row[73]);
|
||||
temp_npctype_data->see_hide = atoi(row[74]) == 0? false: true;
|
||||
temp_npctype_data->see_improved_hide = atoi(row[75]) == 0? false: true;
|
||||
temp_npctype_data->ATK = atoi(row[76]);
|
||||
temp_npctype_data->accuracy_rating = atoi(row[77]);
|
||||
temp_npctype_data->avoidance_rating = atoi(row[78]);
|
||||
temp_npctype_data->slow_mitigation = atoi(row[79]);
|
||||
temp_npctype_data->maxlevel = atoi(row[80]);
|
||||
temp_npctype_data->scalerate = atoi(row[81]);
|
||||
temp_npctype_data->private_corpse = atoi(row[82]) == 1 ? true: false;
|
||||
temp_npctype_data->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false;
|
||||
temp_npctype_data->underwater = atoi(row[84]) == 1 ? true: false;
|
||||
temp_npctype_data->emoteid = atoi(row[85]);
|
||||
temp_npctype_data->spellscale = atoi(row[86]);
|
||||
temp_npctype_data->healscale = atoi(row[87]);
|
||||
temp_npctype_data->no_target_hotkey = atoi(row[88]) == 1 ? true: false;
|
||||
temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false: true;
|
||||
temp_npctype_data->attack_delay = atoi(row[90]);
|
||||
temp_npctype_data->light = (atoi(row[91]) & 0x0F);
|
||||
|
||||
// If NPC with duplicate NPC id already in table,
|
||||
// free item we attempted to add.
|
||||
if (zone->npctable.find(tmpNPCType->npc_id) != zone->npctable.end()) {
|
||||
std::cerr << "Error loading duplicate NPC " << tmpNPCType->npc_id << std::endl;
|
||||
delete tmpNPCType;
|
||||
if (zone->npctable.find(temp_npctype_data->npc_id) != zone->npctable.end()) {
|
||||
std::cerr << "Error loading duplicate NPC " << temp_npctype_data->npc_id << std::endl;
|
||||
delete temp_npctype_data;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
zone->npctable[tmpNPCType->npc_id]=tmpNPCType;
|
||||
npc = tmpNPCType;
|
||||
zone->npctable[temp_npctype_data->npc_id] = temp_npctype_data;
|
||||
npc = temp_npctype_data;
|
||||
}
|
||||
|
||||
return npc;
|
||||
@@ -3246,7 +3400,7 @@ bool ZoneDatabase::LoadFactionData()
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
max_faction = atoi(row[0]);
|
||||
max_faction = row[0] ? atoi(row[0]) : 0;
|
||||
faction_array = new Faction*[max_faction+1];
|
||||
for(unsigned int index=0; index<max_faction; index++)
|
||||
faction_array[index] = nullptr;
|
||||
@@ -3396,9 +3550,9 @@ uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const c
|
||||
dbpc->plat, dbpc->haircolor, dbpc->beardcolor, dbpc->eyecolor1,
|
||||
dbpc->eyecolor2, dbpc->hairstyle, dbpc->face, dbpc->beard,
|
||||
dbpc->drakkin_heritage, dbpc->drakkin_tattoo, dbpc->drakkin_details,
|
||||
dbpc->item_tint[0].color, dbpc->item_tint[1].color, dbpc->item_tint[2].color,
|
||||
dbpc->item_tint[3].color, dbpc->item_tint[4].color, dbpc->item_tint[5].color,
|
||||
dbpc->item_tint[6].color, dbpc->item_tint[7].color, dbpc->item_tint[8].color,
|
||||
dbpc->item_tint[0].Color, dbpc->item_tint[1].Color, dbpc->item_tint[2].Color,
|
||||
dbpc->item_tint[3].Color, dbpc->item_tint[4].Color, dbpc->item_tint[5].Color,
|
||||
dbpc->item_tint[6].Color, dbpc->item_tint[7].Color, dbpc->item_tint[8].Color,
|
||||
db_id);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
@@ -3489,15 +3643,15 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
|
||||
dbpc->drakkin_heritage,
|
||||
dbpc->drakkin_tattoo,
|
||||
dbpc->drakkin_details,
|
||||
dbpc->item_tint[0].color,
|
||||
dbpc->item_tint[1].color,
|
||||
dbpc->item_tint[2].color,
|
||||
dbpc->item_tint[3].color,
|
||||
dbpc->item_tint[4].color,
|
||||
dbpc->item_tint[5].color,
|
||||
dbpc->item_tint[6].color,
|
||||
dbpc->item_tint[7].color,
|
||||
dbpc->item_tint[8].color
|
||||
dbpc->item_tint[0].Color,
|
||||
dbpc->item_tint[1].Color,
|
||||
dbpc->item_tint[2].Color,
|
||||
dbpc->item_tint[3].Color,
|
||||
dbpc->item_tint[4].Color,
|
||||
dbpc->item_tint[5].Color,
|
||||
dbpc->item_tint[6].Color,
|
||||
dbpc->item_tint[7].Color,
|
||||
dbpc->item_tint[8].Color
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
uint32 last_insert_id = results.LastInsertedID();
|
||||
@@ -3669,15 +3823,15 @@ bool ZoneDatabase::LoadCharacterCorpseData(uint32 corpse_id, PlayerCorpse_Struct
|
||||
pcs->drakkin_heritage = atoul(row[i++]); // drakkin_heritage,
|
||||
pcs->drakkin_tattoo = atoul(row[i++]); // drakkin_tattoo,
|
||||
pcs->drakkin_details = atoul(row[i++]); // drakkin_details,
|
||||
pcs->item_tint[0].color = atoul(row[i++]); // wc_1,
|
||||
pcs->item_tint[1].color = atoul(row[i++]); // wc_2,
|
||||
pcs->item_tint[2].color = atoul(row[i++]); // wc_3,
|
||||
pcs->item_tint[3].color = atoul(row[i++]); // wc_4,
|
||||
pcs->item_tint[4].color = atoul(row[i++]); // wc_5,
|
||||
pcs->item_tint[5].color = atoul(row[i++]); // wc_6,
|
||||
pcs->item_tint[6].color = atoul(row[i++]); // wc_7,
|
||||
pcs->item_tint[7].color = atoul(row[i++]); // wc_8,
|
||||
pcs->item_tint[8].color = atoul(row[i++]); // wc_9
|
||||
pcs->item_tint[0].Color = atoul(row[i++]); // wc_1,
|
||||
pcs->item_tint[1].Color = atoul(row[i++]); // wc_2,
|
||||
pcs->item_tint[2].Color = atoul(row[i++]); // wc_3,
|
||||
pcs->item_tint[3].Color = atoul(row[i++]); // wc_4,
|
||||
pcs->item_tint[4].Color = atoul(row[i++]); // wc_5,
|
||||
pcs->item_tint[5].Color = atoul(row[i++]); // wc_6,
|
||||
pcs->item_tint[6].Color = atoul(row[i++]); // wc_7,
|
||||
pcs->item_tint[7].Color = atoul(row[i++]); // wc_8,
|
||||
pcs->item_tint[8].Color = atoul(row[i++]); // wc_9
|
||||
}
|
||||
query = StringFormat(
|
||||
"SELECT \n"
|
||||
|
||||
+2
-2
@@ -365,7 +365,7 @@ public:
|
||||
bool PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay = 0);
|
||||
Spawn2* LoadSpawn2(LinkedList<Spawn2*> &spawn2_list, uint32 spawn2id, uint32 timeleft);
|
||||
bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value);
|
||||
void UpdateSpawn2Timeleft(uint32 id, uint16 instance_id,uint32 timeleft);
|
||||
void UpdateRespawnTime(uint32 id, uint16 instance_id,uint32 timeleft);
|
||||
uint32 GetSpawnTimeLeft(uint32 id, uint16 instance_id);
|
||||
void UpdateSpawn2Status(uint32 id, uint8 new_status);
|
||||
|
||||
@@ -405,7 +405,7 @@ public:
|
||||
|
||||
DBnpcspells_Struct* GetNPCSpells(uint32 iDBSpellsID);
|
||||
DBnpcspellseffects_Struct* GetNPCSpellsEffects(uint32 iDBSpellsEffectsID);
|
||||
const NPCType* GetNPCType(uint32 id);
|
||||
const NPCType* LoadNPCTypesData(uint32 id, bool bulk_load = false);
|
||||
|
||||
/* Mercs */
|
||||
const NPCType* GetMercType(uint32 id, uint16 raceid, uint32 clientlevel);
|
||||
|
||||
+1
-1
@@ -182,7 +182,7 @@ struct PlayerCorpse_Struct {
|
||||
struct Door {
|
||||
uint32 db_id;
|
||||
uint8 door_id;
|
||||
char zone_name[16];
|
||||
char zone_name[32];
|
||||
char door_name[32];
|
||||
float pos_x;
|
||||
float pos_y;
|
||||
|
||||
+7
-3
@@ -587,10 +587,14 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z
|
||||
|
||||
// If we are SoF and later and are respawning from hover, we want the real zone ID, else zero to use the old hack.
|
||||
//
|
||||
if((GetClientVersionBit() & BIT_SoFAndLater) && (!RuleB(Character, RespawnFromHover) || !IsHoveringForRespawn()))
|
||||
gmg->bind_zone_id = 0;
|
||||
else
|
||||
if(zone->GetZoneID() == zoneID) {
|
||||
if((GetClientVersionBit() & BIT_SoFAndLater) && (!RuleB(Character, RespawnFromHover) || !IsHoveringForRespawn()))
|
||||
gmg->bind_zone_id = 0;
|
||||
else
|
||||
gmg->bind_zone_id = zoneID;
|
||||
} else {
|
||||
gmg->bind_zone_id = zoneID;
|
||||
}
|
||||
|
||||
gmg->x = x;
|
||||
gmg->y = y;
|
||||
|
||||
Reference in New Issue
Block a user