Merge from master, probably wont compile but will fix that soon

This commit is contained in:
KimLS 2015-06-21 01:38:19 -07:00
commit 5995afa1b8
125 changed files with 7658 additions and 8436 deletions

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@ EQEmuLogSys Log;
void ExportSpells(SharedDatabase *db); void ExportSpells(SharedDatabase *db);
void ExportSkillCaps(SharedDatabase *db); void ExportSkillCaps(SharedDatabase *db);
void ExportBaseData(SharedDatabase *db); void ExportBaseData(SharedDatabase *db);
void ExportDBStrings(SharedDatabase *db);
int main(int argc, char **argv) { int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformClientExport); RegisterExecutablePlatform(ExePlatformClientExport);
@ -62,6 +63,7 @@ int main(int argc, char **argv) {
ExportSpells(&database); ExportSpells(&database);
ExportSkillCaps(&database); ExportSkillCaps(&database);
ExportBaseData(&database); ExportBaseData(&database);
ExportDBStrings(&database);
Log.CloseFileLogs(); Log.CloseFileLogs();
@ -194,7 +196,38 @@ void ExportBaseData(SharedDatabase *db) {
fprintf(f, "%s\n", line.c_str()); fprintf(f, "%s\n", line.c_str());
} }
} else { }
fclose(f);
}
void ExportDBStrings(SharedDatabase *db) {
Log.Out(Logs::General, Logs::Status, "Exporting DB Strings...");
FILE *f = fopen("export/dbstr_us.txt", "w");
if(!f) {
Log.Out(Logs::General, Logs::Error, "Unable to open export/dbstr_us.txt to write, skipping.");
return;
}
fprintf(f, "Major^Minor^String(New)\n");
const std::string query = "SELECT * FROM db_str ORDER BY id, type";
auto results = db->QueryDatabase(query);
if(results.Success()) {
for(auto row = results.begin(); row != results.end(); ++row) {
std::string line;
unsigned int fields = results.ColumnCount();
for(unsigned int rowIndex = 0; rowIndex < fields; ++rowIndex) {
if(rowIndex != 0)
line.push_back('^');
if(row[rowIndex] != nullptr) {
line += row[rowIndex];
}
}
fprintf(f, "%s\n", line.c_str());
}
} }
fclose(f); fclose(f);

View File

@ -30,6 +30,7 @@ EQEmuLogSys Log;
void ImportSpells(SharedDatabase *db); void ImportSpells(SharedDatabase *db);
void ImportSkillCaps(SharedDatabase *db); void ImportSkillCaps(SharedDatabase *db);
void ImportBaseData(SharedDatabase *db); void ImportBaseData(SharedDatabase *db);
void ImportDBStrings(SharedDatabase *db);
int main(int argc, char **argv) { int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformClientImport); RegisterExecutablePlatform(ExePlatformClientImport);
@ -59,6 +60,7 @@ int main(int argc, char **argv) {
ImportSpells(&database); ImportSpells(&database);
ImportSkillCaps(&database); ImportSkillCaps(&database);
ImportBaseData(&database); ImportBaseData(&database);
ImportDBStrings(&database);
Log.CloseFileLogs(); Log.CloseFileLogs();
@ -202,7 +204,6 @@ void ImportSkillCaps(SharedDatabase *db) {
continue; continue;
} }
int class_id, skill_id, level, cap; int class_id, skill_id, level, cap;
class_id = atoi(split[0].c_str()); class_id = atoi(split[0].c_str());
skill_id = atoi(split[1].c_str()); skill_id = atoi(split[1].c_str());
@ -262,3 +263,56 @@ void ImportBaseData(SharedDatabase *db) {
fclose(f); fclose(f);
} }
void ImportDBStrings(SharedDatabase *db) {
Log.Out(Logs::General, Logs::Status, "Importing DB Strings...");
FILE *f = fopen("import/dbstr_us.txt", "r");
if(!f) {
Log.Out(Logs::General, Logs::Error, "Unable to open import/dbstr_us.txt to read, skipping.");
return;
}
std::string delete_sql = "DELETE FROM db_str";
db->QueryDatabase(delete_sql);
char buffer[2048];
bool first = true;
while(fgets(buffer, 2048, f)) {
if(first) {
first = false;
continue;
}
for(int i = 0; i < 2048; ++i) {
if(buffer[i] == '\n') {
buffer[i] = 0;
break;
}
}
auto split = SplitString(buffer, '^');
if(split.size() < 2) {
continue;
}
std::string sql;
int id, type;
std::string value;
id = atoi(split[0].c_str());
type = atoi(split[1].c_str());
if(split.size() >= 3) {
value = ::EscapeString(split[2]);
}
sql = StringFormat("INSERT INTO db_str(id, type, value) VALUES(%u, %u, '%s')",
id, type, value.c_str());
db->QueryDatabase(sql);
}
fclose(f);
}

View File

@ -348,6 +348,7 @@ N(OP_OpenTributeMaster),
N(OP_PDeletePetition), N(OP_PDeletePetition),
N(OP_PetBuffWindow), N(OP_PetBuffWindow),
N(OP_PetCommands), N(OP_PetCommands),
N(OP_PetHoTT),
N(OP_Petition), N(OP_Petition),
N(OP_PetitionBug), N(OP_PetitionBug),
N(OP_PetitionCheckIn), N(OP_PetitionCheckIn),
@ -364,6 +365,8 @@ N(OP_PetitionUnCheckout),
N(OP_PetitionUpdate), N(OP_PetitionUpdate),
N(OP_PickPocket), N(OP_PickPocket),
N(OP_PlayerProfile), N(OP_PlayerProfile),
N(OP_PlayerStateAdd),
N(OP_PlayerStateRemove),
N(OP_PlayEverquestRequest), N(OP_PlayEverquestRequest),
N(OP_PlayEverquestResponse), N(OP_PlayEverquestResponse),
N(OP_PlayMP3), N(OP_PlayMP3),
@ -519,8 +522,6 @@ N(OP_VetRewardsAvaliable),
N(OP_VoiceMacroIn), N(OP_VoiceMacroIn),
N(OP_VoiceMacroOut), N(OP_VoiceMacroOut),
N(OP_WeaponEquip1), N(OP_WeaponEquip1),
N(OP_WeaponEquip2),
N(OP_WeaponUnequip2),
N(OP_WearChange), N(OP_WearChange),
N(OP_Weather), N(OP_Weather),
N(OP_Weblink), N(OP_Weblink),

View File

@ -281,7 +281,8 @@ struct Spawn_Struct {
/*0146*/ uint8 beard; // Beard style (not totally, sure but maybe!) /*0146*/ uint8 beard; // Beard style (not totally, sure but maybe!)
/*0147*/ uint8 unknown0147[4]; /*0147*/ uint8 unknown0147[4];
/*0151*/ uint8 level; // Spawn Level /*0151*/ uint8 level; // Spawn Level
/*0152*/ uint8 unknown0259[4]; // ***Placeholder // None = 0, Open = 1, WeaponSheathed = 2, Aggressive = 4, ForcedAggressive = 8, InstrumentEquipped = 16, Stunned = 32, PrimaryWeaponEquipped = 64, SecondaryWeaponEquipped = 128
/*0152*/ uint32 PlayerState; // Controls animation stuff
/*0156*/ uint8 beardcolor; // Beard color /*0156*/ uint8 beardcolor; // Beard color
/*0157*/ char suffix[32]; // Player's suffix (of Veeshan, etc.) /*0157*/ char suffix[32]; // Player's suffix (of Veeshan, etc.)
/*0189*/ uint32 petOwnerId; // If this is a pet, the spawn id of owner /*0189*/ uint32 petOwnerId; // If this is a pet, the spawn id of owner
@ -374,6 +375,11 @@ union
}; };
struct PlayerState_Struct {
/*00*/ uint32 spawn_id;
/*04*/ uint32 state;
};
/* /*
** New Spawn ** New Spawn
** Length: 176 Bytes ** Length: 176 Bytes
@ -555,7 +561,7 @@ struct SpellBuff_Struct
/*002*/ uint8 bard_modifier; /*002*/ uint8 bard_modifier;
/*003*/ uint8 effect; //not real /*003*/ uint8 effect; //not real
/*004*/ uint32 spellid; /*004*/ uint32 spellid;
/*008*/ uint32 duration; /*008*/ int32 duration;
/*012*/ uint32 counters; /*012*/ uint32 counters;
/*016*/ uint32 player_id; //'global' ID of the caster, for wearoff messages /*016*/ uint32 player_id; //'global' ID of the caster, for wearoff messages
/*020*/ /*020*/
@ -568,7 +574,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect; /*006*/ uint8 effect;
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 num_hits; /*016*/ uint32 num_hits;
/*020*/ uint32 unknown020; //prolly global player ID /*020*/ uint32 unknown020; //prolly global player ID
/*024*/ uint32 slotid; /*024*/ uint32 slotid;
@ -586,14 +592,8 @@ struct BuffRemoveRequest_Struct
struct PetBuff_Struct { struct PetBuff_Struct {
/*000*/ uint32 petid; /*000*/ uint32 petid;
/*004*/ uint32 spellid[BUFF_COUNT]; /*004*/ uint32 spellid[BUFF_COUNT+5];
/*104*/ uint32 unknown700; /*124*/ int32 ticsremaining[BUFF_COUNT+5];
/*108*/ uint32 unknown701;
/*112*/ uint32 unknown702;
/*116*/ uint32 unknown703;
/*120*/ uint32 unknown704;
/*124*/ uint32 ticsremaining[BUFF_COUNT];
/*224*/ uchar unknown705[20];
/*244*/ uint32 buffcount; /*244*/ uint32 buffcount;
}; };
@ -734,6 +734,7 @@ struct AA_Array
{ {
uint32 AA; uint32 AA;
uint32 value; uint32 value;
uint32 charges;
}; };
@ -1168,7 +1169,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct { struct PetCommand_Struct {
/*000*/ uint32 command; /*000*/ uint32 command;
/*004*/ uint32 unknown; /*004*/ uint32 target;
}; };
/* /*
@ -1326,9 +1327,9 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ uint32 damage; /* 07 */ uint32 damage;
/* 11 */ uint32 unknown11; /* 11 */ float force;
/* 15 */ uint32 sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint32 unknown19; /* 19 */ float meleepush_z;
/* 23 */ /* 23 */
}; };
@ -2167,24 +2168,24 @@ struct Illusion_Struct_Old {
// OP_Sound - Size: 68 // OP_Sound - Size: 68
struct QuestReward_Struct struct QuestReward_Struct
{ {
/*000*/ uint32 from_mob; // ID of mob awarding the client /*000*/ uint32 mob_id; // ID of mob awarding the client
/*004*/ uint32 unknown004; /*004*/ uint32 target_id;
/*008*/ uint32 unknown008; /*008*/ uint32 exp_reward;
/*012*/ uint32 unknown012; /*012*/ uint32 faction;
/*016*/ uint32 unknown016; /*016*/ int32 faction_mod;
/*020*/ uint32 unknown020; /*020*/ uint32 copper; // Gives copper to the client
/*024*/ uint32 silver; // Gives silver to the client /*024*/ uint32 silver; // Gives silver to the client
/*028*/ uint32 gold; // Gives gold to the client /*028*/ uint32 gold; // Gives gold to the client
/*032*/ uint32 platinum; // Gives platinum to the client /*032*/ uint32 platinum; // Gives platinum to the client
/*036*/ uint32 unknown036; /*036*/ uint32 item_id;
/*040*/ uint32 unknown040; /*040*/ uint32 unknown040;
/*044*/ uint32 unknown044; /*044*/ uint32 unknown044;
/*048*/ uint32 unknown048; /*048*/ uint32 unknown048;
/*052*/ uint32 unknown052; /*052*/ uint32 unknown052;
/*056*/ uint32 unknown056; /*056*/ uint32 unknown056;
/*060*/ uint32 unknown060; /*060*/ uint32 unknown060;
/*064*/ uint32 unknown064; /*064*/ uint32 unknown064;
/*068*/ /*068*/
}; };
// Size: 8 // Size: 8
@ -2554,8 +2555,8 @@ struct BookRequest_Struct {
*/ */
struct Object_Struct { struct Object_Struct {
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list /*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
/*08*/ uint16 unknown008; // /*08*/ uint16 size; //
/*10*/ uint16 unknown010; // /*10*/ uint16 solidtype; //
/*12*/ uint32 drop_id; // Unique object id for zone /*12*/ uint32 drop_id; // Unique object id for zone
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in /*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
/*18*/ uint16 zone_instance; // /*18*/ uint16 zone_instance; //
@ -4049,7 +4050,7 @@ struct MarkNPC_Struct
struct InspectBuffs_Struct { struct InspectBuffs_Struct {
/*000*/ uint32 spell_id[BUFF_COUNT]; /*000*/ uint32 spell_id[BUFF_COUNT];
/*100*/ uint32 tics_remaining[BUFF_COUNT]; /*100*/ int32 tics_remaining[BUFF_COUNT];
}; };
struct RaidGeneral_Struct { struct RaidGeneral_Struct {
@ -4295,14 +4296,6 @@ struct AA_Action {
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };
struct AA_Skills { //this should be removed and changed to AA_Array
/*00*/ uint32 aa_skill; // Total AAs Spent
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
/*12*/
};
struct AAExpUpdate_Struct { struct AAExpUpdate_Struct {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
/*04*/ uint32 aapoints_unspent; /*04*/ uint32 aapoints_unspent;
@ -4320,12 +4313,12 @@ struct AltAdvStats_Struct {
}; };
struct PlayerAA_Struct { // Is this still used? struct PlayerAA_Struct { // Is this still used?
AA_Skills aa_list[MAX_PP_AA_ARRAY]; AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct AATable_Struct { struct AATable_Struct {
/*00*/ int32 aa_spent; // Total AAs Spent /*00*/ int32 aa_spent; // Total AAs Spent
/*04*/ AA_Skills aa_list[MAX_PP_AA_ARRAY]; /*04*/ AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct Weather_Struct { struct Weather_Struct {
@ -4750,7 +4743,7 @@ struct BuffIconEntry_Struct
{ {
uint32 buff_slot; uint32 buff_slot;
uint32 spell_id; uint32 spell_id;
uint32 tics_remaining; int32 tics_remaining;
uint32 num_hits; uint32 num_hits;
}; };
@ -4759,6 +4752,7 @@ struct BuffIcon_Struct
uint32 entity_id; uint32 entity_id;
uint8 all_buffs; uint8 all_buffs;
uint16 count; uint16 count;
uint8 type; // 0 = self buff window, 1 = self target window, 4 = group, 5 = PC, 7 = NPC
BuffIconEntry_Struct entries[0]; BuffIconEntry_Struct entries[0];
}; };

View File

@ -72,6 +72,8 @@ void EQStream::init(bool resetSession) {
RateThreshold=RATEBASE/250; RateThreshold=RATEBASE/250;
DecayRate=DECAYBASE/250; DecayRate=DECAYBASE/250;
BytesWritten=0; BytesWritten=0;
sent_packet_count = 0;
received_packet_count = 0;
SequencedBase = 0; SequencedBase = 0;
NextSequencedSend = 0; NextSequencedSend = 0;
@ -464,37 +466,45 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
} }
break; break;
case OP_SessionStatRequest: { case OP_SessionStatRequest: {
if(p->Size() < sizeof(SessionStats)) if(p->Size() < sizeof(ClientSessionStats))
{ {
Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_SessionStatRequest that was of malformed size" __L); Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_SessionStatRequest that was of malformed size" __L);
break; break;
} }
#ifndef COLLECTOR #ifndef COLLECTOR
SessionStats *Stats=(SessionStats *)p->pBuffer; ClientSessionStats *ClientStats=(ClientSessionStats *)p->pBuffer;
Log.Out(Logs::Detail, Logs::Netcode, _L "Received Stats: %lu packets received, %lu packets sent, Deltas: local %lu, (%lu <- %lu -> %lu) remote %lu" __L, Log.Out(Logs::Detail, Logs::Netcode, _L "Received Stats: %lu packets received, %lu packets sent, Deltas: local %lu, (%lu <- %lu -> %lu) remote %lu" __L,
(unsigned long)ntohl(Stats->packets_received), (unsigned long)ntohl(Stats->packets_sent), (unsigned long)ntohl(Stats->last_local_delta), (unsigned long)ntohl(ClientStats->packets_received), (unsigned long)ntohl(ClientStats->packets_sent), (unsigned long)ntohl(ClientStats->last_local_delta),
(unsigned long)ntohl(Stats->low_delta), (unsigned long)ntohl(Stats->average_delta), (unsigned long)ntohl(ClientStats->low_delta), (unsigned long)ntohl(ClientStats->average_delta),
(unsigned long)ntohl(Stats->high_delta), (unsigned long)ntohl(Stats->last_remote_delta)); (unsigned long)ntohl(ClientStats->high_delta), (unsigned long)ntohl(ClientStats->last_remote_delta));
uint64 x=Stats->packets_received;
Stats->packets_received=Stats->packets_sent; AdjustRates(ntohl(ClientStats->average_delta));
Stats->packets_sent=x;
NonSequencedPush(new EQProtocolPacket(OP_SessionStatResponse,p->pBuffer,p->size));
AdjustRates(ntohl(Stats->average_delta));
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) { if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
if(RETRANSMIT_TIMEOUT_MULT && ntohl(Stats->average_delta)) { if (RETRANSMIT_TIMEOUT_MULT && ntohl(ClientStats->average_delta)) {
//recalculate retransmittimeout using the larger of the last rtt or average rtt, which is multiplied by the rule value //recalculate retransmittimeout using the larger of the last rtt or average rtt, which is multiplied by the rule value
if((ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) > (ntohl(Stats->average_delta) * 2)) { if ((ntohl(ClientStats->last_local_delta) + ntohl(ClientStats->last_remote_delta)) > (ntohl(ClientStats->average_delta) * 2)) {
retransmittimeout = (ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) retransmittimeout = (ntohl(ClientStats->last_local_delta) + ntohl(ClientStats->last_remote_delta))
* RETRANSMIT_TIMEOUT_MULT; * RETRANSMIT_TIMEOUT_MULT;
} else { } else {
retransmittimeout = ntohl(Stats->average_delta) * 2 * RETRANSMIT_TIMEOUT_MULT; retransmittimeout = ntohl(ClientStats->average_delta) * 2 * RETRANSMIT_TIMEOUT_MULT;
} }
if(retransmittimeout > RETRANSMIT_TIMEOUT_MAX) if(retransmittimeout > RETRANSMIT_TIMEOUT_MAX)
retransmittimeout = RETRANSMIT_TIMEOUT_MAX; retransmittimeout = RETRANSMIT_TIMEOUT_MAX;
Log.Out(Logs::Detail, Logs::Netcode, _L "Retransmit timeout recalculated to %dms" __L, retransmittimeout); Log.Out(Logs::Detail, Logs::Netcode, _L "Retransmit timeout recalculated to %dms" __L, retransmittimeout);
} }
} }
ServerSessionStats *ServerStats = (ServerSessionStats *)p->pBuffer;
//ServerStats->RequestID = ClientStats->RequestID; // no change
ServerStats->ServerTime = htonl(Timer::GetCurrentTime());
ServerStats->packets_sent_echo = ClientStats->packets_sent; // still in htonll format
ServerStats->packets_received_echo = ClientStats->packets_received; // still in htonll format
ServerStats->packets_sent = htonll(GetPacketsSent());
ServerStats->packets_received = htonll(GetPacketsReceived());
NonSequencedPush(new EQProtocolPacket(OP_SessionStatResponse, p->pBuffer, p->size));
#endif #endif
} }
break; break;
@ -573,16 +583,18 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
// Convert the EQApplicationPacket to 1 or more EQProtocolPackets // Convert the EQApplicationPacket to 1 or more EQProtocolPackets
if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2) if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2)
Log.Out(Logs::Detail, Logs::Netcode, _L "Making oversized packet, len %d" __L, p->size); Log.Out(Logs::Detail, Logs::Netcode, _L "Making oversized packet, len %d" __L, p->Size());
unsigned char *tmpbuff=new unsigned char[p->size+3]; unsigned char *tmpbuff=new unsigned char[p->size+3];
length=p->serialize(opcode, tmpbuff); length=p->serialize(opcode, tmpbuff);
if (length != p->Size())
Log.Out(Logs::Detail, Logs::Netcode, _L "Packet adjustment, len %d to %d" __L, p->Size(), length);
EQProtocolPacket *out=new EQProtocolPacket(OP_Fragment,nullptr,MaxLen-4); EQProtocolPacket *out=new EQProtocolPacket(OP_Fragment,nullptr,MaxLen-4);
*(uint32 *)(out->pBuffer+2)=htonl(p->Size()); *(uint32 *)(out->pBuffer+2)=htonl(length);
used=MaxLen-10; used=MaxLen-10;
memcpy(out->pBuffer+6,tmpbuff,used); memcpy(out->pBuffer+6,tmpbuff,used);
Log.Out(Logs::Detail, Logs::Netcode, _L "First fragment: used %d/%d. Put size %d in the packet" __L, used, p->size, p->Size()); Log.Out(Logs::Detail, Logs::Netcode, _L "First fragment: used %d/%d. Payload size %d in the packet" __L, used, length, p->size);
SequencedPush(out); SequencedPush(out);
@ -593,7 +605,7 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
out->size=chunksize+2; out->size=chunksize+2;
SequencedPush(out); SequencedPush(out);
used+=chunksize; used+=chunksize;
Log.Out(Logs::Detail, Logs::Netcode, _L "Subsequent fragment: len %d, used %d/%d." __L, chunksize, used, p->size); Log.Out(Logs::Detail, Logs::Netcode, _L "Subsequent fragment: len %d, used %d/%d." __L, chunksize, used, length);
} }
delete p; delete p;
delete[] tmpbuff; delete[] tmpbuff;
@ -1101,8 +1113,8 @@ EQProtocolPacket *p=nullptr;
void EQStream::Process(const unsigned char *buffer, const uint32 length) void EQStream::Process(const unsigned char *buffer, const uint32 length)
{ {
static unsigned char newbuffer[2048]; static unsigned char newbuffer[2048];
uint32 newlength=0; uint32 newlength=0;
if (EQProtocolPacket::ValidateCRC(buffer,length,Key)) { if (EQProtocolPacket::ValidateCRC(buffer,length,Key)) {
if (compressed) { if (compressed) {
newlength=EQProtocolPacket::Decompress(buffer,length,newbuffer,2048); newlength=EQProtocolPacket::Decompress(buffer,length,newbuffer,2048);

View File

@ -71,7 +71,7 @@ struct SessionResponse {
}; };
//Deltas are in ms, representing round trip times //Deltas are in ms, representing round trip times
struct SessionStats { struct ClientSessionStats {
/*000*/ uint16 RequestID; /*000*/ uint16 RequestID;
/*002*/ uint32 last_local_delta; /*002*/ uint32 last_local_delta;
/*006*/ uint32 average_delta; /*006*/ uint32 average_delta;
@ -83,6 +83,16 @@ struct SessionStats {
/*038*/ /*038*/
}; };
struct ServerSessionStats {
/*000*/ uint16 RequestID;
/*002*/ uint32 ServerTime;
/*006*/ uint64 packets_sent_echo;
/*014*/ uint64 packets_received_echo;
/*022*/ uint64 packets_sent;
/*030*/ uint64 packets_received;
/*038*/
};
#pragma pack() #pragma pack()
class OpcodeManager; class OpcodeManager;
@ -158,6 +168,9 @@ class EQStream : public EQStreamInterface {
int32 BytesWritten; int32 BytesWritten;
uint64 sent_packet_count;
uint64 received_packet_count;
Mutex MRate; Mutex MRate;
int32 RateThreshold; int32 RateThreshold;
int32 DecayRate; int32 DecayRate;
@ -265,11 +278,13 @@ class EQStream : public EQStreamInterface {
void AddBytesSent(uint32 bytes) void AddBytesSent(uint32 bytes)
{ {
bytes_sent += bytes; bytes_sent += bytes;
++sent_packet_count;
} }
void AddBytesRecv(uint32 bytes) void AddBytesRecv(uint32 bytes)
{ {
bytes_recv += bytes; bytes_recv += bytes;
++received_packet_count;
} }
virtual const uint32 GetBytesSent() const { return bytes_sent; } virtual const uint32 GetBytesSent() const { return bytes_sent; }
@ -288,6 +303,9 @@ class EQStream : public EQStreamInterface {
return bytes_recv / (Timer::GetTimeSeconds() - create_time); return bytes_recv / (Timer::GetTimeSeconds() - create_time);
} }
const uint64 GetPacketsSent() { return sent_packet_count; }
const uint64 GetPacketsReceived() { return received_packet_count; }
//used for dynamic stream identification //used for dynamic stream identification
class Signature { class Signature {
public: public:

View File

@ -43,19 +43,19 @@ EQTime::EQTime(TimeOfDay_Struct start_eq, time_t start_real)
EQTime::EQTime() EQTime::EQTime()
{ {
timezone=0; timezone = 0;
memset(&eqTime, 0, sizeof(eqTime)); memset(&eqTime, 0, sizeof(eqTime));
//Defaults for time //Defaults for time
TimeOfDay_Struct start; TimeOfDay_Struct start;
start.day=1; start.day = 1;
start.hour=9; start.hour = 9;
start.minute=0; start.minute = 0;
start.month=1; start.month = 1;
start.year=3100; start.year = 3100;
//Set default time zone //Set default time zone
timezone=0; timezone = 0;
//Start EQTimer //Start EQTimer
setEQTimeOfDay(start, time(0)); SetCurrentEQTimeOfDay(start, time(0));
} }
EQTime::~EQTime() EQTime::~EQTime()
@ -67,10 +67,10 @@ EQTime::~EQTime()
//Input: Current Time (as a time_t), a pointer to the TimeOfDay_Struct that will be written to. //Input: Current Time (as a time_t), a pointer to the TimeOfDay_Struct that will be written to.
//Output: 0=Error, 1=Sucess //Output: 0=Error, 1=Sucess
int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeOfDay ) int EQTime::GetCurrentEQTimeOfDay(time_t timeConvert, struct TimeOfDay_Struct *eqTimeOfDay)
{ {
/* check to see if we have a reference time to go by. */ /* check to see if we have a reference time to go by. */
if( eqTime.start_realtime == 0 ) if (eqTime.start_realtime == 0)
return 0; return 0;
unsigned long diff = timeConvert - eqTime.start_realtime; unsigned long diff = timeConvert - eqTime.start_realtime;
@ -83,7 +83,7 @@ int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeO
int32 ntz = timezone; int32 ntz = timezone;
/* The minutes range from 0 - 59 */ /* The minutes range from 0 - 59 */
diff += eqTime.start_eqtime.minute + (ntz%60); diff += eqTime.start_eqtime.minute + (ntz % 60);
eqTimeOfDay->minute = diff % 60; eqTimeOfDay->minute = diff % 60;
diff /= 60; diff /= 60;
ntz /= 60; ntz /= 60;
@ -97,24 +97,24 @@ int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeO
// //
// Modify it so that it works from // Modify it so that it works from
// 0-23 for our calculations // 0-23 for our calculations
diff += ( eqTime.start_eqtime.hour - 1) + (ntz%24); diff += (eqTime.start_eqtime.hour - 1) + (ntz % 24);
eqTimeOfDay->hour = (diff%24) + 1; eqTimeOfDay->hour = (diff % 24) + 1;
diff /= 24; diff /= 24;
ntz /= 24; ntz /= 24;
// The days range from 1-28 // The days range from 1-28
// Modify it so that it works from // Modify it so that it works from
// 0-27 for our calculations // 0-27 for our calculations
diff += ( eqTime.start_eqtime.day - 1 ) + (ntz%28); diff += (eqTime.start_eqtime.day - 1) + (ntz % 28);
eqTimeOfDay->day = (diff%28) + 1; eqTimeOfDay->day = (diff % 28) + 1;
diff /= 28; diff /= 28;
ntz /= 28; ntz /= 28;
// The months range from 1-12 // The months range from 1-12
// Modify it so that it works from // Modify it so that it works from
// 0-11 for our calculations // 0-11 for our calculations
diff += ( eqTime.start_eqtime.month - 1 ) + (ntz%12); diff += (eqTime.start_eqtime.month - 1) + (ntz % 12);
eqTimeOfDay->month = (diff%12) + 1; eqTimeOfDay->month = (diff % 12) + 1;
diff /= 12; diff /= 12;
ntz /= 12; ntz /= 12;
@ -124,12 +124,12 @@ int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeO
} }
//setEQTimeOfDay //setEQTimeOfDay
int EQTime::setEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real) int EQTime::SetCurrentEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real)
{ {
if(start_real==0) if (start_real == 0)
return 0; return 0;
eqTime.start_eqtime=start_eq; eqTime.start_eqtime = start_eq;
eqTime.start_realtime=start_real; eqTime.start_realtime = start_real;
return 1; return 1;
} }
@ -139,7 +139,7 @@ bool EQTime::saveFile(const char *filename)
{ {
std::ofstream of; std::ofstream of;
of.open(filename); of.open(filename);
if(!of) if (!of)
{ {
Log.Out(Logs::General, Logs::Error, "EQTime::saveFile failed: Unable to open file '%s'", filename); Log.Out(Logs::General, Logs::Error, "EQTime::saveFile failed: Unable to open file '%s'", filename);
return false; return false;
@ -200,24 +200,24 @@ bool EQTime::loadFile(const char *filename)
bool EQTime::IsTimeBefore(TimeOfDay_Struct *base, TimeOfDay_Struct *test) { bool EQTime::IsTimeBefore(TimeOfDay_Struct *base, TimeOfDay_Struct *test) {
if(base->year > test->year) if (base->year > test->year)
return(true); return(true);
if(base->year < test->year) if (base->year < test->year)
return(false); return(false);
//same years //same years
if(base->month > test->month) if (base->month > test->month)
return(true); return(true);
if(base->month < test->month) if (base->month < test->month)
return(false); return(false);
//same month //same month
if(base->day > test->day) if (base->day > test->day)
return(true); return(true);
if(base->day < test->day) if (base->day < test->day)
return(false); return(false);
//same day //same day
if(base->hour > test->hour) if (base->hour > test->hour)
return(true); return(true);
if(base->hour < test->hour) if (base->hour < test->hour)
return(false); return(false);
//same hour... //same hour...
return(base->minute > test->minute); return(base->minute > test->minute);
@ -230,7 +230,7 @@ void EQTime::AddMinutes(uint32 minutes, TimeOfDay_Struct *to) {
//minutes start at 0, everything else starts at 1 //minutes start at 0, everything else starts at 1
cur = to->minute; cur = to->minute;
cur += minutes; cur += minutes;
if(cur < 60) { if (cur < 60) {
to->minute = cur; to->minute = cur;
return; return;
} }
@ -238,29 +238,29 @@ void EQTime::AddMinutes(uint32 minutes, TimeOfDay_Struct *to) {
//carry hours //carry hours
cur /= 60; cur /= 60;
cur += to->hour; cur += to->hour;
if(cur <= 24) { if (cur <= 24) {
to->hour = cur; to->hour = cur;
return; return;
} }
to->hour = ((cur-1) % 24) + 1; to->hour = ((cur - 1) % 24) + 1;
//carry days //carry days
cur = (cur-1) / 24; cur = (cur - 1) / 24;
cur += to->day; cur += to->day;
if(cur <= 28) { if (cur <= 28) {
to->day = cur; to->day = cur;
return; return;
} }
to->day = ((cur-1) % 28) + 1; to->day = ((cur - 1) % 28) + 1;
//carry months //carry months
cur = (cur-1) / 28; cur = (cur - 1) / 28;
cur += to->month; cur += to->month;
if(cur <= 12) { if (cur <= 12) {
to->month = cur; to->month = cur;
return; return;
} }
to->month = ((cur-1) % 12) + 1; to->month = ((cur - 1) % 12) + 1;
//carry years //carry years
to->year += (cur-1) / 12; to->year += (cur - 1) / 12;
} }
void EQTime::ToString(TimeOfDay_Struct *t, std::string &str) { void EQTime::ToString(TimeOfDay_Struct *t, std::string &str) {
@ -269,5 +269,4 @@ void EQTime::ToString(TimeOfDay_Struct *t, std::string &str) {
t->month, t->day, t->year, t->hour, t->minute); t->month, t->day, t->year, t->hour, t->minute);
buf[127] = '\0'; buf[127] = '\0';
str = buf; str = buf;
} }

View File

@ -21,8 +21,8 @@ public:
~EQTime(); ~EQTime();
//Get functions //Get functions
int getEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(getEQTimeOfDay(time(nullptr), eqTimeOfDay)); } int GetCurrentEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(GetCurrentEQTimeOfDay(time(nullptr), eqTimeOfDay)); }
int getEQTimeOfDay( time_t timeConvert, TimeOfDay_Struct *eqTimeOfDay ); int GetCurrentEQTimeOfDay( time_t timeConvert, TimeOfDay_Struct *eqTimeOfDay );
TimeOfDay_Struct getStartEQTime() { return eqTime.start_eqtime; } TimeOfDay_Struct getStartEQTime() { return eqTime.start_eqtime; }
time_t getStartRealTime() { return eqTime.start_realtime; } time_t getStartRealTime() { return eqTime.start_realtime; }
uint32 getEQTimeZone() { return timezone; } uint32 getEQTimeZone() { return timezone; }
@ -30,7 +30,7 @@ public:
uint32 getEQTimeZoneMin() { return timezone%60; } uint32 getEQTimeZoneMin() { return timezone%60; }
//Set functions //Set functions
int setEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real); int SetCurrentEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real);
void setEQTimeZone(int32 in_timezone) { timezone=in_timezone; } void setEQTimeZone(int32 in_timezone) { timezone=in_timezone; }
//Time math/logic functions //Time math/logic functions

View File

@ -183,7 +183,7 @@ struct ItemData {
uint32 AugType; uint32 AugType;
uint8 AugSlotType[EmuConstants::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Type uint8 AugSlotType[EmuConstants::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Type
uint8 AugSlotVisible[EmuConstants::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Visible uint8 AugSlotVisible[EmuConstants::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Visible
uint8 AugSlotUnk2[EmuConstants::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Unknown uint8 AugSlotUnk2[EmuConstants::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Unknown Most likely Powersource related
uint32 LDoNTheme; uint32 LDoNTheme;
uint32 LDoNPrice; uint32 LDoNPrice;
uint32 LDoNSold; uint32 LDoNSold;

View File

@ -417,7 +417,7 @@ namespace RoF
outapp->WriteUInt32(0); // Duration outapp->WriteUInt32(0); // Duration
outapp->WriteUInt32(0); // ? outapp->WriteUInt32(0); // ?
outapp->WriteUInt8(0); // Caster name outapp->WriteUInt8(0); // Caster name
outapp->WriteUInt8(0); // Terminating byte outapp->WriteUInt8(0); // Type
} }
FINISH_ENCODE(); FINISH_ENCODE();
@ -454,7 +454,7 @@ namespace RoF
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown __packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
__packet->WriteString(""); __packet->WriteString("");
} }
__packet->WriteUInt8(!emu->all_buffs); // Unknown __packet->WriteUInt8(emu->type); // Unknown
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -659,7 +659,9 @@ namespace RoF
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -974,8 +976,8 @@ namespace RoF
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Normally 0, but seen (float)255.0 as well VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Normally 0, but seen (float)255.0 as well
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Unknown VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->solidtype); // Unknown
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 1); // Need to add emu->size to struct VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt.
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z);
@ -2119,7 +2121,7 @@ namespace RoF
{ {
outapp->WriteUInt32(emu->aa_array[r].AA); outapp->WriteUInt32(emu->aa_array[r].AA);
outapp->WriteUInt32(emu->aa_array[r].value); outapp->WriteUInt32(emu->aa_array[r].value);
outapp->WriteUInt32(0); outapp->WriteUInt32(emu->aa_array[r].charges);
} }
// Fill the other 60 AAs with zeroes // Fill the other 60 AAs with zeroes
@ -2817,9 +2819,9 @@ namespace RoF
for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i) for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i)
{ {
eq->aa_list[i].aa_skill = emu->aa_list[i].aa_skill; eq->aa_list[i].AA = emu->aa_list[i].AA;
eq->aa_list[i].aa_value = emu->aa_list[i].aa_value; eq->aa_list[i].value = emu->aa_list[i].value;
eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08; eq->aa_list[i].charges = emu->aa_list[i].charges;
} }
FINISH_ENCODE(); FINISH_ENCODE();
@ -2851,7 +2853,7 @@ namespace RoF
// Check clientver field to verify this AA should be sent for SoF // Check clientver field to verify this AA should be sent for SoF
// clientver 1 is for all clients and 5 is for Live // clientver 1 is for all clients and 5 is for Live
if (emu->clientver <= 5) if (emu->clientver <= 7)
{ {
OUT(id); OUT(id);
eq->unknown004 = 1; eq->unknown004 = 1;
@ -2867,9 +2869,9 @@ namespace RoF
OUT(cost); OUT(cost);
OUT(seq); OUT(seq);
OUT(current_level); OUT(current_level);
eq->unknown037 = 1; // Introduced during HoT eq->prereq_skill_count = 1; // min 1
OUT(prereq_skill); OUT(prereq_skill);
eq->unknown045 = 1; // New Mar 21 2012 - Seen 1 eq->prereq_minpoints_count = 1; // min 1
OUT(prereq_minpoints); OUT(prereq_minpoints);
eq->type = emu->sof_type; eq->type = emu->sof_type;
OUT(spellid); OUT(spellid);
@ -2885,6 +2887,7 @@ namespace RoF
OUT(cost2); OUT(cost2);
eq->aa_expansion = emu->aa_expansion; eq->aa_expansion = emu->aa_expansion;
eq->special_category = emu->special_category; eq->special_category = emu->special_category;
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number
OUT(total_abilities); OUT(total_abilities);
unsigned int r; unsigned int r;
for (r = 0; r < emu->total_abilities; r++) { for (r = 0; r < emu->total_abilities; r++) {
@ -2945,11 +2948,12 @@ namespace RoF
for (int counter = 0; counter < character_count; ++counter) { for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address
strcpy(eq_cse->Name, emu_cse->Name); strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name); eq_ptr += strlen(emu_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset)
eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)]
eq_cse->Class = emu_cse->Class; eq_cse->Class = emu_cse->Class;
eq_cse->Race = emu_cse->Race; eq_cse->Race = emu_cse->Race;
@ -3989,7 +3993,7 @@ namespace RoF
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13 VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown14 - Stance 64 = normal 4 = aggressive 40 = stun/mezzed VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
@ -4390,7 +4394,7 @@ namespace RoF
IN(type); IN(type);
IN(spellid); IN(spellid);
IN(damage); IN(damage);
emu->sequence = eq->sequence; IN(meleepush_xy);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
@ -4718,7 +4722,7 @@ namespace RoF
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct); SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
IN(command); IN(command);
emu->unknown = eq->unknown04; IN(target);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }

View File

@ -485,7 +485,7 @@ namespace RoF2
outapp->WriteUInt32(0); // Duration outapp->WriteUInt32(0); // Duration
outapp->WriteUInt32(0); // ? outapp->WriteUInt32(0); // ?
outapp->WriteUInt8(0); // Caster name outapp->WriteUInt8(0); // Caster name
outapp->WriteUInt8(0); // Terminating byte outapp->WriteUInt8(0); // Type
} }
FINISH_ENCODE(); FINISH_ENCODE();
@ -527,7 +527,7 @@ namespace RoF2
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown __packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
__packet->WriteString(""); __packet->WriteString("");
} }
__packet->WriteUInt8(!emu->all_buffs); // Unknown __packet->WriteUInt8(emu->type); // Unknown
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -700,7 +700,9 @@ namespace RoF2
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -1015,8 +1017,8 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Normally 0, but seen (float)255.0 as well VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Normally 0, but seen (float)255.0 as well
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Unknown VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->solidtype); // Unknown
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 1); // Need to add emu->size to struct VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt.
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z);
@ -2185,7 +2187,7 @@ namespace RoF2
{ {
outapp->WriteUInt32(emu->aa_array[r].AA); outapp->WriteUInt32(emu->aa_array[r].AA);
outapp->WriteUInt32(emu->aa_array[r].value); outapp->WriteUInt32(emu->aa_array[r].value);
outapp->WriteUInt32(0); outapp->WriteUInt32(emu->aa_array[r].charges);
} }
// Fill the other 60 AAs with zeroes // Fill the other 60 AAs with zeroes
@ -2892,9 +2894,9 @@ namespace RoF2
for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i) for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i)
{ {
eq->aa_list[i].aa_skill = emu->aa_list[i].aa_skill; eq->aa_list[i].AA = emu->aa_list[i].AA;
eq->aa_list[i].aa_value = emu->aa_list[i].aa_value; eq->aa_list[i].value = emu->aa_list[i].value;
eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08; eq->aa_list[i].charges = emu->aa_list[i].charges;
} }
FINISH_ENCODE(); FINISH_ENCODE();
@ -2926,7 +2928,7 @@ namespace RoF2
// Check clientver field to verify this AA should be sent for SoF // Check clientver field to verify this AA should be sent for SoF
// clientver 1 is for all clients and 5 is for Live // clientver 1 is for all clients and 5 is for Live
if (emu->clientver <= 5) if (emu->clientver <= 8)
{ {
OUT(id); OUT(id);
eq->unknown004 = 1; eq->unknown004 = 1;
@ -2942,9 +2944,9 @@ namespace RoF2
OUT(cost); OUT(cost);
OUT(seq); OUT(seq);
OUT(current_level); OUT(current_level);
eq->unknown037 = 1; // Introduced during HoT eq->prereq_skill_count = 1; // min 1
OUT(prereq_skill); OUT(prereq_skill);
eq->unknown045 = 1; // New Mar 21 2012 - Seen 1 eq->prereq_minpoints_count = 1; // min 1
OUT(prereq_minpoints); OUT(prereq_minpoints);
eq->type = emu->sof_type; eq->type = emu->sof_type;
OUT(spellid); OUT(spellid);
@ -2961,6 +2963,7 @@ namespace RoF2
eq->aa_expansion = emu->aa_expansion; eq->aa_expansion = emu->aa_expansion;
eq->special_category = emu->special_category; eq->special_category = emu->special_category;
OUT(total_abilities); OUT(total_abilities);
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number
unsigned int r; unsigned int r;
for (r = 0; r < emu->total_abilities; r++) { for (r = 0; r < emu->total_abilities; r++) {
OUT(abilities[r].skill_id); OUT(abilities[r].skill_id);
@ -3020,11 +3023,12 @@ namespace RoF2
for (int counter = 0; counter < character_count; ++counter) { for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address
strcpy(eq_cse->Name, emu_cse->Name); strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name); eq_ptr += strlen(emu_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset)
eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)]
eq_cse->Class = emu_cse->Class; eq_cse->Class = emu_cse->Class;
eq_cse->Race = emu_cse->Race; eq_cse->Race = emu_cse->Race;
@ -4125,7 +4129,7 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13 VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown14 - Stance 64 = normal 4 = aggressive 40 = stun/mezzed VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
@ -4525,7 +4529,7 @@ namespace RoF2
IN(type); IN(type);
IN(spellid); IN(spellid);
IN(damage); IN(damage);
emu->sequence = eq->sequence; IN(meleepush_xy);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
@ -4856,7 +4860,7 @@ namespace RoF2
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct); SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
IN(command); IN(command);
emu->unknown = eq->unknown04; IN(target);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }

View File

@ -416,7 +416,7 @@ struct Spawn_Struct
/*0000*/ uint8 unknown12; /*0000*/ uint8 unknown12;
/*0000*/ uint32 petOwnerId; /*0000*/ uint32 petOwnerId;
/*0000*/ uint8 unknown13; /*0000*/ uint8 unknown13;
/*0000*/ uint32 unknown14; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed /*0000*/ uint32 PlayerState; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed
/*0000*/ uint32 unknown15; /*0000*/ uint32 unknown15;
/*0000*/ uint32 unknown16; /*0000*/ uint32 unknown16;
/*0000*/ uint32 unknown17; /*0000*/ uint32 unknown17;
@ -687,7 +687,7 @@ struct SpellBuff_Struct
/*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages /*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*009*/ uint32 unknown016; /*009*/ uint32 unknown016;
/*013*/ uint8 bard_modifier; /*013*/ uint8 bard_modifier;
/*014*/ uint32 duration; /*014*/ int32 duration;
/*018*/ uint8 level; /*018*/ uint8 level;
/*019*/ uint32 spellid; /*019*/ uint32 spellid;
/*023*/ uint32 counters; /*023*/ uint32 counters;
@ -703,7 +703,7 @@ struct SpellBuff_Struct_Old
/*003*/ uint8 effect; // not real /*003*/ uint8 effect; // not real
/*004*/ float unknown004; // Seen 1 for no buff /*004*/ float unknown004; // Seen 1 for no buff
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 unknown016; /*016*/ uint32 unknown016;
/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages /*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*024*/ uint32 counters; /*024*/ uint32 counters;
@ -720,7 +720,7 @@ struct SpellBuffFade_Struct_Live {
/*007*/ uint8 unknown007; /*007*/ uint8 unknown007;
/*008*/ float unknown008; /*008*/ float unknown008;
/*012*/ uint32 spellid; /*012*/ uint32 spellid;
/*016*/ uint32 duration; /*016*/ int32 duration;
/*020*/ uint32 playerId; // Global player ID? /*020*/ uint32 playerId; // Global player ID?
/*024*/ uint32 num_hits; /*024*/ uint32 num_hits;
/*028*/ uint8 unknown0028[64]; /*028*/ uint8 unknown0028[64];
@ -736,7 +736,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect; /*006*/ uint8 effect;
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 num_hits; /*016*/ uint32 num_hits;
/*020*/ uint32 unknown020; // Global player ID? /*020*/ uint32 unknown020; // Global player ID?
/*024*/ uint32 playerId; // Player id who cast the buff /*024*/ uint32 playerId; // Player id who cast the buff
@ -877,7 +877,7 @@ struct AA_Array
{ {
uint32 AA; uint32 AA;
uint32 value; uint32 value;
uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live uint32 charges; // expendable charges
}; };
struct Disciplines_Struct { struct Disciplines_Struct {
@ -1293,7 +1293,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct { struct PetCommand_Struct {
/*00*/ uint32 command; /*00*/ uint32 command;
/*04*/ uint32 unknown04; /*04*/ uint32 target;
/*08*/ uint32 unknown08; /*08*/ uint32 unknown08;
}; };
@ -1484,9 +1484,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint32 spellid; /* 05 */ uint32 spellid;
/* 09 */ int32 damage; /* 09 */ int32 damage;
/* 13 */ float unknown11; // cd cc cc 3d /* 13 */ float force; // cd cc cc 3d
/* 17 */ float sequence; // see above notes in Action_Struct /* 17 */ float meleepush_xy; // see above notes in Action_Struct
/* 21 */ uint8 unknown19[9]; // was [9] /* 21 */ float meleepush_z;
/* 25 */ uint8 unknown25[5]; // was [9]
/* 30 */ /* 30 */
}; };
@ -2472,7 +2473,7 @@ struct GroupFollow_Struct { // Live Follow Struct
struct InspectBuffs_Struct { struct InspectBuffs_Struct {
/*000*/ uint32 spell_id[BUFF_COUNT]; /*000*/ uint32 spell_id[BUFF_COUNT];
/*168*/ uint32 tics_remaining[BUFF_COUNT]; /*168*/ int32 tics_remaining[BUFF_COUNT];
}; };
struct LFG_Struct { struct LFG_Struct {
@ -4252,9 +4253,9 @@ struct SendAA_Struct {
/*0025*/ uint32 cost; /*0025*/ uint32 cost;
/*0029*/ uint32 seq; /*0029*/ uint32 seq;
/*0033*/ uint32 current_level; //1s, MQ2 calls this AARankRequired /*0033*/ uint32 current_level; //1s, MQ2 calls this AARankRequired
/*0037*/ uint32 unknown037; // Introduced during HoT /*0037*/ uint32 prereq_skill_count; // mutliple prereqs at least 1, even no prereqs
/*0041*/ uint32 prereq_skill; //is < 0, abs() is category # /*0041*/ uint32 prereq_skill; //is < 0, abs() is category #
/*0045*/ uint32 unknown045; // New Mar 21 2012 - Seen 1 /*0045*/ uint32 prereq_minpoints_count; // mutliple prereqs at least 1, even no prereqs
/*0049*/ uint32 prereq_minpoints; //min points in the prereq /*0049*/ uint32 prereq_minpoints; //min points in the prereq
/*0053*/ uint32 type; /*0053*/ uint32 type;
/*0057*/ uint32 spellid; /*0057*/ uint32 spellid;
@ -4267,10 +4268,16 @@ struct SendAA_Struct {
/*0081*/ uint32 last_id; /*0081*/ uint32 last_id;
/*0085*/ uint32 next_id; /*0085*/ uint32 next_id;
/*0089*/ uint32 cost2; /*0089*/ uint32 cost2;
/*0093*/ uint8 unknown80[7]; /*0093*/ uint8 unknown93;
/*0094*/ uint8 grant_only; // VetAAs, progression, etc
/*0095*/ uint8 unknown95; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though
/*0096*/ uint32 expendable_charges; // max charges of the AA
/*0100*/ uint32 aa_expansion; /*0100*/ uint32 aa_expansion;
/*0104*/ uint32 special_category; /*0104*/ uint32 special_category;
/*0108*/ uint32 unknown0096; /*0108*/ uint8 shroud;
/*0109*/ uint8 unknown109;
/*0110*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter?
/*0111*/ uint8 unknown111;
/*0112*/ uint32 total_abilities; /*0112*/ uint32 total_abilities;
/*0116*/ AA_Ability abilities[0]; /*0116*/ AA_Ability abilities[0];
}; };
@ -4287,12 +4294,6 @@ struct AA_Action {
/*16*/ /*16*/
}; };
struct AA_Skills { //this should be removed and changed to AA_Array
/*00*/ uint32 aa_skill; // Total AAs Spent
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
/*12*/
};
struct AAExpUpdate_Struct { struct AAExpUpdate_Struct {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
@ -4312,14 +4313,7 @@ struct AltAdvStats_Struct {
}; };
struct PlayerAA_Struct { // Is this still used? struct PlayerAA_Struct { // Is this still used?
AA_Skills aa_list[MAX_PP_AA_ARRAY]; AA_Array aa_list[MAX_PP_AA_ARRAY];
};
struct AA_Values {
/*00*/ uint32 aa_skill;
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
/*12*/
}; };
struct AATable_Struct { struct AATable_Struct {
@ -4329,7 +4323,7 @@ struct AATable_Struct {
/*12*/ uint32 aa_spent_archetype; // Seen 40 /*12*/ uint32 aa_spent_archetype; // Seen 40
/*16*/ uint32 aa_spent_class; // Seen 103 /*16*/ uint32 aa_spent_class; // Seen 103
/*20*/ uint32 aa_spent_special; // Seen 0 /*20*/ uint32 aa_spent_special; // Seen 0
/*24*/ AA_Values aa_list[MAX_PP_AA_ARRAY]; /*24*/ AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct Weather_Struct { struct Weather_Struct {

View File

@ -410,7 +410,7 @@ struct Spawn_Struct
/*0000*/ uint8 unknown12; /*0000*/ uint8 unknown12;
/*0000*/ uint32 petOwnerId; /*0000*/ uint32 petOwnerId;
/*0000*/ uint8 unknown13; /*0000*/ uint8 unknown13;
/*0000*/ uint32 unknown14; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed /*0000*/ uint32 PlayerState; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed
/*0000*/ uint32 unknown15; /*0000*/ uint32 unknown15;
/*0000*/ uint32 unknown16; /*0000*/ uint32 unknown16;
/*0000*/ uint32 unknown17; /*0000*/ uint32 unknown17;
@ -676,7 +676,7 @@ struct SpellBuff_Struct
/*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages /*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*009*/ uint32 unknown016; /*009*/ uint32 unknown016;
/*013*/ uint8 bard_modifier; /*013*/ uint8 bard_modifier;
/*014*/ uint32 duration; /*014*/ int32 duration;
/*018*/ uint8 level; /*018*/ uint8 level;
/*019*/ uint32 spellid; /*019*/ uint32 spellid;
/*023*/ uint32 counters; /*023*/ uint32 counters;
@ -692,7 +692,7 @@ struct SpellBuff_Struct_Old
/*003*/ uint8 effect; // not real /*003*/ uint8 effect; // not real
/*004*/ float unknown004; // Seen 1 for no buff /*004*/ float unknown004; // Seen 1 for no buff
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 unknown016; /*016*/ uint32 unknown016;
/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages /*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*024*/ uint32 counters; /*024*/ uint32 counters;
@ -709,7 +709,7 @@ struct SpellBuffFade_Struct_Live {
/*007*/ uint8 unknown007; /*007*/ uint8 unknown007;
/*008*/ float unknown008; /*008*/ float unknown008;
/*012*/ uint32 spellid; /*012*/ uint32 spellid;
/*016*/ uint32 duration; /*016*/ int32 duration;
/*020*/ uint32 playerId; // Global player ID? /*020*/ uint32 playerId; // Global player ID?
/*024*/ uint32 num_hits; /*024*/ uint32 num_hits;
/*028*/ uint8 unknown0028[64]; /*028*/ uint8 unknown0028[64];
@ -725,7 +725,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect; /*006*/ uint8 effect;
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 num_hits; /*016*/ uint32 num_hits;
/*020*/ uint32 unknown020; // Global player ID? /*020*/ uint32 unknown020; // Global player ID?
/*024*/ uint32 playerId; // Player id who cast the buff /*024*/ uint32 playerId; // Player id who cast the buff
@ -866,7 +866,7 @@ struct AA_Array
{ {
uint32 AA; uint32 AA;
uint32 value; uint32 value;
uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live uint32 charges; // expendable charges
}; };
struct Disciplines_Struct { struct Disciplines_Struct {
@ -1323,7 +1323,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct { struct PetCommand_Struct {
/*00*/ uint32 command; /*00*/ uint32 command;
/*04*/ uint32 unknown04; /*04*/ uint32 target;
/*08*/ uint32 unknown08; /*08*/ uint32 unknown08;
}; };
@ -1514,9 +1514,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint32 spellid; /* 05 */ uint32 spellid;
/* 09 */ int32 damage; /* 09 */ int32 damage;
/* 13 */ float unknown11; // cd cc cc 3d /* 13 */ float force; // cd cc cc 3d
/* 17 */ float sequence; // see above notes in Action_Struct /* 17 */ float meleepush_xy; // see above notes in Action_Struct
/* 21 */ uint8 unknown19[9]; // was [9] /* 21 */ float meleepush_z;
/* 25 */ uint8 unknown25[5]; // was [9]
/* 30 */ /* 30 */
}; };
@ -2500,7 +2501,7 @@ struct GroupFollow_Struct { // Live Follow Struct
struct InspectBuffs_Struct { struct InspectBuffs_Struct {
/*000*/ uint32 spell_id[BUFF_COUNT]; /*000*/ uint32 spell_id[BUFF_COUNT];
/*168*/ uint32 tics_remaining[BUFF_COUNT]; /*168*/ int32 tics_remaining[BUFF_COUNT];
}; };
struct LFG_Struct { struct LFG_Struct {
@ -4251,9 +4252,9 @@ struct SendAA_Struct {
/*0025*/ uint32 cost; /*0025*/ uint32 cost;
/*0029*/ uint32 seq; /*0029*/ uint32 seq;
/*0033*/ uint32 current_level; //1s, MQ2 calls this AARankRequired /*0033*/ uint32 current_level; //1s, MQ2 calls this AARankRequired
/*0037*/ uint32 unknown037; // Introduced during HoT /*0037*/ uint32 prereq_skill_count; // mutliple prereqs at least 1, even no prereqs
/*0041*/ uint32 prereq_skill; //is < 0, abs() is category # /*0041*/ uint32 prereq_skill; //is < 0, abs() is category #
/*0045*/ uint32 unknown045; // New Mar 21 2012 - Seen 1 /*0045*/ uint32 prereq_minpoints_count; // mutliple prereqs at least 1, even no prereqs
/*0049*/ uint32 prereq_minpoints; //min points in the prereq /*0049*/ uint32 prereq_minpoints; //min points in the prereq
/*0053*/ uint32 type; /*0053*/ uint32 type;
/*0057*/ uint32 spellid; /*0057*/ uint32 spellid;
@ -4266,10 +4267,16 @@ struct SendAA_Struct {
/*0081*/ uint32 last_id; /*0081*/ uint32 last_id;
/*0085*/ uint32 next_id; /*0085*/ uint32 next_id;
/*0089*/ uint32 cost2; /*0089*/ uint32 cost2;
/*0093*/ uint8 unknown80[7]; /*0093*/ uint8 unknown93;
/*0094*/ uint8 grant_only; // VetAAs, progression, etc
/*0095*/ uint8 unknown95; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though
/*0096*/ uint32 expendable_charges; // max charges of the AA
/*0100*/ uint32 aa_expansion; /*0100*/ uint32 aa_expansion;
/*0104*/ uint32 special_category; /*0104*/ uint32 special_category;
/*0108*/ uint32 unknown0096; /*0108*/ uint8 shroud;
/*0109*/ uint8 unknown109;
/*0110*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter?
/*0111*/ uint8 unknown111;
/*0112*/ uint32 total_abilities; /*0112*/ uint32 total_abilities;
/*0116*/ AA_Ability abilities[0]; /*0116*/ AA_Ability abilities[0];
}; };
@ -4286,13 +4293,6 @@ struct AA_Action {
/*16*/ /*16*/
}; };
struct AA_Skills { //this should be removed and changed to AA_Array
/*00*/ uint32 aa_skill; // Total AAs Spent
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
/*12*/
};
struct AAExpUpdate_Struct { struct AAExpUpdate_Struct {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
/*04*/ uint32 aapoints_unspent; /*04*/ uint32 aapoints_unspent;
@ -4311,14 +4311,7 @@ struct AltAdvStats_Struct {
}; };
struct PlayerAA_Struct { // Is this still used? struct PlayerAA_Struct { // Is this still used?
AA_Skills aa_list[MAX_PP_AA_ARRAY]; AA_Array aa_list[MAX_PP_AA_ARRAY];
};
struct AA_Values {
/*00*/ uint32 aa_skill;
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
/*12*/
}; };
struct AATable_Struct { struct AATable_Struct {
@ -4328,7 +4321,7 @@ struct AATable_Struct {
/*12*/ uint32 aa_spent_archetype; // Seen 40 /*12*/ uint32 aa_spent_archetype; // Seen 40
/*16*/ uint32 aa_spent_class; // Seen 103 /*16*/ uint32 aa_spent_class; // Seen 103
/*20*/ uint32 aa_spent_special; // Seen 0 /*20*/ uint32 aa_spent_special; // Seen 0
/*24*/ AA_Values aa_list[MAX_PP_AA_ARRAY]; /*24*/ AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct Weather_Struct { struct Weather_Struct {

View File

@ -447,7 +447,9 @@ namespace SoD
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -1557,6 +1559,7 @@ namespace SoD
for (r = 0; r < MAX_PP_AA_ARRAY; r++) { for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA); OUT(aa_array[r].AA);
OUT(aa_array[r].value); OUT(aa_array[r].value);
OUT(aa_array[r].charges);
} }
// OUT(unknown02220[4]); // OUT(unknown02220[4]);
OUT(mana); OUT(mana);
@ -1897,6 +1900,7 @@ namespace SoD
OUT(cost2); OUT(cost2);
eq->aa_expansion = emu->aa_expansion; eq->aa_expansion = emu->aa_expansion;
eq->special_category = emu->special_category; eq->special_category = emu->special_category;
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number
OUT(total_abilities); OUT(total_abilities);
unsigned int r; unsigned int r;
for (r = 0; r < emu->total_abilities; r++) { for (r = 0; r < emu->total_abilities; r++) {
@ -1961,15 +1965,16 @@ namespace SoD
for (int counter = 0; counter < character_count; ++counter) { for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address
eq_cse->Level = emu_cse->Level; eq_cse->Level = emu_cse->Level;
eq_cse->HairStyle = emu_cse->HairStyle; eq_cse->HairStyle = emu_cse->HairStyle;
eq_cse->Gender = emu_cse->Gender; eq_cse->Gender = emu_cse->Gender;
strcpy(eq_cse->Name, emu_cse->Name); strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name); eq_ptr += strlen(emu_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset)
eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)]
eq_cse->Beard = emu_cse->Beard; eq_cse->Beard = emu_cse->Beard;
eq_cse->HairColor = emu_cse->HairColor; eq_cse->HairColor = emu_cse->HairColor;
@ -2736,7 +2741,7 @@ namespace SoD
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown12 VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown12
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13 VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown14 - Stance 64 = normal 4 = aggressive 40 = stun/mezzed VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
@ -3350,7 +3355,7 @@ namespace SoD
default: default:
emu->command = eq->command; emu->command = eq->command;
} }
OUT(unknown); IN(target);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }

View File

@ -286,7 +286,7 @@ struct Spawn_Struct
/*0000*/ uint8 unknown12; /*0000*/ uint8 unknown12;
/*0000*/ uint32 petOwnerId; /*0000*/ uint32 petOwnerId;
/*0000*/ uint8 unknown13; /*0000*/ uint8 unknown13;
/*0000*/ uint32 unknown14; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed /*0000*/ uint32 PlayerState; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed
/*0000*/ uint32 unknown15; /*0000*/ uint32 unknown15;
/*0000*/ uint32 unknown16; /*0000*/ uint32 unknown16;
/*0000*/ uint32 unknown17; /*0000*/ uint32 unknown17;
@ -547,7 +547,7 @@ struct SpellBuff_Struct
/*002*/ uint8 bard_modifier; /*002*/ uint8 bard_modifier;
/*003*/ uint8 effect; //not real /*003*/ uint8 effect; //not real
/*004*/ uint32 spellid; /*004*/ uint32 spellid;
/*008*/ uint32 duration; /*008*/ int32 duration;
/*012*/ uint32 counters; /*012*/ uint32 counters;
/*016*/ uint32 unknown004; //Might need to be swapped with player_id /*016*/ uint32 unknown004; //Might need to be swapped with player_id
/*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages /*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages
@ -564,7 +564,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect; /*006*/ uint8 effect;
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 unknown016; /*016*/ uint32 unknown016;
/*020*/ uint32 unknown020; //prolly global player ID /*020*/ uint32 unknown020; //prolly global player ID
/*024*/ uint32 playerId; // Player id who cast the buff /*024*/ uint32 playerId; // Player id who cast the buff
@ -666,7 +666,7 @@ struct AA_Array
{ {
uint32 AA; uint32 AA;
uint32 value; uint32 value;
uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live uint32 charges; // expendable
}; };
@ -1091,7 +1091,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct { struct PetCommand_Struct {
/*000*/ uint32 command; /*000*/ uint32 command;
/*004*/ uint32 unknown; /*004*/ uint32 target;
}; };
/* /*
@ -1272,9 +1272,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ int32 damage; /* 07 */ int32 damage;
/* 11 */ float unknown11; // cd cc cc 3d /* 11 */ float force; // cd cc cc 3d
/* 15 */ float sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint8 unknown19[9]; // was [9] /* 19 */ float meleepush_z;
/* 23 */ uint8 unknown23[5]; // was [9]
/* 28 */ /* 28 */
}; };
@ -3818,10 +3819,16 @@ struct SendAA_Struct {
/*0069*/ uint32 last_id; /*0069*/ uint32 last_id;
/*0073*/ uint32 next_id; /*0073*/ uint32 next_id;
/*0077*/ uint32 cost2; /*0077*/ uint32 cost2;
/*0081*/ uint8 unknown80[7]; /*0081*/ uint8 unknown81;
/*0082*/ uint8 grant_only; // VetAAs, progression, etc
/*0083*/ uint8 unknown83; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though
/*0084*/ uint32 expendable_charges; // max charges of the AA
/*0088*/ uint32 aa_expansion; /*0088*/ uint32 aa_expansion;
/*0092*/ uint32 special_category; /*0092*/ uint32 special_category;
/*0096*/ uint32 unknown0096; /*0096*/ uint8 shroud;
/*0097*/ uint8 unknown97;
/*0098*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter?
/*0099*/ uint8 unknown99;
/*0100*/ uint32 total_abilities; /*0100*/ uint32 total_abilities;
/*0104*/ AA_Ability abilities[0]; /*0104*/ AA_Ability abilities[0];
}; };
@ -3837,12 +3844,6 @@ struct AA_Action {
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };
struct AA_Skills { //this should be removed and changed to AA_Array
/*00*/ uint32 aa_skill; // Total AAs Spent
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
};
struct AAExpUpdate_Struct { struct AAExpUpdate_Struct {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
/*04*/ uint32 aapoints_unspent; /*04*/ uint32 aapoints_unspent;
@ -3860,12 +3861,12 @@ struct AltAdvStats_Struct {
}; };
struct PlayerAA_Struct { // Is this still used? struct PlayerAA_Struct { // Is this still used?
AA_Skills aa_list[MAX_PP_AA_ARRAY]; AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct AATable_Struct { struct AATable_Struct {
/*00*/ int32 aa_spent; // Total AAs Spent /*00*/ int32 aa_spent; // Total AAs Spent
/*04*/ AA_Skills aa_list[MAX_PP_AA_ARRAY]; /*04*/ AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct Weather_Struct { struct Weather_Struct {

View File

@ -427,7 +427,9 @@ namespace SoF
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -1215,6 +1217,7 @@ namespace SoF
for (r = 0; r < MAX_PP_AA_ARRAY; r++) { for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA); OUT(aa_array[r].AA);
OUT(aa_array[r].value); OUT(aa_array[r].value);
OUT(aa_array[r].charges);
} }
// OUT(unknown02220[4]); // OUT(unknown02220[4]);
OUT(mana); OUT(mana);
@ -1556,6 +1559,7 @@ namespace SoF
OUT(cost2); OUT(cost2);
eq->aa_expansion = emu->aa_expansion; eq->aa_expansion = emu->aa_expansion;
eq->special_category = emu->special_category; eq->special_category = emu->special_category;
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number
OUT(total_abilities); OUT(total_abilities);
unsigned int r; unsigned int r;
for (r = 0; r < emu->total_abilities; r++) { for (r = 0; r < emu->total_abilities; r++) {
@ -1620,15 +1624,16 @@ namespace SoF
for (int counter = 0; counter < character_count; ++counter) { for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address
eq_cse->Level = emu_cse->Level; eq_cse->Level = emu_cse->Level;
eq_cse->HairStyle = emu_cse->HairStyle; eq_cse->HairStyle = emu_cse->HairStyle;
eq_cse->Gender = emu_cse->Gender; eq_cse->Gender = emu_cse->Gender;
strcpy(eq_cse->Name, emu_cse->Name); strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name); eq_ptr += strlen(emu_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset)
eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)]
eq_cse->Beard = emu_cse->Beard; eq_cse->Beard = emu_cse->Beard;
eq_cse->HairColor = emu_cse->HairColor; eq_cse->HairColor = emu_cse->HairColor;
@ -2087,6 +2092,7 @@ namespace SoF
eq->runspeed = emu->runspeed; eq->runspeed = emu->runspeed;
eq->light = emu->light; eq->light = emu->light;
eq->level = emu->level; eq->level = emu->level;
eq->PlayerState = emu->PlayerState;
eq->lfg = emu->lfg; eq->lfg = emu->lfg;
eq->hairstyle = emu->hairstyle; eq->hairstyle = emu->hairstyle;
eq->haircolor = emu->haircolor; eq->haircolor = emu->haircolor;
@ -2688,7 +2694,7 @@ namespace SoF
default: default:
emu->command = eq->command; emu->command = eq->command;
} }
OUT(unknown); IN(target);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }

View File

@ -241,7 +241,8 @@ struct Spawn_Struct {
/*0506*/ uint8 light; // Spawn's lightsource /*0506*/ uint8 light; // Spawn's lightsource
/*0507*/ uint8 unknown0507[4]; /*0507*/ uint8 unknown0507[4];
/*0511*/ uint8 level; // Spawn Level /*0511*/ uint8 level; // Spawn Level
/*0512*/ uint8 unknown0512[16]; /*0512*/ uint32 PlayerState;
/*0516*/ uint8 unknown0516[12];
/*0528*/ uint8 lfg; /*0528*/ uint8 lfg;
/*0529*/ uint8 unknown0529[4]; /*0529*/ uint8 unknown0529[4];
/*0533*/ uint8 hairstyle; // Sets the style of hair /*0533*/ uint8 hairstyle; // Sets the style of hair
@ -525,7 +526,7 @@ struct SpellBuff_Struct
/*002*/ uint8 bard_modifier; /*002*/ uint8 bard_modifier;
/*003*/ uint8 effect; //not real /*003*/ uint8 effect; //not real
/*004*/ uint32 spellid; /*004*/ uint32 spellid;
/*008*/ uint32 duration; /*008*/ int32 duration;
/*012*/ uint32 counters; /*012*/ uint32 counters;
/*016*/ uint32 unknown004; //Might need to be swapped with player_id /*016*/ uint32 unknown004; //Might need to be swapped with player_id
/*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages /*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages
@ -542,7 +543,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect; /*006*/ uint8 effect;
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 unknown016; /*016*/ uint32 unknown016;
/*020*/ uint32 unknown020; //prolly global player ID /*020*/ uint32 unknown020; //prolly global player ID
/*024*/ uint32 playerId; // Player id who cast the buff /*024*/ uint32 playerId; // Player id who cast the buff
@ -644,7 +645,7 @@ struct AA_Array
{ {
uint32 AA; uint32 AA;
uint32 value; uint32 value;
uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live uint32 charges; // expendable charges
}; };
@ -1068,7 +1069,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct { struct PetCommand_Struct {
/*000*/ uint32 command; /*000*/ uint32 command;
/*004*/ uint32 unknown; /*004*/ uint32 target;
}; };
/* /*
@ -1249,9 +1250,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ int32 damage; /* 07 */ int32 damage;
/* 11 */ float unknown11; // cd cc cc 3d /* 11 */ float force; // cd cc cc 3d
/* 15 */ float sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint8 unknown19[9]; // was [9] /* 19 */ float meleepush_z;
/* 23 */ uint8 unknown23[5]; // was [9]
/* 28 */ /* 28 */
}; };
@ -3681,10 +3683,14 @@ struct SendAA_Struct {
/*0069*/ uint32 last_id; /*0069*/ uint32 last_id;
/*0073*/ uint32 next_id; /*0073*/ uint32 next_id;
/*0077*/ uint32 cost2; /*0077*/ uint32 cost2;
/*0081*/ uint8 unknown80[7]; /*0081*/ uint8 unknown81;
/*0082*/ uint8 grant_only; // VetAAs, progression, etc
/*0083*/ uint8 unknown83; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though
/*0084*/ uint32 expendable_charges; // max charges of the AA
/*0088*/ uint32 aa_expansion; /*0088*/ uint32 aa_expansion;
/*0092*/ uint32 special_category; /*0092*/ uint32 special_category;
/*0096*/ uint16 unknown0096; /*0096*/ uint8 shroud;
/*0097*/ uint8 unknown97;
/*0098*/ uint32 total_abilities; /*0098*/ uint32 total_abilities;
/*0102*/ AA_Ability abilities[0]; /*0102*/ AA_Ability abilities[0];
}; };
@ -3700,12 +3706,6 @@ struct AA_Action {
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };
struct AA_Skills { //this should be removed and changed to AA_Array
/*00*/ uint32 aa_skill; // Total AAs Spent
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
};
struct AAExpUpdate_Struct { struct AAExpUpdate_Struct {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
/*04*/ uint32 aapoints_unspent; /*04*/ uint32 aapoints_unspent;
@ -3723,12 +3723,12 @@ struct AltAdvStats_Struct {
}; };
struct PlayerAA_Struct { struct PlayerAA_Struct {
AA_Skills aa_list[MAX_PP_AA_ARRAY]; AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct AATable_Struct { struct AATable_Struct {
/*00*/ int32 aa_spent; // Total AAs Spent /*00*/ int32 aa_spent; // Total AAs Spent
/*04*/ AA_Skills aa_list[MAX_PP_AA_ARRAY]; /*04*/ AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct Weather_Struct { struct Weather_Struct {

View File

@ -122,7 +122,7 @@ namespace Titanium
EAT_ENCODE(OP_GuildMemberLevelUpdate); // added ; EAT_ENCODE(OP_GuildMemberLevelUpdate); // added ;
EAT_ENCODE(OP_ZoneServerReady); // added ; EAT_ENCODE(OP_ZoneServerReady); // added ;
ENCODE(OP_Action) ENCODE(OP_Action)
{ {
ENCODE_LENGTH_EXACT(Action_Struct); ENCODE_LENGTH_EXACT(Action_Struct);
@ -328,7 +328,7 @@ namespace Titanium
{ {
SETUP_VAR_ENCODE(ExpeditionCompass_Struct); SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count); ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
OUT(count); OUT(count);
for (uint32 i = 0; i < emu->count; ++i) for (uint32 i = 0; i < emu->count; ++i)
@ -1100,8 +1100,8 @@ namespace Titanium
unsigned int r; unsigned int r;
for (r = 0; r < structs::MAX_PP_AA_ARRAY; r++) { for (r = 0; r < structs::MAX_PP_AA_ARRAY; r++) {
OUT(aa_list[r].aa_skill); OUT(aa_list[r].AA);
OUT(aa_list[r].aa_value); OUT(aa_list[r].value);
} }
FINISH_ENCODE(); FINISH_ENCODE();
@ -1310,7 +1310,7 @@ namespace Titanium
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer; delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req); dest->FastQueuePacket(&in, ack_req);
} }
@ -1353,7 +1353,7 @@ namespace Titanium
InBuffer += strlen(InBuffer) + 1; InBuffer += strlen(InBuffer) + 1;
memcpy(OutBuffer, InBuffer, sizeof(TaskDescriptionTrailer_Struct)); memcpy(OutBuffer, InBuffer, sizeof(TaskDescriptionTrailer_Struct));
delete[] __emu_buffer; delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req); dest->FastQueuePacket(&in, ack_req);
} }
@ -1551,7 +1551,7 @@ namespace Titanium
eq->beardcolor = emu->beardcolor; eq->beardcolor = emu->beardcolor;
// eq->unknown0147[4] = emu->unknown0147[4]; // eq->unknown0147[4] = emu->unknown0147[4];
eq->level = emu->level; eq->level = emu->level;
// eq->unknown0259[4] = emu->unknown0259[4]; eq->PlayerState = emu->PlayerState;
eq->beard = emu->beard; eq->beard = emu->beard;
strcpy(eq->suffix, emu->suffix); strcpy(eq->suffix, emu->suffix);
eq->petOwnerId = emu->petOwnerId; eq->petOwnerId = emu->petOwnerId;
@ -1623,7 +1623,7 @@ namespace Titanium
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
DECODE(OP_ApplyPoison) DECODE(OP_ApplyPoison)
{ {
DECODE_LENGTH_EXACT(structs::ApplyPoison_Struct); DECODE_LENGTH_EXACT(structs::ApplyPoison_Struct);
@ -1944,7 +1944,7 @@ namespace Titanium
default: default:
emu->command = eq->command; emu->command = eq->command;
} }
OUT(unknown); IN(target);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
@ -2153,7 +2153,7 @@ namespace Titanium
return serverSlot; // deprecated return serverSlot; // deprecated
} }
static inline int16 ServerToTitaniumCorpseSlot(uint32 serverCorpseSlot) static inline int16 ServerToTitaniumCorpseSlot(uint32 serverCorpseSlot)
{ {
//int16 TitaniumCorpse; //int16 TitaniumCorpse;
@ -2168,7 +2168,7 @@ namespace Titanium
return titaniumSlot; // deprecated return titaniumSlot; // deprecated
} }
static inline uint32 TitaniumToServerCorpseSlot(int16 titaniumCorpseSlot) static inline uint32 TitaniumToServerCorpseSlot(int16 titaniumCorpseSlot)
{ {
//uint32 ServerCorpse; //uint32 ServerCorpse;

View File

@ -212,7 +212,7 @@ struct Spawn_Struct {
/*0146*/ uint8 beardcolor; // Beard color /*0146*/ uint8 beardcolor; // Beard color
/*0147*/ uint8 unknown0147[4]; /*0147*/ uint8 unknown0147[4];
/*0151*/ uint8 level; // Spawn Level /*0151*/ uint8 level; // Spawn Level
/*0152*/ uint8 unknown0259[4]; // ***Placeholder /*0152*/ uint32 PlayerState; // PlayerState controls some animation stuff
/*0156*/ uint8 beard; // Beard style /*0156*/ uint8 beard; // Beard style
/*0157*/ char suffix[32]; // Player's suffix (of Veeshan, etc.) /*0157*/ char suffix[32]; // Player's suffix (of Veeshan, etc.)
/*0189*/ uint32 petOwnerId; // If this is a pet, the spawn id of owner /*0189*/ uint32 petOwnerId; // If this is a pet, the spawn id of owner
@ -445,7 +445,7 @@ struct SpellBuff_Struct
/*002*/ uint8 bard_modifier; /*002*/ uint8 bard_modifier;
/*003*/ uint8 effect; //not real /*003*/ uint8 effect; //not real
/*004*/ uint32 spellid; /*004*/ uint32 spellid;
/*008*/ uint32 duration; /*008*/ int32 duration;
/*012*/ uint32 counters; /*012*/ uint32 counters;
/*016*/ uint32 player_id; //'global' ID of the caster, for wearoff messages /*016*/ uint32 player_id; //'global' ID of the caster, for wearoff messages
}; };
@ -457,7 +457,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect; /*006*/ uint8 effect;
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 unknown016; /*016*/ uint32 unknown016;
/*020*/ uint32 unknown020; //prolly global player ID /*020*/ uint32 unknown020; //prolly global player ID
/*024*/ uint32 slotid; /*024*/ uint32 slotid;
@ -950,7 +950,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct { struct PetCommand_Struct {
/*000*/ uint32 command; /*000*/ uint32 command;
/*004*/ uint32 unknown; /*004*/ uint32 target;
}; };
/* /*
@ -1101,9 +1101,9 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ uint32 damage; /* 07 */ uint32 damage;
/* 11 */ uint32 unknown11; /* 11 */ float force;
/* 15 */ uint32 sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint32 unknown19; /* 19 */ float meleepush_z;
/* 23 */ /* 23 */
}; };
@ -3179,11 +3179,6 @@ struct AA_Action {
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };
struct AA_Skills { //this should be removed and changed to AA_Array
/*00*/ uint32 aa_skill;
/*04*/ uint32 aa_value;
};
struct AAExpUpdate_Struct { struct AAExpUpdate_Struct {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
/*04*/ uint32 aapoints_unspent; /*04*/ uint32 aapoints_unspent;
@ -3201,11 +3196,11 @@ struct AltAdvStats_Struct {
}; };
struct PlayerAA_Struct { struct PlayerAA_Struct {
AA_Skills aa_list[MAX_PP_AA_ARRAY]; AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct AATable_Struct { struct AATable_Struct {
AA_Skills aa_list[MAX_PP_AA_ARRAY]; AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct Weather_Struct { struct Weather_Struct {

View File

@ -387,7 +387,7 @@ namespace UF
__packet->WriteUInt32(emu->entries[i].num_hits); __packet->WriteUInt32(emu->entries[i].num_hits);
__packet->WriteString(""); __packet->WriteString("");
} }
__packet->WriteUInt8(!emu->all_buffs); __packet->WriteUInt8(emu->type);
FINISH_ENCODE(); FINISH_ENCODE();
/* /*
@ -582,7 +582,9 @@ namespace UF
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -856,8 +858,8 @@ namespace UF
// field to be set to (float)255.0 to appear at all, and also the size field below to be 5, to be the correct size. I think SoD has the same // field to be set to (float)255.0 to appear at all, and also the size field below to be 5, to be the correct size. I think SoD has the same
// issue. // issue.
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown, observed 0 VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->solidtype); // Unknown, observed 0
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // This appears to be the size field. VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt.
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z);
@ -1806,6 +1808,7 @@ namespace UF
for (r = 0; r < MAX_PP_AA_ARRAY; r++) { for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA); OUT(aa_array[r].AA);
OUT(aa_array[r].value); OUT(aa_array[r].value);
OUT(aa_array[r].charges);
} }
// OUT(unknown02220[4]); // OUT(unknown02220[4]);
OUT(mana); OUT(mana);
@ -2133,9 +2136,9 @@ namespace UF
for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i) for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i)
{ {
eq->aa_list[i].aa_skill = emu->aa_list[i].aa_skill; eq->aa_list[i].AA = emu->aa_list[i].AA;
eq->aa_list[i].aa_value = emu->aa_list[i].aa_value; eq->aa_list[i].value = emu->aa_list[i].value;
eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08; eq->aa_list[i].charges = emu->aa_list[i].charges;
} }
FINISH_ENCODE(); FINISH_ENCODE();
@ -2180,6 +2183,7 @@ namespace UF
OUT(cost2); OUT(cost2);
eq->aa_expansion = emu->aa_expansion; eq->aa_expansion = emu->aa_expansion;
eq->special_category = emu->special_category; eq->special_category = emu->special_category;
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number
OUT(total_abilities); OUT(total_abilities);
unsigned int r; unsigned int r;
for (r = 0; r < emu->total_abilities; r++) { for (r = 0; r < emu->total_abilities; r++) {
@ -2214,7 +2218,7 @@ namespace UF
FINISH_ENCODE(); FINISH_ENCODE();
return; return;
} }
unsigned char *emu_ptr = __emu_buffer; unsigned char *emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct); emu_ptr += sizeof(CharacterSelect_Struct);
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr; CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
@ -2252,15 +2256,16 @@ namespace UF
for (int counter = 0; counter < character_count; ++counter) { for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address
eq_cse->Level = emu_cse->Level; eq_cse->Level = emu_cse->Level;
eq_cse->HairStyle = emu_cse->HairStyle; eq_cse->HairStyle = emu_cse->HairStyle;
eq_cse->Gender = emu_cse->Gender; eq_cse->Gender = emu_cse->Gender;
strcpy(eq_cse->Name, emu_cse->Name); strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name); eq_ptr += strlen(emu_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset)
eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)]
eq_cse->Beard = emu_cse->Beard; eq_cse->Beard = emu_cse->Beard;
eq_cse->HairColor = emu_cse->HairColor; eq_cse->HairColor = emu_cse->HairColor;
@ -3004,7 +3009,7 @@ namespace UF
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown12 VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown12
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13 VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown14 - Stance 64 = normal 4 = aggressive 40 = stun/mezzed VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
@ -3357,7 +3362,7 @@ namespace UF
IN(type); IN(type);
IN(spellid); IN(spellid);
IN(damage); IN(damage);
emu->sequence = eq->sequence; IN(meleepush_xy);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
@ -3600,7 +3605,7 @@ namespace UF
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct); SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
IN(command); IN(command);
IN(unknown); IN(target);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
@ -3862,7 +3867,7 @@ namespace UF
UF::structs::ItemSerializationHeaderFinish hdrf; UF::structs::ItemSerializationHeaderFinish hdrf;
hdrf.ornamentIcon = ornaIcon; hdrf.ornamentIcon = ornaIcon;
hdrf.unknown060 = 0; //This is Always 0.. or it breaks shit.. hdrf.unknown060 = 0; //This is Always 0.. or it breaks shit..
hdrf.unknown061 = 0; //possibly ornament / special ornament hdrf.unknown061 = 0; //possibly ornament / special ornament
hdrf.isCopied = 0; //Flag for item to be 'Copied' hdrf.isCopied = 0; //Flag for item to be 'Copied'
hdrf.ItemClass = item->ItemClass; hdrf.ItemClass = item->ItemClass;

View File

@ -286,7 +286,7 @@ struct Spawn_Struct
/*0000*/ uint8 unknown12; /*0000*/ uint8 unknown12;
/*0000*/ uint32 petOwnerId; /*0000*/ uint32 petOwnerId;
/*0000*/ uint8 unknown13; /*0000*/ uint8 unknown13;
/*0000*/ uint32 unknown14; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed /*0000*/ uint32 PlayerState; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed
/*0000*/ uint32 unknown15; /*0000*/ uint32 unknown15;
/*0000*/ uint32 unknown16; /*0000*/ uint32 unknown16;
/*0000*/ uint32 unknown17; /*0000*/ uint32 unknown17;
@ -551,7 +551,7 @@ struct SpellBuff_Struct
/*003*/ uint8 effect; // not real /*003*/ uint8 effect; // not real
/*004*/ uint32 unknown004; // Seen 1 for no buff /*004*/ uint32 unknown004; // Seen 1 for no buff
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 unknown016; /*016*/ uint32 unknown016;
/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages /*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*024*/ uint32 counters; /*024*/ uint32 counters;
@ -568,7 +568,7 @@ struct SpellBuffFade_Struct_Underfoot {
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ float unknown008; /*008*/ float unknown008;
/*012*/ uint32 spellid; /*012*/ uint32 spellid;
/*016*/ uint32 duration; /*016*/ int32 duration;
/*020*/ uint32 num_hits; /*020*/ uint32 num_hits;
/*024*/ uint32 playerId; // Global player ID? /*024*/ uint32 playerId; // Global player ID?
/*028*/ uint32 unknown020; /*028*/ uint32 unknown020;
@ -585,7 +585,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect; /*006*/ uint8 effect;
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ int32 duration;
/*016*/ uint32 unknown016; /*016*/ uint32 unknown016;
/*020*/ uint32 unknown020; // Global player ID? /*020*/ uint32 unknown020; // Global player ID?
/*024*/ uint32 playerId; // Player id who cast the buff /*024*/ uint32 playerId; // Player id who cast the buff
@ -713,7 +713,7 @@ struct AA_Array
{ {
uint32 AA; uint32 AA;
uint32 value; uint32 value;
uint32 unknown08; // Looks like AA_Array is now 12 bytes in Underfoot uint32 charges; // expendable
}; };
@ -1146,7 +1146,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct { struct PetCommand_Struct {
/*000*/ uint32 command; /*000*/ uint32 command;
/*004*/ uint32 unknown; /*004*/ uint32 target;
}; };
/* /*
@ -1330,9 +1330,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ int32 damage; /* 07 */ int32 damage;
/* 11 */ float unknown11; // cd cc cc 3d /* 11 */ float force; // cd cc cc 3d
/* 15 */ float sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint8 unknown19[9]; // was [9] /* 19 */ float meleepush_z;
/* 23 */ uint8 unknown23[5]; // was [9]
/* 28 */ /* 28 */
}; };
@ -2187,7 +2188,7 @@ struct GroupFollow_Struct { // Underfoot Follow Struct
struct InspectBuffs_Struct { struct InspectBuffs_Struct {
/*000*/ uint32 spell_id[BUFF_COUNT]; /*000*/ uint32 spell_id[BUFF_COUNT];
/*100*/ uint32 filler100[5]; // BUFF_COUNT is really 30... /*100*/ uint32 filler100[5]; // BUFF_COUNT is really 30...
/*120*/ uint32 tics_remaining[BUFF_COUNT]; /*120*/ int32 tics_remaining[BUFF_COUNT];
/*220*/ uint32 filler220[5]; // BUFF_COUNT is really 30... /*220*/ uint32 filler220[5]; // BUFF_COUNT is really 30...
}; };
@ -3891,10 +3892,16 @@ struct SendAA_Struct {
/*0069*/ uint32 last_id; /*0069*/ uint32 last_id;
/*0073*/ uint32 next_id; /*0073*/ uint32 next_id;
/*0077*/ uint32 cost2; /*0077*/ uint32 cost2;
/*0081*/ uint8 unknown80[7]; /*0081*/ uint8 unknown81;
/*0082*/ uint8 grant_only; // VetAAs, progression, etc
/*0083*/ uint8 unknown83; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though
/*0084*/ uint32 expendable_charges; // max charges of the AA
/*0088*/ uint32 aa_expansion; /*0088*/ uint32 aa_expansion;
/*0092*/ uint32 special_category; /*0092*/ uint32 special_category;
/*0096*/ uint32 unknown0096; /*0096*/ uint8 shroud;
/*0097*/ uint8 unknown97;
/*0098*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter?
/*0099*/ uint8 unknown99;
/*0100*/ uint32 total_abilities; /*0100*/ uint32 total_abilities;
/*0104*/ AA_Ability abilities[0]; /*0104*/ AA_Ability abilities[0];
}; };
@ -3910,11 +3917,6 @@ struct AA_Action {
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };
struct AA_Skills { //this should be removed and changed to AA_Array
/*00*/ uint32 aa_skill; // Total AAs Spent
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
};
struct AAExpUpdate_Struct { struct AAExpUpdate_Struct {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
@ -3933,7 +3935,7 @@ struct AltAdvStats_Struct {
}; };
struct PlayerAA_Struct { // Is this still used? struct PlayerAA_Struct { // Is this still used?
AA_Skills aa_list[MAX_PP_AA_ARRAY]; AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct AATable_Struct { struct AATable_Struct {
@ -3943,7 +3945,7 @@ struct AATable_Struct {
/*12*/ int32 unknown012; /*12*/ int32 unknown012;
/*16*/ int32 unknown016; /*16*/ int32 unknown016;
/*20*/ int32 unknown020; /*20*/ int32 unknown020;
/*24*/ AA_Skills aa_list[MAX_PP_AA_ARRAY]; /*24*/ AA_Array aa_list[MAX_PP_AA_ARRAY];
}; };
struct Weather_Struct { struct Weather_Struct {

View File

@ -39,7 +39,8 @@ enum { //values for pTimerType
pTimerDisciplineReuseStart = 14, pTimerDisciplineReuseStart = 14,
pTimerDisciplineReuseEnd = 24, pTimerDisciplineReuseEnd = 24,
pTimerCombatAbility = 25, pTimerCombatAbility = 25,
pTimerBeggingPickPocket = 26, pTimerCombatAbility2 = 26, // RoF2+ Tiger Claw is unlinked from other monk skills, generic in case other classes ever need it
pTimerBeggingPickPocket = 27,
pTimerLayHands = 87, //these IDs are used by client too pTimerLayHands = 87, //these IDs are used by client too
pTimerHarmTouch = 89, //so dont change them pTimerHarmTouch = 89, //so dont change them

View File

@ -47,6 +47,8 @@
#define IKSAR 128 #define IKSAR 128
#define VAHSHIR 130 #define VAHSHIR 130
#define CONTROLLED_BOAT 141 #define CONTROLLED_BOAT 141
#define MINOR_ILL_OBJ 142
#define TREE 143
#define IKSAR_SKELETON 161 #define IKSAR_SKELETON 161
#define FROGLOK 330 #define FROGLOK 330
#define FROGLOK2 74 // Not sure why /who all reports race as 74 for frogloks #define FROGLOK2 74 // Not sure why /who all reports race as 74 for frogloks

File diff suppressed because it is too large Load Diff

View File

@ -55,3 +55,54 @@ bool EQEmu::IsSpecializedSkill(SkillUseTypes skill)
return false; return false;
} }
} }
float EQEmu::GetSkillMeleePushForce(SkillUseTypes skill)
{
// This is the force/magnitude of the push from an attack of this skill type
// You can find these numbers in the clients skill struct
switch (skill) {
case Skill1HBlunt:
case Skill1HSlashing:
case SkillHandtoHand:
case SkillThrowing:
return 0.1f;
case Skill2HBlunt:
case Skill2HSlashing:
case SkillEagleStrike:
case SkillKick:
case SkillTigerClaw:
//case Skill2HPiercing:
return 0.2f;
case SkillArchery:
return 0.15f;
case SkillBackstab:
case SkillBash:
return 0.3f;
case SkillDragonPunch:
case SkillRoundKick:
return 0.25f;
case SkillFlyingKick:
return 0.4f;
case Skill1HPiercing:
case SkillFrenzy:
return 0.05f;
case SkillIntimidation:
return 2.5f;
default:
return 0.0f;
}
}
bool EQEmu::IsBardInstrumentSkill(SkillUseTypes skill)
{
switch (skill) {
case SkillBrassInstruments:
case SkillSinging:
case SkillStringedInstruments:
case SkillWindInstruments:
case SkillPercussionInstruments:
return true;
default:
return false;
}
}

View File

@ -270,6 +270,8 @@ typedef enum {
namespace EQEmu { namespace EQEmu {
bool IsTradeskill(SkillUseTypes skill); bool IsTradeskill(SkillUseTypes skill);
bool IsSpecializedSkill(SkillUseTypes skill); bool IsSpecializedSkill(SkillUseTypes skill);
float GetSkillMeleePushForce(SkillUseTypes skill);
bool IsBardInstrumentSkill(SkillUseTypes skill);
} }
#endif #endif

View File

@ -72,7 +72,7 @@
#include "../common/eqemu_logsys.h" #include "../common/eqemu_logsys.h"
#include "classes.h" #include "classes.h"
#include "spdat.h" #include "spdat.h"
@ -162,7 +162,7 @@ bool IsCureSpell(uint16 spell_id)
bool CureEffect = false; bool CureEffect = false;
for(int i = 0; i < EFFECT_COUNT; i++){ for(int i = 0; i < EFFECT_COUNT; i++){
if (sp.effectid[i] == SE_DiseaseCounter || sp.effectid[i] == SE_PoisonCounter if (sp.effectid[i] == SE_DiseaseCounter || sp.effectid[i] == SE_PoisonCounter
|| sp.effectid[i] == SE_CurseCounter || sp.effectid[i] == SE_CorruptionCounter) || sp.effectid[i] == SE_CurseCounter || sp.effectid[i] == SE_CorruptionCounter)
CureEffect = true; CureEffect = true;
} }
@ -405,7 +405,7 @@ bool IsPartialCapableSpell(uint16 spell_id)
{ {
if (spells[spell_id].no_partial_resist) if (spells[spell_id].no_partial_resist)
return false; return false;
if (IsPureNukeSpell(spell_id)) if (IsPureNukeSpell(spell_id))
return true; return true;
@ -447,7 +447,7 @@ bool IsTGBCompatibleSpell(uint16 spell_id)
bool IsBardSong(uint16 spell_id) bool IsBardSong(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 255) if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 127 && !spells[spell_id].IsDisciplineBuff)
return true; return true;
return false; return false;
@ -693,9 +693,9 @@ bool IsCombatSkill(uint16 spell_id)
{ {
if (!IsValidSpell(spell_id)) if (!IsValidSpell(spell_id))
return false; return false;
//Check if Discipline //Check if Discipline
if ((spells[spell_id].mana == 0 && (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep))) if ((spells[spell_id].mana == 0 && (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep)))
return true; return true;
return false; return false;
@ -1040,7 +1040,7 @@ bool IsCastonFadeDurationSpell(uint16 spell_id)
bool IsPowerDistModSpell(uint16 spell_id) bool IsPowerDistModSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && if (IsValidSpell(spell_id) &&
(spells[spell_id].max_dist_mod || spells[spell_id].min_dist_mod) && spells[spell_id].max_dist > spells[spell_id].min_dist) (spells[spell_id].max_dist_mod || spells[spell_id].min_dist_mod) && spells[spell_id].max_dist > spells[spell_id].min_dist)
return true; return true;

View File

@ -133,7 +133,7 @@ typedef enum {
/* 42 */ ST_Directional = 0x2a, //ae around this target between two angles /* 42 */ ST_Directional = 0x2a, //ae around this target between two angles
/* 43 */ ST_GroupClientAndPet = 0x2b, /* 43 */ ST_GroupClientAndPet = 0x2b,
/* 44 */ ST_Beam = 0x2c, /* 44 */ ST_Beam = 0x2c,
/* 45 */ ST_Ring = 0x2d, /* 45 */ ST_Ring = 0x2d,
/* 46 */ ST_TargetsTarget = 0x2e, // uses the target of your target /* 46 */ ST_TargetsTarget = 0x2e, // uses the target of your target
/* 47 */ ST_PetMaster = 0x2f, // uses the master as target /* 47 */ ST_PetMaster = 0x2f, // uses the master as target
/* 48 */ // UNKNOWN /* 48 */ // UNKNOWN
@ -151,10 +151,10 @@ typedef enum {
} DmgShieldType; } DmgShieldType;
//Spell Effect IDs //Spell Effect IDs
// full listing: https://forums.station.sony.com/eq/index.php?threads/enumerated-spa-list.206288/ // https://forums.daybreakgames.com/eq/index.php?threads/enumerated-spa-list.206288/
// mirror: http://pastebin.com/MYeQqGwe // mirror: http://pastebin.com/MYeQqGwe
#define SE_CurrentHP 0 // implemented - Heals and nukes, repeates every tic if in a buff #define SE_CurrentHP 0 // implemented - Heals and nukes, repeates every tic if in a buff
#define SE_ArmorClass 1 // implemented #define SE_ArmorClass 1 // implemented
#define SE_ATK 2 // implemented #define SE_ATK 2 // implemented
#define SE_MovementSpeed 3 // implemented - SoW, SoC, etc #define SE_MovementSpeed 3 // implemented - SoW, SoC, etc
#define SE_STR 4 // implemented #define SE_STR 4 // implemented
@ -197,7 +197,7 @@ typedef enum {
#define SE_Destroy 41 // implemented - Disintegrate, Banishment of Shadows #define SE_Destroy 41 // implemented - Disintegrate, Banishment of Shadows
#define SE_ShadowStep 42 // implemented #define SE_ShadowStep 42 // implemented
#define SE_Berserk 43 // implemented (*not used in any known live spell) Makes client 'Berserk' giving crip blow chance. #define SE_Berserk 43 // implemented (*not used in any known live spell) Makes client 'Berserk' giving crip blow chance.
#define SE_Lycanthropy 44 // implemented #define SE_Lycanthropy 44 // implemented
#define SE_Vampirism 45 // implemented (*not used in any known live spell) Stackable lifetap from melee. #define SE_Vampirism 45 // implemented (*not used in any known live spell) Stackable lifetap from melee.
#define SE_ResistFire 46 // implemented #define SE_ResistFire 46 // implemented
#define SE_ResistCold 47 // implemented #define SE_ResistCold 47 // implemented
@ -247,7 +247,7 @@ typedef enum {
#define SE_SummonCorpse 91 // implemented #define SE_SummonCorpse 91 // implemented
#define SE_InstantHate 92 // implemented - add hate #define SE_InstantHate 92 // implemented - add hate
#define SE_StopRain 93 // implemented - Wake of Karana #define SE_StopRain 93 // implemented - Wake of Karana
#define SE_NegateIfCombat 94 // implemented #define SE_NegateIfCombat 94 // implemented
#define SE_Sacrifice 95 // implemented #define SE_Sacrifice 95 // implemented
#define SE_Silence 96 // implemented #define SE_Silence 96 // implemented
#define SE_ManaPool 97 // implemented #define SE_ManaPool 97 // implemented
@ -299,7 +299,7 @@ typedef enum {
#define SE_LimitCastTimeMin 143 // implemented #define SE_LimitCastTimeMin 143 // implemented
#define SE_LimitCastTimeMax 144 // implemented (*not used in any known live spell) #define SE_LimitCastTimeMax 144 // implemented (*not used in any known live spell)
#define SE_Teleport2 145 // implemented - Banishment of the Pantheon #define SE_Teleport2 145 // implemented - Banishment of the Pantheon
//#define SE_ElectricityResist 146 // *not implemented (Lightning Rod: 23233) //#define SE_ElectricityResist 146 // *not implemented (Lightning Rod: 23233)
#define SE_PercentalHeal 147 // implemented #define SE_PercentalHeal 147 // implemented
#define SE_StackingCommand_Block 148 // implemented? #define SE_StackingCommand_Block 148 // implemented?
#define SE_StackingCommand_Overwrite 149 // implemented? #define SE_StackingCommand_Overwrite 149 // implemented?
@ -529,7 +529,7 @@ typedef enum {
#define SE_CastOnFadeEffectAlways 373 // implemented - Triggers if fades after natural duration OR from rune/numhits fades. #define SE_CastOnFadeEffectAlways 373 // implemented - Triggers if fades after natural duration OR from rune/numhits fades.
#define SE_ApplyEffect 374 // implemented #define SE_ApplyEffect 374 // implemented
#define SE_DotCritDmgIncrease 375 // implemented - Increase damage of DoT critical amount #define SE_DotCritDmgIncrease 375 // implemented - Increase damage of DoT critical amount
//#define SE_Fling 376 // *not implemented - used in 2 test spells (12945 | Movement Test Spell 1) //#define SE_Fling 376 // *not implemented - used in 2 test spells (12945 | Movement Test Spell 1)
#define SE_CastOnFadeEffectNPC 377 // implemented - Triggers only if fades after natural duration (On live these are usually players spells that effect an NPC). #define SE_CastOnFadeEffectNPC 377 // implemented - Triggers only if fades after natural duration (On live these are usually players spells that effect an NPC).
#define SE_SpellEffectResistChance 378 // implemented - Increase chance to resist specific spell effect (base1=value, base2=spell effect id) #define SE_SpellEffectResistChance 378 // implemented - Increase chance to resist specific spell effect (base1=value, base2=spell effect id)
#define SE_ShadowStepDirectional 379 // implemented - handled by client #define SE_ShadowStepDirectional 379 // implemented - handled by client
@ -560,7 +560,7 @@ typedef enum {
#define SE_LimitSpellSubclass 404 // *not implemented - Limits to specific types of spells (see CheckSpellCategory) [Categories NOT defined yet] #define SE_LimitSpellSubclass 404 // *not implemented - Limits to specific types of spells (see CheckSpellCategory) [Categories NOT defined yet]
#define SE_TwoHandBluntBlock 405 // implemented - chance to block attacks when using two hand blunt weapons (similiar to shield block) #define SE_TwoHandBluntBlock 405 // implemented - chance to block attacks when using two hand blunt weapons (similiar to shield block)
#define SE_CastonNumHitFade 406 // implemented - casts a spell when a buff fades due to its numhits being depleted #define SE_CastonNumHitFade 406 // implemented - casts a spell when a buff fades due to its numhits being depleted
#define SE_CastonFocusEffect 407 // implemented - casts a spell if focus limits are met (ie triggers when a focus effects is applied) #define SE_CastonFocusEffect 407 // implemented - casts a spell if focus limits are met (ie triggers when a focus effects is applied)
#define SE_LimitHPPercent 408 // implemented - limited to a certain percent of your hp(ie heals up to 50%) #define SE_LimitHPPercent 408 // implemented - limited to a certain percent of your hp(ie heals up to 50%)
#define SE_LimitManaPercent 409 // implemented - limited to a certain percent of your mana #define SE_LimitManaPercent 409 // implemented - limited to a certain percent of your mana
#define SE_LimitEndPercent 410 // implemented - limited to a certain percent of your end #define SE_LimitEndPercent 410 // implemented - limited to a certain percent of your end
@ -576,7 +576,7 @@ typedef enum {
#define SE_FcLimitUse 420 // implemented - increases numhits count by percent (Note: not used in any known live spells) #define SE_FcLimitUse 420 // implemented - increases numhits count by percent (Note: not used in any known live spells)
#define SE_FcIncreaseNumHits 421 // implemented[AA] - increases number of hits a buff has till fade. (focus) #define SE_FcIncreaseNumHits 421 // implemented[AA] - increases number of hits a buff has till fade. (focus)
#define SE_LimitUseMin 422 // implemented - limit a focus to require a min amount of numhits value (used with above) #define SE_LimitUseMin 422 // implemented - limit a focus to require a min amount of numhits value (used with above)
#define SE_LimitUseType 423 // implemented - limit a focus to require a certain numhits type #define SE_LimitUseType 423 // implemented - limit a focus to require a certain numhits type
#define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace #define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace
//#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626) //#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626)
//#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window //#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window
@ -600,9 +600,9 @@ typedef enum {
#define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y #define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y
//#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. //#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs.
#define SE_AStacker 446 // implementet - bufff stacking blocker (26219 | Qirik's Watch) #define SE_AStacker 446 // implementet - bufff stacking blocker (26219 | Qirik's Watch)
#define SE_BStacker 447 // implemented #define SE_BStacker 447 // implemented
#define SE_CStacker 448 // implemented #define SE_CStacker 448 // implemented
#define SE_DStacker 449 // implemented #define SE_DStacker 449 // implemented
#define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value #define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value
#define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage #define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage
#define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage #define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage
@ -618,6 +618,7 @@ typedef enum {
#define DF_Permanent 50 #define DF_Permanent 50
#define DF_Aura 51
// note this struct is historical, we don't actually need it to be // note this struct is historical, we don't actually need it to be
// aligned to anything, but for maintaining it it is kept in the order that // aligned to anything, but for maintaining it it is kept in the order that
@ -733,31 +734,31 @@ struct SPDat_Spell_Struct
/* 197 */ bool not_extendable; /* 197 */ bool not_extendable;
/* 198- 199 */ /* 198- 199 */
/* 200 */ bool suspendable; // buff is suspended in suspended buff zones /* 200 */ bool suspendable; // buff is suspended in suspended buff zones
/* 201 */ int viral_range; /* 201 */ int viral_range;
/* 202 */ /* 202 */
/* 203 */ //int songcap; // individual song cap (how live currently does it, not implemented) /* 203 */ //int songcap; // individual song cap (how live currently does it, not implemented)
/* 204 */ /* 204 */
/* 205 */ bool no_block; /* 205 */ bool no_block;
/* 206 */ /* 206 */
/* 207 */ int spellgroup; /* 207 */ int spellgroup;
/* 208 */ int rank; //increments AA effects with same name /* 208 */ int rank; //increments AA effects with same name
/* 209 */ int powerful_flag; // Need more investigation to figure out what to call this, for now we know -1 makes charm spells not break before their duration is complete, it does alot more though /* 209 */ int powerful_flag; // Need more investigation to figure out what to call this, for now we know -1 makes charm spells not break before their duration is complete, it does alot more though
/* 210 */ // bool DurationFrozen; ??? /* 210 */ // bool DurationFrozen; ???
/* 211 */ int CastRestriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat /* 211 */ int CastRestriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat
/* 212 */ bool AllowRest; /* 212 */ bool AllowRest;
/* 213 */ bool InCombat; //Allow spell if target is in combat /* 213 */ bool InCombat; //Allow spell if target is in combat
/* 214 */ bool OutofCombat; //Allow spell if target is out of combat /* 214 */ bool OutofCombat; //Allow spell if target is out of combat
/* 215 - 217 */ /* 215 - 217 */
/* 218 */ int aemaxtargets; //Is used for various AE effects /* 218 */ int aemaxtargets; //Is used for various AE effects
/* 219 */ int maxtargets; //Is used for beam and ring spells for target # limits (not implemented) /* 219 */ int maxtargets; //Is used for beam and ring spells for target # limits (not implemented)
/* 220 - 223 */ /* 220 - 223 */
/* 224 */ bool persistdeath; // buff doesn't get stripped on death /* 224 */ bool persistdeath; // buff doesn't get stripped on death
/* 225 - 226 */ /* 225 - 226 */
/* 227 */ float min_dist; //spell power modified by distance from caster (Min Distance) /* 227 */ float min_dist; //spell power modified by distance from caster (Min Distance)
/* 228 */ float min_dist_mod; //spell power modified by distance from caster (Modifier at Min Distance) /* 228 */ float min_dist_mod; //spell power modified by distance from caster (Modifier at Min Distance)
/* 229 */ float max_dist; //spell power modified by distance from caster (Max Distance) /* 229 */ float max_dist; //spell power modified by distance from caster (Max Distance)
/* 230 */ float max_dist_mod; //spell power modified by distance from caster (Modifier at Max Distance) /* 230 */ float max_dist_mod; //spell power modified by distance from caster (Modifier at Max Distance)
/* 231 */ float min_range; //Min casting range /* 231 */ float min_range; //Min casting range
/* 232 - 236 */ /* 232 - 236 */
uint8 DamageShieldType; // This field does not exist in spells_us.txt uint8 DamageShieldType; // This field does not exist in spells_us.txt
}; };

View File

@ -83,4 +83,20 @@ typedef const char Const_char; //for perl XS
#define DLLFUNC extern "C" #define DLLFUNC extern "C"
#endif #endif
// htonll and ntohll already defined on windows
#ifndef WIN32
# if defined(__linux__)
# include <endian.h>
# elif defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/endian.h>
# elif defined (__OpenBSD__)
# include <sys/types.h>
# define be16toh(x) betoh16(x)
# define be32toh(x) betoh32(x)
# define be64toh(x) betoh64(x)
# endif
# define htonll(x) htobe64(x)
# define ntohll(x) be64toh(x)
#endif
#endif #endif

View File

@ -24,13 +24,13 @@
#define CURRENT_VERSION "1.1.3" #define CURRENT_VERSION "1.1.3"
/* /*
Everytime a Database SQL is added to Github, Everytime a Database SQL is added to Github,
increment CURRENT_BINARY_DATABASE_VERSION number and make sure you update the manifest increment CURRENT_BINARY_DATABASE_VERSION number and make sure you update the manifest
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/ */
#define CURRENT_BINARY_DATABASE_VERSION 9077 #define CURRENT_BINARY_DATABASE_VERSION 9083
#define COMPILE_DATE __DATE__ #define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__ #define COMPILE_TIME __TIME__
#ifndef WIN32 #ifndef WIN32

View File

@ -113,8 +113,8 @@ bool DatabaseMySQL::GetWorldRegistration(string long_name, string short_name, un
length = mysql_real_escape_string(db, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length()); length = mysql_real_escape_string(db, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length());
escaped_short_name[length+1] = 0; escaped_short_name[length+1] = 0;
stringstream query(stringstream::in | stringstream::out); stringstream query(stringstream::in | stringstream::out);
query << "SELECT WSR.ServerID, WSR.ServerTagDescription, WSR.ServerTrusted, SLT.ServerListTypeID, "; query << "SELECT ifnull(WSR.ServerID,999999) AS ServerID, WSR.ServerTagDescription, ifnull(WSR.ServerTrusted,0) AS ServerTrusted, ifnull(SLT.ServerListTypeID,3) AS ServerListTypeID, ";
query << "SLT.ServerListTypeDescription, WSR.ServerAdminID FROM " << server.options.GetWorldRegistrationTable(); query << "SLT.ServerListTypeDescription, ifnull(WSR.ServerAdminID,0) AS ServerAdminID FROM " << server.options.GetWorldRegistrationTable();
query << " AS WSR JOIN " << server.options.GetWorldServerTypeTable() << " AS SLT ON WSR.ServerListTypeID = SLT.ServerListTypeID"; query << " AS WSR JOIN " << server.options.GetWorldServerTypeTable() << " AS SLT ON WSR.ServerListTypeID = SLT.ServerListTypeID";
query << " WHERE WSR.ServerShortName = '"; query << " WHERE WSR.ServerShortName = '";
query << escaped_short_name; query << escaped_short_name;
@ -254,7 +254,7 @@ bool DatabaseMySQL::CreateWorldRegistration(string long_name, string short_name,
length = mysql_real_escape_string(db, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length()); length = mysql_real_escape_string(db, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length());
escaped_short_name[length+1] = 0; escaped_short_name[length+1] = 0;
stringstream query(stringstream::in | stringstream::out); stringstream query(stringstream::in | stringstream::out);
query << "SELECT max(ServerID) FROM " << server.options.GetWorldRegistrationTable(); query << "SELECT ifnull(max(ServerID),0) FROM " << server.options.GetWorldRegistrationTable();
if(mysql_query(db, query.str().c_str()) != 0) if(mysql_query(db, query.str().c_str()) != 0)
{ {

View File

@ -194,6 +194,7 @@ OP_Consent=0x400e
OP_ConsentDeny=0x34c1 OP_ConsentDeny=0x34c1
OP_AutoFire=0x314e OP_AutoFire=0x314e
OP_PetCommands=0x0093 OP_PetCommands=0x0093
OP_PetHoTT=0x0df4
OP_DeleteSpell=0x305c OP_DeleteSpell=0x305c
OP_Surname=0x1a87 OP_Surname=0x1a87
OP_ClearSurname=0x17b6 OP_ClearSurname=0x17b6
@ -269,8 +270,8 @@ OP_RequestDuel=0x1ea9
OP_MobRename=0x5040 OP_MobRename=0x5040
OP_AugmentItem=0x1627 # Was 0x37cb OP_AugmentItem=0x1627 # Was 0x37cb
OP_WeaponEquip1=0x35c3 OP_WeaponEquip1=0x35c3
OP_WeaponEquip2=0x012f # Was 0x6022 OP_PlayerStateAdd=0x012f # Was 0x6022
OP_WeaponUnequip2=0x1076 # Was 0x0110 OP_PlayerStateRemove=0x1076 # Was 0x0110
OP_ApplyPoison=0x1499 OP_ApplyPoison=0x1499
OP_Save=0x2e6f OP_Save=0x2e6f
OP_TestBuff=0x046e # Was 0x3772 OP_TestBuff=0x046e # Was 0x3772

View File

@ -193,6 +193,7 @@ OP_Consent=0x1fd1
OP_ConsentDeny=0x7a45 OP_ConsentDeny=0x7a45
OP_AutoFire=0x241e OP_AutoFire=0x241e
OP_PetCommands=0x0159 OP_PetCommands=0x0159
OP_PetHoTT=0x794a
OP_DeleteSpell=0x3358 OP_DeleteSpell=0x3358
OP_Surname=0x0423 OP_Surname=0x0423
OP_ClearSurname=0x3fb0 OP_ClearSurname=0x3fb0
@ -268,8 +269,8 @@ OP_RequestDuel=0x3af1
OP_MobRename=0x2c57 OP_MobRename=0x2c57
OP_AugmentItem=0x661b OP_AugmentItem=0x661b
OP_WeaponEquip1=0x34a7 OP_WeaponEquip1=0x34a7
OP_WeaponEquip2=0x559a OP_PlayerStateAdd=0x559a
OP_WeaponUnequip2=0x2d25 OP_PlayerStateRemove=0x2d25
OP_ApplyPoison=0x31e6 OP_ApplyPoison=0x31e6
OP_Save=0x4a39 OP_Save=0x4a39
OP_TestBuff=0x7cb8 OP_TestBuff=0x7cb8
@ -294,8 +295,8 @@ OP_MarkNPC=0x1fb5
OP_MarkRaidNPC=0x5a58 #unimplemented OP_MarkRaidNPC=0x5a58 #unimplemented
OP_ClearNPCMarks=0x2003 OP_ClearNPCMarks=0x2003
OP_ClearRaidNPCMarks=0x20d3 #unimplemented OP_ClearRaidNPCMarks=0x20d3 #unimplemented
OP_DelegateAbility=0x4c9d OP_DelegateAbility=0x76b8
OP_SetGroupTarget=0x026 OP_SetGroupTarget=0x2814
OP_Charm=0x5d92 OP_Charm=0x5d92
OP_Stun=0x36a4 OP_Stun=0x36a4
OP_SendFindableNPCs=0x4613 OP_SendFindableNPCs=0x4613

View File

@ -266,8 +266,8 @@ OP_RequestDuel=0x79e0 # C
OP_MobRename=0x0a1d # C OP_MobRename=0x0a1d # C
OP_AugmentItem=0x0370 # C OP_AugmentItem=0x0370 # C
OP_WeaponEquip1=0x719e # C OP_WeaponEquip1=0x719e # C
OP_WeaponEquip2=0x7b6e # C OP_PlayerStateAdd=0x7b6e # C
OP_WeaponUnequip2=0x19a8 # C OP_PlayerStateRemove=0x19a8 # C
OP_ApplyPoison=0x405b # C OP_ApplyPoison=0x405b # C
OP_Save=0x5c85 # C OP_Save=0x5c85 # C
OP_TestBuff=0x5fc7 # C OP_TestBuff=0x5fc7 # C

View File

@ -262,8 +262,8 @@ OP_RequestDuel=0x3A2B #Xinu 02/22/09
OP_MobRename=0x6be5 #Trevius 01/16/09 OP_MobRename=0x6be5 #Trevius 01/16/09
OP_AugmentItem=0x172A #Trevius 03/14/09 OP_AugmentItem=0x172A #Trevius 03/14/09
OP_WeaponEquip1=0x7260 #Trevius 02/27/09 OP_WeaponEquip1=0x7260 #Trevius 02/27/09
OP_WeaponEquip2=0x5C2F #Trevius 02/27/09 OP_PlayerStateAdd=0x5C2F #Trevius 02/27/09
OP_WeaponUnequip2=0x6213 #Trevius 02/27/09 OP_PlayerStateRemove=0x6213 #Trevius 02/27/09
OP_ApplyPoison=0x4543 #WildcardX 03/6/09 OP_ApplyPoison=0x4543 #WildcardX 03/6/09
OP_Save=0x72F2 #Trevius 03/15/09 OP_Save=0x72F2 #Trevius 03/15/09
OP_TestBuff=0x07BF #/testbuff OP_TestBuff=0x07BF #/testbuff

View File

@ -534,8 +534,8 @@ OP_PVPLeaderBoardDetailsRequest=0x06a2
OP_PVPLeaderBoardDetailsReply=0x246a OP_PVPLeaderBoardDetailsReply=0x246a
OP_PickLockSuccess=0x40E7 OP_PickLockSuccess=0x40E7
OP_WeaponEquip1=0x6c5e OP_WeaponEquip1=0x6c5e
OP_WeaponEquip2=0x63da OP_PlayerStateAdd=0x63da
OP_WeaponUnequip2=0x381d OP_PlayerStateRemove=0x381d
OP_VoiceMacroIn=0x2866 # Client to Server OP_VoiceMacroIn=0x2866 # Client to Server
OP_VoiceMacroOut=0x2ec6 # Server to Client OP_VoiceMacroOut=0x2ec6 # Server to Client
OP_CameraEffect=0x0937 # Correct OP_CameraEffect=0x0937 # Correct

View File

@ -197,6 +197,7 @@ OP_Consent=0x6bb9 # C
OP_ConsentDeny=0x4cd1 # C OP_ConsentDeny=0x4cd1 # C
OP_AutoFire=0x5db5 # C OP_AutoFire=0x5db5 # C
OP_PetCommands=0x7706 # C OP_PetCommands=0x7706 # C
OP_PetHoTT=0x2528
OP_DeleteSpell=0x0698 # C OP_DeleteSpell=0x0698 # C
OP_Surname=0x44ae # C OP_Surname=0x44ae # C
OP_ClearSurname=0x6705 # C OP_ClearSurname=0x6705 # C
@ -272,8 +273,8 @@ OP_RequestDuel=0x6cfe # C
OP_MobRename=0x0507 # C OP_MobRename=0x0507 # C
OP_AugmentItem=0x7c87 # C OP_AugmentItem=0x7c87 # C
OP_WeaponEquip1=0x4572 # C OP_WeaponEquip1=0x4572 # C
OP_WeaponEquip2=0x399b # C OP_PlayerStateAdd=0x399b # C
OP_WeaponUnequip2=0x416b # C OP_PlayerStateRemove=0x416b # C
OP_ApplyPoison=0x5cd3 # C OP_ApplyPoison=0x5cd3 # C
OP_Save=0x6618 # C OP_Save=0x6618 # C
OP_TestBuff=0x3415 # C OP_TestBuff=0x3415 # C

View File

@ -331,9 +331,15 @@
9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty| 9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty|
9076|2015_02_04_average_coin.sql|SHOW COLUMNS FROM `loottable` WHERE Field = 'avgcoin'|contains|smallint 9076|2015_02_04_average_coin.sql|SHOW COLUMNS FROM `loottable` WHERE Field = 'avgcoin'|contains|smallint
9077|2015_02_12_zone_gravity.sql|SHOW COLUMNS FROM `zone` LIKE 'gravity'|empty| 9077|2015_02_12_zone_gravity.sql|SHOW COLUMNS FROM `zone` LIKE 'gravity'|empty|
9078|2015_05_20_BuffInstrumentMod.sql|SHOW COLUMNS FROM `character_buffs` LIKE 'instrument_mod'|empty|
9079|2015_05_23_BuffDurations.sql|SHOW COLUMNS FROM `character_buffs` LIKE 'ticsremaining'|contains|unsigned|
9080|2015_05_23_PetBuffInstrumentMod.sql|SHOW COLUMNS FROM `character_pet_buffs` LIKE 'instrument_mod'|empty|
9081|2015_05_23_dbstr_us.sql|SHOW TABLES LIKE 'db_str'|empty|
9082|2015_05_25_npc_types_texture_fields.sql|SHOW COLUMNS FROM `npc_types` LIKE 'armtexture'|empty|
9083|2015_06_07_aa_update.sql|SHOW COLUMNS FROM `character_alternate_abilities` LIKE 'charges'|empty|
# Upgrade conditions: # Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not # This won't be needed after this system is implemented, but it is used database that are not
# yet using the versioning system to figure out where the database is schema wise to determine # yet using the versioning system to figure out where the database is schema wise to determine
# which updates are necessary to run # which updates are necessary to run
# #

View File

@ -1,3 +1,3 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentRestriction', 'false', 'Forces augment slot restrictions.'); INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentRestriction', 'false', 'Forces augment slot restrictions.');
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentUsability', 'false', 'Forces augmented item usability.'); INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentUsability', 'false', 'Forces augmented item usability.');
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentWear', 'false', 'Forces augment wear slot validation.'); INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentWear', 'false', 'Forces augment wear slot validation.');

View File

@ -0,0 +1,2 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:MeleePush', 'true', 'Turns on Melee Push.');
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:MeleePushChance', '50', 'Chance that an NPC can be pushed from melee.');

View File

@ -0,0 +1 @@
UPDATE rule_values SET rule_value=100 WHERE rule_name='Watermap:FishingLineLength';

View File

@ -0,0 +1 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:AlwaysSendTargetBuffs', 'false', 'Allows the server to send the targets buffs ignoring the LAA.');

View File

@ -0,0 +1 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:TransformSummonedBags', 'true', 'Transforms summoned bags into disenchanted ones instead of deleting.');

View File

@ -0,0 +1 @@
ALTER TABLE `character_buffs` ADD COLUMN `instrument_mod` int(10) DEFAULT 10 NOT NULL;

View File

@ -0,0 +1,2 @@
ALTER TABLE `character_buffs` CHANGE COLUMN `ticsremaining` `ticsremaining` INT(11) SIGNED NOT NULL;
ALTER TABLE `merc_buffs` CHANGE COLUMN `TicsRemaining` `TicsRemaining` INT(11) SIGNED NOT NULL DEFAULT 0;

View File

@ -0,0 +1 @@
ALTER TABLE `character_pet_buffs` ADD COLUMN `instrument_mod` tinyint UNSIGNED DEFAULT 10 NOT NULL;

View File

@ -0,0 +1,6 @@
CREATE TABLE `db_str` (
`id` INT(10) NOT NULL,
`type` INT(10) NOT NULL,
`value` TEXT NOT NULL,
PRIMARY KEY (`id`, `type`)
);

View File

@ -0,0 +1,6 @@
ALTER TABLE npc_types
ADD COLUMN `armtexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `raid_target`,
ADD COLUMN `bracertexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `armtexture`,
ADD COLUMN `handtexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `bracertexture`,
ADD COLUMN `legtexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `handtexture`,
ADD COLUMN `feettexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `legtexture`;

View File

@ -0,0 +1 @@
ALTER TABLE character_alternate_abilities ADD COLUMN charges SMALLINT(11) UNSIGNED NOT NULL DEFAULT 0;

View File

@ -105,6 +105,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou
memset(&pp, 0, sizeof(PlayerProfile_Struct)); memset(&pp, 0, sizeof(PlayerProfile_Struct));
/* Fill CharacterSelectEntry_Struct */ /* Fill CharacterSelectEntry_Struct */
memset(cse->Name, 0, sizeof(cse->Name));
strcpy(cse->Name, row[1]); strcpy(cse->Name, row[1]);
cse->Class = (uint8)atoi(row[4]); cse->Class = (uint8)atoi(row[4]);
cse->Race = (uint32)atoi(row[3]); cse->Race = (uint32)atoi(row[3]);

View File

@ -190,7 +190,7 @@ bool ZoneServer::Process() {
Log.Out(Logs::Detail, Logs::World_Server,"Zone authorization failed."); Log.Out(Logs::Detail, Logs::World_Server,"Zone authorization failed.");
auto pack = new ServerPacket(ServerOP_ZAAuthFailed); auto pack = new ServerPacket(ServerOP_ZAAuthFailed);
SendPacket(pack); SendPacket(pack);
delete pack; safe_delete(pack);
Disconnect(); Disconnect();
return false; return false;
} }
@ -201,7 +201,7 @@ bool ZoneServer::Process() {
Log.Out(Logs::Detail, Logs::World_Server,"Zone authorization failed."); Log.Out(Logs::Detail, Logs::World_Server,"Zone authorization failed.");
auto pack = new ServerPacket(ServerOP_ZAAuthFailed); auto pack = new ServerPacket(ServerOP_ZAAuthFailed);
SendPacket(pack); SendPacket(pack);
delete pack; safe_delete(pack);
Disconnect(); Disconnect();
return false; return false;
} }
@ -779,7 +779,7 @@ bool ZoneServer::Process() {
whom->wrace = whoall->wrace; whom->wrace = whoall->wrace;
strcpy(whom->whom,whoall->whom); strcpy(whom->whom,whoall->whom);
client_list.SendWhoAll(whoall->fromid,whoall->from, whoall->admin, whom, this); client_list.SendWhoAll(whoall->fromid,whoall->from, whoall->admin, whom, this);
delete whom; safe_delete(whom);
break; break;
} }
case ServerOP_RequestOnlineGuildMembers: { case ServerOP_RequestOnlineGuildMembers: {
@ -958,13 +958,13 @@ bool ZoneServer::Process() {
tod->start_eqtime=zoneserver_list.worldclock.getStartEQTime(); tod->start_eqtime=zoneserver_list.worldclock.getStartEQTime();
tod->start_realtime=zoneserver_list.worldclock.getStartRealTime(); tod->start_realtime=zoneserver_list.worldclock.getStartRealTime();
SendPacket(pack); SendPacket(pack);
delete pack; safe_delete(pack);
break; break;
} }
case ServerOP_SetWorldTime: { case ServerOP_SetWorldTime: {
Log.Out(Logs::Detail, Logs::World_Server,"Received SetWorldTime"); Log.Out(Logs::Detail, Logs::World_Server,"Received SetWorldTime");
eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer; eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer;
zoneserver_list.worldclock.setEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime); zoneserver_list.worldclock.SetCurrentEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime);
Log.Out(Logs::Detail, Logs::World_Server,"New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime); Log.Out(Logs::Detail, Logs::World_Server,"New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime);
zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str()); zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str());
zoneserver_list.SendTimeSync(); zoneserver_list.SendTimeSync();
@ -1059,8 +1059,7 @@ bool ZoneServer::Process() {
} }
else else
{ {
delete pack; auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
strcpy(scs->grantname, s->grantname); strcpy(scs->grantname, s->grantname);
strcpy(scs->ownername, s->ownername); strcpy(scs->ownername, s->ownername);
@ -1076,6 +1075,7 @@ bool ZoneServer::Process() {
else { else {
Log.Out(Logs::Detail, Logs::World_Server, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent_Response operation.", s->instance_id); Log.Out(Logs::Detail, Logs::World_Server, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent_Response operation.", s->instance_id);
} }
safe_delete(pack);
} }
} }
else else
@ -1091,8 +1091,7 @@ bool ZoneServer::Process() {
} }
else { else {
// send target not found back to requester // send target not found back to requester
delete pack; auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
strcpy(scs->grantname, s->grantname); strcpy(scs->grantname, s->grantname);
strcpy(scs->ownername, s->ownername); strcpy(scs->ownername, s->ownername);
@ -1107,13 +1106,13 @@ bool ZoneServer::Process() {
else { else {
Log.Out(Logs::Detail, Logs::World_Server, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id); Log.Out(Logs::Detail, Logs::World_Server, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
} }
safe_delete(pack);
} }
} }
} }
else { else {
// send target not found back to requester // send target not found back to requester
delete pack; auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
strcpy(scs->grantname, s->grantname); strcpy(scs->grantname, s->grantname);
strcpy(scs->ownername, s->ownername); strcpy(scs->ownername, s->ownername);
@ -1128,6 +1127,7 @@ bool ZoneServer::Process() {
else { else {
Log.Out(Logs::Detail, Logs::World_Server, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id); Log.Out(Logs::Detail, Logs::World_Server, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
} }
safe_delete(pack);
} }
break; break;
} }
@ -1313,15 +1313,17 @@ bool ZoneServer::Process() {
} }
default: default:
{ {
Log.Out(Logs::Detail, Logs::World_Server,"Unknown ServerOPcode from zone 0x%04x, size %d",pack->opcode,pack->size); Log.Out(Logs::Detail, Logs::World_Server, "Unknown ServerOPcode from zone 0x%04x, size %d", pack->opcode, pack->size);
DumpPacket(pack->pBuffer, pack->size); DumpPacket(pack->pBuffer, pack->size);
break; break;
} }
} }
if (pack) if (pack) {
delete pack; safe_delete(pack);
else }
Log.Out(Logs::Detail, Logs::World_Server, "Zoneserver process tried to delete pack when pack does not exist."); else {
Log.Out(Logs::Detail, Logs::World_Server, "Zoneserver process attempted to delete pack when pack does not exist.");
}
} }
return true; return true;
} }

View File

@ -20,6 +20,7 @@ SET(zone_sources
embparser_api.cpp embparser_api.cpp
embperl.cpp embperl.cpp
embxs.cpp embxs.cpp
encounter.cpp
entity.cpp entity.cpp
exp.cpp exp.cpp
fearpath.cpp fearpath.cpp
@ -35,6 +36,7 @@ SET(zone_sources
lua_corpse.cpp lua_corpse.cpp
lua_client.cpp lua_client.cpp
lua_door.cpp lua_door.cpp
lua_encounter.cpp
lua_entity.cpp lua_entity.cpp
lua_entity_list.cpp lua_entity_list.cpp
lua_general.cpp lua_general.cpp
@ -137,6 +139,7 @@ SET(zone_headers
embparser.h embparser.h
embperl.h embperl.h
embxs.h embxs.h
encounter.h
entity.h entity.h
errmsg.h errmsg.h
event_codes.h event_codes.h
@ -148,6 +151,7 @@ SET(zone_headers
lua_bit.h lua_bit.h
lua_client.h lua_client.h
lua_corpse.h lua_corpse.h
lua_encounter.h
lua_entity.h lua_entity.h
lua_entity_list.h lua_entity_list.h
lua_general.h lua_general.h

View File

@ -1104,9 +1104,9 @@ void Client::SendAATable() {
uint32 i; uint32 i;
for(i=0;i < MAX_PP_AA_ARRAY;i++){ for(i=0;i < MAX_PP_AA_ARRAY;i++){
aa2->aa_list[i].aa_skill = aa[i]->AA; aa2->aa_list[i].AA = aa[i]->value ? aa[i]->AA : 0; // bit of a hack to prevent expendables punching a hole
aa2->aa_list[i].aa_value = aa[i]->value; aa2->aa_list[i].value = aa[i]->value;
aa2->aa_list[i].unknown08 = 0; aa2->aa_list[i].charges = aa[i]->charges;
} }
QueuePacket(outapp); QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
@ -1309,11 +1309,9 @@ void Client::SendAA(uint32 id, int seq) {
SendAA_Struct* saa_next = nullptr; SendAA_Struct* saa_next = nullptr;
saa_next = zone->FindAA(saa->sof_next_id); saa_next = zone->FindAA(saa->sof_next_id);
// hard-coding values like this is dangerous and makes adding/updating clients a nightmare... // this check should work as long as we continue to just add the clients and just increase
if (saa_next && // each number ....
(((GetClientVersionBit() == 4) && (saa_next->clientver > 4)) if (saa_next && static_cast<int>(GetClientVersion()) < saa_next->clientver - 1) {
|| ((GetClientVersionBit() == 8) && (saa_next->clientver > 5))
|| ((GetClientVersionBit() == 16) && (saa_next->clientver > 6)))){
saa->next_id=0xFFFFFFFF; saa->next_id=0xFFFFFFFF;
} }
} }
@ -1397,26 +1395,33 @@ uint32 Client::GetAA(uint32 aa_id) const {
bool Client::SetAA(uint32 aa_id, uint32 new_value) { bool Client::SetAA(uint32 aa_id, uint32 new_value) {
aa_points[aa_id] = new_value; aa_points[aa_id] = new_value;
uint32 cur; uint32 cur;
auto sendaa = zone->FindAA(aa_id); // this is a bit hacky
uint32 charges = sendaa->special_category == 7 && new_value ? 1 : 0;
for(cur=0;cur < MAX_PP_AA_ARRAY;cur++){ for(cur=0;cur < MAX_PP_AA_ARRAY;cur++){
if((aa[cur]->value > 1) && ((aa[cur]->AA - aa[cur]->value + 1)== aa_id)){ if((aa[cur]->value > 1) && ((aa[cur]->AA - aa[cur]->value + 1)== aa_id)){
aa[cur]->value = new_value; aa[cur]->value = new_value;
if(new_value > 0) if(new_value > 0)
aa[cur]->AA++; aa[cur]->AA++;
else aa[cur]->charges = charges;
aa[cur]->AA = 0;
return true; return true;
} }
else if((aa[cur]->value == 1) && (aa[cur]->AA == aa_id)){ else if((aa[cur]->value == 1) && (aa[cur]->AA == aa_id)){
aa[cur]->value = new_value; aa[cur]->value = new_value;
if(new_value > 0) if(new_value > 0)
aa[cur]->AA++; aa[cur]->AA++;
else aa[cur]->charges = charges;
aa[cur]->AA = 0; return true;
}
// hack to prevent expendable exploit, we should probably be reshuffling the array to fix the hole
else if(aa[cur]->value == 0 && new_value == 1 && aa[cur]->AA == aa_id) {
aa[cur]->value = new_value;
aa[cur]->charges = charges;
return true; return true;
} }
else if(aa[cur]->AA==0){ //end of list else if(aa[cur]->AA==0){ //end of list
aa[cur]->AA = aa_id; aa[cur]->AA = aa_id;
aa[cur]->value = new_value; aa[cur]->value = new_value;
aa[cur]->charges = charges;
return true; return true;
} }
} }
@ -1487,8 +1492,10 @@ void Client::ResetAA(){
for (i=0; i < MAX_PP_AA_ARRAY; i++) { for (i=0; i < MAX_PP_AA_ARRAY; i++) {
aa[i]->AA = 0; aa[i]->AA = 0;
aa[i]->value = 0; aa[i]->value = 0;
m_pp.aa_array[MAX_PP_AA_ARRAY].AA = 0; aa[i]->charges = 0;
m_pp.aa_array[MAX_PP_AA_ARRAY].value = 0; m_pp.aa_array[i].AA = 0;
m_pp.aa_array[i].value = 0;
m_pp.aa_array[i].charges= 0;
} }
std::map<uint32,uint8>::iterator itr; std::map<uint32,uint8>::iterator itr;

View File

@ -982,14 +982,24 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
return 0; return 0;
} }
else{ else{
if((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30){ bool MagicGloves=false;
dmg = GetMonkHandToHandDamage(); if (IsClient()) {
if (hate) *hate += dmg; ItemInst *gloves=CastToClient()->GetInv().GetItem(MainHands);
if (gloves != nullptr) {
MagicGloves = gloves->GetItem()->Magic;
}
}
if((GetClass() == MONK || GetClass() == BEASTLORD)) {
if(MagicGloves || GetLevel() >= 30){
dmg = GetMonkHandToHandDamage();
if (hate) *hate += dmg;
}
} }
else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){ //pets wouldn't actually use this but... else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){ //pets wouldn't actually use this but...
dmg = 1; //it gives us an idea if we can hit dmg = 1; //it gives us an idea if we can hit
} }
else if(GetSpecialAbility(SPECATK_MAGICAL)){ else if(MagicGloves || GetSpecialAbility(SPECATK_MAGICAL)){
dmg = 1; dmg = 1;
} }
else else
@ -2134,6 +2144,10 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
if(give_exp && give_exp->IsClient()) if(give_exp && give_exp->IsClient())
give_exp_client = give_exp->CastToClient(); give_exp_client = give_exp->CastToClient();
//do faction hits even if we are a merchant, so long as a player killed us
if (give_exp_client && !RuleB(NPC, EnableMeritBasedFaction))
hate_list.DoFactionHits(GetNPCFactionID());
bool IsLdonTreasure = (this->GetClass() == LDON_TREASURE); bool IsLdonTreasure = (this->GetClass() == LDON_TREASURE);
if (give_exp_client && !IsCorpse()) if (give_exp_client && !IsCorpse())
{ {
@ -2277,10 +2291,6 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
} }
} }
//do faction hits even if we are a merchant, so long as a player killed us
if(give_exp_client && !RuleB(NPC, EnableMeritBasedFaction))
hate_list.DoFactionHits(GetNPCFactionID());
if (!HasOwner() && !IsMerc() && class_ != MERCHANT && class_ != ADVENTUREMERCHANT && !GetSwarmInfo() if (!HasOwner() && !IsMerc() && class_ != MERCHANT && class_ != ADVENTUREMERCHANT && !GetSwarmInfo()
&& MerchantType == 0 && killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) || && MerchantType == 0 && killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) ||
(killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient()))) (killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient())))
@ -3683,7 +3693,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
//send an HP update if we are hurt //send an HP update if we are hurt
if(GetHP() < GetMaxHP()) if(GetHP() < GetMaxHP())
SendHPUpdate(); SendHPUpdate(!iBuffTic); // the OP_Damage actually updates the client in these cases, so we skill them
} //end `if damage was done` } //end `if damage was done`
//send damage packet... //send damage packet...
@ -3700,6 +3710,23 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
a->type = SkillDamageTypes[skill_used]; // was 0x1c a->type = SkillDamageTypes[skill_used]; // was 0x1c
a->damage = damage; a->damage = damage;
a->spellid = spell_id; a->spellid = spell_id;
a->meleepush_xy = attacker->GetHeading() * 2.0f;
if (RuleB(Combat, MeleePush) && damage > 0 && !IsRooted() &&
(IsClient() || zone->random.Roll(RuleI(Combat, MeleePushChance)))) {
a->force = EQEmu::GetSkillMeleePushForce(skill_used);
// update NPC stuff
auto new_pos = glm::vec3(m_Position.x + (a->force * std::sin(a->meleepush_xy) + m_Delta.x),
m_Position.y + (a->force * std::cos(a->meleepush_xy) + m_Delta.y), m_Position.z);
if (zone->zonemap && zone->zonemap->CheckLoS(glm::vec3(m_Position), new_pos)) { // If we have LoS on the new loc it should be reachable.
if (IsNPC()) {
// Is this adequate?
Teleport(new_pos);
SendPosUpdate();
}
} else {
a->force = 0.0f; // we couldn't move there, so lets not
}
}
//Note: if players can become pets, they will not receive damage messages of their own //Note: if players can become pets, they will not receive damage messages of their own
//this was done to simplify the code here (since we can only effectively skip one mob on queue) //this was done to simplify the code here (since we can only effectively skip one mob on queue)
@ -3968,7 +3995,7 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) {
} }
// Innate + aug procs from weapons // Innate + aug procs from weapons
// TODO: powersource procs // TODO: powersource procs -- powersource procs are on invis augs, so shouldn't need anything extra
TryWeaponProc(weapon_g, weapon_g->GetItem(), on, hand); TryWeaponProc(weapon_g, weapon_g->GetItem(), on, hand);
// Procs from Buffs and AA both melee and range // Procs from Buffs and AA both melee and range
TrySpellProc(weapon_g, weapon_g->GetItem(), on, hand); TrySpellProc(weapon_g, weapon_g->GetItem(), on, hand);
@ -4054,7 +4081,7 @@ void Mob::TryWeaponProc(const ItemInst *inst, const ItemData *weapon, Mob *on, u
} }
} }
} }
// TODO: Powersource procs // TODO: Powersource procs -- powersource procs are from augs so shouldn't need anything extra
return; return;
} }
@ -4116,7 +4143,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const ItemData *weapon, Mob *on, ui
outapp->priority = 3; outapp->priority = 3;
entity_list.QueueCloseClients(this, outapp, false, 200, 0, true); entity_list.QueueCloseClients(this, outapp, false, 200, 0, true);
safe_delete(outapp); safe_delete(outapp);
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on); ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
SpellProcs[i].base_spellID); SpellProcs[i].base_spellID);
} else { } else {
@ -4222,7 +4249,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack
} }
#ifdef BOTS #ifdef BOTS
if (this->IsPet() && this->GetOwner()->IsBot()) { if (this->IsPet() && this->GetOwner() && this->GetOwner()->IsBot()) {
this->TryPetCriticalHit(defender,skill,damage); this->TryPetCriticalHit(defender,skill,damage);
return; return;
} }

View File

@ -428,7 +428,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
newbon->DSMitigation += item->DSMitigation; newbon->DSMitigation += item->DSMitigation;
} }
if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type); ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
} }
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
@ -559,7 +559,7 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool
/* /*
Powerful Non-live like option allows developers to add worn effects on items that Powerful Non-live like option allows developers to add worn effects on items that
can stack with other worn effects of the same spell effect type, instead of only taking the highest value. can stack with other worn effects of the same spell effect type, instead of only taking the highest value.
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus. Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus.
To enable use RuleI(Spells, AdditiveBonusWornType) To enable use RuleI(Spells, AdditiveBonusWornType)
Setting value = 2 Will force all live items to automatically be calculated additivily Setting value = 2 Will force all live items to automatically be calculated additivily
Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation
@ -579,7 +579,7 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool
if(GetLevel() < item->ReqLevel) if(GetLevel() < item->ReqLevel)
return; return;
if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType)) if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType))
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);// Non-live like - Addititive latent effects ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);// Non-live like - Addititive latent effects
@ -691,7 +691,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
continue; continue;
Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName()); Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName());
uint8 focus = IsFocusEffect(0, 0, true,effect); uint8 focus = IsFocusEffect(0, 0, true,effect);
if (focus) if (focus)
{ {
@ -1007,7 +1007,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
case SE_BlockBehind: case SE_BlockBehind:
newbon->BlockBehind += base1; newbon->BlockBehind += base1;
break; break;
case SE_StrikeThrough: case SE_StrikeThrough:
case SE_StrikeThrough2: case SE_StrikeThrough2:
newbon->StrikeThrough += base1; newbon->StrikeThrough += base1;
@ -1313,7 +1313,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
case SE_Vampirism: case SE_Vampirism:
newbon->Vampirism += base1; newbon->Vampirism += base1;
break; break;
case SE_FrenziedDevastation: case SE_FrenziedDevastation:
newbon->FrenziedDevastation += base2; newbon->FrenziedDevastation += base2;
@ -1416,7 +1416,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
} }
case SE_SkillProcSuccess:{ case SE_SkillProcSuccess:{
for(int e = 0; e < MAX_SKILL_PROCS; e++) for(int e = 0; e < MAX_SKILL_PROCS; e++)
{ {
if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid) if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid)
@ -1449,7 +1449,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
int buff_count = GetMaxTotalSlots(); int buff_count = GetMaxTotalSlots();
for(i = 0; i < buff_count; i++) { for(i = 0; i < buff_count; i++) {
if(buffs[i].spellid != SPELL_UNKNOWN){ if(buffs[i].spellid != SPELL_UNKNOWN){
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining,i); ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining, i, buffs[i].instrument_mod);
if (buffs[i].numhits > 0) if (buffs[i].numhits > 0)
Numhits(true); Numhits(true);
@ -1472,8 +1472,9 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells. if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
} }
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, uint8 WornType, uint32 ticsremaining, int buffslot, void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *new_bonus, uint16 casterId,
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max) uint8 WornType, int32 ticsremaining, int buffslot, int instrument_mod,
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
{ {
int i, effect_value, base2, max, effectid; int i, effect_value, base2, max, effectid;
bool AdditiveWornBonus = false; bool AdditiveWornBonus = false;
@ -1509,9 +1510,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType)) if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType))
AdditiveWornBonus = true; AdditiveWornBonus = true;
effectid = spells[spell_id].effectid[i]; effectid = spells[spell_id].effectid[i];
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining); effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, instrument_mod, caster, ticsremaining);
base2 = spells[spell_id].base2[i]; base2 = spells[spell_id].base2[i];
max = spells[spell_id].max[i]; max = spells[spell_id].max[i];
} }
@ -1620,10 +1621,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) { if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) {
effect_value -= ((effect_value * GetSlowMitigation()/100)); effect_value -= ((effect_value * GetSlowMitigation()/100));
if (effect_value > new_bonus->inhibitmelee) if (effect_value > new_bonus->inhibitmelee)
new_bonus->inhibitmelee = effect_value; new_bonus->inhibitmelee = effect_value;
} }
break; break;
} }
@ -1839,7 +1840,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
new_bonus->DamageShieldType = GetDamageShieldType(spell_id, max); new_bonus->DamageShieldType = GetDamageShieldType(spell_id, max);
else else
new_bonus->DamageShieldType = GetDamageShieldType(spell_id); new_bonus->DamageShieldType = GetDamageShieldType(spell_id);
break; break;
} }
@ -2020,7 +2021,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
case SE_Vampirism: case SE_Vampirism:
new_bonus->Vampirism += effect_value; new_bonus->Vampirism += effect_value;
break; break;
case SE_AllInstrumentMod: case SE_AllInstrumentMod:
{ {
@ -2263,7 +2264,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
case SE_CriticalSpellChance: case SE_CriticalSpellChance:
{ {
new_bonus->CriticalSpellChance += effect_value; new_bonus->CriticalSpellChance += effect_value;
if (base2 > new_bonus->SpellCritDmgIncNoStack) if (base2 > new_bonus->SpellCritDmgIncNoStack)
new_bonus->SpellCritDmgIncNoStack = base2; new_bonus->SpellCritDmgIncNoStack = base2;
break; break;
@ -2473,7 +2474,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
case SE_NegateAttacks: case SE_NegateAttacks:
{ {
if (!new_bonus->NegateAttacks[0] || if (!new_bonus->NegateAttacks[0] ||
((new_bonus->NegateAttacks[0] && new_bonus->NegateAttacks[2]) && (new_bonus->NegateAttacks[2] < max))){ ((new_bonus->NegateAttacks[0] && new_bonus->NegateAttacks[2]) && (new_bonus->NegateAttacks[2] < max))){
new_bonus->NegateAttacks[0] = 1; new_bonus->NegateAttacks[0] = 1;
new_bonus->NegateAttacks[1] = buffslot; new_bonus->NegateAttacks[1] = buffslot;
@ -2493,7 +2494,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
break; break;
} }
case SE_MeleeThresholdGuard: case SE_MeleeThresholdGuard:
{ {
if (new_bonus->MeleeThresholdGuard[0] < effect_value){ if (new_bonus->MeleeThresholdGuard[0] < effect_value){
@ -2860,17 +2861,17 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
new_bonus->NegateIfCombat = true; new_bonus->NegateIfCombat = true;
break; break;
case SE_Screech: case SE_Screech:
new_bonus->Screech = effect_value; new_bonus->Screech = effect_value;
break; break;
case SE_AlterNPCLevel: case SE_AlterNPCLevel:
if (IsNPC()){ if (IsNPC()){
if (!new_bonus->AlterNPCLevel if (!new_bonus->AlterNPCLevel
|| ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value)) || ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value))
|| ((effect_value > 0) && (new_bonus->AlterNPCLevel < effect_value))) { || ((effect_value > 0) && (new_bonus->AlterNPCLevel < effect_value))) {
int tmp_lv = GetOrigLevel() + effect_value; int tmp_lv = GetOrigLevel() + effect_value;
if (tmp_lv < 1) if (tmp_lv < 1)
tmp_lv = 1; tmp_lv = 1;
@ -2908,7 +2909,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
new_bonus->BerserkSPA = true; new_bonus->BerserkSPA = true;
break; break;
case SE_Metabolism: case SE_Metabolism:
new_bonus->Metabolism += effect_value; new_bonus->Metabolism += effect_value;
break; break;
@ -3009,7 +3010,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
} }
case SE_SkillProc:{ case SE_SkillProc:{
for(int e = 0; e < MAX_SKILL_PROCS; e++) for(int e = 0; e < MAX_SKILL_PROCS; e++)
{ {
if(new_bonus->SkillProc[e] && new_bonus->SkillProc[e] == spell_id) if(new_bonus->SkillProc[e] && new_bonus->SkillProc[e] == spell_id)
@ -3024,7 +3025,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
} }
case SE_SkillProcSuccess:{ case SE_SkillProcSuccess:{
for(int e = 0; e < MAX_SKILL_PROCS; e++) for(int e = 0; e < MAX_SKILL_PROCS; e++)
{ {
if(new_bonus->SkillProcSuccess[e] && new_bonus->SkillProcSuccess[e] == spell_id) if(new_bonus->SkillProcSuccess[e] && new_bonus->SkillProcSuccess[e] == spell_id)
@ -3040,9 +3041,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
if (IsAISpellEffect) { if (IsAISpellEffect) {
//Non-Focused Effect to modify incoming spell damage by resist type. //Non-Focused Effect to modify incoming spell damage by resist type.
case SE_FcSpellVulnerability: case SE_FcSpellVulnerability:
ModVulnerability(base2, effect_value); ModVulnerability(base2, effect_value);
break; break;
} }
@ -4394,7 +4395,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
aabonuses.SlayUndead[0] = effect_value; aabonuses.SlayUndead[0] = effect_value;
aabonuses.SlayUndead[1] = effect_value; aabonuses.SlayUndead[1] = effect_value;
break; break;
case SE_DoubleRangedAttack: case SE_DoubleRangedAttack:
spellbonuses.DoubleRangedAttack = effect_value; spellbonuses.DoubleRangedAttack = effect_value;
aabonuses.DoubleRangedAttack = effect_value; aabonuses.DoubleRangedAttack = effect_value;
@ -4414,7 +4415,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
aabonuses.ShieldEquipDmgMod[1] = effect_value; aabonuses.ShieldEquipDmgMod[1] = effect_value;
itembonuses.ShieldEquipDmgMod[0] = effect_value; itembonuses.ShieldEquipDmgMod[0] = effect_value;
itembonuses.ShieldEquipDmgMod[1] = effect_value; itembonuses.ShieldEquipDmgMod[1] = effect_value;
break; break;
case SE_TriggerMeleeThreshold: case SE_TriggerMeleeThreshold:
spellbonuses.TriggerMeleeThreshold = false; spellbonuses.TriggerMeleeThreshold = false;

File diff suppressed because it is too large Load Diff

View File

@ -60,6 +60,7 @@ enum SpellTypeIndex {
}; };
class Bot : public NPC { class Bot : public NPC {
friend class Mob;
public: public:
// Class enums // Class enums
enum BotfocusType { //focus types enum BotfocusType { //focus types
@ -154,7 +155,7 @@ public:
// Class Methods // Class Methods
bool IsValidRaceClassCombo(); bool IsValidRaceClassCombo();
bool IsValidName(); bool IsValidName();
bool IsBotNameAvailable(std::string* errorMessage); static bool IsBotNameAvailable(char *botName, std::string* errorMessage);
bool DeleteBot(std::string* errorMessage); bool DeleteBot(std::string* errorMessage);
void Spawn(Client* botCharacterOwner, std::string* errorMessage); void Spawn(Client* botCharacterOwner, std::string* errorMessage);
virtual void SetLevel(uint8 in_level, bool command = false); virtual void SetLevel(uint8 in_level, bool command = false);
@ -190,7 +191,9 @@ public:
bool CanDoSpecialAttack(Mob *other); bool CanDoSpecialAttack(Mob *other);
virtual int32 CheckAggroAmount(uint16 spellid); virtual int32 CheckAggroAmount(uint16 spellid);
virtual void CalcBonuses(); virtual void CalcBonuses();
void CalcItemBonuses(); void CalcItemBonuses(StatBonuses* newbon);
void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false);
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr); virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr);
virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther); virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther);
inline virtual bool IsPet() { return false; } inline virtual bool IsPet() { return false; }
@ -310,7 +313,7 @@ public:
virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration); virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration);
virtual float GetAOERange(uint16 spell_id); virtual float GetAOERange(uint16 spell_id);
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100); virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0); virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr); virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr);
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar); virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster); virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
@ -464,6 +467,7 @@ public:
uint32 GetHealRotationNextHealTime() { return _healRotationNextHeal; } uint32 GetHealRotationNextHealTime() { return _healRotationNextHeal; }
uint32 GetHealRotationTimer () { return _healRotationTimer; } uint32 GetHealRotationTimer () { return _healRotationTimer; }
bool GetBardUseOutOfCombatSongs() { return _bardUseOutOfCombatSongs;} bool GetBardUseOutOfCombatSongs() { return _bardUseOutOfCombatSongs;}
bool GetShowHelm() { return _showhelm; }
inline virtual int32 GetAC() const { return AC; } inline virtual int32 GetAC() const { return AC; }
inline virtual int32 GetSTR() const { return STR; } inline virtual int32 GetSTR() const { return STR; }
inline virtual int32 GetSTA() const { return STA; } inline virtual int32 GetSTA() const { return STA; }
@ -547,6 +551,7 @@ public:
void SetHealRotationTimer( uint32 timer ) { _healRotationTimer = timer; } void SetHealRotationTimer( uint32 timer ) { _healRotationTimer = timer; }
void SetNumHealRotationMembers( uint8 numMembers ) { _numHealRotationMembers = numMembers; } void SetNumHealRotationMembers( uint8 numMembers ) { _numHealRotationMembers = numMembers; }
void SetBardUseOutOfCombatSongs(bool useOutOfCombatSongs) { _bardUseOutOfCombatSongs = useOutOfCombatSongs;} void SetBardUseOutOfCombatSongs(bool useOutOfCombatSongs) { _bardUseOutOfCombatSongs = useOutOfCombatSongs;}
void SetShowHelm(bool showhelm) { _showhelm = showhelm; }
// Class Destructors // Class Destructors
virtual ~Bot(); virtual ~Bot();
@ -619,6 +624,7 @@ private:
std::map<uint32, BotAA> botAAs; std::map<uint32, BotAA> botAAs;
InspectMessage_Struct _botInspectMessage; InspectMessage_Struct _botInspectMessage;
bool _bardUseOutOfCombatSongs; bool _bardUseOutOfCombatSongs;
bool _showhelm;
// Private "base stats" Members // Private "base stats" Members
int32 _baseMR; int32 _baseMR;

View File

@ -116,7 +116,7 @@ Client::Client(EQStreamInterface* ieqs)
), ),
//these must be listed in the order they appear in client.h //these must be listed in the order they appear in client.h
position_timer(250), position_timer(250),
hpupdate_timer(1800), hpupdate_timer(2000),
camp_timer(29000), camp_timer(29000),
process_timer(100), process_timer(100),
stamina_timer(40000), stamina_timer(40000),
@ -208,6 +208,7 @@ Client::Client(EQStreamInterface* ieqs)
npclevel = 0; npclevel = 0;
pQueuedSaveWorkID = 0; pQueuedSaveWorkID = 0;
position_timer_counter = 0; position_timer_counter = 0;
position_update_same_count = 0;
fishing_timer.Disable(); fishing_timer.Disable();
shield_timer.Disable(); shield_timer.Disable();
dead_timer.Disable(); dead_timer.Disable();
@ -549,17 +550,22 @@ bool Client::SaveAA(){
} }
} }
m_pp.aapoints_spent = spentpoints + m_epp.expended_aa; m_pp.aapoints_spent = spentpoints + m_epp.expended_aa;
int highest = 0;
for (int a = 0; a < MAX_PP_AA_ARRAY; a++) { for (int a = 0; a < MAX_PP_AA_ARRAY; a++) {
if (aa[a]->AA > 0 && aa[a]->value){ if (aa[a]->AA > 0) { // those with value 0 will be cleaned up on next load
if (first_entry != 1){ if (first_entry != 1){
rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, slot, aa_id, aa_value)" rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, slot, aa_id, aa_value, charges)"
" VALUES (%u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value); " VALUES (%u, %u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value, aa[a]->charges);
first_entry = 1; first_entry = 1;
} else {
rquery = rquery + StringFormat(", (%u, %u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value, aa[a]->charges);
} }
rquery = rquery + StringFormat(", (%u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value); highest = a;
} }
} }
auto results = database.QueryDatabase(rquery); auto results = database.QueryDatabase(rquery);
/* This is another part of the hack to clean up holes left by expendable AAs */
rquery = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u AND `slot` > %d", character_id, highest);
return true; return true;
} }
@ -1051,12 +1057,12 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
if(quest_manager.ProximitySayInUse()) if(quest_manager.ProximitySayInUse())
entity_list.ProcessProximitySay(message, this, language); entity_list.ProcessProximitySay(message, this, language);
if (GetTarget() != 0 && GetTarget()->IsNPC()) { if (GetTarget() != 0 && GetTarget()->IsNPC() &&
!IsInvisible(GetTarget())) {
if(!GetTarget()->CastToNPC()->IsEngaged()) { if(!GetTarget()->CastToNPC()->IsEngaged()) {
CheckLDoNHail(GetTarget()); CheckLDoNHail(GetTarget());
CheckEmoteHail(GetTarget(), message); CheckEmoteHail(GetTarget(), message);
if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= 200) { if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= 200) {
NPC *tar = GetTarget()->CastToNPC(); NPC *tar = GetTarget()->CastToNPC();
parse->EventNPC(EVENT_SAY, tar->CastToNPC(), this, message, language); parse->EventNPC(EVENT_SAY, tar->CastToNPC(), this, message, language);
@ -2540,12 +2546,12 @@ void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32
bool Client::BindWound(Mob* bindmob, bool start, bool fail){ bool Client::BindWound(Mob* bindmob, bool start, bool fail){
EQApplicationPacket* outapp = 0; EQApplicationPacket* outapp = 0;
if(!fail) if(!fail)
{ {
outapp = new EQApplicationPacket(OP_Bind_Wound, sizeof(BindWound_Struct)); outapp = new EQApplicationPacket(OP_Bind_Wound, sizeof(BindWound_Struct));
BindWound_Struct* bind_out = (BindWound_Struct*) outapp->pBuffer; BindWound_Struct* bind_out = (BindWound_Struct*) outapp->pBuffer;
// Start bind // Start bind
if(!bindwound_timer.Enabled()) if(!bindwound_timer.Enabled())
{ {
//make sure we actually have a bandage... and consume it. //make sure we actually have a bandage... and consume it.
int16 bslot = m_inv.HasItemByUse(ItemTypeBandage, 1, invWhereWorn|invWherePersonal); int16 bslot = m_inv.HasItemByUse(ItemTypeBandage, 1, invWhereWorn|invWherePersonal);
@ -2592,9 +2598,9 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){
; // Binding self ; // Binding self
} }
} }
} }
else if (bindwound_timer.Check()) // Did the timer finish? else if (bindwound_timer.Check()) // Did the timer finish?
{ {
// finish bind // finish bind
// disable complete timer // disable complete timer
bindwound_timer.Disable(); bindwound_timer.Disable();
@ -4991,7 +4997,7 @@ void Client::SetShadowStepExemption(bool v)
if((cur_time - m_TimeSinceLastPositionCheck) > 1000) if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
{ {
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
float runs = GetRunspeed(); int runs = GetRunspeed();
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{ {
printf("%s %i moving too fast! moved: %.2f in %ims, speed %.2f\n", __FILE__, __LINE__, printf("%s %i moving too fast! moved: %.2f in %ims, speed %.2f\n", __FILE__, __LINE__,
@ -5048,7 +5054,7 @@ void Client::SetKnockBackExemption(bool v)
if((cur_time - m_TimeSinceLastPositionCheck) > 1000) if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
{ {
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
float runs = GetRunspeed(); int runs = GetRunspeed();
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{ {
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
@ -5105,7 +5111,7 @@ void Client::SetPortExemption(bool v)
if((cur_time - m_TimeSinceLastPositionCheck) > 1000) if((cur_time - m_TimeSinceLastPositionCheck) > 1000)
{ {
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
float runs = GetRunspeed(); int runs = GetRunspeed();
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{ {
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
@ -5709,8 +5715,8 @@ void Client::ProcessInspectRequest(Client* requestee, Client* requester) {
else if (inst && inst->GetOrnamentationIcon()) else if (inst && inst->GetOrnamentationIcon())
{ {
insr->itemicons[L] = inst->GetOrnamentationIcon(); insr->itemicons[L] = inst->GetOrnamentationIcon();
} }
else else
{ {
insr->itemicons[L] = item->Icon; insr->itemicons[L] = item->Icon;
} }
@ -7491,6 +7497,10 @@ void Client::GarbleMessage(char *message, uint8 variance)
const char delimiter = 0x12; const char delimiter = 0x12;
int delimiter_count = 0; int delimiter_count = 0;
// Don't garble # commands
if (message[0] == '#')
return;
for (size_t i = 0; i < strlen(message); i++) { for (size_t i = 0; i < strlen(message); i++) {
// Client expects hex values inside of a text link body // Client expects hex values inside of a text link body
if (message[i] == delimiter) { if (message[i] == delimiter) {
@ -7500,7 +7510,7 @@ void Client::GarbleMessage(char *message, uint8 variance)
} }
uint8 chance = (uint8)zone->random.Int(0, 115); // variation just over worst possible scrambling uint8 chance = (uint8)zone->random.Int(0, 115); // variation just over worst possible scrambling
if (isalpha(message[i]) && (chance <= variance)) { if (isalpha((unsigned char)message[i]) && (chance <= variance)) {
uint8 rand_char = (uint8)zone->random.Int(0,51); // choose a random character from the alpha list uint8 rand_char = (uint8)zone->random.Int(0,51); // choose a random character from the alpha list
message[i] = alpha_list[rand_char]; message[i] = alpha_list[rand_char];
} }
@ -7584,7 +7594,7 @@ FACTION_VALUE Client::GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_ra
} }
//Sets the characters faction standing with the specified NPC. //Sets the characters faction standing with the specified NPC.
void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity) void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity, bool quest)
{ {
int32 faction_id[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int32 faction_id[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int32 npc_value[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int32 npc_value[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@ -7608,9 +7618,18 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui
// Find out starting faction for this faction // Find out starting faction for this faction
// It needs to be used to adj max and min personal // It needs to be used to adj max and min personal
// The range is still the same, 1200-3000(4200), but adjusted for base // The range is still the same, 1200-3000(4200), but adjusted for base
database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(), database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(),
faction_id[i]); faction_id[i]);
if (quest)
{
//The ole switcheroo
if (npc_value[i] > 0)
npc_value[i] = -abs(npc_value[i]);
else if (npc_value[i] < 0)
npc_value[i] = abs(npc_value[i]);
}
// Adjust the amount you can go up or down so the resulting range // Adjust the amount you can go up or down so the resulting range
// is PERSONAL_MAX - PERSONAL_MIN // is PERSONAL_MAX - PERSONAL_MIN
// //
@ -7649,7 +7668,7 @@ void Client::SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class
// Find out starting faction for this faction // Find out starting faction for this faction
// It needs to be used to adj max and min personal // It needs to be used to adj max and min personal
// The range is still the same, 1200-3000(4200), but adjusted for base // The range is still the same, 1200-3000(4200), but adjusted for base
database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(), database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(),
faction_id); faction_id);
// Adjust the amount you can go up or down so the resulting range // Adjust the amount you can go up or down so the resulting range
@ -7835,14 +7854,14 @@ void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_
char name[50]; char name[50];
int32 faction_value; int32 faction_value;
// If we're dropping from MAX or raising from MIN or repairing, // If we're dropping from MAX or raising from MIN or repairing,
// we should base the message on the new updated value so we don't show // we should base the message on the new updated value so we don't show
// a min MAX message // a min MAX message
// //
// If we're changing any other place, we use the value before the // If we're changing any other place, we use the value before the
// hit. For example, if we go from 1199 to 1200 which is the MAX // hit. For example, if we go from 1199 to 1200 which is the MAX
// we still want to say faction got better this time around. // we still want to say faction got better this time around.
if ( (faction_before_hit >= this_faction_max) || if ( (faction_before_hit >= this_faction_max) ||
(faction_before_hit <= this_faction_min)) (faction_before_hit <= this_faction_min))
faction_value = totalvalue; faction_value = totalvalue;
@ -8378,10 +8397,10 @@ std::string Client::TextLink::GenerateLink()
m_Link.clear(); m_Link.clear();
m_LinkBody.clear(); m_LinkBody.clear();
m_LinkText.clear(); m_LinkText.clear();
generate_body(); generate_body();
generate_text(); generate_text();
if ((m_LinkBody.length() == EmuConstants::TEXT_LINK_BODY_LENGTH) && (m_LinkText.length() > 0)) { if ((m_LinkBody.length() == EmuConstants::TEXT_LINK_BODY_LENGTH) && (m_LinkText.length() > 0)) {
m_Link.push_back(0x12); m_Link.push_back(0x12);
m_Link.append(m_LinkBody); m_Link.append(m_LinkBody);
@ -8420,7 +8439,7 @@ void Client::TextLink::generate_body()
{ {
/* /*
Current server mask: EQClientRoF2 Current server mask: EQClientRoF2
RoF2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X" (56) RoF2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X" (56)
RoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (55) RoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (55)
SoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (50) SoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (50)
@ -8428,7 +8447,6 @@ void Client::TextLink::generate_body()
*/ */
memset(&m_LinkBodyStruct, 0, sizeof(TextLinkBody_Struct)); memset(&m_LinkBodyStruct, 0, sizeof(TextLinkBody_Struct));
const ItemData* item_data = nullptr; const ItemData* item_data = nullptr;
switch (m_LinkType) { switch (m_LinkType) {
@ -8475,7 +8493,7 @@ void Client::TextLink::generate_body()
default: default:
break; break;
} }
if (m_ProxyItemID != NOT_USED) { if (m_ProxyItemID != NOT_USED) {
m_LinkBodyStruct.item_id = m_ProxyItemID; m_LinkBodyStruct.item_id = m_ProxyItemID;
} }
@ -8580,3 +8598,42 @@ bool Client::TextLink::GenerateLinkBody(std::string& textLinkBody, const TextLin
if (textLinkBody.length() != EmuConstants::TEXT_LINK_BODY_LENGTH) { return false; } if (textLinkBody.length() != EmuConstants::TEXT_LINK_BODY_LENGTH) { return false; }
return true; return true;
} }
void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction) {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct));
memset(outapp->pBuffer, 0, sizeof(outapp->pBuffer));
QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer;
qr->mob_id = target->GetID(); // Entity ID for the from mob name
qr->target_id = GetID(); // The Client ID (this)
qr->copper = copper;
qr->silver = silver;
qr->gold = gold;
qr->platinum = platinum;
qr->item_id = itemid;
qr->exp_reward = exp;
if (copper > 0 || silver > 0 || gold > 0 || platinum > 0)
AddMoneyToPP(copper, silver, gold, platinum, false);
if (itemid > 0)
SummonItem(itemid, 0, 0, 0, 0, 0, 0, false, MainPowerSource);
if (faction)
{
if (target->IsNPC())
{
int32 nfl_id = target->CastToNPC()->GetNPCFactionID();
SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true);
qr->faction = target->CastToNPC()->GetPrimaryFaction();
qr->faction_mod = 1; // Too lazy to get real value, not sure if this is even used by client anyhow.
}
}
if (exp > 0)
AddEXP(exp);
QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
safe_delete(outapp);
}

View File

@ -559,6 +559,7 @@ public:
void SendCrystalCounts(); void SendCrystalCounts();
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false); void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
uint32 CalcEXP(uint8 conlevel = 0xFF);
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false); void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false);
void AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0); void AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0);
void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp); void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp);
@ -613,7 +614,7 @@ public:
void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max); void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max);
void UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max); void UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max);
void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity); void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity, bool quest = false);
void SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp); void SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp);
int32 GetRawItemAC(); int32 GetRawItemAC();
uint16 GetCombinedAC_TEST(); uint16 GetCombinedAC_TEST();
@ -930,6 +931,7 @@ public:
bool DecreaseByID(uint32 type, uint8 amt); bool DecreaseByID(uint32 type, uint8 amt);
uint8 SlotConvert2(uint8 slot); //Maybe not needed. uint8 SlotConvert2(uint8 slot); //Maybe not needed.
void Escape(); //AA Escape void Escape(); //AA Escape
void DisenchantSummonedBags(bool client_update = true);
void RemoveNoRent(bool client_update = true); void RemoveNoRent(bool client_update = true);
void RemoveDuplicateLore(bool client_update = true); void RemoveDuplicateLore(bool client_update = true);
void MoveSlotNotAllowed(bool client_update = true); void MoveSlotNotAllowed(bool client_update = true);
@ -1154,6 +1156,7 @@ public:
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); } inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
void DragCorpses(); void DragCorpses();
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); } inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
inline void ResetPositionTimer() { position_timer_counter = 0; }
void SendAltCurrencies(); void SendAltCurrencies();
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount); void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0); void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
@ -1279,6 +1282,9 @@ public:
virtual int32 Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); virtual int32 Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
int32 GetMeleeDamage(Mob* other, bool GetMinDamage = false); int32 GetMeleeDamage(Mob* other, bool GetMinDamage = false);
void QuestReward(Mob* target, uint32 copper = 0, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0, uint32 itemid = 0, uint32 exp = 0, bool faction = false);
void ResetHPUpdateTimer() { hpupdate_timer.Start(); }
protected: protected:
friend class Mob; friend class Mob;
void CalcItemBonuses(StatBonuses* newbon); void CalcItemBonuses(StatBonuses* newbon);
@ -1466,6 +1472,9 @@ private:
Timer position_timer; Timer position_timer;
uint8 position_timer_counter; uint8 position_timer_counter;
// this is used to try to cut back on position update reflections
int position_update_same_count;
PTimerList p_timers; //persistent timers PTimerList p_timers; //persistent timers
Timer hpupdate_timer; Timer hpupdate_timer;
Timer camp_timer; Timer camp_timer;

View File

@ -1974,101 +1974,87 @@ int32 Client::CalcATK()
uint32 Mob::GetInstrumentMod(uint16 spell_id) const uint32 Mob::GetInstrumentMod(uint16 spell_id) const
{ {
if (GetClass() != BARD) { if (GetClass() != BARD || spells[spell_id].IsDisciplineBuff) // Puretone is Singing but doesn't get any mod
return 10; return 10;
}
uint32 effectmod = 10; uint32 effectmod = 10;
int effectmodcap = RuleI(Character, BaseInstrumentSoftCap); int effectmodcap = RuleI(Character, BaseInstrumentSoftCap);
//this should never use spell modifiers... // this should never use spell modifiers...
//if a spell grants better modifers, they are copied into the item mods // if a spell grants better modifers, they are copied into the item mods
//because the spells are supposed to act just like having the intrument. // because the spells are supposed to act just like having the intrument.
//item mods are in 10ths of percent increases // item mods are in 10ths of percent increases
// clickies (Symphony of Battle) that have a song skill don't get AA bonus for some reason
// but clickies that are songs (selo's on Composers Greaves) do get AA mod as well
switch (spells[spell_id].skill) { switch (spells[spell_id].skill) {
case SkillPercussionInstruments: case SkillPercussionInstruments:
if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0) { if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0)
effectmod = 10;
}
else if (GetSkill(SkillPercussionInstruments) == 0) {
effectmod = 10;
}
else if (itembonuses.percussionMod > spellbonuses.percussionMod) {
effectmod = itembonuses.percussionMod;
}
else {
effectmod = spellbonuses.percussionMod;
}
effectmod += aabonuses.percussionMod;
break;
case SkillStringedInstruments:
if (itembonuses.stringedMod == 0 && spellbonuses.stringedMod == 0) {
effectmod = 10;
}
else if (GetSkill(SkillStringedInstruments) == 0) {
effectmod = 10;
}
else if (itembonuses.stringedMod > spellbonuses.stringedMod) {
effectmod = itembonuses.stringedMod;
}
else {
effectmod = spellbonuses.stringedMod;
}
effectmod += aabonuses.stringedMod;
break;
case SkillWindInstruments:
if (itembonuses.windMod == 0 && spellbonuses.windMod == 0) {
effectmod = 10;
}
else if (GetSkill(SkillWindInstruments) == 0) {
effectmod = 10;
}
else if (itembonuses.windMod > spellbonuses.windMod) {
effectmod = itembonuses.windMod;
}
else {
effectmod = spellbonuses.windMod;
}
effectmod += aabonuses.windMod;
break;
case SkillBrassInstruments:
if (itembonuses.brassMod == 0 && spellbonuses.brassMod == 0) {
effectmod = 10;
}
else if (GetSkill(SkillBrassInstruments) == 0) {
effectmod = 10;
}
else if (itembonuses.brassMod > spellbonuses.brassMod) {
effectmod = itembonuses.brassMod;
}
else {
effectmod = spellbonuses.brassMod;
}
effectmod += aabonuses.brassMod;
break;
case SkillSinging:
if (itembonuses.singingMod == 0 && spellbonuses.singingMod == 0) {
effectmod = 10;
}
else if (itembonuses.singingMod > spellbonuses.singingMod) {
effectmod = itembonuses.singingMod;
}
else {
effectmod = spellbonuses.singingMod;
}
effectmod += aabonuses.singingMod + spellbonuses.Amplification;
break;
default:
effectmod = 10; effectmod = 10;
break; else if (GetSkill(SkillPercussionInstruments) == 0)
effectmod = 10;
else if (itembonuses.percussionMod > spellbonuses.percussionMod)
effectmod = itembonuses.percussionMod;
else
effectmod = spellbonuses.percussionMod;
if (IsBardSong(spell_id))
effectmod += aabonuses.percussionMod;
break;
case SkillStringedInstruments:
if (itembonuses.stringedMod == 0 && spellbonuses.stringedMod == 0)
effectmod = 10;
else if (GetSkill(SkillStringedInstruments) == 0)
effectmod = 10;
else if (itembonuses.stringedMod > spellbonuses.stringedMod)
effectmod = itembonuses.stringedMod;
else
effectmod = spellbonuses.stringedMod;
if (IsBardSong(spell_id))
effectmod += aabonuses.stringedMod;
break;
case SkillWindInstruments:
if (itembonuses.windMod == 0 && spellbonuses.windMod == 0)
effectmod = 10;
else if (GetSkill(SkillWindInstruments) == 0)
effectmod = 10;
else if (itembonuses.windMod > spellbonuses.windMod)
effectmod = itembonuses.windMod;
else
effectmod = spellbonuses.windMod;
if (IsBardSong(spell_id))
effectmod += aabonuses.windMod;
break;
case SkillBrassInstruments:
if (itembonuses.brassMod == 0 && spellbonuses.brassMod == 0)
effectmod = 10;
else if (GetSkill(SkillBrassInstruments) == 0)
effectmod = 10;
else if (itembonuses.brassMod > spellbonuses.brassMod)
effectmod = itembonuses.brassMod;
else
effectmod = spellbonuses.brassMod;
if (IsBardSong(spell_id))
effectmod += aabonuses.brassMod;
break;
case SkillSinging:
if (itembonuses.singingMod == 0 && spellbonuses.singingMod == 0)
effectmod = 10;
else if (itembonuses.singingMod > spellbonuses.singingMod)
effectmod = itembonuses.singingMod;
else
effectmod = spellbonuses.singingMod;
if (IsBardSong(spell_id))
effectmod += aabonuses.singingMod + spellbonuses.Amplification;
break;
default:
effectmod = 10;
return effectmod;
} }
effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap; effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap;
if (effectmod < 10) { if (effectmod < 10)
effectmod = 10; effectmod = 10;
} if (effectmod > effectmodcap)
if (effectmod > effectmodcap) {
effectmod = effectmodcap; effectmod = effectmodcap;
} Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n", GetName(), spell_id,
Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n", effectmod, effectmodcap);
GetName(), spell_id, effectmod, effectmodcap);
return effectmod; return effectmod;
} }

View File

@ -306,6 +306,8 @@ void MapOpcodes()
ConnectedOpcodes[OP_PetitionRefresh] = &Client::Handle_OP_PetitionRefresh; ConnectedOpcodes[OP_PetitionRefresh] = &Client::Handle_OP_PetitionRefresh;
ConnectedOpcodes[OP_PetitionResolve] = &Client::Handle_OP_PetitionResolve; ConnectedOpcodes[OP_PetitionResolve] = &Client::Handle_OP_PetitionResolve;
ConnectedOpcodes[OP_PetitionUnCheckout] = &Client::Handle_OP_PetitionUnCheckout; ConnectedOpcodes[OP_PetitionUnCheckout] = &Client::Handle_OP_PetitionUnCheckout;
ConnectedOpcodes[OP_PlayerStateAdd] = &Client::Handle_OP_PlayerStateAdd;
ConnectedOpcodes[OP_PlayerStateRemove] = &Client::Handle_OP_PlayerStateRemove;
ConnectedOpcodes[OP_PickPocket] = &Client::Handle_OP_PickPocket; ConnectedOpcodes[OP_PickPocket] = &Client::Handle_OP_PickPocket;
ConnectedOpcodes[OP_PopupResponse] = &Client::Handle_OP_PopupResponse; ConnectedOpcodes[OP_PopupResponse] = &Client::Handle_OP_PopupResponse;
ConnectedOpcodes[OP_PotionBelt] = &Client::Handle_OP_PotionBelt; ConnectedOpcodes[OP_PotionBelt] = &Client::Handle_OP_PotionBelt;
@ -703,7 +705,7 @@ void Client::CompleteConnect()
case SE_AddMeleeProc: case SE_AddMeleeProc:
case SE_WeaponProc: case SE_WeaponProc:
{ {
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid); AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid, buffs[j1].casterlevel);
break; break;
} }
case SE_DefensiveProc: case SE_DefensiveProc:
@ -1444,22 +1446,32 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; } if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; }
/* Initialize AA's : Move to function eventually */ /* Initialize AA's : Move to function eventually */
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ aa[a] = &m_pp.aa_array[a]; } for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++)
aa[a] = &m_pp.aa_array[a];
query = StringFormat( query = StringFormat(
"SELECT " "SELECT "
"slot, " "slot, "
"aa_id, " "aa_id, "
"aa_value " "aa_value, "
"charges "
"FROM " "FROM "
"`character_alternate_abilities` " "`character_alternate_abilities` "
"WHERE `id` = %u ORDER BY `slot`", this->CharacterID()); "WHERE `id` = %u ORDER BY `slot`", this->CharacterID());
results = database.QueryDatabase(query); i = 0; results = database.QueryDatabase(query); i = 0;
int offset = 0; // offset to fix the hole from expendables
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
i = atoi(row[0]); i = atoi(row[0]) - offset;
m_pp.aa_array[i].AA = atoi(row[1]); m_pp.aa_array[i].AA = atoi(row[1]);
m_pp.aa_array[i].value = atoi(row[2]); m_pp.aa_array[i].value = atoi(row[2]);
aa[i]->AA = atoi(row[1]); m_pp.aa_array[i].charges = atoi(row[3]);
aa[i]->value = atoi(row[2]); /* A used expendable could cause there to be a "hole" in the array, this is very bad. Bad things like keeping your expendable after use.
We could do a few things, one of them being reshuffling when the hole is created or defer the fixing until a later point, like during load!
Or just never making a hole in the array and just have hacks every where. Fixing the hole at load really just keeps 1 hack in Client::SendAATable
and keeping this offset that will cause the next AA to be pushed back over the hole. We also need to clean up on save so we don't have multiple
entries for a single AA.
*/
if (m_pp.aa_array[i].value == 0)
offset++;
} }
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){
uint32 id = aa[a]->AA; uint32 id = aa[a]->AA;
@ -1498,7 +1510,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
for (int i = 0; i < max_slots; i++) { for (int i = 0; i < max_slots; i++) {
if (buffs[i].spellid != SPELL_UNKNOWN) { if (buffs[i].spellid != SPELL_UNKNOWN) {
m_pp.buffs[i].spellid = buffs[i].spellid; m_pp.buffs[i].spellid = buffs[i].spellid;
m_pp.buffs[i].bard_modifier = 10; m_pp.buffs[i].bard_modifier = buffs[i].instrument_mod;
m_pp.buffs[i].slotid = 2; m_pp.buffs[i].slotid = 2;
m_pp.buffs[i].player_id = 0x2211; m_pp.buffs[i].player_id = 0x2211;
m_pp.buffs[i].level = buffs[i].casterlevel; m_pp.buffs[i].level = buffs[i].casterlevel;
@ -1707,7 +1719,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
/* Time of Day packet */ /* Time of Day packet */
outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct));
TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer; TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer;
zone->zone_time.getEQTimeOfDay(time(0), tod); zone->zone_time.GetCurrentEQTimeOfDay(time(0), tod);
outapp->priority = 6; outapp->priority = 6;
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
@ -4129,7 +4141,7 @@ void Client::Handle_OP_ClickObject(const EQApplicationPacket *app)
char buf[10]; char buf[10];
snprintf(buf, 9, "%u", click_object->drop_id); snprintf(buf, 9, "%u", click_object->drop_id);
buf[9] = '\0'; buf[9] = '\0';
parse->EventPlayer(EVENT_CLICK_OBJECT, this, buf, 0, &args); parse->EventPlayer(EVENT_CLICK_OBJECT, this, buf, GetID(), &args);
} }
// Observed in RoF after OP_ClickObjectAction: // Observed in RoF after OP_ClickObjectAction:
@ -4267,7 +4279,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
if((cur_time - m_TimeSinceLastPositionCheck) > 0) if((cur_time - m_TimeSinceLastPositionCheck) > 0)
{ {
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
float runs = GetRunspeed(); int runs = GetRunspeed();
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{ {
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
@ -4335,7 +4347,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
if((cur_time - m_TimeSinceLastPositionCheck) > 2500) if((cur_time - m_TimeSinceLastPositionCheck) > 2500)
{ {
float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
float runs = GetRunspeed(); int runs = GetRunspeed();
if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
{ {
if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
@ -4448,9 +4460,20 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
// Outgoing client packet // Outgoing client packet
float tmpheading = EQ19toFloat(ppu->heading); float tmpheading = EQ19toFloat(ppu->heading);
/* The clients send an update at best every 1.3 seconds
* We want to avoid reflecting these updates to other clients as much as possible
* The client also sends an update every 280 ms while turning, if we prevent
* sending these by checking if the location is the same too aggressively, clients end up spinning
* so keep a count of how many packets are the same within a tolerance and stop when we get there */
if (!FCMP(ppu->y_pos, m_Position.y) || !FCMP(ppu->x_pos, m_Position.x) || !FCMP(tmpheading, m_Position.w) || ppu->animation != animation) bool pos_same = FCMP(ppu->y_pos, m_Position.y) && FCMP(ppu->x_pos, m_Position.x) && FCMP(tmpheading, m_Position.w) && ppu->animation == animation;
if (!pos_same || (pos_same && position_update_same_count < 6))
{ {
if (pos_same)
position_update_same_count++;
else
position_update_same_count = 0;
m_Position.x = ppu->x_pos; m_Position.x = ppu->x_pos;
m_Position.y = ppu->y_pos; m_Position.y = ppu->y_pos;
m_Position.z = ppu->z_pos; m_Position.z = ppu->z_pos;
@ -6355,15 +6378,25 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
Bot::ProcessBotGroupDisband(this, std::string()); Bot::ProcessBotGroupDisband(this, std::string());
} }
else { else {
Mob* tempMember = entity_list.GetMob(gd->name2); Mob* tempMember = entity_list.GetMob(gd->name1); //Name1 is the target you are disbanding
if (tempMember) { if (tempMember && tempMember->IsBot()) {
if (tempMember->IsBot()) tempMember->CastToBot()->RemoveBotFromGroup(tempMember->CastToBot(), group);
Bot::ProcessBotGroupDisband(this, std::string(tempMember->GetCleanName())); if (LFP)
{
// If we are looking for players, update to show we are on our own now.
UpdateLFP();
}
return; //No need to continue from here we were removing a bot from party
} }
} }
} }
} }
group = GetGroup();
if (!group) //We must recheck this here.. incase the final bot disbanded the party..otherwise we crash
return;
#endif #endif
if (group->GroupCount() < 3) if (group->GroupCount() < 3)
{ {
group->DisbandGroup(); group->DisbandGroup();
@ -9705,6 +9738,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
char val1[20] = { 0 }; char val1[20] = { 0 };
PetCommand_Struct* pet = (PetCommand_Struct*)app->pBuffer; PetCommand_Struct* pet = (PetCommand_Struct*)app->pBuffer;
Mob* mypet = this->GetPet(); Mob* mypet = this->GetPet();
Mob *target = entity_list.GetMob(pet->target);
if (!mypet || pet->command == PET_LEADER) if (!mypet || pet->command == PET_LEADER)
{ {
@ -9752,22 +9786,22 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
switch (PetCommand) switch (PetCommand)
{ {
case PET_ATTACK: { case PET_ATTACK: {
if (!GetTarget()) if (!target)
break; break;
if (GetTarget()->IsMezzed()) { if (target->IsMezzed()) {
Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), GetTarget()->GetCleanName()); Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), target->GetCleanName());
break; break;
} }
if (mypet->IsFeared()) if (mypet->IsFeared())
break; //prevent pet from attacking stuff while feared break; //prevent pet from attacking stuff while feared
if (!mypet->IsAttackAllowed(GetTarget())) { if (!mypet->IsAttackAllowed(target)) {
mypet->Say_StringID(NOT_LEGAL_TARGET); mypet->Say_StringID(NOT_LEGAL_TARGET);
break; break;
} }
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) { if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) {
if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { if (target != this && DistanceSquaredNoZ(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
if (mypet->IsHeld()) { if (mypet->IsHeld()) {
if (!mypet->IsFocused()) { if (!mypet->IsFocused()) {
mypet->SetHeld(false); //break the hold and guard if we explicitly tell the pet to attack. mypet->SetHeld(false); //break the hold and guard if we explicitly tell the pet to attack.
@ -9775,12 +9809,12 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
mypet->SetPetOrder(SPO_Follow); mypet->SetPetOrder(SPO_Follow);
} }
else { else {
mypet->SetTarget(GetTarget()); mypet->SetTarget(target);
} }
} }
zone->AddAggroMob(); zone->AddAggroMob();
mypet->AddToHateList(GetTarget(), 1); mypet->AddToHateList(target, 1);
Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName()); Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), target->GetCleanName());
} }
} }
break; break;
@ -10275,6 +10309,31 @@ void Client::Handle_OP_PetitionUnCheckout(const EQApplicationPacket *app)
return; return;
} }
void Client::Handle_OP_PlayerStateAdd(const EQApplicationPacket *app)
{
if (app->size != sizeof(PlayerState_Struct)) {
std::cout << "Wrong size: OP_PlayerStateAdd, size=" << app->size << ", expected " << sizeof(PlayerState_Struct) << std::endl;
return;
}
PlayerState_Struct *ps = (PlayerState_Struct *)app->pBuffer;
AddPlayerState(ps->state);
entity_list.QueueClients(this, app, true);
}
void Client::Handle_OP_PlayerStateRemove(const EQApplicationPacket *app)
{
if (app->size != sizeof(PlayerState_Struct)) {
std::cout << "Wrong size: OP_PlayerStateRemove, size=" << app->size << ", expected " << sizeof(PlayerState_Struct) << std::endl;
return;
}
PlayerState_Struct *ps = (PlayerState_Struct *)app->pBuffer;
RemovePlayerState(ps->state);
entity_list.QueueClients(this, app, true);
}
void Client::Handle_OP_PickPocket(const EQApplicationPacket *app) void Client::Handle_OP_PickPocket(const EQApplicationPacket *app)
{ {
if (app->size != sizeof(PickPocket_Struct)) if (app->size != sizeof(PickPocket_Struct))
@ -12745,7 +12804,7 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app)
inspect_buffs = group->GetLeadershipAA(groupAAInspectBuffs); inspect_buffs = group->GetLeadershipAA(groupAAInspectBuffs);
} }
} }
if (nt == this || inspect_buffs || (nt->IsClient() && !nt->CastToClient()->GetPVP()) || if (GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs) || nt == this || inspect_buffs || (nt->IsClient() && !nt->CastToClient()->GetPVP()) ||
(nt->IsPet() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()) || (nt->IsPet() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()) ||
(nt->IsMerc() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP())) (nt->IsMerc() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()))
nt->SendBuffsToClient(this); nt->SendBuffsToClient(this);

View File

@ -218,6 +218,8 @@
void Handle_OP_PetitionRefresh(const EQApplicationPacket *app); void Handle_OP_PetitionRefresh(const EQApplicationPacket *app);
void Handle_OP_PetitionResolve(const EQApplicationPacket *app); void Handle_OP_PetitionResolve(const EQApplicationPacket *app);
void Handle_OP_PetitionUnCheckout(const EQApplicationPacket *app); void Handle_OP_PetitionUnCheckout(const EQApplicationPacket *app);
void Handle_OP_PlayerStateAdd(const EQApplicationPacket *app);
void Handle_OP_PlayerStateRemove(const EQApplicationPacket *app);
void Handle_OP_PickPocket(const EQApplicationPacket *app); void Handle_OP_PickPocket(const EQApplicationPacket *app);
void Handle_OP_PopupResponse(const EQApplicationPacket *app); void Handle_OP_PopupResponse(const EQApplicationPacket *app);
void Handle_OP_PotionBelt(const EQApplicationPacket *app); void Handle_OP_PotionBelt(const EQApplicationPacket *app);

View File

@ -129,7 +129,9 @@ bool Client::Process() {
if(IsTracking() && (GetClientVersion() >= ClientVersion::SoD) && TrackingTimer.Check()) if(IsTracking() && (GetClientVersion() >= ClientVersion::SoD) && TrackingTimer.Check())
DoTracking(); DoTracking();
if(hpupdate_timer.Check()) // SendHPUpdate calls hpupdate_timer.Start so it can delay this timer, so lets not reset with the check
// since the function will anyways
if(hpupdate_timer.Check(false))
SendHPUpdate(); SendHPUpdate();
if(mana_timer.Check()) if(mana_timer.Check())
@ -197,10 +199,8 @@ bool Client::Process() {
instalog = true; instalog = true;
} }
if (IsStunned() && stunned_timer.Check()) { if (IsStunned() && stunned_timer.Check())
this->stunned = false; Mob::UnStun();
this->stunned_timer.Disable();
}
if(!m_CheatDetectMoved) if(!m_CheatDetectMoved)
{ {
@ -262,7 +262,7 @@ bool Client::Process() {
} }
if(light_update_timer.Check()) { if(light_update_timer.Check()) {
UpdateEquipmentLight(); UpdateEquipmentLight();
if(UpdateActiveLight()) { if(UpdateActiveLight()) {
SendAppearancePacket(AT_Light, GetActiveLightType()); SendAppearancePacket(AT_Light, GetActiveLightType());
@ -562,7 +562,7 @@ bool Client::Process() {
} }
ProjectileAttack(); ProjectileAttack();
if(spellbonuses.GravityEffect == 1) { if(spellbonuses.GravityEffect == 1) {
if(gravity_timer.Check()) if(gravity_timer.Check())
DoGravityEffect(); DoGravityEffect();
@ -793,7 +793,7 @@ void Client::OnDisconnect(bool hard_disconnect) {
Mob *Other = trade->With(); Mob *Other = trade->With();
if(Other) if(Other)
{ {
Log.Out(Logs::Detail, Logs::Trading, "Client disconnected during a trade. Returning their items."); Log.Out(Logs::Detail, Logs::Trading, "Client disconnected during a trade. Returning their items.");
FinishTrade(this); FinishTrade(this);
if(Other->IsClient()) if(Other->IsClient())

View File

@ -1369,7 +1369,7 @@ void command_date(Client *c, const Seperator *sep)
else { else {
int h=0, m=0; int h=0, m=0;
TimeOfDay_Struct eqTime; TimeOfDay_Struct eqTime;
zone->zone_time.getEQTimeOfDay( time(0), &eqTime); zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime);
if(!sep->IsNumber(4)) if(!sep->IsNumber(4))
h=eqTime.hour; h=eqTime.hour;
else else
@ -1402,7 +1402,7 @@ void command_timezone(Client *c, const Seperator *sep)
// Update all clients with new TZ. // Update all clients with new TZ.
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); EQApplicationPacket* outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct));
TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer; TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer;
zone->zone_time.getEQTimeOfDay(time(0), tod); zone->zone_time.GetCurrentEQTimeOfDay(time(0), tod);
entity_list.QueueClients(c, outapp); entity_list.QueueClients(c, outapp);
safe_delete(outapp); safe_delete(outapp);
} }
@ -1484,7 +1484,7 @@ void command_npcstats(Client *c, const Seperator *sep)
c->Message(0, "Current HP: %i Max HP: %i", c->GetTarget()->GetHP(), c->GetTarget()->GetMaxHP()); c->Message(0, "Current HP: %i Max HP: %i", c->GetTarget()->GetHP(), c->GetTarget()->GetMaxHP());
//c->Message(0, "Weapon Item Number: %s", c->GetTarget()->GetWeapNo()); //c->Message(0, "Weapon Item Number: %s", c->GetTarget()->GetWeapNo());
c->Message(0, "Gender: %i Size: %f Bodytype: %d", c->GetTarget()->GetGender(), c->GetTarget()->GetSize(), c->GetTarget()->GetBodyType()); c->Message(0, "Gender: %i Size: %f Bodytype: %d", c->GetTarget()->GetGender(), c->GetTarget()->GetSize(), c->GetTarget()->GetBodyType());
c->Message(0, "Runspeed: %f Walkspeed: %f", c->GetTarget()->GetRunspeed(), c->GetTarget()->GetWalkspeed()); c->Message(0, "Runspeed: %i Walkspeed: %i", c->GetTarget()->GetRunspeed(), c->GetTarget()->GetWalkspeed());
c->Message(0, "Spawn Group: %i Grid: %i", c->GetTarget()->CastToNPC()->GetSp2(), c->GetTarget()->CastToNPC()->GetGrid()); c->Message(0, "Spawn Group: %i Grid: %i", c->GetTarget()->CastToNPC()->GetSp2(), c->GetTarget()->CastToNPC()->GetGrid());
c->Message(0, "EmoteID: %i", c->GetTarget()->CastToNPC()->GetEmoteID()); c->Message(0, "EmoteID: %i", c->GetTarget()->CastToNPC()->GetEmoteID());
c->GetTarget()->CastToNPC()->QueryLoot(c); c->GetTarget()->CastToNPC()->QueryLoot(c);
@ -4393,7 +4393,7 @@ void command_time(Client *c, const Seperator *sep)
else { else {
c->Message(13, "To set the Time: #time HH [MM]"); c->Message(13, "To set the Time: #time HH [MM]");
TimeOfDay_Struct eqTime; TimeOfDay_Struct eqTime;
zone->zone_time.getEQTimeOfDay( time(0), &eqTime); zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime);
sprintf(timeMessage,"%02d:%s%d %s (Timezone: %ih %im)", sprintf(timeMessage,"%02d:%s%d %s (Timezone: %ih %im)",
((eqTime.hour - 1) % 12) == 0 ? 12 : ((eqTime.hour - 1) % 12), ((eqTime.hour - 1) % 12) == 0 ? 12 : ((eqTime.hour - 1) % 12),
(eqTime.minute < 10) ? "0" : "", (eqTime.minute < 10) ? "0" : "",
@ -8565,20 +8565,20 @@ void command_object(Client *c, const Seperator *sep)
od.object_type = atoi(row[7]); od.object_type = atoi(row[7]);
icon = atoi(row[8]); icon = atoi(row[8]);
od.unknown008 = atoi(row[9]); od.size = atoi(row[9]);
od.unknown010 = atoi(row[10]); od.solidtype = atoi(row[10]);
od.unknown020 = atoi(row[11]); od.unknown020 = atoi(row[11]);
switch (od.object_type) { switch (od.object_type) {
case 0: // Static Object case 0: // Static Object
case staticType: // Static Object unlocked for changes case staticType: // Static Object unlocked for changes
if (od.unknown008 == 0) // Unknown08 field is optional Size parameter for static objects if (od.size == 0) // Unknown08 field is optional Size parameter for static objects
od.unknown008 = 100; // Static object default Size is 100% od.size = 100; // Static object default Size is 100%
c->Message(0, "- STATIC Object (%s): id %u, x %.1f, y %.1f, z %.1f, h %.1f, model %s, " c->Message(0, "- STATIC Object (%s): id %u, x %.1f, y %.1f, z %.1f, h %.1f, model %s, "
"size %u, solidtype %u, incline %u", "size %u, solidtype %u, incline %u",
(od.object_type == 0) ? "locked" : "unlocked", id, od.x, od.y, od.z, (od.object_type == 0) ? "locked" : "unlocked", id, od.x, od.y, od.z,
od.heading, od.object_name, od.unknown008, od.unknown010, od.unknown020); od.heading, od.object_name, od.size, od.solidtype, od.unknown020);
break; break;
case OT_DROPPEDITEM: // Ground Spawn case OT_DROPPEDITEM: // Ground Spawn
@ -8636,10 +8636,10 @@ void command_object(Client *c, const Seperator *sep)
switch (od.object_type) { switch (od.object_type) {
case 0: // Static Object case 0: // Static Object
if ((sep->argnum - col) > 3) { if ((sep->argnum - col) > 3) {
od.unknown008 = atoi(sep->arg[4 + col]); // Size specified od.size = atoi(sep->arg[4 + col]); // Size specified
if ((sep->argnum - col) > 4) { if ((sep->argnum - col) > 4) {
od.unknown010 = atoi(sep->arg[5 + col]); // SolidType specified od.solidtype = atoi(sep->arg[5 + col]); // SolidType specified
if ((sep->argnum - col) > 5) if ((sep->argnum - col) > 5)
od.unknown020 = atoi(sep->arg[6 + col]); // Incline specified od.unknown020 = atoi(sep->arg[6 + col]); // Incline specified
@ -8938,16 +8938,16 @@ void command_object(Client *c, const Seperator *sep)
return; return;
} }
od.unknown008 = atoi(sep->arg[4]); od.size = atoi(sep->arg[4]);
o->SetObjectData(&od); o->SetObjectData(&od);
if (od.unknown008 == 0) // 0 == unspecified == 100% if (od.size == 0) // 0 == unspecified == 100%
od.unknown008 = 100; od.size = 100;
c->Message(0, "Static Object %u set to %u%% size. Size will take effect when you commit to the " c->Message(0, "Static Object %u set to %u%% size. Size will take effect when you commit to the "
"database with '#object Save', after which the object will be unchangeable until " "database with '#object Save', after which the object will be unchangeable until "
"you unlock it again with '#object Edit' and zone out and back in.", "you unlock it again with '#object Edit' and zone out and back in.",
id, od.unknown008); id, od.size);
} else if (strcmp(sep->arg[3], "solidtype") == 0) { } else if (strcmp(sep->arg[3], "solidtype") == 0) {
if (od.object_type != staticType) { if (od.object_type != staticType) {
@ -8962,13 +8962,13 @@ void command_object(Client *c, const Seperator *sep)
return; return;
} }
od.unknown010 = atoi(sep->arg[4]); od.solidtype = atoi(sep->arg[4]);
o->SetObjectData(&od); o->SetObjectData(&od);
c->Message(0, "Static Object %u set to SolidType %u. Change will take effect when you commit " c->Message(0, "Static Object %u set to SolidType %u. Change will take effect when you commit "
"to the database with '#object Save'. Support for this property is on a " "to the database with '#object Save'. Support for this property is on a "
"per-model basis, mostly seen in smaller objects such as chests and tables.", "per-model basis, mostly seen in smaller objects such as chests and tables.",
id, od.unknown010); id, od.solidtype);
} else if (strcmp(sep->arg[3], "icon") == 0) { } else if (strcmp(sep->arg[3], "icon") == 0) {
if ((od.object_type < 2) || (od.object_type == staticType)) { if ((od.object_type < 2) || (od.object_type == staticType)) {
@ -9255,24 +9255,24 @@ void command_object(Client *c, const Seperator *sep)
"unknown08 = %u, unknown10 = %u, unknown20 = %u " "unknown08 = %u, unknown10 = %u, unknown20 = %u "
"WHERE ID = %u", "WHERE ID = %u",
zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z, zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z,
od.heading, od.object_name, od.object_type, icon, od.unknown008, od.heading, od.object_name, od.object_type, icon, od.size,
od.unknown010, od.unknown020, id); od.solidtype, od.unknown020, id);
else if (id == 0) else if (id == 0)
query = StringFormat("INSERT INTO object " query = StringFormat("INSERT INTO object "
"(zoneid, version, xpos, ypos, zpos, heading, objectname, " "(zoneid, version, xpos, ypos, zpos, heading, objectname, "
"type, icon, unknown08, unknown10, unknown20) " "type, icon, unknown08, unknown10, unknown20) "
"VALUES (%u, %u, %.1f, %.1f, %.1f, %.1f, '%s', %u, %u, %u, %u, %u)", "VALUES (%u, %u, %.1f, %.1f, %.1f, %.1f, '%s', %u, %u, %u, %u, %u)",
zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z, zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z,
od.heading, od.object_name, od.object_type, icon, od.unknown008, od.heading, od.object_name, od.object_type, icon, od.size,
od.unknown010, od.unknown020); od.solidtype, od.unknown020);
else else
query = StringFormat("INSERT INTO object " query = StringFormat("INSERT INTO object "
"(id, zoneid, version, xpos, ypos, zpos, heading, objectname, " "(id, zoneid, version, xpos, ypos, zpos, heading, objectname, "
"type, icon, unknown08, unknown10, unknown20) " "type, icon, unknown08, unknown10, unknown20) "
"VALUES (%u, %u, %u, %.1f, %.1f, %.1f, %.1f, '%s', %u, %u, %u, %u, %u)", "VALUES (%u, %u, %u, %.1f, %.1f, %.1f, %.1f, '%s', %u, %u, %u, %u, %u)",
id, zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z, id, zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z,
od.heading, od.object_name, od.object_type, icon, od.unknown008, od.heading, od.object_name, od.object_type, icon, od.size,
od.unknown010, od.unknown020); od.solidtype, od.unknown020);
results = database.QueryDatabase(query); results = database.QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
@ -9330,12 +9330,12 @@ void command_object(Client *c, const Seperator *sep)
memcpy(door.dest_zone, "NONE", 5); memcpy(door.dest_zone, "NONE", 5);
if ((door.size = od.unknown008) == 0) // unknown08 = optional size percentage if ((door.size = od.size) == 0) // unknown08 = optional size percentage
door.size = 100; door.size = 100;
switch ( switch (
door.opentype = door.opentype =
od.unknown010) // unknown10 = optional request_nonsolid (0 or 1 or experimental number) od.solidtype) // unknown10 = optional request_nonsolid (0 or 1 or experimental number)
{ {
case 0: case 0:
door.opentype = 31; door.opentype = 31;
@ -9592,8 +9592,8 @@ void command_object(Client *c, const Seperator *sep)
strn0cpy(od.object_name, row[4], sizeof(od.object_name)); strn0cpy(od.object_name, row[4], sizeof(od.object_name));
od.object_type = atoi(row[5]); od.object_type = atoi(row[5]);
icon = atoi(row[6]); icon = atoi(row[6]);
od.unknown008 = atoi(row[7]); od.size = atoi(row[7]);
od.unknown010 = atoi(row[8]); od.solidtype = atoi(row[8]);
od.unknown020 = atoi(row[9]); od.unknown020 = atoi(row[9]);
if (od.object_type == 0) if (od.object_type == 0)

View File

@ -173,6 +173,18 @@ enum class NumHit { // Numhits type
OffensiveSpellProcs = 11 // Offensive buff procs OffensiveSpellProcs = 11 // Offensive buff procs
}; };
enum class PlayerState : uint32 {
None = 0,
Open = 1,
WeaponSheathed = 2,
Aggressive = 4,
ForcedAggressive = 8,
InstrumentEquipped = 16,
Stunned = 32,
PrimaryWeaponEquipped = 64,
SecondaryWeaponEquipped = 128
};
//this is our internal representation of the BUFF struct, can put whatever we want in it //this is our internal representation of the BUFF struct, can put whatever we want in it
struct Buffs_Struct { struct Buffs_Struct {
uint16 spellid; uint16 spellid;
@ -190,6 +202,7 @@ struct Buffs_Struct {
int32 caston_z; int32 caston_z;
int32 ExtraDIChance; int32 ExtraDIChance;
int16 RootBreakChance; //Not saved to dbase int16 RootBreakChance; //Not saved to dbase
uint32 instrument_mod;
bool persistant_buff; bool persistant_buff;
bool client; //True if the caster is a client bool client; //True if the caster is a client
bool UpdateClient; bool UpdateClient;
@ -438,7 +451,7 @@ struct StatBonuses {
int32 ShieldEquipHateMod; // Hate mod when shield equiped. int32 ShieldEquipHateMod; // Hate mod when shield equiped.
int32 ShieldEquipDmgMod[2]; // Damage mod when shield equiped. 0 = damage modifier 1 = Unknown int32 ShieldEquipDmgMod[2]; // Damage mod when shield equiped. 0 = damage modifier 1 = Unknown
bool TriggerOnValueAmount; // Triggers off various different conditions, bool to check if client has effect. bool TriggerOnValueAmount; // Triggers off various different conditions, bool to check if client has effect.
int8 StunBashChance; // chance to stun with bash. int8 StunBashChance; // chance to stun with bash.
int8 IncreaseChanceMemwipe; // increases chance to memory wipe int8 IncreaseChanceMemwipe; // increases chance to memory wipe
int8 CriticalMend; // chance critical monk mend int8 CriticalMend; // chance critical monk mend
int32 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy int32 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy
@ -455,6 +468,7 @@ typedef struct
uint16 spellID; uint16 spellID;
uint16 chance; uint16 chance;
uint16 base_spellID; uint16 base_spellID;
int level_override;
} tProc; } tProc;
struct Shielders_Struct { struct Shielders_Struct {
@ -507,7 +521,8 @@ typedef enum {
petOther, petOther,
petCharmed, petCharmed,
petNPCFollow, petNPCFollow,
petTargetLock //remain active as long something is on the hatelist. Don't listen to any commands petTargetLock, //remain active as long something is on the hatelist. Don't listen to any commands
petNone = 0xFF // not a pet
} PetType; } PetType;
typedef enum { typedef enum {

View File

@ -89,7 +89,7 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if (IsClient() && GetClass() == WIZARD) if (IsClient() && GetClass() == WIZARD)
ratio += RuleI(Spells, WizCritRatio); //Default is zero ratio += RuleI(Spells, WizCritRatio); //Default is zero
if (Critical){ if (Critical){
value = value_BaseEffect*ratio/100; value = value_BaseEffect*ratio/100;
@ -172,7 +172,7 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100; value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100; value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100; value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) + int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) +
GetFocusEffect(focusFcDamageAmt, spell_id); GetFocusEffect(focusFcDamageAmt, spell_id);
@ -219,11 +219,11 @@ int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_s
total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time; total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time;
if (total_cast_time > 0 && total_cast_time <= 2500) if (total_cast_time > 0 && total_cast_time <= 2500)
extra_spell_amt = extra_spell_amt*25/100; extra_spell_amt = extra_spell_amt*25/100;
else if (total_cast_time > 2500 && total_cast_time < 7000) else if (total_cast_time > 2500 && total_cast_time < 7000)
extra_spell_amt = extra_spell_amt*(167*((total_cast_time - 1000)/1000)) / 1000; extra_spell_amt = extra_spell_amt*(167*((total_cast_time - 1000)/1000)) / 1000;
else else
extra_spell_amt = extra_spell_amt * total_cast_time / 7000; extra_spell_amt = extra_spell_amt * total_cast_time / 7000;
if(extra_spell_amt*2 < base_spell_dmg) if(extra_spell_amt*2 < base_spell_dmg)
return 0; return 0;
@ -281,7 +281,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
if (Critical) { if (Critical) {
entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits, entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
OTHER_CRIT_HEAL, GetName(), itoa(value)); OTHER_CRIT_HEAL, GetName(), itoa(value));
if (IsClient()) if (IsClient())
Message_StringID(MT_SpellCrits, YOU_CRIT_HEAL, itoa(value)); Message_StringID(MT_SpellCrits, YOU_CRIT_HEAL, itoa(value));
} }
@ -421,16 +421,21 @@ int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
int tic_inc = 0; int tic_inc = 0;
tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id); tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id);
// Only need this for clients, since the change was for bard songs, I assume we should keep non bard songs getting +1 // unsure on the exact details, but bard songs that don't cost mana at some point get an extra tick, 60 for now
// However if its bard or not and is mez, charm or fear, we need to add 1 so that client is in sync // a level 53 bard reported getting 2 tics
if (IsClient() && !(IsShortDurationBuff(spell_id) && IsBardSong(spell_id)) || // bard DOTs do get this extra tick, but beneficial long bard songs don't? (invul, crescendo)
IsFearSpell(spell_id) || if ((IsShortDurationBuff(spell_id) || IsDetrimentalSpell(spell_id)) && IsBardSong(spell_id) &&
IsCharmSpell(spell_id) || spells[spell_id].mana == 0 && GetClass() == BARD && GetLevel() > 60)
IsMezSpell(spell_id) || tic_inc++;
IsBlindSpell(spell_id)) float focused = ((duration * increase) / 100.0f) + tic_inc;
tic_inc += 1; int ifocused = static_cast<int>(focused);
return (((duration * increase) / 100) + tic_inc); // 7.6 is rounded to 7, 8.6 is rounded to 9
// 6 is 6, etc
if (FCMP(focused, ifocused) || ifocused % 2) // equal or odd
return ifocused;
else // even and not equal round to odd
return ifocused + 1;
} }
int32 Client::GetActSpellCasttime(uint16 spell_id, int32 casttime) int32 Client::GetActSpellCasttime(uint16 spell_id, int32 casttime)
@ -771,7 +776,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust); caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
} }
} else { } else {
if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets) if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets)
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust); caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
if (!spells[spell_id].aemaxtargets) if (!spells[spell_id].aemaxtargets)
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust); caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
@ -859,7 +864,7 @@ void EntityList::AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool aff
if (!center->CheckLosFN(curmob)) if (!center->CheckLosFN(curmob))
continue; continue;
} else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies... } else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies...
// See notes in AESpell() above for more info. // See notes in AESpell() above for more info.
if (caster->IsAttackAllowed(curmob, true)) if (caster->IsAttackAllowed(curmob, true))
continue; continue;
if (caster->CheckAggro(curmob)) if (caster->CheckAggro(curmob))

View File

@ -1072,7 +1072,7 @@ void PerlembParser::ExportZoneVariables(std::string &package_name) {
ExportVar(package_name.c_str(), "instanceid", zone->GetInstanceID()); ExportVar(package_name.c_str(), "instanceid", zone->GetInstanceID());
ExportVar(package_name.c_str(), "instanceversion", zone->GetInstanceVersion()); ExportVar(package_name.c_str(), "instanceversion", zone->GetInstanceVersion());
TimeOfDay_Struct eqTime; TimeOfDay_Struct eqTime;
zone->zone_time.getEQTimeOfDay( time(0), &eqTime); zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime);
ExportVar(package_name.c_str(), "zonehour", eqTime.hour - 1); ExportVar(package_name.c_str(), "zonehour", eqTime.hour - 1);
ExportVar(package_name.c_str(), "zonemin", eqTime.minute); ExportVar(package_name.c_str(), "zonemin", eqTime.minute);
ExportVar(package_name.c_str(), "zonetime", (eqTime.hour - 1) * 100 + eqTime.minute); ExportVar(package_name.c_str(), "zonetime", (eqTime.hour - 1) * 100 + eqTime.minute);
@ -1277,6 +1277,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
case EVENT_PLAYER_PICKUP:{ case EVENT_PLAYER_PICKUP:{
ExportVar(package_name.c_str(), "picked_up_id", data); ExportVar(package_name.c_str(), "picked_up_id", data);
ExportVar(package_name.c_str(), "picked_up_entity_id", extradata);
break; break;
} }
@ -1320,6 +1321,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
ExportVar(package_name.c_str(), "itemid", objid); ExportVar(package_name.c_str(), "itemid", objid);
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name); ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
ExportVar(package_name.c_str(), "slotid", extradata); ExportVar(package_name.c_str(), "slotid", extradata);
ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect);
break; break;
} }
@ -1367,6 +1369,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
case EVENT_CLICK_OBJECT: { case EVENT_CLICK_OBJECT: {
ExportVar(package_name.c_str(), "objectid", data); ExportVar(package_name.c_str(), "objectid", data);
ExportVar(package_name.c_str(), "clicker_id", extradata);
break; break;
} }
@ -1397,6 +1400,14 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]); ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
break; break;
} }
case EVENT_DROP_ITEM: {
ExportVar(package_name.c_str(), "quantity", iteminst->IsStackable() ? iteminst->GetCharges() : 1);
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
ExportVar(package_name.c_str(), "itemid", iteminst->GetItem()->ID);
ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect);
ExportVar(package_name.c_str(), "slotid", extradata);
break;
}
default: { default: {
break; break;

View File

@ -1182,13 +1182,26 @@ XS(XS__settime);
XS(XS__settime) XS(XS__settime)
{ {
dXSARGS; dXSARGS;
if (items != 2) if (items < 2)
Perl_croak(aTHX_ "Usage: settime(new_hour, new_min)"); Perl_croak(aTHX_ "Usage: settime(new_hour, new_min, [update_world = true])");
int new_hour = (int)SvIV(ST(0)); if (items == 2){
int new_min = (int)SvIV(ST(1)); int new_hour = (int)SvIV(ST(0));
int new_min = (int)SvIV(ST(1));
quest_manager.settime(new_hour, new_min, true);
}
else if (items == 3){
int new_hour = (int)SvIV(ST(0));
int new_min = (int)SvIV(ST(1));
quest_manager.settime(new_hour, new_min); int update_world = (int)SvIV(ST(2));
if (update_world == 1){
quest_manager.settime(new_hour, new_min, true);
}
else{
quest_manager.settime(new_hour, new_min, false);
}
}
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
@ -1917,6 +1930,52 @@ XS(XS__repopzone)
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
XS(XS__ConnectNodeToNode);
XS(XS__ConnectNodeToNode)
{
dXSARGS;
if (items != 4)
Perl_croak(aTHX_ "Usage: ConnectNodeToNode(node1, node2, teleport, doorid)");
int node1 = (int)SvIV(ST(0));
int node2 = (int)SvIV(ST(1));
int teleport = (int)SvIV(ST(2));
int doorid = (int)SvIV(ST(3));
quest_manager.ConnectNodeToNode(node1, node2, teleport, doorid);
XSRETURN_EMPTY;
}
XS(XS__AddNode);
XS(XS__AddNode)
{
dXSARGS;
//void QuestManager::AddNode(float x, float y, float z, float best_z, int32 requested_id);
if (items < 3 || items > 5)
Perl_croak(aTHX_ "Usage: AddNode(x, y, z, [best_z], [requested_id])");
int x = (int)SvIV(ST(0));
int y = (int)SvIV(ST(1));
int z = (int)SvIV(ST(2));
int best_z = 0;
int requested_id = 0;
if (items == 4)
{
best_z = (int)SvIV(ST(3));
}
else if (items == 5)
{
best_z = (int)SvIV(ST(3));
requested_id = (int)SvIV(ST(4));
}
quest_manager.AddNode(x, y, z, best_z, requested_id);
XSRETURN_EMPTY;
}
XS(XS__npcrace); XS(XS__npcrace);
XS(XS__npcrace) XS(XS__npcrace)
{ {
@ -3699,6 +3758,8 @@ EXTERN_C XS(boot_quest)
newXS(strcpy(buf, "reloadzonestaticdata"), XS__reloadzonestaticdata, file); newXS(strcpy(buf, "reloadzonestaticdata"), XS__reloadzonestaticdata, file);
newXS(strcpy(buf, "removetitle"), XS__removetitle, file); newXS(strcpy(buf, "removetitle"), XS__removetitle, file);
newXS(strcpy(buf, "repopzone"), XS__repopzone, file); newXS(strcpy(buf, "repopzone"), XS__repopzone, file);
newXS(strcpy(buf, "ConnectNodeToNode"), XS__ConnectNodeToNode, file);
newXS(strcpy(buf, "AddNode"), XS__AddNode, file);
newXS(strcpy(buf, "resettaskactivity"), XS__resettaskactivity, file); newXS(strcpy(buf, "resettaskactivity"), XS__resettaskactivity, file);
newXS(strcpy(buf, "respawn"), XS__respawn, file); newXS(strcpy(buf, "respawn"), XS__respawn, file);
newXS(strcpy(buf, "resume"), XS__resume, file); newXS(strcpy(buf, "resume"), XS__resume, file);

53
zone/encounter.cpp Normal file
View File

@ -0,0 +1,53 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef _WINDOWS
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif
#include "../common/races.h"
#include "encounter.h"
#include "entity.h"
#include "mob.h"
class Zone;
Encounter::Encounter(const char* enc_name)
:Mob
(
nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, glm::vec4(0,0,0,0), 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
)
{
encounter_name[0] = 0;
strn0cpy(encounter_name, enc_name, 64);
remove_me = false;
}
Encounter::~Encounter()
{
}
bool Encounter::Process() {
if (remove_me) return false;
return true;
}

62
zone/encounter.h Normal file
View File

@ -0,0 +1,62 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ENCOUNTER_H
#define ENCOUNTER_H
#include "mob.h"
#include "../common/types.h"
#include "../common/timer.h"
class Group;
class Raid;
struct ExtraAttackOptions;
class Encounter : public Mob
{
public:
Encounter(const char* enc_name);
~Encounter();
//abstract virtual function implementations required by base abstract class
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) { return true; }
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false) { return; }
virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
ExtraAttackOptions *opts = nullptr) {
return false;
}
virtual bool HasRaid() { return false; }
virtual bool HasGroup() { return false; }
virtual Raid* GetRaid() { return 0; }
virtual Group* GetGroup() { return 0; }
bool IsEncounter() const { return true; }
const char* GetEncounterName() const { return encounter_name; }
bool Process();
virtual void Depop(bool not_used = true) { remove_me = true; }
protected:
bool remove_me;
char encounter_name[64];
private:
};
#endif

View File

@ -79,7 +79,7 @@ Client *Entity::CastToClient()
} }
#ifdef _EQDEBUG #ifdef _EQDEBUG
if (!IsClient()) { if (!IsClient()) {
Log.Out(Logs::General, Logs::Error, "CastToClient error (not client)"); Log.Out(Logs::General, Logs::Error, "CastToClient error (not client)");
return 0; return 0;
} }
#endif #endif
@ -173,6 +173,11 @@ Beacon *Entity::CastToBeacon()
return static_cast<Beacon *>(this); return static_cast<Beacon *>(this);
} }
Encounter *Entity::CastToEncounter()
{
return static_cast<Encounter *>(this);
}
const Client *Entity::CastToClient() const const Client *Entity::CastToClient() const
{ {
if (this == 0x00) { if (this == 0x00) {
@ -263,6 +268,11 @@ const Beacon* Entity::CastToBeacon() const
return static_cast<const Beacon *>(this); return static_cast<const Beacon *>(this);
} }
const Encounter* Entity::CastToEncounter() const
{
return static_cast<const Encounter *>(this);
}
#ifdef BOTS #ifdef BOTS
Bot *Entity::CastToBot() Bot *Entity::CastToBot()
{ {
@ -533,6 +543,21 @@ void EntityList::BeaconProcess()
} }
} }
void EntityList::EncounterProcess()
{
auto it = encounter_list.begin();
while (it != encounter_list.end()) {
if (!it->second->Process()) {
safe_delete(it->second);
free_ids.push(it->first);
it = encounter_list.erase(it);
}
else {
++it;
}
}
}
void EntityList::AddGroup(Group *group) void EntityList::AddGroup(Group *group)
{ {
if (group == nullptr) //this seems to be happening somehow... if (group == nullptr) //this seems to be happening somehow...
@ -540,7 +565,7 @@ void EntityList::AddGroup(Group *group)
uint32 gid = worldserver.NextGroupID(); uint32 gid = worldserver.NextGroupID();
if (gid == 0) { if (gid == 0) {
Log.Out(Logs::General, Logs::Error, Log.Out(Logs::General, Logs::Error,
"Unable to get new group ID from world server. group is going to be broken."); "Unable to get new group ID from world server. group is going to be broken.");
return; return;
} }
@ -569,7 +594,7 @@ void EntityList::AddRaid(Raid *raid)
uint32 gid = worldserver.NextGroupID(); uint32 gid = worldserver.NextGroupID();
if (gid == 0) { if (gid == 0) {
Log.Out(Logs::General, Logs::Error, Log.Out(Logs::General, Logs::Error,
"Unable to get new group ID from world server. group is going to be broken."); "Unable to get new group ID from world server. group is going to be broken.");
return; return;
} }
@ -618,6 +643,8 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
EQApplicationPacket *app = new EQApplicationPacket; EQApplicationPacket *app = new EQApplicationPacket;
npc->CreateSpawnPacket(app, npc); npc->CreateSpawnPacket(app, npc);
QueueClients(npc, app); QueueClients(npc, app);
npc->SendArmorAppearance();
npc->SetAppearance(npc->GetGuardPointAnim(),false);
safe_delete(app); safe_delete(app);
} else { } else {
NewSpawn_Struct *ns = new NewSpawn_Struct; NewSpawn_Struct *ns = new NewSpawn_Struct;
@ -706,6 +733,12 @@ void EntityList::AddBeacon(Beacon *beacon)
beacon_list.insert(std::pair<uint16, Beacon *>(beacon->GetID(), beacon)); beacon_list.insert(std::pair<uint16, Beacon *>(beacon->GetID(), beacon));
} }
void EntityList::AddEncounter(Encounter *encounter)
{
encounter->SetID(GetFreeID());
encounter_list.insert(std::pair<uint16, Encounter *>(encounter->GetID(), encounter));
}
void EntityList::AddToSpawnQueue(uint16 entityid, NewSpawn_Struct **ns) void EntityList::AddToSpawnQueue(uint16 entityid, NewSpawn_Struct **ns)
{ {
uint32 count; uint32 count;
@ -726,10 +759,23 @@ void EntityList::CheckSpawnQueue()
EQApplicationPacket *outapp = 0; EQApplicationPacket *outapp = 0;
iterator.Reset(); iterator.Reset();
NewSpawn_Struct *ns;
while(iterator.MoreElements()) { while(iterator.MoreElements()) {
outapp = new EQApplicationPacket; outapp = new EQApplicationPacket;
Mob::CreateSpawnPacket(outapp, iterator.GetData()); ns = iterator.GetData();
Mob::CreateSpawnPacket(outapp, ns);
QueueClients(0, outapp); QueueClients(0, outapp);
auto it = npc_list.find(ns->spawn.spawnId);
if (it == npc_list.end()) {
// We must of despawned, hope that's the reason!
Log.Out(Logs::General, Logs::Error, "Error in EntityList::CheckSpawnQueue: Unable to find NPC for spawnId '%u'", ns->spawn.spawnId);
}
else {
NPC *pnpc = it->second;
pnpc->SendArmorAppearance();
pnpc->SetAppearance(pnpc->GetGuardPointAnim(), false);
}
safe_delete(outapp); safe_delete(outapp);
iterator.RemoveCurrent(); iterator.RemoveCurrent();
} }
@ -920,6 +966,11 @@ Entity *EntityList::GetEntityBeacon(uint16 id)
return beacon_list.count(id) ? beacon_list.at(id) : nullptr; return beacon_list.count(id) ? beacon_list.at(id) : nullptr;
} }
Entity *EntityList::GetEntityEncounter(uint16 id)
{
return encounter_list.count(id) ? encounter_list.at(id) : nullptr;
}
Entity *EntityList::GetID(uint16 get_id) Entity *EntityList::GetID(uint16 get_id)
{ {
Entity *ent = 0; Entity *ent = 0;
@ -935,6 +986,8 @@ Entity *EntityList::GetID(uint16 get_id)
return ent; return ent;
else if ((ent=entity_list.GetEntityBeacon(get_id)) != 0) else if ((ent=entity_list.GetEntityBeacon(get_id)) != 0)
return ent; return ent;
else if ((ent = entity_list.GetEntityEncounter(get_id)) != 0)
return ent;
else else
return 0; return 0;
} }
@ -1149,19 +1202,39 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
NewSpawn_Struct ns; NewSpawn_Struct ns;
Mob *spawn; Mob *spawn;
uint32 maxspawns = 100; uint32 maxspawns = 100;
EQApplicationPacket *app;
if (maxspawns > mob_list.size()) if (maxspawns > mob_list.size())
maxspawns = mob_list.size(); maxspawns = mob_list.size();
BulkZoneSpawnPacket *bzsp = new BulkZoneSpawnPacket(client, maxspawns); BulkZoneSpawnPacket *bzsp = new BulkZoneSpawnPacket(client, maxspawns);
int32 race=-1;
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
spawn = it->second; spawn = it->second;
if (spawn && spawn->InZone()) { if (spawn && spawn->InZone()) {
if (spawn->IsClient() && (spawn->CastToClient()->GMHideMe(client) || if (spawn->IsClient() && (spawn->CastToClient()->GMHideMe(client) ||
spawn->CastToClient()->IsHoveringForRespawn())) spawn->CastToClient()->IsHoveringForRespawn()))
continue; continue;
memset(&ns, 0, sizeof(NewSpawn_Struct));
spawn->FillSpawnStruct(&ns, client); race = spawn->GetRace();
bzsp->AddSpawn(&ns);
// Illusion races on PCs don't work as a mass spawn
// But they will work as an add_spawn AFTER CLIENT_CONNECTED.
if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) {
app = new EQApplicationPacket;
spawn->CreateSpawnPacket(app);
client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
safe_delete(app);
}
else {
memset(&ns, 0, sizeof(NewSpawn_Struct));
spawn->FillSpawnStruct(&ns, client);
bzsp->AddSpawn(&ns);
}
// Despite being sent in the OP_ZoneSpawns packet, the client
// does not display worn armor correctly so display it.
spawn->SendArmorAppearance(client);
} }
} }
safe_delete(bzsp); safe_delete(bzsp);
@ -1355,7 +1428,9 @@ void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *ap
if (c != sender) { if (c != sender) {
if (Target == sender) { if (Target == sender) {
if (inspect_buffs) { // if inspect_buffs is true we're sending a mob's buffs to those with the LAA if (inspect_buffs) { // if inspect_buffs is true we're sending a mob's buffs to those with the LAA
if (c->IsRaidGrouped()) { if (c->GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs)) {
Send = true;
} else if (c->IsRaidGrouped()) {
Raid *raid = c->GetRaid(); Raid *raid = c->GetRaid();
if (!raid) if (!raid)
continue; continue;
@ -3389,6 +3464,15 @@ bool EntityList::IsMobInZone(Mob *who)
} }
++it; ++it;
} }
auto enc_it = encounter_list.begin();
while (enc_it != encounter_list.end()) {
if (enc_it->second == who) {
return true;
}
++enc_it;
}
return false; return false;
} }

View File

@ -30,6 +30,7 @@
#include "position.h" #include "position.h"
#include "zonedump.h" #include "zonedump.h"
class Encounter;
class Beacon; class Beacon;
class Client; class Client;
class Corpse; class Corpse;
@ -77,6 +78,7 @@ public:
virtual bool IsDoor() const { return false; } virtual bool IsDoor() const { return false; }
virtual bool IsTrap() const { return false; } virtual bool IsTrap() const { return false; }
virtual bool IsBeacon() const { return false; } virtual bool IsBeacon() const { return false; }
virtual bool IsEncounter() const { return false; }
virtual bool Process() { return false; } virtual bool Process() { return false; }
virtual bool Save() { return true; } virtual bool Save() { return true; }
@ -91,6 +93,7 @@ public:
Doors *CastToDoors(); Doors *CastToDoors();
Trap *CastToTrap(); Trap *CastToTrap();
Beacon *CastToBeacon(); Beacon *CastToBeacon();
Encounter *CastToEncounter();
const Client *CastToClient() const; const Client *CastToClient() const;
const NPC *CastToNPC() const; const NPC *CastToNPC() const;
@ -101,6 +104,7 @@ public:
const Doors *CastToDoors() const; const Doors *CastToDoors() const;
const Trap *CastToTrap() const; const Trap *CastToTrap() const;
const Beacon *CastToBeacon() const; const Beacon *CastToBeacon() const;
const Encounter *CastToEncounter() const;
inline const uint16& GetID() const { return id; } inline const uint16& GetID() const { return id; }
inline const time_t& GetSpawnTimeStamp() const { return spawn_timestamp; } inline const time_t& GetSpawnTimeStamp() const { return spawn_timestamp; }
@ -203,6 +207,7 @@ public:
void MobProcess(); void MobProcess();
void TrapProcess(); void TrapProcess();
void BeaconProcess(); void BeaconProcess();
void EncounterProcess();
void ProcessMove(Client *c, const glm::vec3& location); void ProcessMove(Client *c, const glm::vec3& location);
void ProcessMove(NPC *n, float x, float y, float z); void ProcessMove(NPC *n, float x, float y, float z);
void AddArea(int id, int type, float min_x, float max_x, float min_y, float max_y, float min_z, float max_z); void AddArea(int id, int type, float min_x, float max_x, float min_y, float max_y, float min_z, float max_z);
@ -228,6 +233,7 @@ public:
void AddDoor(Doors* door); void AddDoor(Doors* door);
void AddTrap(Trap* trap); void AddTrap(Trap* trap);
void AddBeacon(Beacon *beacon); void AddBeacon(Beacon *beacon);
void AddEncounter(Encounter *encounter);
void AddProximity(NPC *proximity_for); void AddProximity(NPC *proximity_for);
void Clear(); void Clear();
bool RemoveMob(uint16 delete_id); bool RemoveMob(uint16 delete_id);
@ -266,6 +272,7 @@ public:
Entity *GetEntityCorpse(uint16 id); Entity *GetEntityCorpse(uint16 id);
Entity *GetEntityTrap(uint16 id); Entity *GetEntityTrap(uint16 id);
Entity *GetEntityBeacon(uint16 id); Entity *GetEntityBeacon(uint16 id);
Entity *GetEntityEncounter(uint16 id);
Entity *GetEntityMob(const char *name); Entity *GetEntityMob(const char *name);
Entity *GetEntityCorpse(const char *name); Entity *GetEntityCorpse(const char *name);
@ -448,6 +455,7 @@ private:
std::unordered_map<uint16, Doors *> door_list; std::unordered_map<uint16, Doors *> door_list;
std::unordered_map<uint16, Trap *> trap_list; std::unordered_map<uint16, Trap *> trap_list;
std::unordered_map<uint16, Beacon *> beacon_list; std::unordered_map<uint16, Beacon *> beacon_list;
std::unordered_map<uint16, Encounter *> encounter_list;
std::list<NPC *> proximity_list; std::list<NPC *> proximity_list;
std::list<Group *> group_list; std::list<Group *> group_list;
std::list<Raid *> raid_list; std::list<Raid *> raid_list;

View File

@ -59,6 +59,97 @@ static uint32 MaxBankedRaidLeadershipPoints(int Level)
return 10; return 10;
} }
uint32 Client::CalcEXP(uint8 conlevel) {
uint32 in_add_exp = EXP_FORMULA;
if((XPRate != 0))
in_add_exp = static_cast<uint32>(in_add_exp * (static_cast<float>(XPRate) / 100.0f));
float totalmod = 1.0;
float zemmod = 1.0;
//get modifiers
if(RuleR(Character, ExpMultiplier) >= 0){
totalmod *= RuleR(Character, ExpMultiplier);
}
if(zone->newzone_data.zone_exp_multiplier >= 0){
zemmod *= zone->newzone_data.zone_exp_multiplier;
}
if(RuleB(Character,UseRaceClassExpBonuses))
{
if(GetBaseRace() == HALFLING){
totalmod *= 1.05;
}
if(GetClass() == ROGUE || GetClass() == WARRIOR){
totalmod *= 1.05;
}
}
if(zone->IsHotzone())
{
totalmod += RuleR(Zone, HotZoneBonus);
}
in_add_exp = uint32(float(in_add_exp) * totalmod * zemmod);
if(RuleB(Character,UseXPConScaling))
{
if (conlevel != 0xFF) {
switch (conlevel)
{
case CON_GREEN:
in_add_exp = 0;
return 0;
case CON_LIGHTBLUE:
in_add_exp = in_add_exp * RuleI(Character, LightBlueModifier)/100;
break;
case CON_BLUE:
in_add_exp = in_add_exp * RuleI(Character, BlueModifier)/100;
break;
case CON_WHITE:
in_add_exp = in_add_exp * RuleI(Character, WhiteModifier)/100;
break;
case CON_YELLOW:
in_add_exp = in_add_exp * RuleI(Character, YellowModifier)/100;
break;
case CON_RED:
in_add_exp = in_add_exp * RuleI(Character, RedModifier)/100;
break;
}
}
}
float aatotalmod = 1.0;
if(zone->newzone_data.zone_exp_multiplier >= 0){
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
}
if(RuleB(Character,UseRaceClassExpBonuses))
{
if(GetBaseRace() == HALFLING){
aatotalmod *= 1.05;
}
if(GetClass() == ROGUE || GetClass() == WARRIOR){
aatotalmod *= 1.05;
}
}
if(RuleB(Zone, LevelBasedEXPMods)){
if(zone->level_exp_mod[GetLevel()].ExpMod){
in_add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
}
}
return in_add_exp;
}
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) { void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
ItemScriptStopReturn(); ItemScriptStopReturn();
@ -78,7 +169,7 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
//figure out how much of this goes to AAs //figure out how much of this goes to AAs
add_aaxp = add_exp * m_epp.perAA / 100; add_aaxp = add_exp * m_epp.perAA / 100;
//take that ammount away from regular exp //take that amount away from regular exp
add_exp -= add_aaxp; add_exp -= add_aaxp;
float totalmod = 1.0; float totalmod = 1.0;
@ -247,12 +338,22 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
Message(13, "Error in Client::SetEXP. EXP not set."); Message(13, "Error in Client::SetEXP. EXP not set.");
return; // Must be invalid class/race return; // Must be invalid class/race
} }
uint32 i = 0;
uint32 membercount = 0;
if(GetGroup())
{
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (GetGroup()->members[i] != nullptr) {
membercount++;
}
}
}
if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) { if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) {
if (isrezzexp) if (isrezzexp)
this->Message_StringID(MT_Experience, REZ_REGAIN); this->Message_StringID(MT_Experience, REZ_REGAIN);
else{ else{
if(this->IsGrouped()) if(membercount > 1)
this->Message_StringID(MT_Experience, GAIN_GROUPXP); this->Message_StringID(MT_Experience, GAIN_GROUPXP);
else if(IsRaidGrouped()) else if(IsRaidGrouped())
Message_StringID(MT_Experience, GAIN_RAIDEXP); Message_StringID(MT_Experience, GAIN_RAIDEXP);
@ -268,12 +369,17 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
//this ammount of exp (once these loops complete) //this ammount of exp (once these loops complete)
uint16 check_level = GetLevel()+1; uint16 check_level = GetLevel()+1;
//see if we gained any levels //see if we gained any levels
bool level_increase = true;
int8 level_count = 0;
while (set_exp >= GetEXPForLevel(check_level)) { while (set_exp >= GetEXPForLevel(check_level)) {
check_level++; check_level++;
if (check_level > 127) { //hard level cap if (check_level > 127) { //hard level cap
check_level = 127; check_level = 127;
break; break;
} }
level_count++;
if(GetMercID()) if(GetMercID())
UpdateMercLevel(); UpdateMercLevel();
} }
@ -284,6 +390,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
check_level = 2; check_level = 2;
break; break;
} }
level_increase = false;
if(GetMercID()) if(GetMercID())
UpdateMercLevel(); UpdateMercLevel();
} }
@ -364,17 +471,21 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
if ((GetLevel() != check_level) && !(check_level >= maxlevel)) { if ((GetLevel() != check_level) && !(check_level >= maxlevel)) {
char val1[20]={0}; char val1[20]={0};
if (GetLevel() == check_level-1){ if (level_increase)
Message_StringID(MT_Experience, GAIN_LEVEL,ConvertArray(check_level,val1)); {
SendLevelAppearance(); if (level_count == 1)
/* Message(15, "You have gained a level! Welcome to level %i!", check_level); */ Message_StringID(MT_Experience, GAIN_LEVEL, ConvertArray(check_level, val1));
} else
if (GetLevel() == check_level){ Message(15, "Welcome to level %i!", check_level);
Message_StringID(MT_Experience, LOSE_LEVEL,ConvertArray(check_level,val1));
/* Message(15, "You lost a level! You are now level %i!", check_level); */ if (check_level == RuleI(Character, DeathItemLossLevel))
Message_StringID(15, CORPSE_ITEM_LOST);
if (check_level == RuleI(Character, DeathExpLossLevel))
Message_StringID(15, CORPSE_EXP_LOST);
} }
else else
Message(15, "Welcome to level %i!", check_level); Message_StringID(MT_Experience, LOSE_LEVEL, ConvertArray(check_level, val1));
#ifdef BOTS #ifdef BOTS
uint8 myoldlevel = GetLevel(); uint8 myoldlevel = GetLevel();
@ -594,8 +705,8 @@ void Group::SplitExp(uint32 exp, Mob* other) {
groupmod = 2.16; groupmod = 2.16;
else else
groupmod = 1.0; groupmod = 1.0;
if(membercount > 1 && membercount <= 6)
groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier))); groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier)));
int conlevel = Mob::GetLevelCon(maxlevel, other->GetLevel()); int conlevel = Mob::GetLevelCon(maxlevel, other->GetLevel());
if(conlevel == CON_GREEN) if(conlevel == CON_GREEN)

View File

@ -123,29 +123,6 @@ void Mob::ProcessFlee()
} }
} }
float Mob::GetFearSpeed()
{
if (flee_mode) {
//we know ratio < FLEE_HP_RATIO
float speed = GetBaseRunspeed();
float ratio = GetHPRatio();
float multiplier = RuleR(Combat, FleeMultiplier);
if (GetSnaredAmount() > 40)
multiplier = multiplier / 6.0f;
speed = speed * ratio * multiplier / 100;
//NPC will eventually stop. Snares speeds this up.
if (speed < 0.09)
speed = 0.0001f;
return speed;
}
// fear and blind use their normal run speed
return GetRunspeed();
}
void Mob::CalculateNewFearpoint() void Mob::CalculateNewFearpoint()
{ {
if(RuleB(Pathing, Fear) && zone->pathing) if(RuleB(Pathing, Fear) && zone->pathing)

View File

@ -185,26 +185,35 @@ bool Client::CanFish() {
rodPosition.x = m_Position.x + RodLength * sin(HeadingDegrees * M_PI/180.0f); rodPosition.x = m_Position.x + RodLength * sin(HeadingDegrees * M_PI/180.0f);
rodPosition.y = m_Position.y + RodLength * cos(HeadingDegrees * M_PI/180.0f); rodPosition.y = m_Position.y + RodLength * cos(HeadingDegrees * M_PI/180.0f);
rodPosition.z = m_Position.z;
// Do BestZ to find where the line hanging from the rod intersects the water (if it is water). float bestz = zone->zonemap->FindBestZ(rodPosition, nullptr);
// and go 1 unit into the water. float len = m_Position.z - bestz;
glm::vec3 dest; if(len > LineLength || len < 0.0f) {
dest.x = rodPosition.x; Message_StringID(MT_Skills, FISHING_LAND);
dest.y = rodPosition.y;
dest.z = m_Position.z+10;
rodPosition.z = zone->zonemap->FindBestZ(dest, nullptr) + 4;
bool in_lava = zone->watermap->InLava(rodPosition);
bool in_water = zone->watermap->InWater(rodPosition) || zone->watermap->InVWater(rodPosition);
//Message(0, "Rod is at %4.3f, %4.3f, %4.3f, InWater says %d, InLava says %d", RodX, RodY, RodZ, in_water, in_lava);
if (in_lava) {
Message_StringID(MT_Skills, FISHING_LAVA); //Trying to catch a fire elemental or something?
return false; return false;
} }
if((!in_water) || (m_Position.z-rodPosition.z)>LineLength) { //Didn't hit the water OR the water is too far below us
Message_StringID(MT_Skills, FISHING_LAND); //Trying to catch land sharks perhaps? float step_size = RuleR(Watermap, FishingLineStepSize);
return false;
for(float i = 0.0f; i < len; i += step_size) {
glm::vec3 dest(rodPosition.x, rodPosition.y, m_Position.z - i);
bool in_lava = zone->watermap->InLava(dest);
bool in_water = zone->watermap->InWater(dest) || zone->watermap->InVWater(dest);
if (in_lava) {
Message_StringID(MT_Skills, FISHING_LAVA); //Trying to catch a fire elemental or something?
return false;
}
if(in_water) {
return true;
}
} }
Message_StringID(MT_Skills, FISHING_LAND);
return false;
} }
return true; return true;
} }

View File

@ -606,7 +606,7 @@ void Client::DropItem(int16 slot_id)
// Take control of item in client inventory // Take control of item in client inventory
ItemInst *inst = m_inv.PopItem(slot_id); ItemInst *inst = m_inv.PopItem(slot_id);
if(inst) { if(inst) {
int i = parse->EventItem(EVENT_DROP_ITEM, this, inst, nullptr, "", 0); int i = parse->EventItem(EVENT_DROP_ITEM, this, inst, nullptr, "", slot_id);
if(i != 0) { if(i != 0) {
safe_delete(inst); safe_delete(inst);
} }
@ -2199,6 +2199,187 @@ bool Client::DecreaseByID(uint32 type, uint8 amt) {
return true; return true;
} }
static bool IsSummonedBagID(uint32 item_id)
{
switch (item_id) {
case 17147: // "Spiritual Prismatic Pack"
case 17303: // "Spirit Pouch"
case 17304: // "Dimensional Pocket"
case 17305: // "Dimensional Hole"
case 17306: // "Glowing Backpack"
case 17307: // "Quiver of Marr"
case 17308: // "Bandoleer of Luclin"
case 17309: // "Pouch of Quellious"
case 17310: // "Phantom Satchel"
case 17510: // "Glowing Chest"
case 17900: // "Grandmaster's Satchel"
case 57260: // "Glowing Backpack"
case 57261: // "Pouch of Quellious"
case 57262: // "Phantom Satchel"
case 60224: // "Faded-Glyph Tablet"
case 95199: // "Beginner Artisan Satchel"
case 95200: // "Apprentice Artisan Satchel"
case 95201: // "Freshman Artisan Satchel"
case 95202: // "Journeyman Artisan Satchel"
case 95203: // "Expert Artisan Satchel"
case 95204: // "Master Artisan Satchel"
//case 96960: // "Artisan Satchel" - no 12-slot disenchanted bags
return true;
default:
return false;
}
}
static uint32 GetDisenchantedBagID(uint8 bag_slots)
{
switch (bag_slots) {
case 4:
return 77772; // "Small Disenchanted Backpack"
case 6:
return 77774; // "Disenchanted Backpack"
case 8:
return 77776; // "Large Disenchanted Backpack"
case 10:
return 77778; // "Huge Disenchanted Backpack"
default:
return 0; // no suitable conversions
}
}
static bool CopyBagContents(ItemInst* new_bag, const ItemInst* old_bag)
{
if (!new_bag || !old_bag) { return false; }
if (new_bag->GetItem()->BagSlots < old_bag->GetItem()->BagSlots) { return false; }
// pre-check for size comparisons
for (auto bag_slot = 0; bag_slot < old_bag->GetItem()->BagSlots; ++bag_slot) {
if (!old_bag->GetItem(bag_slot)) { continue; }
if (old_bag->GetItem(bag_slot)->GetItem()->Size > new_bag->GetItem()->BagSize) {
Log.Out(Logs::General, Logs::Inventory, "Copy Bag Contents: Failure due to %s is larger than size capacity of %s (%i > %i)",
old_bag->GetItem(bag_slot)->GetItem()->Name, new_bag->GetItem()->Name, old_bag->GetItem(bag_slot)->GetItem()->Size, new_bag->GetItem()->BagSize);
return false;
}
}
for (auto bag_slot = 0; bag_slot < old_bag->GetItem()->BagSlots; ++bag_slot) {
if (!old_bag->GetItem(bag_slot)) { continue; }
new_bag->PutItem(bag_slot, *(old_bag->GetItem(bag_slot)));
}
return true;
}
void Client::DisenchantSummonedBags(bool client_update)
{
for (auto slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; ++slot_id) {
auto inst = m_inv[slot_id];
if (!inst) { continue; }
if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; }
if (inst->GetItem()->ItemClass != ItemClassContainer) { continue; }
if (inst->GetTotalItemCount() == 1) { continue; }
auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots);
if (!new_id) { continue; }
auto new_item = database.GetItem(new_id);
if (!new_item) { continue; }
auto new_inst = database.CreateBaseItem(new_item);
if (!new_inst) { continue; }
if (CopyBagContents(new_inst, inst)) {
Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id);
PutItemInInventory(slot_id, *new_inst, client_update);
}
safe_delete(new_inst);
}
for (auto slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; ++slot_id) {
auto inst = m_inv[slot_id];
if (!inst) { continue; }
if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; }
if (inst->GetItem()->ItemClass != ItemClassContainer) { continue; }
if (inst->GetTotalItemCount() == 1) { continue; }
auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots);
if (!new_id) { continue; }
auto new_item = database.GetItem(new_id);
if (!new_item) { continue; }
auto new_inst = database.CreateBaseItem(new_item);
if (!new_inst) { continue; }
if (CopyBagContents(new_inst, inst)) {
Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id);
PutItemInInventory(slot_id, *new_inst, client_update);
}
safe_delete(new_inst);
}
for (auto slot_id = EmuConstants::SHARED_BANK_BEGIN; slot_id <= EmuConstants::SHARED_BANK_END; ++slot_id) {
auto inst = m_inv[slot_id];
if (!inst) { continue; }
if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; }
if (inst->GetItem()->ItemClass != ItemClassContainer) { continue; }
if (inst->GetTotalItemCount() == 1) { continue; }
auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots);
if (!new_id) { continue; }
auto new_item = database.GetItem(new_id);
if (!new_item) { continue; }
auto new_inst = database.CreateBaseItem(new_item);
if (!new_inst) { continue; }
if (CopyBagContents(new_inst, inst)) {
Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id);
PutItemInInventory(slot_id, *new_inst, client_update);
}
safe_delete(new_inst);
}
while (!m_inv.CursorEmpty()) {
auto inst = m_inv[MainCursor];
if (!inst) { break; }
if (!IsSummonedBagID(inst->GetItem()->ID)) { break; }
if (inst->GetItem()->ItemClass != ItemClassContainer) { break; }
if (inst->GetTotalItemCount() == 1) { break; }
auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots);
if (!new_id) { break; }
auto new_item = database.GetItem(new_id);
if (!new_item) { break; }
auto new_inst = database.CreateBaseItem(new_item);
if (!new_inst) { break; }
if (CopyBagContents(new_inst, inst)) {
Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, MainCursor);
std::list<ItemInst*> local;
local.push_front(new_inst);
m_inv.PopItem(MainCursor);
safe_delete(inst);
while (!m_inv.CursorEmpty()) {
auto limbo_inst = m_inv.PopItem(MainCursor);
if (limbo_inst == nullptr) { continue; }
local.push_back(limbo_inst);
}
for (auto iter = local.begin(); iter != local.end(); ++iter) {
auto cur_inst = *iter;
if (cur_inst == nullptr) { continue; }
m_inv.PushCursor(*cur_inst);
safe_delete(cur_inst);
}
local.clear();
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
database.SaveCursor(this->CharacterID(), s, e);
}
else {
safe_delete(new_inst); // deletes disenchanted bag if not used
}
break;
}
}
void Client::RemoveNoRent(bool client_update) void Client::RemoveNoRent(bool client_update)
{ {
for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) { for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) {

View File

@ -58,7 +58,7 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) { if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) {
float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash); float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash);
float avg_cash_roll = (float)zone->random.Real(0.0, 1.0); float avg_cash_roll = (float)zone->random.Real(0.0, 1.0);
if(avg_cash_roll < upper_chance) { if(avg_cash_roll < upper_chance) {
cash = zone->random.Int(lts->avgcoin, max_cash); cash = zone->random.Int(lts->avgcoin, max_cash);
} else { } else {
@ -332,6 +332,8 @@ void NPC::AddLootDrop(const ItemData *item2, ItemList* itemlist, int16 charges,
CastToMob()->AddProcToWeapon(item2->Proc.Effect, true); CastToMob()->AddProcToWeapon(item2->Proc.Effect, true);
eslot = MaterialPrimary; eslot = MaterialPrimary;
if (item2->Damage > 0)
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
} }
else if (foundslot == MainSecondary else if (foundslot == MainSecondary
&& (GetOwner() != nullptr || (GetLevel() >= 13 && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) && && (GetOwner() != nullptr || (GetLevel() >= 13 && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) &&
@ -342,6 +344,8 @@ void NPC::AddLootDrop(const ItemData *item2, ItemList* itemlist, int16 charges,
CastToMob()->AddProcToWeapon(item2->Proc.Effect, true); CastToMob()->AddProcToWeapon(item2->Proc.Effect, true);
eslot = MaterialSecondary; eslot = MaterialSecondary;
if (item2->Damage > 0)
SendAddPlayerState(PlayerState::SecondaryWeaponEquipped);
} }
else if (foundslot == MainHead) { else if (foundslot == MainHead) {
eslot = MaterialHead; eslot = MaterialHead;

View File

@ -1255,6 +1255,46 @@ void Lua_Client::PlayMP3(std::string file)
self->PlayMP3(file.c_str()); self->PlayMP3(file.c_str());
} }
void Lua_Client::QuestReward(Lua_Mob target) {
Lua_Safe_Call_Void();
self->QuestReward(target);
}
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper) {
Lua_Safe_Call_Void();
self->QuestReward(target, copper);
}
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver) {
Lua_Safe_Call_Void();
self->QuestReward(target, copper, silver);
}
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold) {
Lua_Safe_Call_Void();
self->QuestReward(target, copper, silver, gold);
}
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum) {
Lua_Safe_Call_Void();
self->QuestReward(target, copper, silver, gold, platinum);
}
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid) {
Lua_Safe_Call_Void();
self->QuestReward(target, copper, silver, gold, platinum, itemid);
}
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp) {
Lua_Safe_Call_Void();
self->QuestReward(target, copper, silver, gold, platinum, itemid, exp);
}
void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction) {
Lua_Safe_Call_Void();
self->QuestReward(target, copper, silver, gold, platinum, itemid, exp, faction);
}
luabind::scope lua_register_client() { luabind::scope lua_register_client() {
return luabind::class_<Lua_Client, Lua_Mob>("Client") return luabind::class_<Lua_Client, Lua_Mob>("Client")
.def(luabind::constructor<>()) .def(luabind::constructor<>())
@ -1504,7 +1544,15 @@ luabind::scope lua_register_client() {
.def("SetConsumption", (void(Lua_Client::*)(int, int))&Lua_Client::SetConsumption) .def("SetConsumption", (void(Lua_Client::*)(int, int))&Lua_Client::SetConsumption)
.def("SendMarqueeMessage", (void(Lua_Client::*)(uint32, uint32, uint32, uint32, uint32, std::string))&Lua_Client::SendMarqueeMessage) .def("SendMarqueeMessage", (void(Lua_Client::*)(uint32, uint32, uint32, uint32, uint32, std::string))&Lua_Client::SendMarqueeMessage)
.def("SendColoredText", (void(Lua_Client::*)(uint32, std::string))&Lua_Client::SendColoredText) .def("SendColoredText", (void(Lua_Client::*)(uint32, std::string))&Lua_Client::SendColoredText)
.def("PlayMP3", (void(Lua_Client::*)(std::string))&Lua_Client::PlayMP3); .def("PlayMP3", (void(Lua_Client::*)(std::string))&Lua_Client::PlayMP3)
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob))&Lua_Client::QuestReward)
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32))&Lua_Client::QuestReward)
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32))&Lua_Client::QuestReward)
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32))&Lua_Client::QuestReward)
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward)
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward)
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward)
.def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32, bool))&Lua_Client::QuestReward);
} }
luabind::scope lua_register_inventory_where() { luabind::scope lua_register_inventory_where() {

View File

@ -278,6 +278,14 @@ public:
void SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, std::string msg); void SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, std::string msg);
void SendColoredText(uint32 type, std::string msg); void SendColoredText(uint32 type, std::string msg);
void PlayMP3(std::string file); void PlayMP3(std::string file);
void QuestReward(Lua_Mob target);
void QuestReward(Lua_Mob target, uint32 copper);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction);
}; };
#endif #endif

13
zone/lua_encounter.cpp Normal file
View File

@ -0,0 +1,13 @@
#ifdef LUA_EQEMU
#include "lua.hpp"
#include <luabind/luabind.hpp>
#include "lua_encounter.h"
#include "encounter.h"
luabind::scope lua_register_encounter() {
return luabind::class_<Lua_Encounter>("Encounter");
}
#endif

30
zone/lua_encounter.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef EQEMU_LUA_ENCOUNTER_H
#define EQEMU_LUA_ENCOUNTER_H
#ifdef LUA_EQEMU
#include "lua_ptr.h"
class Encounter;
namespace luabind {
struct scope;
class object;
}
luabind::scope lua_register_encounter();
class Lua_Encounter : public Lua_Ptr<Encounter>
{
typedef Encounter NativeType;
public:
Lua_Encounter() { SetLuaPtrData(nullptr); }
Lua_Encounter(Encounter *d) { SetLuaPtrData(reinterpret_cast<Encounter*>(d)); }
virtual ~Lua_Encounter() { }
operator Encounter*() {
return reinterpret_cast<Encounter*>(GetLuaPtrData());
}
};
#endif
#endif

View File

@ -18,6 +18,8 @@
#include "qglobals.h" #include "qglobals.h"
#include "../common/timer.h" #include "../common/timer.h"
#include "../common/eqemu_logsys.h" #include "../common/eqemu_logsys.h"
#include "encounter.h"
#include "lua_encounter.h"
struct Events { }; struct Events { };
struct Factions { }; struct Factions { };
@ -34,6 +36,8 @@ struct lua_registered_event {
extern std::map<std::string, std::list<lua_registered_event>> lua_encounter_events_registered; extern std::map<std::string, std::list<lua_registered_event>> lua_encounter_events_registered;
extern std::map<std::string, bool> lua_encounters_loaded; extern std::map<std::string, bool> lua_encounters_loaded;
extern std::map<std::string, Encounter *> lua_encounters;
extern void MapOpcodes(); extern void MapOpcodes();
extern void ClearMappedOpcode(EmuOpcode op); extern void ClearMappedOpcode(EmuOpcode op);
@ -42,19 +46,23 @@ void unregister_event(std::string package_name, std::string name, int evt);
void load_encounter(std::string name) { void load_encounter(std::string name) {
if(lua_encounters_loaded.count(name) > 0) if(lua_encounters_loaded.count(name) > 0)
return; return;
Encounter *enc = new Encounter(name.c_str());
entity_list.AddEncounter(enc);
lua_encounters[name] = enc;
lua_encounters_loaded[name] = true; lua_encounters_loaded[name] = true;
parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, 0); parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, "", 0);
} }
void load_encounter_with_data(std::string name, std::string info_str) { void load_encounter_with_data(std::string name, std::string info_str) {
if(lua_encounters_loaded.count(name) > 0) if(lua_encounters_loaded.count(name) > 0)
return; return;
Encounter *enc = new Encounter(name.c_str());
entity_list.AddEncounter(enc);
lua_encounters[name] = enc;
lua_encounters_loaded[name] = true; lua_encounters_loaded[name] = true;
std::vector<EQEmu::Any> info_ptrs; std::vector<EQEmu::Any> info_ptrs;
info_ptrs.push_back(&info_str); info_ptrs.push_back(&info_str);
parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, 0, &info_ptrs); parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, "", 0, &info_ptrs);
} }
void unload_encounter(std::string name) { void unload_encounter(std::string name) {
@ -80,8 +88,10 @@ void unload_encounter(std::string name) {
} }
} }
lua_encounters[name]->Depop();
lua_encounters.erase(name);
lua_encounters_loaded.erase(name); lua_encounters_loaded.erase(name);
parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0); parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, "", 0);
} }
void unload_encounter_with_data(std::string name, std::string info_str) { void unload_encounter_with_data(std::string name, std::string info_str) {
@ -109,10 +119,12 @@ void unload_encounter_with_data(std::string name, std::string info_str) {
} }
} }
lua_encounters[name]->Depop();
lua_encounters.erase(name);
lua_encounters_loaded.erase(name); lua_encounters_loaded.erase(name);
std::vector<EQEmu::Any> info_ptrs; std::vector<EQEmu::Any> info_ptrs;
info_ptrs.push_back(&info_str); info_ptrs.push_back(&info_str);
parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0, &info_ptrs); parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, "", 0, &info_ptrs);
} }
void register_event(std::string package_name, std::string name, int evt, luabind::adl::object func) { void register_event(std::string package_name, std::string name, int evt, luabind::adl::object func) {
@ -285,6 +297,10 @@ void lua_set_timer(const char *timer, int time_ms, Lua_Mob mob) {
quest_manager.settimerMS(timer, time_ms, mob); quest_manager.settimerMS(timer, time_ms, mob);
} }
void lua_set_timer(const char *timer, int time_ms, Lua_Encounter enc) {
quest_manager.settimerMS(timer, time_ms, enc);
}
void lua_stop_timer(const char *timer) { void lua_stop_timer(const char *timer) {
quest_manager.stoptimer(timer); quest_manager.stoptimer(timer);
} }
@ -297,6 +313,10 @@ void lua_stop_timer(const char *timer, Lua_Mob mob) {
quest_manager.stoptimer(timer, mob); quest_manager.stoptimer(timer, mob);
} }
void lua_stop_timer(const char *timer, Lua_Encounter enc) {
quest_manager.stoptimer(timer, enc);
}
void lua_stop_all_timers() { void lua_stop_all_timers() {
quest_manager.stopalltimers(); quest_manager.stopalltimers();
} }
@ -309,6 +329,10 @@ void lua_stop_all_timers(Lua_Mob mob) {
quest_manager.stopalltimers(mob); quest_manager.stopalltimers(mob);
} }
void lua_stop_all_timers(Lua_Encounter enc) {
quest_manager.stopalltimers(enc);
}
void lua_depop() { void lua_depop() {
quest_manager.depop(0); quest_manager.depop(0);
} }
@ -386,7 +410,11 @@ void lua_create_guild(const char *name, const char *leader) {
} }
void lua_set_time(int hour, int min) { void lua_set_time(int hour, int min) {
quest_manager.settime(hour, min); quest_manager.settime(hour, min, true);
}
void lua_set_time(int hour, int min, bool update_world) {
quest_manager.settime(hour, min, update_world);
} }
void lua_signal(int npc_id, int signal_id) { void lua_signal(int npc_id, int signal_id) {
@ -979,7 +1007,7 @@ int lua_get_zone_weather() {
luabind::adl::object lua_get_zone_time(lua_State *L) { luabind::adl::object lua_get_zone_time(lua_State *L) {
TimeOfDay_Struct eqTime; TimeOfDay_Struct eqTime;
zone->zone_time.getEQTimeOfDay(time(0), &eqTime); zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eqTime);
luabind::adl::object ret = luabind::newtable(L); luabind::adl::object ret = luabind::newtable(L);
ret["zone_hour"] = eqTime.hour - 1; ret["zone_hour"] = eqTime.hour - 1;
@ -1442,12 +1470,15 @@ luabind::scope lua_register_general() {
luabind::def("set_timer", (void(*)(const char*, int))&lua_set_timer), luabind::def("set_timer", (void(*)(const char*, int))&lua_set_timer),
luabind::def("set_timer", (void(*)(const char*, int, Lua_ItemInst))&lua_set_timer), luabind::def("set_timer", (void(*)(const char*, int, Lua_ItemInst))&lua_set_timer),
luabind::def("set_timer", (void(*)(const char*, int, Lua_Mob))&lua_set_timer), luabind::def("set_timer", (void(*)(const char*, int, Lua_Mob))&lua_set_timer),
luabind::def("set_timer", (void(*)(const char*, int, Lua_Encounter))&lua_set_timer),
luabind::def("stop_timer", (void(*)(const char*))&lua_stop_timer), luabind::def("stop_timer", (void(*)(const char*))&lua_stop_timer),
luabind::def("stop_timer", (void(*)(const char*, Lua_ItemInst))&lua_stop_timer), luabind::def("stop_timer", (void(*)(const char*, Lua_ItemInst))&lua_stop_timer),
luabind::def("stop_timer", (void(*)(const char*, Lua_Mob))&lua_stop_timer), luabind::def("stop_timer", (void(*)(const char*, Lua_Mob))&lua_stop_timer),
luabind::def("stop_timer", (void(*)(const char*, Lua_Encounter))&lua_stop_timer),
luabind::def("stop_all_timers", (void(*)(void))&lua_stop_all_timers), luabind::def("stop_all_timers", (void(*)(void))&lua_stop_all_timers),
luabind::def("stop_all_timers", (void(*)(Lua_ItemInst))&lua_stop_all_timers), luabind::def("stop_all_timers", (void(*)(Lua_ItemInst))&lua_stop_all_timers),
luabind::def("stop_all_timers", (void(*)(Lua_Mob))&lua_stop_all_timers), luabind::def("stop_all_timers", (void(*)(Lua_Mob))&lua_stop_all_timers),
luabind::def("stop_all_timers", (void(*)(Lua_Encounter))&lua_stop_all_timers),
luabind::def("depop", (void(*)(void))&lua_depop), luabind::def("depop", (void(*)(void))&lua_depop),
luabind::def("depop", (void(*)(int))&lua_depop), luabind::def("depop", (void(*)(int))&lua_depop),
luabind::def("depop_with_timer", (void(*)(void))&lua_depop_with_timer), luabind::def("depop_with_timer", (void(*)(void))&lua_depop_with_timer),
@ -1467,7 +1498,8 @@ luabind::scope lua_register_general() {
luabind::def("set_sky", &lua_set_sky), luabind::def("set_sky", &lua_set_sky),
luabind::def("set_guild", &lua_set_guild), luabind::def("set_guild", &lua_set_guild),
luabind::def("create_guild", &lua_create_guild), luabind::def("create_guild", &lua_create_guild),
luabind::def("set_time", &lua_set_time), luabind::def("set_time", (void(*)(int, int))&lua_set_time),
luabind::def("set_time", (void(*)(int, int, bool))&lua_set_time),
luabind::def("signal", (void(*)(int,int))&lua_signal), luabind::def("signal", (void(*)(int,int))&lua_signal),
luabind::def("signal", (void(*)(int,int,int))&lua_signal), luabind::def("signal", (void(*)(int,int,int))&lua_signal),
luabind::def("set_global", &lua_set_global), luabind::def("set_global", &lua_set_global),

View File

@ -1590,26 +1590,6 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) {
beard, aa_title, drakkin_heritage, drakkin_tattoo, drakkin_details, size); beard, aa_title, drakkin_heritage, drakkin_tattoo, drakkin_details, size);
} }
void Lua_Mob::QuestReward(Lua_Client c) {
Lua_Safe_Call_Void();
self->QuestReward(c);
}
void Lua_Mob::QuestReward(Lua_Client c, uint32 silver) {
Lua_Safe_Call_Void();
self->QuestReward(c, silver);
}
void Lua_Mob::QuestReward(Lua_Client c, uint32 silver, uint32 gold) {
Lua_Safe_Call_Void();
self->QuestReward(c, silver, gold);
}
void Lua_Mob::QuestReward(Lua_Client c, uint32 silver, uint32 gold, uint32 platinum) {
Lua_Safe_Call_Void();
self->QuestReward(c, silver, gold, platinum);
}
void Lua_Mob::CameraEffect(uint32 duration, uint32 intensity) { void Lua_Mob::CameraEffect(uint32 duration, uint32 intensity) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->CameraEffect(duration, intensity); self->CameraEffect(duration, intensity);
@ -1651,6 +1631,11 @@ void Lua_Mob::TempName(const char *newname) {
self->TempName(newname); self->TempName(newname);
} }
std::string Lua_Mob::GetGlobal(const char *varname) {
Lua_Safe_Call_String();
return self->GetGlobal(varname);
}
void Lua_Mob::SetGlobal(const char *varname, const char *newvalue, int options, const char *duration) { void Lua_Mob::SetGlobal(const char *varname, const char *newvalue, int options, const char *duration) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->SetGlobal(varname, newvalue, options, duration); self->SetGlobal(varname, newvalue, options, duration);
@ -1866,6 +1851,10 @@ int Lua_Mob::CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite
return self->CanBuffStack(spell_id, caster_level, fail_if_overwrite); return self->CanBuffStack(spell_id, caster_level, fail_if_overwrite);
} }
void Lua_Mob::SetPseudoRoot(bool in) {
Lua_Safe_Call_Void();
self->SetPseudoRoot(in);
}
luabind::scope lua_register_mob() { luabind::scope lua_register_mob() {
return luabind::class_<Lua_Mob, Lua_Entity>("Mob") return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
@ -2132,10 +2121,6 @@ luabind::scope lua_register_mob() {
.def("SetRace", (void(Lua_Mob::*)(int))&Lua_Mob::SetRace) .def("SetRace", (void(Lua_Mob::*)(int))&Lua_Mob::SetRace)
.def("SetGender", (void(Lua_Mob::*)(int))&Lua_Mob::SetGender) .def("SetGender", (void(Lua_Mob::*)(int))&Lua_Mob::SetGender)
.def("SendIllusionPacket", (void(Lua_Mob::*)(luabind::adl::object))&Lua_Mob::SendIllusionPacket) .def("SendIllusionPacket", (void(Lua_Mob::*)(luabind::adl::object))&Lua_Mob::SendIllusionPacket)
.def("QuestReward", (void(Lua_Mob::*)(Lua_Client))&Lua_Mob::QuestReward)
.def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32))&Lua_Mob::QuestReward)
.def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32,uint32))&Lua_Mob::QuestReward)
.def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32,uint32,uint32))&Lua_Mob::QuestReward)
.def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32))&Lua_Mob::CameraEffect) .def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32))&Lua_Mob::CameraEffect)
.def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client))&Lua_Mob::CameraEffect) .def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client))&Lua_Mob::CameraEffect)
.def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client,bool))&Lua_Mob::CameraEffect) .def("CameraEffect", (void(Lua_Mob::*)(uint32,uint32,Lua_Client,bool))&Lua_Mob::CameraEffect)
@ -2144,6 +2129,7 @@ luabind::scope lua_register_mob() {
.def("SendSpellEffect", (void(Lua_Mob::*)(uint32,uint32,uint32,bool,uint32,bool,Lua_Client))&Lua_Mob::SendSpellEffect) .def("SendSpellEffect", (void(Lua_Mob::*)(uint32,uint32,uint32,bool,uint32,bool,Lua_Client))&Lua_Mob::SendSpellEffect)
.def("TempName", (void(Lua_Mob::*)(void))&Lua_Mob::TempName) .def("TempName", (void(Lua_Mob::*)(void))&Lua_Mob::TempName)
.def("TempName", (void(Lua_Mob::*)(const char*))&Lua_Mob::TempName) .def("TempName", (void(Lua_Mob::*)(const char*))&Lua_Mob::TempName)
.def("GetGlobal", (std::string(Lua_Mob::*)(const char*))&Lua_Mob::GetGlobal)
.def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*))&Lua_Mob::SetGlobal) .def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*))&Lua_Mob::SetGlobal)
.def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*,Lua_Mob))&Lua_Mob::SetGlobal) .def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*,Lua_Mob))&Lua_Mob::SetGlobal)
.def("TarGlobal", (void(Lua_Mob::*)(const char*,const char*,const char*,int,int,int))&Lua_Mob::TarGlobal) .def("TarGlobal", (void(Lua_Mob::*)(const char*,const char*,const char*,int,int,int))&Lua_Mob::TarGlobal)
@ -2186,7 +2172,8 @@ luabind::scope lua_register_mob() {
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int))&Lua_Mob::BuffFadeBySlot) .def("BuffFadeBySlot", (void(Lua_Mob::*)(int))&Lua_Mob::BuffFadeBySlot)
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot) .def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot)
.def("CanBuffStack", (int(Lua_Mob::*)(int,int))&Lua_Mob::CanBuffStack) .def("CanBuffStack", (int(Lua_Mob::*)(int,int))&Lua_Mob::CanBuffStack)
.def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack); .def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack)
.def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot);
} }
luabind::scope lua_register_special_abilities() { luabind::scope lua_register_special_abilities() {

View File

@ -169,7 +169,7 @@ public:
bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost); bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost);
bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot); bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot);
bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration); bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration);
bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration, bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration,
int resist_adjust); int resist_adjust);
bool SpellFinished(int spell_id, Lua_Mob target); bool SpellFinished(int spell_id, Lua_Mob target);
bool SpellFinished(int spell_id, Lua_Mob target, int slot); bool SpellFinished(int spell_id, Lua_Mob target, int slot);
@ -296,10 +296,6 @@ public:
void SetRace(int in); void SetRace(int in);
void SetGender(int in); void SetGender(int in);
void SendIllusionPacket(luabind::adl::object illusion); void SendIllusionPacket(luabind::adl::object illusion);
void QuestReward(Lua_Client c);
void QuestReward(Lua_Client c, uint32 silver);
void QuestReward(Lua_Client c, uint32 silver, uint32 gold);
void QuestReward(Lua_Client c, uint32 silver, uint32 gold, uint32 platinum);
void CameraEffect(uint32 duration, uint32 intensity); void CameraEffect(uint32 duration, uint32 intensity);
void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c); void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c);
void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c, bool global); void CameraEffect(uint32 duration, uint32 intensity, Lua_Client c, bool global);
@ -311,6 +307,7 @@ public:
uint32 unk020, bool perm_effect, Lua_Client c); uint32 unk020, bool perm_effect, Lua_Client c);
void TempName(); void TempName();
void TempName(const char *newname); void TempName(const char *newname);
std::string GetGlobal(const char *varname);
void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration); void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration);
void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Lua_Mob other); void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Lua_Mob other);
void TarGlobal(const char *varname, const char *value, const char *duration, int npc_id, int char_id, int zone_id); void TarGlobal(const char *varname, const char *value, const char *duration, int npc_id, int char_id, int zone_id);
@ -355,6 +352,7 @@ public:
void BuffFadeBySlot(int slot, bool recalc_bonuses); void BuffFadeBySlot(int slot, bool recalc_bonuses);
int CanBuffStack(int spell_id, int caster_level); int CanBuffStack(int spell_id, int caster_level);
int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite); int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite);
void SetPseudoRoot(bool in);
}; };
#endif #endif

View File

@ -18,7 +18,7 @@ Lua_Packet::Lua_Packet(int opcode, int size, bool raw) {
if(raw) { if(raw) {
SetLuaPtrData(new EQApplicationPacket(OP_Unknown, size)); SetLuaPtrData(new EQApplicationPacket(OP_Unknown, size));
owned_ = true; owned_ = true;
EQApplicationPacket *self = reinterpret_cast<EQApplicationPacket*>(d_); EQApplicationPacket *self = reinterpret_cast<EQApplicationPacket*>(d_);
self->SetOpcodeBypass(opcode); self->SetOpcodeBypass(opcode);
} else { } else {
@ -692,8 +692,8 @@ luabind::scope lua_register_packet_opcodes() {
luabind::value("VetClaimRequest", static_cast<int>(OP_VetClaimRequest)), luabind::value("VetClaimRequest", static_cast<int>(OP_VetClaimRequest)),
luabind::value("VetClaimReply", static_cast<int>(OP_VetClaimReply)), luabind::value("VetClaimReply", static_cast<int>(OP_VetClaimReply)),
luabind::value("WeaponEquip1", static_cast<int>(OP_WeaponEquip1)), luabind::value("WeaponEquip1", static_cast<int>(OP_WeaponEquip1)),
luabind::value("WeaponEquip2", static_cast<int>(OP_WeaponEquip2)), luabind::value("PlayerStateAdd", static_cast<int>(OP_PlayerStateAdd)),
luabind::value("WeaponUnequip2", static_cast<int>(OP_WeaponUnequip2)), luabind::value("PlayerStateRemove", static_cast<int>(OP_PlayerStateRemove)),
luabind::value("WorldLogout", static_cast<int>(OP_WorldLogout)), luabind::value("WorldLogout", static_cast<int>(OP_WorldLogout)),
luabind::value("SessionReady", static_cast<int>(OP_SessionReady)), luabind::value("SessionReady", static_cast<int>(OP_SessionReady)),
luabind::value("Login", static_cast<int>(OP_Login)), luabind::value("Login", static_cast<int>(OP_Login)),

View File

@ -34,6 +34,7 @@
#include "questmgr.h" #include "questmgr.h"
#include "zone.h" #include "zone.h"
#include "lua_parser.h" #include "lua_parser.h"
#include "lua_encounter.h"
const char *LuaEvents[_LargestEventID] = { const char *LuaEvents[_LargestEventID] = {
"event_say", "event_say",
@ -128,6 +129,7 @@ struct lua_registered_event {
std::map<std::string, std::list<lua_registered_event>> lua_encounter_events_registered; std::map<std::string, std::list<lua_registered_event>> lua_encounter_events_registered;
std::map<std::string, bool> lua_encounters_loaded; std::map<std::string, bool> lua_encounters_loaded;
std::map<std::string, Encounter *> lua_encounters;
LuaParser::LuaParser() { LuaParser::LuaParser() {
for(int i = 0; i < _LargestEventID; ++i) { for(int i = 0; i < _LargestEventID; ++i) {
@ -135,6 +137,7 @@ LuaParser::LuaParser() {
PlayerArgumentDispatch[i] = handle_player_null; PlayerArgumentDispatch[i] = handle_player_null;
ItemArgumentDispatch[i] = handle_item_null; ItemArgumentDispatch[i] = handle_item_null;
SpellArgumentDispatch[i] = handle_spell_null; SpellArgumentDispatch[i] = handle_spell_null;
EncounterArgumentDispatch[i] = handle_encounter_null;
} }
NPCArgumentDispatch[EVENT_SAY] = handle_npc_event_say; NPCArgumentDispatch[EVENT_SAY] = handle_npc_event_say;
@ -213,6 +216,10 @@ LuaParser::LuaParser() {
SpellArgumentDispatch[EVENT_SPELL_FADE] = handle_spell_fade; SpellArgumentDispatch[EVENT_SPELL_FADE] = handle_spell_fade;
SpellArgumentDispatch[EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE] = handle_translocate_finish; SpellArgumentDispatch[EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE] = handle_translocate_finish;
EncounterArgumentDispatch[EVENT_TIMER] = handle_encounter_timer;
EncounterArgumentDispatch[EVENT_ENCOUNTER_LOAD] = handle_encounter_load;
EncounterArgumentDispatch[EVENT_ENCOUNTER_UNLOAD] = handle_encounter_unload;
L = nullptr; L = nullptr;
} }
@ -575,7 +582,7 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc,
return 0; return 0;
} }
int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers) { int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers) {
evt = ConvertLuaEvent(evt); evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) { if(evt >= _LargestEventID) {
return 0; return 0;
@ -587,10 +594,10 @@ int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, uint
return 0; return 0;
} }
return _EventEncounter(package_name, evt, encounter_name, extra_data, extra_pointers); return _EventEncounter(package_name, evt, encounter_name, data, extra_data, extra_pointers);
} }
int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data, int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
const char *sub_name = LuaEvents[evt]; const char *sub_name = LuaEvents[evt];
@ -604,13 +611,12 @@ int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::
lua_pushstring(L, encounter_name.c_str()); lua_pushstring(L, encounter_name.c_str());
lua_setfield(L, -2, "name"); lua_setfield(L, -2, "name");
if(extra_pointers) { Encounter *enc = lua_encounters[encounter_name];
std::string *str = EQEmu::any_cast<std::string*>(extra_pointers->at(0));
lua_pushstring(L, str->c_str());
lua_setfield(L, -2, "data");
}
quest_manager.StartQuest(nullptr, nullptr, nullptr, encounter_name); auto arg_function = EncounterArgumentDispatch[evt];
arg_function(this, L, enc, data, extra_data, extra_pointers);
quest_manager.StartQuest(enc, nullptr, nullptr, encounter_name);
if(lua_pcall(L, 1, 1, 0)) { if(lua_pcall(L, 1, 1, 0)) {
std::string error = lua_tostring(L, -1); std::string error = lua_tostring(L, -1);
AddError(error); AddError(error);
@ -786,6 +792,11 @@ void LuaParser::ReloadQuests() {
lua_encounter_events_registered.clear(); lua_encounter_events_registered.clear();
lua_encounters_loaded.clear(); lua_encounters_loaded.clear();
for (auto encounter : lua_encounters) {
encounter.second->Depop();
}
lua_encounters.clear();
if(L) { if(L) {
lua_close(L); lua_close(L);
} }
@ -968,6 +979,7 @@ void LuaParser::MapFunctions(lua_State *L) {
lua_register_client_version(), lua_register_client_version(),
lua_register_appearance(), lua_register_appearance(),
lua_register_entity(), lua_register_entity(),
lua_register_encounter(),
lua_register_mob(), lua_register_mob(),
lua_register_special_abilities(), lua_register_special_abilities(),
lua_register_npc(), lua_register_npc(),

View File

@ -39,7 +39,7 @@ public:
std::vector<EQEmu::Any> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, virtual int EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
virtual bool HasQuestSub(uint32 npc_id, QuestEventID evt); virtual bool HasQuestSub(uint32 npc_id, QuestEventID evt);
@ -82,7 +82,7 @@ private:
uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr); uint32 extra_data, std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr);
int _EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, int _EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr); std::vector<EQEmu::Any> *extra_pointers, luabind::adl::object *l_func = nullptr);
int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data, int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
void LoadScript(std::string filename, std::string package_name); void LoadScript(std::string filename, std::string package_name);
@ -99,6 +99,8 @@ private:
PlayerArgumentHandler PlayerArgumentDispatch[_LargestEventID]; PlayerArgumentHandler PlayerArgumentDispatch[_LargestEventID];
ItemArgumentHandler ItemArgumentDispatch[_LargestEventID]; ItemArgumentHandler ItemArgumentDispatch[_LargestEventID];
SpellArgumentHandler SpellArgumentDispatch[_LargestEventID]; SpellArgumentHandler SpellArgumentDispatch[_LargestEventID];
EncounterArgumentHandler EncounterArgumentDispatch[_LargestEventID];
}; };
#endif #endif

View File

@ -22,6 +22,7 @@
#include "lua_door.h" #include "lua_door.h"
#include "lua_object.h" #include "lua_object.h"
#include "lua_packet.h" #include "lua_packet.h"
#include "lua_encounter.h"
#include "zone.h" #include "zone.h"
#include "lua_parser_events.h" #include "lua_parser_events.h"
@ -704,4 +705,39 @@ void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* cl
std::vector<EQEmu::Any> *extra_pointers) { std::vector<EQEmu::Any> *extra_pointers) {
} }
void handle_encounter_timer(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers) {
lua_pushstring(L, data.c_str());
lua_setfield(L, -2, "timer");
}
void handle_encounter_load(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers) {
if (encounter) {
Lua_Encounter l_enc(encounter);
luabind::adl::object l_enc_o = luabind::adl::object(L, l_enc);
l_enc_o.push(L);
lua_setfield(L, -2, "encounter");
}
if (extra_pointers) {
std::string *str = EQEmu::any_cast<std::string*>(extra_pointers->at(0));
lua_pushstring(L, str->c_str());
lua_setfield(L, -2, "data");
}
}
void handle_encounter_unload(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers) {
if (extra_pointers) {
std::string *str = EQEmu::any_cast<std::string*>(extra_pointers->at(0));
lua_pushstring(L, str->c_str());
lua_setfield(L, -2, "data");
}
}
void handle_encounter_null(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers) {
}
#endif #endif

View File

@ -6,6 +6,7 @@ typedef void(*NPCArgumentHandler)(QuestInterface*, lua_State*, NPC*, Mob*, std::
typedef void(*PlayerArgumentHandler)(QuestInterface*, lua_State*, Client*, std::string, uint32, std::vector<EQEmu::Any>*); typedef void(*PlayerArgumentHandler)(QuestInterface*, lua_State*, Client*, std::string, uint32, std::vector<EQEmu::Any>*);
typedef void(*ItemArgumentHandler)(QuestInterface*, lua_State*, Client*, ItemInst*, Mob*, std::string, uint32, std::vector<EQEmu::Any>*); typedef void(*ItemArgumentHandler)(QuestInterface*, lua_State*, Client*, ItemInst*, Mob*, std::string, uint32, std::vector<EQEmu::Any>*);
typedef void(*SpellArgumentHandler)(QuestInterface*, lua_State*, NPC*, Client*, uint32, uint32, std::vector<EQEmu::Any>*); typedef void(*SpellArgumentHandler)(QuestInterface*, lua_State*, NPC*, Client*, uint32, uint32, std::vector<EQEmu::Any>*);
typedef void(*EncounterArgumentHandler)(QuestInterface*, lua_State*, Encounter* encounter, std::string, uint32, std::vector<EQEmu::Any>*);
//NPC //NPC
void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
@ -127,5 +128,16 @@ void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Cl
void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers); std::vector<EQEmu::Any> *extra_pointers);
//Encounter
void handle_encounter_timer(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers);
void handle_encounter_load(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers);
void handle_encounter_unload(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers);
void handle_encounter_null(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers);
#endif #endif
#endif #endif

View File

@ -64,7 +64,7 @@ Map::~Map() {
float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const { float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
if (!imp) if (!imp)
return false; return BEST_Z_INVALID;
glm::vec3 tmp; glm::vec3 tmp;
if(!result) if(!result)
@ -93,6 +93,41 @@ float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
return BEST_Z_INVALID; return BEST_Z_INVALID;
} }
float Map::FindClosestZ(glm::vec3 &start, glm::vec3 *result) const {
// Unlike FindBestZ, this method finds the closest Z value above or below the specified point.
//
if (!imp)
return false;
float ClosestZ = BEST_Z_INVALID;
glm::vec3 tmp;
if (!result)
result = &tmp;
glm::vec3 from(start.x, start.y, start.z);
glm::vec3 to(start.x, start.y, BEST_Z_INVALID);
float hit_distance;
bool hit = false;
// first check is below us
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
if (hit) {
ClosestZ = result->z;
}
// Find nearest Z above us
to.z = -BEST_Z_INVALID;
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
if (hit) {
if (abs(from.z - result->z) < abs(ClosestZ - from.z))
return result->z;
}
return ClosestZ;
}
bool Map::LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const { bool Map::LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const {
if(!imp) if(!imp)
return false; return false;

View File

@ -34,6 +34,7 @@ public:
~Map(); ~Map();
float FindBestZ(glm::vec3 &start, glm::vec3 *result) const; float FindBestZ(glm::vec3 &start, glm::vec3 *result) const;
float FindClosestZ(glm::vec3 &start, glm::vec3 *result) const;
bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const; bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const;
bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const; bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const;
bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const; bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const;

View File

@ -1236,10 +1236,7 @@ void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
bool Merc::Process() bool Merc::Process()
{ {
if(IsStunned() && stunned_timer.Check()) if(IsStunned() && stunned_timer.Check())
{ Mob::UnStun();
this->stunned = false;
this->stunned_timer.Disable();
}
if (GetDepop()) if (GetDepop())
{ {
@ -1463,14 +1460,16 @@ void Merc::AI_Process() {
if(moved) { if(moved) {
moved = false; moved = false;
SendPosition(); SetCurrentSpeed(0);
SetMoving(false);
} }
} }
return; return;
} }
if (!(m_PlayerState & static_cast<uint32>(PlayerState::Aggressive)))
SendAddPlayerState(PlayerState::Aggressive);
bool atCombatRange = false; bool atCombatRange = false;
float meleeDistance = GetMaxMeleeRangeToTarget(GetTarget()); float meleeDistance = GetMaxMeleeRangeToTarget(GetTarget());
@ -1497,9 +1496,7 @@ void Merc::AI_Process() {
SetRunAnimSpeed(0); SetRunAnimSpeed(0);
if(moved) { if(moved) {
moved = false; SetCurrentSpeed(0);
SendPosition();
SetMoving(false);
} }
} }
@ -1684,6 +1681,9 @@ void Merc::AI_Process() {
confidence_timer.Disable(); confidence_timer.Disable();
_check_confidence = false; _check_confidence = false;
if (m_PlayerState & static_cast<uint32>(PlayerState::Aggressive))
SendRemovePlayerState(PlayerState::Aggressive);
if(!check_target_timer.Enabled()) if(!check_target_timer.Enabled())
check_target_timer.Start(2000, false); check_target_timer.Start(2000, false);
@ -1707,7 +1707,7 @@ void Merc::AI_Process() {
if(follow) if(follow)
{ {
float dist = DistanceSquared(m_Position, follow->GetPosition()); float dist = DistanceSquared(m_Position, follow->GetPosition());
float speed = GetRunspeed(); int speed = GetRunspeed();
if(dist < GetFollowDistance() + 1000) if(dist < GetFollowDistance() + 1000)
speed = GetWalkspeed(); speed = GetWalkspeed();
@ -1724,9 +1724,8 @@ void Merc::AI_Process() {
{ {
if(moved) if(moved)
{ {
moved=false; SetCurrentSpeed(0);
SendPosition(); moved = false;
SetMoving(false);
} }
} }
} }

View File

@ -26,6 +26,7 @@
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <sstream> #include <sstream>
#include <algorithm>
#ifdef BOTS #ifdef BOTS
#include "bot.h" #include "bot.h"
@ -149,6 +150,29 @@ Mob::Mob(const char* in_name,
size = in_size; size = in_size;
base_size = size; base_size = size;
runspeed = in_runspeed; runspeed = in_runspeed;
// neotokyo: sanity check
if (runspeed < 0 || runspeed > 20)
runspeed = 1.25f;
base_runspeed = (int)((float)runspeed * 40.0f);
// clients
if (runspeed == 0.7f) {
base_runspeed = 28;
walkspeed = 0.3f;
base_walkspeed = 12;
fearspeed = 0.625f;
base_fearspeed = 25;
// npcs
} else {
base_walkspeed = base_runspeed * 100 / 265;
walkspeed = ((float)base_walkspeed) * 0.025f;
base_fearspeed = base_runspeed * 100 / 127;
fearspeed = ((float)base_fearspeed) * 0.025f;
}
current_speed = base_runspeed;
m_PlayerState = 0;
// sanity check // sanity check
@ -161,7 +185,7 @@ Mob::Mob(const char* in_name,
m_Light.Level.Spell = m_Light.Type.Spell = 0; m_Light.Level.Spell = m_Light.Type.Spell = 0;
m_Light.Type.Active = m_Light.Type.Innate; m_Light.Type.Active = m_Light.Type.Innate;
m_Light.Level.Active = m_Light.Level.Innate; m_Light.Level.Active = m_Light.Level.Innate;
texture = in_texture; texture = in_texture;
helmtexture = in_helmtexture; helmtexture = in_helmtexture;
armtexture = in_armtexture; armtexture = in_armtexture;
@ -240,15 +264,19 @@ Mob::Mob(const char* in_name,
PermaProcs[j].spellID = SPELL_UNKNOWN; PermaProcs[j].spellID = SPELL_UNKNOWN;
PermaProcs[j].chance = 0; PermaProcs[j].chance = 0;
PermaProcs[j].base_spellID = SPELL_UNKNOWN; PermaProcs[j].base_spellID = SPELL_UNKNOWN;
PermaProcs[j].level_override = -1;
SpellProcs[j].spellID = SPELL_UNKNOWN; SpellProcs[j].spellID = SPELL_UNKNOWN;
SpellProcs[j].chance = 0; SpellProcs[j].chance = 0;
SpellProcs[j].base_spellID = SPELL_UNKNOWN; SpellProcs[j].base_spellID = SPELL_UNKNOWN;
SpellProcs[j].level_override = -1;
DefensiveProcs[j].spellID = SPELL_UNKNOWN; DefensiveProcs[j].spellID = SPELL_UNKNOWN;
DefensiveProcs[j].chance = 0; DefensiveProcs[j].chance = 0;
DefensiveProcs[j].base_spellID = SPELL_UNKNOWN; DefensiveProcs[j].base_spellID = SPELL_UNKNOWN;
DefensiveProcs[j].level_override = -1;
RangedProcs[j].spellID = SPELL_UNKNOWN; RangedProcs[j].spellID = SPELL_UNKNOWN;
RangedProcs[j].chance = 0; RangedProcs[j].chance = 0;
RangedProcs[j].base_spellID = SPELL_UNKNOWN; RangedProcs[j].base_spellID = SPELL_UNKNOWN;
RangedProcs[j].level_override = -1;
} }
for (i = 0; i < _MaterialCount; i++) for (i = 0; i < _MaterialCount; i++)
@ -311,7 +339,7 @@ Mob::Mob(const char* in_name,
pLastChange = 0; pLastChange = 0;
SetPetID(0); SetPetID(0);
SetOwnerID(0); SetOwnerID(0);
typeofpet = petCharmed; //default to charmed... typeofpet = petNone; // default to not a pet
petpower = 0; petpower = 0;
held = false; held = false;
nocast = false; nocast = false;
@ -531,48 +559,32 @@ bool Mob::IsInvisible(Mob* other) const
return(false); return(false);
} }
float Mob::_GetMovementSpeed(int mod) const int Mob::_GetWalkSpeed() const {
{
// List of movement speed modifiers, including AAs & spells: if (IsRooted() || IsStunned() || IsMezzed())
// http://everquest.allakhazam.com/db/item.html?item=1721;page=1;howmany=50#m10822246245352 return 0;
if (IsRooted())
return 0.0f;
else if (IsPseudoRooted()) else if (IsPseudoRooted())
return 0.00001f; return 0;
float speed_mod = runspeed; int aa_mod = 0;
int speed_mod = base_walkspeed;
int base_run = base_runspeed;
bool has_horse = false;
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
aa_mod += aabonuses.BaseMovementSpeed;
// These two cases ignore the cap, be wise in the DB for horses.
if (IsClient()) { if (IsClient()) {
if (CastToClient()->GetGMSpeed()) { Mob *horse = entity_list.GetMob(CastToClient()->GetHorseId());
speed_mod = 3.125f; if (horse) {
if (mod != 0) speed_mod = horse->GetBaseRunspeed();
speed_mod += speed_mod * static_cast<float>(mod) / 100.0f;
return speed_mod; return speed_mod;
} else {
Mob *horse = entity_list.GetMob(CastToClient()->GetHorseId());
if (horse) {
speed_mod = horse->GetBaseRunspeed();
if (mod != 0)
speed_mod += speed_mod * static_cast<float>(mod) / 100.0f;
return speed_mod;
}
} }
} }
int aa_mod = 0; int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
int spell_mod = 0;
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
int movemod = 0; int movemod = 0;
float frunspeedcap = 0.0f;
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
aa_mod += itembonuses.BaseMovementSpeed + spellbonuses.BaseMovementSpeed + aabonuses.BaseMovementSpeed;
spell_mod += spellbonuses.movementspeed + itembonuses.movementspeed;
// hard cap
if (runspeedcap > 225)
runspeedcap = 225;
if (spell_mod < 0) if (spell_mod < 0)
movemod += spell_mod; movemod += spell_mod;
@ -581,27 +593,189 @@ float Mob::_GetMovementSpeed(int mod) const
else else
movemod = aa_mod; movemod = aa_mod;
// cap negative movemods from snares mostly // hard cap
if (movemod < -85) if (runspeedcap > 225)
runspeedcap = 225;
if(movemod < -85) //cap it at moving very very slow
movemod = -85; movemod = -85;
if (movemod != 0) if (!has_horse && movemod != 0)
speed_mod += speed_mod * static_cast<float>(movemod) / 100.0f; speed_mod += (base_run * movemod / 100);
// runspeed caps if(speed_mod < 1)
frunspeedcap = static_cast<float>(runspeedcap) / 100.0f; return(0);
if (IsClient() && speed_mod > frunspeedcap)
speed_mod = frunspeedcap;
// apply final mod such as the -47 for walking //runspeed cap.
// use runspeed since it should stack with snares if(IsClient())
// and if we get here, we know runspeed was the initial {
// value before we applied movemod. if(speed_mod > runspeedcap)
if (mod != 0) speed_mod = runspeedcap;
speed_mod += runspeed * static_cast<float>(mod) / 100.0f; }
return speed_mod;
}
if (speed_mod <= 0.0f) int Mob::_GetRunSpeed() const {
speed_mod = IsClient() ? 0.0001f : 0.0f; if (IsRooted() || IsStunned() || IsMezzed() || IsPseudoRooted())
return 0;
int aa_mod = 0;
int speed_mod = base_runspeed;
int base_walk = base_walkspeed;
bool has_horse = false;
if (IsClient())
{
if(CastToClient()->GetGMSpeed())
{
speed_mod = 325;
}
else
{
Mob* horse = entity_list.GetMob(CastToClient()->GetHorseId());
if(horse)
{
speed_mod = horse->GetBaseRunspeed();
base_walk = horse->GetBaseWalkspeed();
has_horse = true;
}
}
}
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
aa_mod = itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
int movemod = 0;
if(spell_mod < 0)
{
movemod += spell_mod;
}
else if(spell_mod > aa_mod)
{
movemod = spell_mod;
}
else
{
movemod = aa_mod;
}
if(movemod < -85) //cap it at moving very very slow
movemod = -85;
if (!has_horse && movemod != 0)
{
if (IsClient())
{
speed_mod += (speed_mod * movemod / 100);
} else {
if (movemod < 0) {
speed_mod += (50 * movemod / 100);
// basically stoped
if(speed_mod < 1)
{
return(0);
}
// moving slowly
if (speed_mod < 8)
return(8);
} else {
speed_mod += GetBaseWalkspeed();
if (movemod > 50)
speed_mod += 4;
if (movemod > 40)
speed_mod += 3;
}
}
}
if(speed_mod < 1)
{
return(0);
}
//runspeed cap.
if(IsClient())
{
if(speed_mod > runspeedcap)
speed_mod = runspeedcap;
}
return speed_mod;
}
int Mob::_GetFearSpeed() const {
if (IsRooted() || IsStunned() || IsMezzed())
return 0;
//float speed_mod = fearspeed;
int speed_mod = GetBaseFearSpeed();
// use a max of 1.75f in calcs.
int base_run = std::min(GetBaseRunspeed(), 70);
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
int movemod = 0;
if(spell_mod < 0)
{
movemod += spell_mod;
}
if(movemod < -85) //cap it at moving very very slow
movemod = -85;
if (IsClient()) {
if (CastToClient()->IsRunning())
speed_mod = GetBaseRunspeed();
else
speed_mod = GetBaseWalkspeed();
if (movemod < 0)
return GetBaseWalkspeed();
speed_mod += (base_run * movemod / 100);
return speed_mod;
} else {
int hp_ratio = GetIntHPRatio();
// very large snares 50% or higher
if (movemod < -49)
{
if (hp_ratio < 25)
{
return (0);
}
if (hp_ratio < 50)
return (8);
else
return (12);
}
if (hp_ratio < 5) {
speed_mod = base_walkspeed / 3;
} else if (hp_ratio < 15) {
speed_mod = base_walkspeed / 2;
} else if (hp_ratio < 25) {
speed_mod = base_walkspeed + 1; // add the +1 so they do the run animation
} else if (hp_ratio < 50) {
speed_mod *= 82;
speed_mod /= 100;
}
if (movemod > 0) {
speed_mod += GetBaseWalkspeed();
if (movemod > 50)
speed_mod += 4;
if (movemod > 40)
speed_mod += 3;
return speed_mod;
}
else if (movemod < 0) {
speed_mod += (base_run * movemod / 100);
}
}
if (speed_mod < 1)
return (0);
if (speed_mod < 9)
return (8);
if (speed_mod < 13)
return (12);
return speed_mod; return speed_mod;
} }
@ -740,7 +914,7 @@ void Mob::CreateSpawnPacket(EQApplicationPacket* app, Mob* ForWho) {
NewSpawn_Struct* ns = (NewSpawn_Struct*)app->pBuffer; NewSpawn_Struct* ns = (NewSpawn_Struct*)app->pBuffer;
FillSpawnStruct(ns, ForWho); FillSpawnStruct(ns, ForWho);
if(strlen(ns->spawn.lastName) == 0) if(strlen(ns->spawn.lastName) == 0)
{ {
switch(ns->spawn.class_) switch(ns->spawn.class_)
{ {
@ -916,6 +1090,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
ns->spawn.class_ = class_; ns->spawn.class_ = class_;
ns->spawn.gender = gender; ns->spawn.gender = gender;
ns->spawn.level = level; ns->spawn.level = level;
ns->spawn.PlayerState = m_PlayerState;
ns->spawn.deity = deity; ns->spawn.deity = deity;
ns->spawn.animation = 0; ns->spawn.animation = 0;
ns->spawn.findable = findable?1:0; ns->spawn.findable = findable?1:0;
@ -1092,7 +1267,7 @@ void Mob::CreateHPPacket(EQApplicationPacket* app)
} }
// sends hp update of this mob to people who might care // sends hp update of this mob to people who might care
void Mob::SendHPUpdate() void Mob::SendHPUpdate(bool skip_self)
{ {
EQApplicationPacket hp_app; EQApplicationPacket hp_app;
Group *group; Group *group;
@ -1181,8 +1356,7 @@ void Mob::SendHPUpdate()
} }
// send to self - we need the actual hps here // send to self - we need the actual hps here
if(IsClient()) if(IsClient() && !skip_self) {
{
EQApplicationPacket* hp_app2 = new EQApplicationPacket(OP_HPUpdate,sizeof(SpawnHPUpdate_Struct)); EQApplicationPacket* hp_app2 = new EQApplicationPacket(OP_HPUpdate,sizeof(SpawnHPUpdate_Struct));
SpawnHPUpdate_Struct* ds = (SpawnHPUpdate_Struct*)hp_app2->pBuffer; SpawnHPUpdate_Struct* ds = (SpawnHPUpdate_Struct*)hp_app2->pBuffer;
ds->cur_hp = CastToClient()->GetHP() - itembonuses.HP; ds->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
@ -1191,6 +1365,7 @@ void Mob::SendHPUpdate()
CastToClient()->QueuePacket(hp_app2); CastToClient()->QueuePacket(hp_app2);
safe_delete(hp_app2); safe_delete(hp_app2);
} }
ResetHPUpdateTimer(); // delay the timer
} }
// this one just warps the mob to the current location // this one just warps the mob to the current location
@ -1301,7 +1476,7 @@ void Mob::ShowStats(Client* client)
if(n->respawn2 != 0) if(n->respawn2 != 0)
spawngroupid = n->respawn2->SpawnGroupID(); spawngroupid = n->respawn2->SpawnGroupID();
client->Message(0, " NPCID: %u SpawnGroupID: %u Grid: %i LootTable: %u FactionID: %i SpellsID: %u ", GetNPCTypeID(),spawngroupid, n->GetGrid(), n->GetLoottableID(), n->GetNPCFactionID(), n->GetNPCSpellsID()); client->Message(0, " NPCID: %u SpawnGroupID: %u Grid: %i LootTable: %u FactionID: %i SpellsID: %u ", GetNPCTypeID(),spawngroupid, n->GetGrid(), n->GetLoottableID(), n->GetNPCFactionID(), n->GetNPCSpellsID());
client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %f Walkspeed: %f", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), n->GetRunspeed(), n->GetWalkspeed()); client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %u Walkspeed: %u", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), n->GetRunspeed(), n->GetWalkspeed());
n->QueryLoot(client); n->QueryLoot(client);
} }
if (IsAIControlled()) { if (IsAIControlled()) {
@ -1788,7 +1963,7 @@ bool Mob::IsPlayerRace(uint16 in_race) {
uint8 Mob::GetDefaultGender(uint16 in_race, uint8 in_gender) { uint8 Mob::GetDefaultGender(uint16 in_race, uint8 in_gender) {
if (Mob::IsPlayerRace(in_race) || in_race == 15 || in_race == 50 || in_race == 57 || in_race == 70 || in_race == 98 || in_race == 118) { if (Mob::IsPlayerRace(in_race) || in_race == 15 || in_race == 50 || in_race == 57 || in_race == 70 || in_race == 98 || in_race == 118 || in_race == 23) {
if (in_gender >= 2) { if (in_gender >= 2) {
// Male default for PC Races // Male default for PC Races
return 0; return 0;
@ -1909,22 +2084,6 @@ void Mob::SendTargetable(bool on, Client *specific_target) {
safe_delete(outapp); safe_delete(outapp);
} }
void Mob::QuestReward(Client *c, uint32 silver, uint32 gold, uint32 platinum) {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct));
QuestReward_Struct* qr = (QuestReward_Struct*) outapp->pBuffer;
qr->from_mob = GetID(); // Entity ID for the from mob name
qr->silver = silver;
qr->gold = gold;
qr->platinum = platinum;
if(c)
c->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
safe_delete(outapp);
}
void Mob::CameraEffect(uint32 duration, uint32 intensity, Client *c, bool global) { void Mob::CameraEffect(uint32 duration, uint32 intensity, Client *c, bool global) {
@ -2041,12 +2200,12 @@ const int32& Mob::SetMana(int32 amount)
void Mob::SetAppearance(EmuAppearance app, bool iIgnoreSelf) { void Mob::SetAppearance(EmuAppearance app, bool iIgnoreSelf) {
if (_appearance != app) { if (_appearance == app)
_appearance = app; return;
SendAppearancePacket(AT_Anim, GetAppearanceValue(app), true, iIgnoreSelf); _appearance = app;
if (this->IsClient() && this->IsAIControlled()) SendAppearancePacket(AT_Anim, GetAppearanceValue(app), true, iIgnoreSelf);
SendAppearancePacket(AT_Anim, ANIM_FREEZE, false, false); if (this->IsClient() && this->IsAIControlled())
} SendAppearancePacket(AT_Anim, ANIM_FREEZE, false, false);
} }
bool Mob::UpdateActiveLight() bool Mob::UpdateActiveLight()
@ -2138,8 +2297,10 @@ void Mob::SetOwnerID(uint16 NewOwnerID) {
if (NewOwnerID == GetID() && NewOwnerID != 0) // ok, no charming yourself now =p if (NewOwnerID == GetID() && NewOwnerID != 0) // ok, no charming yourself now =p
return; return;
ownerid = NewOwnerID; ownerid = NewOwnerID;
if (ownerid == 0 && this->IsNPC() && this->GetPetType() != petCharmed) // if we're setting the owner ID to 0 and they're not either charmed or not-a-pet then
this->Depop(); // they're a normal pet and should be despawned
if (ownerid == 0 && IsNPC() && GetPetType() != petCharmed && GetPetType() != petNone)
Depop();
} }
// used in checking for behind (backstab) and checking in front (melee LoS) // used in checking for behind (backstab) and checking in front (melee LoS)
@ -2553,7 +2714,35 @@ uint32 NPC::GetEquipment(uint8 material_slot) const
return equipment[invslot]; return equipment[invslot];
} }
void Mob::SendWearChange(uint8 material_slot) void Mob::SendArmorAppearance(Client *one_client)
{
// one_client of 0 means sent to all clients
//
// Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the
// armor being worn and its mats, the client doesn't update the display
// on arrival of these packets reliably.
//
// Send Wear changes if mob is a PC race and item is an armor slot.
// The other packets work for primary/secondary.
if (IsPlayerRace(race))
{
if (!IsClient())
{
const Item_Struct *item;
for (int i=0; i< 7 ; ++i)
{
item=database.GetItem(GetEquipment(i));
if (item != 0)
{
SendWearChange(i,one_client);
}
}
}
}
}
void Mob::SendWearChange(uint8 material_slot, Client *one_client)
{ {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); EQApplicationPacket* outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer;
@ -2565,7 +2754,15 @@ void Mob::SendWearChange(uint8 material_slot)
wc->color.Color = GetEquipmentColor(material_slot); wc->color.Color = GetEquipmentColor(material_slot);
wc->wear_slot_id = material_slot; wc->wear_slot_id = material_slot;
entity_list.QueueClients(this, outapp); if (!one_client)
{
entity_list.QueueClients(this, outapp);
}
else
{
one_client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
}
safe_delete(outapp); safe_delete(outapp);
} }
@ -2691,7 +2888,7 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const
const ItemData *item; const ItemData *item;
item = database.GetItem(GetEquipment(material_slot)); item = database.GetItem(GetEquipment(material_slot));
int16 invslot = InventoryOld::CalcSlotFromMaterial(material_slot); int16 invslot = InventoryOld::CalcSlotFromMaterial(material_slot);
if (item != 0 && invslot != INVALID_INDEX) if (item != 0 && invslot != INVALID_INDEX)
{ {
if (IsClient()) if (IsClient())
@ -2949,10 +3146,10 @@ uint32 Mob::GetLevelHP(uint8 tlevel)
} }
int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime) { int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime) {
int32 cast_reducer = 0; int32 cast_reducer = 0;
cast_reducer += GetFocusEffect(focusSpellHaste, spell_id); cast_reducer += GetFocusEffect(focusSpellHaste, spell_id);
if (level >= 60 && casttime > 1000) if (level >= 60 && casttime > 1000)
{ {
casttime = casttime / 2; casttime = casttime / 2;
@ -2970,7 +3167,7 @@ int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime) {
return casttime; return casttime;
} }
void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on) { void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on, int level_override) {
// Changed proc targets to look up based on the spells goodEffect flag. // Changed proc targets to look up based on the spells goodEffect flag.
// This should work for the majority of weapons. // This should work for the majority of weapons.
if(spell_id == SPELL_UNKNOWN || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) { if(spell_id == SPELL_UNKNOWN || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
@ -3009,14 +3206,14 @@ void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on) {
twinproc = true; twinproc = true;
if (IsBeneficialSpell(spell_id)) { if (IsBeneficialSpell(spell_id)) {
SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff, true); SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff, true, level_override);
if(twinproc) if(twinproc)
SpellOnTarget(spell_id, this, false, false, 0, true); SpellOnTarget(spell_id, this, false, false, 0, true, level_override);
} }
else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients
SpellFinished(spell_id, on, 10, 0, -1, spells[spell_id].ResistDiff, true); SpellFinished(spell_id, on, 10, 0, -1, spells[spell_id].ResistDiff, true, level_override);
if(twinproc) if(twinproc)
SpellOnTarget(spell_id, on, false, false, 0, true); SpellOnTarget(spell_id, on, false, false, 0, true, level_override);
} }
return; return;
} }
@ -3566,7 +3763,7 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)
// All skill dmg mod + Skill specific // All skill dmg mod + Skill specific
skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] + skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] +
itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used]; itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used];
skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1]; skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1];
@ -4006,6 +4203,39 @@ int32 Mob::GetItemStat(uint32 itemid, const char *identifier)
return stat; return stat;
} }
std::string Mob::GetGlobal(const char *varname) {
int qgCharid = 0;
int qgNpcid = 0;
if (this->IsNPC())
qgNpcid = this->GetNPCTypeID();
if (this->IsClient())
qgCharid = this->CastToClient()->CharacterID();
QGlobalCache *qglobals = nullptr;
std::list<QGlobal> globalMap;
if (this->IsClient())
qglobals = this->CastToClient()->GetQGlobals();
if (this->IsNPC())
qglobals = this->CastToNPC()->GetQGlobals();
if(qglobals)
QGlobalCache::Combine(globalMap, qglobals->GetBucket(), qgNpcid, qgCharid, zone->GetZoneID());
std::list<QGlobal>::iterator iter = globalMap.begin();
while(iter != globalMap.end()) {
if ((*iter).name.compare(varname) == 0)
return (*iter).value;
++iter;
}
return "Undefined";
}
void Mob::SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Mob *other) { void Mob::SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Mob *other) {
int qgZoneid = zone->GetZoneID(); int qgZoneid = zone->GetZoneID();
@ -5284,7 +5514,7 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
if (slot < 4){ if (slot < 4){
if (id == "components") { return spells[spell_id].components[slot];} if (id == "components") { return spells[spell_id].components[slot];}
else if (id == "component_counts") { return spells[spell_id].component_counts[slot];} else if (id == "component_counts") { return spells[spell_id].component_counts[slot];}
else if (id == "NoexpendReagent") {return spells[spell_id].NoexpendReagent[slot];} else if (id == "NoexpendReagent") {return spells[spell_id].NoexpendReagent[slot];}
} }
@ -5362,7 +5592,7 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
else if (id == "max_dist") {return static_cast<int32>(spells[spell_id].max_dist); } else if (id == "max_dist") {return static_cast<int32>(spells[spell_id].max_dist); }
else if (id == "min_range") {return static_cast<int32>(spells[spell_id].min_range); } else if (id == "min_range") {return static_cast<int32>(spells[spell_id].min_range); }
else if (id == "DamageShieldType") {return spells[spell_id].DamageShieldType; } else if (id == "DamageShieldType") {return spells[spell_id].DamageShieldType; }
return stat; return stat;
} }
@ -5382,9 +5612,48 @@ bool Mob::CanClassEquipItem(uint32 item_id)
int bitmask = 1; int bitmask = 1;
bitmask = bitmask << (GetClass() - 1); bitmask = bitmask << (GetClass() - 1);
if(!(itm->Classes & bitmask)) if(!(itm->Classes & bitmask))
return false; return false;
else else
return true; return true;
} }
void Mob::SendAddPlayerState(PlayerState new_state)
{
auto app = new EQApplicationPacket(OP_PlayerStateAdd, sizeof(PlayerState_Struct));
auto ps = (PlayerState_Struct *)app->pBuffer;
ps->spawn_id = GetID();
ps->state = static_cast<uint32>(new_state);
AddPlayerState(ps->state);
entity_list.QueueClients(nullptr, app);
safe_delete(app);
}
void Mob::SendRemovePlayerState(PlayerState old_state)
{
auto app = new EQApplicationPacket(OP_PlayerStateRemove, sizeof(PlayerState_Struct));
auto ps = (PlayerState_Struct *)app->pBuffer;
ps->spawn_id = GetID();
ps->state = static_cast<uint32>(old_state);
RemovePlayerState(ps->state);
entity_list.QueueClients(nullptr, app);
safe_delete(app);
}
void Mob::SetCurrentSpeed(int in){
if (current_speed != in)
{
current_speed = in;
tar_ndx = 20;
if (in == 0) {
SetRunAnimSpeed(0);
SetMoving(false);
SendPosition();
}
}
}

View File

@ -172,7 +172,8 @@ public:
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5,
Client *specific_target=nullptr); Client *specific_target=nullptr);
void SendTargetable(bool on, Client *specific_target = nullptr); void SendTargetable(bool on, Client *specific_target = nullptr);
virtual void SendWearChange(uint8 material_slot); virtual void SendArmorAppearance(Client *one_client = nullptr);
virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr);
virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0,
uint32 unknown06 = 0, uint32 unknown18 = 0); uint32 unknown06 = 0, uint32 unknown18 = 0);
virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint); virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint);
@ -200,7 +201,7 @@ public:
bool IsBeneficialAllowed(Mob *target); bool IsBeneficialAllowed(Mob *target);
virtual int GetCasterLevel(uint16 spell_id); virtual int GetCasterLevel(uint16 spell_id);
void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0, void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0,
uint8 WornType = 0, uint32 ticsremaining = 0, int buffslot = -1, uint8 WornType = 0, int32 ticsremaining = 0, int buffslot = -1, int instrument_mod = 10,
bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0); bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0);
void NegateSpellsBonuses(uint16 spell_id); void NegateSpellsBonuses(uint16 spell_id);
virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false); virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false);
@ -211,7 +212,8 @@ public:
virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration); virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration);
virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime);
float ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override = false, float ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override = false,
int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false); int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false,
int level_override = -1);
int ResistPhysical(int level_diff, uint8 caster_level); int ResistPhysical(int level_diff, uint8 caster_level);
uint16 GetSpecializeSkillValue(uint16 spell_id) const; uint16 GetSpecializeSkillValue(uint16 spell_id) const;
void SendSpellBarDisable(); void SendSpellBarDisable();
@ -227,10 +229,10 @@ public:
void CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, uint16 mana_used, void CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, uint16 mana_used,
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0); uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
bool SpellFinished(uint16 spell_id, Mob *target, uint16 slot = 10, uint16 mana_used = 0, bool SpellFinished(uint16 spell_id, Mob *target, uint16 slot = 10, uint16 mana_used = 0,
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false); uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect = false, virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect = false,
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false); bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1);
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100); virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1);
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center,
CastAction_type &CastAction); CastAction_type &CastAction);
virtual bool CheckFizzle(uint16 spell_id); virtual bool CheckFizzle(uint16 spell_id);
@ -253,7 +255,7 @@ public:
//Buff //Buff
void BuffProcess(); void BuffProcess();
virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0); virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
void BuffFadeBySpellID(uint16 spell_id); void BuffFadeBySpellID(uint16 spell_id);
void BuffFadeByEffect(int effectid, int skipslot = -1); void BuffFadeByEffect(int effectid, int skipslot = -1);
void BuffFadeAll(); void BuffFadeAll();
@ -364,6 +366,7 @@ public:
inline Mob* GetTarget() const { return target; } inline Mob* GetTarget() const { return target; }
virtual void SetTarget(Mob* mob); virtual void SetTarget(Mob* mob);
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); } virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); }
virtual inline float GetIntHPRatio() const { return max_hp == 0 ? 0 : (cur_hp/max_hp*100); }
inline virtual int32 GetAC() const { return AC + itembonuses.AC + spellbonuses.AC; } inline virtual int32 GetAC() const { return AC + itembonuses.AC + spellbonuses.AC; }
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; } inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; }
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; } inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
@ -441,9 +444,12 @@ public:
virtual void SetMoving(bool move) { moving = move; m_Delta = glm::vec4(); } virtual void SetMoving(bool move) { moving = move; m_Delta = glm::vec4(); }
virtual void GoToBind(uint8 bindnum = 0) { } virtual void GoToBind(uint8 bindnum = 0) { }
virtual void Gate(); virtual void Gate();
float GetWalkspeed() const { return(_GetMovementSpeed(-47)); } int GetWalkspeed() const { return(_GetWalkSpeed()); }
float GetRunspeed() const { return(_GetMovementSpeed(0)); } int GetRunspeed() const { return(_GetRunSpeed()); }
float GetBaseRunspeed() const { return runspeed; } void SetCurrentSpeed(int in);
int GetBaseRunspeed() const { return base_runspeed; }
int GetBaseWalkspeed() const { return base_walkspeed; }
int GetBaseFearSpeed() const { return base_fearspeed; }
float GetMovespeed() const { return IsRunning() ? GetRunspeed() : GetWalkspeed(); } float GetMovespeed() const { return IsRunning() ? GetRunspeed() : GetWalkspeed(); }
bool IsRunning() const { return m_is_running; } bool IsRunning() const { return m_is_running; }
void SetRunning(bool val) { m_is_running = val; } void SetRunning(bool val) { m_is_running = val; }
@ -493,7 +499,6 @@ public:
inline bool CheckLastLosState() const { return last_los_check; } inline bool CheckLastLosState() const { return last_los_check; }
//Quest //Quest
void QuestReward(Client *c = nullptr, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0);
void CameraEffect(uint32 duration, uint32 intensity, Client *c = nullptr, bool global = false); void CameraEffect(uint32 duration, uint32 intensity, Client *c = nullptr, bool global = false);
inline bool GetQglobal() const { return qglobal; } inline bool GetQglobal() const { return qglobal; }
@ -504,7 +509,8 @@ public:
static void CreateSpawnPacket(EQApplicationPacket* app, NewSpawn_Struct* ns); static void CreateSpawnPacket(EQApplicationPacket* app, NewSpawn_Struct* ns);
virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
void CreateHPPacket(EQApplicationPacket* app); void CreateHPPacket(EQApplicationPacket* app);
void SendHPUpdate(); void SendHPUpdate(bool skip_self = false);
virtual void ResetHPUpdateTimer() {}; // does nothing
//Util //Util
static uint32 RandomTimer(int min, int max); static uint32 RandomTimer(int min, int max);
@ -533,7 +539,7 @@ public:
bool HasDefensiveProcs() const; bool HasDefensiveProcs() const;
bool HasSkillProcs() const; bool HasSkillProcs() const;
bool HasSkillProcSuccess() const; bool HasSkillProcSuccess() const;
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN, int level_override = -1);
bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false); bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false);
bool HasProcs() const; bool HasProcs() const;
bool IsCombatProc(uint16 spell_id); bool IsCombatProc(uint16 spell_id);
@ -802,9 +808,8 @@ public:
//old fear function //old fear function
//void SetFeared(Mob *caster, uint32 duration, bool flee = false); //void SetFeared(Mob *caster, uint32 duration, bool flee = false);
float GetFearSpeed(); int GetFearSpeed() { return _GetFearSpeed(); }
bool IsFeared() { return curfp; } // This returns true if the mob is feared or fleeing due to low HP bool IsFeared() { return (spellbonuses.IsFeared || flee_mode); } // This returns true if the mob is feared or fleeing due to low HP
//old fear: inline void StartFleeing() { SetFeared(GetHateTop(), FLEE_RUN_DURATION, true); }
inline void StartFleeing() { flee_mode = true; CalculateNewFearpoint(); } inline void StartFleeing() { flee_mode = true; CalculateNewFearpoint(); }
void ProcessFlee(); void ProcessFlee();
void CheckFlee(); void CheckFlee();
@ -812,8 +817,8 @@ public:
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);} inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
float CalculateHeadingToTarget(float in_x, float in_y); float CalculateHeadingToTarget(float in_x, float in_y);
bool CalculateNewPosition(float x, float y, float z, float speed, bool checkZ = false); bool CalculateNewPosition(float x, float y, float z, int speed, bool checkZ = false, bool calcheading = true);
virtual bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true); virtual bool CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ = true, bool calcheading = true);
float CalculateDistance(float x, float y, float z); float CalculateDistance(float x, float y, float z);
float GetGroundZ(float new_x, float new_y, float z_offset=0.0); float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
void SendTo(float new_x, float new_y, float new_z); void SendTo(float new_x, float new_y, float new_z);
@ -859,7 +864,7 @@ public:
virtual uint32 GetAA(uint32 aa_id) const { return(0); } virtual uint32 GetAA(uint32 aa_id) const { return(0); }
uint32 GetInstrumentMod(uint16 spell_id) const; uint32 GetInstrumentMod(uint16 spell_id) const;
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, Mob *caster = nullptr, int ticsremaining = 0); int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0);
int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0); int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0);
virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1); virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1);
uint32 GetCastedSpellInvSlot() const { return casting_spell_inventory_slot; } uint32 GetCastedSpellInvSlot() const { return casting_spell_inventory_slot; }
@ -884,6 +889,8 @@ public:
Timer *GetSpecialAbilityTimer(int ability); Timer *GetSpecialAbilityTimer(int ability);
void ClearSpecialAbilities(); void ClearSpecialAbilities();
void ProcessSpecialAbilities(const std::string &str); void ProcessSpecialAbilities(const std::string &str);
bool IsMoved() { return moved; }
void SetMoved(bool moveflag) { moved = moveflag; }
Shielders_Struct shielder[MAX_SHIELDERS]; Shielders_Struct shielder[MAX_SHIELDERS];
Trade* trade; Trade* trade;
@ -906,6 +913,7 @@ public:
inline virtual bool IsBlockedBuff(int16 SpellID) { return false; } inline virtual bool IsBlockedBuff(int16 SpellID) { return false; }
inline virtual bool IsBlockedPetBuff(int16 SpellID) { return false; } inline virtual bool IsBlockedPetBuff(int16 SpellID) { return false; }
std::string GetGlobal(const char *varname);
void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Mob *other = nullptr); void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Mob *other = nullptr);
void TarGlobal(const char *varname, const char *value, const char *duration, int npcid, int charid, int zoneid); void TarGlobal(const char *varname, const char *value, const char *duration, int npcid, int charid, int zoneid);
void DelGlobal(const char *varname); void DelGlobal(const char *varname);
@ -956,7 +964,10 @@ protected:
void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic); void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic);
static uint16 GetProcID(uint16 spell_id, uint8 effect_index); static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
float _GetMovementSpeed(int mod) const; float _GetMovementSpeed(int mod) const;
virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool checkZ); int _GetWalkSpeed() const;
int _GetRunSpeed() const;
int _GetFearSpeed() const;
virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ);
virtual bool AI_EngagedCastCheck() { return(false); } virtual bool AI_EngagedCastCheck() { return(false); }
virtual bool AI_PursueCastCheck() { return(false); } virtual bool AI_PursueCastCheck() { return(false); }
@ -1030,6 +1041,13 @@ protected:
uint32 follow_dist; uint32 follow_dist;
bool no_target_hotkey; bool no_target_hotkey;
uint32 m_PlayerState;
uint32 GetPlayerState() { return m_PlayerState; }
void AddPlayerState(uint32 new_state) { m_PlayerState |= new_state; }
void RemovePlayerState(uint32 old_state) { m_PlayerState &= ~old_state; }
void SendAddPlayerState(PlayerState new_state);
void SendRemovePlayerState(PlayerState old_state);
uint8 gender; uint8 gender;
uint16 race; uint16 race;
uint8 base_gender; uint8 base_gender;
@ -1046,6 +1064,13 @@ protected:
float base_size; float base_size;
float size; float size;
float runspeed; float runspeed;
float walkspeed;
float fearspeed;
int base_runspeed;
int base_walkspeed;
int base_fearspeed;
int current_speed;
uint32 pLastChange; uint32 pLastChange;
bool held; bool held;
bool nocast; bool nocast;
@ -1059,7 +1084,7 @@ protected:
void TryWeaponProc(const ItemInst* inst, const ItemData* weapon, Mob *on, uint16 hand = MainPrimary); void TryWeaponProc(const ItemInst* inst, const ItemData* weapon, Mob *on, uint16 hand = MainPrimary);
void TrySpellProc(const ItemInst* inst, const ItemData* weapon, Mob *on, uint16 hand = MainPrimary); void TrySpellProc(const ItemInst* inst, const ItemData* weapon, Mob *on, uint16 hand = MainPrimary);
void TryWeaponProc(const ItemInst* weapon, Mob *on, uint16 hand = MainPrimary); void TryWeaponProc(const ItemInst* weapon, Mob *on, uint16 hand = MainPrimary);
void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on); void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on, int level_override = -1);
virtual float GetProcChances(float ProcBonus, uint16 hand = MainPrimary); virtual float GetProcChances(float ProcBonus, uint16 hand = MainPrimary);
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = MainPrimary, Mob *on = nullptr); virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = MainPrimary, Mob *on = nullptr);
virtual float GetSpecialProcChances(uint16 hand); virtual float GetSpecialProcChances(uint16 hand);

View File

@ -339,9 +339,7 @@ bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
//stop moving if were casting a spell and were not a bard... //stop moving if were casting a spell and were not a bard...
if(!IsBardSong(AIspells[i].spellid)) { if(!IsBardSong(AIspells[i].spellid)) {
SetRunAnimSpeed(0); SetCurrentSpeed(0);
SendPosition();
SetMoving(false);
} }
return CastSpell(AIspells[i].spellid, tar->GetID(), 1, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0, &(AIspells[i].resist_adjust)); return CastSpell(AIspells[i].spellid, tar->GetID(), 1, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0, &(AIspells[i].resist_adjust));
@ -698,9 +696,7 @@ void Client::AI_SpellCast()
{ {
if(!IsBardSong(spell_to_cast)) if(!IsBardSong(spell_to_cast))
{ {
SetRunAnimSpeed(0); SetCurrentSpeed(0);
SendPosition();
SetMoving(false);
} }
CastSpell(spell_to_cast, tar->GetID(), slot_to_use); CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
return; return;
@ -714,9 +710,7 @@ void Client::AI_SpellCast()
{ {
if(!IsBardSong(spell_to_cast)) if(!IsBardSong(spell_to_cast))
{ {
SetRunAnimSpeed(0); SetCurrentSpeed(0);
SendPosition();
SetMoving(false);
} }
CastSpell(spell_to_cast, tar->GetID(), slot_to_use); CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
return; return;
@ -772,16 +766,13 @@ void Client::AI_Process()
{ {
if(GetTarget()) if(GetTarget())
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SetRunAnimSpeed(0); SetCurrentSpeed(0);
SendPosition();
SetMoving(false);
moved=false;
} }
//continue on to attack code, ensuring that we execute the engaged code //continue on to attack code, ensuring that we execute the engaged code
engaged = true; engaged = true;
} else { } else {
if(AImovement_timer->Check()) { if(AImovement_timer->Check()) {
animation = GetRunspeed() * 21; //animation = GetFearSpeed() * 21;
// Check if we have reached the last fear point // Check if we have reached the last fear point
if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) && if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) &&
(std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) {
@ -839,16 +830,13 @@ void Client::AI_Process()
} }
if (AImovement_timer->Check()) { if (AImovement_timer->Check()) {
SetRunAnimSpeed(0); if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
{
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition();
}
SetCurrentSpeed(0);
} }
if(IsMoving()) {
SetMoving(false);
moved=false;
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition();
tar_ndx =0;
}
if(GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) { if(GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) {
if(attack_timer.Check()) { if(attack_timer.Check()) {
Attack(GetTarget(), MainPrimary); Attack(GetTarget(), MainPrimary);
@ -944,28 +932,27 @@ void Client::AI_Process()
{ {
if(!IsRooted()) if(!IsRooted())
{ {
animation = 21 * GetRunspeed(); if(AImovement_timer->Check())
if(!RuleB(Pathing, Aggro) || !zone->pathing)
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
else
{ {
bool WaypointChanged, NodeReached; if(!RuleB(Pathing, Aggro) || !zone->pathing)
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
GetRunspeed(), WaypointChanged, NodeReached); else
{
bool WaypointChanged, NodeReached;
glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(),
GetRunspeed(), WaypointChanged, NodeReached);
if(WaypointChanged) if(WaypointChanged)
tar_ndx = 20; tar_ndx = 20;
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed()); CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed());
}
} }
} }
else if(IsMoving()) else if(IsMoving())
{ {
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SetRunAnimSpeed(0); SetCurrentSpeed(0);
SendPosition();
SetMoving(false);
moved=false;
} }
} }
AI_SpellCast(); AI_SpellCast();
@ -998,21 +985,23 @@ void Client::AI_Process()
return; return;
float dist = DistanceSquared(m_Position, owner->GetPosition()); float dist = DistanceSquared(m_Position, owner->GetPosition());
if (dist >= 100) if (dist >= 400)
{ {
float speed = dist >= 225 ? GetRunspeed() : GetWalkspeed(); if(AImovement_timer->Check())
animation = 21 * speed; {
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed); int speed = GetWalkspeed();
if (dist >= 5625)
speed = GetRunspeed();
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
}
} }
else else
{ {
SetHeading(owner->GetHeading());
if(moved) if(moved)
{ {
moved=false; SetCurrentSpeed(0);
SetMoving(false); moved = false;
SendPosition();
SetRunAnimSpeed(0);
} }
} }
} }
@ -1042,9 +1031,7 @@ void Mob::AI_Process() {
{ {
if(target) if(target)
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY())); SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
SetRunAnimSpeed(0); SetCurrentSpeed(0);
SendPosition();
SetMoving(false);
moved=false; moved=false;
} }
//continue on to attack code, ensuring that we execute the engaged code //continue on to attack code, ensuring that we execute the engaged code
@ -1058,7 +1045,9 @@ void Mob::AI_Process() {
CalculateNewFearpoint(); CalculateNewFearpoint();
} }
if(!RuleB(Pathing, Fear) || !zone->pathing) if(!RuleB(Pathing, Fear) || !zone->pathing)
{
CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true); CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true);
}
else else
{ {
bool WaypointChanged, NodeReached; bool WaypointChanged, NodeReached;
@ -1084,6 +1073,8 @@ void Mob::AI_Process() {
if (engaged) if (engaged)
{ {
if (!(m_PlayerState & static_cast<uint32>(PlayerState::Aggressive)))
SendAddPlayerState(PlayerState::Aggressive);
// we are prevented from getting here if we are blind and don't have a target in range // we are prevented from getting here if we are blind and don't have a target in range
// from above, so no extra blind checks needed // from above, so no extra blind checks needed
if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind()) if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind())
@ -1114,7 +1105,7 @@ void Mob::AI_Process() {
} }
#ifdef BOTS #ifdef BOTS
if (IsPet() && GetOwner()->IsBot() && target == GetOwner()) if (IsPet() && GetOwner() && GetOwner()->IsBot() && target == GetOwner())
{ {
// this blocks all pet attacks against owner..bot pet test (copied above check) // this blocks all pet attacks against owner..bot pet test (copied above check)
RemoveFromHateList(this); RemoveFromHateList(this);
@ -1154,15 +1145,21 @@ void Mob::AI_Process() {
{ {
if (AImovement_timer->Check()) if (AImovement_timer->Check())
{ {
SetRunAnimSpeed(0); if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
{
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition();
}
SetCurrentSpeed(0);
} }
if(IsMoving()) if(IsMoving())
{ {
SetMoving(false); if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
moved=false; {
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY())); SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition(); SendPosition();
tar_ndx =0; }
SetCurrentSpeed(0);
} }
//casting checked above... //casting checked above...
@ -1367,7 +1364,7 @@ void Mob::AI_Process() {
CastToNPC()->DoClassAttacks(target); CastToNPC()->DoClassAttacks(target);
} }
AI_EngagedCastCheck(); AI_EngagedCastCheck();
} //end is within combat range } //end is within combat rangepet
else { else {
//we cannot reach our target... //we cannot reach our target...
//underwater stuff only works with water maps in the zone! //underwater stuff only works with water maps in the zone!
@ -1423,10 +1420,7 @@ void Mob::AI_Process() {
} }
else if(IsMoving()) { else if(IsMoving()) {
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY())); SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
SetRunAnimSpeed(0); SetCurrentSpeed(0);
SendPosition();
SetMoving(false);
moved=false;
} }
} }
@ -1435,6 +1429,8 @@ void Mob::AI_Process() {
} }
else else
{ {
if (m_PlayerState & static_cast<uint32>(PlayerState::Aggressive))
SendRemovePlayerState(PlayerState::Aggressive);
if(AIfeignremember_timer->Check()) { if(AIfeignremember_timer->Check()) {
// 6/14/06 // 6/14/06
// Improved Feign Death Memory // Improved Feign Death Memory
@ -1477,7 +1473,6 @@ void Mob::AI_Process() {
} }
else if (AImovement_timer->Check() && !IsRooted()) else if (AImovement_timer->Check() && !IsRooted())
{ {
SetRunAnimSpeed(0);
if (IsPet()) if (IsPet())
{ {
// we're a pet, do as we're told // we're a pet, do as we're told
@ -1496,18 +1491,18 @@ void Mob::AI_Process() {
float dist = DistanceSquared(m_Position, owner->GetPosition()); float dist = DistanceSquared(m_Position, owner->GetPosition());
if (dist >= 400) if (dist >= 400)
{ {
float speed = GetWalkspeed(); int speed = GetWalkspeed();
if (dist >= 5625) if (dist >= 5625)
speed = GetRunspeed(); speed = GetRunspeed();
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed); CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
} }
else else
{ {
if(moved) if(moved)
{ {
moved=false; SetCurrentSpeed(0);
SetMoving(false); moved = false;
SendPosition();
} }
} }
@ -1553,19 +1548,15 @@ void Mob::AI_Process() {
if (dist2 >= followdist) // Default follow distance is 100 if (dist2 >= followdist) // Default follow distance is 100
{ {
float speed = GetWalkspeed(); int speed = GetWalkspeed();
if (dist2 >= followdist + 150) if (dist2 >= followdist + 150)
speed = GetRunspeed(); speed = GetRunspeed();
CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed); CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed);
} }
else else
{ {
if(moved) moved = false;
{ SetCurrentSpeed(0);
SendPosition();
moved=false;
SetMoving(false);
}
} }
} }
} }
@ -1662,92 +1653,39 @@ void NPC::AI_DoMovement() {
if (gridno > 0 || cur_wp==-2) { if (gridno > 0 || cur_wp==-2) {
if (movetimercompleted==true) { // time to pause at wp is over if (movetimercompleted==true) { // time to pause at wp is over
AI_SetupNextWaypoint();
int32 spawn_id = this->GetSpawnPointID();
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
iterator.Reset();
Spawn2 *found_spawn = nullptr;
while(iterator.MoreElements())
{
Spawn2* cur = iterator.GetData();
iterator.Advance();
if(cur->GetID() == spawn_id)
{
found_spawn = cur;
break;
}
}
if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) {
CastToNPC()->Depop(true); //depop and resart spawn timer
if(found_spawn)
found_spawn->SetNPCPointerNull();
}
else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) {
CastToNPC()->Depop(false);//depop without spawn timer
if(found_spawn)
found_spawn->SetNPCPointerNull();
}
else {
movetimercompleted=false;
Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp);
//if we were under quest control (with no grid), we are done now..
if(cur_wp == -2) {
Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode.");
roamer = false;
cur_wp = 0;
}
if(GetAppearance() != eaStanding)
SetAppearance(eaStanding, false);
entity_list.OpenDoorsNear(CastToNPC());
if(!DistractedFromGrid) {
//kick off event_waypoint depart
char temp[16];
sprintf(temp, "%d", cur_wp);
parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0);
//setup our next waypoint, if we are still on our normal grid
//remember that the quest event above could have done anything it wanted with our grid
if(gridno > 0) {
CastToNPC()->CalculateNewWaypoint();
}
}
else {
DistractedFromGrid = false;
}
}
} // endif (movetimercompleted==true) } // endif (movetimercompleted==true)
else if (!(AIwalking_timer->Enabled())) else if (!(AIwalking_timer->Enabled()))
{ // currently moving { // currently moving
bool doMove = true;
if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY()) if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY())
{ // are we there yet? then stop { // are we there yet? then stop
Log.Out(Logs::Detail, Logs::AI, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid()); Log.Out(Logs::Detail, Logs::AI, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid());
SetWaypointPause(); if (cur_wp_pause != 0) {
if(GetAppearance() != eaStanding) SetWaypointPause();
SetAppearance(eaStanding, false); SetAppearance(eaStanding, false);
SetMoving(false); SetMoving(false);
if (m_CurrentWayPoint.w >= 0.0) { if (m_CurrentWayPoint.w >= 0.0) {
SetHeading(m_CurrentWayPoint.w); SetHeading(m_CurrentWayPoint.w);
}
SendPosition();
} }
SendPosition();
//kick off event_waypoint arrive //kick off event_waypoint arrive
char temp[16]; char temp[16];
sprintf(temp, "%d", cur_wp); sprintf(temp, "%d", cur_wp);
parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0); parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0);
// start moving directly to next waypoint if we're at a 0 pause waypoint and we didn't get quest halted.
if (!AIwalking_timer->Enabled())
AI_SetupNextWaypoint();
else
doMove = false;
// wipe feign memory since we reached our first waypoint // wipe feign memory since we reached our first waypoint
if(cur_wp == 1) if(cur_wp == 1)
ClearFeignMemory(); ClearFeignMemory();
} }
else if (doMove)
{ // not at waypoint yet, so keep moving { // not at waypoint yet or at 0 pause WP, so keep moving
if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0)) if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0))
CalculateNewPosition2(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true); CalculateNewPosition2(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true);
else else
@ -1775,8 +1713,7 @@ void NPC::AI_DoMovement() {
SetGrid( 0 - GetGrid()); // revert to AI control SetGrid( 0 - GetGrid()); // revert to AI control
Log.Out(Logs::Detail, Logs::Pathing, "Quest pathing is finished. Resuming on grid %d", GetGrid()); Log.Out(Logs::Detail, Logs::Pathing, "Quest pathing is finished. Resuming on grid %d", GetGrid());
if(GetAppearance() != eaStanding) SetAppearance(eaStanding, false);
SetAppearance(eaStanding, false);
CalculateNewWaypoint(); CalculateNewWaypoint();
} }
@ -1812,29 +1749,86 @@ void NPC::AI_DoMovement() {
Log.Out(Logs::Detail, Logs::AI, "Reached guard point (%.3f,%.3f,%.3f)", m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z); Log.Out(Logs::Detail, Logs::AI, "Reached guard point (%.3f,%.3f,%.3f)", m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z);
ClearFeignMemory(); ClearFeignMemory();
moved=false; moved=false;
SetMoving(false);
if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5*5 ) if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5*5 )
{ {
SetHeading(m_GuardPoint.w); SetHeading(m_GuardPoint.w);
} else { } else {
FaceTarget(GetTarget()); FaceTarget(GetTarget());
} }
SendPosition(); SetCurrentSpeed(0);
SetAppearance(GetGuardPointAnim()); SetAppearance(GetGuardPointAnim());
} }
} }
} }
} }
void NPC::AI_SetupNextWaypoint() {
int32 spawn_id = this->GetSpawnPointID();
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
iterator.Reset();
Spawn2 *found_spawn = nullptr;
while (iterator.MoreElements())
{
Spawn2* cur = iterator.GetData();
iterator.Advance();
if (cur->GetID() == spawn_id)
{
found_spawn = cur;
break;
}
}
if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) {
CastToNPC()->Depop(true); //depop and restart spawn timer
if (found_spawn)
found_spawn->SetNPCPointerNull();
}
else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) {
CastToNPC()->Depop(false);//depop without spawn timer
if (found_spawn)
found_spawn->SetNPCPointerNull();
}
else {
movetimercompleted = false;
Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp);
//if we were under quest control (with no grid), we are done now..
if (cur_wp == -2) {
Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode.");
roamer = false;
cur_wp = 0;
}
SetAppearance(eaStanding, false);
entity_list.OpenDoorsNear(CastToNPC());
if (!DistractedFromGrid) {
//kick off event_waypoint depart
char temp[16];
sprintf(temp, "%d", cur_wp);
parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0);
//setup our next waypoint, if we are still on our normal grid
//remember that the quest event above could have done anything it wanted with our grid
if (GetGrid() > 0) {
CastToNPC()->CalculateNewWaypoint();
}
}
else {
DistractedFromGrid = false;
}
}
}
// Note: Mob that caused this may not get added to the hate list until after this function call completes // Note: Mob that caused this may not get added to the hate list until after this function call completes
void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) { void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
if (!IsAIControlled()) if (!IsAIControlled())
return; return;
if(GetAppearance() != eaStanding) SetAppearance(eaStanding);
{
SetAppearance(eaStanding);
}
if (iYellForHelp) { if (iYellForHelp) {
if(IsPet()) { if(IsPet()) {
@ -1881,9 +1875,10 @@ void Mob::AI_Event_NoLongerEngaged() {
pLastFightingDelayMoving += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving); pLastFightingDelayMoving += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving);
// So mobs don't keep running as a ghost until AIwalking_timer fires // So mobs don't keep running as a ghost until AIwalking_timer fires
// if they were moving prior to losing all hate // if they were moving prior to losing all hate
if(IsMoving()){ // except if we're a pet, then we might run into some issues with pets backing off when they should immediately be moving
if(!IsPet())
{
SetRunAnimSpeed(0); SetRunAnimSpeed(0);
SetMoving(false);
SendPosition(); SendPosition();
} }
ClearRampage(); ClearRampage();
@ -2557,11 +2552,9 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
if (!AI_HasSpellsEffects()) if (!AI_HasSpellsEffects())
return; return;
for(int i=0; i < AIspellsEffects.size(); i++) for (int i = 0; i < AIspellsEffects.size(); i++)
{ ApplySpellsBonuses(0, 0, newbon, 0, 0, 0, -1, 10, true, AIspellsEffects[i].spelleffectid,
ApplySpellsBonuses(0, 0, newbon, 0, 0, 0,-1, AIspellsEffects[i].base, AIspellsEffects[i].limit, AIspellsEffects[i].max);
true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
}
return; return;
} }

View File

@ -423,6 +423,7 @@ int main(int argc, char** argv) {
entity_list.Process(); entity_list.Process();
entity_list.MobProcess(); entity_list.MobProcess();
entity_list.BeaconProcess(); entity_list.BeaconProcess();
entity_list.EncounterProcess();
if (zone) { if (zone) {
if(!zone->Process()) { if(!zone->Process()) {

View File

@ -115,7 +115,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
knightattack_timer(1000), knightattack_timer(1000),
assist_timer(AIassistcheck_delay), assist_timer(AIassistcheck_delay),
qglobal_purge_timer(30000), qglobal_purge_timer(30000),
sendhpupdate_timer(1000), sendhpupdate_timer(2000),
enraged_timer(1000), enraged_timer(1000),
taunt_timer(TauntReuseTime * 1000), taunt_timer(TauntReuseTime * 1000),
m_SpawnPoint(position), m_SpawnPoint(position),
@ -522,7 +522,7 @@ void NPC::QueryLoot(Client* to)
linker.SetItemData(item); linker.SetItemData(item);
auto item_link = linker.GenerateLink(); auto item_link = linker.GenerateLink();
to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", item_link.c_str(), item->ID, (*cur)->min_level, (*cur)->max_level); to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", item_link.c_str(), item->ID, (*cur)->min_level, (*cur)->max_level);
} }
@ -569,8 +569,7 @@ bool NPC::Process()
{ {
if (IsStunned() && stunned_timer.Check()) if (IsStunned() && stunned_timer.Check())
{ {
this->stunned = false; Mob::UnStun();
this->stunned_timer.Disable();
this->spun_timer.Disable(); this->spun_timer.Disable();
} }
@ -651,7 +650,8 @@ bool NPC::Process()
} }
} }
if (sendhpupdate_timer.Check() && (IsTargeted() || (IsPet() && GetOwner() && GetOwner()->IsClient()))) { // we might actually want to reset in this check ... won't until issues arise at least :P
if (sendhpupdate_timer.Check(false) && (IsTargeted() || (IsPet() && GetOwner() && GetOwner()->IsClient()))) {
if(!IsFullHP || cur_hp<max_hp){ if(!IsFullHP || cur_hp<max_hp){
SendHPUpdate(); SendHPUpdate();
} }
@ -724,7 +724,7 @@ void NPC::UpdateEquipmentLight()
{ {
m_Light.Type.Equipment = 0; m_Light.Type.Equipment = 0;
m_Light.Level.Equipment = 0; m_Light.Level.Equipment = 0;
for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) { for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) {
if (index == MainAmmo) { continue; } if (index == MainAmmo) { continue; }
@ -1933,7 +1933,7 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; } else if(id == "special_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 == "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; }
@ -2418,7 +2418,7 @@ void NPC::DoQuestPause(Mob *other) {
} }
void NPC::ChangeLastName(const char* in_lastname) void NPC::ChangeLastName(const char* in_lastname)
{ {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct)); EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct));
@ -2468,9 +2468,9 @@ void NPC::DepopSwarmPets()
} }
if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()){ if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()){
Mob *targMob = entity_list.GetMob(GetPetTargetLockID()); Mob *targMob = entity_list.GetMob(GetPetTargetLockID());
if(!targMob || (targMob && targMob->IsCorpse())){ if(!targMob || (targMob && targMob->IsCorpse())){
Kill(); Kill();
return; return;

Some files were not shown because too many files have changed in this diff Show More