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 ExportSkillCaps(SharedDatabase *db);
void ExportBaseData(SharedDatabase *db);
void ExportDBStrings(SharedDatabase *db);
int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformClientExport);
@ -62,6 +63,7 @@ int main(int argc, char **argv) {
ExportSpells(&database);
ExportSkillCaps(&database);
ExportBaseData(&database);
ExportDBStrings(&database);
Log.CloseFileLogs();
@ -194,7 +196,38 @@ void ExportBaseData(SharedDatabase *db) {
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);

View File

@ -30,6 +30,7 @@ EQEmuLogSys Log;
void ImportSpells(SharedDatabase *db);
void ImportSkillCaps(SharedDatabase *db);
void ImportBaseData(SharedDatabase *db);
void ImportDBStrings(SharedDatabase *db);
int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformClientImport);
@ -59,6 +60,7 @@ int main(int argc, char **argv) {
ImportSpells(&database);
ImportSkillCaps(&database);
ImportBaseData(&database);
ImportDBStrings(&database);
Log.CloseFileLogs();
@ -202,7 +204,6 @@ void ImportSkillCaps(SharedDatabase *db) {
continue;
}
int class_id, skill_id, level, cap;
class_id = atoi(split[0].c_str());
skill_id = atoi(split[1].c_str());
@ -262,3 +263,56 @@ void ImportBaseData(SharedDatabase *db) {
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_PetBuffWindow),
N(OP_PetCommands),
N(OP_PetHoTT),
N(OP_Petition),
N(OP_PetitionBug),
N(OP_PetitionCheckIn),
@ -364,6 +365,8 @@ N(OP_PetitionUnCheckout),
N(OP_PetitionUpdate),
N(OP_PickPocket),
N(OP_PlayerProfile),
N(OP_PlayerStateAdd),
N(OP_PlayerStateRemove),
N(OP_PlayEverquestRequest),
N(OP_PlayEverquestResponse),
N(OP_PlayMP3),
@ -519,8 +522,6 @@ N(OP_VetRewardsAvaliable),
N(OP_VoiceMacroIn),
N(OP_VoiceMacroOut),
N(OP_WeaponEquip1),
N(OP_WeaponEquip2),
N(OP_WeaponUnequip2),
N(OP_WearChange),
N(OP_Weather),
N(OP_Weblink),

View File

@ -281,7 +281,8 @@ struct Spawn_Struct {
/*0146*/ uint8 beard; // Beard style (not totally, sure but maybe!)
/*0147*/ uint8 unknown0147[4];
/*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
/*0157*/ char suffix[32]; // Player's suffix (of Veeshan, etc.)
/*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
** Length: 176 Bytes
@ -555,7 +561,7 @@ struct SpellBuff_Struct
/*002*/ uint8 bard_modifier;
/*003*/ uint8 effect; //not real
/*004*/ uint32 spellid;
/*008*/ uint32 duration;
/*008*/ int32 duration;
/*012*/ uint32 counters;
/*016*/ uint32 player_id; //'global' ID of the caster, for wearoff messages
/*020*/
@ -568,7 +574,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect;
/*007*/ uint8 unknown7;
/*008*/ uint32 spellid;
/*012*/ uint32 duration;
/*012*/ int32 duration;
/*016*/ uint32 num_hits;
/*020*/ uint32 unknown020; //prolly global player ID
/*024*/ uint32 slotid;
@ -586,14 +592,8 @@ struct BuffRemoveRequest_Struct
struct PetBuff_Struct {
/*000*/ uint32 petid;
/*004*/ uint32 spellid[BUFF_COUNT];
/*104*/ uint32 unknown700;
/*108*/ uint32 unknown701;
/*112*/ uint32 unknown702;
/*116*/ uint32 unknown703;
/*120*/ uint32 unknown704;
/*124*/ uint32 ticsremaining[BUFF_COUNT];
/*224*/ uchar unknown705[20];
/*004*/ uint32 spellid[BUFF_COUNT+5];
/*124*/ int32 ticsremaining[BUFF_COUNT+5];
/*244*/ uint32 buffcount;
};
@ -734,6 +734,7 @@ struct AA_Array
{
uint32 AA;
uint32 value;
uint32 charges;
};
@ -1168,7 +1169,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct {
/*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
/* 05 */ uint16 spellid;
/* 07 */ uint32 damage;
/* 11 */ uint32 unknown11;
/* 15 */ uint32 sequence; // see above notes in Action_Struct
/* 19 */ uint32 unknown19;
/* 11 */ float force;
/* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ float meleepush_z;
/* 23 */
};
@ -2167,24 +2168,24 @@ struct Illusion_Struct_Old {
// OP_Sound - Size: 68
struct QuestReward_Struct
{
/*000*/ uint32 from_mob; // ID of mob awarding the client
/*004*/ uint32 unknown004;
/*008*/ uint32 unknown008;
/*012*/ uint32 unknown012;
/*016*/ uint32 unknown016;
/*020*/ uint32 unknown020;
/*024*/ uint32 silver; // Gives silver to the client
/*028*/ uint32 gold; // Gives gold to the client
/*032*/ uint32 platinum; // Gives platinum to the client
/*036*/ uint32 unknown036;
/*040*/ uint32 unknown040;
/*044*/ uint32 unknown044;
/*048*/ uint32 unknown048;
/*052*/ uint32 unknown052;
/*056*/ uint32 unknown056;
/*060*/ uint32 unknown060;
/*064*/ uint32 unknown064;
/*068*/
/*000*/ uint32 mob_id; // ID of mob awarding the client
/*004*/ uint32 target_id;
/*008*/ uint32 exp_reward;
/*012*/ uint32 faction;
/*016*/ int32 faction_mod;
/*020*/ uint32 copper; // Gives copper to the client
/*024*/ uint32 silver; // Gives silver to the client
/*028*/ uint32 gold; // Gives gold to the client
/*032*/ uint32 platinum; // Gives platinum to the client
/*036*/ uint32 item_id;
/*040*/ uint32 unknown040;
/*044*/ uint32 unknown044;
/*048*/ uint32 unknown048;
/*052*/ uint32 unknown052;
/*056*/ uint32 unknown056;
/*060*/ uint32 unknown060;
/*064*/ uint32 unknown064;
/*068*/
};
// Size: 8
@ -2554,8 +2555,8 @@ struct BookRequest_Struct {
*/
struct Object_Struct {
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
/*08*/ uint16 unknown008; //
/*10*/ uint16 unknown010; //
/*08*/ uint16 size; //
/*10*/ uint16 solidtype; //
/*12*/ uint32 drop_id; // Unique object id for zone
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
/*18*/ uint16 zone_instance; //
@ -4049,7 +4050,7 @@ struct MarkNPC_Struct
struct InspectBuffs_Struct {
/*000*/ uint32 spell_id[BUFF_COUNT];
/*100*/ uint32 tics_remaining[BUFF_COUNT];
/*100*/ int32 tics_remaining[BUFF_COUNT];
};
struct RaidGeneral_Struct {
@ -4295,14 +4296,6 @@ struct AA_Action {
/*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 {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
/*04*/ uint32 aapoints_unspent;
@ -4320,12 +4313,12 @@ struct AltAdvStats_Struct {
};
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 {
/*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 {
@ -4750,7 +4743,7 @@ struct BuffIconEntry_Struct
{
uint32 buff_slot;
uint32 spell_id;
uint32 tics_remaining;
int32 tics_remaining;
uint32 num_hits;
};
@ -4759,6 +4752,7 @@ struct BuffIcon_Struct
uint32 entity_id;
uint8 all_buffs;
uint16 count;
uint8 type; // 0 = self buff window, 1 = self target window, 4 = group, 5 = PC, 7 = NPC
BuffIconEntry_Struct entries[0];
};

View File

@ -72,6 +72,8 @@ void EQStream::init(bool resetSession) {
RateThreshold=RATEBASE/250;
DecayRate=DECAYBASE/250;
BytesWritten=0;
sent_packet_count = 0;
received_packet_count = 0;
SequencedBase = 0;
NextSequencedSend = 0;
@ -464,37 +466,45 @@ void EQStream::ProcessPacket(EQProtocolPacket *p)
}
break;
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);
break;
}
#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,
(unsigned long)ntohl(Stats->packets_received), (unsigned long)ntohl(Stats->packets_sent), (unsigned long)ntohl(Stats->last_local_delta),
(unsigned long)ntohl(Stats->low_delta), (unsigned long)ntohl(Stats->average_delta),
(unsigned long)ntohl(Stats->high_delta), (unsigned long)ntohl(Stats->last_remote_delta));
uint64 x=Stats->packets_received;
Stats->packets_received=Stats->packets_sent;
Stats->packets_sent=x;
NonSequencedPush(new EQProtocolPacket(OP_SessionStatResponse,p->pBuffer,p->size));
AdjustRates(ntohl(Stats->average_delta));
(unsigned long)ntohl(ClientStats->packets_received), (unsigned long)ntohl(ClientStats->packets_sent), (unsigned long)ntohl(ClientStats->last_local_delta),
(unsigned long)ntohl(ClientStats->low_delta), (unsigned long)ntohl(ClientStats->average_delta),
(unsigned long)ntohl(ClientStats->high_delta), (unsigned long)ntohl(ClientStats->last_remote_delta));
AdjustRates(ntohl(ClientStats->average_delta));
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
if((ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) > (ntohl(Stats->average_delta) * 2)) {
retransmittimeout = (ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta))
if ((ntohl(ClientStats->last_local_delta) + ntohl(ClientStats->last_remote_delta)) > (ntohl(ClientStats->average_delta) * 2)) {
retransmittimeout = (ntohl(ClientStats->last_local_delta) + ntohl(ClientStats->last_remote_delta))
* RETRANSMIT_TIMEOUT_MULT;
} else {
retransmittimeout = ntohl(Stats->average_delta) * 2 * RETRANSMIT_TIMEOUT_MULT;
retransmittimeout = ntohl(ClientStats->average_delta) * 2 * RETRANSMIT_TIMEOUT_MULT;
}
if(retransmittimeout > RETRANSMIT_TIMEOUT_MAX)
retransmittimeout = RETRANSMIT_TIMEOUT_MAX;
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
}
break;
@ -573,16 +583,18 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
// Convert the EQApplicationPacket to 1 or more EQProtocolPackets
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];
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);
*(uint32 *)(out->pBuffer+2)=htonl(p->Size());
*(uint32 *)(out->pBuffer+2)=htonl(length);
used=MaxLen-10;
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);
@ -593,7 +605,7 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
out->size=chunksize+2;
SequencedPush(out);
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[] tmpbuff;
@ -1101,8 +1113,8 @@ EQProtocolPacket *p=nullptr;
void EQStream::Process(const unsigned char *buffer, const uint32 length)
{
static unsigned char newbuffer[2048];
uint32 newlength=0;
static unsigned char newbuffer[2048];
uint32 newlength=0;
if (EQProtocolPacket::ValidateCRC(buffer,length,Key)) {
if (compressed) {
newlength=EQProtocolPacket::Decompress(buffer,length,newbuffer,2048);

View File

@ -71,7 +71,7 @@ struct SessionResponse {
};
//Deltas are in ms, representing round trip times
struct SessionStats {
struct ClientSessionStats {
/*000*/ uint16 RequestID;
/*002*/ uint32 last_local_delta;
/*006*/ uint32 average_delta;
@ -83,6 +83,16 @@ struct SessionStats {
/*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()
class OpcodeManager;
@ -158,6 +168,9 @@ class EQStream : public EQStreamInterface {
int32 BytesWritten;
uint64 sent_packet_count;
uint64 received_packet_count;
Mutex MRate;
int32 RateThreshold;
int32 DecayRate;
@ -265,11 +278,13 @@ class EQStream : public EQStreamInterface {
void AddBytesSent(uint32 bytes)
{
bytes_sent += bytes;
++sent_packet_count;
}
void AddBytesRecv(uint32 bytes)
{
bytes_recv += bytes;
++received_packet_count;
}
virtual const uint32 GetBytesSent() const { return bytes_sent; }
@ -288,6 +303,9 @@ class EQStream : public EQStreamInterface {
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
class Signature {
public:

View File

@ -43,19 +43,19 @@ EQTime::EQTime(TimeOfDay_Struct start_eq, time_t start_real)
EQTime::EQTime()
{
timezone=0;
timezone = 0;
memset(&eqTime, 0, sizeof(eqTime));
//Defaults for time
TimeOfDay_Struct start;
start.day=1;
start.hour=9;
start.minute=0;
start.month=1;
start.year=3100;
start.day = 1;
start.hour = 9;
start.minute = 0;
start.month = 1;
start.year = 3100;
//Set default time zone
timezone=0;
timezone = 0;
//Start EQTimer
setEQTimeOfDay(start, time(0));
SetCurrentEQTimeOfDay(start, time(0));
}
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.
//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. */
if( eqTime.start_realtime == 0 )
if (eqTime.start_realtime == 0)
return 0;
unsigned long diff = timeConvert - eqTime.start_realtime;
@ -83,7 +83,7 @@ int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeO
int32 ntz = timezone;
/* The minutes range from 0 - 59 */
diff += eqTime.start_eqtime.minute + (ntz%60);
diff += eqTime.start_eqtime.minute + (ntz % 60);
eqTimeOfDay->minute = diff % 60;
diff /= 60;
ntz /= 60;
@ -97,24 +97,24 @@ int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeO
//
// Modify it so that it works from
// 0-23 for our calculations
diff += ( eqTime.start_eqtime.hour - 1) + (ntz%24);
eqTimeOfDay->hour = (diff%24) + 1;
diff += (eqTime.start_eqtime.hour - 1) + (ntz % 24);
eqTimeOfDay->hour = (diff % 24) + 1;
diff /= 24;
ntz /= 24;
// The days range from 1-28
// Modify it so that it works from
// 0-27 for our calculations
diff += ( eqTime.start_eqtime.day - 1 ) + (ntz%28);
eqTimeOfDay->day = (diff%28) + 1;
diff += (eqTime.start_eqtime.day - 1) + (ntz % 28);
eqTimeOfDay->day = (diff % 28) + 1;
diff /= 28;
ntz /= 28;
// The months range from 1-12
// Modify it so that it works from
// 0-11 for our calculations
diff += ( eqTime.start_eqtime.month - 1 ) + (ntz%12);
eqTimeOfDay->month = (diff%12) + 1;
diff += (eqTime.start_eqtime.month - 1) + (ntz % 12);
eqTimeOfDay->month = (diff % 12) + 1;
diff /= 12;
ntz /= 12;
@ -124,12 +124,12 @@ int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeO
}
//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;
eqTime.start_eqtime=start_eq;
eqTime.start_realtime=start_real;
eqTime.start_eqtime = start_eq;
eqTime.start_realtime = start_real;
return 1;
}
@ -139,7 +139,7 @@ bool EQTime::saveFile(const char *filename)
{
std::ofstream of;
of.open(filename);
if(!of)
if (!of)
{
Log.Out(Logs::General, Logs::Error, "EQTime::saveFile failed: Unable to open file '%s'", filename);
return false;
@ -200,24 +200,24 @@ bool EQTime::loadFile(const char *filename)
bool EQTime::IsTimeBefore(TimeOfDay_Struct *base, TimeOfDay_Struct *test) {
if(base->year > test->year)
if (base->year > test->year)
return(true);
if(base->year < test->year)
if (base->year < test->year)
return(false);
//same years
if(base->month > test->month)
if (base->month > test->month)
return(true);
if(base->month < test->month)
if (base->month < test->month)
return(false);
//same month
if(base->day > test->day)
if (base->day > test->day)
return(true);
if(base->day < test->day)
if (base->day < test->day)
return(false);
//same day
if(base->hour > test->hour)
if (base->hour > test->hour)
return(true);
if(base->hour < test->hour)
if (base->hour < test->hour)
return(false);
//same hour...
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
cur = to->minute;
cur += minutes;
if(cur < 60) {
if (cur < 60) {
to->minute = cur;
return;
}
@ -238,29 +238,29 @@ void EQTime::AddMinutes(uint32 minutes, TimeOfDay_Struct *to) {
//carry hours
cur /= 60;
cur += to->hour;
if(cur <= 24) {
if (cur <= 24) {
to->hour = cur;
return;
}
to->hour = ((cur-1) % 24) + 1;
to->hour = ((cur - 1) % 24) + 1;
//carry days
cur = (cur-1) / 24;
cur = (cur - 1) / 24;
cur += to->day;
if(cur <= 28) {
if (cur <= 28) {
to->day = cur;
return;
}
to->day = ((cur-1) % 28) + 1;
to->day = ((cur - 1) % 28) + 1;
//carry months
cur = (cur-1) / 28;
cur = (cur - 1) / 28;
cur += to->month;
if(cur <= 12) {
if (cur <= 12) {
to->month = cur;
return;
}
to->month = ((cur-1) % 12) + 1;
to->month = ((cur - 1) % 12) + 1;
//carry years
to->year += (cur-1) / 12;
to->year += (cur - 1) / 12;
}
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);
buf[127] = '\0';
str = buf;
}
}

View File

@ -21,8 +21,8 @@ public:
~EQTime();
//Get functions
int getEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(getEQTimeOfDay(time(nullptr), eqTimeOfDay)); }
int getEQTimeOfDay( time_t timeConvert, TimeOfDay_Struct *eqTimeOfDay );
int GetCurrentEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(GetCurrentEQTimeOfDay(time(nullptr), eqTimeOfDay)); }
int GetCurrentEQTimeOfDay( time_t timeConvert, TimeOfDay_Struct *eqTimeOfDay );
TimeOfDay_Struct getStartEQTime() { return eqTime.start_eqtime; }
time_t getStartRealTime() { return eqTime.start_realtime; }
uint32 getEQTimeZone() { return timezone; }
@ -30,7 +30,7 @@ public:
uint32 getEQTimeZoneMin() { return timezone%60; }
//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; }
//Time math/logic functions

View File

@ -183,7 +183,7 @@ struct ItemData {
uint32 AugType;
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 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 LDoNPrice;
uint32 LDoNSold;

View File

@ -417,7 +417,7 @@ namespace RoF
outapp->WriteUInt32(0); // Duration
outapp->WriteUInt32(0); // ?
outapp->WriteUInt8(0); // Caster name
outapp->WriteUInt8(0); // Terminating byte
outapp->WriteUInt8(0); // Type
}
FINISH_ENCODE();
@ -454,7 +454,7 @@ namespace RoF
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
__packet->WriteString("");
}
__packet->WriteUInt8(!emu->all_buffs); // Unknown
__packet->WriteUInt8(emu->type); // Unknown
FINISH_ENCODE();
}
@ -659,7 +659,9 @@ namespace RoF
OUT(type);
OUT(spellid);
OUT(damage);
eq->sequence = emu->sequence;
OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE();
}
@ -974,8 +976,8 @@ namespace RoF
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, 0); // Normally 0, but seen (float)255.0 as well
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 1); // Need to add emu->size to struct
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->solidtype); // Unknown
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->x);
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].value);
outapp->WriteUInt32(0);
outapp->WriteUInt32(emu->aa_array[r].charges);
}
// Fill the other 60 AAs with zeroes
@ -2817,9 +2819,9 @@ namespace RoF
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_value = emu->aa_list[i].aa_value;
eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08;
eq->aa_list[i].AA = emu->aa_list[i].AA;
eq->aa_list[i].value = emu->aa_list[i].value;
eq->aa_list[i].charges = emu->aa_list[i].charges;
}
FINISH_ENCODE();
@ -2851,7 +2853,7 @@ namespace RoF
// Check clientver field to verify this AA should be sent for SoF
// clientver 1 is for all clients and 5 is for Live
if (emu->clientver <= 5)
if (emu->clientver <= 7)
{
OUT(id);
eq->unknown004 = 1;
@ -2867,9 +2869,9 @@ namespace RoF
OUT(cost);
OUT(seq);
OUT(current_level);
eq->unknown037 = 1; // Introduced during HoT
eq->prereq_skill_count = 1; // min 1
OUT(prereq_skill);
eq->unknown045 = 1; // New Mar 21 2012 - Seen 1
eq->prereq_minpoints_count = 1; // min 1
OUT(prereq_minpoints);
eq->type = emu->sof_type;
OUT(spellid);
@ -2885,6 +2887,7 @@ namespace RoF
OUT(cost2);
eq->aa_expansion = emu->aa_expansion;
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);
unsigned int r;
for (r = 0; r < emu->total_abilities; r++) {
@ -2945,11 +2948,12 @@ namespace RoF
for (int counter = 0; counter < character_count; ++counter) {
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);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_ptr += strlen(emu_cse->Name);
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->Race = emu_cse->Race;
@ -3989,7 +3993,7 @@ namespace RoF
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
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); // unknown16
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
@ -4390,7 +4394,7 @@ namespace RoF
IN(type);
IN(spellid);
IN(damage);
emu->sequence = eq->sequence;
IN(meleepush_xy);
FINISH_DIRECT_DECODE();
}
@ -4718,7 +4722,7 @@ namespace RoF
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
IN(command);
emu->unknown = eq->unknown04;
IN(target);
FINISH_DIRECT_DECODE();
}

View File

@ -485,7 +485,7 @@ namespace RoF2
outapp->WriteUInt32(0); // Duration
outapp->WriteUInt32(0); // ?
outapp->WriteUInt8(0); // Caster name
outapp->WriteUInt8(0); // Terminating byte
outapp->WriteUInt8(0); // Type
}
FINISH_ENCODE();
@ -527,7 +527,7 @@ namespace RoF2
__packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
__packet->WriteString("");
}
__packet->WriteUInt8(!emu->all_buffs); // Unknown
__packet->WriteUInt8(emu->type); // Unknown
FINISH_ENCODE();
}
@ -700,7 +700,9 @@ namespace RoF2
OUT(type);
OUT(spellid);
OUT(damage);
eq->sequence = emu->sequence;
OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE();
}
@ -1015,8 +1017,8 @@ namespace RoF2
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, 0); // Normally 0, but seen (float)255.0 as well
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Unknown
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 1); // Need to add emu->size to struct
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->solidtype); // Unknown
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->x);
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].value);
outapp->WriteUInt32(0);
outapp->WriteUInt32(emu->aa_array[r].charges);
}
// Fill the other 60 AAs with zeroes
@ -2892,9 +2894,9 @@ namespace RoF2
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_value = emu->aa_list[i].aa_value;
eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08;
eq->aa_list[i].AA = emu->aa_list[i].AA;
eq->aa_list[i].value = emu->aa_list[i].value;
eq->aa_list[i].charges = emu->aa_list[i].charges;
}
FINISH_ENCODE();
@ -2926,7 +2928,7 @@ namespace RoF2
// Check clientver field to verify this AA should be sent for SoF
// clientver 1 is for all clients and 5 is for Live
if (emu->clientver <= 5)
if (emu->clientver <= 8)
{
OUT(id);
eq->unknown004 = 1;
@ -2942,9 +2944,9 @@ namespace RoF2
OUT(cost);
OUT(seq);
OUT(current_level);
eq->unknown037 = 1; // Introduced during HoT
eq->prereq_skill_count = 1; // min 1
OUT(prereq_skill);
eq->unknown045 = 1; // New Mar 21 2012 - Seen 1
eq->prereq_minpoints_count = 1; // min 1
OUT(prereq_minpoints);
eq->type = emu->sof_type;
OUT(spellid);
@ -2961,6 +2963,7 @@ namespace RoF2
eq->aa_expansion = emu->aa_expansion;
eq->special_category = emu->special_category;
OUT(total_abilities);
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number
unsigned int r;
for (r = 0; r < emu->total_abilities; r++) {
OUT(abilities[r].skill_id);
@ -3020,11 +3023,12 @@ namespace RoF2
for (int counter = 0; counter < character_count; ++counter) {
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);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_ptr += strlen(emu_cse->Name);
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->Race = emu_cse->Race;
@ -4125,7 +4129,7 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
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); // unknown16
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
@ -4525,7 +4529,7 @@ namespace RoF2
IN(type);
IN(spellid);
IN(damage);
emu->sequence = eq->sequence;
IN(meleepush_xy);
FINISH_DIRECT_DECODE();
}
@ -4856,7 +4860,7 @@ namespace RoF2
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
IN(command);
emu->unknown = eq->unknown04;
IN(target);
FINISH_DIRECT_DECODE();
}

View File

@ -416,7 +416,7 @@ struct Spawn_Struct
/*0000*/ uint8 unknown12;
/*0000*/ uint32 petOwnerId;
/*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 unknown16;
/*0000*/ uint32 unknown17;
@ -687,7 +687,7 @@ struct SpellBuff_Struct
/*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*009*/ uint32 unknown016;
/*013*/ uint8 bard_modifier;
/*014*/ uint32 duration;
/*014*/ int32 duration;
/*018*/ uint8 level;
/*019*/ uint32 spellid;
/*023*/ uint32 counters;
@ -703,7 +703,7 @@ struct SpellBuff_Struct_Old
/*003*/ uint8 effect; // not real
/*004*/ float unknown004; // Seen 1 for no buff
/*008*/ uint32 spellid;
/*012*/ uint32 duration;
/*012*/ int32 duration;
/*016*/ uint32 unknown016;
/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*024*/ uint32 counters;
@ -720,7 +720,7 @@ struct SpellBuffFade_Struct_Live {
/*007*/ uint8 unknown007;
/*008*/ float unknown008;
/*012*/ uint32 spellid;
/*016*/ uint32 duration;
/*016*/ int32 duration;
/*020*/ uint32 playerId; // Global player ID?
/*024*/ uint32 num_hits;
/*028*/ uint8 unknown0028[64];
@ -736,7 +736,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect;
/*007*/ uint8 unknown7;
/*008*/ uint32 spellid;
/*012*/ uint32 duration;
/*012*/ int32 duration;
/*016*/ uint32 num_hits;
/*020*/ uint32 unknown020; // Global player ID?
/*024*/ uint32 playerId; // Player id who cast the buff
@ -877,7 +877,7 @@ struct AA_Array
{
uint32 AA;
uint32 value;
uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live
uint32 charges; // expendable charges
};
struct Disciplines_Struct {
@ -1293,7 +1293,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct {
/*00*/ uint32 command;
/*04*/ uint32 unknown04;
/*04*/ uint32 target;
/*08*/ uint32 unknown08;
};
@ -1484,9 +1484,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint32 spellid;
/* 09 */ int32 damage;
/* 13 */ float unknown11; // cd cc cc 3d
/* 17 */ float sequence; // see above notes in Action_Struct
/* 21 */ uint8 unknown19[9]; // was [9]
/* 13 */ float force; // cd cc cc 3d
/* 17 */ float meleepush_xy; // see above notes in Action_Struct
/* 21 */ float meleepush_z;
/* 25 */ uint8 unknown25[5]; // was [9]
/* 30 */
};
@ -2472,7 +2473,7 @@ struct GroupFollow_Struct { // Live Follow Struct
struct InspectBuffs_Struct {
/*000*/ uint32 spell_id[BUFF_COUNT];
/*168*/ uint32 tics_remaining[BUFF_COUNT];
/*168*/ int32 tics_remaining[BUFF_COUNT];
};
struct LFG_Struct {
@ -4252,9 +4253,9 @@ struct SendAA_Struct {
/*0025*/ uint32 cost;
/*0029*/ uint32 seq;
/*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 #
/*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
/*0053*/ uint32 type;
/*0057*/ uint32 spellid;
@ -4267,10 +4268,16 @@ struct SendAA_Struct {
/*0081*/ uint32 last_id;
/*0085*/ uint32 next_id;
/*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;
/*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;
/*0116*/ AA_Ability abilities[0];
};
@ -4287,12 +4294,6 @@ struct AA_Action {
/*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 {
/*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?
AA_Skills aa_list[MAX_PP_AA_ARRAY];
};
struct AA_Values {
/*00*/ uint32 aa_skill;
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
/*12*/
AA_Array aa_list[MAX_PP_AA_ARRAY];
};
struct AATable_Struct {
@ -4329,7 +4323,7 @@ struct AATable_Struct {
/*12*/ uint32 aa_spent_archetype; // Seen 40
/*16*/ uint32 aa_spent_class; // Seen 103
/*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 {

View File

@ -410,7 +410,7 @@ struct Spawn_Struct
/*0000*/ uint8 unknown12;
/*0000*/ uint32 petOwnerId;
/*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 unknown16;
/*0000*/ uint32 unknown17;
@ -676,7 +676,7 @@ struct SpellBuff_Struct
/*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*009*/ uint32 unknown016;
/*013*/ uint8 bard_modifier;
/*014*/ uint32 duration;
/*014*/ int32 duration;
/*018*/ uint8 level;
/*019*/ uint32 spellid;
/*023*/ uint32 counters;
@ -692,7 +692,7 @@ struct SpellBuff_Struct_Old
/*003*/ uint8 effect; // not real
/*004*/ float unknown004; // Seen 1 for no buff
/*008*/ uint32 spellid;
/*012*/ uint32 duration;
/*012*/ int32 duration;
/*016*/ uint32 unknown016;
/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*024*/ uint32 counters;
@ -709,7 +709,7 @@ struct SpellBuffFade_Struct_Live {
/*007*/ uint8 unknown007;
/*008*/ float unknown008;
/*012*/ uint32 spellid;
/*016*/ uint32 duration;
/*016*/ int32 duration;
/*020*/ uint32 playerId; // Global player ID?
/*024*/ uint32 num_hits;
/*028*/ uint8 unknown0028[64];
@ -725,7 +725,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect;
/*007*/ uint8 unknown7;
/*008*/ uint32 spellid;
/*012*/ uint32 duration;
/*012*/ int32 duration;
/*016*/ uint32 num_hits;
/*020*/ uint32 unknown020; // Global player ID?
/*024*/ uint32 playerId; // Player id who cast the buff
@ -866,7 +866,7 @@ struct AA_Array
{
uint32 AA;
uint32 value;
uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live
uint32 charges; // expendable charges
};
struct Disciplines_Struct {
@ -1323,7 +1323,7 @@ struct TargetReject_Struct {
struct PetCommand_Struct {
/*00*/ uint32 command;
/*04*/ uint32 unknown04;
/*04*/ uint32 target;
/*08*/ uint32 unknown08;
};
@ -1514,9 +1514,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint32 spellid;
/* 09 */ int32 damage;
/* 13 */ float unknown11; // cd cc cc 3d
/* 17 */ float sequence; // see above notes in Action_Struct
/* 21 */ uint8 unknown19[9]; // was [9]
/* 13 */ float force; // cd cc cc 3d
/* 17 */ float meleepush_xy; // see above notes in Action_Struct
/* 21 */ float meleepush_z;
/* 25 */ uint8 unknown25[5]; // was [9]
/* 30 */
};
@ -2500,7 +2501,7 @@ struct GroupFollow_Struct { // Live Follow Struct
struct InspectBuffs_Struct {
/*000*/ uint32 spell_id[BUFF_COUNT];
/*168*/ uint32 tics_remaining[BUFF_COUNT];
/*168*/ int32 tics_remaining[BUFF_COUNT];
};
struct LFG_Struct {
@ -4251,9 +4252,9 @@ struct SendAA_Struct {
/*0025*/ uint32 cost;
/*0029*/ uint32 seq;
/*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 #
/*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
/*0053*/ uint32 type;
/*0057*/ uint32 spellid;
@ -4266,10 +4267,16 @@ struct SendAA_Struct {
/*0081*/ uint32 last_id;
/*0085*/ uint32 next_id;
/*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;
/*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;
/*0116*/ AA_Ability abilities[0];
};
@ -4286,13 +4293,6 @@ struct AA_Action {
/*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 {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
/*04*/ uint32 aapoints_unspent;
@ -4311,14 +4311,7 @@ struct AltAdvStats_Struct {
};
struct PlayerAA_Struct { // Is this still used?
AA_Skills aa_list[MAX_PP_AA_ARRAY];
};
struct AA_Values {
/*00*/ uint32 aa_skill;
/*04*/ uint32 aa_value;
/*08*/ uint32 unknown08;
/*12*/
AA_Array aa_list[MAX_PP_AA_ARRAY];
};
struct AATable_Struct {
@ -4328,7 +4321,7 @@ struct AATable_Struct {
/*12*/ uint32 aa_spent_archetype; // Seen 40
/*16*/ uint32 aa_spent_class; // Seen 103
/*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 {

View File

@ -447,7 +447,9 @@ namespace SoD
OUT(type);
OUT(spellid);
OUT(damage);
eq->sequence = emu->sequence;
OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE();
}
@ -1557,6 +1559,7 @@ namespace SoD
for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA);
OUT(aa_array[r].value);
OUT(aa_array[r].charges);
}
// OUT(unknown02220[4]);
OUT(mana);
@ -1897,6 +1900,7 @@ namespace SoD
OUT(cost2);
eq->aa_expansion = emu->aa_expansion;
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);
unsigned int r;
for (r = 0; r < emu->total_abilities; r++) {
@ -1961,15 +1965,16 @@ namespace SoD
for (int counter = 0; counter < character_count; ++counter) {
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->HairStyle = emu_cse->HairStyle;
eq_cse->Gender = emu_cse->Gender;
strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_ptr += strlen(emu_cse->Name);
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->HairColor = emu_cse->HairColor;
@ -2736,7 +2741,7 @@ namespace SoD
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown12
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
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); // unknown16
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
@ -3350,7 +3355,7 @@ namespace SoD
default:
emu->command = eq->command;
}
OUT(unknown);
IN(target);
FINISH_DIRECT_DECODE();
}

View File

@ -286,7 +286,7 @@ struct Spawn_Struct
/*0000*/ uint8 unknown12;
/*0000*/ uint32 petOwnerId;
/*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 unknown16;
/*0000*/ uint32 unknown17;
@ -547,7 +547,7 @@ struct SpellBuff_Struct
/*002*/ uint8 bard_modifier;
/*003*/ uint8 effect; //not real
/*004*/ uint32 spellid;
/*008*/ uint32 duration;
/*008*/ int32 duration;
/*012*/ uint32 counters;
/*016*/ uint32 unknown004; //Might need to be swapped with player_id
/*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages
@ -564,7 +564,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect;
/*007*/ uint8 unknown7;
/*008*/ uint32 spellid;
/*012*/ uint32 duration;
/*012*/ int32 duration;
/*016*/ uint32 unknown016;
/*020*/ uint32 unknown020; //prolly global player ID
/*024*/ uint32 playerId; // Player id who cast the buff
@ -666,7 +666,7 @@ struct AA_Array
{
uint32 AA;
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 {
/*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
/* 05 */ uint16 spellid;
/* 07 */ int32 damage;
/* 11 */ float unknown11; // cd cc cc 3d
/* 15 */ float sequence; // see above notes in Action_Struct
/* 19 */ uint8 unknown19[9]; // was [9]
/* 11 */ float force; // cd cc cc 3d
/* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ float meleepush_z;
/* 23 */ uint8 unknown23[5]; // was [9]
/* 28 */
};
@ -3818,10 +3819,16 @@ struct SendAA_Struct {
/*0069*/ uint32 last_id;
/*0073*/ uint32 next_id;
/*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;
/*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;
/*0104*/ AA_Ability abilities[0];
};
@ -3837,12 +3844,6 @@ struct AA_Action {
/*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 {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
/*04*/ uint32 aapoints_unspent;
@ -3860,12 +3861,12 @@ struct AltAdvStats_Struct {
};
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 {
/*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 {

View File

@ -427,7 +427,9 @@ namespace SoF
OUT(type);
OUT(spellid);
OUT(damage);
eq->sequence = emu->sequence;
OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE();
}
@ -1215,6 +1217,7 @@ namespace SoF
for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA);
OUT(aa_array[r].value);
OUT(aa_array[r].charges);
}
// OUT(unknown02220[4]);
OUT(mana);
@ -1556,6 +1559,7 @@ namespace SoF
OUT(cost2);
eq->aa_expansion = emu->aa_expansion;
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);
unsigned int r;
for (r = 0; r < emu->total_abilities; r++) {
@ -1620,15 +1624,16 @@ namespace SoF
for (int counter = 0; counter < character_count; ++counter) {
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->HairStyle = emu_cse->HairStyle;
eq_cse->Gender = emu_cse->Gender;
strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_ptr += strlen(emu_cse->Name);
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->HairColor = emu_cse->HairColor;
@ -2087,6 +2092,7 @@ namespace SoF
eq->runspeed = emu->runspeed;
eq->light = emu->light;
eq->level = emu->level;
eq->PlayerState = emu->PlayerState;
eq->lfg = emu->lfg;
eq->hairstyle = emu->hairstyle;
eq->haircolor = emu->haircolor;
@ -2688,7 +2694,7 @@ namespace SoF
default:
emu->command = eq->command;
}
OUT(unknown);
IN(target);
FINISH_DIRECT_DECODE();
}

View File

@ -241,7 +241,8 @@ struct Spawn_Struct {
/*0506*/ uint8 light; // Spawn's lightsource
/*0507*/ uint8 unknown0507[4];
/*0511*/ uint8 level; // Spawn Level
/*0512*/ uint8 unknown0512[16];
/*0512*/ uint32 PlayerState;
/*0516*/ uint8 unknown0516[12];
/*0528*/ uint8 lfg;
/*0529*/ uint8 unknown0529[4];
/*0533*/ uint8 hairstyle; // Sets the style of hair
@ -525,7 +526,7 @@ struct SpellBuff_Struct
/*002*/ uint8 bard_modifier;
/*003*/ uint8 effect; //not real
/*004*/ uint32 spellid;
/*008*/ uint32 duration;
/*008*/ int32 duration;
/*012*/ uint32 counters;
/*016*/ uint32 unknown004; //Might need to be swapped with player_id
/*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages
@ -542,7 +543,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect;
/*007*/ uint8 unknown7;
/*008*/ uint32 spellid;
/*012*/ uint32 duration;
/*012*/ int32 duration;
/*016*/ uint32 unknown016;
/*020*/ uint32 unknown020; //prolly global player ID
/*024*/ uint32 playerId; // Player id who cast the buff
@ -644,7 +645,7 @@ struct AA_Array
{
uint32 AA;
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 {
/*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
/* 05 */ uint16 spellid;
/* 07 */ int32 damage;
/* 11 */ float unknown11; // cd cc cc 3d
/* 15 */ float sequence; // see above notes in Action_Struct
/* 19 */ uint8 unknown19[9]; // was [9]
/* 11 */ float force; // cd cc cc 3d
/* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ float meleepush_z;
/* 23 */ uint8 unknown23[5]; // was [9]
/* 28 */
};
@ -3681,10 +3683,14 @@ struct SendAA_Struct {
/*0069*/ uint32 last_id;
/*0073*/ uint32 next_id;
/*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;
/*0092*/ uint32 special_category;
/*0096*/ uint16 unknown0096;
/*0096*/ uint8 shroud;
/*0097*/ uint8 unknown97;
/*0098*/ uint32 total_abilities;
/*0102*/ AA_Ability abilities[0];
};
@ -3700,12 +3706,6 @@ struct AA_Action {
/*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 {
/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability
/*04*/ uint32 aapoints_unspent;
@ -3723,12 +3723,12 @@ struct AltAdvStats_Struct {
};
struct PlayerAA_Struct {
AA_Skills aa_list[MAX_PP_AA_ARRAY];
AA_Array aa_list[MAX_PP_AA_ARRAY];
};
struct AATable_Struct {
/*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 {

View File

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

View File

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

View File

@ -387,7 +387,7 @@ namespace UF
__packet->WriteUInt32(emu->entries[i].num_hits);
__packet->WriteString("");
}
__packet->WriteUInt8(!emu->all_buffs);
__packet->WriteUInt8(emu->type);
FINISH_ENCODE();
/*
@ -582,7 +582,9 @@ namespace UF
OUT(type);
OUT(spellid);
OUT(damage);
eq->sequence = emu->sequence;
OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
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
// issue.
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown, observed 0
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // This appears to be the size field.
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->solidtype); // Unknown, observed 0
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->x);
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z);
@ -1806,6 +1808,7 @@ namespace UF
for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA);
OUT(aa_array[r].value);
OUT(aa_array[r].charges);
}
// OUT(unknown02220[4]);
OUT(mana);
@ -2133,9 +2136,9 @@ namespace UF
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_value = emu->aa_list[i].aa_value;
eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08;
eq->aa_list[i].AA = emu->aa_list[i].AA;
eq->aa_list[i].value = emu->aa_list[i].value;
eq->aa_list[i].charges = emu->aa_list[i].charges;
}
FINISH_ENCODE();
@ -2180,6 +2183,7 @@ namespace UF
OUT(cost2);
eq->aa_expansion = emu->aa_expansion;
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);
unsigned int r;
for (r = 0; r < emu->total_abilities; r++) {
@ -2214,7 +2218,7 @@ namespace UF
FINISH_ENCODE();
return;
}
unsigned char *emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
@ -2252,15 +2256,16 @@ namespace UF
for (int counter = 0; counter < character_count; ++counter) {
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->HairStyle = emu_cse->HairStyle;
eq_cse->Gender = emu_cse->Gender;
strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_ptr += strlen(emu_cse->Name);
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->HairColor = emu_cse->HairColor;
@ -3004,7 +3009,7 @@ namespace UF
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown12
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId);
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); // unknown16
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17
@ -3357,7 +3362,7 @@ namespace UF
IN(type);
IN(spellid);
IN(damage);
emu->sequence = eq->sequence;
IN(meleepush_xy);
FINISH_DIRECT_DECODE();
}
@ -3600,7 +3605,7 @@ namespace UF
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
IN(command);
IN(unknown);
IN(target);
FINISH_DIRECT_DECODE();
}
@ -3862,7 +3867,7 @@ namespace UF
UF::structs::ItemSerializationHeaderFinish hdrf;
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.isCopied = 0; //Flag for item to be 'Copied'
hdrf.ItemClass = item->ItemClass;

View File

@ -286,7 +286,7 @@ struct Spawn_Struct
/*0000*/ uint8 unknown12;
/*0000*/ uint32 petOwnerId;
/*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 unknown16;
/*0000*/ uint32 unknown17;
@ -551,7 +551,7 @@ struct SpellBuff_Struct
/*003*/ uint8 effect; // not real
/*004*/ uint32 unknown004; // Seen 1 for no buff
/*008*/ uint32 spellid;
/*012*/ uint32 duration;
/*012*/ int32 duration;
/*016*/ uint32 unknown016;
/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages
/*024*/ uint32 counters;
@ -568,7 +568,7 @@ struct SpellBuffFade_Struct_Underfoot {
/*007*/ uint8 unknown7;
/*008*/ float unknown008;
/*012*/ uint32 spellid;
/*016*/ uint32 duration;
/*016*/ int32 duration;
/*020*/ uint32 num_hits;
/*024*/ uint32 playerId; // Global player ID?
/*028*/ uint32 unknown020;
@ -585,7 +585,7 @@ struct SpellBuffFade_Struct {
/*006*/ uint8 effect;
/*007*/ uint8 unknown7;
/*008*/ uint32 spellid;
/*012*/ uint32 duration;
/*012*/ int32 duration;
/*016*/ uint32 unknown016;
/*020*/ uint32 unknown020; // Global player ID?
/*024*/ uint32 playerId; // Player id who cast the buff
@ -713,7 +713,7 @@ struct AA_Array
{
uint32 AA;
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 {
/*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
/* 05 */ uint16 spellid;
/* 07 */ int32 damage;
/* 11 */ float unknown11; // cd cc cc 3d
/* 15 */ float sequence; // see above notes in Action_Struct
/* 19 */ uint8 unknown19[9]; // was [9]
/* 11 */ float force; // cd cc cc 3d
/* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ float meleepush_z;
/* 23 */ uint8 unknown23[5]; // was [9]
/* 28 */
};
@ -2187,7 +2188,7 @@ struct GroupFollow_Struct { // Underfoot Follow Struct
struct InspectBuffs_Struct {
/*000*/ uint32 spell_id[BUFF_COUNT];
/*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...
};
@ -3891,10 +3892,16 @@ struct SendAA_Struct {
/*0069*/ uint32 last_id;
/*0073*/ uint32 next_id;
/*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;
/*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;
/*0104*/ AA_Ability abilities[0];
};
@ -3910,11 +3917,6 @@ struct AA_Action {
/*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 {
/*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?
AA_Skills aa_list[MAX_PP_AA_ARRAY];
AA_Array aa_list[MAX_PP_AA_ARRAY];
};
struct AATable_Struct {
@ -3943,7 +3945,7 @@ struct AATable_Struct {
/*12*/ int32 unknown012;
/*16*/ int32 unknown016;
/*20*/ int32 unknown020;
/*24*/ AA_Skills aa_list[MAX_PP_AA_ARRAY];
/*24*/ AA_Array aa_list[MAX_PP_AA_ARRAY];
};
struct Weather_Struct {

View File

@ -39,7 +39,8 @@ enum { //values for pTimerType
pTimerDisciplineReuseStart = 14,
pTimerDisciplineReuseEnd = 24,
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
pTimerHarmTouch = 89, //so dont change them

View File

@ -47,6 +47,8 @@
#define IKSAR 128
#define VAHSHIR 130
#define CONTROLLED_BOAT 141
#define MINOR_ILL_OBJ 142
#define TREE 143
#define IKSAR_SKELETON 161
#define FROGLOK 330
#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;
}
}
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 {
bool IsTradeskill(SkillUseTypes skill);
bool IsSpecializedSkill(SkillUseTypes skill);
float GetSkillMeleePushForce(SkillUseTypes skill);
bool IsBardInstrumentSkill(SkillUseTypes skill);
}
#endif

View File

@ -72,7 +72,7 @@
#include "../common/eqemu_logsys.h"
#include "../common/eqemu_logsys.h"
#include "classes.h"
#include "spdat.h"
@ -162,7 +162,7 @@ bool IsCureSpell(uint16 spell_id)
bool CureEffect = false;
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)
CureEffect = true;
}
@ -405,7 +405,7 @@ bool IsPartialCapableSpell(uint16 spell_id)
{
if (spells[spell_id].no_partial_resist)
return false;
if (IsPureNukeSpell(spell_id))
return true;
@ -447,7 +447,7 @@ bool IsTGBCompatibleSpell(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 false;
@ -693,9 +693,9 @@ bool IsCombatSkill(uint16 spell_id)
{
if (!IsValidSpell(spell_id))
return false;
//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 false;
@ -1040,7 +1040,7 @@ bool IsCastonFadeDurationSpell(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)
return true;

View File

@ -133,7 +133,7 @@ typedef enum {
/* 42 */ ST_Directional = 0x2a, //ae around this target between two angles
/* 43 */ ST_GroupClientAndPet = 0x2b,
/* 44 */ ST_Beam = 0x2c,
/* 45 */ ST_Ring = 0x2d,
/* 45 */ ST_Ring = 0x2d,
/* 46 */ ST_TargetsTarget = 0x2e, // uses the target of your target
/* 47 */ ST_PetMaster = 0x2f, // uses the master as target
/* 48 */ // UNKNOWN
@ -151,10 +151,10 @@ typedef enum {
} DmgShieldType;
//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
#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_MovementSpeed 3 // implemented - SoW, SoC, etc
#define SE_STR 4 // implemented
@ -197,7 +197,7 @@ typedef enum {
#define SE_Destroy 41 // implemented - Disintegrate, Banishment of Shadows
#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_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_ResistFire 46 // implemented
#define SE_ResistCold 47 // implemented
@ -247,7 +247,7 @@ typedef enum {
#define SE_SummonCorpse 91 // implemented
#define SE_InstantHate 92 // implemented - add hate
#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_Silence 96 // implemented
#define SE_ManaPool 97 // implemented
@ -299,7 +299,7 @@ typedef enum {
#define SE_LimitCastTimeMin 143 // implemented
#define SE_LimitCastTimeMax 144 // implemented (*not used in any known live spell)
#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_StackingCommand_Block 148 // 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_ApplyEffect 374 // implemented
#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_SpellEffectResistChance 378 // implemented - Increase chance to resist specific spell effect (base1=value, base2=spell effect id)
#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_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_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_LimitManaPercent 409 // implemented - limited to a certain percent of your mana
#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_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_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_Display 425 // *not implemented - Illusion: Flying Dragon(21626)
//#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_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_BStacker 447 // implemented
#define SE_BStacker 447 // 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_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
@ -618,6 +618,7 @@ typedef enum {
#define DF_Permanent 50
#define DF_Aura 51
// 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
@ -733,31 +734,31 @@ struct SPDat_Spell_Struct
/* 197 */ bool not_extendable;
/* 198- 199 */
/* 200 */ bool suspendable; // buff is suspended in suspended buff zones
/* 201 */ int viral_range;
/* 201 */ int viral_range;
/* 202 */
/* 203 */ //int songcap; // individual song cap (how live currently does it, not implemented)
/* 204 */
/* 205 */ bool no_block;
/* 206 */
/* 206 */
/* 207 */ int spellgroup;
/* 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
/* 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
/* 212 */ bool AllowRest;
/* 213 */ bool InCombat; //Allow spell if target is in combat
/* 214 */ bool OutofCombat; //Allow spell if target is out of combat
/* 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)
/* 220 - 223 */
/* 220 - 223 */
/* 224 */ bool persistdeath; // buff doesn't get stripped on death
/* 225 - 226 */
/* 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)
/* 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)
/* 231 */ float min_range; //Min casting range
/* 231 */ float min_range; //Min casting range
/* 232 - 236 */
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"
#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

View File

@ -24,13 +24,13 @@
#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
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_TIME __TIME__
#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());
escaped_short_name[length+1] = 0;
stringstream query(stringstream::in | stringstream::out);
query << "SELECT WSR.ServerID, WSR.ServerTagDescription, WSR.ServerTrusted, SLT.ServerListTypeID, ";
query << "SLT.ServerListTypeDescription, WSR.ServerAdminID FROM " << server.options.GetWorldRegistrationTable();
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, 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 << " WHERE WSR.ServerShortName = '";
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());
escaped_short_name[length+1] = 0;
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)
{

View File

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

View File

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

View File

@ -266,8 +266,8 @@ OP_RequestDuel=0x79e0 # C
OP_MobRename=0x0a1d # C
OP_AugmentItem=0x0370 # C
OP_WeaponEquip1=0x719e # C
OP_WeaponEquip2=0x7b6e # C
OP_WeaponUnequip2=0x19a8 # C
OP_PlayerStateAdd=0x7b6e # C
OP_PlayerStateRemove=0x19a8 # C
OP_ApplyPoison=0x405b # C
OP_Save=0x5c85 # 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_AugmentItem=0x172A #Trevius 03/14/09
OP_WeaponEquip1=0x7260 #Trevius 02/27/09
OP_WeaponEquip2=0x5C2F #Trevius 02/27/09
OP_WeaponUnequip2=0x6213 #Trevius 02/27/09
OP_PlayerStateAdd=0x5C2F #Trevius 02/27/09
OP_PlayerStateRemove=0x6213 #Trevius 02/27/09
OP_ApplyPoison=0x4543 #WildcardX 03/6/09
OP_Save=0x72F2 #Trevius 03/15/09
OP_TestBuff=0x07BF #/testbuff

View File

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

View File

@ -197,6 +197,7 @@ OP_Consent=0x6bb9 # C
OP_ConsentDeny=0x4cd1 # C
OP_AutoFire=0x5db5 # C
OP_PetCommands=0x7706 # C
OP_PetHoTT=0x2528
OP_DeleteSpell=0x0698 # C
OP_Surname=0x44ae # C
OP_ClearSurname=0x6705 # C
@ -272,8 +273,8 @@ OP_RequestDuel=0x6cfe # C
OP_MobRename=0x0507 # C
OP_AugmentItem=0x7c87 # C
OP_WeaponEquip1=0x4572 # C
OP_WeaponEquip2=0x399b # C
OP_WeaponUnequip2=0x416b # C
OP_PlayerStateAdd=0x399b # C
OP_PlayerStateRemove=0x416b # C
OP_ApplyPoison=0x5cd3 # C
OP_Save=0x6618 # 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|
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|
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:
# 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
# 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: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));
/* Fill CharacterSelectEntry_Struct */
memset(cse->Name, 0, sizeof(cse->Name));
strcpy(cse->Name, row[1]);
cse->Class = (uint8)atoi(row[4]);
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.");
auto pack = new ServerPacket(ServerOP_ZAAuthFailed);
SendPacket(pack);
delete pack;
safe_delete(pack);
Disconnect();
return false;
}
@ -201,7 +201,7 @@ bool ZoneServer::Process() {
Log.Out(Logs::Detail, Logs::World_Server,"Zone authorization failed.");
auto pack = new ServerPacket(ServerOP_ZAAuthFailed);
SendPacket(pack);
delete pack;
safe_delete(pack);
Disconnect();
return false;
}
@ -779,7 +779,7 @@ bool ZoneServer::Process() {
whom->wrace = whoall->wrace;
strcpy(whom->whom,whoall->whom);
client_list.SendWhoAll(whoall->fromid,whoall->from, whoall->admin, whom, this);
delete whom;
safe_delete(whom);
break;
}
case ServerOP_RequestOnlineGuildMembers: {
@ -958,13 +958,13 @@ bool ZoneServer::Process() {
tod->start_eqtime=zoneserver_list.worldclock.getStartEQTime();
tod->start_realtime=zoneserver_list.worldclock.getStartRealTime();
SendPacket(pack);
delete pack;
safe_delete(pack);
break;
}
case ServerOP_SetWorldTime: {
Log.Out(Logs::Detail, Logs::World_Server,"Received SetWorldTime");
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);
zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str());
zoneserver_list.SendTimeSync();
@ -1059,8 +1059,7 @@ bool ZoneServer::Process() {
}
else
{
delete pack;
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
strcpy(scs->grantname, s->grantname);
strcpy(scs->ownername, s->ownername);
@ -1076,6 +1075,7 @@ bool ZoneServer::Process() {
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);
}
safe_delete(pack);
}
}
else
@ -1091,8 +1091,7 @@ bool ZoneServer::Process() {
}
else {
// send target not found back to requester
delete pack;
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
strcpy(scs->grantname, s->grantname);
strcpy(scs->ownername, s->ownername);
@ -1107,13 +1106,13 @@ bool ZoneServer::Process() {
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);
}
safe_delete(pack);
}
}
}
else {
// send target not found back to requester
delete pack;
pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
strcpy(scs->grantname, s->grantname);
strcpy(scs->ownername, s->ownername);
@ -1128,6 +1127,7 @@ bool ZoneServer::Process() {
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);
}
safe_delete(pack);
}
break;
}
@ -1313,15 +1313,17 @@ bool ZoneServer::Process() {
}
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);
break;
}
}
if (pack)
delete pack;
else
Log.Out(Logs::Detail, Logs::World_Server, "Zoneserver process tried to delete pack when pack does not exist.");
if (pack) {
safe_delete(pack);
}
else {
Log.Out(Logs::Detail, Logs::World_Server, "Zoneserver process attempted to delete pack when pack does not exist.");
}
}
return true;
}

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

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

View File

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

View File

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

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

View File

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

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

View File

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

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 SendColoredText(uint32 type, std::string msg);
void PlayMP3(std::string file);
void QuestReward(Lua_Mob target);
void QuestReward(Lua_Mob target, uint32 copper);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp);
void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction);
};
#endif

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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