Merge branch 'master' into inv2

This commit is contained in:
KimLS 2015-04-07 16:29:07 -07:00
commit ff3cb9fc54
30 changed files with 407 additions and 133 deletions

View File

@ -1,5 +1,9 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 03/29/2015 ==
Secrets: Identified the Target Ring fields for RoF/RoF2.
Secrets: Added a perl accessor for the last target ring position received from the client. Usage: $client->GetTargetRingX(), $client->GetTargetRingY(), $client->GetTargetRingZ()
== 03/12/2015 ==
Akkadius: [eqemu_update.pl V7] Add Option 9) LUA Modules - Download latest LUA Modules (Required for Lua)

View File

@ -1287,8 +1287,8 @@ struct RequestClientZoneChange_Struct {
struct Animation_Struct {
/*00*/ uint16 spawnid;
/*02*/ uint8 action;
/*03*/ uint8 value;
/*02*/ uint8 speed;
/*03*/ uint8 action;
/*04*/
};

View File

@ -227,8 +227,8 @@ namespace RoF
SETUP_DIRECT_ENCODE(Animation_Struct, structs::Animation_Struct);
OUT(spawnid);
OUT(value);
OUT(action);
OUT(speed);
FINISH_ENCODE();
}
@ -479,7 +479,7 @@ namespace RoF
eq->slot = 13;
else
OUT(slot);
OUT(spell_id);
eq->inventoryslot = ServerToRoFSlot(emu->inventoryslot);
//OUT(inventoryslot);
@ -703,7 +703,7 @@ namespace RoF
{
SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
OUT(count);
for (uint32 i = 0; i < emu->count; ++i)
@ -1250,7 +1250,7 @@ namespace RoF
switch (emu_e->rank) {
case 0: { e->rank = htonl(5); break; } // GUILD_MEMBER 0
case 1: { e->rank = htonl(3); break; } // GUILD_OFFICER 1
case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2
case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2
default: { e->rank = htonl(emu_e->rank); break; } // GUILD_NONE
}
@ -2990,7 +2990,7 @@ namespace RoF
eq_cse->Enabled = emu_cse->Enabled;
eq_cse->LastLogin = emu_cse->LastLogin;
eq_cse->Unknown2 = emu_cse->Unknown2;
emu_ptr += sizeof(CharacterSelectEntry_Struct);
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
}
@ -3047,7 +3047,7 @@ namespace RoF
switch (emu->Rank) {
case 0: { eq->Rank = 5; break; } // GUILD_MEMBER 0
case 1: { eq->Rank = 3; break; } // GUILD_OFFICER 1
case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2
case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2
default: { eq->Rank = emu->Rank; break; }
}
@ -3314,7 +3314,7 @@ namespace RoF
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
#if 0 // original code
EQApplicationPacket *in = *p;
*p = nullptr;
@ -3778,7 +3778,7 @@ namespace RoF
}
ENCODE(OP_ZoneEntry) { ENCODE_FORWARD(OP_ZoneSpawns); }
ENCODE(OP_ZonePlayerToBind)
{
SETUP_VAR_ENCODE(ZonePlayerToBind_Struct);
@ -3969,8 +3969,8 @@ namespace RoF
switch (emu->guildrank) {
case 0: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 5); break; } // GUILD_MEMBER 0
case 1: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 3); break; } // GUILD_OFFICER 1
case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2
default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } //
case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2
default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } //
}
}
@ -4119,6 +4119,18 @@ namespace RoF
FINISH_DIRECT_DECODE();
}
DECODE(OP_Animation)
{
DECODE_LENGTH_EXACT(structs::Animation_Struct);
SETUP_DIRECT_DECODE(Animation_Struct, structs::Animation_Struct);
IN(spawnid);
IN(action);
IN(speed);
FINISH_DIRECT_DECODE();
}
DECODE(OP_ApplyPoison)
{
DECODE_LENGTH_EXACT(structs::ApplyPoison_Struct);
@ -4231,12 +4243,16 @@ namespace RoF
emu->slot = 10;
else
IN(slot);
IN(spell_id);
emu->inventoryslot = RoFToServerSlot(eq->inventoryslot);
//IN(inventoryslot);
IN(target_id);
IN(y_pos);
IN(x_pos);
IN(z_pos);
FINISH_DIRECT_DECODE();
}
@ -5102,7 +5118,7 @@ namespace RoF
hdrf.ItemClass = item->ItemClass;
ss.write((const char*)&hdrf, sizeof(RoF::structs::ItemSerializationHeaderFinish));
if (strlen(item->Name) > 0)
{
ss.write(item->Name, strlen(item->Name));

View File

@ -160,7 +160,7 @@ namespace RoF2
eq->exit_url_length = emu->exit_url_length;
eq->exit_url_length2 = emu->exit_url_length2;
FINISH_ENCODE();
}
@ -185,7 +185,7 @@ namespace RoF2
{
eq->entries[i] = 1;
}
FINISH_ENCODE();
}
@ -295,8 +295,8 @@ namespace RoF2
SETUP_DIRECT_ENCODE(Animation_Struct, structs::Animation_Struct);
OUT(spawnid);
OUT(value);
OUT(action);
OUT(speed);
FINISH_ENCODE();
}
@ -515,6 +515,11 @@ namespace RoF2
{
buffslot += 17;
}
// TODO: We should really just deal with these "server side"
// so we can have clients not limited to other clients.
// This fixes discs, songs were changed to 20
if (buffslot == 54)
buffslot = 62;
__packet->WriteUInt32(buffslot);
__packet->WriteUInt32(emu->entries[i].spell_id);
@ -547,7 +552,7 @@ namespace RoF2
eq->slot = 13;
else
OUT(slot);
OUT(spell_id);
eq->inventoryslot = ServerToRoF2Slot(emu->inventoryslot);
//OUT(inventoryslot);
@ -571,7 +576,7 @@ namespace RoF2
//in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
in->size = strlen(emu->sender) + strlen(emu->targetname) + new_message.length() + 39;
in->pBuffer = new unsigned char[in->size];
char *OutBuffer = (char *)in->pBuffer;
@ -739,7 +744,7 @@ namespace RoF2
{
SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
OUT(count);
for (uint32 i = 0; i < emu->count; ++i)
@ -1286,7 +1291,7 @@ namespace RoF2
switch (emu_e->rank) {
case 0: { e->rank = htonl(5); break; } // GUILD_MEMBER 0
case 1: { e->rank = htonl(3); break; } // GUILD_OFFICER 1
case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2
case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2
default: { e->rank = htonl(emu_e->rank); break; } // GUILD_NONE
}
@ -2375,9 +2380,9 @@ namespace RoF2
outapp->WriteSInt32(-1);
}
}
outapp->WriteUInt32(consts::POTION_BELT_ITEM_COUNT);
// Copy potion belt where server and client indexes converge
for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) {
outapp->WriteString(emu->potionbelt.Items[r].Name);
@ -2473,7 +2478,7 @@ namespace RoF2
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(emu->gm);
outapp->WriteUInt32(emu->guild_id);
outapp->WriteUInt8(emu->guildrank); // guildrank
outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt8(0); // Unknown
@ -2528,12 +2533,12 @@ namespace RoF2
outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown
for (uint32 r = 0; r < 125; r++)
{
outapp->WriteUInt8(0); // Unknown
}
outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(emu->currentRadCrystals);
@ -3099,7 +3104,7 @@ namespace RoF2
switch (emu->Rank) {
case 0: { eq->Rank = 5; break; } // GUILD_MEMBER 0
case 1: { eq->Rank = 3; break; } // GUILD_OFFICER 1
case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2
case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2
default: { eq->Rank = emu->Rank; break; }
}
@ -3905,7 +3910,7 @@ namespace RoF2
}
ENCODE(OP_ZoneEntry) { ENCODE_FORWARD(OP_ZoneSpawns); }
ENCODE(OP_ZonePlayerToBind)
{
SETUP_VAR_ENCODE(ZonePlayerToBind_Struct);
@ -4096,8 +4101,8 @@ namespace RoF2
switch (emu->guildrank) {
case 0: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 5); break; } // GUILD_MEMBER 0
case 1: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 3); break; } // GUILD_OFFICER 1
case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2
default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } //
case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2
default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } //
}
}
@ -4180,7 +4185,7 @@ namespace RoF2
Position->z = emu->z;
Position->animation = emu->animation;
Position->deltaY = emu->deltaY;
Buffer += sizeof(structs::Spawn_Struct_Position);
if (strlen(emu->title))
@ -4251,6 +4256,18 @@ namespace RoF2
FINISH_DIRECT_DECODE();
}
DECODE(OP_Animation)
{
DECODE_LENGTH_EXACT(structs::Animation_Struct);
SETUP_DIRECT_DECODE(Animation_Struct, structs::Animation_Struct);
IN(spawnid);
IN(action);
IN(speed);
FINISH_DIRECT_DECODE();
}
DECODE(OP_ApplyPoison)
{
DECODE_LENGTH_EXACT(structs::ApplyPoison_Struct);
@ -4362,11 +4379,14 @@ namespace RoF2
emu->slot = 10;
else
IN(slot);
IN(spell_id);
emu->inventoryslot = RoF2ToServerSlot(eq->inventoryslot);
//IN(inventoryslot);
IN(target_id);
IN(y_pos);
IN(x_pos);
IN(z_pos);
FINISH_DIRECT_DECODE();
}
@ -5090,7 +5110,7 @@ namespace RoF2
IN(Quantity);
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct (Unknowns) Unknown004 %d, Unknown008 %d, Unknown012 %d, Unknown076 %d, Unknown276 %d",
eq->Unknown004, eq->Unknown008, eq->Unknown012, eq->Unknown076, eq->Unknown276);
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, eq->ItemName);
FINISH_DIRECT_DECODE();
@ -5720,7 +5740,7 @@ namespace RoF2
RoF2Slot.SlotType = maps::MapPossessions;
RoF2Slot.MainSlot = serverSlot;
}
if (serverSlot == MainPowerSource)
RoF2Slot.MainSlot = slots::MainPowerSource;

View File

@ -124,6 +124,7 @@ E(OP_ZoneSpawns)
D(OP_AdventureMerchantSell)
D(OP_AltCurrencySell)
D(OP_AltCurrencySellSelection)
D(OP_Animation)
D(OP_ApplyPoison)
D(OP_AugmentInfo)
D(OP_AugmentItem)

View File

@ -658,7 +658,10 @@ struct CastSpell_Struct
/*04*/ uint32 spell_id;
/*08*/ ItemSlotStruct inventoryslot; // slot for clicky item, Seen unknown of 131 = normal cast
/*20*/ uint32 target_id;
/*24*/ uint32 cs_unknown[5];
/*24*/ uint32 cs_unknown[2];
/*32*/ float y_pos;
/*36*/ float x_pos;
/*40*/ float z_pos;
/*44*/
};
@ -1415,8 +1418,8 @@ struct RequestClientZoneChange_Struct {
struct Animation_Struct {
/*00*/ uint16 spawnid;
/*02*/ uint8 value;
/*03*/ uint8 action;
/*02*/ uint8 action;
/*03*/ uint8 speed;
/*04*/
};
@ -4186,9 +4189,11 @@ struct Arrow_Struct {
/*068*/ uint8 unknown068;
/*069*/ uint8 unknown069;
/*070*/ uint8 unknown070;
/*071*/ uint8 item_type;
/*072*/ uint8 skill;
/*073*/ uint8 unknown073[16];
/*071*/ uint8 unknown071;
/*072*/ uint8 unknown072;
/*073*/ uint8 skill;
/*074*/ uint8 item_type;
/*075*/ uint8 unknown075[14];
/*089*/ char model_name[27];
/*116*/
};

View File

@ -109,6 +109,7 @@ E(OP_ZoneSpawns)
D(OP_AdventureMerchantSell)
D(OP_AltCurrencySell)
D(OP_AltCurrencySellSelection)
D(OP_Animation)
D(OP_ApplyPoison)
D(OP_AugmentInfo)
D(OP_AugmentItem)

View File

@ -647,7 +647,10 @@ struct CastSpell_Struct
/*04*/ uint32 spell_id;
/*08*/ ItemSlotStruct inventoryslot; // slot for clicky item, Seen unknown of 131 = normal cast
/*20*/ uint32 target_id;
/*24*/ uint32 cs_unknown[5];
/*24*/ uint32 cs_unknown[2];
/*32*/ float y_pos;
/*36*/ float x_pos;
/*40*/ float z_pos;
/*44*/
};
@ -1445,8 +1448,8 @@ struct RequestClientZoneChange_Struct {
struct Animation_Struct {
/*00*/ uint16 spawnid;
/*02*/ uint8 value;
/*03*/ uint8 action;
/*02*/ uint8 action;
/*03*/ uint8 speed;
/*04*/
};

View File

@ -1205,8 +1205,8 @@ struct RequestClientZoneChange_Struct {
struct Animation_Struct {
/*00*/ uint16 spawnid;
/*02*/ uint8 action;
/*03*/ uint8 value;
/*02*/ uint8 speed;
/*03*/ uint8 action;
/*04*/
};

View File

@ -1182,8 +1182,8 @@ struct RequestClientZoneChange_Struct {
struct Animation_Struct {
/*00*/ uint16 spawnid;
/*02*/ uint8 action;
/*03*/ uint8 value;
/*02*/ uint8 speed;
/*03*/ uint8 action;
/*04*/
};

View File

@ -1062,8 +1062,8 @@ struct RequestClientZoneChange_Struct {
struct Animation_Struct {
/*00*/ uint16 spawnid;
/*02*/ uint8 action;
/*03*/ uint8 value;
/*02*/ uint8 speed;
/*03*/ uint8 action;
/*04*/
};

View File

@ -1260,8 +1260,8 @@ struct RequestClientZoneChange_Struct {
struct Animation_Struct {
/*00*/ uint16 spawnid;
/*02*/ uint8 action;
/*03*/ uint8 value;
/*02*/ uint8 speed;
/*03*/ uint8 action;
/*04*/
};

View File

@ -103,6 +103,16 @@ RULE_INT ( Character, BaseRunSpeedCap, 158) // Base Run Speed Cap, on live it's
RULE_INT ( Character, OrnamentationAugmentType, 20) //Ornamentation Augment Type
RULE_REAL(Character, EnvironmentDamageMulipliter, 1)
RULE_BOOL(Character, UnmemSpellsOnDeath, true)
RULE_INT ( Character, TradeskillUpAlchemy, 2 ) // Alchemy skillup rate adjust. Lower is faster.
RULE_INT ( Character, TradeskillUpBaking, 2 ) // Baking skillup rate adjust. Lower is faster.
RULE_INT ( Character, TradeskillUpBlacksmithing, 2 ) // Blacksmithing skillup rate adjust. Lower is faster.
RULE_INT ( Character, TradeskillUpBrewing, 3 ) // Brewing skillup rate adjust. Lower is faster.
RULE_INT ( Character, TradeskillUpFletching, 2 ) // Fletching skillup rate adjust. Lower is faster.
RULE_INT ( Character, TradeskillUpJewelcrafting, 2 ) // Jewelcrafting skillup rate adjust. Lower is faster.
RULE_INT ( Character, TradeskillUpMakePoison, 2 ) // Make Poison skillup rate adjust. Lower is faster.
RULE_INT ( Character, TradeskillUpPottery, 4 ) // Pottery skillup rate adjust. Lower is faster.
RULE_INT ( Character, TradeskillUpResearch, 1 ) // Research skillup rate adjust. Lower is faster.
RULE_INT ( Character, TradeskillUpTinkering, 2 ) // Tinkering skillup rate adjust. Lower is faster.
RULE_CATEGORY_END()
RULE_CATEGORY( Mercs )

View File

@ -1318,8 +1318,10 @@ bool ZoneServer::Process() {
break;
}
}
delete pack;
if (pack)
delete pack;
else
Log.Out(Logs::Detail, Logs::World_Server, "Zoneserver process tried to delete pack when pack does not exist.");
}
return true;
}

View File

@ -384,7 +384,7 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
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);
@ -406,7 +406,7 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
float riposte_chance = 0.0f;
if (CanRiposte && damage > 0 && CanThisClassRiposte() && InFront)
{
riposte_chance = (100.0f + static_cast<float>(aabonuses.RiposteChance + spellbonuses.RiposteChance +
riposte_chance = (100.0f + static_cast<float>(aabonuses.RiposteChance + spellbonuses.RiposteChance +
itembonuses.RiposteChance - counter_riposte - counter_all)) / 100.0f;
skill = GetSkill(SkillRiposte);
if (IsClient()) {
@ -437,7 +437,7 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
float block_chance = 0.0f;
if (damage > 0 && CanThisClassBlock() && (InFront || bBlockFromRear)) {
block_chance = (100.0f + static_cast<float>(aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance +
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()) {
@ -455,18 +455,18 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
}
//Try Shield Block OR TwoHandBluntBlockCheck
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear))
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))
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() && InFront){
parry_chance = (100.0f + static_cast<float>(aabonuses.ParryChance + itembonuses.ParryChance +
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()) {
@ -490,7 +490,7 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
float dodge_chance = 0.0f;
if (damage > 0 && CanThisClassDodge() && InFront){
dodge_chance = (100.0f + static_cast<float>(aabonuses.DodgeChance + spellbonuses.DodgeChance +
dodge_chance = (100.0f + static_cast<float>(aabonuses.DodgeChance + spellbonuses.DodgeChance +
itembonuses.DodgeChance - counter_dodge - counter_all)) / 100.0f;
skill = CastToClient()->GetSkill(SkillDodge);
@ -946,10 +946,10 @@ 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
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++)
@ -2427,7 +2427,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
bool wasengaged = IsEngaged();
Mob* owner = other->GetOwner();
Mob* mypet = this->GetPet();
Mob* mypet = this->GetPet();
Mob* myowner = this->GetOwner();
Mob* targetmob = this->GetTarget();
@ -3932,7 +3932,7 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand) {
float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance)/100.0f);
if (zone->random.Roll(chance)) {
ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0,
CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0,
DefensiveProcs[i].base_spellID);
}
}
@ -4108,6 +4108,14 @@ void Mob::TrySpellProc(const ItemInst *inst, const ItemData *weapon, Mob *on, ui
Log.Out(Logs::Detail, Logs::Combat,
"Spell proc %d procing spell %d (%.2f percent chance)",
i, SpellProcs[i].spellID, chance);
auto outapp = new EQApplicationPacket(OP_BeginCast,sizeof(BeginCast_Struct));
BeginCast_Struct* begincast = (BeginCast_Struct*)outapp->pBuffer;
begincast->caster_id = GetID();
begincast->spell_id = SpellProcs[i].spellID;
begincast->cast_time = 0;
outapp->priority = 3;
entity_list.QueueCloseClients(this, outapp, false, 200, 0, true);
safe_delete(outapp);
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
SpellProcs[i].base_spellID);

View File

@ -54,7 +54,7 @@ Beacon::Beacon(Mob *at_mob, int lifetime)
:Mob
(
nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, at_mob->GetPosition(), 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
),
remove_timer(lifetime),
spell_timer(0)

View File

@ -107,8 +107,12 @@ Client::Client(EQStreamInterface* ieqs)
0,
0, // qglobal
0, // maxlevel
0 // scalerate
0, // scalerate
0,
0,
0,
0,
0
),
//these must be listed in the order they appear in client.h
position_timer(250),
@ -7763,7 +7767,8 @@ void Client::MerchantRejectMessage(Mob *merchant, int primaryfaction)
if (primaryfaction > 0) {
if (database.GetFactionData(&fmod, GetClass(), GetRace(), GetDeity(), primaryfaction)) {
tmpFactionValue = GetCharacterFactionLevel(primaryfaction);
lowestvalue = std::min(tmpFactionValue, std::min(fmod.class_mod, fmod.race_mod));
lowestvalue = std::min(std::min(tmpFactionValue, fmod.deity_mod),
std::min(fmod.class_mod, fmod.race_mod));
}
}
// If no primary faction or biggest influence is your faction hit
@ -7811,6 +7816,11 @@ void Client::MerchantRejectMessage(Mob *merchant, int primaryfaction)
}
} else if (lowestvalue == fmod.class_mod) {
merchant->Say_StringID(zone->random.Int(WONT_SELL_CLASS1, WONT_SELL_CLASS5), itoa(GetClass()));
} else {
// Must be deity - these two sound the best for that.
// Can't use a message with a field, GUI wants class/race names.
// for those message IDs. These are straight text.
merchant->Say_StringID(zone->random.Int(WONT_SELL_DEEDS1, WONT_SELL_DEEDS2));
}
return;
}

View File

@ -337,7 +337,7 @@ void MapOpcodes()
// Use or Ignore sense heading based on rule.
bool train=RuleB(Skills, TrainSenseHeading);
ConnectedOpcodes[OP_SenseHeading] =
ConnectedOpcodes[OP_SenseHeading] =
(train) ? &Client::Handle_OP_SenseHeading : &Client::Handle_OP_Ignore;
ConnectedOpcodes[OP_SenseTraps] = &Client::Handle_OP_SenseTraps;
@ -413,10 +413,10 @@ int Client::HandlePacket(const EQApplicationPacket *app)
if (Log.log_settings[Logs::Client_Server_Packet].is_category_enabled == 1)
Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size());
if (Log.log_settings[Logs::Client_Server_Packet_With_Dump].is_category_enabled == 1)
Log.Out(Logs::General, Logs::Client_Server_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str());
EmuOpcode opcode = app->GetOpcode();
if (opcode == OP_AckPacket) {
return true;
@ -458,7 +458,7 @@ int Client::HandlePacket(const EQApplicationPacket *app)
case CLIENT_CONNECTED: {
ClientPacketProc p;
p = ConnectedOpcodes[opcode];
if(p == nullptr) {
if(p == nullptr) {
std::vector<EQEmu::Any> args;
args.push_back(const_cast<EQApplicationPacket*>(app));
parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 0, &args);
@ -2607,7 +2607,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app)
++iter;
}
if (item_id == 0 || reclaim->count == 0) {
if (item_id == 0) {
return;
}
@ -2628,6 +2628,9 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app)
else {
uint32 max_currency = GetAlternateCurrencyValue(reclaim->currency_id);
if(max_currency == 0 || reclaim->count == 0)
return;
/* If you input more than you have currency wise, just give the max of the currency you currently have */
if (reclaim->count > max_currency) {
SummonItem(item_id, max_currency, 0);
@ -2831,8 +2834,7 @@ void Client::Handle_OP_Animation(const EQApplicationPacket *app)
Animation_Struct *s = (Animation_Struct *)app->pBuffer;
//might verify spawn ID, but it wouldent affect anything
DoAnim(s->action, s->value);
DoAnim(s->action, s->speed);
return;
}
@ -3015,7 +3017,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
{
DeleteItemInInventory(slot_id, 0, true);
DeleteItemInInventory(MainCursor, 0, true);
if (PutItemInInventory(slot_id, *itemOneToPush, true))
{
CalcBonuses();
@ -5421,12 +5423,12 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
/* EVENT_ENVIRONMENTAL_DAMAGE */
int final_damage = (damage * RuleR(Character, EnvironmentDamageMulipliter));
char buf[24];
snprintf(buf, 23, "%u %u %i", ed->damage, ed->dmgtype, final_damage);
snprintf(buf, 23, "%u %u %i", ed->damage, ed->dmgtype, final_damage);
parse->EventPlayer(EVENT_ENVIRONMENTAL_DAMAGE, this, buf, 0);
}
if (GetHP() <= 0) {
mod_client_death_env();
mod_client_death_env();
Death(0, 32000, SPELL_UNKNOWN, SkillHandtoHand);
}
SendHPUpdate();
@ -9793,7 +9795,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), GetTarget()->GetCleanName());
break;
}
if (!mypet->IsAttackAllowed(GetTarget())) {
mypet->Say_StringID(NOT_LEGAL_TARGET);
break;
@ -9889,7 +9891,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
}
}
break;
}
}
case PET_TAUNT_ON: {
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
Message_StringID(MT_PetResponse, PET_DO_TAUNT);
@ -11623,7 +11625,7 @@ void Client::Handle_OP_SenseHeading(const EQApplicationPacket *app)
// eventually sends a message.
if (GetLevel() <= 8)
chancemod += (9-level) * 10;
CheckIncreaseSkill(SkillSenseHeading, nullptr, chancemod);
return;
@ -12200,7 +12202,7 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
int freeslot = 0;
if (charges > 0 && (freeslot = zone->SaveTempItem(vendor->CastToNPC()->MerchantType, vendor->GetNPCTypeID(), itemid, charges, true)) > 0){
ItemInst* inst2 = inst->Clone();
while (true) {
if (inst2 == nullptr)
break;
@ -13285,7 +13287,7 @@ 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)
{
@ -13430,7 +13432,7 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
if (app->size == sizeof(TraderClick_Struct))
{
TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer;
Log.Out(Logs::Detail, Logs::Trading, "Handle_OP_TraderShop: TraderClick_Struct TraderID %d, Code %d, Unknown008 %d, Approval %d",

View File

@ -152,7 +152,7 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP
in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),in_npc->GetSize(),0,
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),
0,0,0,0,0,0,0,0,0,0,0,0xff,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
corpse_decay_timer(in_decaytime),
corpse_rez_timer(0),
corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)),
@ -253,7 +253,12 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
0, // int32 in_mana_regen,
0, // uint8 in_qglobal,
0, // uint8 in_maxlevel,
0 // uint32 in_scalerate
0, // uint32 in_scalerate
0, // uint8 in_armtexture,
0, // uint8 in_bracertexture,
0, // uint8 in_handtexture,
0, // uint8 in_legtexture,
0 // uint8 in_feettexture,
),
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
corpse_rez_timer(RuleI(Character, CorpseResTimeMS)),
@ -478,6 +483,11 @@ in_helmtexture,
0,
0,
0,
0,
0,
0,
0,
0,
0),
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
corpse_rez_timer(RuleI(Character, CorpseResTimeMS)),

View File

@ -137,6 +137,7 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml
}
float roll_t = 0.0f;
float roll_t_min = 0.0f;
bool active_item_list = false;
for(uint32 i = 0; i < lds->NumEntries; ++i) {
const ItemData* db_item = GetItem(lds->Entries[i].item_id);
@ -146,15 +147,44 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml
}
}
roll_t_min = roll_t;
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) {
for(int i = 0; i < mindrop; ++i) {
float roll = (float)zone->random.Real(0.0, roll_t_min);
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;
}
}
}
}
for(int i = mindrop; i < droplimit; ++i) {
float roll = (float)zone->random.Real(0.0, roll_t);
for(uint32 j = 0; j < lds->NumEntries; ++j) {
const ItemData* db_item = GetItem(lds->Entries[j].item_id);

View File

@ -83,7 +83,12 @@ Mob::Mob(const char* in_name,
int32 in_mana_regen,
uint8 in_qglobal,
uint8 in_maxlevel,
uint32 in_scalerate
uint32 in_scalerate,
uint8 in_armtexture,
uint8 in_bracertexture,
uint8 in_handtexture,
uint8 in_legtexture,
uint8 in_feettexture
) :
attack_timer(2000),
attack_dw_timer(2000),
@ -159,6 +164,13 @@ Mob::Mob(const char* in_name,
texture = in_texture;
helmtexture = in_helmtexture;
armtexture = in_armtexture;
bracertexture = in_bracertexture;
handtexture = in_handtexture;
legtexture = in_legtexture;
feettexture = in_feettexture;
multitexture = (armtexture || bracertexture || handtexture || legtexture || feettexture);
haircolor = in_haircolor;
beardcolor = in_beardcolor;
eyecolor1 = in_eyecolor1;
@ -931,7 +943,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
ns->spawn.drakkin_heritage = drakkin_heritage;
ns->spawn.drakkin_tattoo = drakkin_tattoo;
ns->spawn.drakkin_details = drakkin_details;
ns->spawn.equip_chest2 = GetHerosForgeModel(1) != 0 ? 0xff : texture;
ns->spawn.equip_chest2 = GetHerosForgeModel(1) != 0 || multitexture? 0xff : texture;
// ns->spawn.invis2 = 0xff;//this used to be labeled beard.. if its not FF it will turn mob invis
@ -1303,12 +1315,12 @@ void Mob::DoAnim(const int animnum, int type, bool ackreq, eqFilterType filter)
Animation_Struct* anim = (Animation_Struct*)outapp->pBuffer;
anim->spawnid = GetID();
if(type == 0){
anim->action = 10;
anim->value=animnum;
anim->action = animnum;
anim->speed = 10;
}
else{
anim->action = animnum;
anim->value=type;
anim->speed = type;
}
entity_list.QueueCloseClients(this, outapp, false, 200, 0, ackreq, filter);
safe_delete(outapp);

View File

@ -113,7 +113,12 @@ public:
int32 in_mana_regen,
uint8 in_qglobal,
uint8 in_maxlevel,
uint32 in_scalerate
uint32 in_scalerate,
uint8 in_armtexture,
uint8 in_bracertexture,
uint8 in_handtexture,
uint8 in_legtexture,
uint8 in_feettexture
);
virtual ~Mob();
@ -975,6 +980,12 @@ protected:
uint16 entity_id_being_looted; //the id of the entity being looted, 0 if not looting.
uint8 texture;
uint8 helmtexture;
uint8 armtexture;
uint8 bracertexture;
uint8 handtexture;
uint8 legtexture;
uint8 feettexture;
bool multitexture;
int AC;
int32 ATK;

View File

@ -103,7 +103,12 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
d->mana_regen,
d->qglobal,
d->maxlevel,
d->scalerate ),
d->scalerate,
d->armtexture,
d->bracertexture,
d->handtexture,
d->legtexture,
d->feettexture),
attacked_timer(CombatEventTimer_expire),
swarm_timer(100),
classattack_timer(1000),
@ -1308,6 +1313,16 @@ int32 NPC::GetEquipmentMaterial(uint8 material_slot) const
return helmtexture;
case MaterialChest:
return texture;
case MaterialArms:
return armtexture;
case MaterialWrist:
return bracertexture;
case MaterialHands:
return handtexture;
case MaterialLegs:
return legtexture;
case MaterialFeet:
return feettexture;
case MaterialPrimary:
return d_melee_texture1;
case MaterialSecondary:

View File

@ -6110,6 +6110,84 @@ XS(XS_Client_SendSpellAnim)
XSRETURN_EMPTY;
}
XS(XS_Client_GetTargetRingX); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_GetTargetRingX)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client::GetTargetRingX(THIS)");
{
Client * THIS;
float RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Client *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Client");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetTargetRingX();
XSprePUSH; PUSHn((double)RETVAL);
}
XSRETURN(1);
}
XS(XS_Client_GetTargetRingY); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_GetTargetRingY)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client::GetTargetRingY(THIS)");
{
Client * THIS;
float RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Client *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Client");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetTargetRingY();
XSprePUSH; PUSHn((double)RETVAL);
}
XSRETURN(1);
}
XS(XS_Client_GetTargetRingZ); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_GetTargetRingZ)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client::GetTargetRingZ(THIS)");
{
Client * THIS;
float RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Client *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Client");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetTargetRingZ();
XSprePUSH; PUSHn((double)RETVAL);
}
XSRETURN(1);
}
#ifdef __cplusplus
extern "C"
#endif
@ -6351,6 +6429,9 @@ XS(boot_Client)
newXSproto(strcpy(buf, "SendMarqueeMessage"), XS_Client_SendMarqueeMessage, file, "$$$$$$$");
newXSproto(strcpy(buf, "SendColoredText"), XS_Client_SendColoredText, file, "$$$");
newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$");
newXSproto(strcpy(buf, "GetTargetRingX"), XS_Client_GetTargetRingX, file, "$$");
newXSproto(strcpy(buf, "GetTargetRingY"), XS_Client_GetTargetRingY, file, "$$");
newXSproto(strcpy(buf, "GetTargetRingZ"), XS_Client_GetTargetRingZ, file, "$$");
XSRETURN_YES;
}

View File

@ -5253,7 +5253,7 @@ uint16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
if (IsValidSpell(proc_spellid)){
ProcChance = GetSympatheticProcChances(spell_id, GetSympatheticSpellProcRate(spell_id));
ProcChance = GetSympatheticProcChances(spell_id, GetSympatheticSpellProcRate(proc_spellid));
if(zone->random.Roll(ProcChance))
SympatheticProcList.push_back(proc_spellid);
}

View File

@ -2672,7 +2672,7 @@ int CalcBuffDuration_formula(int level, int formula, int duration)
return i < duration ? (i < 1 ? 1 : i) : duration;
case 11:
return duration;
return std::min((level + 3) * 30, duration);
case 12:
return duration;
@ -5254,7 +5254,7 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff)
sbf->slot = 2;
sbf->spellid = buff.spellid;
sbf->slotid = 0;
sbf->effect = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
sbf->effect = 255;
sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
sbf->bufffade = 0;
sbf->duration = buff.ticsremaining;

View File

@ -848,24 +848,41 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
// Some tradeskills are more eqal then others. ;-)
// If you want to customize the stage1 success rate do it here.
// Remember: skillup_modifier is (float). Lower is better
switch(spec->tradeskill) {
case SkillFletching:
case SkillAlchemy:
case SkillJewelryMaking:
case SkillPottery:
skillup_modifier = 4;
break;
case SkillBaking:
case SkillBrewing:
skillup_modifier = 3;
break;
case SkillResearch:
skillup_modifier = 1;
break;
default:
skillup_modifier = 2;
break;
}
switch(spec->tradeskill) {
case SkillFletching:
skillup_modifier = RuleI(Character, TradeskillUpFletching);
break;
case SkillAlchemy:
skillup_modifier = RuleI(Character, TradeskillUpAlchemy);
break;
case SkillJewelryMaking:
skillup_modifier = RuleI(Character, TradeskillUpJewelcrafting);
break;
case SkillPottery:
skillup_modifier = RuleI(Character, TradeskillUpPottery);
break;
case SkillBaking:
skillup_modifier = RuleI(Character, TradeskillUpBaking);
break;
case SkillBrewing:
skillup_modifier = RuleI(Character, TradeskillUpBrewing);
break;
case SkillBlacksmithing:
skillup_modifier = RuleI(Character, TradeskillUpBlacksmithing);
break;
case SkillResearch:
skillup_modifier = RuleI(Character, TradeskillUpResearch);
break;
case SkillMakePoison:
skillup_modifier = RuleI(Character, TradeskillUpMakePoison);
break;
case SkillTinkering:
skillup_modifier = RuleI(Character, TradeskillUpTinkering);
break;
default:
skillup_modifier = 2;
break;
}
// Some tradeskills take the higher of one additional stat beside INT and WIS
// to determine the skillup rate. Additionally these tradeskills do not have an

View File

@ -1626,23 +1626,10 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic
return;
}
ReturnTraderReq(app, outtbs->Quantity, ItemID);
outtbs->TraderID = this->GetID();
outtbs->Action = BazaarBuyItem;
strn0cpy(outtbs->ItemName, BuyItem->GetItem()->Name, 64);
int TraderSlot = 0;
if(BuyItem->IsStackable())
SendTraderItem(BuyItem->GetItem()->ID, outtbs->Quantity);
else
SendTraderItem(BuyItem->GetItem()->ID, BuyItem->GetCharges());
// This cannot overflow assuming MAX_TRANSACTION_VALUE, checked above, is the default of 2000000000
uint32 TotalCost = tbs->Price * outtbs->Quantity;
if (Trader->GetClientVersion() >= ClientVersion::RoF)
if(Trader->GetClientVersion() >= ClientVersion::RoF)
{
// RoF+ uses individual item price where older clients use total price
outtbs->Price = tbs->Price;
@ -1673,6 +1660,19 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic
Log.Out(Logs::Detail, Logs::Trading, "Trader Received: %d Platinum, %d Gold, %d Silver, %d Copper", platinum, gold, silver, copper);
ReturnTraderReq(app, outtbs->Quantity, ItemID);
outtbs->TraderID = this->GetID();
outtbs->Action = BazaarBuyItem;
strn0cpy(outtbs->ItemName, BuyItem->GetItem()->Name, 64);
int TraderSlot = 0;
if(BuyItem->IsStackable())
SendTraderItem(BuyItem->GetItem()->ID, outtbs->Quantity);
else
SendTraderItem(BuyItem->GetItem()->ID, BuyItem->GetCharges());
TraderSlot = Trader->FindTraderItem(tbs->ItemID, outtbs->Quantity);
if(RuleB(Bazaar, AuditTrail))

View File

@ -1905,7 +1905,12 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
"npc_types.no_target_hotkey, "
"npc_types.raid_target, "
"npc_types.attack_delay, "
"npc_types.light "
"npc_types.light, "
"npc_types.armtexture, "
"npc_types.bracertexture, "
"npc_types.handtexture, "
"npc_types.legtexture, "
"npc_types.feettexture "
"FROM npc_types %s",
where_condition.c_str()
);
@ -2075,6 +2080,12 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
temp_npctype_data->attack_delay = atoi(row[90]);
temp_npctype_data->light = (atoi(row[91]) & 0x0F);
temp_npctype_data->armtexture = atoi(row[92]);
temp_npctype_data->bracertexture = atoi(row[93]);
temp_npctype_data->handtexture = atoi(row[94]);
temp_npctype_data->legtexture = atoi(row[95]);
temp_npctype_data->feettexture = atoi(row[96]);
// If NPC with duplicate NPC id already in table,
// free item we attempted to add.
if (zone->npctable.find(temp_npctype_data->npc_id) != zone->npctable.end()) {

View File

@ -127,6 +127,11 @@ struct NPCType
bool no_target_hotkey;
bool raid_target;
uint8 probability;
uint8 armtexture;
uint8 bracertexture;
uint8 handtexture;
uint8 legtexture;
uint8 feettexture;
};
namespace player_lootitem {