Compare commits

..

20 Commits

Author SHA1 Message Date
Alex King 6130e10831 [Release] 22.56.2 (#4480) 2024-09-19 21:59:53 -05:00
Alex King c3e1c531d2 [Bug Fix] Fix Issue with Database::ReserveName (#4477) 2024-09-19 21:15:14 -05:00
Alex King b52719a535 [Quest API] Add GrantAllAAPoints() Overload To Perl/Lua (#4474) 2024-09-19 21:09:24 -05:00
Alex King 1af252466f [Bug Fix] Fix Untrained Disciplines in Client::SaveDisciplines() (#4472)
* [Bug Fix] Fix Untrained Disciplines in Client::SaveDisciplines()

* [Bug Fix] Fix Infinite Loop in Adventure::Finished() (#4473)

Fix infinite loop condition when bot encountered

* [Bug Fix] Fix Untrained Disciplines in Client::SaveDisciplines()

* Change to release

---------

Co-authored-by: oddx2k <103136558+oddx2k@users.noreply.github.com>
2024-09-19 21:09:09 -05:00
catapultam-habeo 699d22fc28 [Bug Fix] Fix 'Teleport Doors' from being blocked by GM flag (#4475)
* gm flag blocks teleport doors with keys from working instead of allowing them to work

* correct coniditional logic
2024-09-18 17:18:07 -04:00
Mitch Freeman 5d1fe68906 [Bug Fix] Parcel purchase of bazaar items with unlimited charges (#4479)
Fix for unlimited charges in bazaar
2024-09-18 09:36:00 -04:00
oddx2k 52dcf35425 [Bug Fix] Fix Infinite Loop in Adventure::Finished() (#4473)
Fix infinite loop condition when bot encountered
2024-09-13 13:20:55 -04:00
Alex King a7550fbd9e [Release] 22.56.0 (#4471)
* [Release] 22.55.2

### Code

* Add IsCloseToBanker method ([#4462](https://github.com/EQEmu/Server/pull/4462)) @Akkadius 2024-08-27

### Feature

* Add Rule to Limit Task Update Messages ([#4459](https://github.com/EQEmu/Server/pull/4459)) @Kinglykrab 2024-08-28
* Allow NPCs to cast Sacrifice ([#4470](https://github.com/EQEmu/Server/pull/4470)) @fuzzlecutter 2024-09-12
* Lazy Load Bank Contents ([#4453](https://github.com/EQEmu/Server/pull/4453)) @catapultam-habeo 2024-08-27

### Fixes

* Add RULE_STRING to RuleManager::ResetRules ([#4467](https://github.com/EQEmu/Server/pull/4467)) @Kinglykrab 2024-09-07
* Fix Bard Effect in Migration 9237 ([#4468](https://github.com/EQEmu/Server/pull/4468)) @Kinglykrab 2024-09-09
* ModernAAScalingEnabled() Calculation Error ([#4469](https://github.com/EQEmu/Server/pull/4469)) @carolus21rex 2024-09-11

### Performance

* Move Discipline Loading to Client::CompleteConnect() ([#4466](https://github.com/EQEmu/Server/pull/4466)) @Kinglykrab 2024-09-09

### Rules

* Add a Bandolier Swap Delay Rule ([#4465](https://github.com/EQEmu/Server/pull/4465)) @Kinglykrab 2024-09-08

* 22.56.0
2024-09-12 20:39:48 -05:00
fuzzlecutter cc0171dfe1 [Feature] Allow NPCs to cast Sacrifice (#4470)
* [Feature] Teach npcs how to cast sacrifice

* [Feature] Teach npcs how to cast sacrifice

- Remove the hardcoded limit preventing npcs from casting sacrifice. The
  npc will receive as loot an emerald essence as expected.

* Update client.cpp
* Update client_packet.cpp
* Update spell_effects.cpp

* rename Client::SacrificeCaster to Client::sacrifice_caster_id
2024-09-12 15:42:44 -04:00
carolus21rex 913c5da70f [Bug Fix] ModernAAScalingEnabled() Calculation Error (#4469)
Current version only looks at your unspent AAs, meaning if you have 2000 spent AAs and 1 unspent AA, your scaling will be based on the 1 unspent AA instead of the 2001 total AA.

Here's the original log which is custom code found in the ModernAAScalingEnabled function:

[Wed Sep 11 14:10:19 2024] [AA] [ScaleAAXPBasedOnCurrentAATotal] AA Experience Calculation: add_aaxp = 660796, Base Bonus = 256.000000, Half-Life = 64.000000, Minimum Bonus = 1.000000, Earned AA = 1, Calculated Bonus = 253.242371

Custom code looks like this:

uint64 totalWithExpMod = add_aaxp;
	if (RuleB(AA, EnableLogrithmicClasslessAABonus)) {
		float base_bonus = RuleR(AA, InitialLogrithmicClasslessAABonus);
		float half_life = RuleR(AA, HalfLifeLogrithmicClasslessAABonus);
		float min_bon = RuleR(AA, MinimumLogrithmicClasslessAABonus);
		float bonus_expon = earnedAA / half_life;

		float bonus = base_bonus * std::pow(0.5, bonus_expon);
		Log(Logs::General,
			Logs::AA,
			"AA Experience Calculation: add_aaxp = %d, Base Bonus = %f, Half-Life = %f, Minimum Bonus = %f, Earned AA = %d, Calculated Bonus = %f",
			add_aaxp, base_bonus, half_life, min_bon, earnedAA, bonus);

		if (bonus < min_bon) bonus = min_bon;

		totalWithExpMod = (uint64)(totalWithExpMod * bonus);
	}

After the fix, the log becomes:

[Wed Sep 11 14:10:19 2024] [AA] [ScaleAAXPBasedOnCurrentAATotal] AA Experience Calculation: add_aaxp = 660796, Base Bonus = 256.000000, Half-Life = 64.000000, Minimum Bonus = 1.000000, Earned AA = 1, Calculated Bonus = 253.242371

Which is much closer to the expected behavior
2024-09-11 17:06:48 -04:00
Alex King 40fecbfaf5 [Performance] Move Discipline Loading to Client::CompleteConnect() (#4466)
* [Performance] Move Character Discipline Loading

* Push

* Final
2024-09-09 18:20:12 -05:00
Alex King b1646381b0 [Bug Fix] Fix Bard Effect in Migration 9237 (#4468) 2024-09-09 18:02:58 -05:00
Alex King bb1578796b [Rule] Add a Bandolier Swap Delay Rule (#4465)
* [Rule] Add a Bandolier Swap Delay Rule

* Push

* Update exp.cpp
2024-09-07 22:05:44 -05:00
Alex King 0e5a38f072 [Bug Fix] Add RULE_STRING to RuleManager::ResetRules (#4467)
* [Bug Fix] Add RULE_STRING to RuleManager::ResetRules

* Update rulesys.cpp
2024-09-07 18:29:46 -05:00
Alex King 39876ab858 [Feature] Add Rule to Limit Task Update Messages (#4459)
* [Feature] Add Rule to Limit Task Update Messages

* Update task_client_state.cpp

* Update task_client_state.cpp

* Change rule
2024-08-27 21:49:07 -04:00
catapultam-habeo ff16a76481 [Feature] Lazy Load Bank Contents (#4453)
* initial work porting this to upstream

* more

* track complete connect

* it sucks to suck

* Few optimizations

* Move sent_inventory init

* Move var

* Adjustments

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-08-27 13:21:55 -05:00
Akkadius ffd68eb63d [Release] 22.55.1 2024-08-27 08:17:20 -05:00
Akkadius 76c1da1aad [Release] 22.55.1 2024-08-27 08:09:13 -05:00
Chris Miles a91e03fa43 [Code] Add IsCloseToBanker method (#4462)
* [Code] Add IsCloseToBanker method

* Update mob.cpp
2024-08-26 22:59:06 -05:00
Chris Miles 453106439f [Release] 22.55.0 (#4464) 2024-08-26 22:03:37 -05:00
28 changed files with 337 additions and 91 deletions
+85
View File
@@ -1,3 +1,88 @@
## [22.56.2] 9/20/2024
### Fixes
* Fix Issue with Database::ReserveName ([#4477](https://github.com/EQEmu/Server/pull/4477)) @Kinglykrab 2024-09-20
### Quest API
* Add GrantAllAAPoints() Overload To Perl/Lua ([#4474](https://github.com/EQEmu/Server/pull/4474)) @Kinglykrab 2024-09-20
## [22.56.1] 9/20/2024
### Fixes
* Fix Untrained Disciplines in Client::SaveDisciplines() ([#4472](https://github.com/EQEmu/Server/pull/4472)) @Kinglykrab 2024-09-13
* Fix Infinite Loop in Adventure::Finished() ([#4473](https://github.com/EQEmu/Server/pull/4473)) @oddx2k 2024-09-13
## [22.56.0] 9/12/2024
### Code
* Add IsCloseToBanker method ([#4462](https://github.com/EQEmu/Server/pull/4462)) @Akkadius 2024-08-27
### Feature
* Add Rule to Limit Task Update Messages ([#4459](https://github.com/EQEmu/Server/pull/4459)) @Kinglykrab 2024-08-28
* Allow NPCs to cast Sacrifice ([#4470](https://github.com/EQEmu/Server/pull/4470)) @fuzzlecutter 2024-09-12
* Lazy Load Bank Contents ([#4453](https://github.com/EQEmu/Server/pull/4453)) @catapultam-habeo 2024-08-27
### Fixes
* Add RULE_STRING to RuleManager::ResetRules ([#4467](https://github.com/EQEmu/Server/pull/4467)) @Kinglykrab 2024-09-07
* Fix Bard Effect in Migration 9237 ([#4468](https://github.com/EQEmu/Server/pull/4468)) @Kinglykrab 2024-09-09
* ModernAAScalingEnabled() Calculation Error ([#4469](https://github.com/EQEmu/Server/pull/4469)) @carolus21rex 2024-09-11
### Performance
* Move Discipline Loading to Client::CompleteConnect() ([#4466](https://github.com/EQEmu/Server/pull/4466)) @Kinglykrab 2024-09-09
### Rules
* Add a Bandolier Swap Delay Rule ([#4465](https://github.com/EQEmu/Server/pull/4465)) @Kinglykrab 2024-09-08
## [22.55.1] 8/26/2024
### Code
* Remove unused methods ([#4449](https://github.com/EQEmu/Server/pull/4449)) @Kinglykrab 2024-08-22
### Feature
* Add Character:DefaultGuildRank Rule ([#4438](https://github.com/EQEmu/Server/pull/4438)) @Kinglykrab 2024-08-04
* Add Optional Return to EVENT_DAMAGE_TAKEN ([#4454](https://github.com/EQEmu/Server/pull/4454)) @Kinglykrab 2024-08-27
* Extend Spell Buckets Functionality ([#4441](https://github.com/EQEmu/Server/pull/4441)) @Kinglykrab 2024-08-22
### Fixes
* Apply Race & Class restrictions to Auto-Combines ([#4452](https://github.com/EQEmu/Server/pull/4452)) @catapultam-habeo 2024-08-20
* Attune Augments when Equipped ([#4446](https://github.com/EQEmu/Server/pull/4446)) @fryguy503 2024-08-10
* Correct missed maxlevel reference in exp.cpp ([#4463](https://github.com/EQEmu/Server/pull/4463)) @N0ctrnl 2024-08-27
* Ensure close of Tribute Item search ([#4439](https://github.com/EQEmu/Server/pull/4439)) @joligario 2024-08-04
* Fix AddCrystals() in Perl/Lua ([#4445](https://github.com/EQEmu/Server/pull/4445)) @Kinglykrab 2024-08-10
* Fix Bot Spell Entries IDs Capping at 32,767 ([#4444](https://github.com/EQEmu/Server/pull/4444)) @Kinglykrab 2024-08-27
* Fix Character ID of 0 being inserted into character_stats_record ([#4458](https://github.com/EQEmu/Server/pull/4458)) @Kinglykrab 2024-08-22
* Fix Issue with Removed #setfaction Command ([#4448](https://github.com/EQEmu/Server/pull/4448)) @Kinglykrab 2024-08-11
* Fix Lua Client FilteredMessage ([#4437](https://github.com/EQEmu/Server/pull/4437)) @Kinglykrab 2024-07-31
* Fix client hotbar exchanging items when zoning ([#4460](https://github.com/EQEmu/Server/pull/4460)) @neckkola 2024-08-27
* Fix issue with killed mob coordinates ([#4457](https://github.com/EQEmu/Server/pull/4457)) @Kinglykrab 2024-08-22
* Imitate Death should also clear zone feign aggro ([#4436](https://github.com/EQEmu/Server/pull/4436)) @fryguy503 2024-07-31
* client_max_level allow leveling to end of level ([#4455](https://github.com/EQEmu/Server/pull/4455)) @fryguy503 2024-08-20
### Improvement
* Filtered Messages Extension ([#4435](https://github.com/EQEmu/Server/pull/4435)) @fryguy503 2024-07-31
### Quest API
* Add AreTasksCompleted() to Perl/Lua. ([#4456](https://github.com/EQEmu/Server/pull/4456)) @Kinglykrab 2024-08-23
* Add Area-Based Quest Methods to Perl/Lua ([#4447](https://github.com/EQEmu/Server/pull/4447)) @Kinglykrab 2024-08-27
* Add Several Door Methods to Perl/Lua ([#4451](https://github.com/EQEmu/Server/pull/4451)) @Kinglykrab 2024-08-16
### World
* Fix slow world bootup bug ([#4461](https://github.com/EQEmu/Server/pull/4461)) @Akkadius 2024-08-27
## [22.54.0] 7/30/2024
### Code
+23 -8
View File
@@ -285,16 +285,31 @@ bool Database::SetAccountStatus(const std::string& account_name, int16 status)
bool Database::ReserveName(uint32 account_id, const std::string& name)
{
const auto& l = CharacterDataRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}'",
Strings::Escape(name)
)
const std::string& where_filter = fmt::format(
"`name` = '{}'",
Strings::Escape(name)
);
if (!l.empty()) {
LogInfo("Account: [{}] tried to request name: [{}], but it is already taken", account_id, name);
if (RuleB(Bots, Enabled)) {
const auto& b = BotDataRepository::GetWhere(*this, where_filter);
if (!b.empty()) {
LogInfo("Account [{}] requested name [{}] but name is already taken by a bot", account_id, name);
return false;
}
}
const auto& c = CharacterDataRepository::GetWhere(*this, where_filter);
if (!c.empty()) {
LogInfo("Account [{}] requested name [{}] but name is already taken by a character", account_id, name);
return false;
}
const auto& n = NpcTypesRepository::GetWhere(*this, where_filter);
if (!n.empty()) {
LogInfo("Account [{}] requested name [{}] but name is already taken by an NPC", account_id, name);
return false;
}
+1 -1
View File
@@ -4947,7 +4947,7 @@ UPDATE `aa_ability` SET `auto_grant_enabled` = 1 WHERE `grant_only` = 0 AND `cha
.version = 9237,
.description = "2023_10_15_import_13th_floor.sql",
.check = "SHOW COLUMNS FROM `items` LIKE 'bardeffect';",
.condition = "contains",
.condition = "missing",
.match = "mediumint",
.sql = R"(
ALTER TABLE `items`
+2
View File
@@ -189,6 +189,8 @@ void RuleManager::ResetRules(bool reload) {
m_RuleRealValues[ Real__##rule_name ] = default_value;
#define RULE_BOOL(category_name, rule_name, default_value, notes) \
m_RuleBoolValues[ Bool__##rule_name ] = default_value;
#define RULE_STRING(category_name, rule_name, default_value, notes) \
m_RuleStringValues[ String__##rule_name ] = default_value;
#include "ruletypes.h"
// restore these rules to their pre-reset values
+3
View File
@@ -229,6 +229,7 @@ RULE_BOOL(Character, GroupInvitesRequireTarget, false, "Enable to require player
RULE_BOOL(Character, PlayerTradingLoreFeedback, true, "If enabled, during a player to player trade, if lore items exist, it will output which items.")
RULE_INT(Character, MendAlwaysSucceedValue, 199, "Value at which mend will always succeed its skill check. Default: 199")
RULE_BOOL(Character, SneakAlwaysSucceedOver100, false, "When sneak skill is over 100, always succeed sneak/hide. Default: false")
RULE_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0")
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
@@ -715,6 +716,7 @@ RULE_BOOL(TaskSystem, ExpRewardsIgnoreLevelBasedEXPMods, false, "Rewarding Level
RULE_INT(TaskSystem, SharedTasksWorldProcessRate, 6000, "Timer interval (milliseconds) that shared tasks are processed in world")
RULE_INT(TaskSystem, SharedTasksTerminateTimerMS, 120000, "Delay (milliseconds) until a shared task is terminated if requirements are no longer met after member removal (default: 2 minutes)")
RULE_BOOL(TaskSystem, UpdateOneElementPerTask, true, "If true (live-like) task updates only increment the first matching activity. If false all matching elements will be incremented.")
RULE_INT(TaskSystem, MaxUpdateMessages, 50, "Maximum update messages for non-GiveCash activity types in IncrementDoneCount")
RULE_CATEGORY_END()
RULE_CATEGORY(Range)
@@ -909,6 +911,7 @@ RULE_BOOL(Inventory, AllowAnyWeaponTransformation, false, "Weapons can use any w
RULE_BOOL(Inventory, TransformSummonedBags, false, "Transforms summoned bags into disenchanted ones instead of deleting")
RULE_BOOL(Inventory, AllowMultipleOfSameAugment, false, "Allows multiple of the same augment to be placed in an item via #augmentitem or MQ2, set to true to allow")
RULE_INT(Inventory, AlternateAugmentationSealer, 53, "Allows RoF+ clients to augment items from a special container type")
RULE_BOOL(Inventory, LazyLoadBank, true, "Don't load bank during zoning, only when in proximinity to a banker. May increase zone speed and stability")
RULE_CATEGORY_END()
RULE_CATEGORY(Client)
+2 -2
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.54.0-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.56.2-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
@@ -42,7 +42,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9282
#define CURRENT_BINARY_DATABASE_VERSION 9283
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
#endif
-1
View File
@@ -221,7 +221,6 @@ void Client::Handle_Login(const char *data, unsigned int size)
ParseAccountString(user, user, db_loginserver);
if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id)) {
result = VerifyLoginHash(user, db_loginserver, cred, db_account_password_hash);
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.54.0",
"version": "22.56.2",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
+1
View File
@@ -287,6 +287,7 @@ void Adventure::Finished(AdventureWinStatus ws)
auto character_id = database.GetCharacterID(*iter);
if (character_id == 0) {
++iter;
continue;
}
+5 -1
View File
@@ -2185,7 +2185,7 @@ void Client::AutoGrantAAPoints() {
SendAlternateAdvancementStats();
}
void Client::GrantAllAAPoints(uint8 unlock_level)
void Client::GrantAllAAPoints(uint8 unlock_level, bool skip_grant_only)
{
//iterate through every AA
for (auto& aa : zone->aa_abilities) {
@@ -2195,6 +2195,10 @@ void Client::GrantAllAAPoints(uint8 unlock_level)
continue;
}
if (ability->grant_only && skip_grant_only) {
continue;
}
const uint8 level = unlock_level ? unlock_level : GetLevel();
AA::Rank* rank = ability->first;
+51 -9
View File
@@ -185,7 +185,9 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
position_update_timer(10000),
consent_throttle_timer(2000),
tmSitting(0),
parcel_timer(RuleI(Parcel, ParcelDeliveryDelay))
parcel_timer(RuleI(Parcel, ParcelDeliveryDelay)),
lazy_load_bank_check_timer(1000),
bandolier_throttle_timer(0)
{
for (auto client_filter = FilterNone; client_filter < _FilterCount; client_filter = eqFilterType(client_filter + 1)) {
SetFilter(client_filter, FilterShow);
@@ -284,6 +286,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
memset(&m_epp, 0, sizeof(m_epp));
PendingTranslocate = false;
PendingSacrifice = false;
sacrifice_caster_id = 0;
controlling_boat_id = 0;
controlled_mob_id = 0;
qGlobals = nullptr;
@@ -391,7 +394,6 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
SetBotPrecombat(false);
AI_Init();
}
Client::~Client() {
@@ -3970,7 +3972,7 @@ void Client::SetEndurance(int32 newEnd)
CheckManaEndUpdate();
}
void Client::SacrificeConfirm(Client *caster)
void Client::SacrificeConfirm(Mob *caster)
{
auto outapp = new EQApplicationPacket(OP_Sacrifice, sizeof(Sacrifice_Struct));
Sacrifice_Struct *ss = (Sacrifice_Struct *)outapp->pBuffer;
@@ -3997,14 +3999,14 @@ void Client::SacrificeConfirm(Client *caster)
ss->Confirm = 0;
QueuePacket(outapp);
safe_delete(outapp);
// We store the Caster's name, because when the packet comes back, it only has the victim's entityID in it,
// We store the Caster's id, because when the packet comes back, it only has the victim's entityID in it,
// not the caster.
SacrificeCaster += caster->GetName();
sacrifice_caster_id = caster->GetID();
PendingSacrifice = true;
}
//Essentially a special case death function
void Client::Sacrifice(Client *caster)
void Client::Sacrifice(Mob *caster)
{
if (GetLevel() >= RuleI(Spells, SacrificeMinLevel) && GetLevel() <= RuleI(Spells, SacrificeMaxLevel)) {
int exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000);
@@ -4052,8 +4054,11 @@ void Client::Sacrifice(Client *caster)
}
Save();
GoToDeath();
if (caster) // I guess it's possible?
caster->SummonItem(RuleI(Spells, SacrificeItemID));
if (caster && caster->IsClient()) {
caster->CastToClient()->SummonItem(RuleI(Spells, SacrificeItemID));
} else if (caster && caster->IsNPC()) {
caster->CastToNPC()->AddItem(RuleI(Spells, SacrificeItemID), 1, false);
}
}
} else {
caster->MessageString(Chat::Red, SAC_TOO_LOW); // This being is not a worthy sacrifice.
@@ -11092,7 +11097,9 @@ void Client::SaveDisciplines()
{
std::vector<CharacterDisciplinesRepository::CharacterDisciplines> v;
for (int slot_id = 0; slot_id < MAX_PP_DISCIPLINES; slot_id++) {
std::vector<std::string> delete_slots;
for (uint16 slot_id = 0; slot_id < MAX_PP_DISCIPLINES; slot_id++) {
if (IsValidSpell(m_pp.disciplines.values[slot_id])) {
auto e = CharacterDisciplinesRepository::NewEntity();
@@ -11101,9 +11108,21 @@ void Client::SaveDisciplines()
e.disc_id = m_pp.disciplines.values[slot_id];
v.emplace_back(e);
} else {
delete_slots.emplace_back(std::to_string(slot_id));
}
}
if (!delete_slots.empty()) {
CharacterDisciplinesRepository::DeleteWhere(
database,
fmt::format(
"`slot_id` IN ({})",
Strings::Join(delete_slots, ", ")
)
);
}
if (!v.empty()) {
CharacterDisciplinesRepository::ReplaceMany(database, v);
}
@@ -12706,3 +12725,26 @@ bool Client::TakeMoneyFromPPWithOverFlow(uint64 copper, bool update_client)
RecalcWeight();
return true;
}
void Client::SendTopLevelInventory()
{
EQ::ItemInstance* inst = nullptr;
static const int16 slots[][2] = {
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END }
};
const auto& inv = GetInv();
const size_t slot_index_count = sizeof(slots) / sizeof(slots[0]);
for (int slot_index = 0; slot_index < slot_index_count; ++slot_index) {
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
inst = inv.GetItem(slot_id);
if (inst) {
SendItemPacket(slot_id, inst, ItemPacketType::ItemPacketTrade);
}
}
}
}
+11 -5
View File
@@ -762,8 +762,8 @@ public:
void GetRaidAAs(RaidLeadershipAA_Struct *into) const;
void ClearGroupAAs();
void UpdateGroupAAs(int32 points, uint32 type);
void SacrificeConfirm(Client* caster);
void Sacrifice(Client* caster);
void SacrificeConfirm(Mob* caster);
void Sacrifice(Mob* caster);
void GoToDeath();
inline const int32 GetInstanceID() const { return zone->GetInstanceID(); }
void SetZoning(bool in) { bZoning = in; }
@@ -1025,7 +1025,7 @@ public:
int GetSpentAA() { return m_pp.aapoints_spent; }
uint32 GetRequiredAAExperience();
void AutoGrantAAPoints();
void GrantAllAAPoints(uint8 unlock_level = 0);
void GrantAllAAPoints(uint8 unlock_level = 0, bool skip_grant_only = false);
bool HasAlreadyPurchasedRank(AA::Rank* rank);
void ListPurchasedAAs(Client *to, std::string search_criteria = std::string());
@@ -1245,7 +1245,7 @@ public:
bool PendingTranslocate;
time_t TranslocateTime;
bool PendingSacrifice;
std::string SacrificeCaster;
uint16 sacrifice_caster_id;
PendingTranslocate_Struct PendingTranslocateData;
void SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID);
@@ -2012,6 +2012,8 @@ private:
void ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z, float heading, uint8 ignorerestrictions, ZoneMode zm);
void ProcessMovePC(uint32 zoneID, uint32 instance_id, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void SendTopLevelInventory();
glm::vec4 m_ZoneSummonLocation;
uint16 zonesummon_id;
uint8 zonesummon_ignorerestrictions;
@@ -2056,6 +2058,11 @@ private:
Timer task_request_timer;
Timer pick_lock_timer;
Timer parcel_timer; //Used to limit the number of parcels to one every 30 seconds (default). Changable via rule.
Timer lazy_load_bank_check_timer;
Timer bandolier_throttle_timer;
bool m_lazy_load_bank = false;
int m_lazy_load_sent_bank_slots = 0;
glm::vec3 m_Proximity;
glm::vec4 last_position_before_bulk_update;
@@ -2175,7 +2182,6 @@ private:
bool m_has_quest_compass = false;
std::vector<uint32_t> m_dynamic_zone_ids;
public:
enum BotOwnerOption : size_t {
booDeathMarquee,
+29 -19
View File
@@ -934,6 +934,7 @@ void Client::CompleteConnect()
}
database.LoadAuras(this); // this ends up spawning them so probably safer to load this later (here)
database.LoadCharacterDisciplines(this);
entity_list.RefreshClientXTargets(this);
@@ -1318,7 +1319,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
database.LoadCharacterInspectMessage(cid, &m_inspect_message); /* Load Character Inspect Message */
database.LoadCharacterSpellBook(cid, &m_pp); /* Load Character Spell Book */
database.LoadCharacterMemmedSpells(cid, &m_pp); /* Load Character Memorized Spells */
database.LoadCharacterDisciplines(cid, &m_pp); /* Load Character Disciplines */
database.LoadCharacterLanguages(cid, &m_pp); /* Load Character Languages */
database.LoadCharacterLeadershipAbilities(cid, &m_pp); /* Load Character Leadership AA's */
database.LoadCharacterTribute(this); /* Load CharacterTribute */
@@ -3642,29 +3642,39 @@ void Client::Handle_OP_AutoFire(const EQApplicationPacket *app)
void Client::Handle_OP_Bandolier(const EQApplicationPacket *app)
{
// Although there are three different structs for OP_Bandolier, they are all the same size.
//
if (app->size != sizeof(BandolierCreate_Struct)) {
LogDebug("Size mismatch in OP_Bandolier expected [{}] got [{}]", sizeof(BandolierCreate_Struct), app->size);
DumpPacket(app);
return;
}
BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer;
auto bs = (BandolierCreate_Struct*) app->pBuffer;
switch (bs->Action)
{
case bandolierCreate:
CreateBandolier(app);
break;
case bandolierRemove:
RemoveBandolier(app);
break;
case bandolierSet:
SetBandolier(app);
break;
default:
LogDebug("Unknown Bandolier action [{}]", bs->Action);
break;
switch (bs->Action) {
case bandolierCreate:
CreateBandolier(app);
break;
case bandolierRemove:
RemoveBandolier(app);
break;
case bandolierSet:
if (bandolier_throttle_timer.GetDuration() && !bandolier_throttle_timer.Check()) {
Message(
Chat::White,
fmt::format(
"You may only modify your bandolier once every {}.",
Strings::ToLower(Strings::MillisecondsToTime(RuleI(Character, BandolierSwapDelay)))
).c_str()
);
SendTopLevelInventory();
break;
}
SetBandolier(app);
break;
default:
LogDebug("Unknown Bandolier action [{}]", bs->Action);
break;
}
}
@@ -13671,11 +13681,11 @@ void Client::Handle_OP_Sacrifice(const EQApplicationPacket *app)
}
if (ss->Confirm) {
Client *Caster = entity_list.GetClientByName(SacrificeCaster.c_str());
Mob *Caster = entity_list.GetMob(sacrifice_caster_id);
if (Caster) Sacrifice(Caster);
}
PendingSacrifice = false;
SacrificeCaster.clear();
sacrifice_caster_id = 0;
}
void Client::Handle_OP_SafeFallSuccess(const EQApplicationPacket *app) // bit of a misnomer, sent whenever safe fall is used (success of fail)
+58 -25
View File
@@ -289,6 +289,37 @@ bool Client::Process() {
entity_list.ScanCloseMobs(close_mobs, this, IsMoving());
}
if (RuleB(Inventory, LazyLoadBank)) {
// poll once a second to see if we are close to a banker and we haven't loaded the bank yet
if (!m_lazy_load_bank && lazy_load_bank_check_timer.Check()) {
if (m_lazy_load_sent_bank_slots <= EQ::invslot::SHARED_BANK_END && IsCloseToBanker()) {
m_lazy_load_bank = true;
lazy_load_bank_check_timer.Disable();
}
}
if (m_lazy_load_bank && m_lazy_load_sent_bank_slots <= EQ::invslot::SHARED_BANK_END) {
const EQ::ItemInstance *inst = nullptr;
// Jump the gaps
if (m_lazy_load_sent_bank_slots < EQ::invslot::BANK_BEGIN) {
m_lazy_load_sent_bank_slots = EQ::invslot::BANK_BEGIN;
}
else if (m_lazy_load_sent_bank_slots > EQ::invslot::BANK_END &&
m_lazy_load_sent_bank_slots < EQ::invslot::SHARED_BANK_BEGIN) {
m_lazy_load_sent_bank_slots = EQ::invslot::SHARED_BANK_BEGIN;
}
else {
m_lazy_load_sent_bank_slots++;
}
inst = m_inv[m_lazy_load_sent_bank_slots];
if (inst) {
SendItemPacket(m_lazy_load_sent_bank_slots, inst, ItemPacketType::ItemPacketTrade);
}
}
}
bool may_use_attacks = false;
/*
Things which prevent us from attacking:
@@ -780,39 +811,41 @@ void Client::BulkSendInventoryItems()
last_pos = ob.tellp();
}
// Bank items
for (int16 slot_id = EQ::invslot::BANK_BEGIN; slot_id <= EQ::invslot::BANK_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst)
continue;
if (!RuleB(Inventory, LazyLoadBank)) {
// Bank items
for (int16 slot_id = EQ::invslot::BANK_BEGIN; slot_id <= EQ::invslot::BANK_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst)
continue;
inst->Serialize(ob, slot_id);
inst->Serialize(ob, slot_id);
if (ob.tellp() == last_pos)
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
if (ob.tellp() == last_pos)
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
last_pos = ob.tellp();
}
last_pos = ob.tellp();
}
// SharedBank items
for (int16 slot_id = EQ::invslot::SHARED_BANK_BEGIN; slot_id <= EQ::invslot::SHARED_BANK_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst)
continue;
// SharedBank items
for (int16 slot_id = EQ::invslot::SHARED_BANK_BEGIN; slot_id <= EQ::invslot::SHARED_BANK_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst)
continue;
inst->Serialize(ob, slot_id);
inst->Serialize(ob, slot_id);
if (ob.tellp() == last_pos)
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
if (ob.tellp() == last_pos)
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
last_pos = ob.tellp();
}
last_pos = ob.tellp();
}
}
auto outapp = new EQApplicationPacket(OP_CharInventory);
outapp->size = ob.size();
outapp->pBuffer = ob.detach();
QueuePacket(outapp);
safe_delete(outapp);
auto outapp = new EQApplicationPacket(OP_CharInventory);
outapp->size = ob.size();
outapp->pBuffer = ob.detach();
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
+2 -2
View File
@@ -542,8 +542,8 @@ void Doors::HandleClick(Client *sender, uint8 trigger)
if (EQ::ValueWithin(m_open_type, 57, 58) && HasDestinationZone()) {
bool has_key_required = (required_key_item && required_key_item == player_key);
if (sender->GetGM() && has_key_required) {
has_key_required = false;
if (sender->GetGM() && !has_key_required) {
has_key_required = true;
sender->Message(Chat::White, "Your GM flag allows you to open this door without a key.");
}
+1 -1
View File
@@ -527,7 +527,7 @@ void Client::AddEXP(ExpSource exp_source, uint64 in_add_exp, uint8 conlevel, boo
// Are we also doing linear AA acceleration?
if (RuleB(AA, ModernAAScalingEnabled) && aaexp > 0)
{
aaexp = ScaleAAXPBasedOnCurrentAATotal(GetAAPoints(), aaexp);
aaexp = ScaleAAXPBasedOnCurrentAATotal(GetSpentAA() + GetAAPoints(), aaexp);
}
// Check for AA XP Cap
+6 -4
View File
@@ -7,15 +7,16 @@ void command_grantaa(Client *c, const Seperator *sep)
return;
}
const uint8 unlock_level = sep->IsNumber(1) ? static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[1])) : 0;
const uint8 unlock_level = sep->IsNumber(1) ? static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[1])) : 0;
const bool skip_grant_only = sep->IsNumber(2) ? Strings::ToBool(sep->arg[2]) : false;
auto t = c->GetTarget()->CastToClient();
t->GrantAllAAPoints(unlock_level);
t->GrantAllAAPoints(unlock_level, skip_grant_only);
c->Message(
Chat::White,
fmt::format(
"Successfully granted all Alternate Advancements for {}{}.",
"Successfully granted all Alternate Advancements for {}{}{}.",
c->GetTargetDescription(t),
(
unlock_level ?
@@ -24,7 +25,8 @@ void command_grantaa(Client *c, const Seperator *sep)
unlock_level
) :
""
)
),
skip_grant_only ? "except for grant only AAs" : ""
).c_str()
);
}
+6 -1
View File
@@ -3431,6 +3431,11 @@ void Client::SetBandolier(const EQApplicationPacket *app)
}
}
}
if (RuleI(Character, BandolierSwapDelay) > 0) {
bandolier_throttle_timer.Start(RuleI(Character, BandolierSwapDelay));
}
// finally, recalculate any stat bonuses from the item change
CalcBonuses();
}
@@ -4913,4 +4918,4 @@ bool Client::FindNumberOfFreeInventorySlotsWithSizeCheck(std::vector<BuyerLineTr
}
}
return false;
};
};
+7
View File
@@ -3216,6 +3216,12 @@ void Lua_Client::GrantAllAAPoints(uint8 unlock_level)
self->GrantAllAAPoints(unlock_level);
}
void Lua_Client::GrantAllAAPoints(uint8 unlock_level, bool skip_grant_only)
{
Lua_Safe_Call_Void();
self->GrantAllAAPoints(unlock_level, skip_grant_only);
}
void Lua_Client::AddEbonCrystals(uint32 amount)
{
Lua_Safe_Call_Void();
@@ -3699,6 +3705,7 @@ luabind::scope lua_register_client() {
.def("GoFish", (void(Lua_Client::*)(void))&Lua_Client::GoFish)
.def("GrantAllAAPoints", (void(Lua_Client::*)(void))&Lua_Client::GrantAllAAPoints)
.def("GrantAllAAPoints", (void(Lua_Client::*)(uint8))&Lua_Client::GrantAllAAPoints)
.def("GrantAllAAPoints", (void(Lua_Client::*)(uint8,bool))&Lua_Client::GrantAllAAPoints)
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int))&Lua_Client::GrantAlternateAdvancementAbility)
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int, bool))&Lua_Client::GrantAlternateAdvancementAbility)
.def("GuildID", (uint32(Lua_Client::*)(void))&Lua_Client::GuildID)
+1
View File
@@ -487,6 +487,7 @@ public:
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration);
void GrantAllAAPoints();
void GrantAllAAPoints(uint8 unlock_level);
void GrantAllAAPoints(uint8 unlock_level, bool skip_grant_only);
void AddEbonCrystals(uint32 amount);
void AddRadiantCrystals(uint32 amount);
void RemoveEbonCrystals(uint32 amount);
+13 -1
View File
@@ -5491,7 +5491,7 @@ int Mob::GetHaste()
}
}
else {
h += spellbonuses.hastetype3;
h += spellbonuses.hastetype3;
}
h += extra_haste; //GM granted haste.
@@ -8611,3 +8611,15 @@ void Mob::SetExtraHaste(int haste, bool need_to_save)
}
}
}
bool Mob::IsCloseToBanker()
{
for (auto &e: entity_list.GetCloseMobList(this)) {
auto mob = e.second;
if (mob && mob->IsNPC() && mob->GetClass() == Class::Banker) {
return true;
}
}
return false;
}
+2
View File
@@ -1477,6 +1477,8 @@ public:
DataBucketKey GetScopedBucketKeys();
bool IsCloseToBanker();
protected:
void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
+6
View File
@@ -3031,6 +3031,11 @@ void Perl_Client_GrantAllAAPoints(Client* self, uint8 unlock_level)
self->GrantAllAAPoints(unlock_level);
}
void Perl_Client_GrantAllAAPoints(Client* self, uint8 unlock_level, bool skip_grant_only)
{
self->GrantAllAAPoints(unlock_level, skip_grant_only);
}
void Perl_Client_AddEbonCrystals(Client* self, uint32 amount)
{
self->AddEbonCrystals(amount);
@@ -3471,6 +3476,7 @@ void perl_register_client()
package.add("GoFish", &Perl_Client_GoFish);
package.add("GrantAllAAPoints", (void(*)(Client*))&Perl_Client_GrantAllAAPoints);
package.add("GrantAllAAPoints", (void(*)(Client*, uint8))&Perl_Client_GrantAllAAPoints);
package.add("GrantAllAAPoints", (void(*)(Client*, uint8, bool))&Perl_Client_GrantAllAAPoints);
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int))&Perl_Client_GrantAlternateAdvancementAbility);
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int, bool))&Perl_Client_GrantAlternateAdvancementAbility);
package.add("GuildID", &Perl_Client_GuildID);
+2 -2
View File
@@ -2202,10 +2202,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#ifdef SPELL_EFFECT_SPAM
snprintf(effect_desc, _EDLEN, "Sacrifice");
#endif
if(!caster || !IsClient() || !caster->IsClient()){
if(!caster || !IsClient() ){
break;
}
CastToClient()->SacrificeConfirm(caster->CastToClient());
CastToClient()->SacrificeConfirm(caster);
break;
}
+6 -1
View File
@@ -869,7 +869,12 @@ int ClientTaskState::IncrementDoneCount(
if (task_data->type != TaskType::Shared) {
// live messages for each increment of non-shared tasks
auto activity_type = task_data->activity_information[activity_id].activity_type;
int msg_count = activity_type == TaskActivityType::GiveCash ? 1 : count;
int msg_count = 1;
if (activity_type != TaskActivityType::GiveCash) {
msg_count = std::min(count, RuleI(TaskSystem, MaxUpdateMessages));
}
for (int i = 0; i < msg_count; ++i) {
client->MessageString(Chat::DefaultText, TASK_UPDATED, task_data->title.c_str());
}
+1 -1
View File
@@ -3495,7 +3495,7 @@ void Client::BuyTraderItemOutsideBazaar(TraderBuy_Struct *tbs, const EQApplicati
ps.item_slot = parcel_out.slot_id;
strn0cpy(ps.send_to, GetCleanName(), sizeof(ps.send_to));
if (trader_item.item_charges == tbs->quantity) {
if (trader_item.item_charges <= static_cast<int32>(tbs->quantity)) {
TraderRepository::DeleteOne(database, trader_item.id);
} else {
TraderRepository::UpdateQuantity(
+11 -5
View File
@@ -671,12 +671,16 @@ bool ZoneDatabase::LoadCharacterLeadershipAbilities(uint32 character_id, PlayerP
return true;
}
bool ZoneDatabase::LoadCharacterDisciplines(uint32 character_id, PlayerProfile_Struct* pp){
bool ZoneDatabase::LoadCharacterDisciplines(Client* c)
{
if (!c) {
return false;
}
const auto& l = CharacterDisciplinesRepository::GetWhere(
database, fmt::format(
"`id` = {} ORDER BY `slot_id`",
character_id
c->CharacterID()
)
);
@@ -684,16 +688,18 @@ bool ZoneDatabase::LoadCharacterDisciplines(uint32 character_id, PlayerProfile_S
return false;
}
for (int slot_id = 0; slot_id < MAX_PP_DISCIPLINES; slot_id++) { // Initialize Disciplines
pp->disciplines.values[slot_id] = 0;
for (int slot_id = 0; slot_id < MAX_PP_DISCIPLINES; slot_id++) {
c->GetPP().disciplines.values[slot_id] = 0;
}
for (const auto& e : l) {
if (IsValidSpell(e.disc_id) && e.slot_id < MAX_PP_DISCIPLINES) {
pp->disciplines.values[e.slot_id] = e.disc_id;
c->GetPP().disciplines.values[e.slot_id] = e.disc_id;
}
}
c->SendDisciplineUpdate();
return true;
}
+1 -1
View File
@@ -436,7 +436,7 @@ public:
bool LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp);
bool LoadCharacterDisciplines(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterDisciplines(Client* c);
bool LoadCharacterFactionValues(uint32 character_id, faction_map & val_list);
bool LoadCharacterLanguages(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterLeadershipAbilities(uint32 character_id, PlayerProfile_Struct* pp);