Merge from master

This commit is contained in:
KimLS 2014-12-20 19:32:00 -08:00
commit 5cbd741358
32 changed files with 675 additions and 483 deletions

View File

@ -1,5 +1,22 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 12/20/2014 ==
Akkadius: Updated #cvs to display RoF2 Client Stream count
== 12/19/2014 ==
Trevius: (RoF2) Fixed Leadership AA Purchasing and Recipe Search by correcting opcodes.
Trevius: Fixed Armor Tinting (players and NPCs) that was broken during a previous update.
Trevius: (RoF2) Fixed Rest Timer, Show Helm Option, Auto-Consent Options, and identified Krono in the PP.
Trevius: Fixed Selling for Alternate Currency Merchants for RoF and RoF2.
== 12/18/2014 ==
Trevius: Finished lining up the RoF2 Player Profile Struct. Zone times are now normal, and everything from the PP is accurate in game now.
Trevius: Fixed zoning after death for RoF2.
== 12/17/2014 ==
demonstar55: Use vectors for route stuff, should be more CPU cache friendly so faster
Secrets: EQStream changes as recommended by a community member in private.
== 12/15/2014 == == 12/15/2014 ==
Trevius: (RoF+) Implemented the 6th Augment Slot for Items. Trevius: (RoF+) Implemented the 6th Augment Slot for Items.
Trevius: Player Corpses now saved attuned settings for Items. Trevius: Player Corpses now saved attuned settings for Items.

View File

@ -548,6 +548,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) {
}, },
{ // local[MapBank] { // local[MapBank]
/*Unknown*/ NOT_USED, /*Unknown*/ NOT_USED,
/*62*/ NOT_USED,
/*Titanium*/ Titanium::consts::MAP_BANK_SIZE, /*Titanium*/ Titanium::consts::MAP_BANK_SIZE,
/*SoF*/ EmuConstants::MAP_BANK_SIZE, /*SoF*/ EmuConstants::MAP_BANK_SIZE,
/*SoD*/ EmuConstants::MAP_BANK_SIZE, /*SoD*/ EmuConstants::MAP_BANK_SIZE,
@ -697,6 +698,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) {
}, },
{ // local[MapCorpse] { // local[MapCorpse]
/*Unknown*/ NOT_USED, /*Unknown*/ NOT_USED,
/*62*/ NOT_USED,
/*Titanium*/ Titanium::consts::MAP_CORPSE_SIZE, /*Titanium*/ Titanium::consts::MAP_CORPSE_SIZE,
/*SoF*/ SoF::consts::MAP_CORPSE_SIZE, /*SoF*/ SoF::consts::MAP_CORPSE_SIZE,
/*SoD*/ SoD::consts::MAP_CORPSE_SIZE, /*SoD*/ SoD::consts::MAP_CORPSE_SIZE,
@ -726,6 +728,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) {
}, },
{ // local[MapInspect] { // local[MapInspect]
/*Unknown*/ NOT_USED, /*Unknown*/ NOT_USED,
/*62*/ NOT_USED,
/*Titanium*/ Titanium::consts::MAP_INSPECT_SIZE, /*Titanium*/ Titanium::consts::MAP_INSPECT_SIZE,
/*SoF*/ SoF::consts::MAP_INSPECT_SIZE, /*SoF*/ SoF::consts::MAP_INSPECT_SIZE,
/*SoD*/ SoD::consts::MAP_INSPECT_SIZE, /*SoD*/ SoD::consts::MAP_INSPECT_SIZE,
@ -1003,6 +1006,7 @@ uint64 EQLimits::CursorBitmask(uint32 version) {
bool EQLimits::AllowsEmptyBagInBag(uint32 version) { bool EQLimits::AllowsEmptyBagInBag(uint32 version) {
static const bool local[_EmuClientCount] = { static const bool local[_EmuClientCount] = {
/*Unknown*/ false, /*Unknown*/ false,
/*62*/ false,
/*Titanium*/ Titanium::limits::ALLOWS_EMPTY_BAG_IN_BAG, /*Titanium*/ Titanium::limits::ALLOWS_EMPTY_BAG_IN_BAG,
/*SoF*/ SoF::limits::ALLOWS_EMPTY_BAG_IN_BAG, /*SoF*/ SoF::limits::ALLOWS_EMPTY_BAG_IN_BAG,
/*SoD*/ SoD::limits::ALLOWS_EMPTY_BAG_IN_BAG, /*SoD*/ SoD::limits::ALLOWS_EMPTY_BAG_IN_BAG,
@ -1023,6 +1027,8 @@ bool EQLimits::AllowsEmptyBagInBag(uint32 version) {
bool EQLimits::AllowsClickCastFromBag(uint32 version) { bool EQLimits::AllowsClickCastFromBag(uint32 version) {
static const bool local[_EmuClientCount] = { static const bool local[_EmuClientCount] = {
/*Unknown*/ false, /*Unknown*/ false,
/*62*/ false,
/*Titanium*/ Titanium::limits::ALLOWS_CLICK_CAST_FROM_BAG,
/*SoF*/ SoF::limits::ALLOWS_CLICK_CAST_FROM_BAG, /*SoF*/ SoF::limits::ALLOWS_CLICK_CAST_FROM_BAG,
/*SoD*/ SoD::limits::ALLOWS_CLICK_CAST_FROM_BAG, /*SoD*/ SoD::limits::ALLOWS_CLICK_CAST_FROM_BAG,
/*Underfoot*/ Underfoot::limits::ALLOWS_CLICK_CAST_FROM_BAG, /*Underfoot*/ Underfoot::limits::ALLOWS_CLICK_CAST_FROM_BAG,
@ -1082,6 +1088,7 @@ uint16 EQLimits::ItemContainerSize(uint32 version) {
bool EQLimits::CoinHasWeight(uint32 version) { bool EQLimits::CoinHasWeight(uint32 version) {
static const bool local[_EmuClientCount] = { static const bool local[_EmuClientCount] = {
/*Unknown*/ true, /*Unknown*/ true,
/*62*/ true,
/*Titanium*/ Titanium::limits::COIN_HAS_WEIGHT, /*Titanium*/ Titanium::limits::COIN_HAS_WEIGHT,
/*SoF*/ SoF::limits::COIN_HAS_WEIGHT, /*SoF*/ SoF::limits::COIN_HAS_WEIGHT,
/*SoD*/ SoD::limits::COIN_HAS_WEIGHT, /*SoD*/ SoD::limits::COIN_HAS_WEIGHT,

View File

@ -1380,19 +1380,19 @@ struct PlayerPositionUpdateServer_Struct
struct PlayerPositionUpdateClient_Struct struct PlayerPositionUpdateClient_Struct
{ {
/*0000*/ uint16 spawn_id; /*0000*/ uint16 spawn_id;
/*0022*/ uint16 sequence; //increments one each packet /*0002*/ uint16 sequence; //increments one each packet
/*0004*/ float y_pos; // y coord /*0004*/ float y_pos; // y coord
/*0008*/ float delta_z; // Change in z /*0008*/ float delta_z; // Change in z
/*0016*/ float delta_x; // Change in x /*0012*/ float delta_x; // Change in x
/*0012*/ float delta_y; // Change in y /*0016*/ float delta_y; // Change in y
/*0020*/ int32 animation:10, // animation /*0020*/ int32 animation:10, // animation
delta_heading:10, // change in heading delta_heading:10, // change in heading
padding0020:12; // ***Placeholder (mostly 1) padding0020:12; // ***Placeholder (mostly 1)
/*0024*/ float x_pos; // x coord /*0024*/ float x_pos; // x coord
/*0028*/ float z_pos; // z coord /*0028*/ float z_pos; // z coord
/*0034*/ uint16 heading:12, // Directional heading /*0032*/ uint16 heading:12, // Directional heading
padding0004:4; // ***Placeholder padding0004:4; // ***Placeholder
/*0032*/ uint8 unknown0006[2]; // ***Placeholder /*0034*/ uint8 unknown0006[2]; // ***Placeholder
/*0036*/ /*0036*/
}; };

View File

@ -47,7 +47,13 @@
uint16 EQStream::MaxWindowSize=2048; uint16 EQStream::MaxWindowSize=2048;
void EQStream::init() { void EQStream::init(bool resetSession) {
// we only reset these statistics if it is a 'new' connection
if ( resetSession )
{
streamactive = false;
sessionAttempts = 0;
}
active_users = 0; active_users = 0;
Session=0; Session=0;
Key=0; Key=0;
@ -313,18 +319,22 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
} }
#ifndef COLLECTOR #ifndef COLLECTOR
if (GetState()==ESTABLISHED) { if (GetState()==ESTABLISHED) {
_log(NET__ERROR, _L "Received OP_SessionRequest in ESTABLISHED state (%d)" __L, GetState()); _log(NET__ERROR, _L "Received OP_SessionRequest in ESTABLISHED state (%d) streamactive (%i) attempt (%i)" __L, GetState(),streamactive,sessionAttempts);
/*RemoveData(); // client seems to try a max of 30 times (initial+3 retries) then gives up, giving it a few more attempts just in case
init(); // streamactive means we identified the opcode for the stream, we cannot re-establish this connection
State=UNESTABLISHED;*/ if ( streamactive || ( sessionAttempts > MAX_SESSION_RETRIES ) )
_SendDisconnect(); {
SetState(CLOSED); _SendDisconnect();
break; SetState(CLOSED);
break;
}
} }
#endif #endif
//std::cout << "Got OP_SessionRequest" << std::endl; //std::cout << "Got OP_SessionRequest" << std::endl;
init(); sessionAttempts++;
// we set established below, so statistics will not be reset for session attempts/stream active.
init(GetState()!=ESTABLISHED);
OutboundQueueClear(); OutboundQueueClear();
SessionRequest *Request=(SessionRequest *)p->pBuffer; SessionRequest *Request=(SessionRequest *)p->pBuffer;
Session=ntohl(Request->Session); Session=ntohl(Request->Session);

View File

@ -49,6 +49,10 @@ class EQProtocolPacket;
#define RETRANSMIT_ACKED_PACKETS true #define RETRANSMIT_ACKED_PACKETS true
#endif #endif
#ifndef MAX_SESSION_RETRIES
#define MAX_SESSION_RETRIES 30
#endif
#pragma pack(1) #pragma pack(1)
struct SessionRequest { struct SessionRequest {
uint32 UnknownA; uint32 UnknownA;
@ -104,6 +108,9 @@ class EQStream : public EQStreamInterface {
uint32 retransmittimer; uint32 retransmittimer;
uint32 retransmittimeout; uint32 retransmittimeout;
uint16 sessionAttempts;
bool streamactive;
//uint32 buffer_len; //uint32 buffer_len;
uint32 Session, Key; uint32 Session, Key;
@ -197,9 +204,9 @@ class EQStream : public EQStreamInterface {
void _SendDisconnect(); void _SendDisconnect();
void init(); void init(bool resetSession=true);
public: public:
EQStream() { init(); remote_ip = 0; remote_port = 0; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); } EQStream() { init(); remote_ip = 0; remote_port = 0; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); sessionAttempts = 0; streamactive=false; }
EQStream(sockaddr_in addr) { init(); remote_ip=addr.sin_addr.s_addr; remote_port=addr.sin_port; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); } EQStream(sockaddr_in addr) { init(); remote_ip=addr.sin_addr.s_addr; remote_port=addr.sin_port; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); }
virtual ~EQStream() { RemoveData(); SetState(CLOSED); } virtual ~EQStream() { RemoveData(); SetState(CLOSED); }
void SetMaxLen(uint32 length) { MaxLen=length; } void SetMaxLen(uint32 length) { MaxLen=length; }
@ -224,6 +231,9 @@ class EQStream : public EQStreamInterface {
void SetLastPacketTime(uint32 t) {LastPacket=t;} void SetLastPacketTime(uint32 t) {LastPacket=t;}
void Write(int eq_fd); void Write(int eq_fd);
// whether or not the stream has been assigned (we passed our stream match)
void SetActive(bool val) { streamactive = val; }
// //
inline bool IsInUse() { bool flag; MInUse.lock(); flag=(active_users>0); MInUse.unlock(); return flag; } inline bool IsInUse() { bool flag; MInUse.lock(); flag=(active_users>0); MInUse.unlock(); return flag; }
inline void PutInUse() { MInUse.lock(); active_users++; MInUse.unlock(); } inline void PutInUse() { MInUse.lock(); active_users++; MInUse.unlock(); }

View File

@ -110,6 +110,9 @@ void EQStreamIdentifier::Process() {
_log(NET__IDENTIFY, "Identified stream %s:%d with signature %s", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()), p->name.c_str()); _log(NET__IDENTIFY, "Identified stream %s:%d with signature %s", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()), p->name.c_str());
// before we assign the eqstream to an interface, let the stream recognize it is in use and the session should not be reset any further
r->stream->SetActive(true);
//might want to do something less-specific here... some day.. //might want to do something less-specific here... some day..
EQStreamInterface *s = new EQStreamProxy(r->stream, p->structs, p->opcodes); EQStreamInterface *s = new EQStreamProxy(r->stream, p->structs, p->opcodes);
m_identified.push(s); m_identified.push(s);

View File

@ -205,7 +205,7 @@ namespace RoF
SETUP_DIRECT_ENCODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); SETUP_DIRECT_ENCODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct);
OUT(merchant_entity_id); OUT(merchant_entity_id);
eq->slot_id = ServerToRoFSlot(emu->slot_id); eq->slot_id = ServerToRoFMainInvSlot(emu->slot_id);
OUT(charges); OUT(charges);
OUT(cost); OUT(cost);
@ -2045,15 +2045,6 @@ namespace RoF
outapp->WriteUInt32(emu->skills[r]); outapp->WriteUInt32(emu->skills[r]);
} }
// deprecated
// Write zeroes for the rest of the skills
/*
for(uint32 r = 0; r < structs::MAX_PP_SKILL - MAX_PP_SKILL; r++)
{
outapp->WriteUInt32(emu->skills[r]);
}
*/
outapp->WriteUInt32(25); // Unknown count outapp->WriteUInt32(25); // Unknown count
for (uint32 r = 0; r < 25; r++) for (uint32 r = 0; r < 25; r++)
@ -2130,18 +2121,6 @@ namespace RoF
outapp->WriteUInt32(structs::BUFF_COUNT); outapp->WriteUInt32(structs::BUFF_COUNT);
//*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise
//*001*/ float unknown004; // Seen 1 for no buff
//*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
//*009*/ uint32 unknown016;
//*013*/ uint8 bard_modifier;
//*014*/ uint32 duration;
//*018*/ uint8 level;
//*019*/ uint32 spellid;
//*023*/ uint32 counters;
//*027*/ uint8 unknown0028[53];
//*080*/
for (uint32 r = 0; r < BUFF_COUNT; r++) for (uint32 r = 0; r < BUFF_COUNT; r++)
{ {
float instrument_mod = 0.0f; float instrument_mod = 0.0f;
@ -3902,7 +3881,7 @@ namespace RoF
SETUP_DIRECT_DECODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); SETUP_DIRECT_DECODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct);
IN(merchant_entity_id); IN(merchant_entity_id);
emu->slot_id = RoFToServerSlot(eq->slot_id); emu->slot_id = RoFToServerMainInvSlot(eq->slot_id);
IN(charges); IN(charges);
IN(cost); IN(cost);
@ -3915,7 +3894,7 @@ namespace RoF
SETUP_DIRECT_DECODE(AltCurrencySelectItem_Struct, structs::AltCurrencySelectItem_Struct); SETUP_DIRECT_DECODE(AltCurrencySelectItem_Struct, structs::AltCurrencySelectItem_Struct);
IN(merchant_entity_id); IN(merchant_entity_id);
emu->slot_id = RoFToServerSlot(eq->slot_id); emu->slot_id = RoFToServerMainInvSlot(eq->slot_id);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
@ -4878,7 +4857,8 @@ namespace RoF
uint16 ornaIcon = 0; uint16 ornaIcon = 0;
int32 heroModel = 0; int32 heroModel = 0;
/* /*
if (inst->GetOrnamentationAug(ornamentationAugtype)) { if (inst->GetOrnamentationAug(ornamentationAugtype))
{
const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem();
//Mainhand //Mainhand
ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile));
@ -5081,11 +5061,6 @@ namespace RoF
isbs.augslots[x].unknown = item->AugSlotUnk2[x]; isbs.augslots[x].unknown = item->AugSlotUnk2[x];
} }
// Increased to 6 max aug slots
//isbs.augslots[5].type = 0;
//isbs.augslots[5].visible = 1;
//isbs.augslots[5].unknown = 0;
isbs.ldonpoint_type = item->PointType; isbs.ldonpoint_type = item->PointType;
isbs.ldontheme = item->LDoNTheme; isbs.ldontheme = item->LDoNTheme;
isbs.ldonprice = item->LDoNPrice; isbs.ldonprice = item->LDoNPrice;

View File

@ -205,7 +205,7 @@ namespace RoF2
SETUP_DIRECT_ENCODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); SETUP_DIRECT_ENCODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct);
OUT(merchant_entity_id); OUT(merchant_entity_id);
eq->slot_id = ServerToRoF2Slot(emu->slot_id); eq->slot_id = ServerToRoF2MainInvSlot(emu->slot_id);
OUT(charges); OUT(charges);
OUT(cost); OUT(cost);
@ -1696,6 +1696,8 @@ namespace RoF2
eq->unknown932 = -1; // Set from PoK Example eq->unknown932 = -1; // Set from PoK Example
eq->unknown936 = -1; // Set from PoK Example eq->unknown936 = -1; // Set from PoK Example
eq->unknown944 = 1.0; // Set from PoK Example eq->unknown944 = 1.0; // Set from PoK Example
eq->unknown948 = 0; // New on Live as of Dec 15 2014
eq->unknown952 = 100; // New on Live as of Dec 15 2014
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -2121,18 +2123,6 @@ namespace RoF2
outapp->WriteUInt32(structs::BUFF_COUNT); outapp->WriteUInt32(structs::BUFF_COUNT);
//*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise
//*001*/ float unknown004; // Seen 1 for no buff
//*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
//*009*/ uint32 unknown016;
//*013*/ uint8 bard_modifier;
//*014*/ uint32 duration;
//*018*/ uint8 level;
//*019*/ uint32 spellid;
//*023*/ uint32 counters;
//*027*/ uint8 unknown0028[53];
//*080*/
for (uint32 r = 0; r < BUFF_COUNT; r++) for (uint32 r = 0; r < BUFF_COUNT; r++)
{ {
float instrument_mod = 0.0f; float instrument_mod = 0.0f;
@ -2172,7 +2162,6 @@ namespace RoF2
// 80 bytes of zeroes // 80 bytes of zeroes
for (uint32 j = 0; j < 20; ++j) for (uint32 j = 0; j < 20; ++j)
outapp->WriteUInt32(0); outapp->WriteUInt32(0);
} }
outapp->WriteUInt32(emu->platinum); outapp->WriteUInt32(emu->platinum);
@ -2197,8 +2186,8 @@ namespace RoF2
outapp->WriteUInt32(emu->aapoints_spent); outapp->WriteUInt32(emu->aapoints_spent);
outapp->WriteUInt32(5); // AA Points count ?? outapp->WriteUInt32(5); // AA Window Tab Count
outapp->WriteUInt32(1234); // AA Points assigned outapp->WriteUInt32(0); // AA Points assigned ?
outapp->WriteUInt32(0); // AA Points in General ? outapp->WriteUInt32(0); // AA Points in General ?
outapp->WriteUInt32(0); // AA Points in Class ? outapp->WriteUInt32(0); // AA Points in Class ?
outapp->WriteUInt32(0); // AA Points in Archetype ? outapp->WriteUInt32(0); // AA Points in Archetype ?
@ -2326,36 +2315,31 @@ namespace RoF2
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(emu->gm); outapp->WriteUInt8(emu->gm);
outapp->WriteUInt32(emu->guild_id); outapp->WriteUInt32(emu->guild_id);
outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet.
outapp->WriteUInt32(0); // Unknown - observed 1 in a live packet. outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet. outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt64(emu->exp); outapp->WriteUInt64(emu->exp); // int32 in client
outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(0); // Unknown - Seen 5 on Live
outapp->WriteUInt32(emu->platinum_bank); outapp->WriteUInt32(emu->platinum_bank);
outapp->WriteUInt32(emu->gold_bank); outapp->WriteUInt32(emu->gold_bank);
outapp->WriteUInt32(emu->silver_bank); outapp->WriteUInt32(emu->silver_bank);
outapp->WriteUInt32(emu->copper_bank); outapp->WriteUInt32(emu->copper_bank);
// Commenting out for RoF Test
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(42); // The meaning of life ?
for (uint32 r = 0; r < 42; r++)
{
outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown
}
outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteSInt32(-1); // Unknown
outapp->WriteSInt32(-1); // Unknown
outapp->WriteUInt32(emu->career_tribute_points); outapp->WriteUInt32(emu->career_tribute_points);
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(emu->tribute_points); outapp->WriteUInt32(emu->tribute_points);
@ -2387,16 +2371,10 @@ namespace RoF2
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
/* for (uint32 r = 0; r < 125; r++)
{
// Begin RoF2 Test
for (uint32 r = 0; r < 1000; r++)
outapp->WriteUInt8(0); // Unknown
// End RoF2 Test
// Block of 121 unknown bytes
for (uint32 r = 0; r < 121; r++)
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
}
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
@ -2411,7 +2389,9 @@ namespace RoF2
// Unknown String ? // Unknown String ?
outapp->WriteUInt32(64); // Unknown outapp->WriteUInt32(64); // Unknown
for (uint32 r = 0; r < 64; r++) for (uint32 r = 0; r < 64; r++)
{
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
}
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
@ -2439,22 +2419,30 @@ namespace RoF2
// Unknown String ? // Unknown String ?
outapp->WriteUInt32(64); // Unknown outapp->WriteUInt32(64); // Unknown
for (uint32 r = 0; r < 64; r++) for (uint32 r = 0; r < 64; r++)
{
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
}
// Unknown String ? // Unknown String ?
outapp->WriteUInt32(64); // Unknown outapp->WriteUInt32(64); // Unknown
for (uint32 r = 0; r < 64; r++) for (uint32 r = 0; r < 64; r++)
{
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
}
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
// Block of 320 unknown bytes // Block of 320 unknown bytes
for (uint32 r = 0; r < 320; r++) for (uint32 r = 0; r < 320; r++)
{
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
}
// Block of 343 unknown bytes // Block of 343 unknown bytes
for (uint32 r = 0; r < 343; r++) for (uint32 r = 0; r < 343; r++)
{
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
}
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
@ -2479,10 +2467,14 @@ namespace RoF2
outapp->WriteUInt32(64); // Group of 64 int32s follow Group/Raid Leadership abilities ? outapp->WriteUInt32(64); // Group of 64 int32s follow Group/Raid Leadership abilities ?
for (uint32 r = 0; r < MAX_LEADERSHIP_AA_ARRAY; r++) for (uint32 r = 0; r < MAX_LEADERSHIP_AA_ARRAY; r++)
{
outapp->WriteUInt32(emu->leader_abilities.ranks[r]); outapp->WriteUInt32(emu->leader_abilities.ranks[r]);
}
for (uint32 r = 0; r < 64 - MAX_LEADERSHIP_AA_ARRAY; r++) for (uint32 r = 0; r < 64 - MAX_LEADERSHIP_AA_ARRAY; r++)
{
outapp->WriteUInt32(0); // Unused/unsupported Leadership abilities outapp->WriteUInt32(0); // Unused/unsupported Leadership abilities
}
outapp->WriteUInt32(emu->air_remaining); // ? outapp->WriteUInt32(emu->air_remaining); // ?
@ -2535,33 +2527,31 @@ namespace RoF2
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
*/ outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Krono - itemid 88888 Hard coded in client?
outapp->WriteUInt8(emu->groupAutoconsent); outapp->WriteUInt8(emu->groupAutoconsent);
outapp->WriteUInt8(emu->raidAutoconsent); outapp->WriteUInt8(emu->raidAutoconsent);
outapp->WriteUInt8(emu->guildAutoconsent); outapp->WriteUInt8(emu->guildAutoconsent);
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
outapp->WriteUInt32(emu->level); // Level3 ? outapp->WriteUInt32(emu->level); // Level3 ?
outapp->WriteUInt8(emu->showhelm); outapp->WriteUInt8(emu->showhelm);
outapp->WriteUInt32(emu->RestTimer); outapp->WriteUInt32(emu->RestTimer);
outapp->WriteUInt32(1024); // Unknown Count outapp->WriteUInt32(1024); // Unknown Count
// Block of 1024 unknown bytes // Block of 1024 unknown bytes
outapp->WriteUInt8(31); // Unknown for (uint32 r = 0; r < 1024; r++)
{
for (uint32 r = 0; r < 1023; r++)
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
}
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown
// Think we need 1 byte of padding at the end // Think we need 1 byte of padding at the end
outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown
_log(NET__STRUCTS, "Player Profile Packet is %i bytes", outapp->GetWritePosition()); _log(NET__STRUCTS, "Player Profile Packet is %i bytes", outapp->GetWritePosition());
@ -3887,6 +3877,7 @@ namespace RoF2
} }
// DECODE methods // DECODE methods
DECODE(OP_AdventureMerchantSell) DECODE(OP_AdventureMerchantSell)
{ {
DECODE_LENGTH_EXACT(structs::Adventure_Sell_Struct); DECODE_LENGTH_EXACT(structs::Adventure_Sell_Struct);
@ -3906,7 +3897,7 @@ namespace RoF2
SETUP_DIRECT_DECODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); SETUP_DIRECT_DECODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct);
IN(merchant_entity_id); IN(merchant_entity_id);
emu->slot_id = RoF2ToServerSlot(eq->slot_id); emu->slot_id = RoF2ToServerMainInvSlot(eq->slot_id);
IN(charges); IN(charges);
IN(cost); IN(cost);
@ -3919,7 +3910,7 @@ namespace RoF2
SETUP_DIRECT_DECODE(AltCurrencySelectItem_Struct, structs::AltCurrencySelectItem_Struct); SETUP_DIRECT_DECODE(AltCurrencySelectItem_Struct, structs::AltCurrencySelectItem_Struct);
IN(merchant_entity_id); IN(merchant_entity_id);
emu->slot_id = RoF2ToServerSlot(eq->slot_id); emu->slot_id = RoF2ToServerMainInvSlot(eq->slot_id);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
@ -4860,8 +4851,8 @@ namespace RoF2
hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges);
hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0;
hdr.unknown044 = 0; hdr.unknown044 = 0;
hdr.unknown048 = 7300 + Inventory::CalcMaterialFromSlot(slot_id_in); //0; hdr.unknown048 = 0;
hdr.unknown052 = 7300 + Inventory::CalcMaterialFromSlot(slot_id_in); //0; hdr.unknown052 = 0;
hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0;
ss.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader)); ss.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader));
@ -5085,11 +5076,6 @@ namespace RoF2
isbs.augslots[x].unknown = item->AugSlotUnk2[x]; isbs.augslots[x].unknown = item->AugSlotUnk2[x];
} }
// Increased to 6 max aug slots
//isbs.augslots[5].type = 0;
//isbs.augslots[5].visible = 1;
//isbs.augslots[5].unknown = 0;
isbs.ldonpoint_type = item->PointType; isbs.ldonpoint_type = item->PointType;
isbs.ldontheme = item->LDoNTheme; isbs.ldontheme = item->LDoNTheme;
isbs.ldonprice = item->LDoNPrice; isbs.ldonprice = item->LDoNPrice;
@ -5325,13 +5311,8 @@ namespace RoF2
iqbs.SpellDmg = item->SpellDmg; iqbs.SpellDmg = item->SpellDmg;
iqbs.clairvoyance = item->Clairvoyance; iqbs.clairvoyance = item->Clairvoyance;
iqbs.unknown28 = 0; iqbs.unknown28 = 0;
// Begin RoF2 Test
iqbs.unknown_TEST1 = 0;
// End RoF2 Test
iqbs.unknown30 = 0; iqbs.unknown30 = 0;
iqbs.unknown37a = 0;
iqbs.unknown39 = 1; iqbs.unknown39 = 1;
iqbs.subitem_count = 0; iqbs.subitem_count = 0;

View File

@ -4,7 +4,6 @@
// incoming packets that require a DECODE translation: // incoming packets that require a DECODE translation:
// Begin RoF2 Decodes // Begin RoF2 Decodes
// End RoF2 Encodes/Decodes // End RoF2 Encodes/Decodes
// These require Encodes/Decodes for RoF, so they do for RoF2 as well // These require Encodes/Decodes for RoF, so they do for RoF2 as well

View File

@ -520,72 +520,73 @@ struct ServerZoneEntry_Struct //Adjusted from SEQ Everquest.h Struct
//New Zone Struct - Size: 948 //New Zone Struct - Size: 948
struct NewZone_Struct { struct NewZone_Struct {
/*0000*/ char char_name[64]; // Character Name /*0000*/ char char_name[64]; // Character Name
/*0064*/ char zone_short_name[32]; // Zone Short Name /*0064*/ char zone_short_name[32]; // Zone Short Name
/*0096*/ char unknown0096[96]; /*0096*/ char unknown0096[96];
/*0192*/ char zone_long_name[278]; // Zone Long Name /*0192*/ char zone_long_name[278]; // Zone Long Name
/*0470*/ uint8 ztype; // Zone type (usually FF) /*0470*/ uint8 ztype; // Zone type (usually FF)
/*0471*/ uint8 fog_red[4]; // Zone fog (red) /*0471*/ uint8 fog_red[4]; // Zone fog (red)
/*0475*/ uint8 fog_green[4]; // Zone fog (green) /*0475*/ uint8 fog_green[4]; // Zone fog (green)
/*0479*/ uint8 fog_blue[4]; // Zone fog (blue) /*0479*/ uint8 fog_blue[4]; // Zone fog (blue)
/*0483*/ uint8 unknown323; /*0483*/ uint8 unknown323;
/*0484*/ float fog_minclip[4]; /*0484*/ float fog_minclip[4];
/*0500*/ float fog_maxclip[4]; /*0500*/ float fog_maxclip[4];
/*0516*/ float gravity; /*0516*/ float gravity;
/*0520*/ uint8 time_type; /*0520*/ uint8 time_type;
/*0521*/ uint8 rain_chance[4]; /*0521*/ uint8 rain_chance[4];
/*0525*/ uint8 rain_duration[4]; /*0525*/ uint8 rain_duration[4];
/*0529*/ uint8 snow_chance[4]; /*0529*/ uint8 snow_chance[4];
/*0533*/ uint8 snow_duration[4]; /*0533*/ uint8 snow_duration[4];
/*0537*/ uint8 unknown537[33]; /*0537*/ uint8 unknown537[33];
/*0570*/ uint8 sky; // Sky Type /*0570*/ uint8 sky; // Sky Type
/*0571*/ uint8 unknown571[13]; // ***Placeholder /*0571*/ uint8 unknown571[13]; // ***Placeholder
/*0584*/ float zone_exp_multiplier; // Experience Multiplier /*0584*/ float zone_exp_multiplier; // Experience Multiplier
/*0588*/ float safe_y; // Zone Safe Y /*0588*/ float safe_y; // Zone Safe Y
/*0592*/ float safe_x; // Zone Safe X /*0592*/ float safe_x; // Zone Safe X
/*0596*/ float safe_z; // Zone Safe Z /*0596*/ float safe_z; // Zone Safe Z
/*0600*/ float min_z; // Guessed - NEW - Seen 0 /*0600*/ float min_z; // Guessed - NEW - Seen 0
/*0604*/ float max_z; // Guessed /*0604*/ float max_z; // Guessed
/*0608*/ float underworld; // Underworld, min z (Not Sure?) /*0608*/ float underworld; // Underworld, min z (Not Sure?)
/*0612*/ float minclip; // Minimum View Distance /*0612*/ float minclip; // Minimum View Distance
/*0616*/ float maxclip; // Maximum View DIstance /*0616*/ float maxclip; // Maximum View DIstance
/*0620*/ uint8 unknown620[84]; // ***Placeholder /*0620*/ uint8 unknown620[84]; // ***Placeholder
/*0704*/ char zone_short_name2[96]; //zone file name? excludes instance number which can be in previous version. /*0704*/ char zone_short_name2[96]; //zone file name? excludes instance number which can be in previous version.
/*0800*/ int32 unknown800; //seen -1 /*0800*/ int32 unknown800; //seen -1
/*0804*/ char unknown804[40]; // /*0804*/ char unknown804[40]; //
/*0844*/ int32 unknown844; //seen 600 /*0844*/ int32 unknown844; //seen 600
/*0848*/ int32 unknown848; /*0848*/ int32 unknown848;
/*0852*/ uint16 zone_id; /*0852*/ uint16 zone_id;
/*0854*/ uint16 zone_instance; /*0854*/ uint16 zone_instance;
/*0856*/ char unknown856[20]; /*0856*/ char unknown856[20];
/*0876*/ uint32 SuspendBuffs; /*0876*/ uint32 SuspendBuffs;
/*0880*/ uint32 unknown880; // Seen 50 /*0880*/ uint32 unknown880; // Seen 50
/*0884*/ uint32 unknown884; // Seen 10 /*0884*/ uint32 unknown884; // Seen 10
/*0888*/ uint8 unknown888; // Seen 1 /*0888*/ uint8 unknown888; // Seen 1
/*0889*/ uint8 unknown889; // Seen 0 (POK) or 1 (rujj) /*0889*/ uint8 unknown889; // Seen 0 (POK) or 1 (rujj)
/*0890*/ uint8 unknown890; // Seen 1 /*0890*/ uint8 unknown890; // Seen 1
/*0891*/ uint8 unknown891; // Seen 0 /*0891*/ uint8 unknown891; // Seen 0
/*0892*/ uint8 unknown892; // Seen 0 /*0892*/ uint8 unknown892; // Seen 0
/*0893*/ uint8 unknown893; // Seen 0 - 00 /*0893*/ uint8 unknown893; // Seen 0 - 00
/*0894*/ uint8 fall_damage; // 0 = Fall Damage on, 1 = Fall Damage off /*0894*/ uint8 fall_damage; // 0 = Fall Damage on, 1 = Fall Damage off
/*0895*/ uint8 unknown895; // Seen 0 - 00 /*0895*/ uint8 unknown895; // Seen 0 - 00
/*0896*/ uint32 unknown896; // Seen 180 /*0896*/ uint32 unknown896; // Seen 180
/*0900*/ uint32 unknown900; // Seen 180 /*0900*/ uint32 unknown900; // Seen 180
/*0904*/ uint32 unknown904; // Seen 180 /*0904*/ uint32 unknown904; // Seen 180
/*0908*/ uint32 unknown908; // Seen 2 /*0908*/ uint32 unknown908; // Seen 2
/*0912*/ uint32 unknown912; // Seen 2 /*0912*/ uint32 unknown912; // Seen 2
/*0916*/ float FogDensity; // Most zones have this set to 0.33 Blightfire had 0.16 /*0916*/ float FogDensity; // Most zones have this set to 0.33 Blightfire had 0.16
/*0920*/ uint32 unknown920; // Seen 0 /*0920*/ uint32 unknown920; // Seen 0
/*0924*/ uint32 unknown924; // Seen 0 /*0924*/ uint32 unknown924; // Seen 0
/*0928*/ uint32 unknown928; // Seen 0 /*0928*/ uint32 unknown928; // Seen 0
/*0932*/ int32 unknown932; // Seen -1 /*0932*/ int32 unknown932; // Seen -1
/*0936*/ int32 unknown936; // Seen -1 /*0936*/ int32 unknown936; // Seen -1
/*0940*/ uint32 unknown940; // Seen 0 /*0940*/ uint32 unknown940; // Seen 0
/*0944*/ float unknown944; // Seen 1.0 /*0944*/ float unknown944; // Seen 1.0
/*0948*/ /*0948*/ uint32 unknown948; // Seen 0 - New on Live as of Dec 15 2014
/*0952*/ uint32 unknown952; // Seen 100 - New on Live as of Dec 15 2014
/*0956*/
}; };
/* /*
** Memorize Spell Struct ** Memorize Spell Struct
** Length: 16 Bytes ** Length: 16 Bytes
@ -1598,23 +1599,24 @@ struct RespawnWindow_Struct {
*/ */
struct PlayerPositionUpdateServer_Struct struct PlayerPositionUpdateServer_Struct
{ {
uint16 spawn_id; /*0000*/ uint16 spawn_id;
uint16 spawnId2; /*0002*/ uint16 spawnId2;
signed padding0004:12; /*0004*/ signed padding0004 : 12;
signed y_pos:19; // y coord signed y_pos : 19; // y coord
unsigned padding:1; unsigned padding : 1;
signed delta_z:13; // change in z /*0008*/ signed delta_z : 13; // change in z
signed delta_x:13; // change in x signed delta_x : 13; // change in x
signed padding0008:6; signed padding0008 : 6;
signed x_pos:19; // x coord /*0012*/ signed x_pos : 19; // x coord
unsigned heading:12; // heading unsigned heading : 12; // heading
signed padding0016:1; signed padding0016 : 1;
signed delta_heading:10; // change in heading /*0016*/ signed delta_heading : 10; // change in heading
signed z_pos:19; // z coord signed z_pos : 19; // z coord
signed padding0020:3; signed padding0020 : 3;
signed animation:10; // animation /*0020*/ signed animation : 10; // animation
signed delta_y:13; // change in y signed delta_y : 13; // change in y
signed padding0024:9; signed padding0024 : 9;
/*0024*/
}; };
/* /*
@ -1625,21 +1627,22 @@ struct PlayerPositionUpdateServer_Struct
*/ */
struct PlayerPositionUpdateClient_Struct struct PlayerPositionUpdateClient_Struct
{ {
uint16 sequence; // increments one each packet - Verified /*0000*/ uint16 sequence; // increments one each packet - Verified
uint16 spawn_id; // Player's spawn id /*0002*/ uint16 spawn_id; // Player's spawn id
uint8 unknown0004[6]; // ***Placeholder /*0004*/ uint8 unknown0004[6]; // ***Placeholder
float delta_x; // Change in x /*0010*/ float delta_x; // Change in x
unsigned heading:12; // Directional heading /*0014*/ unsigned heading : 12; // Directional heading
unsigned padding0040:20; // ***Placeholder unsigned padding0040 : 20; // ***Placeholder
float x_pos; // x coord (2nd loc value) /*0018*/ float x_pos; // x coord (2nd loc value)
float delta_z; // Change in z /*0022*/ float delta_z; // Change in z
float z_pos; // z coord (3rd loc value) /*0026*/ float z_pos; // z coord (3rd loc value)
float y_pos; // y coord (1st loc value) /*0030*/ float y_pos; // y coord (1st loc value)
unsigned animation:10; // ***Placeholder /*0034*/ unsigned animation : 10; // ***Placeholder
unsigned padding0024:22; // animation unsigned padding0024 : 22; // animation
float delta_y; // Change in y /*0038*/ float delta_y; // Change in y
signed delta_heading:10; // change in heading /*0042*/ signed delta_heading : 10; // change in heading
unsigned padding0041:22; // ***Placeholder unsigned padding0041 : 22; // ***Placeholder
/*0046*/
}; };
/* /*
@ -2177,8 +2180,8 @@ struct AltCurrencyUpdate_Struct {
//When an item is selected while the alt currency merchant window is open //When an item is selected while the alt currency merchant window is open
struct AltCurrencySelectItem_Struct { struct AltCurrencySelectItem_Struct {
/*000*/ uint32 merchant_entity_id; /*000*/ uint32 merchant_entity_id;
/*004*/ MainInvItemSlotStruct slot_id;
/*004*/ //uint32 slot_id; /*004*/ //uint32 slot_id;
ItemSlotStruct slot_id;
/*008*/ uint32 unknown008; /*008*/ uint32 unknown008;
/*012*/ uint32 unknown012; /*012*/ uint32 unknown012;
/*016*/ uint32 unknown016; /*016*/ uint32 unknown016;
@ -2235,10 +2238,10 @@ struct AltCurrencyReclaim_Struct {
struct AltCurrencySellItem_Struct { struct AltCurrencySellItem_Struct {
/*000*/ uint32 merchant_entity_id; /*000*/ uint32 merchant_entity_id;
/*004*/ MainInvItemSlotStruct slot_id;
/*004*/ //uint32 slot_id; /*004*/ //uint32 slot_id;
ItemSlotStruct slot_id; /*016*/ uint32 charges;
/*008*/ uint32 charges; /*020*/ uint32 cost;
/*012*/ uint32 cost;
}; };
struct Adventure_Purchase_Struct { struct Adventure_Purchase_Struct {
@ -2258,14 +2261,14 @@ struct Adventure_Sell_Struct {
}; };
struct AdventurePoints_Update_Struct { struct AdventurePoints_Update_Struct {
/*000*/ uint32 ldon_available_points; // Total available points /*000*/ uint32 ldon_available_points; // Total available points
/*004*/ uint8 unkown_apu004[20]; /*004*/ uint8 unkown_apu004[20];
/*024*/ uint32 ldon_guk_points; // Earned Deepest Guk points /*024*/ uint32 ldon_guk_points; // Earned Deepest Guk points
/*028*/ uint32 ldon_mirugal_points; // Earned Mirugal' Mebagerie points /*028*/ uint32 ldon_mirugal_points; // Earned Mirugal' Mebagerie points
/*032*/ uint32 ldon_mistmoore_points; // Earned Mismoore Catacombs Points /*032*/ uint32 ldon_mistmoore_points; // Earned Mismoore Catacombs Points
/*036*/ uint32 ldon_rujarkian_points; // Earned Rujarkian Hills points /*036*/ uint32 ldon_rujarkian_points; // Earned Rujarkian Hills points
/*040*/ uint32 ldon_takish_points; // Earned Takish points /*040*/ uint32 ldon_takish_points; // Earned Takish points
/*044*/ uint8 unknown_apu042[216]; /*044*/ uint8 unknown_apu042[216];
}; };
@ -4687,11 +4690,7 @@ struct ItemQuaternaryBodyStruct
uint32 unknown37; uint32 unknown37;
uint32 unknown_RoF27; uint32 unknown_RoF27;
uint32 unknown_RoF28; uint32 unknown_RoF28;
uint8 unknown37a; // (guessed position) New to RoF2
// Begin RoF2 Test
uint8 unknown_TEST1;
// End RoF2 Test
uint8 unknown38; // 0 uint8 unknown38; // 0
uint8 unknown39; // 1 uint8 unknown39; // 1
uint32 subitem_count; uint32 subitem_count;

View File

@ -2174,8 +2174,7 @@ struct AltCurrencyUpdate_Struct {
//When an item is selected while the alt currency merchant window is open //When an item is selected while the alt currency merchant window is open
struct AltCurrencySelectItem_Struct { struct AltCurrencySelectItem_Struct {
/*000*/ uint32 merchant_entity_id; /*000*/ uint32 merchant_entity_id;
/*004*/ //uint32 slot_id; /*004*/ MainInvItemSlotStruct slot_id;
ItemSlotStruct slot_id;
/*008*/ uint32 unknown008; /*008*/ uint32 unknown008;
/*012*/ uint32 unknown012; /*012*/ uint32 unknown012;
/*016*/ uint32 unknown016; /*016*/ uint32 unknown016;
@ -2232,8 +2231,7 @@ struct AltCurrencyReclaim_Struct {
struct AltCurrencySellItem_Struct { struct AltCurrencySellItem_Struct {
/*000*/ uint32 merchant_entity_id; /*000*/ uint32 merchant_entity_id;
/*004*/ //uint32 slot_id; /*004*/ MainInvItemSlotStruct slot_id;
ItemSlotStruct slot_id;
/*008*/ uint32 charges; /*008*/ uint32 charges;
/*012*/ uint32 cost; /*012*/ uint32 cost;
}; };

View File

@ -4365,8 +4365,8 @@ struct AltCurrencySelectItem_Struct {
struct AltCurrencySellItem_Struct { struct AltCurrencySellItem_Struct {
/*000*/ uint32 merchant_entity_id; /*000*/ uint32 merchant_entity_id;
/*004*/ uint32 slot_id; /*004*/ uint32 slot_id;
/*006*/ uint32 charges; /*008*/ uint32 charges;
/*010*/ uint32 cost; /*012*/ uint32 cost;
}; };
struct AltCurrencyPopulateEntry_Struct struct AltCurrencyPopulateEntry_Struct

View File

@ -1234,6 +1234,9 @@ ItemInst* SharedDatabase::CreateBaseItem(const Item_Struct* item, int16 charges)
// set it to 1 charge so that it is usable on creation // set it to 1 charge so that it is usable on creation
if (charges == 0 && item->MaxCharges == -1) if (charges == 0 && item->MaxCharges == -1)
charges = 1; charges = 1;
// Stackable items need a minimum charge of 1 to remain moveable.
if(charges <= 0 && item->Stackable)
charges = 1;
inst = new ItemInst(item, charges); inst = new ItemInst(item, charges);

View File

@ -113,7 +113,7 @@ OP_ClientUpdate=0x7dfc
OP_ClientReady=0x345d OP_ClientReady=0x345d
OP_SetServerFilter=0x444d OP_SetServerFilter=0x444d
# Guild Opcodes - Disabled until crashes are resolved in RoF # Guild Opcodes
OP_GetGuildMOTD=0x36e0 OP_GetGuildMOTD=0x36e0
OP_GetGuildMOTDReply=0x4f1f OP_GetGuildMOTDReply=0x4f1f
OP_GuildMemberUpdate=0x69b9 OP_GuildMemberUpdate=0x69b9
@ -121,7 +121,6 @@ OP_GuildInvite=0x7099
OP_GuildRemove=0x1444 OP_GuildRemove=0x1444
OP_GuildPeace=0x67e3 OP_GuildPeace=0x67e3
OP_SetGuildMOTD=0x0b0b OP_SetGuildMOTD=0x0b0b
OP_GuildList=0x6279
OP_GuildWar=0x1ffb OP_GuildWar=0x1ffb
OP_GuildLeader=0x7e09 OP_GuildLeader=0x7e09
OP_GuildDelete=0x3708 OP_GuildDelete=0x3708
@ -212,7 +211,7 @@ OP_ChannelMessage=0x2b2d
OP_Assist=0x4478 OP_Assist=0x4478
OP_AssistGroup=0x27f8 OP_AssistGroup=0x27f8
OP_MoveCoin=0x0bcf OP_MoveCoin=0x0bcf
OP_ZonePlayerToBind=0x0ecb OP_ZonePlayerToBind=0x08d8
OP_KeyRing=0x6857 OP_KeyRing=0x6857
OP_WhoAllRequest=0x674b OP_WhoAllRequest=0x674b
OP_WhoAllResponse=0x578c OP_WhoAllResponse=0x578c
@ -257,9 +256,9 @@ OP_MoveDoor=0x08e8
OP_RemoveAllDoors=0x700c OP_RemoveAllDoors=0x700c
OP_EnvDamage=0x51fd OP_EnvDamage=0x51fd
OP_BoardBoat=0x4211 OP_BoardBoat=0x4211
OP_Forage=0x5306
OP_LeaveBoat=0x7617 OP_LeaveBoat=0x7617
OP_ControlBoat=0x0ae7 OP_ControlBoat=0x0ae7
OP_Forage=0x5306
OP_SafeFallSuccess=0x2219 OP_SafeFallSuccess=0x2219
OP_RezzComplete=0x760d OP_RezzComplete=0x760d
OP_RezzRequest=0x3c21 OP_RezzRequest=0x3c21
@ -287,16 +286,16 @@ OP_ReadBook=0x72df
OP_Dye=0x23b9 OP_Dye=0x23b9
OP_InterruptCast=0x048c OP_InterruptCast=0x048c
OP_AAAction=0x424e OP_AAAction=0x424e
OP_LeadershipExpToggle=0x6c55 OP_LeadershipExpToggle=0x74bd
OP_LeadershipExpUpdate=0x2797 OP_LeadershipExpUpdate=0x2797
OP_PurchaseLeadershipAA=0x0026 OP_PurchaseLeadershipAA=0x6c55
OP_UpdateLeadershipAA=0x026 OP_UpdateLeadershipAA=0x0026
OP_MarkNPC=0x5a58 OP_MarkNPC=0x1fb5
OP_MarkRaidNPC=0x74bd #unimplemented OP_MarkRaidNPC=0x5a58 #unimplemented
OP_ClearNPCMarks=0x2003 OP_ClearNPCMarks=0x2003
OP_ClearRaidNPCMarks=0x20d3 #unimplemented OP_ClearRaidNPCMarks=0x20d3 #unimplemented
OP_DelegateAbility=0x76b8 OP_DelegateAbility=0x4c9d
OP_SetGroupTarget=0x2814 OP_SetGroupTarget=0x026
OP_Charm=0x5d92 OP_Charm=0x5d92
OP_Stun=0x36a4 OP_Stun=0x36a4
OP_SendFindableNPCs=0x4613 OP_SendFindableNPCs=0x4613
@ -318,7 +317,7 @@ OP_PVPLeaderBoardReply=0x071f
OP_PVPLeaderBoardDetailsRequest=0x3707 OP_PVPLeaderBoardDetailsRequest=0x3707
OP_PVPLeaderBoardDetailsReply=0x25b7 OP_PVPLeaderBoardDetailsReply=0x25b7
OP_RestState=0x000f OP_RestState=0x000f
OP_RespawnWindow=0x28bc OP_RespawnWindow=0x0ecb
OP_LDoNButton=0x5327 OP_LDoNButton=0x5327
OP_SetStartCity=0x6326 OP_SetStartCity=0x6326
OP_VoiceMacroIn=0x17fd OP_VoiceMacroIn=0x17fd
@ -367,7 +366,7 @@ OP_DzExpeditionInfo=0x4f7e
OP_DzExpeditionList=0x9119 OP_DzExpeditionList=0x9119
OP_DzMemberStatus=0xb2e3 OP_DzMemberStatus=0xb2e3
OP_DzLeaderStatus=0x32f0 OP_DzLeaderStatus=0x32f0
OP_DzExpeditionEndsWarning=0x7e94 OP_DzExpeditionEndsWarning=0x383c
OP_DzMemberList=0x3de9 OP_DzMemberList=0x3de9
OP_DzCompass=0x3e0e OP_DzCompass=0x3e0e
OP_DzChooseZone=0x0b7d OP_DzChooseZone=0x0b7d
@ -445,11 +444,11 @@ OP_ShopDelItem=0x724f
OP_ClickObject=0x4aa1 OP_ClickObject=0x4aa1
OP_ClickObjectAction=0x0c1e OP_ClickObjectAction=0x0c1e
OP_ClearObject=0x7a11 OP_ClearObject=0x7a11
OP_RecipeDetails=0x40d7 OP_RecipeDetails=0x6e02
OP_RecipesFavorite=0x71b1 OP_RecipesFavorite=0x71b1
OP_RecipesSearch=0x1db6 OP_RecipesSearch=0x6290
OP_RecipeReply=0x6e02 OP_RecipeReply=0x1db6
OP_RecipeAutoCombine=0x6261 OP_RecipeAutoCombine=0x40d7
OP_TradeSkillCombine=0x579a OP_TradeSkillCombine=0x579a
# Tribute Packets: # Tribute Packets:
@ -501,7 +500,7 @@ OP_GroupDisbandOther=0x74da
OP_GroupLeaderChange=0x21b4 OP_GroupLeaderChange=0x21b4
OP_GroupRoles=0x70e2 OP_GroupRoles=0x70e2
OP_GroupMakeLeader=0x4229 OP_GroupMakeLeader=0x4229
OP_DoGroupLeadershipAbility=0x1fb5 OP_DoGroupLeadershipAbility=0x6eae
OP_GroupLeadershipAAUpdate=0x02cf OP_GroupLeadershipAAUpdate=0x02cf
OP_GroupMentor=0x3342 OP_GroupMentor=0x3342
OP_InspectBuffs=0x486c OP_InspectBuffs=0x486c

View File

@ -1301,6 +1301,8 @@ void ClientList::SendClientVersionSummary(const char *Name)
uint32 ClientSoDCount = 0; uint32 ClientSoDCount = 0;
uint32 ClientUnderfootCount = 0; uint32 ClientUnderfootCount = 0;
uint32 ClientRoFCount = 0; uint32 ClientRoFCount = 0;
uint32 ClientRoF2Count = 0;
LinkedListIterator<ClientListEntry*> Iterator(clientlist); LinkedListIterator<ClientListEntry*> Iterator(clientlist);
@ -1343,6 +1345,11 @@ void ClientList::SendClientVersionSummary(const char *Name)
++ClientRoFCount; ++ClientRoFCount;
break; break;
} }
case 7:
{
++ClientRoF2Count;
break;
}
default: default:
break; break;
} }
@ -1352,7 +1359,7 @@ void ClientList::SendClientVersionSummary(const char *Name)
} }
zoneserver_list.SendEmoteMessage(Name, 0, 0, 13, "There are %i Titanium, %i SoF, %i SoD, %i UF, %i RoF clients currently connected.", zoneserver_list.SendEmoteMessage(Name, 0, 0, 13, "There are %i Titanium, %i SoF, %i SoD, %i UF, %i RoF, %i RoF2 clients currently connected.",
ClientTitaniumCount, ClientSoFCount, ClientSoDCount, ClientUnderfootCount, ClientRoFCount); ClientTitaniumCount, ClientSoFCount, ClientSoDCount, ClientUnderfootCount, ClientRoFCount, ClientRoF2Count);
} }

View File

@ -213,11 +213,21 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*
} }
else else
{ {
uint32 color = 0;
if (pp.item_tint[matslot].rgb.use_tint)
{
color = pp.item_tint[matslot].color;
}
else
{
color = inst->GetColor();
}
// Armor Materials/Models // Armor Materials/Models
cs->equip[char_num][matslot].material = item->Material; cs->equip[char_num][matslot].material = item->Material;
cs->equip[char_num][matslot].elitematerial = item->EliteMaterial; cs->equip[char_num][matslot].elitematerial = item->EliteMaterial;
cs->equip[char_num][matslot].heroforgemodel = inst->GetOrnamentHeroModel(matslot); cs->equip[char_num][matslot].heroforgemodel = inst->GetOrnamentHeroModel(matslot);
cs->equip[char_num][matslot].color.color = inst->GetColor(); cs->equip[char_num][matslot].color.color = color;
} }
} }
} }

View File

@ -2107,6 +2107,18 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
#endif //BOTS #endif //BOTS
} }
if(give_exp && give_exp->IsTempPet() && give_exp->IsPetOwnerClient()) {
if (give_exp->IsNPC() && give_exp->CastToNPC()->GetSwarmOwner()){
Mob* temp_owner = nullptr;
temp_owner = entity_list.GetMobID(give_exp->CastToNPC()->GetSwarmOwner());
if (temp_owner)
give_exp = temp_owner;
}
}
int PlayerCount = 0; // QueryServ Player Counting int PlayerCount = 0; // QueryServ Player Counting
Client *give_exp_client = nullptr; Client *give_exp_client = nullptr;
@ -3937,6 +3949,11 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) {
return; return;
} }
if (DivineAura()) {
mlog(COMBAT__PROCS, "Procs canceled, Divine Aura is in effect.");
return;
}
if(!weapon_g) { if(!weapon_g) {
TrySpellProc(nullptr, (const Item_Struct*)nullptr, on); TrySpellProc(nullptr, (const Item_Struct*)nullptr, on);
return; return;

View File

@ -538,9 +538,9 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
} }
void Client::CalcEdibleBonuses(StatBonuses* newbon) { void Client::CalcEdibleBonuses(StatBonuses* newbon) {
#if EQDEBUG >= 11 //#if EQDEBUG >= 11
std::cout<<"Client::CalcEdibleBonuses(StatBonuses* newbon)"<<std::endl; // std::cout<<"Client::CalcEdibleBonuses(StatBonuses* newbon)"<<std::endl;
#endif //#endif
// Search player slots for skill=14(food) and skill=15(drink) // Search player slots for skill=14(food) and skill=15(drink)
uint32 i; uint32 i;

View File

@ -11276,7 +11276,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
if(!results.Success()) if(!results.Success())
return; return;
int slotmaterial = Inventory::CalcMaterialFromSlot(setslot); uint8 slotmaterial = Inventory::CalcMaterialFromSlot(setslot);
c->GetTarget()->CastToBot()->SendWearChange(slotmaterial); c->GetTarget()->CastToBot()->SendWearChange(slotmaterial);
} }
else { else {

View File

@ -2685,8 +2685,11 @@ void Client::SetMaterial(int16 in_slot, uint32 item_id) {
const Item_Struct* item = database.GetItem(item_id); const Item_Struct* item = database.GetItem(item_id);
if (item && (item->ItemClass==ItemClassCommon)) if (item && (item->ItemClass==ItemClassCommon))
{ {
uint32 matslot = Inventory::CalcMaterialFromSlot(in_slot); uint8 matslot = Inventory::CalcMaterialFromSlot(in_slot);
m_pp.item_material[matslot] = GetEquipmentMaterial(matslot); if (matslot != _MaterialInvalid)
{
m_pp.item_material[matslot] = GetEquipmentMaterial(matslot);
}
} }
} }
@ -3016,31 +3019,14 @@ void Client::SetTint(int16 in_slot, uint32 color) {
// Still need to reconcile bracer01 versus bracer02 // Still need to reconcile bracer01 versus bracer02
void Client::SetTint(int16 in_slot, Color_Struct& color) { void Client::SetTint(int16 in_slot, Color_Struct& color) {
if (in_slot==MainHead)
m_pp.item_tint[MaterialHead].color=color.color;
else if (in_slot==MainArms)
m_pp.item_tint[MaterialArms].color=color.color;
else if (in_slot==MainWrist1)
m_pp.item_tint[MaterialWrist].color=color.color;
/*
// non-live behavior
else if (in_slot==SLOT_BRACER02)
m_pp.item_tint[MaterialWrist].color=color.color;
*/
else if (in_slot==MainHands)
m_pp.item_tint[MaterialHands].color=color.color;
else if (in_slot==MainPrimary)
m_pp.item_tint[MaterialPrimary].color=color.color;
else if (in_slot==MainSecondary)
m_pp.item_tint[MaterialSecondary].color=color.color;
else if (in_slot==MainChest)
m_pp.item_tint[MaterialChest].color=color.color;
else if (in_slot==MainLegs)
m_pp.item_tint[MaterialLegs].color=color.color;
else if (in_slot==MainFeet)
m_pp.item_tint[MaterialFeet].color=color.color;
database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color.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);
}
} }
void Client::SetHideMe(bool flag) void Client::SetHideMe(bool flag)

View File

@ -1428,8 +1428,12 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
/* Set item material tint */ /* Set item material tint */
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) 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) {
m_pp.item_tint[i].rgb.use_tint = 0xFF; if (m_pp.item_tint[i].rgb.use_tint == 1 || m_pp.item_tint[i].rgb.use_tint == 255)
{
m_pp.item_tint[i].rgb.use_tint = 0xFF;
}
}
if (level){ level = m_pp.level; } if (level){ level = m_pp.level; }
@ -5745,7 +5749,7 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
} }
else else
{ {
std::list<int> pathlist = zone->pathing->FindRoute(Start, End); std::deque<int> pathlist = zone->pathing->FindRoute(Start, End);
if (pathlist.size() == 0) if (pathlist.size() == 0)
{ {
@ -5784,7 +5788,7 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
p.z = GetZ(); p.z = GetZ();
points.push_back(p); points.push_back(p);
for (std::list<int>::iterator Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator) for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator)
{ {
if ((*Iterator) == -1) // Teleporter if ((*Iterator) == -1) // Teleporter
{ {

View File

@ -2664,7 +2664,7 @@ void EntityList::FindPathsToAllNPCs()
while (it != npc_list.end()) { while (it != npc_list.end()) {
Map::Vertex Node0 = zone->pathing->GetPathNodeCoordinates(0, false); Map::Vertex Node0 = zone->pathing->GetPathNodeCoordinates(0, false);
Map::Vertex Dest(it->second->GetX(), it->second->GetY(), it->second->GetZ()); Map::Vertex Dest(it->second->GetX(), it->second->GetY(), it->second->GetZ());
std::list<int> Route = zone->pathing->FindRoute(Node0, Dest); std::deque<int> Route = zone->pathing->FindRoute(Node0, Dest);
if (Route.size() == 0) if (Route.size() == 0)
printf("Unable to find a route to %s\n", it->second->GetName()); printf("Unable to find a route to %s\n", it->second->GetName());
else else

View File

@ -158,7 +158,7 @@ void Mob::CalculateNewFearpoint()
Map::Vertex CurrentPosition(GetX(), GetY(), GetZ()); Map::Vertex CurrentPosition(GetX(), GetY(), GetZ());
std::list<int> Route = zone->pathing->FindRoute(CurrentPosition, Loc); std::deque<int> Route = zone->pathing->FindRoute(CurrentPosition, Loc);
if(Route.size() > 0) if(Route.size() > 0)
{ {

View File

@ -542,6 +542,8 @@ float Mob::_GetMovementSpeed(int mod) const
// http://everquest.allakhazam.com/db/item.html?item=1721;page=1;howmany=50#m10822246245352 // http://everquest.allakhazam.com/db/item.html?item=1721;page=1;howmany=50#m10822246245352
if (IsRooted()) if (IsRooted())
return 0.0f; return 0.0f;
else if (IsPseudoRooted())
return 0.00001f;
float speed_mod = runspeed; float speed_mod = runspeed;
@ -2795,10 +2797,17 @@ uint32 Mob::GetEquipmentColor(uint8 material_slot) const
{ {
const Item_Struct *item; const Item_Struct *item;
item = database.GetItem(GetEquipment(material_slot)); if (armor_tint[material_slot])
if(item != 0)
{ {
return item->Color; return armor_tint[material_slot];
}
else
{
item = database.GetItem(GetEquipment(material_slot));
if (item != 0)
{
return item->Color;
}
} }
return 0; return 0;
@ -5323,98 +5332,98 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
} }
if (slot < 16){ if (slot < 16){
if (id == "classes") {stat = spells[spell_id].classes[slot]; } if (id == "classes") {return spells[spell_id].classes[slot]; }
else if (id == "dieties") {stat = spells[spell_id].deities[slot];} else if (id == "dieties") {return spells[spell_id].deities[slot];}
} }
if (slot < 12){ if (slot < 12){
if (id == "base") {stat = spells[spell_id].base[slot];} if (id == "base") {return spells[spell_id].base[slot];}
else if (id == "base2") {stat = spells[spell_id].base2[slot];} else if (id == "base2") {return spells[spell_id].base2[slot];}
else if (id == "max") {stat = spells[spell_id].max[slot];} else if (id == "max") {return spells[spell_id].max[slot];}
else if (id == "formula") {spells[spell_id].formula[slot];} else if (id == "formula") {return spells[spell_id].formula[slot];}
else if (id == "effectid") {spells[spell_id].effectid[slot];} else if (id == "effectid") {return spells[spell_id].effectid[slot];}
} }
if (slot < 4){ if (slot < 4){
if (id == "components") { spells[spell_id].components[slot];} if (id == "components") { return spells[spell_id].components[slot];}
else if (id == "component_counts") {spells[spell_id].component_counts[slot];} else if (id == "component_counts") { return spells[spell_id].component_counts[slot];}
else if (id == "NoexpendReagent") {spells[spell_id].NoexpendReagent[slot];} else if (id == "NoexpendReagent") {return spells[spell_id].NoexpendReagent[slot];}
} }
if (id == "range") {stat = static_cast<int32>(spells[spell_id].range); } if (id == "range") {return static_cast<int32>(spells[spell_id].range); }
else if (id == "aoerange") {stat = static_cast<int32>(spells[spell_id].aoerange);} else if (id == "aoerange") {return static_cast<int32>(spells[spell_id].aoerange);}
else if (id == "pushback") {stat = static_cast<int32>(spells[spell_id].pushback);} else if (id == "pushback") {return static_cast<int32>(spells[spell_id].pushback);}
else if (id == "pushup") {stat = static_cast<int32>(spells[spell_id].pushup);} else if (id == "pushup") {return static_cast<int32>(spells[spell_id].pushup);}
else if (id == "cast_time") {stat = spells[spell_id].cast_time;} else if (id == "cast_time") {return spells[spell_id].cast_time;}
else if (id == "recovery_time") {stat = spells[spell_id].recovery_time;} else if (id == "recovery_time") {return spells[spell_id].recovery_time;}
else if (id == "recast_time") {stat = spells[spell_id].recast_time;} else if (id == "recast_time") {return spells[spell_id].recast_time;}
else if (id == "buffdurationformula") {stat = spells[spell_id].buffdurationformula;} else if (id == "buffdurationformula") {return spells[spell_id].buffdurationformula;}
else if (id == "buffduration") {stat = spells[spell_id].buffduration;} else if (id == "buffduration") {return spells[spell_id].buffduration;}
else if (id == "AEDuration") {stat = spells[spell_id].AEDuration;} else if (id == "AEDuration") {return spells[spell_id].AEDuration;}
else if (id == "mana") {stat = spells[spell_id].mana;} else if (id == "mana") {return spells[spell_id].mana;}
//else if (id == "LightType") {stat = spells[spell_id].LightType;} - Not implemented //else if (id == "LightType") {stat = spells[spell_id].LightType;} - Not implemented
else if (id == "goodEffect") {stat = spells[spell_id].goodEffect;} else if (id == "goodEffect") {return spells[spell_id].goodEffect;}
else if (id == "Activated") {stat = spells[spell_id].Activated;} else if (id == "Activated") {return spells[spell_id].Activated;}
else if (id == "resisttype") {stat = spells[spell_id].resisttype;} else if (id == "resisttype") {return spells[spell_id].resisttype;}
else if (id == "targettype") {stat = spells[spell_id].targettype;} else if (id == "targettype") {return spells[spell_id].targettype;}
else if (id == "basedeiff") {stat = spells[spell_id].basediff;} else if (id == "basedeiff") {return spells[spell_id].basediff;}
else if (id == "skill") {stat = spells[spell_id].skill;} else if (id == "skill") {return spells[spell_id].skill;}
else if (id == "zonetype") {stat = spells[spell_id].zonetype;} else if (id == "zonetype") {return spells[spell_id].zonetype;}
else if (id == "EnvironmentType") {stat = spells[spell_id].EnvironmentType;} else if (id == "EnvironmentType") {return spells[spell_id].EnvironmentType;}
else if (id == "TimeOfDay") {stat = spells[spell_id].TimeOfDay;} else if (id == "TimeOfDay") {return spells[spell_id].TimeOfDay;}
else if (id == "CastingAnim") {stat = spells[spell_id].CastingAnim;} else if (id == "CastingAnim") {return spells[spell_id].CastingAnim;}
else if (id == "SpellAffectIndex") {stat = spells[spell_id].SpellAffectIndex; } else if (id == "SpellAffectIndex") {return spells[spell_id].SpellAffectIndex; }
else if (id == "disallow_sit") {stat = spells[spell_id].disallow_sit; } else if (id == "disallow_sit") {return spells[spell_id].disallow_sit; }
//else if (id == "spellanim") {stat = spells[spell_id].spellanim; } - Not implemented //else if (id == "spellanim") {stat = spells[spell_id].spellanim; } - Not implemented
else if (id == "uninterruptable") {stat = spells[spell_id].uninterruptable; } else if (id == "uninterruptable") {return spells[spell_id].uninterruptable; }
else if (id == "ResistDiff") {stat = spells[spell_id].ResistDiff; } else if (id == "ResistDiff") {return spells[spell_id].ResistDiff; }
else if (id == "dot_stacking_exemp") {stat = spells[spell_id].dot_stacking_exempt; } else if (id == "dot_stacking_exemp") {return spells[spell_id].dot_stacking_exempt; }
else if (id == "RecourseLink") {stat = spells[spell_id].RecourseLink; } else if (id == "RecourseLink") {return spells[spell_id].RecourseLink; }
else if (id == "no_partial_resist") {stat = spells[spell_id].no_partial_resist; } else if (id == "no_partial_resist") {return spells[spell_id].no_partial_resist; }
else if (id == "short_buff_box") {stat = spells[spell_id].short_buff_box; } else if (id == "short_buff_box") {return spells[spell_id].short_buff_box; }
else if (id == "descnum") {stat = spells[spell_id].descnum; } else if (id == "descnum") {return spells[spell_id].descnum; }
else if (id == "effectdescnum") {stat = spells[spell_id].effectdescnum; } else if (id == "effectdescnum") {return spells[spell_id].effectdescnum; }
else if (id == "npc_no_los") {stat = spells[spell_id].npc_no_los; } else if (id == "npc_no_los") {return spells[spell_id].npc_no_los; }
else if (id == "reflectable") {stat = spells[spell_id].reflectable; } else if (id == "reflectable") {return spells[spell_id].reflectable; }
else if (id == "bonushate") {stat = spells[spell_id].bonushate; } else if (id == "bonushate") {return spells[spell_id].bonushate; }
else if (id == "EndurCost") {stat = spells[spell_id].EndurCost; } else if (id == "EndurCost") {return spells[spell_id].EndurCost; }
else if (id == "EndurTimerIndex") {stat = spells[spell_id].EndurTimerIndex; } else if (id == "EndurTimerIndex") {return spells[spell_id].EndurTimerIndex; }
else if (id == "IsDisciplineBuf") {stat = spells[spell_id].IsDisciplineBuff; } else if (id == "IsDisciplineBuf") {return spells[spell_id].IsDisciplineBuff; }
else if (id == "HateAdded") {stat = spells[spell_id].HateAdded; } else if (id == "HateAdded") {return spells[spell_id].HateAdded; }
else if (id == "EndurUpkeep") {stat = spells[spell_id].EndurUpkeep; } else if (id == "EndurUpkeep") {return spells[spell_id].EndurUpkeep; }
else if (id == "numhitstype") {stat = spells[spell_id].numhitstype; } else if (id == "numhitstype") {return spells[spell_id].numhitstype; }
else if (id == "numhits") {stat = spells[spell_id].numhits; } else if (id == "numhits") {return spells[spell_id].numhits; }
else if (id == "pvpresistbase") {stat = spells[spell_id].pvpresistbase; } else if (id == "pvpresistbase") {return spells[spell_id].pvpresistbase; }
else if (id == "pvpresistcalc") {stat = spells[spell_id].pvpresistcalc; } else if (id == "pvpresistcalc") {return spells[spell_id].pvpresistcalc; }
else if (id == "pvpresistcap") {stat = spells[spell_id].pvpresistcap; } else if (id == "pvpresistcap") {return spells[spell_id].pvpresistcap; }
else if (id == "spell_category") {stat = spells[spell_id].spell_category; } else if (id == "spell_category") {return spells[spell_id].spell_category; }
else if (id == "can_mgb") {stat = spells[spell_id].can_mgb; } else if (id == "can_mgb") {return spells[spell_id].can_mgb; }
else if (id == "dispel_flag") {stat = spells[spell_id].dispel_flag; } else if (id == "dispel_flag") {return spells[spell_id].dispel_flag; }
else if (id == "MinResist") {stat = spells[spell_id].MinResist; } else if (id == "MinResist") {return spells[spell_id].MinResist; }
else if (id == "MaxResist") {stat = spells[spell_id].MaxResist; } else if (id == "MaxResist") {return spells[spell_id].MaxResist; }
else if (id == "viral_targets") {stat = spells[spell_id].viral_targets; } else if (id == "viral_targets") {return spells[spell_id].viral_targets; }
else if (id == "viral_timer") {stat = spells[spell_id].viral_timer; } else if (id == "viral_timer") {return spells[spell_id].viral_timer; }
else if (id == "NimbusEffect") {stat = spells[spell_id].NimbusEffect; } else if (id == "NimbusEffect") {return spells[spell_id].NimbusEffect; }
else if (id == "directional_start") {stat = static_cast<int32>(spells[spell_id].directional_start); } else if (id == "directional_start") {return static_cast<int32>(spells[spell_id].directional_start); }
else if (id == "directional_end") {stat = static_cast<int32>(spells[spell_id].directional_end); } else if (id == "directional_end") {return static_cast<int32>(spells[spell_id].directional_end); }
else if (id == "not_extendable") {stat = spells[spell_id].not_extendable; } else if (id == "not_extendable") {return spells[spell_id].not_extendable; }
else if (id == "suspendable") {stat = spells[spell_id].suspendable; } else if (id == "suspendable") {return spells[spell_id].suspendable; }
else if (id == "viral_range") {stat = spells[spell_id].viral_range; } else if (id == "viral_range") {return spells[spell_id].viral_range; }
else if (id == "spellgroup") {stat = spells[spell_id].spellgroup; } else if (id == "spellgroup") {return spells[spell_id].spellgroup; }
else if (id == "rank") {stat = spells[spell_id].rank; } else if (id == "rank") {return spells[spell_id].rank; }
else if (id == "powerful_flag") {stat = spells[spell_id].powerful_flag; } else if (id == "powerful_flag") {return spells[spell_id].powerful_flag; }
else if (id == "CastRestriction") {stat = spells[spell_id].CastRestriction; } else if (id == "CastRestriction") {return spells[spell_id].CastRestriction; }
else if (id == "AllowRest") {stat = spells[spell_id].AllowRest; } else if (id == "AllowRest") {return spells[spell_id].AllowRest; }
else if (id == "InCombat") {stat = spells[spell_id].InCombat; } else if (id == "InCombat") {return spells[spell_id].InCombat; }
else if (id == "OutofCombat") {stat = spells[spell_id].OutofCombat; } else if (id == "OutofCombat") {return spells[spell_id].OutofCombat; }
else if (id == "aemaxtargets") {stat = spells[spell_id].aemaxtargets; } else if (id == "aemaxtargets") {return spells[spell_id].aemaxtargets; }
else if (id == "maxtargets") {stat = spells[spell_id].maxtargets; } else if (id == "maxtargets") {return spells[spell_id].maxtargets; }
else if (id == "persistdeath") {stat = spells[spell_id].persistdeath; } else if (id == "persistdeath") {return spells[spell_id].persistdeath; }
else if (id == "min_dist") {stat = static_cast<int32>(spells[spell_id].min_dist); } else if (id == "min_dist") {return static_cast<int32>(spells[spell_id].min_dist); }
else if (id == "min_dist_mod") {stat = static_cast<int32>(spells[spell_id].min_dist_mod); } else if (id == "min_dist_mod") {return static_cast<int32>(spells[spell_id].min_dist_mod); }
else if (id == "max_dist") {stat = static_cast<int32>(spells[spell_id].max_dist); } else if (id == "max_dist") {return static_cast<int32>(spells[spell_id].max_dist); }
else if (id == "min_range") {stat = static_cast<int32>(spells[spell_id].min_range); } else if (id == "min_range") {return static_cast<int32>(spells[spell_id].min_range); }
else if (id == "DamageShieldType") {stat = spells[spell_id].DamageShieldType; } else if (id == "DamageShieldType") {return spells[spell_id].DamageShieldType; }
return stat; return stat;
} }

View File

@ -1225,7 +1225,7 @@ protected:
Map::Vertex PathingLastPosition; Map::Vertex PathingLastPosition;
int PathingLoopCount; int PathingLoopCount;
int PathingLastNodeVisited; int PathingLastNodeVisited;
std::list<int> Route; std::deque<int> Route;
LOSType PathingLOSState; LOSType PathingLOSState;
Timer *PathingLOSCheckTimer; Timer *PathingLOSCheckTimer;
Timer *PathingRouteUpdateTimerShort; Timer *PathingRouteUpdateTimerShort;

View File

@ -2751,7 +2751,7 @@ DBnpcspells_Struct* ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID) {
npc_spells_cache[iDBSpellsID]->attack_proc = tmpattack_proc; npc_spells_cache[iDBSpellsID]->attack_proc = tmpattack_proc;
npc_spells_cache[iDBSpellsID]->proc_chance = tmpproc_chance; npc_spells_cache[iDBSpellsID]->proc_chance = tmpproc_chance;
npc_spells_cache[iDBSpellsID]->range_proc = tmprange_proc; npc_spells_cache[iDBSpellsID]->range_proc = tmprange_proc;
npc_spells_cache[iDBSpellsID]->rproc_chance = tmpdproc_chance; npc_spells_cache[iDBSpellsID]->rproc_chance = tmprproc_chance;
npc_spells_cache[iDBSpellsID]->defensive_proc = tmpdefensive_proc; npc_spells_cache[iDBSpellsID]->defensive_proc = tmpdefensive_proc;
npc_spells_cache[iDBSpellsID]->dproc_chance = tmpdproc_chance; npc_spells_cache[iDBSpellsID]->dproc_chance = tmpdproc_chance;
npc_spells_cache[iDBSpellsID]->fail_recast = tmppfail_recast; npc_spells_cache[iDBSpellsID]->fail_recast = tmppfail_recast;

View File

@ -476,7 +476,7 @@ void NPC::CheckMinMaxLevel(Mob *them)
if(themlevel < (*cur)->min_level || themlevel > (*cur)->max_level) if(themlevel < (*cur)->min_level || themlevel > (*cur)->max_level)
{ {
material = Inventory::CalcMaterialFromSlot((*cur)->equip_slot); material = Inventory::CalcMaterialFromSlot((*cur)->equip_slot);
if(material != 0xFF) if (material != _MaterialInvalid)
SendWearChange(material); SendWearChange(material);
cur = itemlist.erase(cur); cur = itemlist.erase(cur);
@ -1942,6 +1942,7 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; } else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; }
else if(id == "special_abilities") { ProcessSpecialAbilities(val.c_str()); return; } else if(id == "special_abilities") { ProcessSpecialAbilities(val.c_str()); return; }
else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; } else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; }
else if(id == "attack_delay") { attack_delay = atoi(val.c_str()); CalcBonuses(); return; }
else if(id == "atk") { ATK = atoi(val.c_str()); return; } else if(id == "atk") { ATK = atoi(val.c_str()); return; }
else if(id == "accuracy") { accuracy_rating = atoi(val.c_str()); return; } else if(id == "accuracy") { accuracy_rating = atoi(val.c_str()); return; }
else if(id == "avoidance") { avoidance_rating = atoi(val.c_str()); return; } else if(id == "avoidance") { avoidance_rating = atoi(val.c_str()); return; }

View File

@ -155,6 +155,7 @@ public:
virtual void RangedAttack(Mob* other); virtual void RangedAttack(Mob* other);
virtual void ThrowingAttack(Mob* other) { } virtual void ThrowingAttack(Mob* other) { }
int32 GetNumberOfAttacks() const { return attack_count; } int32 GetNumberOfAttacks() const { return attack_count; }
void DoRangedAttackDmg(Mob* other, bool Launch=true, int16 damage_mod=0, int16 chance_mod=0, SkillUseTypes skill=SkillArchery, float speed=4.0f, const char *IDFile = nullptr);
bool DatabaseCastAccepted(int spell_id); bool DatabaseCastAccepted(int spell_id);
bool IsFactionListAlly(uint32 other_faction); bool IsFactionListAlly(uint32 other_faction);
@ -259,6 +260,7 @@ public:
uint32 GetMinDMG() const {return min_dmg;} uint32 GetMinDMG() const {return min_dmg;}
int16 GetSlowMitigation() const {return slow_mitigation;} int16 GetSlowMitigation() const {return slow_mitigation;}
float GetAttackSpeed() const {return attack_speed;} float GetAttackSpeed() const {return attack_speed;}
uint8 GetAttackDelay() const {return attack_delay;}
bool IsAnimal() const { return(bodytype == BT_Animal); } bool IsAnimal() const { return(bodytype == BT_Animal); }
uint16 GetPetSpellID() const {return pet_spell_id;} uint16 GetPetSpellID() const {return pet_spell_id;}
void SetPetSpellID(uint16 amt) {pet_spell_id = amt;} void SetPetSpellID(uint16 amt) {pet_spell_id = amt;}

View File

@ -205,15 +205,15 @@ Map::Vertex PathManager::GetPathNodeCoordinates(int NodeNumber, bool BestZ)
} }
std::list<int> PathManager::FindRoute(int startID, int endID) std::deque<int> PathManager::FindRoute(int startID, int endID)
{ {
_log(PATHING__DEBUG, "FindRoute from node %i to %i", startID, endID); _log(PATHING__DEBUG, "FindRoute from node %i to %i", startID, endID);
memset(ClosedListFlag, 0, sizeof(int) * Head.PathNodeCount); memset(ClosedListFlag, 0, sizeof(int) * Head.PathNodeCount);
std::list<AStarNode> OpenList, ClosedList; std::deque<AStarNode> OpenList, ClosedList;
std::list<int>Route; std::deque<int>Route;
AStarNode AStarEntry, CurrentNode; AStarNode AStarEntry, CurrentNode;
@ -251,7 +251,7 @@ std::list<int> PathManager::FindRoute(int startID, int endID)
Route.push_back(endID); Route.push_back(endID);
std::list<AStarNode>::iterator RouteIterator; std::deque<AStarNode>::iterator RouteIterator;
while(CurrentNode.PathNodeID != startID) while(CurrentNode.PathNodeID != startID)
{ {
@ -300,7 +300,7 @@ std::list<int> PathManager::FindRoute(int startID, int endID)
bool AlreadyInOpenList = false; bool AlreadyInOpenList = false;
std::list<AStarNode>::iterator OpenListIterator, InsertionPoint = OpenList.end(); std::deque<AStarNode>::iterator OpenListIterator, InsertionPoint = OpenList.end();
for(OpenListIterator = OpenList.begin(); OpenListIterator != OpenList.end(); ++OpenListIterator) for(OpenListIterator = OpenList.begin(); OpenListIterator != OpenList.end(); ++OpenListIterator)
{ {
@ -350,11 +350,11 @@ bool SortPathNodesByDistance(PathNodeSortStruct n1, PathNodeSortStruct n2)
return n1.Distance < n2.Distance; return n1.Distance < n2.Distance;
} }
std::list<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End) std::deque<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
{ {
_log(PATHING__DEBUG, "FindRoute(%8.3f, %8.3f, %8.3f, %8.3f, %8.3f, %8.3f)", Start.x, Start.y, Start.z, End.x, End.y, End.z); _log(PATHING__DEBUG, "FindRoute(%8.3f, %8.3f, %8.3f, %8.3f, %8.3f, %8.3f)", Start.x, Start.y, Start.z, End.x, End.y, End.z);
std::list<int> noderoute; std::deque<int> noderoute;
float CandidateNodeRangeXY = RuleR(Pathing, CandidateNodeRangeXY); float CandidateNodeRangeXY = RuleR(Pathing, CandidateNodeRangeXY);
@ -365,7 +365,7 @@ std::list<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
// //
int ClosestPathNodeToStart = -1; int ClosestPathNodeToStart = -1;
std::list<PathNodeSortStruct> SortedByDistance; std::deque<PathNodeSortStruct> SortedByDistance;
PathNodeSortStruct TempNode; PathNodeSortStruct TempNode;
@ -382,9 +382,9 @@ std::list<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
} }
} }
SortedByDistance.sort(SortPathNodesByDistance); std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance);
for(std::list<PathNodeSortStruct>::iterator Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator)
{ {
_log(PATHING__DEBUG, "Checking Reachability of Node %i from Start Position.", PathNodes[(*Iterator).id].id); _log(PATHING__DEBUG, "Checking Reachability of Node %i from Start Position.", PathNodes[(*Iterator).id].id);
@ -420,9 +420,9 @@ std::list<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
} }
} }
SortedByDistance.sort(SortPathNodesByDistance); std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance);
for(std::list<PathNodeSortStruct>::iterator Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator)
{ {
_log(PATHING__DEBUG, "Checking Reachability of Node %i from End Position.", PathNodes[(*Iterator).id].id); _log(PATHING__DEBUG, "Checking Reachability of Node %i from End Position.", PathNodes[(*Iterator).id].id);
_log(PATHING__DEBUG, " (%8.3f, %8.3f, %8.3f) to (%8.3f, %8.3f, %8.3f)", _log(PATHING__DEBUG, " (%8.3f, %8.3f, %8.3f) to (%8.3f, %8.3f, %8.3f)",
@ -456,7 +456,7 @@ std::list<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
{ {
int CulledNodes = 0; int CulledNodes = 0;
std::list<int>::iterator First, Second; std::deque<int>::iterator First, Second;
while((noderoute.size() >= 2) && (CulledNodes < NodesToAttemptToCull)) while((noderoute.size() >= 2) && (CulledNodes < NodesToAttemptToCull))
{ {
@ -487,7 +487,7 @@ std::list<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
{ {
int CulledNodes = 0; int CulledNodes = 0;
std::list<int>::iterator First, Second; std::deque<int>::iterator First, Second;
while((noderoute.size() >= 2) && (CulledNodes < NodesToAttemptToCull)) while((noderoute.size() >= 2) && (CulledNodes < NodesToAttemptToCull))
{ {
@ -611,7 +611,7 @@ void PathManager::MeshTest()
if(j == i) if(j == i)
continue; continue;
std::list<int> Route = FindRoute(PathNodes[i].id, PathNodes[j].id); std::deque<int> Route = FindRoute(PathNodes[i].id, PathNodes[j].id);
if(Route.size() == 0) if(Route.size() == 0)
{ {
@ -638,7 +638,7 @@ void PathManager::SimpleMeshTest()
for(uint32 j = 1; j < Head.PathNodeCount; ++j) for(uint32 j = 1; j < Head.PathNodeCount; ++j)
{ {
std::list<int> Route = FindRoute(PathNodes[0].id, PathNodes[j].id); std::deque<int> Route = FindRoute(PathNodes[0].id, PathNodes[j].id);
if(Route.size() == 0) if(Route.size() == 0)
{ {
@ -1103,7 +1103,7 @@ int PathManager::FindNearestPathNode(Map::Vertex Position)
int ClosestPathNodeToStart = -1; int ClosestPathNodeToStart = -1;
std::list<PathNodeSortStruct> SortedByDistance; std::deque<PathNodeSortStruct> SortedByDistance;
PathNodeSortStruct TempNode; PathNodeSortStruct TempNode;
@ -1120,9 +1120,9 @@ int PathManager::FindNearestPathNode(Map::Vertex Position)
} }
} }
SortedByDistance.sort(SortPathNodesByDistance); std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance);
for(std::list<PathNodeSortStruct>::iterator Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator)
{ {
_log(PATHING__DEBUG, "Checking Reachability of Node %i from Start Position.", PathNodes[(*Iterator).id].id); _log(PATHING__DEBUG, "Checking Reachability of Node %i from Start Position.", PathNodes[(*Iterator).id].id);
@ -1262,9 +1262,7 @@ void Mob::PrintRoute()
printf("Route is : "); printf("Route is : ");
std::list<int>::iterator Iterator; for(auto Iterator = Route.begin(); Iterator !=Route.end(); ++Iterator)
for(Iterator = Route.begin(); Iterator !=Route.end(); ++Iterator)
{ {
printf("%i, ", (*Iterator)); printf("%i, ", (*Iterator));
} }

View File

@ -3,7 +3,7 @@
#include "map.h" #include "map.h"
#include <list> #include <deque>
class Client; class Client;
class Mob; class Mob;
@ -60,8 +60,8 @@ public:
static PathManager *LoadPathFile(const char *ZoneName); static PathManager *LoadPathFile(const char *ZoneName);
bool loadPaths(FILE *fp); bool loadPaths(FILE *fp);
void PrintPathing(); void PrintPathing();
std::list<int> FindRoute(Map::Vertex Start, Map::Vertex End); std::deque<int> FindRoute(Map::Vertex Start, Map::Vertex End);
std::list<int> FindRoute(int startID, int endID); std::deque<int> FindRoute(int startID, int endID);
Map::Vertex GetPathNodeCoordinates(int NodeNumber, bool BestZ = true); Map::Vertex GetPathNodeCoordinates(int NodeNumber, bool BestZ = true);
bool CheckLosFN(Map::Vertex a, Map::Vertex b); bool CheckLosFN(Map::Vertex a, Map::Vertex b);

View File

@ -2119,6 +2119,32 @@ XS(XS_NPC_GetAttackSpeed)
XSRETURN(1); XSRETURN(1);
} }
XS(XS_NPC_GetAttackDelay); /* prototype to pass -Wmissing-prototypes */
XS(XS_NPC_GetAttackDelay)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: NPC::GetAttackDelay(THIS)");
{
NPC * THIS;
float RETVAL;
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 == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetAttackDelay();
XSprePUSH; PUSHn((double)RETVAL);
}
XSRETURN(1);
}
XS(XS_NPC_GetAccuracyRating); /* prototype to pass -Wmissing-prototypes */ XS(XS_NPC_GetAccuracyRating); /* prototype to pass -Wmissing-prototypes */
XS(XS_NPC_GetAccuracyRating) XS(XS_NPC_GetAccuracyRating)
{ {
@ -2145,6 +2171,32 @@ XS(XS_NPC_GetAccuracyRating)
XSRETURN(1); XSRETURN(1);
} }
XS(XS_NPC_GetAvoidanceRating); /* prototype to pass -Wmissing-prototypes */
XS(XS_NPC_GetAvoidanceRating)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: NPC::GetAvoidanceyRating(THIS)");
{
NPC * THIS;
int32 RETVAL;
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 == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetAvoidanceRating();
XSprePUSH; PUSHu((UV)RETVAL);
}
XSRETURN(1);
}
XS(XS_NPC_GetSpawnKillCount); /* prototype to pass -Wmissing-prototypes */ XS(XS_NPC_GetSpawnKillCount); /* prototype to pass -Wmissing-prototypes */
XS(XS_NPC_GetSpawnKillCount) XS(XS_NPC_GetSpawnKillCount)
{ {
@ -2245,6 +2297,81 @@ XS(XS_NPC_GetMerchantProbability) {
XSRETURN(1); XSRETURN(1);
} }
XS(XS_NPC_AddMeleeProc);
XS(XS_NPC_AddMeleeProc) {
dXSARGS;
if (items != 3)
Perl_croak(aTHX_ "Usage: NPC::AddMeleeProc(THIS,spellid,chance)");
{
NPC * THIS;
int spell_id = (int)SvIV(ST(1));
int chance = (int)SvIV(ST(2));
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->AddProcToWeapon(spell_id, true, chance);
}
XSRETURN_EMPTY;
}
XS(XS_NPC_AddRangedProc);
XS(XS_NPC_AddRangedProc) {
dXSARGS;
if (items != 3)
Perl_croak(aTHX_ "Usage: NPC::AddRangedProc(THIS,spellid,chance)");
{
NPC * THIS;
int spell_id = (int)SvIV(ST(1));
int chance = (int)SvIV(ST(2));
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->AddDefensiveProc(spell_id,chance);
}
XSRETURN_EMPTY;
}
XS(XS_NPC_AddDefensiveProc);
XS(XS_NPC_AddDefensiveProc) {
dXSARGS;
if (items != 3)
Perl_croak(aTHX_ "Usage: NPC::AddDefensiveProc(THIS,spellid,chance)");
{
NPC * THIS;
int spell_id = (int)SvIV(ST(1));
int chance = (int)SvIV(ST(2));
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->AddProcToWeapon(spell_id, true, chance);
}
XSRETURN_EMPTY;
}
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
#endif #endif
@ -2342,11 +2469,16 @@ XS(boot_NPC)
newXSproto(strcpy(buf, "GetSpellFocusHeal"), XS_NPC_GetSpellFocusHeal, file, "$"); newXSproto(strcpy(buf, "GetSpellFocusHeal"), XS_NPC_GetSpellFocusHeal, file, "$");
newXSproto(strcpy(buf, "GetSlowMitigation"), XS_NPC_GetSlowMitigation, file, "$"); newXSproto(strcpy(buf, "GetSlowMitigation"), XS_NPC_GetSlowMitigation, file, "$");
newXSproto(strcpy(buf, "GetAttackSpeed"), XS_NPC_GetAttackSpeed, file, "$"); newXSproto(strcpy(buf, "GetAttackSpeed"), XS_NPC_GetAttackSpeed, file, "$");
newXSproto(strcpy(buf, "GetAttackDelay"), XS_NPC_GetAttackDelay, file, "$");
newXSproto(strcpy(buf, "GetAccuracyRating"), XS_NPC_GetAccuracyRating, file, "$"); newXSproto(strcpy(buf, "GetAccuracyRating"), XS_NPC_GetAccuracyRating, file, "$");
newXSproto(strcpy(buf, "GetAvoidanceRating"), XS_NPC_GetAvoidanceRating, file, "$");
newXSproto(strcpy(buf, "GetSpawnKillCount"), XS_NPC_GetSpawnKillCount, file, "$"); newXSproto(strcpy(buf, "GetSpawnKillCount"), XS_NPC_GetSpawnKillCount, file, "$");
newXSproto(strcpy(buf, "GetScore"), XS_NPC_GetScore, file, "$"); newXSproto(strcpy(buf, "GetScore"), XS_NPC_GetScore, file, "$");
newXSproto(strcpy(buf, "SetMerchantProbability"), XS_NPC_SetMerchantProbability, file, "$$"); newXSproto(strcpy(buf, "SetMerchantProbability"), XS_NPC_SetMerchantProbability, file, "$$");
newXSproto(strcpy(buf, "GetMerchantProbability"), XS_NPC_GetMerchantProbability, file, "$"); newXSproto(strcpy(buf, "GetMerchantProbability"), XS_NPC_GetMerchantProbability, file, "$");
newXSproto(strcpy(buf, "AddMeleeProc"), XS_NPC_AddMeleeProc, file, "$$$");
newXSproto(strcpy(buf, "AddRangedProc"), XS_NPC_AddRangedProc, file, "$$$");
newXSproto(strcpy(buf, "AddDefensiveProc"), XS_NPC_AddDefensiveProc, file, "$$$");
XSRETURN_YES; XSRETURN_YES;
} }

View File

@ -103,6 +103,9 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
if (!who) if (!who)
return; return;
if(who->GetInvul() || who->GetSpecialAbility(IMMUNE_MELEE) || who->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE))
return; //-5?
int32 hate = max_damage; int32 hate = max_damage;
if(hate_override > -1) if(hate_override > -1)
hate = hate_override; hate = hate_override;
@ -1059,8 +1062,8 @@ bool Mob::TryProjectileAttack(Mob* other, const Item_Struct *item, SkillUseTypes
if(item) if(item)
SendItemAnimation(other, item, skillInUse, speed); SendItemAnimation(other, item, skillInUse, speed);
else if (IsNPC()) //else if (IsNPC())
ProjectileAnimation(other, 0,false,speed,0,0,0,CastToNPC()->GetAmmoIDfile(),skillInUse); //ProjectileAnimation(other, 0,false,speed,0,0,0,CastToNPC()->GetAmmoIDfile(),skillInUse);
return true; return true;
} }
@ -1097,12 +1100,19 @@ void Mob::ProjectileAttack()
if (ProjectileAtk[i].hit_increment <= ProjectileAtk[i].increment){ if (ProjectileAtk[i].hit_increment <= ProjectileAtk[i].increment){
if (target){ if (target){
if (ProjectileAtk[i].skill == SkillArchery)
DoArcheryAttackDmg(target, nullptr, nullptr,ProjectileAtk[i].wpn_dmg,0,0,0,ProjectileAtk[i].ranged_id, ProjectileAtk[i].ammo_id, nullptr, ProjectileAtk[i].ammo_slot); if (IsNPC())
else if (ProjectileAtk[i].skill == SkillThrowing) CastToNPC()->DoRangedAttackDmg(target, false, ProjectileAtk[i].wpn_dmg,0, static_cast<SkillUseTypes>(ProjectileAtk[i].skill));
DoThrowingAttackDmg(target, nullptr, nullptr,ProjectileAtk[i].wpn_dmg,0,0,0, ProjectileAtk[i].ranged_id, ProjectileAtk[i].ammo_slot);
else if (ProjectileAtk[i].skill == SkillConjuration && IsValidSpell(ProjectileAtk[i].wpn_dmg)) else
SpellOnTarget(ProjectileAtk[i].wpn_dmg, target, false, true, spells[ProjectileAtk[i].wpn_dmg].ResistDiff, true); {
if (ProjectileAtk[i].skill == SkillArchery)
DoArcheryAttackDmg(target, nullptr, nullptr,ProjectileAtk[i].wpn_dmg,0,0,0,ProjectileAtk[i].ranged_id, ProjectileAtk[i].ammo_id, nullptr, ProjectileAtk[i].ammo_slot);
else if (ProjectileAtk[i].skill == SkillThrowing)
DoThrowingAttackDmg(target, nullptr, nullptr,ProjectileAtk[i].wpn_dmg,0,0,0, ProjectileAtk[i].ranged_id, ProjectileAtk[i].ammo_slot);
else if (ProjectileAtk[i].skill == SkillConjuration && IsValidSpell(ProjectileAtk[i].wpn_dmg))
SpellOnTarget(ProjectileAtk[i].wpn_dmg, target, false, true, spells[ProjectileAtk[i].wpn_dmg].ResistDiff, true);
}
} }
ProjectileAtk[i].increment = 0; ProjectileAtk[i].increment = 0;
@ -1187,14 +1197,8 @@ void NPC::RangedAttack(Mob* other)
attacks = attacks > 0 ? attacks : 1; attacks = attacks > 0 ? attacks : 1;
for(int i = 0; i < attacks; ++i) { for(int i = 0; i < attacks; ++i) {
//if we have SPECATK_RANGED_ATK set then we range attack without weapon or ammo
const Item_Struct* weapon = nullptr;
const Item_Struct* ammo = nullptr;
if(!GetSpecialAbility(SPECATK_RANGED_ATK)) if(!GetSpecialAbility(SPECATK_RANGED_ATK))
{
//find our bow and ammo return if we can't find them...
return; return;
}
int sa_min_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 4); //Min Range of NPC attack int sa_min_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 4); //Min Range of NPC attack
int sa_max_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 1); //Max Range of NPC attack int sa_max_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 1); //Max Range of NPC attack
@ -1208,17 +1212,12 @@ void NPC::RangedAttack(Mob* other)
if (sa_min_range) if (sa_min_range)
min_range = static_cast<float>(sa_min_range); min_range = static_cast<float>(sa_min_range);
mlog(COMBAT__RANGED, "Calculated bow range to be %.1f", max_range);
max_range *= max_range; max_range *= max_range;
if(DistNoRootNoZ(*other) > max_range) { if(DistNoRoot(*other) > max_range)
mlog(COMBAT__RANGED, "Ranged attack out of range...%.2f vs %.2f", DistNoRootNoZ(*other), max_range);
//target is out of range, client does a message
return; return;
} else if(DistNoRoot(*other) < (min_range * min_range))
else if(DistNoRootNoZ(*other) < (min_range * min_range))
return; return;
if(!other || !IsAttackAllowed(other) || if(!other || !IsAttackAllowed(other) ||
IsCasting() || IsCasting() ||
DivineAura() || DivineAura() ||
@ -1229,74 +1228,100 @@ void NPC::RangedAttack(Mob* other)
return; return;
} }
SkillUseTypes skillinuse = SkillArchery;
skillinuse = static_cast<SkillUseTypes>(GetRangedSkill());
if(!ammo && !GetAmmoIDfile())
ammo = database.GetItem(8005);
if(ammo)
SendItemAnimation(other, ammo, SkillArchery);
else
ProjectileAnimation(other, 0,false,0,0,0,0,GetAmmoIDfile(),skillinuse);
FaceTarget(other); FaceTarget(other);
if (!other->CheckHitChance(this, skillinuse, MainRange, GetSpecialAbilityParam(SPECATK_RANGED_ATK, 2))) DoRangedAttackDmg(other);
{
mlog(COMBAT__RANGED, "Ranged attack missed %s.", other->GetName());
other->Damage(this, 0, SPELL_UNKNOWN, skillinuse);
}
else
{
int16 WDmg = GetWeaponDamage(other, weapon);
int16 ADmg = GetWeaponDamage(other, ammo);
int32 TotalDmg = 0;
if(WDmg > 0 || ADmg > 0)
{
mlog(COMBAT__RANGED, "Ranged attack hit %s.", other->GetName());
int32 MaxDmg = max_dmg * RuleR(Combat, ArcheryNPCMultiplier); // should add a field to npc_types
int32 MinDmg = min_dmg * RuleR(Combat, ArcheryNPCMultiplier);
if(RuleB(Combat, UseIntervalAC))
TotalDmg = MaxDmg;
else
TotalDmg = zone->random.Int(MinDmg, MaxDmg);
TotalDmg += TotalDmg * GetSpecialAbilityParam(SPECATK_RANGED_ATK, 3) / 100; //Damage modifier
other->AvoidDamage(this, TotalDmg, false);
other->MeleeMitigation(this, TotalDmg, MinDmg);
if (TotalDmg > 0)
CommonOutgoingHitSuccess(other, TotalDmg, skillinuse);
}
else
TotalDmg = -5;
if (TotalDmg > 0)
other->AddToHateList(this, TotalDmg, 0, false);
else
other->AddToHateList(this, 0, 0, false);
other->Damage(this, TotalDmg, SPELL_UNKNOWN, skillinuse);
if (TotalDmg > 0 && HasSkillProcSuccess() && GetTarget() && !other->HasDied())
TrySkillProc(other, skillinuse, 0, true, MainRange);
}
//try proc on hits and misses
if(other && !other->HasDied())
TrySpellProc(nullptr, (const Item_Struct*)nullptr, other, MainRange);
if (HasSkillProcs() && other && !other->HasDied())
TrySkillProc(other, skillinuse, 0, false, MainRange);
CommonBreakInvisible(); CommonBreakInvisible();
} }
} }
void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 chance_mod, SkillUseTypes skill, float speed, const char *IDFile) {
if ((other == nullptr ||
(other->HasDied())) ||
HasDied() ||
(!IsAttackAllowed(other)) ||
(other->GetInvul() ||
other->GetSpecialAbility(IMMUNE_MELEE)))
{
return;
}
SkillUseTypes skillInUse = static_cast<SkillUseTypes>(GetRangedSkill());
if (skill != skillInUse)
skillInUse = skill;
if (Launch)
{
const char *ammo = "IT10";
if (IDFile != nullptr)
ammo = IDFile;
else if (GetAmmoIDfile())
ammo = GetAmmoIDfile();
ProjectileAnimation(other, 0,false,speed,0,0,0,ammo,skillInUse);
if (RuleB(Combat, ProjectileDmgOnImpact))
{
TryProjectileAttack(other, nullptr, skillInUse, damage_mod, nullptr, nullptr, 0, speed);
return;
}
}
if (!chance_mod)
chance_mod = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 2);
if (!other->CheckHitChance(this, skillInUse, MainRange, chance_mod))
{
other->Damage(this, 0, SPELL_UNKNOWN, skillInUse);
}
else
{
int32 TotalDmg = 0;
int32 MaxDmg = max_dmg * RuleR(Combat, ArcheryNPCMultiplier); // should add a field to npc_types
int32 MinDmg = min_dmg * RuleR(Combat, ArcheryNPCMultiplier);
if(RuleB(Combat, UseIntervalAC))
TotalDmg = MaxDmg;
else
TotalDmg = zone->random.Int(MinDmg, MaxDmg);
if (!damage_mod)
damage_mod = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 3);//Damage modifier
TotalDmg += TotalDmg * damage_mod / 100;
other->AvoidDamage(this, TotalDmg, false);
other->MeleeMitigation(this, TotalDmg, MinDmg);
if (TotalDmg > 0)
CommonOutgoingHitSuccess(other, TotalDmg, skillInUse);
else
TotalDmg = -5;
if (TotalDmg > 0)
other->AddToHateList(this, TotalDmg, 0, false);
else
other->AddToHateList(this, 0, 0, false);
other->Damage(this, TotalDmg, SPELL_UNKNOWN, skillInUse);
if (TotalDmg > 0 && HasSkillProcSuccess() && !other->HasDied())
TrySkillProc(other, skillInUse, 0, true, MainRange);
}
//try proc on hits and misses
if(other && !other->HasDied())
TrySpellProc(nullptr, (const Item_Struct*)nullptr, other, MainRange);
if (HasSkillProcs() && other && !other->HasDied())
TrySkillProc(other, skillInUse, 0, false, MainRange);
}
uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) { uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) {
uint16 MaxDmg = (((2 * wDmg) * GetDamageTable(SkillThrowing)) / 100); uint16 MaxDmg = (((2 * wDmg) * GetDamageTable(SkillThrowing)) / 100);