zaela-Server/zone/exp.cpp

1164 lines
33 KiB
C++
Raw Permalink Normal View History

2013-05-09 10:44:08 -04:00
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net)
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
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.
2013-05-06 13:07:41 -04:00
2013-05-09 10:44:08 -04:00
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
2013-02-16 16:14:39 -08:00
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
2013-05-09 10:44:08 -04:00
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
2013-05-06 13:07:41 -04:00
2013-05-09 10:44:08 -04:00
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
2013-02-16 16:14:39 -08:00
*/
2014-12-15 17:22:13 -06:00
#include "../common/global_define.h"
2013-02-20 13:54:26 -08:00
#include "../common/features.h"
2013-02-16 16:14:39 -08:00
#include "../common/rulesys.h"
2014-12-15 17:22:13 -06:00
#include "../common/string_util.h"
#include "client.h"
#include "groups.h"
#include "mob.h"
#include "raids.h"
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
#include "queryserv.h"
2014-12-15 17:22:13 -06:00
#include "quest_parser_collection.h"
#include "lua_parser.h"
2014-12-15 17:22:13 -06:00
#include "string_ids.h"
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
2014-12-15 20:08:46 -05:00
#ifdef BOTS
#include "bot.h"
#endif
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
extern QueryServ* QServ;
2013-02-16 16:14:39 -08:00
static uint32 ScaleAAXPBasedOnCurrentAATotal(int earnedAA, uint32 add_aaxp)
{
float baseModifier = RuleR(AA, ModernAAScalingStartPercent);
int aaMinimum = RuleI(AA, ModernAAScalingAAMinimum);
int aaLimit = RuleI(AA, ModernAAScalingAALimit);
// Are we within the scaling window?
if (earnedAA >= aaLimit || earnedAA < aaMinimum)
{
2019-09-01 23:54:24 -05:00
LogDebug("Not within AA scaling window");
// At or past the limit. We're done.
return add_aaxp;
}
// We're not at the limit yet. How close are we?
int remainingAA = aaLimit - earnedAA;
// We might not always be X - 0
int scaleRange = aaLimit - aaMinimum;
// Normalize and get the effectiveness based on the range and the character's
// current spent AA.
float normalizedScale = (float)remainingAA / scaleRange;
// Scale.
uint32 totalWithExpMod = add_aaxp * (baseModifier / 100) * normalizedScale;
// Are we so close to the scale limit that we're earning more XP without scaling? This
// will happen when we get very close to the limit. In this case, just grant the unscaled
// amount.
if (totalWithExpMod < add_aaxp)
{
return add_aaxp;
}
2018-01-02 17:27:59 -05:00
Log(Logs::Detail,
Logs::None,
"Total before the modifier %d :: NewTotal %d :: ScaleRange: %d, SpentAA: %d, RemainingAA: %d, normalizedScale: %0.3f",
add_aaxp, totalWithExpMod, scaleRange, earnedAA, remainingAA, normalizedScale);
return totalWithExpMod;
}
2013-02-16 16:14:39 -08:00
static uint32 MaxBankedGroupLeadershipPoints(int Level)
{
if(Level < 35)
return 4;
if(Level < 51)
return 6;
return 8;
}
static uint32 MaxBankedRaidLeadershipPoints(int Level)
{
if(Level < 45)
return 6;
if(Level < 55)
return 8;
return 10;
}
Haynar's movement fixes. Changes Speed from float to int. EQ client deals with int step locs better than it does floats according to Haynar's testing. This also contains mob runspeed changes. I recommend you set runspeeds to start in the DB 1.25 for NPCs below 1.25 which will match player runspeeds almost equally. Existing DBs will need to be updated. General Cleanup of MobAI functions. Mobs now change their heading on AIMovement timers if their targets' heading has changed since that time. This prevents players from being able to land backstabs inbetween mob swings. Charmed/feared players now send the appropriate packet, there was a missing CastToClient() in spells that was missing. Mob runspeed can no longer be snared to 0%, instead, 1% of their base runspeed is the maximum. Roots apply as roots instead of a modifier under this code. There is going to be bugs with this code. It's better we push through it than revert it. Sanctuary has been running this for a good week and we've worked through the issues. Misc updates: Exported some variables to perl, including: EVENT_ITE_CLICK_CAST: EVENT_ITEM_CLICK: spell_id - returns the spell_id of the click effect. return value - cancels the cast. EVENT_DROP_ITEM: quantity - returns the # of items dropped in the packet. If the item has charges, charges are returned here instead. itemname - name of the item being dropped itemid - id of the item being droppped spell_id - spell_id associated with the item's click effect. slotid - the inventory slot id of the item being dropped. return value - cancels the item from being dropped. Added Perl function: CalcEXP. Calculates the experience you would gain for an NPC that cons a specific con value to you. Fixed a bug where you would receive the group experience bonus and group experience messages for simply being in a group, regardless of the player being in the same zone as you.
2015-05-25 12:35:53 -04:00
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_GRAY:
Haynar's movement fixes. Changes Speed from float to int. EQ client deals with int step locs better than it does floats according to Haynar's testing. This also contains mob runspeed changes. I recommend you set runspeeds to start in the DB 1.25 for NPCs below 1.25 which will match player runspeeds almost equally. Existing DBs will need to be updated. General Cleanup of MobAI functions. Mobs now change their heading on AIMovement timers if their targets' heading has changed since that time. This prevents players from being able to land backstabs inbetween mob swings. Charmed/feared players now send the appropriate packet, there was a missing CastToClient() in spells that was missing. Mob runspeed can no longer be snared to 0%, instead, 1% of their base runspeed is the maximum. Roots apply as roots instead of a modifier under this code. There is going to be bugs with this code. It's better we push through it than revert it. Sanctuary has been running this for a good week and we've worked through the issues. Misc updates: Exported some variables to perl, including: EVENT_ITE_CLICK_CAST: EVENT_ITEM_CLICK: spell_id - returns the spell_id of the click effect. return value - cancels the cast. EVENT_DROP_ITEM: quantity - returns the # of items dropped in the packet. If the item has charges, charges are returned here instead. itemname - name of the item being dropped itemid - id of the item being droppped spell_id - spell_id associated with the item's click effect. slotid - the inventory slot id of the item being dropped. return value - cancels the item from being dropped. Added Perl function: CalcEXP. Calculates the experience you would gain for an NPC that cons a specific con value to you. Fixed a bug where you would receive the group experience bonus and group experience messages for simply being in a group, regardless of the player being in the same zone as you.
2015-05-25 12:35:53 -04:00
in_add_exp = 0;
return 0;
case CON_GREEN:
in_add_exp = in_add_exp * RuleI(Character, GreenModifier) / 100;
break;
Haynar's movement fixes. Changes Speed from float to int. EQ client deals with int step locs better than it does floats according to Haynar's testing. This also contains mob runspeed changes. I recommend you set runspeeds to start in the DB 1.25 for NPCs below 1.25 which will match player runspeeds almost equally. Existing DBs will need to be updated. General Cleanup of MobAI functions. Mobs now change their heading on AIMovement timers if their targets' heading has changed since that time. This prevents players from being able to land backstabs inbetween mob swings. Charmed/feared players now send the appropriate packet, there was a missing CastToClient() in spells that was missing. Mob runspeed can no longer be snared to 0%, instead, 1% of their base runspeed is the maximum. Roots apply as roots instead of a modifier under this code. There is going to be bugs with this code. It's better we push through it than revert it. Sanctuary has been running this for a good week and we've worked through the issues. Misc updates: Exported some variables to perl, including: EVENT_ITE_CLICK_CAST: EVENT_ITEM_CLICK: spell_id - returns the spell_id of the click effect. return value - cancels the cast. EVENT_DROP_ITEM: quantity - returns the # of items dropped in the packet. If the item has charges, charges are returned here instead. itemname - name of the item being dropped itemid - id of the item being droppped spell_id - spell_id associated with the item's click effect. slotid - the inventory slot id of the item being dropped. return value - cancels the item from being dropped. Added Perl function: CalcEXP. Calculates the experience you would gain for an NPC that cons a specific con value to you. Fixed a bug where you would receive the group experience bonus and group experience messages for simply being in a group, regardless of the player being in the same zone as you.
2015-05-25 12:35:53 -04:00
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;
}
uint32 Client::GetExperienceForKill(Mob *against)
{
#ifdef LUA_EQEMU
uint32 lua_ret = 0;
bool ignoreDefault = false;
lua_ret = LuaParser::Instance()->GetExperienceForKill(this, against, ignoreDefault);
if (ignoreDefault) {
return lua_ret;
}
#endif
if (against && against->IsNPC()) {
uint32 level = (uint32)against->GetLevel();
return EXP_FORMULA;
}
return 0;
}
float static GetConLevelModifierPercent(uint8 conlevel)
{
switch (conlevel)
{
case CON_GREEN:
return (float)RuleI(Character, GreenModifier) / 100;
break;
case CON_LIGHTBLUE:
return (float)RuleI(Character, LightBlueModifier) / 100;
break;
case CON_BLUE:
return (float)RuleI(Character, BlueModifier) / 100;
break;
case CON_WHITE:
return (float)RuleI(Character, WhiteModifier) / 100;
break;
case CON_YELLOW:
return (float)RuleI(Character, YellowModifier) / 100;
break;
case CON_RED:
return (float)RuleI(Character, RedModifier) / 100;
break;
default:
return 0;
}
}
2013-02-16 16:14:39 -08:00
void Client::CalculateNormalizedAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp)
{
// Functionally this is the same as having the case in the switch, but this is
// cleaner to read.
if (CON_GRAY == conlevel || resexp)
{
add_aaxp = 0;
return;
}
// For this, we ignore the provided value of add_aaxp because it doesn't
// apply. XP per AA is normalized such that there are X white con kills
// per AA.
uint32 whiteConKillsPerAA = RuleI(AA, NormalizedAANumberOfWhiteConPerAA);
uint32 xpPerAA = RuleI(AA, ExpPerPoint);
float colorModifier = GetConLevelModifierPercent(conlevel);
float percentToAAXp = (float)m_epp.perAA / 100;
// Normalize the amount of AA XP we earned for this kill.
add_aaxp = percentToAAXp * (xpPerAA / (whiteConKillsPerAA / colorModifier));
}
void Client::CalculateStandardAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp)
{
if (!resexp)
{
//if XP scaling is based on the con of a monster, do that now.
if (RuleB(Character, UseXPConScaling))
{
if (conlevel != 0xFF && !resexp)
{
add_aaxp *= GetConLevelModifierPercent(conlevel);
}
}
} //end !resexp
float aatotalmod = 1.0;
if (zone->newzone_data.zone_exp_multiplier >= 0) {
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
}
// Shouldn't race not affect AA XP?
if (RuleB(Character, UseRaceClassExpBonuses))
{
if (GetBaseRace() == HALFLING) {
aatotalmod *= 1.05;
}
if (GetClass() == ROGUE || GetClass() == WARRIOR) {
aatotalmod *= 1.05;
}
}
// why wasn't this here? Where should it be?
if (zone->IsHotzone())
{
aatotalmod += RuleR(Zone, HotZoneBonus);
}
if (RuleB(Zone, LevelBasedEXPMods)) {
if (zone->level_exp_mod[GetLevel()].ExpMod) {
add_aaxp *= zone->level_exp_mod[GetLevel()].AAExpMod;
}
}
add_aaxp = (uint32)(RuleR(Character, AAExpMultiplier) * add_aaxp * aatotalmod);
}
void Client::CalculateLeadershipExp(uint32 &add_exp, uint8 conlevel)
{
if (IsLeadershipEXPOn() && (conlevel == CON_BLUE || conlevel == CON_WHITE || conlevel == CON_YELLOW || conlevel == CON_RED))
{
add_exp = static_cast<uint32>(static_cast<float>(add_exp) * 0.8f);
if (GetGroup())
{
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0)
{
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
Client *mentoree = GetGroup()->GetMentoree();
if (GetGroup()->GetMentorPercent() && mentoree &&
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel()))
{
uint32 mentor_exp = exp * (GetGroup()->GetMentorPercent() / 100.0f);
exp -= mentor_exp;
mentoree->AddLeadershipEXP(mentor_exp, 0); // ends up rounded down
2019-08-11 00:14:02 -05:00
mentoree->MessageString(Chat::LeaderShip, GAIN_GROUP_LEADERSHIP_EXP);
}
if (exp > 0)
{
// possible if you mentor 100% to the other client
AddLeadershipEXP(exp, 0); // ends up rounded up if mentored, no idea how live actually does it
2019-08-11 00:14:02 -05:00
MessageString(Chat::LeaderShip, GAIN_GROUP_LEADERSHIP_EXP);
}
}
else
{
2019-08-11 00:14:02 -05:00
MessageString(Chat::LeaderShip, MAX_GROUP_LEADERSHIP_POINTS);
}
}
else
{
Raid *raid = GetRaid();
// Raid leaders CAN NOT gain group AA XP, other group leaders can though!
if (raid->IsLeader(this))
{
if (m_pp.raid_leadership_points < MaxBankedRaidLeadershipPoints(GetLevel())
&& RuleI(Character, KillsPerRaidLeadershipAA) > 0)
{
AddLeadershipEXP(0, RAID_EXP_PER_POINT / RuleI(Character, KillsPerRaidLeadershipAA));
2019-08-11 00:14:02 -05:00
MessageString(Chat::LeaderShip, GAIN_RAID_LEADERSHIP_EXP);
}
else
{
2019-08-11 00:14:02 -05:00
MessageString(Chat::LeaderShip, MAX_RAID_LEADERSHIP_POINTS);
}
}
else
{
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0)
{
uint32 group_id = raid->GetGroup(this);
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
Client *mentoree = raid->GetMentoree(group_id);
if (raid->GetMentorPercent(group_id) && mentoree &&
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel()))
{
uint32 mentor_exp = exp * (raid->GetMentorPercent(group_id) / 100.0f);
exp -= mentor_exp;
mentoree->AddLeadershipEXP(mentor_exp, 0);
2019-08-11 00:14:02 -05:00
mentoree->MessageString(Chat::LeaderShip, GAIN_GROUP_LEADERSHIP_EXP);
}
if (exp > 0)
{
AddLeadershipEXP(exp, 0);
2019-08-11 00:14:02 -05:00
MessageString(Chat::LeaderShip, GAIN_GROUP_LEADERSHIP_EXP);
}
}
else
{
2019-08-11 00:14:02 -05:00
MessageString(Chat::LeaderShip, MAX_GROUP_LEADERSHIP_POINTS);
}
}
}
}
}
void Client::CalculateExp(uint32 in_add_exp, uint32 &add_exp, uint32 &add_aaxp, uint8 conlevel, bool resexp)
{
add_exp = in_add_exp;
2013-02-16 16:14:39 -08:00
if (!resexp && (XPRate != 0))
{
2013-02-16 16:14:39 -08:00
add_exp = static_cast<uint32>(in_add_exp * (static_cast<float>(XPRate) / 100.0f));
}
2013-05-06 13:07:41 -04:00
// Make sure it was initialized.
add_aaxp = 0;
2013-05-06 13:07:41 -04:00
if (!resexp)
{
2013-02-16 16:14:39 -08:00
//figure out how much of this goes to AAs
add_aaxp = add_exp * m_epp.perAA / 100;
Haynar's movement fixes. Changes Speed from float to int. EQ client deals with int step locs better than it does floats according to Haynar's testing. This also contains mob runspeed changes. I recommend you set runspeeds to start in the DB 1.25 for NPCs below 1.25 which will match player runspeeds almost equally. Existing DBs will need to be updated. General Cleanup of MobAI functions. Mobs now change their heading on AIMovement timers if their targets' heading has changed since that time. This prevents players from being able to land backstabs inbetween mob swings. Charmed/feared players now send the appropriate packet, there was a missing CastToClient() in spells that was missing. Mob runspeed can no longer be snared to 0%, instead, 1% of their base runspeed is the maximum. Roots apply as roots instead of a modifier under this code. There is going to be bugs with this code. It's better we push through it than revert it. Sanctuary has been running this for a good week and we've worked through the issues. Misc updates: Exported some variables to perl, including: EVENT_ITE_CLICK_CAST: EVENT_ITEM_CLICK: spell_id - returns the spell_id of the click effect. return value - cancels the cast. EVENT_DROP_ITEM: quantity - returns the # of items dropped in the packet. If the item has charges, charges are returned here instead. itemname - name of the item being dropped itemid - id of the item being droppped spell_id - spell_id associated with the item's click effect. slotid - the inventory slot id of the item being dropped. return value - cancels the item from being dropped. Added Perl function: CalcEXP. Calculates the experience you would gain for an NPC that cons a specific con value to you. Fixed a bug where you would receive the group experience bonus and group experience messages for simply being in a group, regardless of the player being in the same zone as you.
2015-05-25 12:35:53 -04:00
//take that amount away from regular exp
2013-02-16 16:14:39 -08:00
add_exp -= add_aaxp;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
float totalmod = 1.0;
float zemmod = 1.0;
2013-02-16 16:14:39 -08:00
//get modifiers
if (RuleR(Character, ExpMultiplier) >= 0) {
2013-02-16 16:14:39 -08:00
totalmod *= RuleR(Character, ExpMultiplier);
}
//add the zone exp modifier.
if (zone->newzone_data.zone_exp_multiplier >= 0) {
2013-02-16 16:14:39 -08:00
zemmod *= zone->newzone_data.zone_exp_multiplier;
}
if (RuleB(Character, UseRaceClassExpBonuses))
2013-02-16 16:14:39 -08:00
{
if (GetBaseRace() == HALFLING) {
2013-02-16 16:14:39 -08:00
totalmod *= 1.05;
}
if (GetClass() == ROGUE || GetClass() == WARRIOR) {
2013-02-16 16:14:39 -08:00
totalmod *= 1.05;
}
}
//add hotzone modifier if one has been set.
if (zone->IsHotzone())
2013-02-16 16:14:39 -08:00
{
totalmod += RuleR(Zone, HotZoneBonus);
}
add_exp = uint32(float(add_exp) * totalmod * zemmod);
2013-05-06 13:07:41 -04:00
//if XP scaling is based on the con of a monster, do that now.
if (RuleB(Character, UseXPConScaling))
2013-02-16 16:14:39 -08:00
{
if (conlevel != 0xFF && !resexp)
{
add_exp = add_exp * GetConLevelModifierPercent(conlevel);
2013-02-16 16:14:39 -08:00
}
}
// Calculate any changes to leadership experience.
CalculateLeadershipExp(add_exp, conlevel);
2013-02-16 16:14:39 -08:00
} //end !resexp
if (RuleB(Zone, LevelBasedEXPMods)) {
if (zone->level_exp_mod[GetLevel()].ExpMod) {
add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
2013-02-16 16:14:39 -08:00
}
}
add_exp = GetEXP() + add_exp;
}
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
2013-02-16 16:14:39 -08:00
this->EVENT_ITEM_ScriptStopReturn();
uint32 exp = 0;
uint32 aaexp = 0;
2013-02-16 16:14:39 -08:00
if (m_epp.perAA<0 || m_epp.perAA>100)
m_epp.perAA=0; // stop exploit with sanity check
// Calculate regular XP
CalculateExp(in_add_exp, exp, aaexp, conlevel, resexp);
// Calculate regular AA XP
if (!RuleB(AA, NormalizedAAEnabled))
{
CalculateStandardAAExp(aaexp, conlevel, resexp);
}
else
{
CalculateNormalizedAAExp(aaexp, conlevel, resexp);
}
// Are we also doing linear AA acceleration?
if (RuleB(AA, ModernAAScalingEnabled) && aaexp > 0)
{
aaexp = ScaleAAXPBasedOnCurrentAATotal(GetAAPoints(), aaexp);
}
// Get current AA XP total
2013-02-16 16:14:39 -08:00
uint32 had_aaexp = GetAAXP();
// Add it to the XP we just earned.
2013-02-16 16:14:39 -08:00
aaexp += had_aaexp;
// Make sure our new total (existing + just earned) isn't lower than the
// existing total. If it is, we overflowed the bounds of uint32 and wrapped.
// Reset to the existing total.
if (aaexp < had_aaexp)
{
2013-02-16 16:14:39 -08:00
aaexp = had_aaexp; //watch for wrap
}
2013-05-06 13:07:41 -04:00
// AA Sanity Checking for players who set aa exp and deleveled below allowed aa level.
if (GetLevel() <= 50 && m_epp.perAA > 0) {
2019-08-11 00:00:55 -05:00
Message(Chat::Yellow, "You are below the level allowed to gain AA Experience. AA Experience set to 0%");
aaexp = 0;
m_epp.perAA = 0;
}
// Now update our character's normal and AA xp
2013-02-16 16:14:39 -08:00
SetEXP(exp, aaexp, resexp);
}
void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
2019-09-01 23:54:24 -05:00
LogDebug("Attempting to Set Exp for [{}] (XP: [{}], AAXP: [{}], Rez: [{}])", this->GetCleanName(), set_exp, set_aaxp, isrezzexp ? "true" : "false");
auto max_AAXP = GetRequiredAAExperience();
2013-02-16 16:14:39 -08:00
if (max_AAXP == 0 || GetEXPForLevel(GetLevel()) == 0xFFFFFFFF) {
2019-08-11 00:00:55 -05:00
Message(Chat::Red, "Error in Client::SetEXP. EXP not set.");
2013-02-16 16:14:39 -08:00
return; // Must be invalid class/race
}
Haynar's movement fixes. Changes Speed from float to int. EQ client deals with int step locs better than it does floats according to Haynar's testing. This also contains mob runspeed changes. I recommend you set runspeeds to start in the DB 1.25 for NPCs below 1.25 which will match player runspeeds almost equally. Existing DBs will need to be updated. General Cleanup of MobAI functions. Mobs now change their heading on AIMovement timers if their targets' heading has changed since that time. This prevents players from being able to land backstabs inbetween mob swings. Charmed/feared players now send the appropriate packet, there was a missing CastToClient() in spells that was missing. Mob runspeed can no longer be snared to 0%, instead, 1% of their base runspeed is the maximum. Roots apply as roots instead of a modifier under this code. There is going to be bugs with this code. It's better we push through it than revert it. Sanctuary has been running this for a good week and we've worked through the issues. Misc updates: Exported some variables to perl, including: EVENT_ITE_CLICK_CAST: EVENT_ITEM_CLICK: spell_id - returns the spell_id of the click effect. return value - cancels the cast. EVENT_DROP_ITEM: quantity - returns the # of items dropped in the packet. If the item has charges, charges are returned here instead. itemname - name of the item being dropped itemid - id of the item being droppped spell_id - spell_id associated with the item's click effect. slotid - the inventory slot id of the item being dropped. return value - cancels the item from being dropped. Added Perl function: CalcEXP. Calculates the experience you would gain for an NPC that cons a specific con value to you. Fixed a bug where you would receive the group experience bonus and group experience messages for simply being in a group, regardless of the player being in the same zone as you.
2015-05-25 12:35:53 -04:00
uint32 i = 0;
uint32 membercount = 0;
if(GetGroup())
{
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (GetGroup()->members[i] != nullptr) {
membercount++;
}
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) {
2016-09-26 02:09:39 -07:00
uint32 exp_gained = set_exp - m_pp.exp;
uint32 aaxp_gained = set_aaxp - m_pp.expAA;
float exp_percent = (float)((float)exp_gained / (float)(GetEXPForLevel(GetLevel() + 1) - GetEXPForLevel(GetLevel())))*(float)100; //EXP needed for level
float aaxp_percent = (float)((float)aaxp_gained / (float)(RuleI(AA, ExpPerPoint)))*(float)100; //AAEXP needed for level
std::string exp_amount_message = "";
if (RuleI(Character, ShowExpValues) >= 1) {
if (exp_gained > 0 && aaxp_gained > 0) exp_amount_message = StringFormat("%u, %u AA", exp_gained, aaxp_gained);
else if (exp_gained > 0) exp_amount_message = StringFormat("%u", exp_gained);
else exp_amount_message = StringFormat("%u AA", aaxp_gained);
}
std::string exp_percent_message = "";
if (RuleI(Character, ShowExpValues) >= 2) {
if (exp_gained > 0 && aaxp_gained > 0) exp_percent_message = StringFormat("(%.3f%%, %.3f%%AA)", exp_percent, aaxp_percent);
else if (exp_gained > 0) exp_percent_message = StringFormat("(%.3f%%)", exp_percent);
else exp_percent_message = StringFormat("(%.3f%%AA)", aaxp_percent);
}
if (isrezzexp) {
2017-06-16 23:12:54 -07:00
if (RuleI(Character, ShowExpValues) > 0)
2019-08-11 00:00:55 -05:00
Message(Chat::Experience, "You regain %s experience from resurrection. %s", exp_amount_message.c_str(), exp_percent_message.c_str());
2019-08-11 00:14:02 -05:00
else MessageString(Chat::Experience, REZ_REGAIN);
2016-09-26 02:09:39 -07:00
} else {
if (membercount > 1) {
2017-06-16 23:12:54 -07:00
if (RuleI(Character, ShowExpValues) > 0)
2019-08-11 00:00:55 -05:00
Message(Chat::Experience, "You have gained %s party experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
2019-08-11 00:14:02 -05:00
else MessageString(Chat::Experience, GAIN_GROUPXP);
2016-09-26 02:09:39 -07:00
}
else if (IsRaidGrouped()) {
2017-06-16 23:12:54 -07:00
if (RuleI(Character, ShowExpValues) > 0)
2019-08-11 00:00:55 -05:00
Message(Chat::Experience, "You have gained %s raid experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
2019-08-11 00:14:02 -05:00
else MessageString(Chat::Experience, GAIN_RAIDEXP);
2016-09-26 02:09:39 -07:00
}
else {
2017-06-16 23:12:54 -07:00
if (RuleI(Character, ShowExpValues) > 0)
2019-08-11 00:00:55 -05:00
Message(Chat::Experience, "You have gained %s experience! %s", exp_amount_message.c_str(), exp_percent_message.c_str());
2019-08-11 00:14:02 -05:00
else MessageString(Chat::Experience, GAIN_XP);
2016-09-26 02:09:39 -07:00
}
2013-02-16 16:14:39 -08:00
}
}
else if((set_exp + set_aaxp) < (m_pp.exp+m_pp.expAA)){ //only loss message if you lose exp, no message if you gained/lost nothing.
2016-09-26 02:09:39 -07:00
uint32 exp_lost = m_pp.exp - set_exp;
float exp_percent = (float)((float)exp_lost / (float)(GetEXPForLevel(GetLevel() + 1) - GetEXPForLevel(GetLevel())))*(float)100;
2019-08-11 00:00:55 -05:00
if (RuleI(Character, ShowExpValues) == 1 && exp_lost > 0) Message(Chat::Yellow, "You have lost %i experience.", exp_lost);
else if (RuleI(Character, ShowExpValues) == 2 && exp_lost > 0) Message(Chat::Yellow, "You have lost %i experience. (%.3f%%)", exp_lost, exp_percent);
else Message(Chat::Yellow, "You have lost experience.");
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//check_level represents the level we should be when we have
//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;
2013-02-16 16:14:39 -08:00
while (set_exp >= GetEXPForLevel(check_level)) {
check_level++;
if (check_level > 127) { //hard level cap
check_level = 127;
break;
}
level_count++;
2013-02-16 16:14:39 -08:00
if(GetMercID())
UpdateMercLevel();
}
//see if we lost any levels
while (set_exp < GetEXPForLevel(check_level-1)) {
check_level--;
if (check_level < 2) { //hard level minimum
check_level = 2;
break;
}
level_increase = false;
2013-02-16 16:14:39 -08:00
if(GetMercID())
UpdateMercLevel();
}
check_level--;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//see if we gained any AAs
if (set_aaxp >= max_AAXP) {
/*
Note: AA exp is stored differently than normal exp.
2013-05-06 13:07:41 -04:00
Exp points are only stored in m_pp.expAA until you
gain a full AA point, once you gain it, a point is
2013-02-16 16:14:39 -08:00
added to m_pp.aapoints and the ammount needed to gain
that point is subtracted from m_pp.expAA
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
then, once they spend an AA point, it is subtracted from
m_pp.aapoints. In theory it then goes into m_pp.aapoints_spent,
but im not sure if we have that in the right spot.
*/
//record how many points we have
uint32 last_unspentAA = m_pp.aapoints;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//figure out how many AA points we get from the exp were setting
m_pp.aapoints = set_aaxp / max_AAXP;
2019-09-01 23:54:24 -05:00
LogDebug("Calculating additional AA Points from AAXP for [{}]: [{}] / [{}] = [{}] points", this->GetCleanName(), set_aaxp, max_AAXP, (float)set_aaxp / (float)max_AAXP);
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//get remainder exp points, set in PP below
set_aaxp = set_aaxp - (max_AAXP * m_pp.aapoints);
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//add in how many points we had
m_pp.aapoints += last_unspentAA;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//figure out how many points were actually gained
/*uint32 gained = m_pp.aapoints - last_unspentAA;*/ //unused
2013-05-06 13:07:41 -04:00
2019-08-11 00:00:55 -05:00
//Message(Chat::Yellow, "You have gained %d skill points!!", m_pp.aapoints - last_unspentAA);
2013-02-16 16:14:39 -08:00
char val1[20]={0};
2019-08-11 00:14:02 -05:00
MessageString(Chat::Experience, GAIN_ABILITY_POINT, ConvertArray(m_pp.aapoints, val1),m_pp.aapoints == 1 ? "" : "(s)"); //You have gained an ability point! You now have %1 ability point%2.
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
/* QS: PlayerLogAARate */
if (RuleB(QueryServ, PlayerLogAARate)){
int add_points = (m_pp.aapoints - last_unspentAA);
std::string query = StringFormat("INSERT INTO `qs_player_aa_rate_hourly` (char_id, aa_count, hour_time) VALUES (%i, %i, UNIX_TIMESTAMP() - MOD(UNIX_TIMESTAMP(), 3600)) ON DUPLICATE KEY UPDATE `aa_count` = `aa_count` + %i", this->CharacterID(), add_points, add_points);
QServ->SendQuery(query.c_str());
}
2019-08-11 00:00:55 -05:00
//Message(Chat::Yellow, "You now have %d skill points available to spend.", m_pp.aapoints);
2013-02-16 16:14:39 -08:00
}
uint8 maxlevel = RuleI(Character, MaxExpLevel) + 1;
if(maxlevel <= 1)
maxlevel = RuleI(Character, MaxLevel) + 1;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if(check_level > maxlevel) {
check_level = maxlevel;
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
if(RuleB(Character, KeepLevelOverMax)) {
set_exp = GetEXPForLevel(GetLevel()+1);
}
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
else {
set_exp = GetEXPForLevel(maxlevel);
}
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
if (GetClientMaxLevel() > 0) {
int client_max_level = GetClientMaxLevel();
if (GetLevel() >= client_max_level) {
uint32 expneeded = GetEXPForLevel(client_max_level);
if(set_exp > expneeded) {
set_exp = expneeded;
}
}
}
2013-02-16 16:14:39 -08:00
if ((GetLevel() != check_level) && !(check_level >= maxlevel)) {
char val1[20]={0};
if (level_increase)
{
if (level_count == 1)
2019-08-11 00:14:02 -05:00
MessageString(Chat::Experience, GAIN_LEVEL, ConvertArray(check_level, val1));
else
2019-08-11 00:00:55 -05:00
Message(Chat::Yellow, "Welcome to level %i!", check_level);
if (check_level == RuleI(Character, DeathItemLossLevel))
2019-08-11 00:14:02 -05:00
MessageString(Chat::Yellow, CORPSE_ITEM_LOST);
if (check_level == RuleI(Character, DeathExpLossLevel))
2019-08-11 00:14:02 -05:00
MessageString(Chat::Yellow, CORPSE_EXP_LOST);
2013-02-16 16:14:39 -08:00
}
else
2019-08-11 00:14:02 -05:00
MessageString(Chat::Experience, LOSE_LEVEL, ConvertArray(check_level, val1));
#ifdef BOTS
uint8 myoldlevel = GetLevel();
#endif
2013-02-16 16:14:39 -08:00
SetLevel(check_level);
#ifdef BOTS
if(RuleB(Bots, BotLevelsWithOwner))
// hack way of doing this..but, least invasive... (same criteria as gain level for sendlvlapp)
Bot::LevelBotWithClient(this, GetLevel(), (myoldlevel==check_level-1));
#endif
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//If were at max level then stop gaining experience if we make it to the cap
if(GetLevel() == maxlevel - 1){
uint32 expneeded = GetEXPForLevel(maxlevel);
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
if(set_exp > expneeded) {
2013-05-09 10:44:08 -04:00
set_exp = expneeded;
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
}
2013-02-16 16:14:39 -08:00
//set the client's EXP and AAEXP
m_pp.exp = set_exp;
m_pp.expAA = set_aaxp;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if (GetLevel() < 51) {
m_epp.perAA = 0; // turn off aa exp if they drop below 51
} else
SendAlternateAdvancementStats(); //otherwise, send them an AA update
2013-02-16 16:14:39 -08:00
//send the expdata in any case so the xp bar isnt stuck after leveling
uint32 tmpxp1 = GetEXPForLevel(GetLevel()+1);
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
// Quag: crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
2016-05-25 16:10:28 -04:00
auto outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
2013-02-16 16:14:39 -08:00
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
float tmpxp = (float) ( (float) set_exp-tmpxp2 ) / ( (float) tmpxp1-tmpxp2 );
eu->exp = (uint32)(330.0f * tmpxp);
FastQueuePacket(&outapp);
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if (admin>=100 && GetGM()) {
char val1[20]={0};
char val2[20]={0};
char val3[20]={0};
2019-08-11 00:14:02 -05:00
MessageString(Chat::Experience, GM_GAINXP, ConvertArray(set_aaxp,val1),ConvertArray(set_exp,val2),ConvertArray(GetEXPForLevel(GetLevel()+1),val3)); //[GM] You have gained %1 AXP and %2 EXP (%3).
2013-02-16 16:14:39 -08:00
}
}
void Client::SetLevel(uint8 set_level, bool command)
{
2013-05-09 10:44:08 -04:00
if (GetEXPForLevel(set_level) == 0xFFFFFFFF) {
2019-09-01 22:05:44 -05:00
LogError("Client::SetLevel() GetEXPForLevel([{}]) = 0xFFFFFFFF", set_level);
2013-05-09 10:44:08 -04:00
return;
}
2016-05-25 16:10:28 -04:00
auto outapp = new EQApplicationPacket(OP_LevelUpdate, sizeof(LevelUpdate_Struct));
2013-05-09 10:44:08 -04:00
LevelUpdate_Struct* lu = (LevelUpdate_Struct*)outapp->pBuffer;
lu->level = set_level;
if(m_pp.level2 != 0)
lu->level_old = m_pp.level2;
else
lu->level_old = level;
level = set_level;
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
if(IsRaidGrouped()) {
2013-05-09 10:44:08 -04:00
Raid *r = this->GetRaid();
if(r){
r->UpdateLevel(GetName(), set_level);
}
}
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
if(set_level > m_pp.level2) {
2013-05-09 10:44:08 -04:00
if(m_pp.level2 == 0)
m_pp.points += 5;
else
m_pp.points += (5 * (set_level - m_pp.level2));
m_pp.level2 = set_level;
}
if(set_level > m_pp.level) {
parse->EventPlayer(EVENT_LEVEL_UP, this, "", 0);
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
/* QS: PlayerLogLevels */
if (RuleB(QueryServ, PlayerLogLevels)){
std::string event_desc = StringFormat("Leveled UP :: to Level:%i from Level:%i in zoneid:%i instid:%i", set_level, m_pp.level, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Levels, this->CharacterID(), event_desc);
}
}
else if (set_level < m_pp.level){
/* QS: PlayerLogLevels */
if (RuleB(QueryServ, PlayerLogLevels)){
std::string event_desc = StringFormat("Leveled DOWN :: to Level:%i from Level:%i in zoneid:%i instid:%i", set_level, m_pp.level, this->GetZoneID(), this->GetInstanceID());
QServ->PlayerLogEvent(Player_Log_Levels, this->CharacterID(), event_desc);
}
2013-05-09 10:44:08 -04:00
}
m_pp.level = set_level;
if (command){
m_pp.exp = GetEXPForLevel(set_level);
2019-08-11 00:00:55 -05:00
Message(Chat::Yellow, "Welcome to level %i!", set_level);
2013-05-09 10:44:08 -04:00
lu->exp = 0;
}
else {
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
float tmpxp = (float) ( (float) m_pp.exp - GetEXPForLevel( GetLevel() )) / ( (float) GetEXPForLevel(GetLevel()+1) - GetEXPForLevel(GetLevel()));
2013-05-09 10:44:08 -04:00
lu->exp = (uint32)(330.0f * tmpxp);
}
QueuePacket(outapp);
safe_delete(outapp);
this->SendAppearancePacket(AT_WhoLevel, set_level); // who level change
2013-02-16 16:14:39 -08:00
2019-09-02 02:18:54 -05:00
LogInfo("Setting Level for [{}] to [{}]", GetName(), set_level);
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
CalcBonuses();
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
if(!RuleB(Character, HealOnLevel)) {
2013-05-09 10:44:08 -04:00
int mhp = CalcMaxHP();
if(GetHP() > mhp)
SetHP(mhp);
}
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
else {
2013-05-09 10:44:08 -04:00
SetHP(CalcMaxHP()); // Why not, lets give them a free heal
}
2013-05-06 13:07:41 -04:00
2018-02-26 09:33:15 -08:00
if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true);
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
DoTributeUpdate();
2013-05-09 10:44:08 -04:00
SendHPUpdate();
SetMana(CalcMaxMana());
UpdateWho();
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
UpdateMercLevel();
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
2013-05-09 10:44:08 -04:00
Save();
2013-02-16 16:14:39 -08:00
}
// Note: The client calculates exp separately, we cant change this function
// Add: You can set the values you want now, client will be always sync :) - Merkur
uint32 Client::GetEXPForLevel(uint16 check_level)
{
#ifdef LUA_EQEMU
uint32 lua_ret = 0;
bool ignoreDefault = false;
lua_ret = LuaParser::Instance()->GetEXPForLevel(this, check_level, ignoreDefault);
if (ignoreDefault) {
return lua_ret;
}
#endif
2013-02-16 16:14:39 -08:00
uint16 check_levelm1 = check_level-1;
float mod;
if (check_level < 31)
mod = 1.0;
else if (check_level < 36)
mod = 1.1;
else if (check_level < 41)
mod = 1.2;
else if (check_level < 46)
mod = 1.3;
else if (check_level < 52)
mod = 1.4;
else if (check_level < 53)
mod = 1.5;
else if (check_level < 54)
mod = 1.6;
else if (check_level < 55)
mod = 1.7;
else if (check_level < 56)
mod = 1.9;
else if (check_level < 57)
mod = 2.1;
else if (check_level < 58)
mod = 2.3;
else if (check_level < 59)
mod = 2.5;
else if (check_level < 60)
mod = 2.7;
else if (check_level < 61)
mod = 3.0;
else
mod = 3.1;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
float base = (check_levelm1)*(check_levelm1)*(check_levelm1);
mod *= 1000;
2013-05-06 13:07:41 -04:00
2013-06-01 10:49:58 -05:00
uint32 finalxp = uint32(base * mod);
if(RuleB(Character,UseOldRaceExpPenalties))
{
float racemod = 1.0;
if(GetBaseRace() == TROLL || GetBaseRace() == IKSAR) {
racemod = 1.2;
} else if(GetBaseRace() == OGRE) {
racemod = 1.15;
} else if(GetBaseRace() == BARBARIAN) {
racemod = 1.05;
} else if(GetBaseRace() == HALFLING) {
racemod = 0.95;
}
finalxp = uint32(finalxp * racemod);
}
if(RuleB(Character,UseOldClassExpPenalties))
{
float classmod = 1.0;
if(GetClass() == PALADIN || GetClass() == SHADOWKNIGHT || GetClass() == RANGER || GetClass() == BARD) {
classmod = 1.4;
} else if(GetClass() == MONK) {
classmod = 1.2;
} else if(GetClass() == WIZARD || GetClass() == ENCHANTER || GetClass() == MAGICIAN || GetClass() == NECROMANCER) {
classmod = 1.1;
} else if(GetClass() == ROGUE) {
classmod = 0.91;
} else if(GetClass() == WARRIOR) {
classmod = 0.9;
}
finalxp = uint32(finalxp * classmod);
}
2013-05-22 07:19:09 -05:00
finalxp = mod_client_xp_for_level(finalxp, check_level);
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
return finalxp;
2013-02-16 16:14:39 -08:00
}
void Client::AddLevelBasedExp(uint8 exp_percentage, uint8 max_level, bool ignore_mods)
{
uint32 award;
uint32 xp_for_level;
if (exp_percentage > 100)
{
exp_percentage = 100;
}
if (!max_level || GetLevel() < max_level)
{
max_level = GetLevel();
}
xp_for_level = GetEXPForLevel(max_level + 1) - GetEXPForLevel(max_level);
award = xp_for_level * exp_percentage / 100;
if(RuleB(Zone, LevelBasedEXPMods) && !ignore_mods)
{
if(zone->level_exp_mod[GetLevel()].ExpMod)
{
award *= zone->level_exp_mod[GetLevel()].ExpMod;
}
}
uint32 newexp = GetEXP() + award;
2013-02-16 16:14:39 -08:00
SetEXP(newexp, GetAAXP());
}
void Group::SplitExp(uint32 exp, Mob* other) {
if( other->CastToNPC()->MerchantType != 0 ) // Ensure NPC isn't a merchant
2013-05-09 10:44:08 -04:00
return;
2013-02-16 16:14:39 -08:00
if(other->GetOwner() && other->GetOwner()->IsClient()) // Ensure owner isn't pc
return;
2013-05-06 13:07:41 -04:00
unsigned int i;
uint32 groupexp = exp;
uint8 membercount = 0;
2013-02-16 16:14:39 -08:00
uint8 maxlevel = 1;
2013-05-06 13:07:41 -04:00
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (members[i] != nullptr) {
if(members[i]->GetLevel() > maxlevel)
maxlevel = members[i]->GetLevel();
2013-02-16 16:14:39 -08:00
membercount++;
2013-05-06 13:07:41 -04:00
}
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
float groupmod;
if (membercount > 1 && membercount < 6)
2013-11-12 16:08:31 -08:00
groupmod = 1 + .2*(membercount - 1); //2members=1.2exp, 3=1.4, 4=1.6, 5=1.8
2013-02-16 16:14:39 -08:00
else if (membercount == 6)
groupmod = 2.16;
else
groupmod = 1.0;
if(membercount > 1 && membercount <= 6)
Haynar's movement fixes. Changes Speed from float to int. EQ client deals with int step locs better than it does floats according to Haynar's testing. This also contains mob runspeed changes. I recommend you set runspeeds to start in the DB 1.25 for NPCs below 1.25 which will match player runspeeds almost equally. Existing DBs will need to be updated. General Cleanup of MobAI functions. Mobs now change their heading on AIMovement timers if their targets' heading has changed since that time. This prevents players from being able to land backstabs inbetween mob swings. Charmed/feared players now send the appropriate packet, there was a missing CastToClient() in spells that was missing. Mob runspeed can no longer be snared to 0%, instead, 1% of their base runspeed is the maximum. Roots apply as roots instead of a modifier under this code. There is going to be bugs with this code. It's better we push through it than revert it. Sanctuary has been running this for a good week and we've worked through the issues. Misc updates: Exported some variables to perl, including: EVENT_ITE_CLICK_CAST: EVENT_ITEM_CLICK: spell_id - returns the spell_id of the click effect. return value - cancels the cast. EVENT_DROP_ITEM: quantity - returns the # of items dropped in the packet. If the item has charges, charges are returned here instead. itemname - name of the item being dropped itemid - id of the item being droppped spell_id - spell_id associated with the item's click effect. slotid - the inventory slot id of the item being dropped. return value - cancels the item from being dropped. Added Perl function: CalcEXP. Calculates the experience you would gain for an NPC that cons a specific con value to you. Fixed a bug where you would receive the group experience bonus and group experience messages for simply being in a group, regardless of the player being in the same zone as you.
2015-05-25 12:35:53 -04:00
groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier)));
2013-02-16 16:14:39 -08:00
int conlevel = Mob::GetLevelCon(maxlevel, other->GetLevel());
if(conlevel == CON_GRAY)
2013-02-16 16:14:39 -08:00
return; //no exp for greenies...
2013-05-06 13:07:41 -04:00
if (membercount == 0)
return;
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
2013-05-04 18:06:58 -07:00
if (members[i] != nullptr && members[i]->IsClient()) // If Group Member is Client
2013-02-16 16:14:39 -08:00
{
Client *cmember = members[i]->CastToClient();
2013-05-06 13:07:41 -04:00
// add exp + exp cap
2013-02-16 16:14:39 -08:00
int16 diff = cmember->GetLevel() - maxlevel;
int16 maxdiff = -(cmember->GetLevel()*15/10 - cmember->GetLevel());
if(maxdiff > -5)
maxdiff = -5;
2013-05-06 13:07:41 -04:00
if (diff >= (maxdiff)) { /*Instead of person who killed the mob, the person who has the highest level in the group*/
2013-02-16 16:14:39 -08:00
uint32 tmp = (cmember->GetLevel()+3) * (cmember->GetLevel()+3) * 75 * 35 / 10;
uint32 tmp2 = groupexp / membercount;
2013-05-06 13:07:41 -04:00
cmember->AddEXP( tmp < tmp2 ? tmp : tmp2, conlevel );
}
}
2013-02-16 16:14:39 -08:00
}
}
void Raid::SplitExp(uint32 exp, Mob* other) {
if( other->CastToNPC()->MerchantType != 0 ) // Ensure NPC isn't a merchant
return;
if(other->GetOwner() && other->GetOwner()->IsClient()) // Ensure owner isn't pc
return;
2013-05-06 13:07:41 -04:00
uint32 groupexp = exp;
uint8 membercount = 0;
2013-02-16 16:14:39 -08:00
uint8 maxlevel = 1;
2013-05-06 13:07:41 -04:00
for (int i = 0; i < MAX_RAID_MEMBERS; i++) {
if (members[i].member != nullptr) {
if(members[i].member->GetLevel() > maxlevel)
maxlevel = members[i].member->GetLevel();
2013-02-16 16:14:39 -08:00
2013-05-06 13:07:41 -04:00
membercount++;
}
2013-02-16 16:14:39 -08:00
}
groupexp = (uint32)((float)groupexp * (1.0f-(RuleR(Character, RaidExpMultiplier))));
int conlevel = Mob::GetLevelCon(maxlevel, other->GetLevel());
if(conlevel == CON_GRAY)
2013-02-16 16:14:39 -08:00
return; //no exp for greenies...
2013-05-06 13:07:41 -04:00
if (membercount == 0)
return;
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
for (unsigned int x = 0; x < MAX_RAID_MEMBERS; x++) {
2013-05-04 18:06:58 -07:00
if (members[x].member != nullptr) // If Group Member is Client
2013-02-16 16:14:39 -08:00
{
Client *cmember = members[x].member;
2013-05-06 13:07:41 -04:00
// add exp + exp cap
2013-02-16 16:14:39 -08:00
int16 diff = cmember->GetLevel() - maxlevel;
int16 maxdiff = -(cmember->GetLevel()*15/10 - cmember->GetLevel());
if(maxdiff > -5)
maxdiff = -5;
2013-05-06 13:07:41 -04:00
if (diff >= (maxdiff)) { /*Instead of person who killed the mob, the person who has the highest level in the group*/
2013-02-16 16:14:39 -08:00
uint32 tmp = (cmember->GetLevel()+3) * (cmember->GetLevel()+3) * 75 * 35 / 10;
uint32 tmp2 = (groupexp / membercount) + 1;
2013-05-06 13:07:41 -04:00
cmember->AddEXP( tmp < tmp2 ? tmp : tmp2, conlevel );
}
}
2013-02-16 16:14:39 -08:00
}
}
void Client::SetLeadershipEXP(uint32 group_exp, uint32 raid_exp) {
while(group_exp >= GROUP_EXP_PER_POINT) {
group_exp -= GROUP_EXP_PER_POINT;
m_pp.group_leadership_points++;
2019-08-11 00:14:02 -05:00
MessageString(Chat::LeaderShip, GAIN_GROUP_LEADERSHIP_POINT);
2013-02-16 16:14:39 -08:00
}
while(raid_exp >= RAID_EXP_PER_POINT) {
raid_exp -= RAID_EXP_PER_POINT;
m_pp.raid_leadership_points++;
2019-08-11 00:14:02 -05:00
MessageString(Chat::LeaderShip, GAIN_RAID_LEADERSHIP_POINT);
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
m_pp.group_leadership_exp = group_exp;
m_pp.raid_leadership_exp = raid_exp;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
SendLeadershipEXPUpdate();
}
void Client::AddLeadershipEXP(uint32 group_exp, uint32 raid_exp) {
SetLeadershipEXP(GetGroupEXP() + group_exp, GetRaidEXP() + raid_exp);
}
void Client::SendLeadershipEXPUpdate() {
2016-05-25 16:10:28 -04:00
auto outapp = new EQApplicationPacket(OP_LeadershipExpUpdate, sizeof(LeadershipExpUpdate_Struct));
2013-02-16 16:14:39 -08:00
LeadershipExpUpdate_Struct* eu = (LeadershipExpUpdate_Struct *) outapp->pBuffer;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
eu->group_leadership_exp = m_pp.group_leadership_exp;
eu->group_leadership_points = m_pp.group_leadership_points;
eu->raid_leadership_exp = m_pp.raid_leadership_exp;
eu->raid_leadership_points = m_pp.raid_leadership_points;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
FastQueuePacket(&outapp);
}
uint32 Client::GetCharMaxLevelFromQGlobal() {
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
QGlobalCache *char_c = nullptr;
char_c = this->GetQGlobals();
2013-02-16 16:14:39 -08:00
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
std::list<QGlobal> globalMap;
uint32 ntype = 0;
2013-02-16 16:14:39 -08:00
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
if(char_c) {
QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, this->CharacterID(), zone->GetZoneID());
}
2013-02-16 16:14:39 -08:00
2016-05-25 16:10:28 -04:00
auto iter = globalMap.begin();
Changed zone process window title format, example: 'crushbone :: clients: 6 inst_id: 1 inst_ver: 0 :: port: 7015' Most of the following changes are QueryServ related, fully implemented its original functionality to be able to offload intensive or metric based logging to a remote server process that could exist on another server entirely Implemented Player Event Logging Types (Go to table `qs_player_events`): 1 = Player_Log_Quest, 2 = Player_Log_Zoning, 3 = Player_Log_Deaths, 4 = Player_Log_Connect_State, 5 = Player_Log_Levels, 6 = Player_Log_Keyring_Addition, 7 = Player_Log_QGlobal_Update, 8 = Player_Log_Task_Updates, 9 = Player_Log_AA_Purchases, 10 = Player_Log_Trade_Skill_Events, 11 = Player_Log_Issued_Commands, 12 = Player_Log_Money_Transactions, 13 = Player_Log_Alternate_Currency_Transactions, - All QueryServ logging will be implemented with a front end in EoC 2.0 very soon Changed all QS Error related logging to 'QUERYSERV__ERROR' (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Added MySQL Tables: - `qs_player_aa_rate_hourly` - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: - utils\sql\git\queryserv\required\Complete_QueryServ_Table_Structures.sql Added rules for each logging type, source rules here with them enabled by default: - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Spawn related logging cleanup General code cleanup Added queryserv.cpp and queryserv.h with QueryServ class
2014-08-23 23:59:20 -05:00
uint32 gcount = 0;
while(iter != globalMap.end()) {
if((*iter).name.compare("CharMaxLevel") == 0){
return atoi((*iter).value.c_str());
}
++iter;
++gcount;
}
2013-02-16 16:14:39 -08:00
return 0;
}
2019-09-01 22:05:44 -05:00
uint32 Client::GetCharMaxLevelFromBucket()
{
uint32 char_id = this->CharacterID();
std::string query = StringFormat("SELECT value FROM data_buckets WHERE `key` = '%i-CharMaxLevel'", char_id);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
2019-09-01 22:05:44 -05:00
LogError("Data bucket for CharMaxLevel for char ID [{}] failed", char_id);
return 0;
}
if (results.RowCount() > 0) {
auto row = results.begin();
return atoi(row[0]);
}
return 0;
}
uint32 Client::GetRequiredAAExperience() {
#ifdef LUA_EQEMU
uint32 lua_ret = 0;
bool ignoreDefault = false;
lua_ret = LuaParser::Instance()->GetRequiredAAExperience(this, ignoreDefault);
if (ignoreDefault) {
return lua_ret;
}
#endif
return RuleI(AA, ExpPerPoint);
}