Add client->SendToGuildHall - have instances properly cycle out IDs

This commit is contained in:
Akkadius 2020-04-10 01:43:00 -05:00
parent 1728923bbb
commit 88ff56b2f2
12 changed files with 323 additions and 174 deletions

View File

@ -159,7 +159,7 @@ public:
uint16 GetInstanceID(const char* zone, uint32 charid, int16 version); uint16 GetInstanceID(const char* zone, uint32 charid, int16 version);
uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version); uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version);
uint16 GetInstanceVersion(uint16 instance_id); uint16 GetInstanceVersion(uint16 instance_id);
uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma); uint32 GetTimeRemainingInstance(uint16 instance_id, bool is_perma = false);
uint32 VersionFromInstanceID(uint16 instance_id); uint32 VersionFromInstanceID(uint16 instance_id);
uint32 ZoneIDFromInstanceID(uint16 instance_id); uint32 ZoneIDFromInstanceID(uint16 instance_id);
@ -196,19 +196,19 @@ public:
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus); void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
void SetAgreementFlag(uint32 acctid); void SetAgreementFlag(uint32 acctid);
int GetIPExemption(std::string account_ip); int GetIPExemption(std::string account_ip);
int GetInstanceID(uint32 char_id, uint32 zone_id); int GetInstanceID(uint32 char_id, uint32 zone_id);
/* Groups */ /* Groups */
char* GetGroupLeaderForLogin(const char* name,char* leaderbuf); char* GetGroupLeaderForLogin(const char* name,char* leaderbuf);
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr); char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
uint32 GetGroupID(const char* name); uint32 GetGroupID(const char* name);
void ClearGroup(uint32 gid = 0); void ClearGroup(uint32 gid = 0);
void ClearGroupLeader(uint32 gid = 0); void ClearGroupLeader(uint32 gid = 0);
void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false); void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false);

View File

@ -97,42 +97,53 @@ bool Database::CheckInstanceExists(uint16 instance_id) {
bool Database::CheckInstanceExpired(uint16 instance_id) bool Database::CheckInstanceExpired(uint16 instance_id)
{ {
int32 start_time = 0; int32 start_time = 0;
int32 duration = 0; int32 duration = 0;
uint32 never_expires = 0; uint32 never_expires = 0;
std::string query = StringFormat("SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id); std::string query = StringFormat(
"SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u",
instance_id
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) if (!results.Success()) {
return true; return true;
}
if (results.RowCount() == 0) if (results.RowCount() == 0) {
return true; return true;
}
auto row = results.begin(); auto row = results.begin();
start_time = atoi(row[0]); start_time = atoi(row[0]);
duration = atoi(row[1]); duration = atoi(row[1]);
never_expires = atoi(row[2]); never_expires = atoi(row[2]);
if (never_expires == 1) if (never_expires == 1) {
return false; return false;
}
timeval tv; timeval tv{};
gettimeofday(&tv, nullptr); gettimeofday(&tv, nullptr);
if ((start_time + duration) <= tv.tv_sec) return (start_time + duration) <= tv.tv_sec;
return true;
return false;
} }
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration) bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
{ {
std::string query = StringFormat("INSERT INTO instance_list (id, zone, version, start_time, duration)" std::string query = StringFormat(
" values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)", "INSERT INTO instance_list (id, zone, version, start_time, duration)"
(unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration); " values (%u, %u, %u, UNIX_TIMESTAMP(), %u)",
instance_id,
zone_id,
version,
duration
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
return results.Success(); return results.Success();
@ -140,66 +151,79 @@ bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version
bool Database::GetUnusedInstanceID(uint16 &instance_id) bool Database::GetUnusedInstanceID(uint16 &instance_id)
{ {
uint32 count = RuleI(Zone, ReservedInstances); uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
uint32 max = 65535; uint32 max = 32000;
std::string query = StringFormat(
"SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u",
max_reserved_instance_id,
max_reserved_instance_id
);
if (RuleB(Instances, RecycleInstanceIds)) {
query = (
SQL(
SELECT i.id + 1 AS next_available
FROM instance_list i
LEFT JOIN instance_list i2 ON i2.id = i.id + 1
WHERE i2.id IS NULL
ORDER BY i.id
LIMIT 0, 1;
)
);
}
std::string query = StringFormat("SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u", count, count);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) if (!results.Success()) {
{
instance_id = 0; instance_id = 0;
return false; return false;
} }
if (results.RowCount() == 0) if (results.RowCount() == 0) {
{ instance_id = max_reserved_instance_id;
instance_id = 0; return true;
return false;
} }
auto row = results.begin(); auto row = results.begin();
if (atoi(row[0]) <= max) if (atoi(row[0]) <= max) {
{
instance_id = atoi(row[0]); instance_id = atoi(row[0]);
return true; return true;
} }
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", count); query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id);
results = QueryDatabase(query); results = QueryDatabase(query);
if (!results.Success()) if (!results.Success()) {
{
instance_id = 0; instance_id = 0;
return false; return false;
} }
if (results.RowCount() == 0) if (results.RowCount() == 0) {
{
instance_id = 0; instance_id = 0;
return false; return false;
} }
count++; max_reserved_instance_id++;
for (auto row = results.begin(); row != results.end(); ++row) for (auto row = results.begin(); row != results.end(); ++row) {
{ if (max_reserved_instance_id < atoi(row[0])) {
if (count < atoi(row[0])) instance_id = max_reserved_instance_id;
{
instance_id = count;
return true; return true;
} }
if (count > max) if (max_reserved_instance_id > max) {
{
instance_id = 0; instance_id = 0;
return false; return false;
} }
count++; max_reserved_instance_id++;
} }
instance_id = count; instance_id = max_reserved_instance_id;
return true; return true;
} }
@ -357,7 +381,7 @@ uint16 Database::GetInstanceVersion(uint16 instance_id) {
return atoi(row[0]); return atoi(row[0]);
} }
uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma) uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool is_perma)
{ {
uint32 start_time = 0; uint32 start_time = 0;
uint32 duration = 0; uint32 duration = 0;
@ -548,17 +572,36 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &ch
void Database::PurgeExpiredInstances() void Database::PurgeExpiredInstances()
{ {
std::string query("SELECT id FROM instance_list where (start_time+duration) <= UNIX_TIMESTAMP() and never_expires = 0");
/**
* Delay purging by a day so that we can continue using adjacent free instance id's
* from the table without risking the chance we immediately re-allocate a zone that freshly expired but
* has not been fully de-allocated
*/
std::string query =
SQL(
SELECT
id
FROM
instance_list
where
(start_time + duration) <= (UNIX_TIMESTAMP() + 86400)
and never_expires = 0
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) if (!results.Success()) {
return; return;
}
if (results.RowCount() == 0) if (results.RowCount() == 0) {
return; return;
}
for (auto row = results.begin(); row != results.end(); ++row) for (auto row = results.begin(); row != results.end(); ++row) {
DeleteInstance(atoi(row[0])); DeleteInstance(atoi(row[0]));
}
} }
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration) void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
@ -566,4 +609,4 @@ void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), " std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), "
"duration=%u WHERE id=%u", new_duration, instance_id); "duration=%u WHERE id=%u", new_duration, instance_id);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
} }

View File

@ -270,7 +270,6 @@ RULE_INT(Zone, PEQZoneDebuff1, 4454, "First debuff casted by #peqzone Default is
RULE_INT(Zone, PEQZoneDebuff2, 2209, "Second debuff casted by #peqzone Default is Tendrils of Apathy") RULE_INT(Zone, PEQZoneDebuff2, 2209, "Second debuff casted by #peqzone Default is Tendrils of Apathy")
RULE_BOOL(Zone, UsePEQZoneDebuffs, true, "Will determine if #peqzone will debuff players or not when used") RULE_BOOL(Zone, UsePEQZoneDebuffs, true, "Will determine if #peqzone will debuff players or not when used")
RULE_REAL(Zone, HotZoneBonus, 0.75, "") RULE_REAL(Zone, HotZoneBonus, 0.75, "")
RULE_INT(Zone, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running")
RULE_INT(Zone, EbonCrystalItemID, 40902, "") RULE_INT(Zone, EbonCrystalItemID, 40902, "")
RULE_INT(Zone, RadiantCrystalItemID, 40903, "") RULE_INT(Zone, RadiantCrystalItemID, 40903, "")
RULE_BOOL(Zone, LevelBasedEXPMods, false, "Allows you to use the level_exp_mods table in consideration to your players EXP hits") RULE_BOOL(Zone, LevelBasedEXPMods, false, "Allows you to use the level_exp_mods table in consideration to your players EXP hits")
@ -775,6 +774,12 @@ RULE_BOOL(HotReload, QuestsRepopWhenPlayersNotInCombat, true, "When a hot reload
RULE_BOOL(HotReload, QuestsResetTimersWithReload, true, "When a hot reload is triggered, quest timers will be reset") RULE_BOOL(HotReload, QuestsResetTimersWithReload, true, "When a hot reload is triggered, quest timers will be reset")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Instances)
RULE_INT(Instances, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running")
RULE_BOOL(Instances, RecycleInstanceIds, true, "Will recycle free instance ids instead of gradually running out at 32k")
RULE_INT(Instances, GuildHallExpirationDays, 90, "Amount of days before a Guild Hall instance expires")
RULE_CATEGORY_END()
#undef RULE_CATEGORY #undef RULE_CATEGORY
#undef RULE_INT #undef RULE_INT
#undef RULE_REAL #undef RULE_REAL

View File

@ -129,13 +129,17 @@ void Timer::SetTimer(uint32 set_timer_time) {
} }
} }
uint32 Timer::GetRemainingTime() const { uint32 Timer::GetRemainingTime() const
{
if (enabled) { if (enabled) {
if (current_time - start_time > timer_time) if (current_time - start_time > timer_time) {
return 0; return 0;
else }
else {
return (start_time + timer_time) - current_time; return (start_time + timer_time) - current_time;
} else { }
}
else {
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }
} }

View File

@ -1918,7 +1918,7 @@ void Client::CheckManaEndUpdate() {
else if (group) { else if (group) {
group->SendEndurancePacketFrom(this); group->SendEndurancePacketFrom(this);
} }
auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct)); auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer; EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer;
endurance_update->cur_end = GetEndurance(); endurance_update->cur_end = GetEndurance();
@ -8756,7 +8756,7 @@ void Client::CheckRegionTypeChanges()
// still same region, do nothing // still same region, do nothing
if (last_region_type == new_region) if (last_region_type == new_region)
return; return;
// If we got out of water clear any water aggro for water only npcs // If we got out of water clear any water aggro for water only npcs
if (last_region_type == RegionTypeWater) { if (last_region_type == RegionTypeWater) {
entity_list.ClearWaterAggro(this); entity_list.ClearWaterAggro(this);
@ -9203,7 +9203,7 @@ void Client::SetSecondaryWeaponOrnamentation(uint32 model_id)
secondary_item->SetOrnamentationIDFile(model_id); secondary_item->SetOrnamentationIDFile(model_id);
SendItemPacket(EQEmu::invslot::slotSecondary, secondary_item, ItemPacketTrade); SendItemPacket(EQEmu::invslot::slotSecondary, secondary_item, ItemPacketTrade);
WearChange(EQEmu::textures::weaponSecondary, static_cast<uint16>(model_id), 0); WearChange(EQEmu::textures::weaponSecondary, static_cast<uint16>(model_id), 0);
Message(Chat::Yellow, "Your secondary weapon appearance has been modified"); Message(Chat::Yellow, "Your secondary weapon appearance has been modified");
} }
} }
@ -9292,3 +9292,41 @@ void Client::SetBotOption(BotOwnerOption boo, bool flag) {
} }
#endif #endif
void Client::SendToGuildHall()
{
std::string zone_short_name = "guildhall";
uint32 zone_id = database.GetZoneID(zone_short_name.c_str());
if (zone_id == 0) {
return;
}
uint32 expiration_time = (RuleI(Instances, GuildHallExpirationDays) * 86400);
uint16 instance_id = 0;
std::string guild_hall_instance_key = fmt::format("guild-hall-instance-{}", GuildID());
std::string instance_data = DataBucket::GetData(guild_hall_instance_key);
if (!instance_data.empty() && std::stoi(instance_data) > 0) {
instance_id = std::stoi(instance_data);
}
if (instance_id <= 0) {
if (!database.GetUnusedInstanceID(instance_id)) {
Message(Chat::Red, "Server was unable to find a free instance id.");
return;
}
if (!database.CreateInstance(instance_id, zone_id, 0, expiration_time)) {
Message(Chat::Red, "Server was unable to create a new instance.");
return;
}
DataBucket::SetData(
guild_hall_instance_key,
std::to_string(instance_id),
std::to_string(expiration_time)
);
}
AssignToInstance(instance_id);
MovePC(345, instance_id, -1.00, -1.00, 3.34, 0, 1);
}

View File

@ -633,6 +633,7 @@ public:
void MovePC(uint32 zoneID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); void MovePC(uint32 zoneID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void MovePC(float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); void MovePC(float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void MovePC(uint32 zoneID, uint32 instanceID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); void MovePC(uint32 zoneID, uint32 instanceID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void SendToGuildHall();
void AssignToInstance(uint16 instance_id); void AssignToInstance(uint16 instance_id);
void RemoveFromInstance(uint16 instance_id); void RemoveFromInstance(uint16 instance_id);
void WhoAll(); void WhoAll();
@ -691,7 +692,7 @@ public:
int GetClientMaxLevel() const { return client_max_level; } int GetClientMaxLevel() const { return client_max_level; }
void SetClientMaxLevel(int max_level) { client_max_level = max_level; } void SetClientMaxLevel(int max_level) { client_max_level = max_level; }
void CheckManaEndUpdate(); void CheckManaEndUpdate();
void SendManaUpdate(); void SendManaUpdate();
void SendEnduranceUpdate(); void SendEnduranceUpdate();
@ -1293,7 +1294,7 @@ public:
void SendHPUpdateMarquee(); void SendHPUpdateMarquee();
void CheckRegionTypeChanges(); void CheckRegionTypeChanges();
WaterRegionType GetLastRegion() { return last_region_type; } WaterRegionType GetLastRegion() { return last_region_type; }
int32 CalcATK(); int32 CalcATK();
@ -1635,9 +1636,9 @@ private:
bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth); bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth);
int client_max_level; int client_max_level;
#ifdef BOTS #ifdef BOTS
public: public:
enum BotOwnerOption : size_t { enum BotOwnerOption : size_t {
booDeathMarquee, booDeathMarquee,
@ -1654,7 +1655,7 @@ public:
bool GetBotOption(BotOwnerOption boo) const; bool GetBotOption(BotOwnerOption boo) const;
void SetBotOption(BotOwnerOption boo, bool flag = true); void SetBotOption(BotOwnerOption boo, bool flag = true);
bool GetBotPulling() { return m_bot_pulling; } bool GetBotPulling() { return m_bot_pulling; }
void SetBotPulling(bool flag = true) { m_bot_pulling = flag; } void SetBotPulling(bool flag = true) { m_bot_pulling = flag; }

View File

@ -599,7 +599,7 @@ void Client::CompleteConnect()
if (group) if (group)
group->SendHPManaEndPacketsTo(this); group->SendHPManaEndPacketsTo(this);
} }
//bulk raid send in here eventually //bulk raid send in here eventually
@ -818,35 +818,46 @@ void Client::CompleteConnect()
database.QueryDatabase( database.QueryDatabase(
StringFormat( StringFormat(
"UPDATE `character_data` SET `last_login` = UNIX_TIMESTAMP() WHERE id = %u", "UPDATE `character_data` SET `last_login` = UNIX_TIMESTAMP() WHERE id = %u",
this->CharacterID() CharacterID()
) )
); );
} }
if (zone) { if (zone && zone->GetInstanceID() > 0) {
if (zone->GetInstanceTimer()) {
uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime(); uint32 remaining_time_seconds = zone->GetInstanceTimeRemaining();
uint32 day = (ttime / 86400000); uint32 day = (remaining_time_seconds / 86400);
uint32 hour = (ttime / 3600000) % 24; uint32 hour = (remaining_time_seconds / 3600) % 24;
uint32 minute = (ttime / 60000) % 60; uint32 minute = (remaining_time_seconds / 60) % 60;
uint32 second = (ttime / 1000) % 60; uint32 second = (remaining_time_seconds / 1) % 60;
if (day) {
Message(Chat::Yellow, "%s(%u) will expire in %u days, %u hours, %u minutes, and %u seconds.", LogInfo("Remaining time seconds [{}]", remaining_time_seconds);
zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second);
} if (day) {
else if (hour) { Message(
Message(Chat::Yellow, "%s(%u) will expire in %u hours, %u minutes, and %u seconds.", Chat::Yellow, "%s (%u) will expire in %u days, %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), hour, minute, second); zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second
} );
else if (minute) {
Message(Chat::Yellow, "%s(%u) will expire in %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), minute, second);
}
else {
Message(Chat::Yellow, "%s(%u) will expire in in %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), second);
}
} }
else if (hour) {
Message(
Chat::Yellow, "%s (%u) will expire in %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), hour, minute, second
);
}
else if (minute) {
Message(
Chat::Yellow, "%s (%u) will expire in %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), minute, second
);
}
else {
Message(
Chat::Yellow, "%s (%u) will expire in in %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), second
);
}
} }
SendRewards(); SendRewards();
@ -1237,7 +1248,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */ database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */
// set to full support in case they're a gm with items in disabled expansion slots..but, have their gm flag off... // set to full support in case they're a gm with items in disabled expansion slots..but, have their gm flag off...
// item loss will occur when they use the 'empty' slots, if this is not done // item loss will occur when they use the 'empty' slots, if this is not done
m_inv.SetGMInventory(true); m_inv.SetGMInventory(true);
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */ loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */ database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */ database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */
@ -1341,7 +1352,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
client_max_level = GetCharMaxLevelFromBucket(); client_max_level = GetCharMaxLevelFromBucket();
} }
SetClientMaxLevel(client_max_level); SetClientMaxLevel(client_max_level);
// we know our class now, so we might have to fix our consume timer! // we know our class now, so we might have to fix our consume timer!
if (class_ == MONK) if (class_ == MONK)
consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER); consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER);
@ -2840,7 +2851,7 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app)
// rogue simply won't apply at all, no skill check done. // rogue simply won't apply at all, no skill check done.
uint16 poison_skill = GetSkill(EQEmu::skills::SkillApplyPoison); uint16 poison_skill = GetSkill(EQEmu::skills::SkillApplyPoison);
if (ChanceRoll < (.75 + poison_skill / 1000)) { if (ChanceRoll < (.75 + poison_skill / 1000)) {
ApplyPoisonSuccessResult = 1; ApplyPoisonSuccessResult = 1;
AddProcToWeapon(poison->Proc.Effect, false, (GetDEX() / 100) + 103, POISON_PROC); AddProcToWeapon(poison->Proc.Effect, false, (GetDEX() / 100) + 103, POISON_PROC);
@ -3917,7 +3928,7 @@ void Client::Handle_OP_Bug(const EQApplicationPacket *app)
Message(0, "Bug reporting is disabled on this server."); Message(0, "Bug reporting is disabled on this server.");
return; return;
} }
if (app->size != sizeof(BugReport_Struct)) { if (app->size != sizeof(BugReport_Struct)) {
printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct)); printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct));
} }
@ -4017,7 +4028,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
//Message(Chat::Red, "You cant cast right now, you arent in control of yourself!"); //Message(Chat::Red, "You cant cast right now, you arent in control of yourself!");
return; return;
} }
// Hack for broken RoF2 which allows casting after a zoned IVU/IVA // Hack for broken RoF2 which allows casting after a zoned IVU/IVA
if (invisible_undead || invisible_animals) { if (invisible_undead || invisible_animals) {
BuffFadeByEffect(SE_InvisVsAnimals); BuffFadeByEffect(SE_InvisVsAnimals);
@ -4370,9 +4381,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
sizeof(PlayerPositionUpdateClient_Struct), app->size); sizeof(PlayerPositionUpdateClient_Struct), app->size);
return; return;
} }
PlayerPositionUpdateClient_Struct *ppu = (PlayerPositionUpdateClient_Struct *) app->pBuffer; PlayerPositionUpdateClient_Struct *ppu = (PlayerPositionUpdateClient_Struct *) app->pBuffer;
/* Boat handling */ /* Boat handling */
if (ppu->spawn_id != GetID()) { if (ppu->spawn_id != GetID()) {
/* If player is controlling boat */ /* If player is controlling boat */
@ -4382,16 +4393,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
controlling_boat_id = 0; controlling_boat_id = 0;
return; return;
} }
auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
boat->SetDelta(boat_delta); boat->SetDelta(boat_delta);
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *ppus = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer; PlayerPositionUpdateServer_Struct *ppus = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
boat->MakeSpawnUpdate(ppus); boat->MakeSpawnUpdate(ppus);
entity_list.QueueCloseClients(boat, outapp, true, 300, this, false); entity_list.QueueCloseClients(boat, outapp, true, 300, this, false);
safe_delete(outapp); safe_delete(outapp);
/* Update the boat's position on the server, without sending an update */ /* Update the boat's position on the server, without sending an update */
boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading), false); boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading), false);
return; return;
@ -4406,9 +4417,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
if (cmob != nullptr) { if (cmob != nullptr) {
cmob->SetPosition(ppu->x_pos, ppu->y_pos, ppu->z_pos); cmob->SetPosition(ppu->x_pos, ppu->y_pos, ppu->z_pos);
cmob->SetHeading(EQ12toFloat(ppu->heading)); cmob->SetHeading(EQ12toFloat(ppu->heading));
mMovementManager->SendCommandToClients(cmob, 0.0, 0.0, 0.0, mMovementManager->SendCommandToClients(cmob, 0.0, 0.0, 0.0,
0.0, 0, ClientRangeAny, nullptr, this); 0.0, 0, ClientRangeAny, nullptr, this);
cmob->CastToNPC()->SaveGuardSpot(glm::vec4(ppu->x_pos, cmob->CastToNPC()->SaveGuardSpot(glm::vec4(ppu->x_pos,
ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading))); ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading)));
} }
} }
@ -4426,7 +4437,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
// From this point forward, we need to use a new set of variables for client // From this point forward, we need to use a new set of variables for client
// position. If the client is in a boat, we need to add the boat pos and // position. If the client is in a boat, we need to add the boat pos and
// the client offset together. // the client offset together.
float cx = ppu->x_pos; float cx = ppu->x_pos;
float cy = ppu->y_pos; float cy = ppu->y_pos;
float cz = ppu->z_pos; float cz = ppu->z_pos;
@ -4451,45 +4462,45 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
/* Check to see if PPU should trigger an update to the rewind position. */ /* Check to see if PPU should trigger an update to the rewind position. */
float rewind_x_diff = 0; float rewind_x_diff = 0;
float rewind_y_diff = 0; float rewind_y_diff = 0;
rewind_x_diff = cx - m_RewindLocation.x; rewind_x_diff = cx - m_RewindLocation.x;
rewind_x_diff *= rewind_x_diff; rewind_x_diff *= rewind_x_diff;
rewind_y_diff = cy - m_RewindLocation.y; rewind_y_diff = cy - m_RewindLocation.y;
rewind_y_diff *= rewind_y_diff; rewind_y_diff *= rewind_y_diff;
/* /*
We only need to store updated values if the player has moved. We only need to store updated values if the player has moved.
If the player has moved more than units for x or y, then we'll store If the player has moved more than units for x or y, then we'll store
his pre-PPU x and y for /rewind, in case he gets stuck. his pre-PPU x and y for /rewind, in case he gets stuck.
*/ */
if ((rewind_x_diff > 750) || (rewind_y_diff > 750)) if ((rewind_x_diff > 750) || (rewind_y_diff > 750))
m_RewindLocation = glm::vec3(m_Position); m_RewindLocation = glm::vec3(m_Position);
/* /*
If the PPU was a large jump, such as a cross zone gate or Call of Hero, If the PPU was a large jump, such as a cross zone gate or Call of Hero,
just update rewind coordinates to the new ppu coordinates. This will prevent exploitation. just update rewind coordinates to the new ppu coordinates. This will prevent exploitation.
*/ */
if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000)) if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000))
m_RewindLocation = glm::vec3(cx, cy, cz); m_RewindLocation = glm::vec3(cx, cy, cz);
if (proximity_timer.Check()) { if (proximity_timer.Check()) {
entity_list.ProcessMove(this, glm::vec3(cx, cy, cz)); entity_list.ProcessMove(this, glm::vec3(cx, cy, cz));
if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity)) if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity))
ProcessTaskProximities(cx, cy, cz); ProcessTaskProximities(cx, cy, cz);
m_Proximity = glm::vec3(cx, cy, cz); m_Proximity = glm::vec3(cx, cy, cz);
} }
/* Update internal state */ /* Update internal state */
m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
if (IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) { if (IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) {
if (zone->random.Real(0, 100) < 70)//should be good if (zone->random.Real(0, 100) < 70)//should be good
CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20); CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20);
} }
/* Break Hide if moving without sneaking and set rewind timer if moved */ /* Break Hide if moving without sneaking and set rewind timer if moved */
if (cy != m_Position.y || cx != m_Position.x) { if (cy != m_Position.y || cx != m_Position.x) {
if ((hidden || improved_hidden) && !sneaking) { if ((hidden || improved_hidden) && !sneaking) {
@ -4508,7 +4519,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
} }
rewind_timer.Start(30000, true); rewind_timer.Start(30000, true);
} }
/* Handle client aggro scanning timers NPCs */ /* Handle client aggro scanning timers NPCs */
is_client_moving = (cy == m_Position.y && cx == m_Position.x) ? false : true; is_client_moving = (cy == m_Position.y && cx == m_Position.x) ? false : true;
@ -4572,55 +4583,55 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
} }
int32 new_animation = ppu->animation; int32 new_animation = ppu->animation;
/* Update internal server position from what the client has sent */ /* Update internal server position from what the client has sent */
m_Position.x = cx; m_Position.x = cx;
m_Position.y = cy; m_Position.y = cy;
m_Position.z = cz; m_Position.z = cz;
/* Visual Debugging */ /* Visual Debugging */
if (RuleB(Character, OPClientUpdateVisualDebug)) { if (RuleB(Character, OPClientUpdateVisualDebug)) {
LogDebug("ClientUpdate: ppu x: [{}] y: [{}] z: [{}] h: [{}]", cx, cy, cz, new_heading); LogDebug("ClientUpdate: ppu x: [{}] y: [{}] z: [{}] h: [{}]", cx, cy, cz, new_heading);
this->SendAppearanceEffect(78, 0, 0, 0, 0); this->SendAppearanceEffect(78, 0, 0, 0, 0);
this->SendAppearanceEffect(41, 0, 0, 0, 0); this->SendAppearanceEffect(41, 0, 0, 0, 0);
} }
/* Only feed real time updates when client is moving */ /* Only feed real time updates when client is moving */
if (is_client_moving || new_heading != m_Position.w || new_animation != animation) { if (is_client_moving || new_heading != m_Position.w || new_animation != animation) {
animation = ppu->animation; animation = ppu->animation;
m_Position.w = new_heading; m_Position.w = new_heading;
/* Broadcast update to other clients */ /* Broadcast update to other clients */
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer; PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
MakeSpawnUpdate(position_update); MakeSpawnUpdate(position_update);
if (gm_hide_me) { if (gm_hide_me) {
entity_list.QueueClientsStatus(this, outapp, true, Admin(), 255); entity_list.QueueClientsStatus(this, outapp, true, Admin(), 255);
} else { } else {
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true); entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true);
} }
/* Always send position updates to group - send when beyond normal ClientPositionUpdate range */ /* Always send position updates to group - send when beyond normal ClientPositionUpdate range */
Group *group = this->GetGroup(); Group *group = this->GetGroup();
Raid *raid = this->GetRaid(); Raid *raid = this->GetRaid();
if (raid) { if (raid) {
raid->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1)); raid->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
} else if (group) { } else if (group) {
group->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1)); group->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
} }
safe_delete(outapp); safe_delete(outapp);
} }
if (zone->watermap) { if (zone->watermap) {
if (zone->watermap->InLiquid(glm::vec3(m_Position))) { if (zone->watermap->InLiquid(glm::vec3(m_Position))) {
CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17); CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17);
// Dismount horses when entering water // Dismount horses when entering water
if (GetHorseId() && RuleB(Character, DismountWater)) { if (GetHorseId() && RuleB(Character, DismountWater)) {
SetHorseId(0); SetHorseId(0);
@ -5757,23 +5768,23 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
printf("Error in FindPersonRequest_Struct. Expected size of: %zu, but got: %i\n", sizeof(FindPersonRequest_Struct), app->size); printf("Error in FindPersonRequest_Struct. Expected size of: %zu, but got: %i\n", sizeof(FindPersonRequest_Struct), app->size);
else { else {
FindPersonRequest_Struct* t = (FindPersonRequest_Struct*)app->pBuffer; FindPersonRequest_Struct* t = (FindPersonRequest_Struct*)app->pBuffer;
std::vector<FindPerson_Point> points; std::vector<FindPerson_Point> points;
Mob* target = entity_list.GetMob(t->npc_id); Mob* target = entity_list.GetMob(t->npc_id);
if (target == nullptr) { if (target == nullptr) {
//empty length packet == not found. //empty length packet == not found.
EQApplicationPacket outapp(OP_FindPersonReply, 0); EQApplicationPacket outapp(OP_FindPersonReply, 0);
QueuePacket(&outapp); QueuePacket(&outapp);
return; return;
} }
if (!RuleB(Pathing, Find) && RuleB(Bazaar, EnableWarpToTrader) && target->IsClient() && (target->CastToClient()->Trader || if (!RuleB(Pathing, Find) && RuleB(Bazaar, EnableWarpToTrader) && target->IsClient() && (target->CastToClient()->Trader ||
target->CastToClient()->Buyer)) { target->CastToClient()->Buyer)) {
Message(Chat::Yellow, "Moving you to Trader %s", target->GetName()); Message(Chat::Yellow, "Moving you to Trader %s", target->GetName());
MovePC(zone->GetZoneID(), zone->GetInstanceID(), target->GetX(), target->GetY(), target->GetZ(), 0.0f); MovePC(zone->GetZoneID(), zone->GetInstanceID(), target->GetX(), target->GetY(), target->GetZ(), 0.0f);
} }
if (!RuleB(Pathing, Find) || !zone->pathing) if (!RuleB(Pathing, Find) || !zone->pathing)
{ {
//fill in the path array... //fill in the path array...
@ -5796,40 +5807,40 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
{ {
glm::vec3 Start(GetX(), GetY(), GetZ() + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION); glm::vec3 Start(GetX(), GetY(), GetZ() + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION);
glm::vec3 End(target->GetX(), target->GetY(), target->GetZ() + (target->GetSize() < 6.0 ? 6 : target->GetSize()) * HEAD_POSITION); glm::vec3 End(target->GetX(), target->GetY(), target->GetZ() + (target->GetSize() < 6.0 ? 6 : target->GetSize()) * HEAD_POSITION);
bool partial = false; bool partial = false;
bool stuck = false; bool stuck = false;
auto pathlist = zone->pathing->FindRoute(Start, End, partial, stuck); auto pathlist = zone->pathing->FindRoute(Start, End, partial, stuck);
if (pathlist.empty() || partial) if (pathlist.empty() || partial)
{ {
EQApplicationPacket outapp(OP_FindPersonReply, 0); EQApplicationPacket outapp(OP_FindPersonReply, 0);
QueuePacket(&outapp); QueuePacket(&outapp);
return; return;
} }
// Live appears to send the points in this order: // Live appears to send the points in this order:
// Final destination. // Final destination.
// Current Position. // Current Position.
// rest of the points. // rest of the points.
FindPerson_Point p; FindPerson_Point p;
int PointNumber = 0; int PointNumber = 0;
bool LeadsToTeleporter = false; bool LeadsToTeleporter = false;
auto v = pathlist.back(); auto v = pathlist.back();
p.x = v.pos.x; p.x = v.pos.x;
p.y = v.pos.y; p.y = v.pos.y;
p.z = v.pos.z; p.z = v.pos.z;
points.push_back(p); points.push_back(p);
p.x = GetX(); p.x = GetX();
p.y = GetY(); p.y = GetY();
p.z = GetZ(); p.z = GetZ();
points.push_back(p); points.push_back(p);
for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator) for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator)
{ {
if ((*Iterator).teleport) // Teleporter if ((*Iterator).teleport) // Teleporter
@ -5837,7 +5848,7 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
LeadsToTeleporter = true; LeadsToTeleporter = true;
break; break;
} }
glm::vec3 v = (*Iterator).pos; glm::vec3 v = (*Iterator).pos;
p.x = v.x; p.x = v.x;
p.y = v.y; p.y = v.y;
@ -5845,17 +5856,17 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
points.push_back(p); points.push_back(p);
++PointNumber; ++PointNumber;
} }
if (!LeadsToTeleporter) if (!LeadsToTeleporter)
{ {
p.x = target->GetX(); p.x = target->GetX();
p.y = target->GetY(); p.y = target->GetY();
p.z = target->GetZ(); p.z = target->GetZ();
points.push_back(p); points.push_back(p);
} }
} }
SendPathPacket(points); SendPathPacket(points);
} }
} }
@ -11098,14 +11109,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
{ {
case RaidCommandInviteIntoExisting: case RaidCommandInviteIntoExisting:
case RaidCommandInvite: { case RaidCommandInvite: {
Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name); Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name);
if (!player_to_invite) if (!player_to_invite)
break; break;
Group *player_to_invite_group = player_to_invite->GetGroup(); Group *player_to_invite_group = player_to_invite->GetGroup();
if (player_to_invite->HasRaid()) { if (player_to_invite->HasRaid()) {
Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName()); Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName());
break; break;
@ -11120,7 +11131,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid.");
break; break;
} }
/* Send out invite to the client */ /* Send out invite to the client */
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
RaidGeneral_Struct *raid_command = (RaidGeneral_Struct*)outapp->pBuffer; RaidGeneral_Struct *raid_command = (RaidGeneral_Struct*)outapp->pBuffer;
@ -11132,7 +11143,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid_command->action = 20; raid_command->action = 20;
player_to_invite->QueuePacket(outapp); player_to_invite->QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
break; break;
@ -11228,7 +11239,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
} }
if (player_invited_group->IsLeader(player_invited_group->members[x])) { if (player_invited_group->IsLeader(player_invited_group->members[x])) {
Client *c = nullptr; Client *c = nullptr;
if (player_invited_group->members[x]->IsClient()) if (player_invited_group->members[x]->IsClient())
c = player_invited_group->members[x]->CastToClient(); c = player_invited_group->members[x]->CastToClient();
else else
@ -11238,24 +11249,24 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id, true, true, true); raid->AddMember(c, raid_free_group_id, true, true, true);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
} }
else { else {
Client *c = nullptr; Client *c = nullptr;
if (player_invited_group->members[x]->IsClient()) if (player_invited_group->members[x]->IsClient())
c = player_invited_group->members[x]->CastToClient(); c = player_invited_group->members[x]->CastToClient();
else else
continue; continue;
raid->SendRaidCreate(c); raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id); raid->AddMember(c, raid_free_group_id);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
@ -11289,12 +11300,12 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
c = group->members[x]->CastToClient(); c = group->members[x]->CastToClient();
else else
continue; continue;
raid->SendRaidCreate(c); raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id, false, true); raid->AddMember(c, raid_free_group_id, false, true);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
@ -11302,17 +11313,17 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
else else
{ {
Client *c = nullptr; Client *c = nullptr;
if (group->members[x]->IsClient()) if (group->members[x]->IsClient())
c = group->members[x]->CastToClient(); c = group->members[x]->CastToClient();
else else
continue; continue;
raid->SendRaidCreate(c); raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id); raid->AddMember(c, raid_free_group_id);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
@ -11329,7 +11340,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
if (player_invited_group) { if (player_invited_group) {
raid = new Raid(player_accepting_invite); raid = new Raid(player_accepting_invite);
entity_list.AddRaid(raid); entity_list.AddRaid(raid);
raid->SetRaidDetails(); raid->SetRaidDetails();
Client *addClientig = nullptr; Client *addClientig = nullptr;
@ -11353,7 +11364,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, 0, true, true, true); raid->AddMember(c, 0, true, true, true);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
@ -11478,7 +11489,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SetGroupLeader(raid_command_packet->leader_name, false); raid->SetGroupLeader(raid_command_packet->leader_name, false);
/* We were the leader of our old group */ /* We were the leader of our old group */
if (old_group < 12) { if (old_group < 12) {
/* Assign new group leader if we can */ /* Assign new group leader if we can */
for (int x = 0; x < MAX_RAID_MEMBERS; x++) { for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (raid->members[x].GroupNumber == old_group) { if (raid->members[x].GroupNumber == old_group) {
@ -11507,7 +11518,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
strn0cpy(raid_command_packet->playername, raid->members[x].membername, 64); strn0cpy(raid_command_packet->playername, raid->members[x].membername, 64);
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
} }
break; break;
@ -11553,7 +11564,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SetGroupLeader(raid_command_packet->leader_name, false); raid->SetGroupLeader(raid_command_packet->leader_name, false);
for (int x = 0; x < MAX_RAID_MEMBERS; x++) { for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (raid->members[x].GroupNumber == oldgrp && strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid_command_packet->leader_name) != 0){ if (raid->members[x].GroupNumber == oldgrp && strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid_command_packet->leader_name) != 0){
raid->SetGroupLeader(raid->members[x].membername); raid->SetGroupLeader(raid->members[x].membername);
raid->UpdateGroupAAs(oldgrp); raid->UpdateGroupAAs(oldgrp);
@ -11576,7 +11587,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
strn0cpy(raid_command->playername, raid->members[x].membername, 64); strn0cpy(raid_command->playername, raid->members[x].membername, 64);
raid_command->zoneid = zone->GetZoneID(); raid_command->zoneid = zone->GetZoneID();
raid_command->instance_id = zone->GetInstanceID(); raid_command->instance_id = zone->GetInstanceID();
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
} }
@ -11591,14 +11602,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
else { else {
auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct));
ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer; ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
raid_command->rid = raid->GetID(); raid_command->rid = raid->GetID();
raid_command->zoneid = zone->GetZoneID(); raid_command->zoneid = zone->GetZoneID();
raid_command->instance_id = zone->GetInstanceID(); raid_command->instance_id = zone->GetInstanceID();
strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64); strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64);
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
} }

View File

@ -90,6 +90,11 @@ void Lua_Client::SetPVP(bool v) {
self->SetPVP(v); self->SetPVP(v);
} }
void Lua_Client::SendToGuildHall() {
Lua_Safe_Call_Void();
self->SendToGuildHall();
}
bool Lua_Client::GetPVP() { bool Lua_Client::GetPVP() {
Lua_Safe_Call_Bool(); Lua_Safe_Call_Bool();
return self->GetPVP(); return self->GetPVP();
@ -1584,6 +1589,7 @@ luabind::scope lua_register_client() {
.def("Disconnect", (void(Lua_Client::*)(void))&Lua_Client::Disconnect) .def("Disconnect", (void(Lua_Client::*)(void))&Lua_Client::Disconnect)
.def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD) .def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD)
.def("WorldKick", (void(Lua_Client::*)(void))&Lua_Client::WorldKick) .def("WorldKick", (void(Lua_Client::*)(void))&Lua_Client::WorldKick)
.def("SendToGuildHall", (void(Lua_Client::*)(void))&Lua_Client::SendToGuildHall)
.def("GetAnon", (bool(Lua_Client::*)(void))&Lua_Client::GetAnon) .def("GetAnon", (bool(Lua_Client::*)(void))&Lua_Client::GetAnon)
.def("Duck", (void(Lua_Client::*)(void))&Lua_Client::Duck) .def("Duck", (void(Lua_Client::*)(void))&Lua_Client::Duck)
.def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand) .def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand)

View File

@ -39,6 +39,7 @@ public:
void Disconnect(); void Disconnect();
bool IsLD(); bool IsLD();
void WorldKick(); void WorldKick();
void SendToGuildHall();
bool GetAnon(); bool GetAnon();
void Duck(); void Duck();
void Stand(); void Stand();

View File

@ -245,6 +245,27 @@ XS(XS_Client_WorldKick) {
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
XS(XS_Client_SendToGuildHall); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_SendToGuildHall) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client::SendToGuildHall(THIS)");
{
Client *THIS;
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
THIS = INT2PTR(Client *, tmp);
} else
Perl_croak(aTHX_ "THIS is not of type Client");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->SendToGuildHall();
}
XSRETURN_EMPTY;
}
XS(XS_Client_GetAnon); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_GetAnon); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_GetAnon) { XS(XS_Client_GetAnon) {
dXSARGS; dXSARGS;
@ -2439,7 +2460,7 @@ XS(XS_Client_MemmedCount) {
RETVAL = THIS->MemmedCount(); RETVAL = THIS->MemmedCount();
XSprePUSH; XSprePUSH;
PUSHu((UV) RETVAL); PUSHu((UV) RETVAL);
} }
XSRETURN(1); XSRETURN(1);
} }
@ -4786,7 +4807,7 @@ XS(XS_Client_AddLevelBasedExp) {
if (items > 2) if (items > 2)
max_level = (uint8) SvUV(ST(2)); max_level = (uint8) SvUV(ST(2));
if (items > 3) if (items > 3)
ignore_mods = (bool) SvTRUE(ST(3)); ignore_mods = (bool) SvTRUE(ST(3));
@ -6564,6 +6585,7 @@ XS(boot_Client) {
newXSproto(strcpy(buf, "SendSound"), XS_Client_SendSound, file, "$"); newXSproto(strcpy(buf, "SendSound"), XS_Client_SendSound, file, "$");
newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$"); newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$");
newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$"); newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$");
newXSproto(strcpy(buf, "SendToGuildHall"), XS_Client_SendToGuildHall, file, "$");
newXSproto(strcpy(buf, "SendWebLink"), XS_Client_SendWebLink, file, "$:$"); newXSproto(strcpy(buf, "SendWebLink"), XS_Client_SendWebLink, file, "$:$");
newXSproto(strcpy(buf, "SendZoneFlagInfo"), XS_Client_SendZoneFlagInfo, file, "$$"); newXSproto(strcpy(buf, "SendZoneFlagInfo"), XS_Client_SendZoneFlagInfo, file, "$$");
newXSproto(strcpy(buf, "SetAAPoints"), XS_Client_SetAAPoints, file, "$$"); newXSproto(strcpy(buf, "SetAAPoints"), XS_Client_SetAAPoints, file, "$$");

View File

@ -140,7 +140,7 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
if(iInstanceID != 0) if(iInstanceID != 0)
{ {
auto pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16)); auto pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16));
*((uint16*)pack->pBuffer) = iInstanceID; *((uint16*)pack->pBuffer) = iInstanceID;
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
delete pack; delete pack;
} }
@ -491,7 +491,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid) {
void Zone::GetMerchantDataForZoneLoad() { void Zone::GetMerchantDataForZoneLoad() {
LogInfo("Loading Merchant Lists"); LogInfo("Loading Merchant Lists");
std::string query = StringFormat( std::string query = StringFormat(
"SELECT " "SELECT "
"DISTINCT ml.merchantid, " "DISTINCT ml.merchantid, "
"ml.slot, " "ml.slot, "
@ -816,7 +816,7 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
{ {
LogDebug("Graveyard ID is [{}]", graveyard_id()); LogDebug("Graveyard ID is [{}]", graveyard_id());
bool GraveYardLoaded = database.GetZoneGraveyard(graveyard_id(), &pgraveyard_zoneid, &m_Graveyard.x, &m_Graveyard.y, &m_Graveyard.z, &m_Graveyard.w); bool GraveYardLoaded = database.GetZoneGraveyard(graveyard_id(), &pgraveyard_zoneid, &m_Graveyard.x, &m_Graveyard.y, &m_Graveyard.z, &m_Graveyard.w);
if (GraveYardLoaded) { if (GraveYardLoaded) {
LogDebug("Loaded a graveyard for zone [{}]: graveyard zoneid is [{}] at [{}]", short_name, graveyard_zoneid(), to_string(m_Graveyard).c_str()); LogDebug("Loaded a graveyard for zone [{}]: graveyard zoneid is [{}] at [{}]", short_name, graveyard_zoneid(), to_string(m_Graveyard).c_str());
} }
@ -907,7 +907,7 @@ Zone::~Zone() {
//Modified for timezones. //Modified for timezones.
bool Zone::Init(bool iStaticZone) { bool Zone::Init(bool iStaticZone) {
SetStaticZone(iStaticZone); SetStaticZone(iStaticZone);
//load the zone config file. //load the zone config file.
if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion())) // try loading the zone name... if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion())) // try loading the zone name...
LoadZoneCFG(zone->GetFileName(), zone->GetInstanceVersion()); // if that fails, try the file name, then load defaults LoadZoneCFG(zone->GetFileName(), zone->GetInstanceVersion()); // if that fails, try the file name, then load defaults
@ -1018,6 +1018,10 @@ bool Zone::Init(bool iStaticZone) {
petition_list.ClearPetitions(); petition_list.ClearPetitions();
petition_list.ReadDatabase(); petition_list.ReadDatabase();
if (zone->GetInstanceID() > 0) {
zone->SetInstanceTimeRemaining(database.GetTimeRemainingInstance(zone->GetInstanceID()));
}
LogInfo("Loading timezone data"); LogInfo("Loading timezone data");
zone->zone_time.setEQTimeZone(database.GetZoneTZ(zoneid, GetInstanceVersion())); zone->zone_time.setEQTimeZone(database.GetZoneTZ(zoneid, GetInstanceVersion()));
@ -1089,7 +1093,7 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id)
if (instance_id != 0) if (instance_id != 0)
{ {
safe_delete_array(map_name); safe_delete_array(map_name);
if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate, if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate,
can_castoutdoor, is_city, is_hotzone, allow_mercs, max_movement_update_range, zone_type, default_ruleset, &map_name)) can_castoutdoor, is_city, is_hotzone, allow_mercs, max_movement_update_range, zone_type, default_ruleset, &map_name))
{ {
LogError("Error loading the Zone Config"); LogError("Error loading the Zone Config");
@ -2455,3 +2459,13 @@ void Zone::SetQuestHotReloadQueued(bool in_quest_hot_reload_queued)
{ {
quest_hot_reload_queued = in_quest_hot_reload_queued; quest_hot_reload_queued = in_quest_hot_reload_queued;
} }
uint32 Zone::GetInstanceTimeRemaining() const
{
return instance_time_remaining;
}
void Zone::SetInstanceTimeRemaining(uint32 instance_time_remaining)
{
Zone::instance_time_remaining = instance_time_remaining;
}

View File

@ -278,6 +278,9 @@ public:
ZonePoint *GetClosestZonePoint(const glm::vec3 &location, uint32 to, Client *client, float max_distance = 40000.0f); ZonePoint *GetClosestZonePoint(const glm::vec3 &location, uint32 to, Client *client, float max_distance = 40000.0f);
ZonePoint *GetClosestZonePointWithoutZone(float x, float y, float z, Client *client, float max_distance = 40000.0f); ZonePoint *GetClosestZonePointWithoutZone(float x, float y, float z, Client *client, float max_distance = 40000.0f);
uint32 GetInstanceTimeRemaining() const;
void SetInstanceTimeRemaining(uint32 instance_time_remaining);
/** /**
* GMSay Callback for LogSys * GMSay Callback for LogSys
* *
@ -361,6 +364,7 @@ private:
uint8 zone_type; uint8 zone_type;
uint16 instanceversion; uint16 instanceversion;
uint32 instanceid; uint32 instanceid;
uint32 instance_time_remaining;
uint32 pgraveyard_id, pgraveyard_zoneid; uint32 pgraveyard_id, pgraveyard_zoneid;
uint32 pMaxClients; uint32 pMaxClients;
uint32 zoneid; uint32 zoneid;