Compare commits

...

984 Commits

Author SHA1 Message Date
Akkadius c25cb0cc23 [Release] 22.22.1 2023-07-30 01:36:49 -05:00
Chris Miles ddac326239 [Doors] Add door blacklist (#3516)
* [Doors] Add door blacklist

* Renaming to simplify
2023-07-30 01:35:44 -05:00
Akkadius 14fe396510 [Database] Hotfix: Add command_subsettings to server tables 2023-07-28 22:22:43 -05:00
Chris Miles c968a0acdc [Release] 22.22.0 (#3513)
* [Release] 22.22.0

* Version other areas
2023-07-28 11:35:40 -05:00
Alex King 8c4cd34e01 [Quest API] Add GetMobTypeIdentifier() to Perl/Lua (#3512)
# Perl
- Add `$mob->GetMobTypeIdentifier()`.

# Lua
- Add `mob:GetMobTypeIdentifier()`.

# Notes
- Gets unique identifier independent of mob type.
2023-07-27 23:16:41 -05:00
Akkadius 0dbcf83a11 [Database] Fix console output in database:dump --dump-output-to-console 2023-07-25 11:45:26 -05:00
Alex King a75648f73f [Data Buckets] Distributed Databucket Caching (#3500)
* [Data Buckets] Zone-Based Data Bucket Caching

# Notes
- Adds a data bucket cache so we're not needlessly hitting the database every time we need to read a data bucket value.

* Cleanup and unify GetData access patterns

* Cache work

* Push

* Add to cache when we fetch and do a db hit

* Handle bucket misses in cache

* Formatting

* Logging

* [Data Buckets] Zone-Based Data Bucket Caching

- Adds a data bucket cache so we're not needlessly hitting the database every time we need to read a data bucket value.

* Cleanup and unify GetData access patterns

* Cache work

* Push

* Add to cache when we fetch and do a db hit

* Handle bucket misses in cache

* Formatting

* Remove redundant fetches from cache since GetData does the same thing

* Push progress

* Distributed cache work

* Logging

* Fix issue with scoping where same named keys could return overlapping results

* Misses cache tweak, logging, comments

* Add bot, client, and NPC bucket methods to Lua.

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-07-24 12:22:50 -05:00
Alex King 6c2886a71d [Cleanup] Fix casing in corpse money and decay time. (#3511)
# Notes
- These were uppercase and should be lowercase.
2023-07-23 16:19:07 -04:00
Alex King 1d96ddb60d [Bug Fix] Escape search string in #find item (#3510) 2023-07-22 18:20:00 -04:00
Vayle c30074be66 [Crash Fix] Guard against Spells:MaxTotalSlotsPET being set above client allowed maximum. (#3507)
* Guard against MaxTotalSlotsPET being set too high

This prevents a crash from MaxTotalSlotsPET being set too high.

* Tweak
2023-07-22 10:20:22 -04:00
Chris Miles b5652e6010 [Saylink] Fix cases where saylinks were not being cached (#3508)
* [Saylink] Fix cases where saylinks were not being cached

* Update say_link.cpp
2023-07-19 23:57:04 -05:00
Akkadius 202d2ed496 [Release] 22.21.2 2023-07-19 23:50:47 -05:00
Chris Miles 81cee49ea1 [Databuckets] Fix rarer same bucket name scoping overlap issue (#3509) 2023-07-19 23:49:11 -05:00
Akkadius 2d61cd2b9a [Release] 22.21.1 2023-07-18 20:50:56 -05:00
Vayle b06505b80a [Cleanup] Remove arbitrary teleport blocking in Tutorial and Load zones (#3506) 2023-07-18 20:56:21 -04:00
Chris Miles 4c2f9a4423 [Databuckets] Fix issue with expired databuckets not being expired and returned properly (#3504) 2023-07-18 17:18:36 -05:00
Alex King fb3159b657 [Bug Fix] #set title_suffix Argument Position (#3505)
# Notes
- Off by one on argument index.
2023-07-18 18:02:25 -04:00
Michael 8ebf5bbb78 [Bug] Show Petition and Show Petition_Info fix (#3503)
Where Statement was using incorrect field name.
2023-07-18 17:15:21 -04:00
Akkadius d2aae4d79c [Release] 22.21.0 2023-07-18 02:54:20 -05:00
Chris Miles f9dc9da42b [Pathing] Improvements to roambox logic, pathing (#3502)
* [Roambox] Improvements to roambox logic

* Update npc.cpp

* Update npc.cpp

* More pathing fixes
2023-07-18 02:52:04 -05:00
Chris Miles 3f3bbe98b5 [Data Buckets] Implement scoped data buckets (#3498)
* [Data Buckets] Implement scoped data buckets

* Update database_update_manifest.cpp

* Update data_bucket.cpp

* Update data_bucket.cpp

* Update data_bucket.cpp

* Update data_bucket.h

* Update database_update_manifest.cpp

* Add GetScopedDbFilters references

* Scope transfer
2023-07-16 14:52:28 -04:00
Chris Miles 59537ae977 [Z Clipping] Don't issue zclip adjustments when NPC is not moving (#3499) 2023-07-16 14:52:17 -04:00
Alex King ee45a28efe [Quest API] Add SetLDoNPoints() to Perl/Lua (#3496)
# Perl
- Add `$client->SetLDoNPoints(theme_id, points)`.

# Lua
- Add `client:SetLDoNPoints(theme_id, points)`.

# Notes
- Allows operators to directly set LDoN Points.
2023-07-15 21:46:49 -05:00
Jonathan Sider 70ce81fb0a [Bug Fix] Fix rule check and add rule for pickpocket command (#3492)
* Fix bugs in skills

-Add rule for allowing pickpocket
-Fix method that is supposed to check rule
-Changed Z axis range for pickpocket (was failing on giants)

* Add zoffset to account for taller models
2023-07-15 21:46:26 -05:00
Akkadius e06d28ad20 [Release] 22.20.1 2023-07-15 13:30:36 -05:00
Mitch Freeman d57489781c [Database] Fix database manifest entry for #3443
Updates the syntax for mariadb 10.1
2023-07-15 13:29:34 -05:00
Chris Miles 21d65c73b7 [Release] 22.20.0 (#3495) 2023-07-15 00:46:42 -05:00
Alex King 8f6d606f53 [Bug Fix] Fix Tradeskill Combines with augmented items (#3490)
* [Bug Fix] Fix Tradeskill Combines with augmented items

# Notes
- Keeps players from doing tradeskill combines with augmented items.
- Behavior is Live-like, we don't need a rule since `EVENT_COMBINE` is separate and processed prior to the recipe check.

* Update tradeskills.cpp

* Update tradeskills.cpp

* Cleanup

* Update tradeskills.cpp
2023-07-15 00:39:19 -05:00
Alex King f25e37d0c5 [Commands] Consolidate #set-like commands into a singular #set command (#3486)
* First push

* Final push.

* Consolidate zone commands in to one.

* Update command.cpp

* Remove debug messages.

* Test

* Add support for sub command status levels.

* Update command.cpp

* Update client.cpp

* Update database_update_manifest.cpp

* Update version.h

* Update item.cpp

* Update version.h

* Update database_update_manifest.cpp

* Fix command arguments.

* Help message.

* Update command.cpp

* Do DB injection/deletion

* Indent

* Update server_locked.cpp

* Update set.cpp

* Lock aliases

* Update command_subsettings_repository.h

* Update set.cpp

* Fix

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-07-15 00:37:51 -05:00
Alex King e55f9b9d27 [Feature] Add Support for item textures higher than 65,535 (#3494)
* [Feature] Add Support for item textures higher than 65,535

# Notes
- We were previously using `uint16` which has a max of `65,535`, but some of the new Live textures that are being used have values way beyond this.
- Updates quest API, commands, and database tables that also used `uint16`.

* Update version.h
2023-07-14 18:49:59 -04:00
Mitch Freeman b01486d767 [Feature] Update raid features (#3443)
* [RAID] Add Raid Features

[RAID] Add Raid Features

- Add delegate main assist
- Add delegate main marker
- Add target ring for main assisters.  Uses MA1, then MA2, then MA3
- Add /assist raid respecting /assist on and /assist off
- Add Raid Notes.  Functions across zones
- Add Raid XTarget functional
- Raid Leader can mark without being delegated Main Marker.  Must have the appropriate AA

* Update to new db routines

* Updated several formatting issues based on review

* Update to pp->tribute_time_remaining to avoid edge case.  Unrelated to raid updates.

* Updates to resolve comments/review.
Added a few edge case updates as well.

* Refactored to use database repositories for raid_details and raid_members.  Other updates as noted in review.

* Updated database manifest and fixed potential leak within Client::Handle_OP_AssistGroup

* Update for remaining review items

* Refactor SendAssistTarget to use struct/vector loop

* Have IsAssister use range based for loop and return bool

* General cleanup

* Simplify SendRaidAssistTarget to use struct / vector

* Formatting in Handle_OP_RaidDelegateAbility

* Format SendRemoveRaidXTargets and clean up error statements

* Format SendRemoveAllRaidXTargets

* Formatting

* Default return FindNextRaidDelegateSlot to -1

* Change fields to marked_npc_1/2/3 (missing last underscore)

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-07-12 22:04:50 -05:00
Jonathan Sider 50ce99ce3e [Bug Fix] Update bot naming check and add more explanation (#3491)
* Refactor my original PR

Block all puncation,numbers, and _

* Add error message
2023-07-12 21:59:17 -05:00
Alex King 4854201b2a [Quest API] Add Mob/Entity type check methods to Perl/Lua (#3493)
* [Quest API] Add Mob/Entity type check methods to Perl/Lua

# Perl
- Add `$mob->IsAura()`.
- Add `$mob->IsEncounter()`.
- Add `$mob->IsMerc()`.
- Add `$mob->IsOfClientBot()`.
- Add `$mob->IsOfClientBotMerc()`.
- Add `$mob->IsTemporaryPet()`.

# Lua
- Add `entity:IsAura()`.
- Add `entity:IsOfClientBot()`.
- Add `entity:IsOfClientBotMerc()`.
- Add `mob:IsTemporaryPet()`.

* Update lua_entity.cpp

* Update lua_mob.cpp
2023-07-12 21:20:07 -05:00
Jonathan Sider c81d05940a [Bots] Remove orphaned commands related to botgroup (#3489) 2023-07-09 00:00:28 -04:00
Paul Coene 47be17e2af [Bug Fix] Fix charmed pets to follow when charmed. (#3488)
* [Bug Fix] Fix charmed pets to follow when charmed.

* Added STOP (missed this on a local merge)
2023-07-08 19:58:45 -04:00
Chris Miles 809b3b6099 [Release] 22.19.0 (#3487) 2023-07-08 16:54:15 -05:00
Jonathan Sider f06c7e8834 [Bots] Add Pickpocket Command (#3484)
* Add Pickpocket Command

* Formatting

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-07-08 16:51:52 -05:00
Alex King 096448d23c [Commands] Add #itemsearch alias to #find aliases (#3485)
# Notes
- `#itemsearch` did not exist in this alias list.
2023-07-08 16:33:29 -05:00
Alex King e55fb1cafd [Commands] Consolidate #show commands into a singular #show command (#3478)
* [Cleanup] Consolidate #show commands into a singular #show command

# Notes
- All `#show` commands like `#showbuffs` are now subcommands of `#show`.
- All aliases like `#showbuffs` still function.

* Push up progress.

* Final push.

* Cleanup.

* Update ip_lookup.cpp

* emotes not emote

* Cleanup

* Update servertalk.h

* Update show.cpp

* Fix

* Final push.

* #aggro

* #who
2023-07-08 11:06:25 -04:00
Alex King d4962bb2ab [Cleanup] Move #find item summon links to front (#3483)
# Notes
- Move the summon links to the front so they're in a consistent location.
2023-07-04 23:08:29 -04:00
Jasdac 98e56bdfe9 [Rules] Add Skills:TrivialTradeskillCombinesNoFail Rule (#3481)
* Add TrivialNoFail rule

* feedback fixes

* Update tradeskills.cpp

* Update 1392_recipe_learning.sql

* Update ruletypes.h

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-07-04 22:47:56 -04:00
Akkadius 5c1be3643e [Release] 22.18.0 2023-07-04 15:21:35 -05:00
Alex King c2fa61b3a2 [Bug Fix] Add chatchannel_reserved_names to a new manifest (#3482)
# Notes
- This should resolve issues where the old query fails because it's adding an already existing column to another table.
2023-07-04 15:19:24 -05:00
Alex King 01a1186e63 [Commands] Add #emotesearch to #find command (#3480)
# Notes
- Missed this with initial `#find` command consolidation.
2023-07-04 14:17:42 -05:00
Alex King 7427318213 [Commands] Cleanup #copycharacter Command (#3479)
# Notes
- Cleanup messages and logic.
2023-07-04 14:14:33 -05:00
Alex King d3c3d7b384 [Bug Fix] Fix issue in zone store of returning reference to local variable (#3477)
# Notes
- Compiler did not like possibly returning a reference to a local variable.
2023-07-04 03:08:44 -05:00
Alex King e9e8143778 [Release] 22.17.0 (#3476)
## [22.17.0] - 07/03/2023

### Cleanup/Feature

* Add support for bots to #showstats/#mystats ([#3427](https://github.com/EQEmu/Server/pull/3427)) @Kinglykrab 2023-07-01

### Code

* Remove LoadItemDBFieldNames() from common/misc.cpp and common/misc.h ([#3473](https://github.com/EQEmu/Server/pull/3473)) @Kinglykrab 2023-07-04
* Remove handle_npc_single_npc from zone/lua_parser_events.cpp and zone/lua_parser_events.h ([#3467](https://github.com/EQEmu/Server/pull/3467)) @Kinglykrab 2023-07-03

### Database

* Set multi statements off when returning early ([#3462](https://github.com/EQEmu/Server/pull/3462)) @Akkadius 2023-07-01

### Feature

* Add Strings::BeginsWith() and Strings::EndsWith() ([#3471](https://github.com/EQEmu/Server/pull/3471)) @Kinglykrab 2023-07-03

### Fixes

* Add check for underscores in botcreate command ([#3458](https://github.com/EQEmu/Server/pull/3458)) @tuday2 2023-06-29
* EVENT_LANGUAGE_SKILL_UP in Lua was using EVENT_SKILL_UP logic ([#3466](https://github.com/EQEmu/Server/pull/3466)) @Kinglykrab 2023-07-03
* Fix _PutItem having a slot_id of -1 on mobs with no items ([#3474](https://github.com/EQEmu/Server/pull/3474)) @Kinglykrab 2023-07-04
* Fix data type of GetAggroCount() ([#3470](https://github.com/EQEmu/Server/pull/3470)) @Kinglykrab 2023-07-03

### Logging

* Fix logging crash when % are sent through query logs ([#3461](https://github.com/EQEmu/Server/pull/3461)) @Akkadius 2023-07-01

### Quest API

* Add ClearAccountFlag() and GetAccountFlags() to Perl/Lua ([#3469](https://github.com/EQEmu/Server/pull/3469)) @Kinglykrab 2023-07-03
* Add GetClassAbbreviation() and GetRaceAbbreviation() to Perl/Lua ([#3463](https://github.com/EQEmu/Server/pull/3463)) @Kinglykrab 2023-07-02
* Add GetClassPlural() and GetRacePlural() to Perl/Lua ([#3468](https://github.com/EQEmu/Server/pull/3468)) @Kinglykrab 2023-07-03
* Add GetCloseMobList() and CalculateDistance() overload to Perl/Lua ([#3455](https://github.com/EQEmu/Server/pull/3455)) @Kinglykrab 2023-07-02
* Add Hate Entry Methods to Perl ([#3459](https://github.com/EQEmu/Server/pull/3459)) @Kinglykrab 2023-07-02
* Add ItemData Class to Perl ([#3465](https://github.com/EQEmu/Server/pull/3465)) @Kinglykrab 2023-07-02
* Add Spawn2 Class to Perl ([#3456](https://github.com/EQEmu/Server/pull/3456)) @Kinglykrab 2023-07-02
* Add StatBonuses Class to Perl ([#3460](https://github.com/EQEmu/Server/pull/3460)) @Kinglykrab 2023-07-02
* Add missing Item Methods to Perl/Lua. ([#3464](https://github.com/EQEmu/Server/pull/3464)) @Kinglykrab 2023-07-02
2023-07-03 19:46:15 -05:00
Alex King bc71997518 [Bug Fix] Fix _PutItem having a slot_id of -1 on mobs with no items (#3474)
# Notes
- This was causing an insane amount of error logs because we were always using `PutItem`, even with a `slot_id` of `-1`.
2023-07-03 20:33:21 -04:00
Alex King 4a9a9fa197 [Cleanup] Remove LoadItemDBFieldNames() from common/misc.cpp and common/misc.h (#3473)
# Notes
- This is unused.
2023-07-03 19:20:34 -05:00
Alex King ee14aed8de [Feature] Add Strings::BeginsWith() and Strings::EndsWith() (#3471)
* [Strings] Add Strings::BeginsWith() and Strings::EndsWith()

# Notes
- These are useful so that we don't have to manually calculate size or perform a substring.

* Update questmgr.cpp

* Update client.cpp
2023-07-03 09:40:44 -04:00
Alex King 2717fcc339 [Quest API] Add ClearAccountFlag() and GetAccountFlags() to Perl/Lua (#3469)
* [Quest API] Add ClearAccountFlag() and GetAccountFlags() to Perl/Lua

# Perl
- Add `$client->ClearAccountFlag(flag)`.
- Add `$client->GetAccountFlags()`.

# Lua
- Add `client:ClearAccountFlag(flag)`.
- Add `client:GetAccountFlags()`.

# Notes
- Made use of repositories and cleaned up existing code.

* Update lua_client.cpp

* Don't use auto.
2023-07-03 01:19:48 -05:00
Alex King dc28c8d485 [Bug Fix] Fix data type of GetAggroCount() (#3470)
# Notes
- This is an `unsigned int`, not an `int`, so this fixes that.
2023-07-03 00:10:27 -05:00
Alex King a633784f78 [Quest API] Add GetClassPlural() and GetRacePlural() to Perl/Lua (#3468)
* [Quest API] Add GetClassPlural() and GetRacePlural() to Perl/Lua

# Perl
- Add `$mob->GetClassPlural()`.
- Add `$mob->GetRacePlural()`.

# Lua
- Add `mob:GetClassPlural()`.
- Add `mob:GetRacePlural()`.

# Notes
- Allows operators to get the plural of a player class or race, example being `Warrior` as `Warriors` or `Dark Elf` as `Dark Elves`.

* Update mob.cpp
2023-07-03 00:08:04 -05:00
Alex King 5519c3e781 [Cleanup] Remove handle_npc_single_npc from zone/lua_parser_events.cpp and zone/lua_parser_events.h (#3467)
# Notes
- This is unused.
2023-07-02 23:56:04 -05:00
Alex King 9401323708 [Bug Fix] EVENT_LANGUAGE_SKILL_UP in Lua was using EVENT_SKILL_UP logic (#3466)
# Notes
- `EVENT_LANGUAGE_SKILL_UP` only takes `3` values whereas `EVENT_SKILL_UP` takes `4`.
2023-07-02 20:41:53 -04:00
Alex King 251993c61b [Quest API] Add ItemData Class to Perl (#3465)
* [Quest API] Add ItemData Class to Perl

- Add `$questitem->GetItem()`.
- Add `$questitem->GetUnscaledItem()`.
- Add `$questitemdata->GetAGI()`.
- Add `$questitemdata->GetAC()`.
- Add `$questitemdata->GetCHA()`.
- Add `$questitemdata->GetDEX()`.
- Add `$questitemdata->GetINT()`.
- Add `$questitemdata->GetSTA()`.
- Add `$questitemdata->GetSTR()`.
- Add `$questitemdata->GetAWis()`.
- Add `$questitemdata->GetAccuracy()`.
- Add `$questitemdata->GetArtifactFlag()`.
- Add `$questitemdata->GetAttack()`.
- Add `$questitemdata->GetAttuneable()`.
- Add `$questitemdata->GetAugmentDistiller()`.
- Add `$questitemdata->GetAugmentRestrict()`.
- Add `$questitemdata->GetAugmentSlotType(slot_id)`.
- Add `$questitemdata->GetAugmentSlotUnk2(slot_id)`.
- Add `$questitemdata->GetAugmentSlotVisible(slot_id)`.
- Add `$questitemdata->GetAugmentType()`.
- Add `$questitemdata->GetAvoidance()`.
- Add `$questitemdata->GetBackstabDamage()`.
- Add `$questitemdata->GetBagSize()`.
- Add `$questitemdata->GetBagSlots()`.
- Add `$questitemdata->GetBagType()`.
- Add `$questitemdata->GetBagWeightReduction()`.
- Add `$questitemdata->GetBaneDamageAmount()`.
- Add `$questitemdata->GetBaneDamageBody()`.
- Add `$questitemdata->GetBaneDamageRace()`.
- Add `$questitemdata->GetBaneDamageRaceAmount()`.
- Add `$questitemdata->GetBardEffect()`.
- Add `$questitemdata->GetBardLevel()`.
- Add `$questitemdata->GetBardLevel2()`.
- Add `$questitemdata->GetBardType()`.
- Add `$questitemdata->GetBardSkillType()`.
- Add `$questitemdata->GetBardSkillValue()`.
- Add `$questitemdata->GetBenefitFlag()`.
- Add `$questitemdata->GetBook()`.
- Add `$questitemdata->GetBookType()`.
- Add `$questitemdata->GetCR()`.
- Add `$questitemdata->GetCastTime()`.
- Add `$questitemdata->GetCastTime_()`.
- Add `$questitemdata->GetCharmFile()`.
- Add `$questitemdata->GetCharmFileID()`.
- Add `$questitemdata->GetClairvoyance()`.
- Add `$questitemdata->GetClasses()`.
- Add `$questitemdata->GetClickName()`.
- Add `$questitemdata->GetClickEffect()`.
- Add `$questitemdata->GetClickLevel()`.
- Add `$questitemdata->GetClickLevel2()`.
- Add `$questitemdata->GetClickType()`.
- Add `$questitemdata->GetColor()`.
- Add `$questitemdata->GetCombatEffects()`.
- Add `$questitemdata->GetCorruption()`.
- Add `$questitemdata->GetDR()`.
- Add `$questitemdata->GetDSMitigation()`.
- Add `$questitemdata->GetDamage()`.
- Add `$questitemdata->GetDamageShield()`.
- Add `$questitemdata->GetDeity()`.
- Add `$questitemdata->GetDelay()`.
- Add `$questitemdata->GetDOTShielding()`.
- Add `$questitemdata->GetElementalDamageAmount()`.
- Add `$questitemdata->GetElementalDamageType()`.
- Add `$questitemdata->GetEliteMaterial()`.
- Add `$questitemdata->GetEndurance()`.
- Add `$questitemdata->GetEnduranceRegen()`.
- Add `$questitemdata->GetExpendableArrow()`.
- Add `$questitemdata->GetExtraDamageAmount()`.
- Add `$questitemdata->GetExtraDamageSkill()`.
- Add `$questitemdata->GetFR()`.
- Add `$questitemdata->GetFVNoDrop()`.
- Add `$questitemdata->GetFactionAmount1()`.
- Add `$questitemdata->GetFactionAmount2()`.
- Add `$questitemdata->GetFactionAmount3()`.
- Add `$questitemdata->GetFactionAmount4()`.
- Add `$questitemdata->GetFactionModifier1()`.
- Add `$questitemdata->GetFactionModifier2()`.
- Add `$questitemdata->GetFactionModifier3()`.
- Add `$questitemdata->GetFactionModifier4()`.
- Add `$questitemdata->GetFavor()`.
- Add `$questitemdata->GetFilename()`.
- Add `$questitemdata->GetFocusEffect()`.
- Add `$questitemdata->GetFocusName()`.
- Add `$questitemdata->GetFocusLevel()`.
- Add `$questitemdata->GetFocusLevel2()`.
- Add `$questitemdata->GetFocusType()`.
- Add `$questitemdata->GetFulfilment()`.
- Add `$questitemdata->GetGuildFavor()`.
- Add `$questitemdata->GetHP()`.
- Add `$questitemdata->GetHaste()`.
- Add `$questitemdata->GetHealAmount()`.
- Add `$questitemdata->GetHeroicAGI()`.
- Add `$questitemdata->GetHeroicCR()`.
- Add `$questitemdata->GetHeroicCHA()`.
- Add `$questitemdata->GetHeroicCorruption()`.
- Add `$questitemdata->GetHeroicDR()`.
- Add `$questitemdata->GetHeroicDEX()`.
- Add `$questitemdata->GetHeroicFR()`.
- Add `$questitemdata->GetHeroicINT()`.
- Add `$questitemdata->GetHeroicMR()`.
- Add `$questitemdata->GetHeroicPR()`.
- Add `$questitemdata->GetHeroicSTA()`.
- Add `$questitemdata->GetHeroicSTR()`.
- Add `$questitemdata->GetHeroicWIS()`.
- Add `$questitemdata->GetID()`.
- Add `$questitemdata->GetIDFile()`.
- Add `$questitemdata->GetIcon()`.
- Add `$questitemdata->GetItemClass()`.
- Add `$questitemdata->GetItemType()`.
- Add `$questitemdata->GetLDoNPrice()`.
- Add `$questitemdata->GetLDoNSellBackRate()`.
- Add `$questitemdata->GetLDoNSold()`.
- Add `$questitemdata->GetLDoNTheme()`.
- Add `$questitemdata->GetLight()`.
- Add `$questitemdata->GetLore()`.
- Add `$questitemdata->GetLoreFlag()`.
- Add `$questitemdata->GetLoreGroup()`.
- Add `$questitemdata->GetMR()`.
- Add `$questitemdata->GetMagic()`.
- Add `$questitemdata->GetMana()`.
- Add `$questitemdata->GetManaRegen()`.
- Add `$questitemdata->GetMaterial()`.
- Add `$questitemdata->GetMaximumCharges()`.
- Add `$questitemdata->GetMinimumStatus()`.
- Add `$questitemdata->GetName()`.
- Add `$questitemdata->GetNoDrop()`.
- Add `$questitemdata->GetNoPet()`.
- Add `$questitemdata->GetNoRent()`.
- Add `$questitemdata->GetNoTransfer()`.
- Add `$questitemdata->GetPR()`.
- Add `$questitemdata->GetPendingLoreFlag()`.
- Add `$questitemdata->GetPointType()`.
- Add `$questitemdata->GetPotionBelt()`.
- Add `$questitemdata->GetPotionBeltSlots()`.
- Add `$questitemdata->GetPrice()`.
- Add `$questitemdata->GetProcEffect()`.
- Add `$questitemdata->GetProcName()`.
- Add `$questitemdata->GetProcRate()`.
- Add `$questitemdata->GetProcLevel()`.
- Add `$questitemdata->GetProcLevel2()`.
- Add `$questitemdata->GetProcType()`.
- Add `$questitemdata->GetPurity()`.
- Add `$questitemdata->GetQuestItemFlag()`.
- Add `$questitemdata->GetRaces()`.
- Add `$questitemdata->GetRange()`.
- Add `$questitemdata->GetRecLevel()`.
- Add `$questitemdata->GetRecSkill()`.
- Add `$questitemdata->GetRecastDelay()`.
- Add `$questitemdata->GetRecastType()`.
- Add `$questitemdata->GetRegen()`.
- Add `$questitemdata->GetReqLevel()`.
- Add `$questitemdata->GetScriptFileID()`.
- Add `$questitemdata->GetScrollEffect()`.
- Add `$questitemdata->GetScrollName()`.
- Add `$questitemdata->GetScrollLevel()`.
- Add `$questitemdata->GetScrollLevel2()`.
- Add `$questitemdata->GetScrollType()`.
- Add `$questitemdata->GetSellRate()`.
- Add `$questitemdata->GetShielding()`.
- Add `$questitemdata->GetSize()`.
- Add `$questitemdata->GetSkillModifierType()`.
- Add `$questitemdata->GetSkillModifierValue()`.
- Add `$questitemdata->GetSlots()`.
- Add `$questitemdata->GetSpellDamage()`.
- Add `$questitemdata->GetSpellShield()`.
- Add `$questitemdata->GetStackSize()`.
- Add `$questitemdata->GetStackable()`.
- Add `$questitemdata->GetStrikeThrough()`.
- Add `$questitemdata->GetStunResist()`.
- Add `$questitemdata->GetSummonedFlag()`.
- Add `$questitemdata->GetTradeskills()`.
- Add `$questitemdata->GetWeight()`.
- Add `$questitemdata->GetWornName()`.
- Add `$questitemdata->GetWornEffect()`.
- Add `$questitemdata->GetWornLevel()`.
- Add `$questitemdata->GetWornLevel2()`.
- Add `$questitemdata->GetWornType()`.

- Fixed data type of parameters in a handful of methods.

- Allows operators to directly interact with item data without the need for `quest::getitemstat` or DBI or anything of the sort.

* Update perl_questitem.cpp

* Update lua_iteminst.cpp

* Update lua_iteminst.h

* Update lua_iteminst.h
2023-07-02 11:26:49 -04:00
Alex King 728ce0c519 [Quest API] Add GetCloseMobList() and CalculateDistance() overload to Perl/Lua (#3455)
* [Quest API] Add GetCloseMobList() and CalculateDistance() overload to Perl/Lua

# Perl
- Add `$entity_list->GetCloseMobList(mob)`.
- Add `$entity_list->GetCloseMobList(mob, distance)`.
- Add `$mob->CalculateDistance(mob)`.
- Add `$mob->GetCloseMobList()`.
- Add `$mob->GetCloseMobList(distance)`.

# Lua
- Add `eq.get_entity_list():GetCloseMobList(mob)`.
- Add `eq.get_entity_list():GetCloseMobList(mob, distance)`.
- Add `mob:CalculateDistance(mob)`.
- Add `mob:GetCloseMobList()`.
- Add `mob:GetCloseMobList(distance)`.

* Ignore Self

* Update lua_entity_list.cpp

* Cleanup
2023-07-02 10:55:27 -04:00
Alex King 6a80bcecc7 [Quest API] Add missing Item Methods to Perl/Lua. (#3464)
# Perl
- Add `$questitem->AddEXP(exp)`.
- Add `$questitem->ClearTimers()`.
- Add `$questitem->Clone()`.
- Add `$questitem->DeleteCustomData(identifier)`.
- Add `$questitem->GetAugmentItemID(slot_id)`.
- Add `$questitem->GetAugmentType()`.
- Add `$questitem->GetColor()`.
- Add `$questitem->GetCustomData(identifier)`.
- Add `$questitem->GetCustomDataString()`.
- Add `$questitem->GetEXP()`.
- Add `$questitem->GetItem(slot_id)`.
- Add `$questitem->GetItemID(slot_id)`.
- Add `$questitem->GetItemScriptID()`.
- Add `$questitem->GetKillsNeeded()`.
- Add `$questitem->GetMaxEvolveLevel()`.
- Add `$questitem->GetPrice()`.
- Add `$questitem->GetTotalItemCount()`.
- Add `$questitem->IsAmmo()`.
- Add `$questitem->IsAugmentable()`.
- Add `$questitem->IsAugmented()`.
- Add `$questitem->IsEquipable(slot_id)`.
- Add `$questitem->IsEquipable(race_bitmask, class_bitmask)`.
- Add `$questitem->IsExpendable()`.
- Add `$questitem->IsInstanceNoDrop()`.
- Add `$questitem->IsWeapon()`.
- Add `$questitem->SetAttuned(is_attuned)`.
- Add `$questitem->SetColor(color)`.
- Add `$questitem->SetCustomData(identifier, bool_value)`.
- Add `$questitem->SetCustomData(identifier, float_value)`.
- Add `$questitem->SetCustomData(identifier, int_value)`.
- Add `$questitem->SetCustomData(identifier, string_value)`.
- Add `$questitem->SetEXP(exp)`.
- Add `$questitem->SetInstanceNoDrop(is_attuned)`.
- Add `$questitem->SetPrice(price)`.
- Add `$questitem->SetScaling(is_scaling)`.
- Add `$questitem->SetTimer(timer_name, timer)`.
- Add `$questitem->StopTimer(timer_name)`.

# Lua
- Add `iteminst:GetName()`.
- Add `iteminst:IsAttuned()`.
- Add `iteminst:ItemSay(text)`.
- Add `iteminst:ItemSay(text, language_id)`.
- Add `iteminst:SetAttuned(is_attuned)`.

# Notes
- Cleaned up return types and parameter types that were mismatched.
- Removed `SetItem` from Lua as it wasn't used.
- Removed unused parameter in `GetUnscaledItem` in Lua.
- I plan to add Perl ItemData support after this makes its way in, so the missing methods like the `GetItem` overload will be added then.
2023-07-02 10:27:05 -04:00
Alex King 6324e3687a [Quest API] Add GetClassAbbreviation() and GetRaceAbbreviation() to Perl/Lua (#3463)
# Perl
- Add `$bot->GetClassAbbreviation()`.
- Add `$bot->GetRaceAbbreviation()`.
- Add `$client->GetClassAbbreviation()`.
- Add `$client->GetRaceAbbreviation()`.

# Lua
- Add `bot:GetClassAbbreviation()`.
- Add `bot:GetRaceAbbreviation()`.
- Add `client:GetClassAbbreviation()`.
- Add `client:GetRaceAbbreviation()`.

# Notes
- Allows operators to easily get a player race/class abbreviation, example being `Warrior` as `WAR`.
2023-07-02 10:26:51 -04:00
Alex King d16ac99033 [Quest API] Add StatBonuses Class to Perl (#3460)
* [Quest API] Add StatBonuses Class to Perl

# Perl
- Add `$mob->GetAABonuses()`.
- Add `$mob->GetItemBonuses()`.
- Add `$mob->GetSpellBonuses()`.
- Add `$statbonuses->GetAbsorbMagicAttack(slot)`.
- Add `$statbonuses->GetAC()`.
- Add `$statbonuses->GetAccuracy(slot)`.
- Add `$statbonuses->GetAdjustedCastingSkill()`.
- Add `$statbonuses->GetAggroRange()`.
- Add `$statbonuses->GetAGI()`.
- Add `$statbonuses->GetAGICapModifier()`.
- Add `$statbonuses->GetAlterNPCLevel()`.
- Add `$statbonuses->GetAmbidexterity()`.
- Add `$statbonuses->GetAmplification()`.
- Add `$statbonuses->GetAntiGate()`.
- Add `$statbonuses->GetArcheryDamageModifier()`.
- Add `$statbonuses->GetAssassinate(slot)`.
- Add `$statbonuses->GetAssassinateLevel(slot)`.
- Add `$statbonuses->GetAssistRange()`.
- Add `$statbonuses->GetAStacker(slot)`.
- Add `$statbonuses->GetATK()`.
- Add `$statbonuses->GetAvoidMeleeChance()`.
- Add `$statbonuses->GetAvoidMeleeChanceEffect()`.
- Add `$statbonuses->GetBaseMovementSpeed()`.
- Add `$statbonuses->GetBerserkSPA()`.
- Add `$statbonuses->GetBindWound()`.
- Add `$statbonuses->GetBlockBehind()`.
- Add `$statbonuses->GetBrassModifier()`.
- Add `$statbonuses->GetBStacker(slot)`.
- Add `$statbonuses->GetBuffSlotIncrease()`.
- Add `$statbonuses->GetCHA()`.
- Add `$statbonuses->GetCHACapModifier()`.
- Add `$statbonuses->GetChannelChanceItems()`.
- Add `$statbonuses->GetChannelChanceSpells()`.
- Add `$statbonuses->GetCharmBreakChance()`.
- Add `$statbonuses->GetClairvoyance()`.
- Add `$statbonuses->GetCombatStability()`.
- Add `$statbonuses->GetConsumeProjectile()`.
- Add `$statbonuses->GetCorrup()`.
- Add `$statbonuses->GetCorrupCapModifier()`.
- Add `$statbonuses->GetCR()`.
- Add `$statbonuses->GetCRCapModifier()`.
- Add `$statbonuses->GetCripplingBlowChance()`.
- Add `$statbonuses->GetCriticalDamageModifier(slot)`.
- Add `$statbonuses->GetCriticalDoTChance()`.
- Add `$statbonuses->GetCriticalDOTDecay()`.
- Add `$statbonuses->GetCriticalHealChance()`.
- Add `$statbonuses->GetCriticalHealDecay()`.
- Add `$statbonuses->GetCriticalHealOverTime()`.
- Add `$statbonuses->GetCriticalHitChance(slot)`.
- Add `$statbonuses->GetCriticalMend()`.
- Add `$statbonuses->GetCriticalRegenDecay()`.
- Add `$statbonuses->GetCriticalSpellChance()`.
- Add `$statbonuses->GetCStacker(slot)`.
- Add `$statbonuses->GetDamageModifier(slot)`.
- Add `$statbonuses->GetDamageModifier2(slot)`.
- Add `$statbonuses->GetDamageShield()`.
- Add `$statbonuses->GetDamageShieldSpellID()`.
- Add `$statbonuses->GetDamageShieldType()`.
- Add `$statbonuses->GetDeathSave(slot)`.
- Add `$statbonuses->GetDelayDeath()`.
- Add `$statbonuses->GetDEX()`.
- Add `$statbonuses->GetDEXCapModifier()`.
- Add `$statbonuses->GetDistanceRemoval()`.
- Add `$statbonuses->GetDivineAura()`.
- Add `$statbonuses->GetDivineSaveChance(slot)`.
- Add `$statbonuses->GetDodgeChance()`.
- Add `$statbonuses->GetDOTCriticalDamageIncrease()`.
- Add `$statbonuses->GetDoTShielding()`.
- Add `$statbonuses->GetDoubleAttackChance()`.
- Add `$statbonuses->GetDoubleRangedAttack()`.
- Add `$statbonuses->GetDoubleRiposte()`.
- Add `$statbonuses->GetDoubleSpecialAttack()`.
- Add `$statbonuses->GetDR()`.
- Add `$statbonuses->GetDRCapModifier()`.
- Add `$statbonuses->GetDSMitigation()`.
- Add `$statbonuses->GetDSMitigationOffHand()`.
- Add `$statbonuses->GetDStacker(slot)`.
- Add `$statbonuses->GetDualWieldChance()`.
- Add `$statbonuses->GetEffectiveCastingLevel()`.
- Add `$statbonuses->GetEndurancePercentCap(slot)`.
- Add `$statbonuses->GetEndurance()`.
- Add `$statbonuses->GetEnduranceReduction()`.
- Add `$statbonuses->GetEnduranceRegen()`.
- Add `$statbonuses->GetExtraXTargets()`.
- Add `$statbonuses->GetExtraAttackChance()`.
- Add `$statbonuses->GetFactionModifierPercent()`.
- Add `$statbonuses->GetFearless()`.
- Add `$statbonuses->GetFeignedCastOnChance()`.
- Add `$statbonuses->GetFinishingBlow(slot)`.
- Add `$statbonuses->GetFinishingBlowLevel(slot)`.
- Add `$statbonuses->GetFlurryChance()`.
- Add `$statbonuses->GetFocusEffects(slot)`.
- Add `$statbonuses->GetFocusEffectsWorn(slot)`.
- Add `$statbonuses->GetForageAdditionalItems()`.
- Add `$statbonuses->GetFR()`.
- Add `$statbonuses->GetFRCapModifier()`.
- Add `$statbonuses->GetFrenziedDevastation()`.
- Add `$statbonuses->GetFrontalBackstabChance()`.
- Add `$statbonuses->GetFrontalBackstabMinimumDamage()`.
- Add `$statbonuses->GetFrontalStunResist()`.
- Add `$statbonuses->GetGiveDoubleAttack()`.
- Add `$statbonuses->GetGiveDoubleRiposte(slot)`.
- Add `$statbonuses->GetGivePetGroupTarget()`.
- Add `$statbonuses->GetGravityEffect()`.
- Add `$statbonuses->GetHaste()`.
- Add `$statbonuses->GetHasteType2()`.
- Add `$statbonuses->GetHasteType3()`.
- Add `$statbonuses->GetHateModifier()`.
- Add `$statbonuses->GetHeadShot(slot)`.
- Add `$statbonuses->GetHeadShotLevel(slot)`.
- Add `$statbonuses->GetHealAmt()`.
- Add `$statbonuses->GetHealRate()`.
- Add `$statbonuses->GetHeroicAGI()`.
- Add `$statbonuses->GetHeroicCHA()`.
- Add `$statbonuses->GetHeroicCorrup()`.
- Add `$statbonuses->GetHeroicCR()`.
- Add `$statbonuses->GetHeroicDEX()`.
- Add `$statbonuses->GetHeroicDR()`.
- Add `$statbonuses->GetHeroicFR()`.
- Add `$statbonuses->GetHeroicINT()`.
- Add `$statbonuses->GetHeroicMR()`.
- Add `$statbonuses->GetHeroicPR()`.
- Add `$statbonuses->GetHeroicSTA()`.
- Add `$statbonuses->GetHeroicSTR()`.
- Add `$statbonuses->GetHeroicWIS()`.
- Add `$statbonuses->GetHitChance()`.
- Add `$statbonuses->GetHitChanceEffect(slot)`.
- Add `$statbonuses->GetHP()`.
- Add `$statbonuses->GetHPPercentCap(slot)`.
- Add `$statbonuses->GetHPRegen()`.
- Add `$statbonuses->GetHPToManaConvert()`.
- Add `$statbonuses->GetHundredHands()`.
- Add `$statbonuses->GetIllusionPersistence()`.
- Add `$statbonuses->GetImmuneToFlee()`.
- Add `$statbonuses->GetImprovedReclaimEnergy()`.
- Add `$statbonuses->GetImprovedTauntslot()`.
- Add `$statbonuses->GetIncreaseBlockChance()`.
- Add `$statbonuses->GetIncreaseChanceMemoryWipe()`.
- Add `$statbonuses->GetIncreaseRunSpeedCap()`.
- Add `$statbonuses->GetInhibitMelee()`.
- Add `$statbonuses->GetINT()`.
- Add `$statbonuses->GetINTCapModifier()`.
- Add `$statbonuses->GetIsBlind()`.
- Add `$statbonuses->GetIsFeared()`.
- Add `$statbonuses->GetItemATKCap()`.
- Add `$statbonuses->GetItemHPRegenCap()`.
- Add `$statbonuses->GetItemManaRegenCap()`.
- Add `$statbonuses->GetLimitToSkill(slot)`.
- Add `$statbonuses->GetMagicWeapon()`.
- Add `$statbonuses->GetMana()`.
- Add `$statbonuses->GetManaAbsorbPercentDamage(slot)`.
- Add `$statbonuses->GetManaPercentCap(slot)`.
- Add `$statbonuses->GetManaRegen()`.
- Add `$statbonuses->GetMasteryOfPast()`.
- Add `$statbonuses->GetMaxBindWound()`.
- Add `$statbonuses->GetMaxHP()`.
- Add `$statbonuses->GetMaxHPChange()`.
- Add `$statbonuses->GetMeleeLifetap()`.
- Add `$statbonuses->GetMeleeMitigation()`.
- Add `$statbonuses->GetMeleeMitigationEffect()`.
- Add `$statbonuses->GetMeleeRune(slot)`.
- Add `$statbonuses->GetMeleeSkillCheck()`.
- Add `$statbonuses->GetMeleeSkillCheckSkill()`.
- Add `$statbonuses->GetMeleeThresholdGuard(slot)`.
- Add `$statbonuses->GetMetabolism()`.
- Add `$statbonuses->GetMinimumDamageModifier(slot)`.
- Add `$statbonuses->GetMitigateDOTRune(slot)`.
- Add `$statbonuses->GetMitigateMeleeRune(slot)`.
- Add `$statbonuses->GetMitigateSpellRune(slot)`.
- Add `$statbonuses->GetMovementSpeed()`.
- Add `$statbonuses->GetMR()`.
- Add `$statbonuses->GetMRCapModifier()`.
- Add `$statbonuses->GetNegateAttacks(slot)`.
- Add `$statbonuses->GetNegateEffects()`.
- Add `$statbonuses->GetNegateIfCombat()`.
- Add `$statbonuses->GetNoBreakAESneak()`.
- Add `$statbonuses->GetOffhandRiposteFail()`.
- Add `$statbonuses->GetPackrat()`.
- Add `$statbonuses->GetParryChance()`.
- Add `$statbonuses->GetPCPetFlurry(slot)`.
- Add `$statbonuses->GetPCPetRampage(slot)`.
- Add `$statbonuses->GetPercussionModifier()`.
- Add `$statbonuses->GetPersistentCasting()`.
- Add `$statbonuses->GetPetAvoidance()`.
- Add `$statbonuses->GetPetCriticalHit()`.
- Add `$statbonuses->GetPetFlurry()`.
- Add `$statbonuses->GetPetMaxHP()`.
- Add `$statbonuses->GetPetMeleeMitigation()`.
- Add `$statbonuses->GetPR()`.
- Add `$statbonuses->GetPRCapModifier()`.
- Add `$statbonuses->GetProcChance()`.
- Add `$statbonuses->GetProcChanceSPA()`.
- Add `$statbonuses->GetRaiseSkillCap(slot)`.
- Add `$statbonuses->GetReduceFallDamage()`.
- Add `$statbonuses->GetReduceTradeskillFail(slot)`.
- Add `$statbonuses->GetReflectChance()`.
- Add `$statbonuses->GetResistFearChance()`.
- Add `$statbonuses->GetResistSpellChance()`.
- Add `$statbonuses->GetReverseDamageShield()`.
- Add `$statbonuses->GetReverseDamageShieldSpellID()`.
- Add `$statbonuses->GetReverseDamageShieldType()`.
- Add `$statbonuses->GetRiposteChance()`.
- Add `$statbonuses->GetRoot(slot)`.
- Add `$statbonuses->GetRootBreakChance()`.
- Add `$statbonuses->GetSalvageChance()`.
- Add `$statbonuses->GetSanctuary()`.
- Add `$statbonuses->GetScreech()`.
- Add `$statbonuses->GetSecondaryDamageIncrease()`.
- Add `$statbonuses->GetSeeInvis()`.
- Add `$statbonuses->GetSEResist(slot)`.
- Add `$statbonuses->GetShieldBlock()`.
- Add `$statbonuses->GetShieldEquipDamageModifier()`.
- Add `$statbonuses->GetShroudOfStealth()`.
- Add `$statbonuses->GetSingingModifier()`.
- Add `$statbonuses->GetSkillAttackProc(slot)`.
- Add `$statbonuses->GetSkillDamageAmount(slot)`.
- Add `$statbonuses->GetSkillDamageAmount2(slot)`.
- Add `$statbonuses->GetSkillDamageTaken(slot)`.
- Add `$statbonuses->GetSkillModifier(slot)`.
- Add `$statbonuses->GetSkillModifierMax(slot)`.
- Add `$statbonuses->GetSkillProc(slot)`.
- Add `$statbonuses->GetSkillProcSuccess(slot)`.
- Add `$statbonuses->GetSkillReuseTime(slot)`.
- Add `$statbonuses->GetSlayUndead(slot)`.
- Add `$statbonuses->GetSongModifierCap()`.
- Add `$statbonuses->GetSongRange()`.
- Add `$statbonuses->GetSpellCriticalDamageIncreaseNOStack()`.
- Add `$statbonuses->GetSpellCriticalDamageIncrease()`.
- Add `$statbonuses->GetSpellDamageShield()`.
- Add `$statbonuses->GetSpellDamage()`.
- Add `$statbonuses->GetSpellOnDeath(slot)`.
- Add `$statbonuses->GetSpellOnKill(slot)`.
- Add `$statbonuses->GetSpellProcChance()`.
- Add `$statbonuses->GetSpellShield()`.
- Add `$statbonuses->GetSpellThresholdGuard(slot)`.
- Add `$statbonuses->GetSpellTriggers(slot)`.
- Add `$statbonuses->GetSTA()`.
- Add `$statbonuses->GetSTACapModifier()`.
- Add `$statbonuses->GetSTR()`.
- Add `$statbonuses->GetSTRCapModifier()`.
- Add `$statbonuses->GetStrikeThrough()`.
- Add `$statbonuses->GetStringedModifier()`.
- Add `$statbonuses->GetStunBashChance()`.
- Add `$statbonuses->GetStunResist()`.
- Add `$statbonuses->GetTradeSkillMastery()`.
- Add `$statbonuses->GetTriggerMeleeThreshold()`.
- Add `$statbonuses->GetTriggerOnValueAmount()`.
- Add `$statbonuses->GetTriggerSpellThreshold()`.
- Add `$statbonuses->GetTripleAttackChance()`.
- Add `$statbonuses->GetTripleBackstab()`.
- Add `$statbonuses->GetTwoHandBluntBlock()`.
- Add `$statbonuses->GetUnfailingDivinity()`.
- Add `$statbonuses->GetVampirism()`.
- Add `$statbonuses->GetVoiceGraft()`.
- Add `$statbonuses->GetWindModifier()`.
- Add `$statbonuses->GetWIS()`.
- Add `$statbonuses->GetWISCapModifier()`.
- Add `$statbonuses->GetXPRateModifier()`.

# Notes
- Adds methods to get mob's stat bonuses to Mob methods.
- Adds support for stat bonuses class to Perl similar to Lua.

* Update perl_stat_bonuses.cpp

* Update perl_stat_bonuses.cpp
2023-07-02 10:26:46 -04:00
Alex King e12368f002 [Quest API] Add Hate Entry Methods to Perl (#3459)
# Perl
- Add `$hate_entry->GetFrenzy()`.
- Add `$hate_entry->SetDamage(value)`.
- Add `$hate_entry->SetEnt(mob)`.
- Add `$hate_entry->SetFrenzy(is_frenzy)`.
- Add `$hate_entry->SetHate(value)`.

# Lua
- Convert `hate_entry:GetFrenzy()` to `bool` instead of `int`, as `is_entity_frenzy` is a `bool`.
2023-07-02 10:26:37 -04:00
Alex King a13fa07e68 [Quest API] Add Spawn2 Class to Perl (#3456)
# Perl
- Add `$spawn->Depop()`.
- Add `$spawn->Disable()`.
- Add `$spawn->Enable()`.
- Add `$spawn->ForceDespawn()`.
- Add `$spawn->GetCurrentNPCID()`.
- Add `$spawn->GetHeading()`.
- Add `$spawn->GetID()`.
- Add `$spawn->GetKillCount()`.
- Add `$spawn->GetRespawnTimer()`.
- Add `$spawn->GetSpawnCondition()`.
- Add `$spawn->GetSpawnGroupID()`.
- Add `$spawn->GetVariance()`.
- Add `$spawn->GetX()`.
- Add `$spawn->GetY()`.
- Add `$spawn->GetZ()`.
- Add `$spawn->IsEnabled()`.
- Add `$spawn->IsNPCPointerValid()`.
- Add `$spawn->LoadGrid()`.
- Add `$spawn->Repop()`.
- Add `$spawn->Repop(delay)`.
- Add `$spawn->Reset()`.
- Add `$spawn->SetCurrentNPCID(npc_id)`.
- Add `$spawn->SetNPCPointer(npc_pointer)`.
- Add `$spawn->SetRespawnTimer(new_respawn_time)`.
- Add `$spawn->SetTimer(duration)`.
- Add `$spawn->SetVariance(variance)`.

# Notes
- Adds support for Spawn2 class to Perl.
2023-07-02 10:26:32 -04:00
Chris Miles 7873ad3771 [Database] Set multi statements off when returning early (#3462) 2023-07-01 19:49:09 -04:00
Chris Miles dfadc237e5 [Logging] Fix logging crash when % are sent through query logs (#3461) 2023-07-01 19:49:01 -04:00
Alex King a1f2764978 [Cleanup/Feature] Add support for bots to #showstats/#mystats (#3427)
* Initial Push

* Update classes.cpp

* Update mob.cpp

* Update mob.cpp

* Update showstats.cpp

* Update mystats.cpp

* Remove unused variables.

* Update mob.cpp

* Update class.cpp

* Update race.cpp

* Update mob.h
2023-07-01 19:47:54 -04:00
Jonathan Sider 927d379e75 [Bug Fix] Add check for underscores in botcreate command (#3458)
* Update bot_command.cpp with botcreate check

Check for underscores in bot names as the server will replace with a space and add to the database. The bot can't be deleted/summoned or changed except by editing the database

* Update bot_command.cpp

* Update bot_command.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-06-28 20:18:44 -04:00
Chris Miles a1f154749c [Release] 22.16.0 (#3457) 2023-06-28 17:51:05 -04:00
Alex King 42a2e19e73 [Commands] Consolidate #findX commands to a singular #find Command (#3452)
* Push up example for Kingly

* Update aa.cpp

* Update find.cpp

* Bulk push.

* Update aa.cpp

* Cleanup

* Repository method.

* Static aliasing

* Aliases

* Fix alias error.

* Update zone.cpp

* Update command.cpp

* Update find.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-06-27 21:53:20 -05:00
mibastian c56b2e3e03 [Fix] Fix error in 023_01_21_bots_raid_members.sql (#3453)
world process did not start. An strace showed something wrong in 023_01_21_bots_raid_members.sql.  Seemed like a snap&paste error.
2023-06-27 21:52:27 -05:00
Alex King b05f1d3218 [Bug Fix] Merchant Open Flag set only for regular Merchants (#3454)
* [Bug Fix] Merchant Open Flag set only for regular Merchants

* Update npc.cpp
2023-06-27 16:23:48 -04:00
Alex King a004924112 [Bug Fix] Fix NPC Item Stat Bonuses (#3444)
* [Bug Fix] Fix NPC Item Stat Bonuses

# Notes
- Due to https://github.com/EQEmu/Server/pull/3136 NPCs/Mercs were not receiving stat bonuses from their items, this fixes that.

* Update npc.h

* Changes.

* Cleanup

* Cleanup

* Update loottables.cpp

* Update npc.cpp

* Update loottables.cpp
2023-06-26 00:22:10 -04:00
Alex King 8d986c95cd [Commands] Add #finddeity Command (#3435)
# Notes
- Add `#finddeity` command.
- Remove `ConvertDeityTypeBitToDeityType` as it's unused.
- Rename `ConvertDeityTypeToDeityTypeBit` to `GetDeityBitmask`.
2023-06-25 23:00:32 -05:00
Alex King ef7a3cae17 [Commands] Cleanup #showbuffs Command (#3439)
* [Commands] Cleanup #showbuffs Command

# Notes
- Cleaned up messages and logic.
- Removed unnecessary itembonuses/spellbonuses stuff.
- Removed `Mob::ShowBuffList` as it's just a copy of this method.

* Update mob.cpp

* Further cleanup.

* Update mob.cpp

* Update mob.cpp
2023-06-25 22:59:47 -05:00
Alex King 050aba65b6 [Commands] Cleanup #viewcurrencies Command (#3441)
# Notes
- Utilize Dialogue Window table for cleanliness and readability.
2023-06-24 20:26:41 -04:00
Alex King 9154c90418 [Commands] Add #findlanguage Command (#3434)
# Notes
- Add `#findlanguage` command.
2023-06-24 20:26:29 -04:00
Alex King d558f9ece2 [Rules] Add ClientPetsUserOwnerNameInLastName rule (#3442)
* [Rules] Add ClientPetsUserOwnerNameInLastName rule

# Notes
- This rule defaults to `true` and maintains `Kinglykrab's Pet` as my pet's name, disabling allows you to manually modify the last name or have pets with no last name.

* Update npc.cpp
2023-06-24 20:01:40 -04:00
Alex King 327dacdbe1 [Cleanup] Remove GetACAvoid() from zone/merc.h (#3447)
- This is unused.
2023-06-24 20:00:56 -04:00
Alex King f2ff4245c0 [Commands] Consolidate #merchant_close_shop and #merchant_open_shop to #merchantshop (#3433)
* [Commands] Consolidate #merchant_close_shop and #merchant_open_shop to #merchantshop

# Notes
- `#merchant_close_shop` and `#merchant_open_shop` are now consolidated into `#merchantshop`.
- Command now works on any type of merchant instead of just regular merchants.
- Can be used on Merchants, Discord Merchants, Adventure Merchants, Norrath's Keepers Merchants, Dark Reign Merchants, and Alternate Currency Merchants.

* Update merchantshop.cpp

* Update merchantshop.cpp

* Update merchantshop.cpp
2023-06-24 13:14:19 -05:00
Alex King 3ceb743195 [Commands] Add #showspells Command (#3429)
* [Commands] Add #showspells Command

# Notes
- Add `#showspells` command to show your or your target's memorized spells or learned disciplines.

* Update client.cpp
2023-06-24 13:13:02 -05:00
Alex King 021f04c17d [Cleanup] Remove command_unlock from zone/command.h (#3431)
# Notes
- This is unused.
2023-06-24 13:10:19 -05:00
Alex King f7e2dbdce6 [Cleanup] Remove command_packetprofile from zone/command.h (#3432)
* [Cleanup] Remove command_packetprofile from zone/command.h

# Notes
- This is unused.

* Update command.h
2023-06-24 13:10:05 -05:00
Alex King 2a679f1002 [Cleanup] Remove command_showpetspell in zone/command.h (#3430)
# Notes
- This is unused.
2023-06-24 13:09:51 -05:00
Alex King 8c9849ec73 [Commands] Delete #showbonusstats Command (#3437)
# Notes
- Never seen this used, also missing 99% of the bonuses data.
2023-06-24 13:09:39 -05:00
Alex King 10086ce97c [Commands] Delete #spellinfo Command (#3438)
# Notes
- Never seen this used, also missing 99% of the spell data.
2023-06-24 13:09:23 -05:00
Alex King 223ae22f73 [Cleanup] Delete common/worldconn.cpp (#3436)
# Notes
- This is unused.
2023-06-24 13:05:45 -05:00
Alex King 4330494f57 [Commands] Cleanup #shownpcgloballoot and #showzonegloballoot Commands (#3440)
# Notes
- Cleanup messages and logic.
- Utilize Dialogue Window tables.
2023-06-24 13:03:37 -05:00
Alex King 64ae7e4529 [Cleanup] Remove _ClearWaypints() from zone/npc.h (#3445)
# Notes
- This is unused.
2023-06-24 12:58:28 -05:00
Alex King 58c3e267e1 [Cleanup] Remove GetACMit() from zone/merc.h (#3446)
# Notes
- This is unused.
2023-06-24 12:58:13 -05:00
Alex King 598483a1a4 [Cleanup] Remove acmod() from zone/merc.h (#3448)
# Notes
- This is unused.
2023-06-24 12:57:43 -05:00
Alex King c1122022b9 [Cleanup] Remove DatabaseCastAccepted() from zone/npc.cpp and zone/npc.h (#3449)
* [Cleanup] Remove DatabaseCastAccepted() from zone/npc.cpp and zone/npc.h

# Notes
- This is unused.

* Update npc.h
2023-06-24 12:57:21 -05:00
Chris Miles f2c4babd8d [Database] Fix database version checking edge case issue (#3428) 2023-06-22 18:00:23 -05:00
Akkadius 5249b065d3 [Release] 22.15.3 2023-06-19 19:15:42 -05:00
Alex King 9312261444 [Bug Fix] Fix improper condition in Water LOS checks (#3426)
# Notes
- Oversight on my part, should've been `==`, not `&&`.
2023-06-19 18:53:19 -04:00
Akkadius 85054fedf8 [Release] 22.15.2 (Hotfix) 2023-06-19 12:00:41 -05:00
Chris Miles 6d7beb1796 [Database] Fix multi-statement error reporting (#3425) 2023-06-19 11:55:32 -05:00
JJ 66e377fd4a [Readme] Update new location of database updates (#3424) 2023-06-19 12:12:59 -04:00
Akkadius 67c4c26f70 [Release] 22.15.1 2023-06-19 02:21:09 -05:00
Akkadius b1c8e3890a [Release] 22.15.0 2023-06-19 01:41:55 -05:00
Alex King d6e06a19a7 [Commands] Add missing subcommands to #npcedit (#3423)
# Notes
- Add `#npcedit model [Race ID]` to edit an NPC's race model.
- Add `#npcedit heroic_strikethrough [Heroic Strikethrough]` to edit an NPC's heroic strikethrough.
- Add `#npcedit faction_amount [Faction Amount]` to edit an NPC's faction amount.
2023-06-19 01:40:27 -05:00
Akkadius 4092b3a2cb [Release] 22.15.0 2023-06-19 01:38:12 -05:00
Alex King f4f0619618 [Bug Fix] Fix possible crash with #npcedit weapon (#3421)
# Notes
- Using `#npcedit weapon` without the secondary model had a chance to crash the zone you were in, i.e `#npcedit weapon 1`.

# Crash Logs
```txt
[06-18-2023 16:26:55] [Zone] [Crash] [New LWP 802548]
[06-18-2023 16:26:55] [Zone] [Crash] [New LWP 802549]
[06-18-2023 16:26:55] [Zone] [Crash] [New LWP 802550]
[06-18-2023 16:26:55] [Zone] [Crash] [New LWP 802551]
[06-18-2023 16:26:55] [Zone] [Crash] [Thread debugging using libthread_db enabled]
[06-18-2023 16:26:55] [Zone] [Crash] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[06-18-2023 16:26:55] [Zone] [Crash] 0x00007f22b2b14207 in __GI___wait4 (pid=819104, stat_loc=0x0, options=0, usage=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:27
[06-18-2023 16:26:55] [Zone] [Crash] [Current thread is 1 (Thread 0x7f22b29eab00 (LWP 802540))]
[06-18-2023 16:26:55] [Zone] [Crash] #0  0x00007f22b2b14207 in __GI___wait4 (pid=819104, stat_loc=0x0, options=0, usage=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:27
[06-18-2023 16:26:55] [Zone] [Crash] #1  0x000055e4451b6b6e in print_trace () at /home/eqemu/code/common/crash.cpp:281
[06-18-2023 16:26:55] [Zone] [Crash] #2  <signal handler called>
[06-18-2023 16:26:55] [Zone] [Crash] #3  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
[06-18-2023 16:26:55] [Zone] [Crash] #4  0x00007f22b2a6e537 in __GI_abort () at abort.c:79
[06-18-2023 16:26:55] [Zone] [Crash] #5  0x00007f22b2e067ec in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:26:55] [Zone] [Crash] #6  0x00007f22b2e11966 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:26:55] [Zone] [Crash] #7  0x00007f22b2e119d1 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:26:55] [Zone] [Crash] #8  0x00007f22b2e11c65 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:26:55] [Zone] [Crash] #9  0x00007f22b2e08faa in std::__throw_logic_error(char const*) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:26:55] [Zone] [Crash] #10 0x000055e444216b48 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*> (this=0x7fff9bd06620, __beg=0x0, __end=0xffffffffffffffff <error: Cannot access memory at address 0xffffffffffffffff>) at /usr/include/c++/10/bits/basic_string.tcc:212
[06-18-2023 16:26:55] [Zone] [Crash] #11 0x000055e44420dd09 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char const*> (this=0x7fff9bd06620, __beg=0x0, __end=0xffffffffffffffff <error: Cannot access memory at address 0xffffffffffffffff>) at /usr/include/c++/10/bits/basic_string.h:247
[06-18-2023 16:26:55] [Zone] [Crash] #12 0x000055e444203977 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*> (this=0x7fff9bd06620, __beg=0x0, __end=0xffffffffffffffff <error: Cannot access memory at address 0xffffffffffffffff>) at /usr/include/c++/10/bits/basic_string.h:266
[06-18-2023 16:26:55] [Zone] [Crash] #13 0x000055e4441f93ef in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> > (this=0x7fff9bd06620, __s=0x0, __a=...) at /usr/include/c++/10/bits/basic_string.h:527
[06-18-2023 16:26:55] [Zone] [Crash] #14 0x000055e4445469df in command_npcedit (c=0x55e448292480, sep=0x7fff9bd09a20) at /home/eqemu/code/zone/gm_commands/npcedit.cpp:540
[06-18-2023 16:26:55] [Zone] [Crash] #15 0x000055e4444e2039 in command_realdispatch (c=0x55e448292480, message="#npcedit weapon 1", ignore_status=false) at /home/eqemu/code/zone/command.cpp:602
[06-18-2023 16:26:55] [Zone] [Crash] #16 0x000055e4443b03d3 in Client::ChannelMessageReceived (this=0x55e448292480, chan_num=8 '\b', language=0 '\000', lang_skill=100 'd', orig_message=0x55e44a69e314 "#npcedit weapon 1", targetname=0x55e44a69e280 "a_willowisp000", is_silent=false) at /home/eqemu/code/zone/client.cpp:1122
[06-18-2023 16:26:55] [Zone] [Crash] #17 0x000055e444454597 in Client::Handle_OP_ChannelMessage (this=0x55e448292480, app=0x55e449156a70) at /home/eqemu/code/zone/client_packet.cpp:4478
[06-18-2023 16:26:55] [Zone] [Crash] #18 0x000055e44443c5d2 in Client::HandlePacket (this=0x55e448292480, app=0x55e449156a70) at /home/eqemu/code/zone/client_packet.cpp:495
[06-18-2023 16:26:55] [Zone] [Crash] #19 0x000055e4444b7add in Client::Process (this=0x55e448292480) at /home/eqemu/code/zone/client_process.cpp:587
[06-18-2023 16:26:55] [Zone] [Crash] #20 0x000055e44472df12 in EntityList::MobProcess (this=0x55e445df07c0 <entity_list>) at /home/eqemu/code/zone/entity.cpp:510
[06-18-2023 16:26:55] [Zone] [Crash] #21 0x000055e444c149b0 in operator() (__closure=0x55e448dc9170, t=0x7fff9bd0c4a0) at /home/eqemu/code/zone/main.cpp:562
[06-18-2023 16:26:55] [Zone] [Crash] #22 0x000055e444c19fd2 in std::__invoke_impl<void, main(int, char**)::<lambda(EQ::Timer*)>&, EQ::Timer*>(std::__invoke_other, struct {...} &) (__f=...) at /usr/include/c++/10/bits/invoke.h:60
[06-18-2023 16:26:55] [Zone] [Crash] #23 0x000055e444c19da1 in std::__invoke_r<void, main(int, char**)::<lambda(EQ::Timer*)>&, EQ::Timer*>(struct {...} &) (__fn=...) at /usr/include/c++/10/bits/invoke.h:110
[06-18-2023 16:26:55] [Zone] [Crash] #24 0x000055e444c19ac8 in std::_Function_handler<void(EQ::Timer*), main(int, char**)::<lambda(EQ::Timer*)> >::_M_invoke(const std::_Any_data &, EQ::Timer *&&) (__functor=..., __args#0=@0x7fff9bd0bea0: 0x7fff9bd0c4a0) at /usr/include/c++/10/bits/std_function.h:291
[06-18-2023 16:26:55] [Zone] [Crash] #25 0x000055e444c1f4c5 in std::function<void (EQ::Timer*)>::operator()(EQ::Timer*) const (this=0x7fff9bd0c4a8, __args#0=0x7fff9bd0c4a0) at /usr/include/c++/10/bits/std_function.h:622
[06-18-2023 16:26:55] [Zone] [Crash] #26 0x000055e444c1d265 in EQ::Timer::Execute (this=0x7fff9bd0c4a0) at /home/eqemu/code/zone/../common/net/../event/timer.h:61
[06-18-2023 16:26:55] [Zone] [Crash] #27 0x000055e444c1d023 in EQ::Timer::Start(unsigned long, bool)::{lambda(uv_timer_s*)#1}::operator()(uv_timer_s*) const (__closure=0x0, handle=0x55e44832b570) at /home/eqemu/code/zone/../common/net/../event/timer.h:38
[06-18-2023 16:26:55] [Zone] [Crash] #28 0x000055e444c1d043 in EQ::Timer::Start(unsigned long, bool)::{lambda(uv_timer_s*)#1}::_FUN(uv_timer_s*) () at /home/eqemu/code/zone/../common/net/../event/timer.h:39
[06-18-2023 16:26:55] [Zone] [Crash] #29 0x000055e4454afb5d in uv__run_timers (loop=loop@entry=0x7f22b29ea7a8) at /home/eqemu/code/submodules/libuv/src/timer.c:178
[06-18-2023 16:26:55] [Zone] [Crash] #30 0x000055e4454b3182 in uv_run (loop=0x7f22b29ea7a8, mode=UV_RUN_DEFAULT) at /home/eqemu/code/submodules/libuv/src/unix/core.c:393
[06-18-2023 16:26:55] [Zone] [Crash] #31 0x000055e444c1ceeb in EQ::EventLoop::Run (this=0x7f22b29ea7a8) at /home/eqemu/code/zone/../common/net/../event/event_loop.h:25
[06-18-2023 16:26:55] [Zone] [Crash] #32 0x000055e444c18b6e in main (argc=1, argv=0x7fff9bd0d568) at /home/eqemu/code/zone/main.cpp:591
[06-18-2023 16:26:55] [Zone] [Crash] [Inferior 1 (process 802540) detached]
```

```txt
[06-18-2023 16:29:51] [Zone] [Crash] [New LWP 819434]
[06-18-2023 16:29:51] [Zone] [Crash] [New LWP 819436]
[06-18-2023 16:29:51] [Zone] [Crash] [New LWP 819438]
[06-18-2023 16:29:51] [Zone] [Crash] [New LWP 819440]
[06-18-2023 16:29:51] [Zone] [Crash] [Thread debugging using libthread_db enabled]
[06-18-2023 16:29:51] [Zone] [Crash] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[06-18-2023 16:29:51] [Zone] [Crash] 0x00007f489d185207 in __GI___wait4 (pid=819646, stat_loc=0x0, options=0, usage=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:27
[06-18-2023 16:29:51] [Zone] [Crash] [Current thread is 1 (Thread 0x7f489d05bb00 (LWP 819417))]
[06-18-2023 16:29:51] [Zone] [Crash] #0  0x00007f489d185207 in __GI___wait4 (pid=819646, stat_loc=0x0, options=0, usage=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:27
[06-18-2023 16:29:51] [Zone] [Crash] #1  0x000055d58e442b6e in print_trace () at /home/eqemu/code/common/crash.cpp:281
[06-18-2023 16:29:51] [Zone] [Crash] #2  <signal handler called>
[06-18-2023 16:29:51] [Zone] [Crash] #3  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
[06-18-2023 16:29:51] [Zone] [Crash] #4  0x00007f489d0df537 in __GI_abort () at abort.c:79
[06-18-2023 16:29:51] [Zone] [Crash] #5  0x00007f489d4777ec in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:29:51] [Zone] [Crash] #6  0x00007f489d482966 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:29:51] [Zone] [Crash] #7  0x00007f489d4829d1 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:29:51] [Zone] [Crash] #8  0x00007f489d482c65 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:29:51] [Zone] [Crash] #9  0x00007f489d479faa in std::__throw_logic_error(char const*) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
[06-18-2023 16:29:51] [Zone] [Crash] #10 0x000055d58d4a2b48 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*> (this=0x7ffdbbca2500, __beg=0x0, __end=0xffffffffffffffff <error: Cannot access memory at address 0xffffffffffffffff>) at /usr/include/c++/10/bits/basic_string.tcc:212
[06-18-2023 16:29:51] [Zone] [Crash] #11 0x000055d58d499d09 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char const*> (this=0x7ffdbbca2500, __beg=0x0, __end=0xffffffffffffffff <error: Cannot access memory at address 0xffffffffffffffff>) at /usr/include/c++/10/bits/basic_string.h:247
[06-18-2023 16:29:51] [Zone] [Crash] #12 0x000055d58d48f977 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*> (this=0x7ffdbbca2500, __beg=0x0, __end=0xffffffffffffffff <error: Cannot access memory at address 0xffffffffffffffff>) at /usr/include/c++/10/bits/basic_string.h:266
[06-18-2023 16:29:51] [Zone] [Crash] #13 0x000055d58d4853ef in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> > (this=0x7ffdbbca2500, __s=0x0, __a=...) at /usr/include/c++/10/bits/basic_string.h:527
[06-18-2023 16:29:51] [Zone] [Crash] #14 0x000055d58d7d29df in command_npcedit (c=0x55d59219f080, sep=0x7ffdbbca5900) at /home/eqemu/code/zone/gm_commands/npcedit.cpp:540
[06-18-2023 16:29:51] [Zone] [Crash] #15 0x000055d58d76e039 in command_realdispatch (c=0x55d59219f080, message="#npcedit weapon 1", ignore_status=false) at /home/eqemu/code/zone/command.cpp:602
[06-18-2023 16:29:51] [Zone] [Crash] #16 0x000055d58d63c3d3 in Client::ChannelMessageReceived (this=0x55d59219f080, chan_num=8 '\b', language=0 '\000', lang_skill=100 'd', orig_message=0x55d591b59b44 "#npcedit weapon 1", targetname=0x55d591b59ab0 "a_whiskered_bat002", is_silent=false) at /home/eqemu/code/zone/client.cpp:1122
[06-18-2023 16:29:51] [Zone] [Crash] #17 0x000055d58d6e0597 in Client::Handle_OP_ChannelMessage (this=0x55d59219f080, app=0x55d592711c60) at /home/eqemu/code/zone/client_packet.cpp:4478
[06-18-2023 16:29:51] [Zone] [Crash] #18 0x000055d58d6c85d2 in Client::HandlePacket (this=0x55d59219f080, app=0x55d592711c60) at /home/eqemu/code/zone/client_packet.cpp:495
[06-18-2023 16:29:51] [Zone] [Crash] #19 0x000055d58d743add in Client::Process (this=0x55d59219f080) at /home/eqemu/code/zone/client_process.cpp:587
[06-18-2023 16:29:51] [Zone] [Crash] #20 0x000055d58d9b9f12 in EntityList::MobProcess (this=0x55d58f07c7c0 <entity_list>) at /home/eqemu/code/zone/entity.cpp:510
[06-18-2023 16:29:51] [Zone] [Crash] #21 0x000055d58dea09b0 in operator() (__closure=0x55d591a07f10, t=0x7ffdbbca8380) at /home/eqemu/code/zone/main.cpp:562
[06-18-2023 16:29:51] [Zone] [Crash] #22 0x000055d58dea5fd2 in std::__invoke_impl<void, main(int, char**)::<lambda(EQ::Timer*)>&, EQ::Timer*>(std::__invoke_other, struct {...} &) (__f=...) at /usr/include/c++/10/bits/invoke.h:60
[06-18-2023 16:29:51] [Zone] [Crash] #23 0x000055d58dea5da1 in std::__invoke_r<void, main(int, char**)::<lambda(EQ::Timer*)>&, EQ::Timer*>(struct {...} &) (__fn=...) at /usr/include/c++/10/bits/invoke.h:110
[06-18-2023 16:29:51] [Zone] [Crash] #24 0x000055d58dea5ac8 in std::_Function_handler<void(EQ::Timer*), main(int, char**)::<lambda(EQ::Timer*)> >::_M_invoke(const std::_Any_data &, EQ::Timer *&&) (__functor=..., __args#0=@0x7ffdbbca7d80: 0x7ffdbbca8380) at /usr/include/c++/10/bits/std_function.h:291
[06-18-2023 16:29:51] [Zone] [Crash] #25 0x000055d58deab4c5 in std::function<void (EQ::Timer*)>::operator()(EQ::Timer*) const (this=0x7ffdbbca8388, __args#0=0x7ffdbbca8380) at /usr/include/c++/10/bits/std_function.h:622
[06-18-2023 16:29:51] [Zone] [Crash] #26 0x000055d58dea9265 in EQ::Timer::Execute (this=0x7ffdbbca8380) at /home/eqemu/code/zone/../common/net/../event/timer.h:61
[06-18-2023 16:29:51] [Zone] [Crash] #27 0x000055d58dea9023 in EQ::Timer::Start(unsigned long, bool)::{lambda(uv_timer_s*)#1}::operator()(uv_timer_s*) const (__closure=0x0, handle=0x55d590f6a610) at /home/eqemu/code/zone/../common/net/../event/timer.h:38
[06-18-2023 16:29:51] [Zone] [Crash] #28 0x000055d58dea9043 in EQ::Timer::Start(unsigned long, bool)::{lambda(uv_timer_s*)#1}::_FUN(uv_timer_s*) () at /home/eqemu/code/zone/../common/net/../event/timer.h:39
[06-18-2023 16:29:51] [Zone] [Crash] #29 0x000055d58e73bb5d in uv__run_timers (loop=loop@entry=0x7f489d05b7a8) at /home/eqemu/code/submodules/libuv/src/timer.c:178
[06-18-2023 16:29:51] [Zone] [Crash] #30 0x000055d58e73f182 in uv_run (loop=0x7f489d05b7a8, mode=UV_RUN_DEFAULT) at /home/eqemu/code/submodules/libuv/src/unix/core.c:393
[06-18-2023 16:29:51] [Zone] [Crash] #31 0x000055d58dea8eeb in EQ::EventLoop::Run (this=0x7f489d05b7a8) at /home/eqemu/code/zone/../common/net/../event/event_loop.h:25
[06-18-2023 16:29:51] [Zone] [Crash] #32 0x000055d58dea4b6e in main (argc=1, argv=0x7ffdbbca9448) at /home/eqemu/code/zone/main.cpp:591
[06-18-2023 16:29:51] [Zone] [Crash] [Inferior 1 (process 819417) detached]
```
2023-06-19 01:32:36 -05:00
Alex King 71ca7f9b39 [Cleanup] Default skill type to Hand to Hand in #npcedit meleetype (#3422)
# Notes
- We default to `28` in the database, so we need to default to this in `#npcedit meleetype` in case the operator only sets the first melee type this avoids the NPC hitting with `1H Blunt (Skill ID 0)`.
2023-06-19 01:32:13 -05:00
Chris Miles 5fcc83b4b6 [Database] Implement native database migrations in server (#2857)
* [Database] Implement native database updates in server

* Cleanup

* Delete db_update_manifest.txt

* Bots updates

* Final tweaks

* Revert manifest

* Tweaks

* Remove code from eqemu_server.pl

* Update database_update.cpp

* Add user prompt update skipping with timeouts

* Add termcolor IS_TTY is check

* Update database_conversions.cpp

* Remove large migrations

* Push

* fix headers.

* Remove last of non-bot large migrations

* Update database_update_manifest.cpp

* More purging

* Tweaks

* Bot migrations

* More work

* Tweaks

* Implement multi-statement query execution only for migrations

* Add CLI database:updates

* Add bootstrap commands

* Upload bootstrap sql's

* Update bot_tables_bootstrap.sql

* Update bot_tables_bootstrap.sql

* Add mercs:bootstrap and bots:bootstrap

* Update bot_tables_bootstrap.sql

* Update database.cpp

* Update bot_tables_bootstrap.sql

* More cleanup

* Add mercs:disable and bots:disable

* Update eqemu_server.pl

* Update eqemu_server.pl

* Update eqemu_server.pl

* Test cases

* Update eqemu_server.pl

* Delete 2023_05_08_character_tribute_primary_key.sql

* Post rebase fixes

* Post rebase tweaks

* Delete errant files

* Rebase files from master

* More adjustments

* Delete files no longer used

* Add missing migrations

* bots:bootstrap is now bots:enable

---------

Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
2023-06-19 01:31:07 -05:00
Chris Miles 1f25639dd3 [Release] 22.14.1 (#3420) 2023-06-18 15:38:50 -05:00
Chris Miles 2a176835b1 [CI] Build static linux binaries (#3419)
* [CI] Build static linux binaries

* Fix tests

* Update linux-build.sh
2023-06-18 15:19:25 -05:00
Chris Miles fff3e77a6e [Binaries] Add support for static linking (portable) binaries (#3417)
* [Binaries] Add support for static linking (portable) binaries

* Update CMakeLists.txt
2023-06-18 14:41:39 -05:00
Alex King 6efb9ec228 [Quest API] Add convert_money_to_string() to Perl/Lua (#3418)
* [Quest API] Add convert_money_to_string() to Perl/Lua

# Perl
- Add `quest::convert_money_to_string(money_hash)`.

# Lua
- Add `eq.convert_money_to_string(money_table)`.

# Notes
- Allows operators to convert money in to a readable string using `Strings::Money`.

# Examples

## Perl
```pl
sub EVENT_SAY {
	if ($text=~/#a/i) {
		my %money_data = (
			"platinum" => 3123,
			"gold" => 5692,
			"copper" => 9
		);
		quest::message(315, quest::convert_money_to_string(%money_data));
	}
}
```

## Lua
```lua
function event_say(e)
	if e.message:find("#a") then
		local money_data = {
			gold = 12,
			silver = 523904,
			copper = 3
		}
		eq.message(315, "Lua: " .. eq.convert_money_to_string(money_data))
	end
end```

* Update lua_general.cpp
2023-06-18 15:29:14 -04:00
Chris Miles a663c822e8 [CLI] Add mercs:enable and mercs:disable commands (#3416)
* [CLI] Add `mercs:enable` and `mercs:disable` commands

* Update descriptions
2023-06-17 19:30:36 -05:00
Chris Miles cf49b2fe49 [CLI] Add bots:enable and bots:disable commands (#3415)
* [CLI] Add `bots:enable` and `bots:disable` commands

* Add input warning
2023-06-17 18:48:47 -05:00
Chris Miles b45e0e80b5 [Database] Add query multi statement execution support (#3414) 2023-06-17 18:20:13 -05:00
Chris Miles 3200145d01 [CLI] Console menu validation fixes (#3413) 2023-06-17 18:19:55 -05:00
Chris Miles 53563b9720 [Backups] Move world database:dump to use MySQL credentials file (#3410) 2023-06-17 18:16:29 -05:00
Chris Miles 1e22baf267 [Logging] Logging improvements, console silencing, terminal coloring (#3412) 2023-06-17 18:16:21 -05:00
Chris Miles d99c3145ad [Strings] Add more test cases for string utils (#3411) 2023-06-17 18:16:14 -05:00
Alex King 57243c6799 [Telnet] Add cross zone/world wide cast and move functionality to Telnet (#3409)
* [Telnet] Add cross zone/world wide cast and move functionality to Telnet

# Notes
- Add `czcast`, `czmove`, `wwcast`, and `wwmove` to Telnet functionality.
- Allows operators to cast spells across zone/world-wide and move players across zone/world-wide from telnet.

* Update console.cpp

* Update console.cpp

* Validation

* Update console.cpp
2023-06-17 17:50:37 -05:00
Paul Coene 1100668f21 [Targeting] Fix bug when using /tar on invalid target (#3407)
* [Targetting] Fix bug when using /tar on invalid target

* Removed instrumentation.
2023-06-17 16:53:59 -05:00
nytmyr 0cf454dc29 [Feature] Add Water Line of Sight Checks (#3408)
* [Feature] Add Water Line of Sight Checks

This adds rules to enable or disable checks for spells and autofire to prevent casting or autofire from landing if the player or bot do not match their targets plane in regards to water.

Currently players and bots can cast or autofire if they are not in the water but their target is and vice versa, this should not be possible.

RuleB(Combat, WaterMatchRequiredForAutoFireLoS) set to True (default) checks that both parties are in or out of the water for AutoFire to work.

RuleB(Spells, WaterMatchRequiredForLoS) set to True (default) checks that both parties are in or out of the water for spells to land.

* Cleanup.

* Cleanup.

* Cleanup.

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-06-17 12:32:15 -05:00
Paul Coene 75391d96f4 [Release] 22.13.1 (#3406)
* Update version.h for /target Emergency release 22.13.1

* Update CHANGELOG.md for 22.13.1 release

* Update package.json for 22.13.1 emergency patch release

* Update CHANGELOG.md using tool as instructed
2023-06-13 17:50:33 -04:00
Paul Coene 81b07a5aa0 [Targeting] Revert #3383 (#3405) 2023-06-13 15:48:35 -05:00
Alex King 774aa99b29 [Release] 22.13.0 (#3404)
* [Release] 22.13.0

* Update CHANGELOG.md
2023-06-12 20:56:43 -04:00
Alex King 756e835144 [Quest API/Cleanup] Add several spell methods to Perl/Lua (#3379)
* [Quest API/Cleanup] Add several spell methods to Perl/Lua

- Add `quest::CalculateCorruptionCounters(spell_id)`.
- Add `quest::CalculateCounters(spell_id)`.
- Add `quest::CalculateCurseCounters(spell_id)`.
- Add `quest::CalculateDiseaseCounters(spell_id)`.
- Add `quest::CalculatePoisonCounters(spell_id)`.
- Add `quest::GetSpellEffectDescriptionNumber(spell_id)`.
- Add `quest::GetSpellEffectIndex(spell_id, effect_id)`.
- Add `quest::GetSpellFuriousBash(spell_id)`.
- Add `quest::GetSpellMinimumLevel(spell_id)`.
- Add `quest::GetSpellNimbusEffect(spell_id)`.
- Add `quest::GetSpellPartialMagicRuneAmount(spell_id)`.
- Add `quest::GetSpellPartialMagicRuneReduction(spell_id)`.
- Add `quest::GetSpellPartialMeleeRuneAmount(spell_id)`.
- Add `quest::GetSpellPartialMeleeRuneReduction(spell_id)`.
- Add `quest::GetSpellProcLimitTimer(spell_id)`.
- Add `quest::GetSpellResistType(spell_id)`.
- Add `quest::GetSpellResurrectionSicknessCheck(spell_id_one, spell_id_two)`.
- Add `quest::GetSpellTargetType(spell_id)`.
- Add `quest::GetSpellTriggerSpellID(spell_id)`.
- Add `quest::GetSpellViralMaximumSpreadTime(spell_id)`.
- Add `quest::GetSpellViralMinimumSpreadTime(spell_id)`.
- Add `quest::GetSpellViralSpreadRange(spell_id)`.
- Add `quest::IsAEDurationSpell(spell_id)`.
- Add `quest::IsAENukeSpell(spell_id)`.
- Add `quest::IsAERainNukeSpell(spell_id)`.
- Add `quest::IsAllianceSpell(spell_id)`.
- Add `quest::IsBardOnlyStackEffect(effect_id)`.
- Add `quest::IsBardSong(spell_id)`.
- Add `quest::IsBlankSpellEffect(spell_id, effect_index)`.
- Add `quest::IsBlindSpell(spell_id)`.
- Add `quest::IsBuffSpell(spell_id)`.
- Add `quest::IsCastNotStandingSpell(spell_id)`.
- Add `quest::IsCastOnFadeDurationSpell(spell_id)`.
- Add `quest::IsCastRestrictedSpell(spell_id)`.
- Add `quest::IsCastTimeReductionSpell(spell_id)`.
- Add `quest::IsCastWhileInvisibleSpell(spell_id)`.
- Add `quest::IsCharmSpell(spell_id)`.
- Add `quest::IsCombatSkill(spell_id)`.
- Add `quest::IsCompleteHealDurationSpell(spell_id)`.
- Add `quest::IsCompleteHealSpell(spell_id)`.
- Add `quest::IsCureSpell(spell_id)`.
- Add `quest::IsDamageSpell(spell_id)`.
- Add `quest::IsDeathSaveSpell(spell_id)`.
- Add `quest::IsDebuffSpell(spell_id)`.
- Add `quest::IsDetrimentalSpell(spell_id)`.
- Add `quest::IsDiscipline(spell_id)`.
- Add `quest::IsDisciplineBuff(spell_id)`.
- Add `quest::IsDiseaseCounterSpell(spell_id)`.
- Add `quest::IsDistanceModifierSpell(spell_id)`.
- Add `quest::IsEffectIgnoredInStacking(effect_id)`.
- Add `quest::IsFastHealSpell(spell_id)`.
- Add `quest::IsFearSpell(spell_id)`.
- Add `quest::IsFocusLimit(effect_id)`.
- Add `quest::IsFullDeathSaveSpell(spell_id)`.
- Add `quest::IsGateSpell(spell_id)`.
- Add `quest::IsImprovedDamageSpell(spell_id)`.
- Add `quest::IsImprovedHealingSpell(spell_id)`.
- Add `quest::IsIncreaseDurationSpell(spell_id)`.
- Add `quest::IsIncreaseRangeSpell(spell_id)`.
- Add `quest::IsInstrumentModifierAppliedToSpellEffect(spell_id, effect_id)`.
- Add `quest::IsInvisibleSpell(spell_id)`.
- Add `quest::IsInvulnerabilitySpell(spell_id)`.
- Add `quest::IsLDoNObjectSpell(spell_id)`.
- Add `quest::IsLifetapSpell(spell_id)`.
- Add `quest::IsMagicRuneSpell(spell_id)`.
- Add `quest::IsManaCostReductionSpell(spell_id)`.
- Add `quest::IsManaTapSpell(spell_id)`.
- Add `quest::IsMesmerizeSpell(spell_id)`.
- Add `quest::IsNoDetrimentalSpellAggroSpell(spell_id)`.
- Add `quest::IsPBAENukeSpell(spell_id)`.
- Add `quest::IsPartialDeathSaveSpell(spell_id)`.
- Add `quest::IsPartialResistableSpell(spell_id)`.
- Add `quest::IsPercentalHealSpell(spell_id)`.
- Add `quest::IsPersistDeathSpell(spell_id)`.
- Add `quest::IsPetSpell(spell_id)`.
- Add `quest::IsPoisonCounterSpell(spell_id)`.
- Add `quest::IsPulsingBardSong(spell_id)`.
- Add `quest::IsPureNukeSpell(spell_id)`.
- Add `quest::IsRegularGroupHealSpell(spell_id)`.
- Add `quest::IsRegularSingleTargetHealSpell(spell_id)`.
- Add `quest::IsResistDebuffSpell(spell_id)`.
- Add `quest::IsResistableSpell(spell_id)`.
- Add `quest::IsRestAllowedSpell(spell_id)`.
- Add `quest::IsResurrectionEffects(spell_id)`.
- Add `quest::IsRuneSpell(spell_id)`.
- Add `quest::IsRunning(spell_id)`.
- Add `quest::IsSacrificeSpell(spell_id)`.
- Add `quest::IsSelfConversionSpell(spell_id)`.
- Add `quest::IsShadowStepSpell(spell_id)`.
- Add `quest::IsShortDurationBuff(spell_id)`.
- Add `quest::IsSpellUsableInThisZoneType(spell_id)`.
- Add `quest::IsSpellUsableInThisZoneType(spell_id, zone_type)`.
- Add `quest::IsStackableDOT(spell_id)`.
- Add `quest::IsStunSpell(spell_id)`.
- Add `quest::IsSuccorSpell(spell_id)`.
- Add `quest::IsSummonItemSpell(spell_id)`.
- Add `quest::IsSummonPCSpell(spell_id)`.
- Add `quest::IsSummonPetSpell(spell_id)`.
- Add `quest::IsSummonSkeletonSpell(spell_id)`.
- Add `quest::IsSummonSpell(spell_id)`.
- Add `quest::IsSuspendableSpell(spell_id)`.
- Add `quest::IsTargetRequiredForSpell(spell_id)`.
- Add `quest::IsTargetableAESpell(spell_id)`.
- Add `quest::IsTeleportSpell(spell_id)`.
- Add `quest::IsTranslocateSpell(spell_id)`.
- Add `quest::IsValidSpell(spell_id)`.
- Add `quest::IsVeryFastHealSpell(spell_id)`.
- Add `quest::IsVirusSpell(spell_id)`.

- Add `eq.calculate_corruption_counters(spell_id)`.
- Add `eq.calculate_counters(spell_id)`.
- Add `eq.calculate_curse_counters(spell_id)`.
- Add `eq.calculate_disease_counters(spell_id)`.
- Add `eq.calculate_poison_counters(spell_id)`.
- Add `eq.get_spell_effect_description_number(spell_id)`.
- Add `eq.get_spell_effect_index(spell_id, effect_id)`.
- Add `eq.get_spell_furious_bash(spell_id)`.
- Add `eq.get_spell_level(spell_id, class_id)`.
- Add `eq.get_spell_minimum_level(spell_id)`.
- Add `eq.get_spell_nimbus_effect(spell_id)`.
- Add `eq.get_spell_partial_magic_rune_amount(spell_id)`.
- Add `eq.get_spell_partial_magic_rune_reduction(spell_id)`.
- Add `eq.get_spell_partial_melee_rune_amount(spell_id)`.
- Add `eq.get_spell_partial_melee_rune_reduction(spell_id)`.
- Add `eq.get_spell_proc_limit_timer(spell_id)`.
- Add `eq.get_spell_resist_type(spell_id)`.
- Add `eq.get_spell_resurrection_sickness_check(spell_id_one, spell_id_two)`.
- Add `eq.get_spell_target_type(spell_id)`.
- Add `eq.get_spell_trigger_spell_id(spell_id)`.
- Add `eq.get_spell_viral_maximum_spread_time(spell_id)`.
- Add `eq.get_spell_viral_minimum_spread_time(spell_id)`.
- Add `eq.get_spell_viral_spread_range(spell_id)`.
- Add `eq.is_ae_duration_spell(spell_id)`.
- Add `eq.is_ae_nuke_spell(spell_id)`.
- Add `eq.is_ae_rain_nuke_spell(spell_id)`.
- Add `eq.is_alliance_spell(spell_id)`.
- Add `eq.is_bard_only_stack_effect(spell_id)`.
- Add `eq.is_bard_song(spell_id)`.
- Add `eq.is_beneficial_spell(spell_id)`.
- Add `eq.is_blank_spell_effect(spell_id)`.
- Add `eq.is_blind_spell(spell_id)`.
- Add `eq.is_buff_spell(spell_id)`.
- Add `eq.is_cast_not_standing_spell(spell_id)`.
- Add `eq.is_cast_on_fade_duration_spell(spell_id)`.
- Add `eq.is_cast_restricted_spell(spell_id)`.
- Add `eq.is_cast_time_reduction_spell(spell_id)`.
- Add `eq.is_cast_while_invisible_spell(spell_id)`.
- Add `eq.is_charm_spell(spell_id)`.
- Add `eq.is_combat_skill(spell_id)`.
- Add `eq.is_complete_heal_duration_spell(spell_id)`.
- Add `eq.is_complete_heal_spell(spell_id)`.
- Add `eq.is_cure_spell(spell_id)`.
- Add `eq.is_damage_spell(spell_id)`.
- Add `eq.is_death_save_spell(spell_id)`.
- Add `eq.is_debuff_spell(spell_id)`.
- Add `eq.is_detrimental_spell(spell_id)`.
- Add `eq.is_discipline(spell_id)`.
- Add `eq.is_discipline_buff(spell_id)`.
- Add `eq.is_disease_counter_spell(spell_id)`.
- Add `eq.is_distance_modifier_spell(spell_id)`.
- Add `eq.is_effect_ignored_in_stacking(effect_id)`.
- Add `eq.is_effect_in_spell(spell_id, effect_id)`.
- Add `eq.is_fast_heal_spell(spell_id)`.
- Add `eq.is_fear_spell(spell_id)`.
- Add `eq.is_focus_limit(effect_id)`.
- Add `eq.is_full_death_save_spell(spell_id)`.
- Add `eq.is_gate_spell(spell_id)`.
- Add `eq.is_group_complete_heal_spell(spell_id)`.
- Add `eq.is_group_heal_over_time_spell(spell_id)`.
- Add `eq.is_group_only_spell(spell_id)`.
- Add `eq.is_group_spell(spell_id)`.
- Add `eq.is_harmony_spell(spell_id)`.
- Add `eq.is_haste_spell(spell_id)`.
- Add `eq.is_heal_over_time_spell(spell_id)`.
- Add `eq.is_health_spell(spell_id)`.
- Add `eq.is_illusion_spell(spell_id)`.
- Add `eq.is_improved_damage_spell(spell_id)`.
- Add `eq.is_improved_healing_spell(spell_id)`.
- Add `eq.is_increase_duration_spell(spell_id)`.
- Add `eq.is_increase_range_spell(spell_id)`.
- Add `eq.is_instrument_modifier_applied_to_spell_effect(spell_id, effect_id)`.
- Add `eq.is_invisible_spell(spell_id)`.
- Add `eq.is_invulnerability_spell(spell_id)`.
- Add `eq.is_ldon_object_spell(spell_id)`.
- Add `eq.is_lifetap_spell(spell_id)`.
- Add `eq.is_magic_rune_spell(spell_id)`.
- Add `eq.is_mana_cost_reduction_spell(spell_id)`.
- Add `eq.is_mana_tap_spell(spell_id)`.
- Add `eq.is_mesmerize_spell(spell_id)`.
- Add `eq.is_no_detrimental_spell_aggro_spell(spell_id)`.
- Add `eq.is_partial_death_save_spell(spell_id)`.
- Add `eq.is_partial_resistable_spell(spell_id)`.
- Add `eq.is_pbae_nuke_spell(spell_id)`.
- Add `eq.is_percental_heal_spell(spell_id)`.
- Add `eq.is_persist_death_spell(spell_id)`.
- Add `eq.is_pet_spell(spell_id)`.
- Add `eq.is_poison_counter_spell(spell_id)`.
- Add `eq.is_pulsing_bard_song(spell_id)`.
- Add `eq.is_pure_nuke_spell(spell_id)`.
- Add `eq.is_regular_group_heal_spell(spell_id)`.
- Add `eq.is_regular_single_target_heal_spell(spell_id)`.
- Add `eq.is_resist_debuff_spell(spell_id)`.
- Add `eq.is_resistable_spell(spell_id)`.
- Add `eq.is_rest_allowed_spell(spell_id)`.
- Add `eq.is_resurrection_effects(spell_id)`.
- Add `eq.is_rune_spell(spell_id)`.
- Add `eq.is_sacrifice_spell(spell_id)`.
- Add `eq.is_self_conversion_spell(spell_id)`.
- Add `eq.is_shadow_step_spell(spell_id)`.
- Add `eq.is_short_duration_buff(spell_id)`.
- Add `eq.is_spell_usable_in_this_zone_type(spell_id)`.
- Add `eq.is_spell_usable_in_this_zone_type(spell_id, zone_type)`.
- Add `eq.is_stackable_dot(spell_id)`.
- Add `eq.is_stun_spell(spell_id)`.
- Add `eq.is_succor_spell(spell_id)`.
- Add `eq.is_summon_item_spell(spell_id)`.
- Add `eq.is_summon_pc_spell(spell_id)`.
- Add `eq.is_summon_pet_spell(spell_id)`.
- Add `eq.is_summon_skeleton_spell(spell_id)`.
- Add `eq.is_summon_spell(spell_id)`.
- Add `eq.is_suspendable_spell(spell_id)`.
- Add `eq.is_target_required_for_spell(spell_id)`.
- Add `eq.is_targetable_ae_spell(spell_id)`.
- Add `eq.is_teleport_spell(spell_id)`.
- Add `eq.is_tgb_compatible_spell(spell_id)`.
- Add `eq.is_translocate_spell(spell_id)`.
- Add `eq.is_valid_spell(spell_id)`.
- Add `eq.is_very_fast_heal_spell(spell_id)`.
- Add `eq.is_virus_spell(spell_id)`.

- A lot of cleanup in the logic and naming of these methods was done.
- Missing GM restricted spells like Guide spells and GM Health buffs were added as defines.
- Good effect values were added as defines.
- Resurrection effects non-stacking value was added as a define.
- Max fast heal casting time and max very fast heal casting time were added as defines.
- `SE_Display` was uncommented so we could use it instead of the magic number `425`.
- `IsEvacSpell(spell_id)` was removed as it was unnecessary since `IsSuccorSpell(spell_id)` checks for `SE_Succor` as well.
- `GetMorphTrigger(spell_id)` was removed as it was unused.
- `GroupOnlySpell(spell_id)` was removed as it was unnecessary since `IsGroupOnlySpell(spell_id)` exists.
- `CanUseSpell(spell_id)` was removed as it was unnecessary since `GetSpellLevel(spell_id, class_id)` exists.
- `BeneficialSpell(spell_id)` was removed as it was unnecessary since `IsBeneficialSpell(spell_id)` exists.

* Update spell_effects.cpp

* Update spdat.cpp
2023-06-12 20:27:22 -04:00
Alex King c5c575b028 [Quest API] Add GetEXPForLevel() to Perl/Lua (#3403)
# Perl
- Add `$client->GetEXPForLevel(check_level)`.

# Lua
- Add `client:GetEXPForLevel(check_level)`.

# Notes
- This allows operators to see the required experience for a level based on the client provided, this takes race/class modifiers into account as well if enabled.
2023-06-12 19:18:39 -05:00
Alex King 152e99444c [Cleanup] Remove GetClientCount() from zone/entity.cpp and zone/entity.h (#3392)
* [Cleanup] Remove GetClientCount() from zone/entity.cpp and zone/entity.h

# Notes
- This is unused.

* Update entity.cpp
2023-06-12 19:18:17 -05:00
Alex King 795df5c597 [Cleanup] Remove CountTempPets() from zone/entity.cpp and zone/entity.h (#3390)
* [Cleanup] Remove CountTempPets() from zone/entity.cpp and zone/entity.h

# Notes
- This is unused.

* Update entity.h
2023-06-12 19:17:53 -05:00
Alex King 18eff726d0 [Commands] Assign #opcode to a #reload alias (#3401)
* [Commands] Assign #opcode to a #reload alias

# Notes
- Can use `#reload opcodes

* Add ServerOP_ReloadOpcodes
2023-06-12 18:42:39 -04:00
Alex King f06a37a009 [Cleanup] Add GMFind_Struct to packet structures (#3402)
* [Cleanup] Add GMFind_Struct to packet structures

# Notes
- X and Y were swapped in GMSummon_Struct so it displayed XYZ incorrectly in /find, adding its own struct fixes this.

* Update eq_packet_structs.h

* Update eq_packet_structs.h
2023-06-12 18:35:04 -04:00
Paul Coene ae53efc52c [Targeting] /tar <bad target> should not untarget existing target (#3383)
* [Targeting] /tar <bad target> should not untarget existing target

* Forgot string Id file.

* removed unneeded this->
2023-06-12 16:40:09 -05:00
Alex King 548eb65e1d [Cleanup] Remove InteractiveChat() and TakenAction() from zone/npc.h (#3382)
# Notes
- These are unimplemented and unused.
2023-06-12 15:14:34 -05:00
Alex King fede8760d4 [Cleanup] Remove CheckCoordLosNoZLeaps() from zone/entity.cpp and zone/entity.h (#3384)
# Notes
- This is unused.
2023-06-12 15:13:03 -05:00
Alex King 6faa202b57 [Cleanup] Remove pDBAsyncWorkID from zone/entity.h (#3385)
# Notes
- This is unused.
2023-06-12 15:12:47 -05:00
Alex King c406710623 [Cleanup] Remove GetClient(ip, port) from zone/entity.h (#3386)
# Notes
- This is unused.
2023-06-12 15:12:22 -05:00
Alex King 662c4012db [Cleanup] Remove GetGroupByBot(), GetRaidByMob(), and GetRaidByLeaderName() from zone/entity.cpp and zone/entity.h (#3387)
# Notes
- These are unused.
2023-06-12 15:12:00 -05:00
Alex King 849e7b910d [Cleanup] Remove SendAATimer() from zone/entity.h (#3388)
# Notes
- This is unused.
2023-06-12 15:11:32 -05:00
Alex King 8e33755f02 [Cleanup] Remove RemoveMob() and RemoveRaid() from zone/entity.cpp and zone/entity.h (#3389)
# Notes
- These are unused.
2023-06-12 15:11:17 -05:00
Alex King dfaa929778 [Cleanup] Remove GateAllClients() from zone/entity.cpp and zone/entity.h (#3391)
# Notes
- This is unused.
2023-06-12 15:10:36 -05:00
Alex King 306b06745f [Cleanup] Remove LimitCheckBoth() from zone/entity.cpp and zone/entity.h (#3393)
# Notes
- This is unused.
2023-06-12 15:05:39 -05:00
Alex King 108fc82ee0 [Cleanup] Remove Evade() from zone/entity.cpp and zone/entity.h (#3394)
# Notes
- This is unused.
2023-06-12 15:05:23 -05:00
Alex King 577f61b082 [Cleanup] Remove WriteEntityIDs() from zone/entity.cpp and zone/entity.h (#3395)
# Notes
- This is unused.
2023-06-12 15:05:09 -05:00
Alex King a01cf0718d [Cleanup] Remove struct DynamicZoneSafeReturn from zone/entity.h (#3396)
# Notes
- This is unused.
2023-06-12 15:04:54 -05:00
Alex King 90412ba61b [Cleanup] Remove struct TradeEntity from zone/common.h (#3397)
# Notes
- This is unused.
2023-06-12 15:04:38 -05:00
Alex King 5cbc380c62 [Cleanup] Remove CHECK_LOS_STEP from zone/common.h (#3398)
# Notes
- This is unused.
2023-06-12 15:04:25 -05:00
Alex King 6c289a7c71 [Cleanup] Remove _BECOMENPCPET() and _NPCPET() from zone/common.h (#3399)
# Notes
- These are unused.
2023-06-12 15:04:09 -05:00
Alex King 57335b188f [Cleanup] Remove SPECIALIZE_MANA_REDUCE from zone/common.h (#3400)
# Notes
- This is unused.
2023-06-12 15:03:55 -05:00
Alex King 056e429100 [Cleanup] Remove NPC::AddCash() from npc.cpp/npc.h (#3380)
# Notes
- This is unused.
2023-06-09 11:50:52 -04:00
Paul Coene f548aeddb2 [Logging] Fixed statements that logged incorrect data (#3381) 2023-06-07 08:26:04 -04:00
Paul Coene 4ff9faa4e6 [Illusions] RandomizeFeatures and SetGender were killing db texture (#3376)
* [Illusions] RandomizeFeatures and SetGender were killing db texture

* Found actual source of the problem.
2023-06-06 08:30:41 -04:00
Alex King 17fc350d46 [Quest API] Add SendChannelMessage() to Perl/Lua (#3378)
* [Quest API] Add SendChannelMessage() to Perl/Lua

# Perl
- Add `quest::send_channel_message(channel_number, guild_id, language_id, language_skill, message)`.
- Add `quest::send_channel_message(from, channel_number, guild_id, language_id, language_skill, message)`.
- Add `quest::send_channel_message(from, to, channel_number, guild_id, language_id, language_skill, message)`.

# Lua
- Add `eq.send_channel_message(channel_number, guild_id, language_id, language_skill, message)`.
- Add `eq.send_channel_message(from, channel_number, guild_id, language_id, language_skill, message)`.
- Add `eq.send_channel_message(from, to, channel_number, guild_id, language_id, language_skill, message)`.

# Notes
- This allows operators to send channel messages from scripts like a broadcast or tell.

* Update zoneserver.cpp

* Update lua_general.cpp

* Update questmgr.h
2023-06-03 19:06:40 -05:00
Chris Miles b18bc66b42 [Release] 22.12.0 (#3377) 2023-05-30 00:10:44 -05:00
Alex King 324bfd448e [Commands] Add entity variable command (#3345)
* [Commands] Add entity variable commands

# Commands
- Add `#clearentityvariables` to clear all entity variables from yourself or your target.
- Add `#deleteentityvariable [Variable Name]` to delete an entity variable from yourself or your target.
- Add `#setentityvariable [Variable Name] [Variable Value]` to set an entity variable for yourself or your target.
- Add `#viewentityvariables [Search Criteria]` to view your or your target's entity variables.

# Notes
- `#setentityvariable` can use multi-word names/values by using double quotes like `#setentityvariable "Test Variable" "Test Value"`.
- `#viewentityvariable` does not require a search criteria, not using one shows all entity variables on yourself or your target.

* Update viewentityvariables.cpp

* Unnecessary parameter.

* Consolidate commands.

* Update entityvariable.cpp

* Update command.cpp

* Proper arguments.
2023-05-25 19:49:09 -04:00
Alex King 75560ee830 [Performance] Character tribute is now bulk saved (#3340)
* [Performance] Character tribute is now bulk saved

This pull request combines individual `character_tribute` queries during `Save()` into one.

This pull request also adds a primary key of `id` to `character_tribute` and renames the pre-existing `id` column to `character_id`, this allows us to use repositories for this table.

* Update zonedb.cpp

* Update zonedb.cpp
2023-05-25 19:21:18 -04:00
Alex King 50db7637aa [Quest API] Add Memorize and Scribe Spell Events to Perl/Lua (#3363)
* [Quest API] Add Memorize and Scribe Spell Events to Perl/Lua

# Perl
- Add `EVENT_MEMORIZE_SPELL`.
- Add `EVENT_UNMEMORIZE_SPELL`.
- Add `EVENT_SCRIBE_SPELL`.
- Add `EVENT_UNSCRIBE_SPELL`.

# Lua
- Add `event_memorize_spell`.
- Add `event_unmemorize_spell`.
- Add `event_scribe_spell`.
- Add `event_unscribe_spell`.

# Notes
- Allows operators to perform events on memorization, unmemorization, scribe, or unscribe.
- Cleaned up target description messages for `#unscribespell`.

* Update client.cpp
2023-05-25 18:18:14 -05:00
Alex King 67fdc75df3 [Commands] Cleanup #setanim (#3350)
# Notes
- Make use of constants instead of hard-coded strings.
2023-05-25 18:04:09 -05:00
Chris Miles 9993022418 [Pets] Fix saving inconsistencies with pets (#3375) 2023-05-25 11:33:34 -04:00
Alex King bd95ed44fd [Cleanup] Remove GetMaxRank() from aa_ability.cpp/aa_ability.h (#3347)
# Notes
- This is unused.
2023-05-24 22:44:53 -05:00
Alex King 65fd323eab [Cleanup] Remove LoadSpawn2() and PopulateZoneSpawnListClose() from spawn2.cpp/zonedb.h (#3344)
# Notes
- These are unused.
2023-05-24 22:42:20 -05:00
Aeadoin 290c58741e [Bug Fix] Fix issue with Group Pointers/Member roles (#3374)
* [Bug Fix] Fix issue with Group Corruption

* cleanup

* Fix for Group Roles

* Fix for Group Roles
2023-05-24 22:40:59 -05:00
Alex King 39d0772a01 [Cleanup] Remove IsRaid() from raids.h (#3361)
# Notes
- This is unused.
2023-05-24 22:40:32 -05:00
Alex King 622fe50479 [Cleanup] Remove numMembers from raids.h (#3362)
# Notes
- This is unused.
2023-05-24 22:40:20 -05:00
Alex King f41a219309 [Cleanup] Remove CalcPetHp from spdat.h (#3364)
# Notes
- This is unused.
2023-05-24 22:37:04 -05:00
Alex King 23bc3c7fd6 [Cleanup] Remove Z_AGGRO from spdat.h (#3365)
# Notes
- This is unused.
2023-05-24 22:36:52 -05:00
Alex King 3144ac1a28 [Cleanup] Cleanup #setskill and #setskillall Commands (#3367)
# Notes
- No need to cap at 400 for max skill.
- When setting skill/skills, if we go over cap, set to cap.
2023-05-24 22:36:38 -05:00
Alex King a5106420e8 [Commands] Add #findcurrency Command (#3368)
* [Commands] Add #findcurrency Command

# Notes
- Allows you to find alternate currencies by item ID or name.
- Has a saylink for summoning a stack of the currency if the GM can use the `#summonitem` command.

* Update findcurrency.cpp

* Update findcurrency.cpp
2023-05-24 22:30:06 -05:00
Alex King 5a42c4f667 [Quest API] Add zone data methods to Perl/Lua (#3342)
# Perl
- Add `quest::GetZoneSafeX(zone_id)`.
- Add `quest::GetZoneSafeX(zone_id, version)`.
- Add `quest::GetZoneSafeY(zone_id)`.
- Add `quest::GetZoneSafeY(zone_id, version)`.
- Add `quest::GetZoneSafeZ(zone_id)`.
- Add `quest::GetZoneSafeZ(zone_id, version)`.
- Add `quest::GetZoneSafeHeading(zone_id)`.
- Add `quest::GetZoneSafeHeading(zone_id, version)`.
- Add `quest::GetZoneMinimumLevel(zone_id)`.
- Add `quest::GetZoneMinimumLevel(zone_id, version)`.
- Add `quest::GetZoneMaximumLevel(zone_id)`.
- Add `quest::GetZoneMaximumLevel(zone_id, version)`.
- Add `quest::GetZoneMinimumStatus(zone_id)`.
- Add `quest::GetZoneMinimumStatus(zone_id, version)`.
- Add `quest::GetZoneTimeZone(zone_id)`.
- Add `quest::GetZoneTimeZone(zone_id, version)`.
- Add `quest::GetZoneMaximumPlayers(zone_id)`.
- Add `quest::GetZoneMaximumPlayers(zone_id, version)`.
- Add `quest::GetZoneRuleSet(zone_id)`.
- Add `quest::GetZoneRuleSet(zone_id, version)`.
- Add `quest::GetZoneNote(zone_id)`.
- Add `quest::GetZoneNote(zone_id, version)`.
- Add `quest::GetZoneUnderworld(zone_id)`.
- Add `quest::GetZoneUnderworld(zone_id, version)`.
- Add `quest::GetZoneMinimumClip(zone_id)`.
- Add `quest::GetZoneMinimumClip(zone_id, version)`.
- Add `quest::GetZoneMaximumClip(zone_id)`.
- Add `quest::GetZoneMaximumClip(zone_id, version)`.
- Add `quest::GetZoneFogMinimumClip(zone_id)`.
- Add `quest::GetZoneFogMinimumClip(zone_id, slot)`.
- Add `quest::GetZoneFogMinimumClip(zone_id, slot, version)`.
- Add `quest::GetZoneFogMaximumClip(zone_id)`.
- Add `quest::GetZoneFogMaximumClip(zone_id, slot)`.
- Add `quest::GetZoneFogMaximumClip(zone_id, slot, version)`.
- Add `quest::GetZoneFogRed(zone_id)`.
- Add `quest::GetZoneFogRed(zone_id, slot)`.
- Add `quest::GetZoneFogRed(zone_id, slot, version)`.
- Add `quest::GetZoneFogGreen(zone_id)`.
- Add `quest::GetZoneFogGreen(zone_id, slot)`.
- Add `quest::GetZoneFogGreen(zone_id, slot, version)`.
- Add `quest::GetZoneFogBlue(zone_id)`.
- Add `quest::GetZoneFogBlue(zone_id, slot)`.
- Add `quest::GetZoneFogBlue(zone_id, slot, version)`.
- Add `quest::GetZoneSky(zone_id)`.
- Add `quest::GetZoneSky(zone_id, version)`.
- Add `quest::GetZoneZType(zone_id)`.
- Add `quest::GetZoneZType(zone_id, version)`.
- Add `quest::GetZoneExperienceMultiplier(zone_id)`.
- Add `quest::GetZoneExperienceMultiplier(zone_id, version)`.
- Add `quest::GetZoneWalkSpeed(zone_id)`.
- Add `quest::GetZoneWalkSpeed(zone_id, version)`.
- Add `quest::GetZoneTimeType(zone_id)`.
- Add `quest::GetZoneTimeType(zone_id, version)`.
- Add `quest::GetZoneFogDensity(zone_id)`.
- Add `quest::GetZoneFogDensity(zone_id, version)`.
- Add `quest::GetZoneFlagNeeded(zone_id)`.
- Add `quest::GetZoneFlagNeeded(zone_id, version)`.
- Add `quest::GetZoneCanBind(zone_id)`.
- Add `quest::GetZoneCanBind(zone_id, version)`.
- Add `quest::GetZoneCanCombat(zone_id)`.
- Add `quest::GetZoneCanCombat(zone_id, version)`.
- Add `quest::GetZoneCanLevitate(zone_id)`.
- Add `quest::GetZoneCanLevitate(zone_id, version)`.
- Add `quest::GetZoneCastOutdoor(zone_id)`.
- Add `quest::GetZoneCastOutdoor(zone_id, version)`.
- Add `quest::GetZoneHotzone(zone_id)`.
- Add `quest::GetZoneHotzone(zone_id, version)`.
- Add `quest::GetZoneInstanceType(zone_id)`.
- Add `quest::GetZoneInstanceType(zone_id, version)`.
- Add `quest::GetZoneShutdownDelay(zone_id)`.
- Add `quest::GetZoneShutdownDelay(zone_id, version)`.
- Add `quest::GetZonePEQZone(zone_id)`.
- Add `quest::GetZonePEQZone(zone_id, version)`.
- Add `quest::GetZoneExpansion(zone_id)`.
- Add `quest::GetZoneExpansion(zone_id, version)`.
- Add `quest::GetZoneBypassExpansionCheck(zone_id)`.
- Add `quest::GetZoneBypassExpansionCheck(zone_id, version)`.
- Add `quest::GetZoneSuspendBuffs(zone_id)`.
- Add `quest::GetZoneSuspendBuffs(zone_id, version)`.
- Add `quest::GetZoneRainChance(zone_id)`.
- Add `quest::GetZoneRainChance(zone_id, slot)`.
- Add `quest::GetZoneRainChance(zone_id, slot, version)`.
- Add `quest::GetZoneRainDuration(zone_id)`.
- Add `quest::GetZoneRainDuration(zone_id, slot)`.
- Add `quest::GetZoneRainDuration(zone_id, slot, version)`.
- Add `quest::GetZoneSnowChance(zone_id)`.
- Add `quest::GetZoneSnowChance(zone_id, slot)`.
- Add `quest::GetZoneSnowChance(zone_id, slot, version)`.
- Add `quest::GetZoneSnowDuration(zone_id)`.
- Add `quest::GetZoneSnowDuration(zone_id, slot)`.
- Add `quest::GetZoneSnowDuration(zone_id, slot, version)`.
- Add `quest::GetZoneGravity(zone_id)`.
- Add `quest::GetZoneGravity(zone_id, version)`.
- Add `quest::GetZoneType(zone_id)`.
- Add `quest::GetZoneType(zone_id, version)`.
- Add `quest::GetZoneSkyLock(zone_id)`.
- Add `quest::GetZoneSkyLock(zone_id, version)`.
- Add `quest::GetZoneFastRegenHP(zone_id)`.
- Add `quest::GetZoneFastRegenHP(zone_id, version)`.
- Add `quest::GetZoneFastRegenMana(zone_id)`.
- Add `quest::GetZoneFastRegenMana(zone_id, version)`.
- Add `quest::GetZoneFastRegenEndurance(zone_id)`.
- Add `quest::GetZoneFastRegenEndurance(zone_id, version)`.
- Add `quest::GetZoneNPCMaximumAggroDistance(zone_id)`.
- Add `quest::GetZoneNPCMaximumAggroDistance(zone_id, version)`.
- Add `quest::GetZoneMaximumMovementUpdateRange(zone_id)`.
- Add `quest::GetZoneMaximumMovementUpdateRange(zone_id, version)`.
- Add `quest::GetZoneMinimumExpansion(zone_id)`.
- Add `quest::GetZoneMinimumExpansion(zone_id, version)`.
- Add `quest::GetZoneMaximumExpansion(zone_id)`.
- Add `quest::GetZoneMaximumExpansion(zone_id, version)`.
- Add `quest::GetZoneContentFlags(zone_id)`.
- Add `quest::GetZoneContentFlags(zone_id, version)`.
- Add `quest::GetZoneContentFlagsDisabled(zone_id)`.
- Add `quest::GetZoneContentFlagsDisabled(zone_id, version)`.
- Add `quest::GetZoneUnderworldTeleportIndex(zone_id)`.
- Add `quest::GetZoneUnderworldTeleportIndex(zone_id, version)`.
- Add `quest::GetZoneLavaDamage(zone_id)`.
- Add `quest::GetZoneLavaDamage(zone_id, version)`.
- Add `quest::GetZoneMinimumLavaDamage(zone_id)`.
- Add `quest::GetZoneMinimumLavaDamage(zone_id, version)`.

# Lua
- Add `eq.get_zone_safe_x(zone_id)`.
- Add `eq.get_zone_safe_x(zone_id, version)`.
- Add `eq.get_zone_safe_y(zone_id)`.
- Add `eq.get_zone_safe_y(zone_id, version)`.
- Add `eq.get_zone_safe_z(zone_id)`.
- Add `eq.get_zone_safe_z(zone_id, version)`.
- Add `eq.get_zone_safe_heading(zone_id)`.
- Add `eq.get_zone_safe_heading(zone_id, version)`.
- Add `eq.get_zone_minimum_level(zone_id)`.
- Add `eq.get_zone_minimum_level(zone_id, version)`.
- Add `eq.get_zone_maximum_level(zone_id)`.
- Add `eq.get_zone_maximum_level(zone_id, version)`.
- Add `eq.get_zone_minimum_status(zone_id)`.
- Add `eq.get_zone_minimum_status(zone_id, version)`.
- Add `eq.get_zone_time_zone(zone_id)`.
- Add `eq.get_zone_time_zone(zone_id, version)`.
- Add `eq.get_zone_maximum_players(zone_id)`.
- Add `eq.get_zone_maximum_players(zone_id, version)`.
- Add `eq.get_zone_rule_set(zone_id)`.
- Add `eq.get_zone_rule_set(zone_id, version)`.
- Add `eq.get_zone_note(zone_id)`.
- Add `eq.get_zone_note(zone_id, version)`.
- Add `eq.get_zone_underworld(zone_id)`.
- Add `eq.get_zone_underworld(zone_id, version)`.
- Add `eq.get_zone_minimum_clip(zone_id)`.
- Add `eq.get_zone_minimum_clip(zone_id, version)`.
- Add `eq.get_zone_maximum_clip(zone_id)`.
- Add `eq.get_zone_maximum_clip(zone_id, version)`.
- Add `eq.get_zone_fog_minimum_clip(zone_id)`.
- Add `eq.get_zone_fog_minimum_clip(zone_id, slot)`.
- Add `eq.get_zone_fog_minimum_clip(zone_id, slot, version)`.
- Add `eq.get_zone_fog_maximum_clip(zone_id)`.
- Add `eq.get_zone_fog_maximum_clip(zone_id, slot)`.
- Add `eq.get_zone_fog_maximum_clip(zone_id, slot, version)`.
- Add `eq.get_zone_fog_red(zone_id)`.
- Add `eq.get_zone_fog_red(zone_id, slot)`.
- Add `eq.get_zone_fog_red(zone_id, slot, version)`.
- Add `eq.get_zone_fog_green(zone_id)`.
- Add `eq.get_zone_fog_green(zone_id, slot)`.
- Add `eq.get_zone_fog_green(zone_id, slot, version)`.
- Add `eq.get_zone_fog_blue(zone_id)`.
- Add `eq.get_zone_fog_blue(zone_id, slot)`.
- Add `eq.get_zone_fog_blue(zone_id, slot, version)`.
- Add `eq.get_zone_sky(zone_id)`.
- Add `eq.get_zone_sky(zone_id, version)`.
- Add `eq.get_zone_ztype(zone_id)`.
- Add `eq.get_zone_ztype(zone_id, version)`.
- Add `eq.get_zone_experience_multiplier(zone_id)`.
- Add `eq.get_zone_experience_multiplier(zone_id, version)`.
- Add `eq.get_zone_walk_speed(zone_id)`.
- Add `eq.get_zone_walk_speed(zone_id, version)`.
- Add `eq.get_zone_time_type(zone_id)`.
- Add `eq.get_zone_time_type(zone_id, version)`.
- Add `eq.get_zone_fog_density(zone_id)`.
- Add `eq.get_zone_fog_density(zone_id, version)`.
- Add `eq.get_zone_flag_needed(zone_id)`.
- Add `eq.get_zone_flag_needed(zone_id, version)`.
- Add `eq.get_zone_can_bind(zone_id)`.
- Add `eq.get_zone_can_bind(zone_id, version)`.
- Add `eq.get_zone_can_combat(zone_id)`.
- Add `eq.get_zone_can_combat(zone_id, version)`.
- Add `eq.get_zone_can_levitate(zone_id)`.
- Add `eq.get_zone_can_levitate(zone_id, version)`.
- Add `eq.get_zone_cast_outdoor(zone_id)`.
- Add `eq.get_zone_cast_outdoor(zone_id, version)`.
- Add `eq.get_zone_hotzone(zone_id)`.
- Add `eq.get_zone_hotzone(zone_id, version)`.
- Add `eq.get_zone_instance_type(zone_id)`.
- Add `eq.get_zone_instance_type(zone_id, version)`.
- Add `eq.get_zone_shutdown_delay(zone_id)`.
- Add `eq.get_zone_shutdown_delay(zone_id, version)`.
- Add `eq.get_zone_peqzone(zone_id)`.
- Add `eq.get_zone_peqzone(zone_id, version)`.
- Add `eq.get_zone_expansion(zone_id)`.
- Add `eq.get_zone_expansion(zone_id, version)`.
- Add `eq.get_zone_bypass_expansion_check(zone_id)`.
- Add `eq.get_zone_bypass_expansion_check(zone_id, version)`.
- Add `eq.get_zone_suspend_buffs(zone_id)`.
- Add `eq.get_zone_suspend_buffs(zone_id, version)`.
- Add `eq.get_zone_rain_chance(zone_id)`.
- Add `eq.get_zone_rain_chance(zone_id, slot)`.
- Add `eq.get_zone_rain_chance(zone_id, slot, version)`.
- Add `eq.get_zone_rain_duration(zone_id)`.
- Add `eq.get_zone_rain_duration(zone_id, slot)`.
- Add `eq.get_zone_rain_duration(zone_id, slot, version)`.
- Add `eq.get_zone_snow_chance(zone_id)`.
- Add `eq.get_zone_snow_chance(zone_id, slot)`.
- Add `eq.get_zone_snow_chance(zone_id, slot, version)`.
- Add `eq.get_zone_snow_duration(zone_id)`.
- Add `eq.get_zone_snow_duration(zone_id, slot)`.
- Add `eq.get_zone_snow_duration(zone_id, slot, version)`.
- Add `eq.get_zone_gravity(zone_id)`.
- Add `eq.get_zone_gravity(zone_id, version)`.
- Add `eq.get_zone_type(zone_id)`.
- Add `eq.get_zone_type(zone_id, version)`.
- Add `eq.get_zone_sky_lock(zone_id)`.
- Add `eq.get_zone_sky_lock(zone_id, version)`.
- Add `eq.get_zone_fast_regen_hp(zone_id)`.
- Add `eq.get_zone_fast_regen_hp(zone_id, version)`.
- Add `eq.get_zone_fast_regen_mana(zone_id)`.
- Add `eq.get_zone_fast_regen_mana(zone_id, version)`.
- Add `eq.get_zone_fast_regen_endurance(zone_id)`.
- Add `eq.get_zone_fast_regen_endurance(zone_id, version)`.
- Add `eq.get_zone_npc_maximum_aggro_distance(zone_id)`.
- Add `eq.get_zone_npc_maximum_aggro_distance(zone_id, version)`.
- Add `eq.get_zone_maximum_movement_update_range(zone_id)`.
- Add `eq.get_zone_maximum_movement_update_range(zone_id, version)`.
- Add `eq.get_zone_minimum_expansion(zone_id)`.
- Add `eq.get_zone_minimum_expansion(zone_id, version)`.
- Add `eq.get_zone_maximum_expansion(zone_id)`.
- Add `eq.get_zone_maximum_expansion(zone_id, version)`.
- Add `eq.get_zone_content_flags(zone_id)`.
- Add `eq.get_zone_content_flags(zone_id, version)`.
- Add `eq.get_zone_content_flags_disabled(zone_id)`.
- Add `eq.get_zone_content_flags_disabled(zone_id, version)`.
- Add `eq.get_zone_underworld_teleport_index(zone_id)`.
- Add `eq.get_zone_underworld_teleport_index(zone_id, version)`.
- Add `eq.get_zone_lava_damage(zone_id)`.
- Add `eq.get_zone_lava_damage(zone_id, version)`.
- Add `eq.get_zone_minimum_lava_damage(zone_id)`.
- Add `eq.get_zone_minimum_lava_damage(zone_id, version)`.

# Notes
- These methods add support for reading every value that the `zone` table contains, allowing operators to get any information about a specific zone and version they could need.
2023-05-24 17:59:18 -04:00
Alex King a3107cc54d [Bug Fix] Fix duplicate messages in #npcedit (#3372)
# Notes
- `#npcedit special_attacks` and `#npcedit special_abilities` send duplicate messages since the `d` variable wasn't being set and a message was being sent instead, meaning a message was sent inside the condition as well as a blank message at the bottom of the command.
2023-05-21 18:56:51 -04:00
Alex King f0152cef66 [Rules] Add World:MaximumQuestErrors Rule (#3349)
* [Rules] Add World:MaximumQuestErrors Rule

# Notes
- Allows operators to display more than 30 errors with #questerrors if they want.

* Update quest_interface.h
2023-05-21 18:48:30 -04:00
Alex King 21755a9f9e [Bug Fix] Fix typos in #zheader (#3370)
# Notes
- Argument 2 and 3 were being used when it should have been arguments 1 and 2.
2023-05-21 18:48:22 -04:00
Alex King b329515a07 [Quest API] Cleanup The Darkened Sea Quest Methods Names (#3369)
# Notes
- These were spelled incorrectly.
2023-05-21 18:48:15 -04:00
Alex King ff4b117cfa [Cleanup] Fix #spawn command NPCs having 0 health (#3371)
# Notes
- NPCs when spawned with this command have 0 health by default, requiring operators to manually edit their health if they're using this NPC as an NPC in their hub.
2023-05-21 18:48:08 -04:00
Paul Coene e305ba852b [Bug Fix] NPC Armor Upgrade to a slot not handled correctly (#3366)
* [NPC Armor - Bug] NPC upgardes in armor not correct

* Revert "[NPC Armor - Bug] NPC upgardes in armor not correct"

This reverts commit d5a68654a7.

* [NPC item bonuses] Upgrades not processed correctly

* Update loottables.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-05-19 22:28:01 -04:00
RekkasGit b8c91cf4f9 [Bug Fix] Mob scaling issue with min dmg set to zero while max dmg is not (#3351)
* fix for mob scaling issue with min dmg set to zero while max dmg is not.

* Cleanup

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-05-19 22:11:11 -04:00
Alex King cd82bd8472 [Cleanup] Remove DumpMerchantList() from zone.cpp/zone.h (#3343)
# Notes
- This is unused.
2023-05-17 09:02:14 -04:00
Alex King 20bed20f47 [Cleanup] Delete message.h (#3348)
# Notes
- This is unsued.
2023-05-17 09:00:38 -04:00
Alex King c93054421f [Cleanup] Remove CountNPC() and QueueManaged() from entity.cpp/entity.h (#3346)
# Notes
- These are unused.
2023-05-17 08:58:50 -04:00
Alex King b7a1fc6644 [Cleanup] Remove IsEntityInFrenzyMode() from hate_list.cpp/hate_list.h (#3352)
# Notes
- This is unused.
2023-05-17 08:58:27 -04:00
Alex King 6bfb8fca2e [Cleanup] Remove GetEscapingEntOnHateList() from hate_list.cpp/hate_list.h (#3353)
# Notes
- This is unused.
2023-05-17 08:58:13 -04:00
Alex King 9d6a7ad743 [Cleanup] Remove SetGraveyard() from zone.cpp/zone.h (#3354)
# Notes
- This is unused.
2023-05-17 08:58:02 -04:00
Alex King 076b88be9a [Cleanup] Remove TypeToSkill() from tradeskills.cpp/object.h (#3355)
# Notes
- This is unused.
2023-05-17 08:57:51 -04:00
Alex King 84a779c4df [Cleanup] Remove SetTradeCash() from trading.cpp/common.h (#3356)
# Notes
- This is unused.
2023-05-17 08:57:09 -04:00
Alex King 3fb479e612 [Cleanup] Remove TraderUpdate() from trading.cpp/client.h (#3357)
# Notes
- This is unused.
2023-05-17 08:56:42 -04:00
Alex King c1f4ee0e65 [Cleanup] Remove GetDamageReceived() and GetHealReceived() from combat_record.cpp/combat_record.h (#3358)
# Notes
- These are unused.
2023-05-17 08:56:09 -04:00
RekkasGit 32f7dc3d1b [Quest API] Add GetHateListClosest(), GetHateListClosestBot(), GetHateListClosestClient(), and GetHateListClosestNPC() methods/overloads to Perl/Lua (#3359)
* Add HateListClosestClient available for scripting.

* Add other methods.

* Use pre-existing constants.

* Typos

* Update mob.h

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-05-15 21:23:19 -04:00
RekkasGit fa55fd1664 [Bug Fix] Fix Heroic INT/WIS Bonuses (#3341)
* fix for heroic int/wis for hybrids

* Update classes.cpp

* Update classes.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-05-15 10:52:53 -04:00
Chris Miles c44c0d4efa [Performance] Character buffs now save in bulk (#3336)
* [Performance] Character buffs now save in bulk

* Only insert if we have buffs to insert

* Swap for .empty()
2023-05-09 13:28:34 -05:00
Chris Miles 50c63b95db [Performance] Character pet bulk saving (#3337)
* [Performance] Character pet bulk saving

* Update zonedb.cpp
2023-05-09 13:27:17 -05:00
Chris Miles 612029de6e [Performance] Character bind is now bulk saved (#3338)
* [Performance] Character bind is now bulk saved

* Fix bind heading
2023-05-09 13:22:57 -05:00
Chris Miles dbc6346fe8 [Performance] Mail key is now cached during player load (#3339)
* [Performance] Mail key is now cached during player load

* More refactoring
2023-05-09 13:22:43 -05:00
nytmyr 93a4153a4b [Rules] ResurrectionEffectBlock to prevent/allow/move buffs. (#3288)
* [Rules] ResurrectionEffectsBlock to prevent/allow/move buffs.

This removes the rule ResurrectionEffectsBlock (Bool) and creates ResurrectionEffectsBlock (Int)

Default = 2

Setting to 0 = Functions as it did before any blocking changes, Focus of Spirit and Strength buffs can overwrite Resurrection Effects.

Setting to 1 = Blocks all buffs that could overwrite Resurrection Effects.

Setting to 2 = Allows all buffs that would overwrite Resurrection Effects to land, however they will be moved to a new buff slot if one is available to allow both the beneficial buff to land and detrimental effects of Resurrection Effects to stay in effect until the duration is expired.

* Update logging

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-05-08 08:32:21 -05:00
Akkadius 434f270f68 Revert "[Bug Fix] ReloadQuests() on Zone::Init() to avoid cached global quests/plugins (#3333)"
This reverts commit 8c23eee42a.
2023-05-07 23:33:43 -05:00
Alex King 5ba33b88bd [Cleanup] Set GetAugmentType() to int again (#3335)
# Notes
- Augment type can be `-1` for all augment types.
2023-05-07 21:40:45 -04:00
Alex King ce1de9997b [Quest API] Add GetPet() to Perl (#3309)
# Perl
- Add `$mob->GetPet()`.

# Notes
- This exists in Lua, but not Perl.
2023-05-07 19:13:26 -05:00
Chris Miles 8814ab26cd [Hotfix] Fix mob item bonus calc (#3334) 2023-05-07 18:23:22 -05:00
Alex King 8c23eee42a [Bug Fix] ReloadQuests() on Zone::Init() to avoid cached global quests/plugins (#3333)
# Notes
- Before this, quests/plugins would be cached in an old state, so you'd have to either enter the zone and `#reload quest` or `#reload world` to get them to update.
2023-05-07 14:41:57 -04:00
Alex King 5475615448 [Bug Fix] #augmentitem bypasses augment restrictions (#3332)
* [Bug Fix] #augmentitem bypasses augment restrictions

# Notes
- `Object::HandleAugmentation` did not properly check for `augrestrict` values. This allowed augment restrictions to be bypassed with `#augmentitem` or anything else that uses this method.
- `Client::SummonItem` already properly checked these, so I just broke it out into a `Client::IsAugmentRestricted()` method.

* Update item_instance.h
2023-05-07 11:40:04 -04:00
Chris Miles 4a5559022f [Memory Leak] Fix large memory leak introduced in CalcItemBonuses (#3331) 2023-05-07 09:47:03 -04:00
Paul Coene 5be2041085 [Messages] Remove duplicate heal message for healing yourself (#3329) 2023-05-03 16:50:54 -04:00
Jasdac 9f4d60ec36 [Feature] Intoxication setter/getter for source, getter for Perl/Lua (#3330)
* Add setter and getter methods for intoxication
Add GetIntoxication functions for perl and Lua

* Remove trailing tab

* Use clamp instead of min/max
2023-05-03 16:19:53 -04:00
Chris Miles c64a2aec94 [Release] 22.11.0 (#3328)
* [Release] 22.11.0

* Update version.h
2023-04-29 20:37:04 -05:00
Alex King 0e582eda82 [Quest API] Add HasSpellEffect() to Perl/Lua (#3319)
* [Quest API] Add HasSpellEffect() to Perl/Lua

# Perl
- Add `$mob->HasSpellEffect(effect_id)`.

# Lua
- Add `mob:HasSpellEffect(effect_id)`.

# Notes
- Allows operators to see if a Mob has an effect ID from any of their buffs.

* Update mob.cpp
2023-04-29 20:09:00 -05:00
Alex King 7eff6ada87 [Cleanup] Remove unused code in zone/pets.cpp (#3310)
# Notes
- This code is unused.
2023-04-29 20:00:37 -05:00
Alex King 291997d35b [Cleanup] Remove pDontCastBefore_casting_spell from zone/npc.h (#3311)
# Notes
- This is unused.
2023-04-29 20:00:20 -05:00
Alex King ac4572bf79 [Cleanup] Remove unused methods in zone/client.cpp and zone/client.h (#3312)
* [Cleanup] Remove unused methods in zone/client.cpp and zone/client.h

# Notes
- Remove `CheckAccess()` in `zone/client.cpp`.
- Remove `CheckAccess()` in `zone/client.h`.
- Remove `CheckQuests()` in `zone/client.h`.
- Remove `MakeCorpse()` in `zone/client.h`.
- Remove `HPTick()` in `zone/client.h`.
- These methods are unused.

* Update client.h
2023-04-29 20:00:08 -05:00
Alex King f0a9578b6a [Cleanup] Remove GetClassHPFactor() from zone/merc.h (#3314)
# Notes
- This is unused.
2023-04-29 19:59:50 -05:00
Alex King baa824d8fb [Cleanup] Remove GetClassHPFactor() from zone/client_mods.cpp and zone/client.h (#3313)
# Notes
- This is unused.
2023-04-29 19:59:19 -05:00
Alex King b19d3ac8a2 [Cleanup] Remove unused methods in zone/bot.cpp and zone/bot.h (#3315)
# Notes
- Remove `DoFinishedSpellAETarget()`.
- Remove `SendBotArcheryWearChange()`.
- These are unused.
2023-04-29 19:59:05 -05:00
Alex King 6a393bf0c3 [Quest API] Add GetDefaultRaceSize() overloads to Perl/Lua (#3320)
# Perl
- Add `$mob->GetDefaultRaceSize(race_id)`.
- Add `$mob->GetDefaultRaceSize(race_id, gender_id)`.

# Lua
- Add `mob:GetDefaultRaceSize(race_id)`.
- Add `mob:GetDefaultRaceSize(race_id, gender_id)`.

# Notes
- This allows you to get a default size for a race and gender that isn't the current mob's race and gender.
2023-04-29 19:53:49 -05:00
Alex King 09a5551de1 [Cleanup] quest::setallskill() had always true condition. (#3301)
# Notes
- Remove unnecessary double check of `initiator`.
- Cleanup logic to use `EQ::skills::GetSkillTypeMap()`.
2023-04-29 19:52:30 -05:00
Alex King 6e2e035d66 [Cleanup] Remove unused variable in common/crash.cpp (#3308)
# Notes
- This variable is unused.
2023-04-29 19:51:41 -05:00
Alex King ac5922bb32 [Cleanup] Use default ctor/dtor in oriented_bounding_box.h (#3307)
# Notes
- Use default ctor/dtor instead of empty ones.
2023-04-29 19:51:21 -05:00
Chris Miles ecf2a369cc [Discord] Add Discord webhook callback processing to world (#3322) 2023-04-29 20:49:06 -04:00
Chris Miles 95b306599f [Maps] Update download with faster releases link (#3321) 2023-04-29 19:39:24 -05:00
Chris Miles 497d20512a [Crash] Fix UCS crash that occurs during log reloading (#3324) 2023-04-29 19:39:13 -05:00
Aeadoin db916e946e [Bug Fix] Fix issue with spawning Mercs (#3327) 2023-04-29 18:45:35 -04:00
Alex King 958549b407 [Bug Fix] Possible issues with SummonItem in Client::QuestReward() methods (#3325)
# Notes
- These methods were ignoring the sixth augment slot and could cause item to be summoned attuned being `EQ::invslot::slotCursor` is a non-zero value.
2023-04-26 21:28:24 -04:00
Paul Coene 71ebf1b2d4 [Messages] Remove duplicate you have lost a level message (#3323) 2023-04-25 17:42:31 -04:00
Paul Coene e19b8d3056 [Bug Fix] Fix issue with NPCs no longer using some armor. (#3318)
* [BugFix/NPCs] Fix issue with NPCs no longer using some armor.

* Removed redundant memory clear
2023-04-24 17:05:29 -04:00
Alex King 8b1d64a043 [Cleanup] quest::createBot() unnecessary check against nullptr (#3302)
# Notes
- We initialize this variable, so it can never be a nullptr.
2023-04-23 15:08:50 -04:00
Alex King 576f99f292 [Cleanup] Add initiator/owner checks to various methods in questmgr.cpp (#3306)
* [Cleanup] Add initiator/owner checks to various methods in questmgr.cpp

# Notes
- Add `initiator` check to `quest::permaclass()`.
- Add `initiator` check to `quest::permarace()`.
- Add `initiator` check to `quest::permagender()`.
- Add `initiator` check to `quest::scribespells()`.
- Add `initiator` check to `quest::traindiscs()`.
- Add `initiator` check to `quest::unscribespells()`.
- Add `initiator` check to `quest::untraindiscs()`.
- Cleanup `initiator` check in `quest::pvp()`.
- Cleanup `initiator` check in `quest::movepc()`.
- Cleanup `initiator` check in `quest::gmmove()`.
- Cleanup `initiator` check in `quest::movegrp()`.
- Add `owner` check to `quest::doanim()`.
- Cleanup `initiator` check in `quest::addskill()`.
- Cleanup `initiator` check in `quest::setlanguage()`.
- Cleanup `initiator` check in `quest::setskill()`.

* Update questmgr.cpp

* Update questmgr.cpp

* Update questmgr.cpp

* Update questmgr.cpp
2023-04-23 15:08:32 -04:00
Alex King e3761cf2a3 [Cleanup] Add check for owner in quest::resumetimer() (#3305)
# Notes
- We didn't check for owner before doing `owner->GetName()`.
2023-04-23 15:07:49 -04:00
Alex King ad1764b464 [Cleanup] Add cehck for owner in quest::pausetimer() (#3304)
# Notes
- We didn't check for `owner` before doing `owner->GetName()`.
2023-04-23 15:07:09 -04:00
Alex King 1c9ea57a4e [Cleanup] Fix possible nullptr in quest::addloot() (#3303)
# Notes
- We didn't check for `owner` before calling `owner->IsNPC()`.
2023-04-23 15:06:53 -04:00
Alex King 03c158b674 [Crash] Fix possible nullptr in Client::GetCharMaxLevelFromQGlobal() (#3317)
# Notes
- We could possibly not have a `zone` here, causing a crash.
- http://spire.akkadius.com/dev/release/22.9.1?id=3051
- http://spire.akkadius.com/dev/release/22.9.1?id=3052
- http://spire.akkadius.com/dev/release/22.9.1?id=3073
- http://spire.akkadius.com/dev/release/22.9.1?id=3102
- http://spire.akkadius.com/dev/release/22.9.1?id=3103
- http://spire.akkadius.com/dev/release/22.9.1?id=3104
- http://spire.akkadius.com/dev/release/22.9.1?id=3107
- http://spire.akkadius.com/dev/release/22.9.1?id=3108
- http://spire.akkadius.com/dev/release/22.9.1?id=3109
- http://spire.akkadius.com/dev/release/22.9.1?id=3110
- http://spire.akkadius.com/dev/release/22.9.1?id=3111
- http://spire.akkadius.com/dev/release/22.9.1?id=3112
- http://spire.akkadius.com/dev/release/22.9.1?id=3113
- http://spire.akkadius.com/dev/release/22.9.1?id=3114
2023-04-23 15:05:47 -04:00
Aeadoin 39b5374e92 [Crash] Fix possible dereference of nullptr in Client::CalcHPRegen (#3316) 2023-04-23 14:27:43 -04:00
Aeadoin 2d3ddcb574 [Release] 22.10.0 (#3300) 2023-04-22 10:17:20 -04:00
Aeadoin ed09281f66 [Bug Fix] Camping was causing player to leave raid, causing unexpected behavior (#3299) 2023-04-22 10:03:40 -04:00
Paul Coene 8e51bf8b19 Fix crash when Removing empty password protected channel. (#3298) 2023-04-22 08:49:34 -04:00
Alex King 844efa7e20 [Cleanup] Breaks in wrong spot in cases in spell_effects.cpp (#3297)
* [Cleanup] Breaks in wrong spot in cases in spell_effects.cpp

# Notes
- These breaks were inside conditions, meaning the case wasn't always broken.

* Update spell_effects.cpp
2023-04-22 08:49:13 -04:00
Alex King fa3a5c7a72 [Feature] Make ornamentations work with any augment type (#3281)
* [Feature] Make ornamentations work with any augment type

# Notes
- On Live there are augments that are not type 20/21 and are ornamentations.
- We also only allow a singular augment type to be ornamentation augment types, this will allow you to use any augment type as an ornamentation if it has a proper Hero's Forge model or a non-IT63/non-IT64 idfile.

* Update ruletypes.h

* Update client_packet.cpp

* Update item_instance.cpp

* Cleanup.
2023-04-16 10:26:19 -04:00
Aeadoin 93db35658a [Crash] Add additional raid integrity checks on Bot Spawn. (#3295)
* simple cleanup before changes

* can't be in a raid yet

* change to sizeof

* change to use sizeof
2023-04-16 10:06:19 -04:00
Alex King d45a57056a [Cleanup] Remove getd(), geti(), InUse(), lasterr(), my_get_sv(), and VarExists() in embperl.cpp/embperl.h (#3283)
* [Cleanup] Remove getd(), geti(), InUse(), lasterr(), and VarExists() in embperl.cpp/embperl.h

# Notes
- These are unused.

* Update embperl.h

* Update embperl.cpp
2023-04-15 13:20:18 -04:00
Alex King ff40dbc710 [Cleanup] Utilize IsTaunting(), SetPetPower(), SetPetType(), and SetTaunting() (#3275)
* [Cleanup] Utilize SetPetPower() in zone/pets.cpp

# Notes
- This wasn't used before.

* Utilize other methods.

* Update special_attacks.cpp
2023-04-15 13:20:04 -04:00
Aeadoin 7523c972fa [Crash] Fix crash with uninitialized item instance, and Bot timeout (#3296) 2023-04-15 13:12:48 -04:00
Alex King 4320c1429e [Cleanup] Remove _GetMovementSpeed() from mob.h (#3276)
# Notes
- This is unused.
2023-04-14 19:42:48 -04:00
Alex King dc8bfddd7a [Cleanup] Remove IsFullHP from mob.cpp/mob.h (#3277)
# Notes
- This is unused.
2023-04-14 19:42:39 -04:00
Alex King a8cdfb07e6 [Cleanup] Remove pendinggroup from mob.h (#3278)
# Notes
- This is unused.
2023-04-14 19:42:27 -04:00
Alex King 011de2692e [Cleanup] Remove IsMeleeDmg() from skills.cpp/skills.h (#3279)
# Notes
- This is unused.
2023-04-14 19:42:14 -04:00
Alex King 0cc76ab489 [Cleanup] Remove position_same_update_count from client.cpp/client.h (#3280)
# Notes
- This is unused.
2023-04-14 19:42:01 -04:00
Alex King c5c9985e0d [Cleanup] Remove ExportVarComplex() from embparser.cpp/embparser.h (#3282)
# Notes
- This is unused.
2023-04-14 19:41:23 -04:00
Alex King a7e95d7818 [Cleanup] Delete embxs.cpp/embxs.h (#3284)
* [Cleanup] Delete embxs.cpp/embxs.h

# Notes
- These files and the one method in them are unused.

* Update embperl.cpp
2023-04-14 19:40:51 -04:00
Alex King 933d856b5b [Cleanup] Remove GetQGlobal() from qglobals.cpp/qglobals.h (#3285)
# Notes
- This is unused.
2023-04-14 19:40:35 -04:00
Alex King 285cc3af29 [Cleanup] Remove item_timers from questmgr.cpp/questmgr.h (#3286)
* [Cleanup] Remove item_timers from questmgr.cpp/questmgr.h

# Notes
- This is unused.

* Update questmgr.h
2023-04-14 19:40:21 -04:00
Alex King de8ae7afa6 [Cleanup] Cleanup zone/zoning.cpp (#3289)
# Notes
- Duplicate outcome cases in `Client::Handle_OP_ZoneChange`.
- Use `.length()` over `strlen` in array defintition.
- Remove unnecessary `else if` in `Client::ZonePC`
2023-04-14 19:40:01 -04:00
Alex King 1b272cba50 [Cleanup] Remove unused ctor and use default dtor in xtargetautohaters.h (#3290)
* [Cleanup] Remove unused ctor and use default dtor in xtargetautohaters.h

# Notes
- Utilize default dtor.
- Remove unused ctor.

* Update zone_event_scheduler.cpp
2023-04-14 19:39:25 -04:00
Alex King e35e38b039 [Cleanup] Remove unused variables and use reference in task_manager.cpp (#3291)
# Notes
- Remove unused `query` and `item` variable.
- Use a reference for task data instead of calling `cts->m_completed_tasks[task_index]` over and over.
2023-04-14 19:39:07 -04:00
Alex King 9215ba7a8a [Cleanup] Remove always true statements in task_client_state.cpp (#3292)
# Notes
- `!tasks_enabled.empty()` is always true.
- `tasks_disabled.size()` is always true.
2023-04-14 19:38:35 -04:00
Alex King 3f4334985b [Cleanup] Remove unnecessary condition and cleanup variable name in tasks.cpp (#3293)
# Notes
- `task_state` is verified by `safe_delete`.
- `size` is the name of a member variable, we should just use `sizeof(uint32_t)` instead.
2023-04-14 19:38:28 -04:00
Alex King 21002c2e8a [Quest API] Fix LDoN Methods in Perl/Lua (#3287)
# Perl
- Add `quest::removeldonloss(theme_id)`.
- Add `quest::removeldonwin(theme_id)`.

# Lua
- Fix `eq.remove_ldon_win(theme_id)` as it was using `quest_manager.addldonwin(theme_id)` instead of `quest_manager.removeldonwin(theme_id)`.
2023-04-10 16:16:54 -04:00
Alex King 445f967ed6 [Quest API] Add ApplySpellRaid() and SetSpellDurationRaid() to Bots in Perl/Lua (#3274)
# Perl
- Add `$bot->ApplySpellRaid(spell_id)`.
- Add `$bot->ApplySpellRaid(spell_id, duration)`.
- Add `$bot->ApplySpellRaid(spell_id, duration, allow_pets)`.
- Add `$bot->ApplySpellRaid(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `$bot->SetSpellDuration(spell_id)`.
- Add `$bot->SetSpellDuration(spell_id, duration)`.
- Add `$bot->SetSpellDuration(spell_id, duration, allow_pets)`.
- Add `$bot->SetSpellDuration(spell_id, duration, allow_pets, is_raid_group_only)`.

# Lua
- Add `bot:ApplySpellRaid(spell_id)`.
- Add `bot:ApplySpellRaid(spell_id, duration)`.
- Add `bot:ApplySpellRaid(spell_id, duration, allow_pets)`.
- Add `bot:ApplySpellRaid(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `bot:SetSpellDuration(spell_id)`.
- Add `bot:SetSpellDuration(spell_id, duration)`.
- Add `bot:SetSpellDuration(spell_id, duration, allow_pets)`.
- Add `bot:SetSpellDuration(spell_id, duration, allow_pets, is_raid_group_only)`.

# Notes
- These methods weren't added initially as we did not support bots in raid groups until recently.
2023-04-09 12:00:12 -04:00
Alex King 57a15d473f [Quest API] Add GetBuffSpellIDs() to Perl/Lua (#3273)
# Perl
- Add `$mob->GetBuffSpellIDs()`.

# Lua
- Add `$mob->GetBuffSpellIDs()`.

# Notes
- These methods allow operators to get a list of a mob's buff IDs without having to loop through their buffs themselves.
2023-04-09 10:58:35 -04:00
Trent df92c578d2 [Rules] Optional summoning when already in melee range (#3204)
* Add summon melee range rule

* Fix compilation

* Remove redundant range check for HateSummon
2023-04-08 18:04:17 -04:00
Aeadoin 3af43a8e8d [Hotfix] Resolve loading of inventory (#3272) 2023-04-08 17:45:06 -04:00
Aeadoin 647bcce30b [Crash] Resolve crash due to uninitialized pointer. (#3271) 2023-04-08 17:21:53 -04:00
Alex King 25b527156c [Cleanup] Fix possible nullptr inst in GetSharedBank() (#3190)
* [Cleanup] Fix possible nullptr inst in GetSharedBank()

# Notes
- We weren't continuing if we had a `nullptr`.

* Update shareddb.cpp

* Fix.
2023-04-08 09:42:10 -04:00
Aeadoin b3ab7deb80 [Bots] Cleanup GetBotTables() (#3270) 2023-04-06 17:43:57 -05:00
Alex King 4a9cb07132 [Cleanup] Remove unnecessary setting of reuse variable in Bot::DoClassAttacks() (#3233)
# Notes
- Bash, Kick, and Taunt have the same reuse time, no reason to set it to the same value.
2023-04-05 19:17:15 -04:00
Alex King 8f1b62d166 [Cleanup] Remove always true/false conditions from bot.cpp (#3237)
* [Cleanup] Remove always true/false conditions from bot.cpp

# Notes
- Some of these conditions were always true or false based on previous conditions.

* Update bot.cpp
2023-04-05 19:05:49 -04:00
Alex King 7e9994b5d4 [Cleanup] Fix ornamentation augment icons in inspect requests (#3264)
* [Cleanup] Fix ornamentation augment icons in inspect requests

# Notes
- We were not setting `aug_item` to the ornamentation augment when we found one.

* Update client.cpp
2023-04-05 19:04:32 -04:00
Chris Miles f2f8fae58b [Telnet] Telnet encoding fix (#3269) 2023-04-05 12:16:25 -04:00
Alex King 3a1e88f9ed [Cleanup] Remove unused SetConfigFile in common/eqemu_config.h (#3208)
# Notes
- This is unused.
2023-04-05 12:15:10 -04:00
Alex King 4e101aa6d6 [Cleanup] Use default dtor instead of empty dtor for EQTime in eqtime.cpp/eqtime.h (#3210)
# Notes
- This is better than using an empty dtor.
2023-04-05 12:15:02 -04:00
Alex King ef411ee154 [Cleanup] Use default ctor instead of an empty ctor. (#3206)
# Notes
- Use `= default;` instead of an empty ctor.
- https://pvs-studio.com/en/docs/warnings/v832/
2023-04-05 12:14:22 -04:00
Alex King 93b3f97f24 [Cleanup] Cleanup discord.cpp and discord_manager.cpp (#3205)
# Notes
- Unused variables in `discord.cpp`.
- Use `.clear()` instead of setting to `""` in `discord_manager.cpp`.
2023-04-05 12:14:14 -04:00
Alex King c1d4cb90b9 [Cleanup] Cleanup cheap-to-copy reference to use value instead in eq_stream_ident.cpp/eq_stream_ident.h (#3209)
# Notes
- More performant to pass by value than by reference.
2023-04-05 12:14:01 -04:00
Alex King e939c82717 [Cleanup] Convert equipable_slot_list to std::vector from std::list in bot_command.cpp (#3253)
# Notes
- No need to use a `std::list` here.
2023-04-05 11:35:04 -04:00
Alex King 7d03479f41 [Cleanup] Use constant reference and check for empty string properly in dbcore.cpp (#3203)
# Notes
- Passing by constant reference is more performant.
- Checking for empty string with `!= '\0'` is more performant.
- https://pvs-studio.com/en/docs/warnings/v805/
- https://pvs-studio.com/en/docs/warnings/v813/
2023-04-05 11:27:50 -04:00
Alex King ff440e16b6 [Cleanup] Use .clear() and .empty() instead of comparing to empty string or setting to empty string in CheckDatabaseConvertPPBlob() (#3201)
# Notes
- Use these methods to increase performance.
2023-04-05 11:27:12 -04:00
Alex King c6bb0f6495 [Cleanup] Move variable definition to more relevant scope in DatabaseDumpService::Dump() (#3200)
# Notes
- This was unused except for in this one spot, move to scope of condition where it's used.
- https://pvs-studio.com/en/docs/warnings/v821/
2023-04-05 11:26:21 -04:00
Alex King d142bc552a [Cleanuo] Only define row if we have results in Database::GetCharacterID() (#3199)
# Notes
- This is more performant and we don't unnecessarily define a variable we can't use.
- https://pvs-studio.com/en/docs/warnings/v821/
2023-04-05 11:25:28 -04:00
Alex King 7dc57c3b05 [Cleanup] Utilize .empty() instead of checking for an empty string in Database::ReserveName() (#3198)
# Notes
- This is more performant.
- https://pvs-studio.com/en/docs/warnings/v815/
2023-04-05 11:24:54 -04:00
Alex King ea9b09cf1f [Cleanup] Remove unused variable in Database::CopyCharacter() (#3197)
# Notes
- This variable was created but never used.
- https://pvs-studio.com/en/docs/warnings/v808/
2023-04-05 11:24:27 -04:00
Alex King 968278d8f8 [Cleanup] Use .clear() instead of setting string to empty in eqemu_command_handler.cpp (#3195)
# Notes
- `x = ""` has less performance than `x.clear()`.
- https://pvs-studio.com/en/docs/warnings/v815/
2023-04-05 11:24:12 -04:00
Alex King aa910864c8 [Cleanup] Remove unused macros in common/types.h (#3194)
# Notes
- These are unused.
2023-04-05 11:23:37 -04:00
Alex King 1499f3338e [Cleanup] Remove always true condition in Strings::Commify() (#3193)
# Notes
- `i < 0` was always true.
2023-04-05 11:23:24 -04:00
Alex King fef2f9fc61 [Cleanup] Fix shared_tasks.cpp/shared_tasks.cpp variable named same as class member (#3192)
* [Cleanup] Fix shared_tasks.cpp/shared_tasks.cpp variable named same as class member

# Notes
- This variable was named `m_db_shared_task` which is the same as `SharedTask:;m_db_shared_task`.

* Single letter receiver of complex type.
2023-04-05 11:22:42 -04:00
Alex King 8afbc585da [Cleanup] Remove bool return from GetSharedPlatinum() (#3191)
# Notes
- This was returning `false` and implicitly converting it to an integer.
2023-04-05 11:22:23 -04:00
Alex King 457ce85746 [Cleanup] Cleanup always true/false statements in shareddb.cpp (#3189)
# Notes
- `parent_index < EQ::invslot::SLOT_BEGIN` was always `false`.
- `item->LoreGroup != -1` was always `true`.
2023-04-05 11:21:43 -04:00
Alex King 49c093dc62 [Cleanup] Remove always true statement in say_link.cpp (#3188)
# Notes
- This is always true since we check `!saylinks.empty()` prior to this.
2023-04-05 11:20:52 -04:00
Alex King beccd557a8 [Cleanup] Cleanup item_instance.cpp always true statements and reassigning of same values (#3187)
# Notes
- Some things were always true.
- Some values were reassigned to the value they already were.
2023-04-05 11:20:36 -04:00
Alex King e11610b9fa [Cleanup] Remove unnecessary check for IsStackable() in DeleteItem() (#3186)
# Notes
- We check the opposites therefore we don't need either.
- https://pvs-studio.com/en/docs/warnings/v728/
2023-04-05 11:20:13 -04:00
Alex King 3e652b98bc [Cleanup] Cleanup macros in features.h (#3185)
# Notes
- These needed to either be wrapped in parentheses or simplified to their values.
- https://pvs-studio.com/en/docs/warnings/v1003/
2023-04-05 11:18:22 -04:00
Alex King d43af28de4 [Cleanup] Multiple cases with same outcome in GetDiscordPayloadFromEvent() (#3184)
# Notes
- All 4 of these use `FormatWithNodata`.
2023-04-05 11:17:52 -04:00
Alex King f5106b6af6 [Cleanup] Remove unused code in eq_packet.cpp/eq_packet.h (#3183)
# Notes
- These are unused.
2023-04-05 11:17:29 -04:00
Alex King 3386d13d2d [Cleanup] results variable is assigned but never used in SaveCharacterCreate() (#3180)
# Notes
- This was unnecessary since `QueryDatabase()` runs regardless.
2023-04-05 11:17:10 -04:00
Alex King d1b7c675f9 [Cleanup] Validate for nullptrs in bot.cpp (#3232)
* [Cleanup] Validate for nullptrs in bot.cpp

# Notes
- Validate for nullptrs in these spots in bot.cpp before using the variable.

* Update bot.cpp
2023-04-05 11:15:46 -04:00
Alex King a40e1cf893 [Cleanup] Add missing breaks and returns in bonuses.cpp (#3231)
# Notes
- Many spots were missing a `break;` or a `return` for their value.
2023-04-05 11:15:22 -04:00
Alex King c81ab00764 [Cleanup] Set bonuses to use spell ID instead of boolean (#3230)
# Notes
- Spell bonuses `Illusion` is the spell ID, not a boolean.
2023-04-05 11:14:55 -04:00
Alex King 025ef5e1d6 [Cleanup] Move unreachable code in ApplySpellsBonuses() (#3229)
# Notes
- This code was unreachable since it was inside the switch and should have been checked on its own in the condition where we verify we are using AISpellEffects.
2023-04-05 11:14:28 -04:00
Alex King 1f29a40e6d [Cleanup] Remove extraneous check for NegateAttacks in SE_NegateAttacks (#3228)
# Notes
- We checked both, we only need to check one.
2023-04-05 11:12:02 -04:00
Alex King 66cadd599b [Cleanup] Remove extraneous parentheses around math in Mob::ApplySpellsBonuses() (#3227)
# Notes
- Extra parentheses.
2023-04-05 11:11:41 -04:00
Alex King aa0345c1f1 [Cleanup] Cleanup duplicate conditions in negate bonuses in bonuses.cpp (#3226)
# Notes
- Lots of duplicate conditions.
2023-04-05 11:11:22 -04:00
Alex King 73b11c5036 [Cleanup] SE_StrikeThrough and SE_StrikeThrough2 are the same in bonuses.cpp (#3223)
# Notes
- These were the same code duplicated.
2023-04-05 11:05:59 -04:00
Alex King efbeb2dbb7 [Cleanup] SE_AttackSpeed3 effect_value is always less than 0 (#3222)
# Notes
- This was always false.
2023-04-05 11:05:44 -04:00
Alex King 8c97c20727 [Cleanup] Fix skill_used being used as boolean in Mob::CommonDamage() (#3220)
# Notes
- This is unnecessary as we always have a skill value.
2023-04-05 11:03:28 -04:00
Alex King f2d07e5c69 [Cleanup] Remove unnecessary break in while loop in Mob::AddToHateList() (#3219)
# Notes
- This is unnecessary and breaks the loop for no reason.
2023-04-05 10:31:57 -04:00
Alex King 64d5b54e65 [Cleanup] Fix filter condition in attack.cpp (#3218)
# Notes
- This condition was causing them to be used as `booleans` versus being checked individually.
2023-04-05 10:31:34 -04:00
Alex King 89b3a04eb3 [Cleanup] Identical conditions right beside each other in aa.cpp (#3213)
# Notes
- These conditions were identical and could be consolidated.
2023-04-05 10:30:27 -04:00
Alex King 1bafe0b6b3 [Cleanup] other is always defined in these cases in attack.cpp (#3217)
# Notes
- `other` is always defined since we check it prior to checking here.
2023-04-05 10:30:13 -04:00
Alex King 82762c3f5a [Cleanup] Use variable for character instead of a loop (#3268)
# Notes
- Store character in a variable instead of looping a list of 1 entry.
2023-04-05 10:29:16 -04:00
Alex King 2742eca119 [Cleanup] Remove unnecessary conditions in Client::SendFactionMessage() (#3267)
# Notes
- `faction_value < this_faction_max` and `faction_value > this_faction_min` are always true if they get to that point in the code.
2023-04-05 10:27:15 -04:00
Alex King 8fc7f3a732 [Cleanup] Cleanup unnecessary condition in Client::SendAlternateCurrencyValue() (#3266)
# Notes
- `value == 0` is unnecessary as it can only be 0 if we fail the `value > 0` check.
2023-04-05 10:27:01 -04:00
Alex King 39ce0178f9 [Cleanup] Remove unnecessary conditions in Client::Consume() (#3265)
# Notes
- We check `increase < 0` prior to this, so this can't ever happen.
2023-04-05 10:26:32 -04:00
Alex King 3d2f560436 [Cleanup] Fix GetLastName() length check in Client::SendWindow() (#3263)
# Notes
- `target->GetLastName()` was always true, we need to make sure the target has a last name.
2023-04-05 10:23:54 -04:00
Alex King a0768d2d28 [Cleanup] Remove unnecessary conditions in Client::FilteredMessageCheck() (#3262)
# Notes
- We check `FilterHide` prior to the secondary conditions, so it can never show up.
2023-04-05 10:23:33 -04:00
Alex King 9009a7aa23 [Cleanup] Remove extra assignment of current_endurance in Client ctor (#3261)
# Notes
- We already assign `current_endurance` to `0`, no need to do it again.
2023-04-05 10:23:20 -04:00
Alex King 67b03b4e31 [Cleanup] Combine similar cases in Client::InitInnates() (#3260)
# Notes
- These cases were the same, consolidating them is better.
2023-04-05 10:23:05 -04:00
Alex King b08975aefb [Cleanup] Use .empty() in Client::ScribeSpells() and Client::LearnDisciplines() (#3259)
* [Cleanup] Use .empty() in Client::ScribeSpells() and Client::LearnDisciplines()

# Notes
- Use `.empty()` instead of using a variable storing size in condition.

* Update client.cpp
2023-04-05 10:22:36 -04:00
Alex King ea3a7cae0b [Cleanup] Remove always true conditions and unreachable code in Client::SendMercPersonalInfo() (#3258)
* [Cleanup] Remove unreachable code in Client::SendMercPersonalInfo()

# Notes
- This cannot be reached due to prior returns.

* Update client.cpp

* Update client.cpp
2023-04-05 10:14:07 -04:00
Alex King 81314a3315 [Cleanup] Fix check for !this in Client::SendHPUpdateMarquee() (#3257)
# Notes
- `!this` isn't valid, as `this` can never be nullptr.
2023-04-05 10:13:24 -04:00
Alex King d33cfad567 [Cleanup] Fix always false conditions in Client::IncStats() (#3256)
# Notes
- Value can never be less than `0` as it's unsigned.
2023-04-05 10:12:32 -04:00
Alex King c1698a5bdd [Cleanup] Fix possible overflows in Client::AddPlatinum() and Client::TakePlatinum() (#3255)
# Notes
- Fix possible overflows by casting properly.
2023-04-05 10:10:33 -04:00
Alex King 2a094e8792 [Cleanup] Use variable for c->GetTarget() instead of calling multiple times in bot_command.cpp (#3254)
# Notes
- Calling multiple times is less performant than using a variable.
2023-04-05 10:09:19 -04:00
Alex King 4a0725e278 [Cleanup] Cleanup string -> char* -> string conversions in bot_command.cpp (#3252)
# Notes
- We were converting back and forth between types unnecessarily.
2023-04-05 09:59:43 -04:00
Alex King 218ffbb2c5 [Cleanup] Delete unused strings in bot_command.cpp (#3251)
# Notes
- These are unused.
2023-04-05 09:59:24 -04:00
Chris Miles 3e30e78158 [Backups] Fix database dump error reporting (#3175)
* [Backups] Fix database dump error reporting

* Update database_dump_service.cpp
2023-04-04 00:14:23 -05:00
Aeadoin ff2af0c49e [Release] 22.9.1 (#3250) 2023-04-03 17:49:39 -04:00
Alex King cd5697bc81 [Cleanup] Multiple cases same outcome and set skip variable to same value (#3216)
# Notes
- `skip` is set to `attacker` before it's set to `attacker` again.
- Multiple spots in `Mob::AttackAnimation` use the same animations.
2023-04-03 17:24:27 -04:00
Alex King b1571cd062 [Cleanup] Wake The Dead argument was named the same as a member variable in Mob (#3214)
# Notes
- Member variable is also named `target`.
2023-04-03 17:23:48 -04:00
Alex King 3e5d0a0601 [Cleanup] Unconditional return in for loop in GetRaidByCharID() (#3179)
# Notes
- This is improper and should just check if we have no result, return `0`, otherwise return `row[0]` of the row we queried.
2023-04-03 17:23:32 -04:00
Alex King 6a80a061dd [Cleanup] Multiple cases with same outcome in GetGMSayColorFromCategory() (#3182)
# Notes
- Both cases have the same return.
- https://pvs-studio.com/en/docs/warnings/v1037/
2023-04-03 17:20:43 -04:00
Alex King 509fd0615e [Cleanup] Remove unused query variable in Database::DeleteInstance() (#3202)
# Notes
- Variable was defined but never used.
2023-04-03 17:18:40 -04:00
Alex King da5e672a28 [Cleanup] Remove unnecessary group validation in Bot::Death() (#3235)
# Note
- We already break if there is no group above, revalidation is unnecessary.
2023-04-03 17:15:09 -04:00
Alex King 7090382074 [Cleanup] Remove unnecessary skill_to_use check in Bot::DoClassAttacks() (#3236)
# Notes
- `skill_to_use` will never be `-1` as it passes through the switch and checks class.
2023-04-03 17:11:56 -04:00
Alex King 26eabcd7a4 [Cleanup] Explicitly cast to float for more precision in Bot::GenerateBastHitPoints() (#3238)
# Notes
- Not casting explicitly we lost precision.
2023-04-03 17:05:48 -04:00
Alex King 60091015d3 [Cleanup] Remove unnecessary >= 0 checks for procs in botspellsai.cpp (#3242)
# Notes
- These are always `>= 0` since they're `uint16`.
2023-04-03 17:05:03 -04:00
Alex King 470392021b [Cleanup] Remove unnecessary setting of spell_type_index in Bot::GetChanceToCastBySpellType() (#3243)
# Notes
- The default is already `SPELL_TYPE_COUNT`, no need to set it again.
2023-04-03 17:04:51 -04:00
Alex King 90984c3215 [Cleanup] Remove unnecessary spell_list validation check in botspellsai.cpp (#3244)
# Notes
- We check if valid above, no need to do it again.
2023-04-03 17:03:56 -04:00
Alex King da2296d416 [Cleanup] Remove unnecessary hpr checks in Bot::BotCastHeal() (#3245)
# Notes
- These checks are unnecessary as we know it doesn't pass previous checks.
2023-04-03 17:03:36 -04:00
Alex King c9221f239c [Cleanup] Remove unnecessary botCaster check in Bot::GetDebuffBotSpell() (#3246)
# Notes
- We already check if `botCaster` is invalid above, no need to do so again.
2023-04-03 17:02:48 -04:00
Alex King f4edc69a87 [Cleanup] Cleanup unnecessary string -> char* -> string conversions in eqemu_config.cpp (#3207)
# Notes
- These conversions are unnecessary since we can just use the string itself.
2023-04-03 17:01:44 -04:00
Alex King 7d04608c4d [Cleanup] summon_count > MAX_SWARM_PETS is always false in aa.cpp (#3212)
# Notes
- This was always false.
2023-04-03 17:00:08 -04:00
Alex King 32be049d96 [Cleanup] Remove extraneous loottable_id setting in WakeTheDead in aa.cpp (#3215)
# Notes
- We already set `made_npc->loottable_id` to `0` above.
2023-04-03 16:59:06 -04:00
Alex King 26fd52fb06 [Cleanup] Fix SEResist array settings duplicate code (#3225)
# Notes
- These conditions did the same thing, combining them is simpler.
2023-04-03 16:53:48 -04:00
Alex King 5dd849ac75 [Cleanup] Fix typo where itembonuses should have been used instead of spellbonuses (#3221)
# Notes
- `itembonuses` was the proper name here, not `spellbonuses`.
2023-04-03 16:51:22 -04:00
Alex King f484fe4176 [Cleanup] gid is assigned 2 values simultaneously in bot.cpp (#3234)
# Notes
- Unnecessarily assigning the value twice simultaneously.
2023-04-03 16:47:46 -04:00
Alex King 3d20c0d6aa [Cleanup] Change level to bot_level in Bot::DoClassAttacks() to not overlap member variable (#3239)
# Notes
- Member variable is named `level`, change variable to `bot_level` so we don't cause issues.
2023-04-03 16:47:31 -04:00
Alex King 0297045cc5 [Cleanup] Move cases in Bot::AICastSpell() (#3247)
# Notes
- These all returned `false`, no need to be separate.
2023-04-03 16:46:31 -04:00
Alex King cb90d00832 [Cleanup] Cleanup variable names in Bot::AddSpellToBotList() (#3248)
# Notes
- `max_hp` was named after a member variable.
2023-04-03 16:45:36 -04:00
Aeadoin f752b57a55 [Cleanup] Cleanup uses of insert/push_back when a temp object is used. (#3170) 2023-04-03 16:45:01 -04:00
Alex King 2bb15271c5 [Cleanup] Fix possible dereferencing of invalid iterator in constants (#3181)
# Notes
- Possible dereferencing of invalid iterator based on logic: https://pvs-studio.com/en/docs/warnings/v783/
2023-04-03 16:42:45 -04:00
Alex King 6976e27501 [Cleanup] Use a constant reference for content_flags in SetContentFlags() (#3196)
# Notes
- This is more performant.
- https://pvs-studio.com/en/docs/warnings/v813/
- https://pvs-studio.com/en/docs/warnings/v820/
2023-04-03 16:38:20 -04:00
Alex King c9f27d6f90 [Cleanup] Remove possible dereferenced nullptrs in bot.cpp (#3241)
# Notes
- Possible dereferenced nullptrs based on logic.
2023-04-03 16:30:46 -04:00
Alex King cb129efcad [Cleanup] Fix loop and code duplication for SE_ProcOnKillShot (#3224)
* [Cleanup] Fix loop for SE_ProcOnKillShot

# Notes
- We were doing `e = 3` instead of doing `e += 3`.

* Update bonuses.cpp
2023-04-03 16:28:15 -04:00
Aeadoin d653989b03 [Bug Fix] Fix issue with Bot Raid invites not working. (#3249)
* [Bug Fix] Fix issue with Bot Raid invites not always working.

* ordering
2023-04-03 16:28:05 -04:00
Alex King ea9b373180 [Cleanup] Further bot.cpp nullptr checks (#3240)
# Notes
- `nullptr` validation
2023-04-03 16:25:00 -04:00
Aeadoin a4e006fbfb [Bug Fix] Correct Forward Declaration compilation warning (#3176)
* [Bug Fix] Correct Forward Declaration compilation warning

* no need for include
2023-04-02 12:19:43 -04:00
Aeadoin 1ffdd4cb34 [Performance] Change to use Pass by reference where valid. (#3163)
* [Performance] Change to use Pass by reference where valid.

* typo
2023-04-01 22:55:40 -04:00
Aeadoin 7f7ba2e6c2 [Cleanup] Remove unused Includes under zone files (#3162) 2023-04-01 22:55:28 -04:00
Aeadoin 090086f50c [Release] 22.9.0 (#3174) 2023-04-01 14:27:52 -04:00
Alex King 407b003f7d [Cleanup] Add client pointer validation to Zone::GetClosestZonePoint() (#3173)
# Notes
- We were not validating pointer here, could cause issues.
2023-04-01 14:22:52 -04:00
Alex King b6d315d803 [Cleanup] Remove unnecessary validation check in Zone::ClearBlockedSpells() (#3172)
# Notes
- This is unnecessary, since `safe_delete_array` checks for validity.
2023-04-01 13:59:03 -04:00
Aeadoin 6927177291 [Fix] Correct SE_SlayUndead & SE_HeadShotLevel limit Value when applied. (#3171) 2023-04-01 13:31:13 -04:00
Aeadoin 31ede355a8 [Cleanup] Cleanup excessive type casting: string -> char * -> string (#3169)
* [Cleanup] Cleanup excessive type casting: string -> char * -> string

* [Cleanup] Cleanup excessive type casting: string -> char * -> string
2023-04-01 12:45:16 -04:00
Aeadoin 0df84e1ee6 [Crash] Fix out of bound arrays, other potential crashes (#3166) 2023-04-01 12:44:41 -04:00
Aeadoin 0d509a7f3a [Crash] Add Checks for valid pointers or fix existing. (#3164) 2023-04-01 12:44:00 -04:00
Aeadoin 4c2271ff69 [Fix] Prevent VerifyGroup from setting OOZ membername to Null character. (#3168) 2023-04-01 12:40:55 -04:00
Aeadoin ca2072e7bf [Bots] Remove Bot Groups Functionality (#3165)
* [Bots] Remove Bot Groups Functionality

* in-class initializers for member variables.
2023-03-31 21:37:52 -04:00
Alex King e1eb1ff738 [Quest API] Add missing Luabind definitions to lua_general.cpp (#3167)
# Notes
- These definitions were missing somehow.
2023-03-31 21:05:01 -04:00
Aeadoin 25f5898bae [Release] 22.8.2 (#3161) 2023-03-30 09:22:58 -04:00
Aeadoin 934ff3dadf [Bug Fix] Correct logic checks for Bot rule AllowOwnerOptionAltCombat (#3158)
* [Bug Fix] Correct logic checks for Bot rule AllowOwnerOptionAltCombat

* fix ordering of raid/group checks
2023-03-30 08:31:57 -04:00
Aeadoin e4ff76dceb [Bug Fix] Fix for OOZ Group updates when removing/inviting Bots (#3159)
* [Bug Fix] Fix for Cross Zone Group updates with Bots when disbanding/joining groups.

* check for nullptr
2023-03-30 08:31:50 -04:00
Alex King 6960a1a682 [Bug Fix] Fix issues with Lua tables not starting at index 1 (#3160)
* [Bug Fix] Fix issues with Lua tables not starting at index 1

# Notes
- This would cause the first item in the table to be inaccessible since Lua tables start at index `1` instead of index `0`.
- All other spots using Lua tables have their indexes starting at `1`.

* Update lua_general.cpp
2023-03-30 06:02:53 -04:00
Aeadoin d4174ca236 [Fix] Fix strcpy-param-overlap (#3157) 2023-03-29 08:33:06 -04:00
Aeadoin 7854130a93 [Bug Fix] Check Rule "Bots Enabled" to prevent bot database calls on connect (#3154)
* [Bug Fix] Check for Rule "Bots Enabled" to prevent bot database calls if not enabled.

* formatting

* check if LoadBotsList failed, or is bots_list empty
2023-03-28 22:44:47 -04:00
Alex King e9c63c7d94 [Rules] Remove Guild Bank Zone ID Rule (#3156)
# notes
- This rule is useless as guild bank zone ID is hard-coded into the client.
2023-03-28 21:58:58 -04:00
Aeadoin 27e0665aae [Bug Fix] Fix bot_raid_members.sql for MYSQL. (#3155) 2023-03-28 15:25:16 -04:00
Alex King ea2f431fce [Fix] Fix an issue with EVENT_DISCONNECT not firing on regular /camp (#3153)
* [Fix] Fix an issue with EVENT_DISCONNECT not firing on regular /camp

# Notes
- We were only sending `EVENT_DISCONNECT` on GM instant camps or linkdeads.

* Update client_process.cpp
2023-03-27 21:45:02 -04:00
Aeadoin 8bdcf7cb94 [Crash] Add Checks for out of bounds & dereferencing nullptrs (#3151)
* [Crash] Add Checks for out of bounds/nullptr dereferences

* formatting

* formatting

* formatting

* Update bot.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-03-27 21:43:46 -04:00
Aeadoin 87cb74b851 [Release] 22.8.1 (#3152) 2023-03-27 17:55:48 -04:00
Alex King 26c267db1b [Cleanup] "equipped" not "equiped", "dual" not "duel". (#3149)
* [Cleanup] "equipped" not "equiped", "dual" not "duel".

# Notes
- These are spelled incorrectly.

* Update spdat.h

* Formatting further.

* Update api_service.cpp
2023-03-27 17:55:37 -04:00
Aeadoin 99f8e6cef5 [Bug Fix] Fix for NPCs having spells interrupted. (#3150) 2023-03-27 16:57:08 -04:00
Aeadoin b6917ec782 [Release] 22.8.0 (#3148) 2023-03-25 20:48:43 -04:00
Aeadoin eb51550109 [Cleanup] Cleanup Strings::ToInt uses. (#3142)
* [Cleanup] Cleanup Strings::ToInt uses.

* fix for conversion

* remove != 0

* cleanup
2023-03-25 20:32:30 -04:00
Alex King 9d1ace627c [Feature] Add support for -1 extradmgskill to allow all skills to be scaled. (#3136)
* [Feature] Add support for -1 extradmgskill to allow all skills to be scaled.

- `$mob->GetSkillDmgAmt(skill_id)` now uses `int` instead of `uint16`.

- `statbonuses:GetSkillDamageAmount(skill_id)` now uses `-1` properly.
- `mob:GetSkillDmgAmt(skill_id)` now uses `int` instead of `uint16`.

- A `-1` value in `extradmgskill` denotes the ability to scale all skills at once.
- Consolidated `AddItemBonuses()`, `AdditiveWornBonuses()`, `CalcItemBonuses()`, and `CalcRecommendedLevelBonus()` to mob-based methods to avoid code duplication.
- Bots, NPCs, and Mercs can now use additive worn effects if the rule is enabled, as well as all other proper stat bonuses that only clients had before.
- No SQL update required to change `extradmgskill` and `extradmgamt` to `int` as they already are this type in the database, just had to adjust `item_data.h` and `shareddb.cpp`.

* Update mob.cpp

* Cleanup.

* Cleanup.

* Move #include <vector> to header.

* Add method for GetExtraDamageSkills

* fix additembonuses

* Update bonuses.cpp

* Update mob.cpp

* Out of bounds.

* Update bonuses.cpp

---------

Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
2023-03-25 20:26:01 -04:00
Aeadoin ec3ef411a1 [Fix] Fix for SQL Query in npc_scale_global_base (#3144) 2023-03-25 20:08:40 -04:00
Aeadoin 1394b6a4d2 [Hotfix] Fix for Items looted from corpses. (#3147) 2023-03-25 20:00:31 -04:00
Aeadoin 7f41547963 [Crash] Fix for crash in Raid::QueuePacket (#3145)
* [Crash] Fix for crash in Raid::QueuePacket

* bots can't be a part of BalanceMana

* corrected additions

* adding additional is_bot gates

* updating raid for loops to be range based.

* typo

* formatting

* formatting
2023-03-25 18:02:05 -04:00
Alex King 2e4071cdcf [Cleanup] Remove extern bool Critical (#3146)
# Notes
- This is unused.
2023-03-25 17:48:40 -04:00
Aeadoin dc475a1bd7 [Release] 22.7.0 (#3143) 2023-03-24 15:11:42 -05:00
Aeadoin 59ad91a140 [Feature] Add Data Bucket support for scaling of Heroic Stats. (#3058)
* [Feature] Add Data Bucket support for scaling of Heroic Stats.

* update

* fixes, still reworking logic

* fixes, still reworking logic

* logic done

* logic done

* fixes

* Cleanup

* Cleanup

* Cleanup naming, verify behaviors

* formatting

* formatting

* fix issue with endurance and mana.

* update rule desc

* cleanup

* DataBucket Struct

* Cleanup data_bucket.cpp and add constants

* cleanup

* changes

* formatting

* fix from merge

* escape keyword `key`

* Add `key` to generator, run repository-generator.pl

* fix for change to key

* cleanup

* formatting

* formatting

* typo
2023-03-23 21:42:13 -04:00
Aeadoin abc27ab423 [Bug Fix] Fix edge cases where camped bots would be left in a raid (#3139)
* [Bug Fix] Fix edge cases where camped bots would be left in a raid

* formatting
2023-03-23 19:23:34 -04:00
Aeadoin c975dc2412 [Bug Fix] Fix for transferring Raid Leader (#3140) 2023-03-23 19:04:59 -04:00
Aeadoin e085f271f5 [Bug Fix] Fix for incorrect bindpoint x,y,z,headings (#3141) 2023-03-23 18:55:56 -04:00
Alex 5a6314e1a9 [Fix] Fixes for corpses not properly saving some item instance data correctly. (#3123)
* Convert ZoneDb::LoadCharacterCorpseData to use a cleaner api that has a better layout.

* Update corpse save methods to use a new cleaner api.

* Add item to corpse will use a few new fields that don't yet save.

* Fix for some issues moving data to corpses.

* Make CreateItem more explicit to avoid overlooking places it's used and add more arguments.

* DB changes

* Revert of the changes to the database.CreateItem api change.

* Missed one.

* Fixes for mr Krab

* Small formatting

---------

Co-authored-by: KimLS <KimLS@peqtgc.com>
Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-03-23 01:16:52 -05:00
Aeadoin dc45e0d280 [Fix] Change SPA 193 Weapon Damage to allow values over 65,535 (#3138) 2023-03-23 01:06:51 -05:00
Aeadoin 2e2c4d64fe [Cleanup] Cleanup uses of Strings::ToInt to match correct type. (#3054)
* [Cleanup] Cleanup uses of Strings::ToInt to match correct type.

* cleanup
2023-03-22 12:22:03 -04:00
Aeadoin c5add503ab [Bug Fix] Fix for Raid Disband if leader not in same zone. (#3135) 2023-03-21 19:16:01 -04:00
Aeadoin fe2dcb6544 [Crash] Fix dangling Group member pointers for Bots. (#3134)
* [Crash] Fix dangling Group member pointers for Bots.

* fixes for edge cases
2023-03-21 11:57:04 -04:00
Alex King 4fe44f4cb6 [Quest API] Add Timer related methods to Mobs in Perl/Lua (#3133)
* [Quest API] Add Timer related methods to Mobs in Perl/Lua

# Perl
- Add `quest::ispausedtimer(timer_name)`.
- Add `quest::pausetimer(timer_name)`.
- Add `quest::resumetimer(timer_name)`.
- Add `$mob->GetRemainingTimeMS(timer_name)`.
- Add `$mob->GetTimerDurationMS(timer_name)`.
- Add `$mob->HasTimer(timer_name)`.
- Add `$mob->IsPausedTimer(timer_name)`.
- Add `$mob->PauseTimer(timer_name)`.
- Add `$mob->ResumeTimer(timer_name)`.
- Add `$mob->SetTimer(timer_name)`.
- Add `$mob->SetTimerMS(timer_name)`.
- Add `$mob->StopTimer(timer_name)`.

# Lua
- Add `mob:GetRemainingTimeMS(timer_name)`.
- Add `mob:GetTimerDurationMS(timer_name)`.
- Add `mob:HasTimer(timer_name)`.
- Add `mob:IsPausedTimer(timer_name)`.
- Add `mob:PauseTimer(timer_name)`.
- Add `mob:ResumeTimer(timer_name)`.
- Add `mob:SetTimer(timer_name)`.
- Add `mob:SetTimerMS(timer_name)`.
- Add `mob:StopTimer(timer_name)`.

# Notes
- The mob-based methods allow operators to loop entity list or whatever to set, stop, resume, pause, etc for timers.

* StopAllTimers()

* Update questmgr.cpp
2023-03-20 16:18:51 -04:00
Alex King 63a8d2d641 [Cleanup] Delete zone_numbers.h (#3129)
* [Cleanup] Delete zone_numbers.h

# Notes
- This is unused.

* Update client_packet.cpp

* Update client_packet.cpp
2023-03-20 12:06:40 -04:00
Alex King abcb5d069f [Cleanup] Remove FindPatch() from struct_category.cpp and struct_category.h (#3130)
# Notes
- This is unused.
2023-03-20 12:06:10 -04:00
Aeadoin d6b954a4b9 [Cleanup] Cleaning up Raid.cpp (#3125)
* [Cleanup] Cleanup Raid.cpp

* cleanup

* fix is_bot instances

* bracket cleanup

* bracket cleanup

* rename variables in struct

* fix for merge
2023-03-20 11:39:14 -04:00
Alex King 2415645b86 [Fix] Fix typo for bot_id raid_members column in db_update_manifest.txt (#3132)
# Notes
- This was causing this query to run over and over.
2023-03-19 22:32:35 -04:00
Aeadoin e77a83f8c3 [Rule] Add Rule to allow ExtraDmgSkill/SPA 220 to effect Spell Skills (#3124)
* [Rule] Add Rule to allow ExtraDmgSkill/SPA 220 to effect Spell Skills

* add support for rule "ItemExtraSkillDamageCalcAsPercent"
2023-03-19 12:16:32 -04:00
Alex King a5d564a6fb [Cleanup] Remove ChangeHP() from mob.h (#3128)
# Notes
- This is unused.
2023-03-19 10:18:31 -04:00
Alex King 2f4c91824e [Feature] Add Item Extra Skill Damage Percent Modifier (#3127)
* [Feature] Add Item Extra Skill Damage Percent Modifier

# Notes
- Allows `Character:ItemExtraDmgCap` to be disabled if set to `-1` or lower.
- Allows operators to set `Character:ItemExtraSkillDamageCalcAsPercent` to `true` to allow skill damage for Frenzy, Backstab, Bash, Slam, Kick, and all Monk attacks to scale with a percentage based on `extradmgamt` values from items and spells.

* > 0
2023-03-19 09:59:13 -04:00
Aeadoin 53e6f931c9 [Crash] Fixes Crash when Zoning with XTarget when Bots are in group. (#3126) 2023-03-19 08:26:16 -04:00
Alex King a6efb1e8b5 [Cleanup] Remove GetStartCount() and InitStartTimer() from zone_launch.cpp and zone_launch.h (#3121)
# Notes
- These are unused.
2023-03-17 19:21:50 -04:00
Alex King b2757143a8 [Cleanup] Remove SetConnection() from loginserver/world_server.h (#3120)
# Notes
- This is unused.
2023-03-17 19:21:44 -04:00
Alex King 6e5da0e558 [Cleanup] Remove GetServerByAddress() from server_manager.h (#3119)
# Notes
- This is unused.
2023-03-17 19:21:38 -04:00
Alex King 6b8e74a29f [Cleanup] Remove PlayerLogin_Struct from login_types.h (#3118)
# Notes
- This is unused.
2023-03-17 19:21:30 -04:00
Alex King 203e63101a [Cleanup] Remove IsConnected() from loginserver/database.h (#3117)
# Notes
- This is unused.
2023-03-17 19:21:18 -04:00
Alex King 91257d599b [Cleanup] Remove unused methods in loginserver/client.h (#3116)
* [Cleanup] Remove LoginOnNewConnection(), LoginOnPacketRecv(), and LoginOnStatusChange() from loginserver/client.h

# Notes
- These are unused.

* Cleanup.
2023-03-17 19:21:08 -04:00
Alex King 491b358e28 [Cleanup] Remove UpdateLoginserverWorldAdminAccountPasswordById() from account_management.cpp (#3115)
# Notes
- This is unused.
2023-03-17 19:20:56 -04:00
Alex King 180c3088ca [Cleanup] Remove DBInitVars() and HandleMysqlError() from queryserv/database.h (#3114)
# Notes
- These are unused.
2023-03-17 19:20:47 -04:00
Alex King 97e4547192 [Cleanup] Remove DBInitVars(), HandleMysqlError(), and IsChatChannelInDB() in ucs/database.h (#3113)
# Notes
- These are unused.
2023-03-17 19:20:41 -04:00
Aeadoin 0caee9026a [Rule] Add Task System Rule ExpRewardsIgnoreLevelBasedEXPMods (#3112)
* [Rule] Add Task System Rule ExpRewardsIgnoreLevelBasedEXPMods

* description
2023-03-17 19:15:02 -04:00
Aeadoin 0be7ead1d1 [Bug Fix] Fix Bard Bot Casting (#3122) 2023-03-17 19:07:54 -04:00
Aeadoin 950489bc34 [Bug Fix] Fix Raid methods that could cause crashes with Bots in raid (#3111) 2023-03-17 16:19:29 -04:00
Mitch Freeman 45da8cab61 [Bots] Add Basic Bot Raiding Functionality (#2782)
* Fix for GENERIC_9_STRINGS

* Add Bot Heal Message Display

Creates a new rule to display Bot heal messages to the Bot Owner

* 2021-03-25 11L04pm

Spell and Heal Rule added to allow for Bot spell and heal damage to be sent to the Bot Owner's Group.  Also added a check to remove duplicate message for #damage on self.

* Update .gitignore

* BOT work

Added BOT logging damage/heals to owner
Added BOT message to owner for harmony fails
Made var Critical global to remove duplicate crit messages
Added a NULL check to Mob:GetCleanname()

* Bot Group Work

Fixed botid=charid spawn on zone issue
Added a group_list update on zone to refresh from database to fix a dangling pointer to a Bot object that was camped but was previously in a group within the zone being entered.
Modified Bot::ProcessBotGroupInvite to use the client of the bot when doing the Bot initialization so that a leader can invite another owner's Bot

* Jan 4

Basic structure in place for Raid::AddBot though not working

* Basement Jan 5

* End of day Jan 5
Working Raid Invite to a Bot.

* Update to Client::QueuePacket to not attempt to send a packet to a BoT.  Not clean, but a broad solution.

* Updated Raid::VerifyRaid

* Some Bot Raid working

* Before VS Crash

* Use Case 1, 2, 3,4,7 working.
Need to fix 5, 6, 8

* Work on usecase 5

* A few more use cases working

* New work on Raid invite with a invitor having a group

* Bot Raid inviting working for all use cases

* A few changes

* end of day jan 10

* Jan 11

* end of day Jan 11

* Bot Invite/Accept cleanup

* Start of moving raid bot functions to their own methods

* More bot raid changes

* More raid spell work

* end of day Jan 16

* spawn work

* Spawn on login working

* End of Day Jan 18

* Raid leader and mana/hp updates fixed

* Spell Tracking

* Issue with Bot Death in raid when casted upon.  1741 raid.cpp

* Bot Death fixed and few other crashes

* Working on botgroup removal

* Bot Disbanding Work 90%

* Looks like BOTs are working

* Fixed a bot crash

* bug tracing on entity list mismatch

* safe_delete resoves problem.  No to track down leak

* seems to be working

* Memory corruption found - sending packets to BoTs using Client class

* added Raid::IsRaidMemberBot()

* Update p_raid_instance

* g3

* Final - Bot Raid Working

* Fixed IsRaidMemberBot to remove memory leak
Fixed altcombat crash though RaidMainAssist (428) needs fixing

* add RaidMember.IsBot

* Repaired IsBot function to be more preformant.  Now works on standard performance machine

* Fixed Bard AE Target Spells
Removed assert for buffs

* updated based on Feb 2022 master updates

* Added bot_db_updates and version increment

* Cleanup of bot raid work and inclusion of bot_raid in cmake

* Delete .gitignore

* Revert "Delete .gitignore"

This reverts commit 8523658d3b.

* Fixed a packet issue

* Merged upstream/master

Merged upstream/master and removed ifdef BOTS as per recent dev approach for BOTS.  Functionality is there, compiles and tests ok.  A few problems to be resolved though this is a good baseline.

* Added sql update for raid_members to add isbot

* Updated Bot Follow Function

Bot will now follow the Group Leader if IsClient, otherwise follows the Bot Owner

* Updates to Bot Raid System

When camping a client, remove them from the raid.  If they are leader, place leadership to the next client.
Update a few crash checks in bot_raid.cpp

* [BOTS] Added RuleB Enabled checks and updated base repo for raid_members

Updated several RuleB(Bots, Enabled) checks
Updated the base repo to be autogenerated.
Raid functionality should work with a non-bots enabled database.

* Few quick updates

* Updates

Corrected a number of comments.  Compiled and tested against bot and non-bot database though requires the isbot column in raid_members for both.
Moved the db update out of the bot stream to make bot check code easier.

* Formatting and other small updates

* A few more RuleB(Bots, Enabled) additions

* Fix issue with conflict of bot ID versus character ID.

* Delete CMakeSettings.json

* Comment Updates and other

Several updates including
- fixed comments from PR
- added id to raid_members and unique index on name to avoid botid and charid conflicts
- updated a few raid functions for iterators
- reordered several raid operations to ensure send leader packet to be the last item to ensure proper updating on the client
- update sql to use Replace instead of Insert for botid conflicting with charid

* Exploit fix for Raid Bots

Added item from @Nite to disallow spawning or camping bots if Raid is engaged.  Avoids abusive situations.

* Initial Commit

* fix Raid Window after zoning

The raid window was not fully updating for clients not in the zone.

* Cleanup

* Update

Fixed comments

* Resolve crash for MOTD

Fixed a crash situation sending a raid MOTD to BOTS.

* Update ruletypes.h

* Updated to resolve a few recent comments

Fixed some comments within attack.cpp

* fix sql query

* update repository

* prevent duplicate entries in raid after group invite, and cleanup

* fixes for botgroups not following, and add already in raid messages.

* fix messagestring

* fixes

* Cleanup, and resolving issues with disbanding

* refactoring

* more cleanup/fixing.

* fixes for removing from ground in raid

* Refactoring/fixing multiple clients

* fix for compiling

* Bugs from refactoring fixed

* Testing completed, cleaning up unwanted items/duplicate code.

* Cleaned up AICastSpell

* fix typos

* Refactoring

* Adding Raid checks to AI_Process/cleanup

* Fix a typo

Was getting a SQL error on BOT spawn.  Fixed typo.

* fix for crash

* Fixed crash when inviting player, more refactoring

* AI_Process Refactoring work

* More Refactoring/fixes for follow

* Finish Refactoring AI_Process

* cleanup

* cleanup

* cleanup

* cleanup

* fix melee attack loop

* fix for leashowner.

* fix for leashowner.

* Bots persist in raid after client death/LD/Camp

* Fix Bot Groups when zoning after death.

* Fix Bots in group following after client death

* remove unnecessary query

* Allow Raid members to invite Bots if owner is in raid. cleanup

* optimization of raid verification

* remove this

* Code Cleanup

* formatting

* formatting

* formatting

* fix for macro

* add return for TryClassAttacks

* fix query

* fix for crash

* restrict camping/spawn in combat.

* Fix other crash issue.

* update learnmembers to use Strings::To, cleanup magic numbers

* fix for merge.

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
2023-03-17 11:19:59 -04:00
Alex King e778041198 [Cleanup] Remove ownHiddenTrigger from trap.cpp and trap.h (#3092)
# Notes
- This is unsued.
2023-03-17 08:37:36 -04:00
Alex King 97e50ced93 [Cleanup] Delete deprecated/perlxs folder (#3110)
# Notes
- This entire folder is unused.
2023-03-17 06:23:30 -04:00
Alex King 4491bb9a70 [Cleanup] Remove is_authenticatd, LSShutDownUpdate(), and SetInstanceID() from zoneserver.h (#3109)
# Notes
- These are unsued.
2023-03-17 06:23:19 -04:00
Alex King 04fba27467 [Cleanup] Remove StoreCharacter() from worlddb.h (#3108)
# Notes
- This is unused.
2023-03-17 06:23:10 -04:00
Alex King fa47dd7f93 [Cleanup] Remove DisableStats(), EnableStats(), DisableLoginserver(), and EnableLoginserver() from world_config.h (#3107)
# Notes
- These are unused.
2023-03-17 06:23:01 -04:00
Alex King b3fb5f00ab [Cleanup] Remove MakeGuildMembers() from wguild_mgr.h (#3106)
# Notes
- This is unused.
2023-03-17 06:22:51 -04:00
Alex King e17fad9ae0 [Cleanup] Cleanup unused methods and variables in world/main.cpp and world/main.h (#3105)
# Notes
- These are unused.
2023-03-17 06:22:41 -04:00
Alex King bbdaacd3b0 [Cleanup] Remove AllConnected(), CanUpdate(), and SendInfo() from login_server_list.cpp and login_server_list.h (#3104)
# Notes
- These are unused.
2023-03-17 06:22:34 -04:00
Alex King 61bd485449 [Cleanup] Remove unused methods in eql_config.cpp, eql_config.h, launcher_list.cpp, and launcher_list.h (#3103)
# Notes
- These are unused.
2023-03-17 06:22:01 -04:00
Alex King 4b405fe9fe [Cleanup] Remove authenticated from launcher_link.cpp and launcher_link.h (#3101)
# Notes
- This is unused.
2023-03-17 06:21:51 -04:00
Alex King d5aaf7cee5 [Cleanup] Remove CountZones() from launcher_link.h (#3100)
# Notes
- This is unused.
2023-03-17 06:21:41 -04:00
Alex King 12e9e0f71d [Cleanup] Delete world/console.old.cpp (#3099)
# Notes
- This is unused.
2023-03-17 06:21:23 -04:00
Alex King 0a64e26672 [Cleanup] Remove FindCLEByLSID(), GetCLE(), GetCLEIPCount(), and RemoveCLEByLSID() from clientlist.h (#3098)
# Notes
- These are unused.
2023-03-17 06:21:14 -04:00
Alex King 11fc5a9e93 [Cleanup] Remove SendGuildPacket() from clientlist.cpp, clientlist.h, and wguild_mgr.cpp (#3097)
# Notes
- This is unused.
2023-03-17 06:21:00 -04:00
Alex King 7bbcdfb479 [Cleanup] Remove FindByName(charname) from clientlist.h (#3096)
# Notes
- This is unused.
2023-03-17 06:20:46 -04:00
Alex King 3a530eb43b [Cleanup] Remove CheckAuth(), SetOnline(), and pMD5Pass from cliententry.h (#3095)
# Notes
- These are unused.
2023-03-17 06:20:36 -04:00
Alex King 48a60114b7 [Cleanup] Remove CommandRequirement() from zonedb.h (#3094)
# Notes
- This is unused.
2023-03-17 06:20:25 -04:00
Alex King 06f1f36c95 [Cleanup] Utilize GetScheduler() in zone/worldserver.cpp (#3093)
# Notes
- This was unused.
2023-03-17 06:20:13 -04:00
Alex King ccd9bd7d4c [Cleanup] Utilize SetHiddenTrigger in trap.cpp (#3091)
# Notes
- This was unused.
2023-03-17 06:17:53 -04:00
Alex King fea6cbf633 [Cleanup] Remove RemoveSpawnGroup() from spawngroup.h (#3090)
# Notes
- This is unused.
2023-03-17 06:17:44 -04:00
Alex King 460739d35c [Cleanup] Delete queues.h (#3089)
# Notes
- This is unsued.
2023-03-17 06:17:32 -04:00
Alex King 11e1edc99f [Cleanup] Remove IsOrigin(glm::vec2) from position.h (#3088)
# Notes
- This is unused.
2023-03-17 06:17:20 -04:00
Alex King 7374660045 [Cleanup] Remove last_insert_id from petitions.h (#3087)
# Notes
- This is unused.
2023-03-17 06:17:10 -04:00
Alex King 9e8d365ca7 [Cleanup] Remove SetSentTime2 in petitions.h (#3086)
# Notes
- This is unused.
2023-03-17 06:17:00 -04:00
Alex King 14d69a0a14 [Cleanup] Remove perlparser.h (#3085)
# Notes
- This is unused.
2023-03-17 06:16:51 -04:00
Alex King fe063637e9 [Cleanup] Remove GetTransformation() and GetInvertedTransformation() from oriented_bounding_box.h (#3084)
# Notes
- These are unused.
2023-03-17 06:16:40 -04:00
Alex King 232b1028d7 [Cleanup] Remove m_inuse, m_z, and m_heading from object.h (#3083)
# Notes
- These are unsued.
2023-03-16 21:47:27 -04:00
Alex King 3624307385 [Cleanup] Remove SetDBID() from object.h (#3082)
# Notes
- This is unused.
2023-03-16 21:36:03 -04:00
Alex King c0055cf357 [Cleanup] Remove npc_ai.cpp/npc_ai.cpp (#3081)
# Notes
- These files were unused.
2023-03-16 21:17:23 -04:00
Alex King f9c1683d36 [Cleanup] Remove GetAILevel() from npc.h (#3080)
# Notes
- This is unused.
2023-03-16 21:06:24 -04:00
Alex King 64df993c10 [Cleanup] Remove FlushLootStats() from npc.h (#3079)
# Notes
- This is unused.
2023-03-16 21:06:10 -04:00
Alex King 890ef696fe [Cleanup] Remove GetDestination() from doors.h (#3078)
# Notes
- This is unused.
2023-03-16 20:47:40 -04:00
Alex King 3f1848b01a [Cleanup] Remove can_corpse_be_rezzed from corpse.h (#3077)
# Notes
- This is unused.
2023-03-16 20:47:25 -04:00
Alex King f7c4f1ff75 [Cleanup] Remove _baseBotStance from bot.h (#3076)
# Notes
- This is unused.
2023-03-16 20:25:45 -04:00
Alex King dcb127f4b6 [Cleanup] Remove _botRole from bot.h (#3075)
# Notes
- This is unused.
2023-03-16 20:25:35 -04:00
Alex King 669b068978 [Cleanup] Remove _previousTarget from bot.h (#3074)
# Notes
- This is unused.
2023-03-16 20:25:25 -04:00
Alex King db2aeca38f [Cleanup] remove _botOrderAttack from bot.h (#3073)
# Notes
- This is unused.
2023-03-16 20:25:16 -04:00
Alex King 1b3ca95f8c [Cleanup] Remove firstlogin and realfirstlogin from world/client.h (#3072)
# Notes
- These are unused.
2023-03-16 20:25:03 -04:00
Alex King c05baac551 [Cleanup] Remove CLIENT_TIMEOUT from world/client.h and zone/client.h (#3071)
# Notes
- This is unused.
2023-03-16 20:24:53 -04:00
Alex King 939fc79d19 [Cleanup] Remove IsAffectedByBuff() (#3068)
# Notes
- This is unused.
2023-03-16 20:24:44 -04:00
Alex King a0e6fce057 [Cleanup] Remove fixedZ from mob.h (#3065)
# Notes
- This is unused.
2023-03-16 20:24:35 -04:00
Alex King 452389b7a5 [Cleanup] Remove class EQStream from client.h (#3070)
# Notes
- This is unused.
2023-03-16 20:24:08 -04:00
Alex King dd184fa8b6 [Cleanup] Remove inWater from mob.h (#3069)
# Notes
- This is unused.
2023-03-16 20:23:56 -04:00
Alex King 4a3e6b5edc [Cleanup] Remove current_buff_count (#3067)
# Notes
- This was unused.
2023-03-16 20:23:41 -04:00
Alex King 7961d7afa8 [Cleanup] Utilize GetPlayerState() in mob methods (#3066)
# Notes
- This method was unused, make use of it.
2023-03-16 20:23:34 -04:00
Alex King cc6bcf3295 [Cleanup] Remove casting_spell_type from mob.h (#3064)
# Notes
- This is unused.
2023-03-16 20:23:21 -04:00
Alex King b73c2016cf [Cleanup] Remove last_max_hp from mob.h (#3063)
# Notes
- This is unused.
2023-03-16 20:23:11 -04:00
Alex King db7e8241ac [Cleanup] Remove DoBuffWearOffEffect() from mob.h (#3062)
# Notes
- This is unused.
2023-03-16 20:12:01 -04:00
Paul Coene b7747b07db [Illusions] Fix bug where spells like Ignite Bones left NPC size incorrect. (#3061) 2023-03-16 18:59:09 -04:00
Alex King 02ada0e496 [Quest API] Add SendIllusion overloads/parameters to Perl/Lua (#3059)
* [Quest API] Add SendIllusion methods to Perl.

# Perl
- Add `$mob->SendIllusion(race, gender, texture, helmtexture, face, hairstyle, haircolor, beard, beardcolor, drakkin_heritage, drakkin_tattoo, drakkin_details, size, target)`.
- Add `$mob->SendIllusionPacket(illusion_table_ref)`.

* Change defaults.

* Remove debug message

* Cleanup.

* Cleanup

* Update perl_mob.cpp
2023-03-15 20:37:37 -04:00
Alex King 7c819539c8 [Quest API] Add Spell GetActX methods to Perl/Lua (#3056)
# Perl
- Add `$mob->GetActDoTDamage(spell_id, value, target)`.
- Add `$mob->GetActDoTDamage(spell_id, value, target, from_buff_tic)`.
- Add `$mob->GetActReflectedSpellDamage(spell_id, value, effectiveness)`.
- Add `$mob->GetActSpellDamage(spell_id, value, target)`.
- Add `$mob->GetActSpellHealing(spell_id, value, target)`.
- Add `$mob->GetActSpellHealing(spell_id, value, target, from_buff_tic)`.

# Lua
- Add `mob:GetActDoTDamage(spell_id, value, target)`.
- Add `mob:GetActDoTDamage(spell_id, value, target, from_buff_tic)`.
- Add `mob:GetActReflectedSpellDamage(spell_id, value, effectiveness)`.
- Add `mob:GetActSpellCasttime(spell_id, cast_time)`.
- Add `mob:GetActSpellCost(spell_id, cost)`.
- Add `mob:GetActSpellDamage(spell_id, value)`.
- Add `mob:GetActSpellDamage(spell_id, value, target)`.
- Add `mob:GetActSpellDuration(spell_id, duration)`.
- Add `mob:GetActSpellHealing(spell_id, value)`.
- Add `mob:GetActSpellHealing(spell_id, value, target)`.
- Add `mob:GetActSpellHealing(spell_id, value, target, from_buff_tic)`.
- Add `mob:GetActSpellRange(spell_id, range)`.

 # Notes
- Allows operators to get various spell related values.
2023-03-12 15:36:43 -04:00
Alex King e670c89163 [Cleanup] Remove unused lua_hate_entry.cpp (#3057)
# Notes
- This is unused and causes duplication of these methods in Spire Quest API Explorer.
2023-03-12 15:36:20 -04:00
Aeadoin 9ecdf057db [Feature] Add Heroic Strikethrough & HP Regen Per Second to GM Entity Info (#3055)
* [Feature] Add Heroic Strikethrough to GM Entity Info

* [Feature] Add Heroic Strikethrough to GM Entity Info

* typo
2023-03-11 20:46:31 -05:00
Aeadoin b6448c840f [Bug Fix] Fix Raid Invites causing client desync issues (#3053) 2023-03-11 11:42:52 -05:00
Aeadoin 0ba90df1f1 [Bug Fix] Fix issue with overflow on min/max hit dmg in npc scaling calculations (#3052)
* [Cleanup] Cleanup npc.cpp and npc scaling

* fix issue with min/max damage overflows

* formatting
2023-03-10 09:36:59 -05:00
Alex King 12dcbd0871 [Bug Fix] Fix Heal Scale and Spell Scale in NPC Scaling (#3051)
# Notes
- These had typos and didn't work.
2023-03-09 22:32:47 -05:00
Aeadoin b0be4ca8bd [Feature] Add Avoidance and HP Regen Per Second too NPC Scaling. (#3050) 2023-03-09 11:07:03 -05:00
nytmyr 412eb5deaa [Bots] Prevent interrupt spam when OOM (#3011)
Notes:

Bots currently do not do a mana check until the spell cast has already been started which results in an interrupt immediately after. If it is the last spell for a bot to cast, it tends to result in interrupt spam until the bot has enough mana. This will block the interrupt spam if the spell is invalid.
2023-03-07 18:17:09 -05:00
Alex King f030461bc7 [Feature] Add Heroic Strikethrough to NPC Scaling (#3028)
* [Feature] Add Heroic Strikethrough to NPC Scaling

# Notes
- Adds Heroic Strikethrough support to NPC scaling.
- Cleans up `std::stoul` to use `Strings::ToUnsignedInt` since recent changes.
- Sets default values to sane values and removes support for `NULL` values.

* Update 2023_03_04_npc_scale_global_base_heroic_strikethrough.sql
2023-03-05 22:36:53 -05:00
Alex King 8f5e7978ab [Commands] Remove #equipitem Command (#3040)
* [Commands] Remove #equipitem Command

# Notes
- This command causes issues with cursor and inventory slot desynchronizations and seems to largely be unused/unnecessary.

* Remove from command files.
2023-03-05 22:36:04 -05:00
Alex King 2e55da2b2d [Fix] Checkmarks and X characters in popup messages (#3041)
# Notes
- Due to changing the popups to use strings, these show as squares, instead of the proper character.
2023-03-05 22:35:52 -05:00
Alex King 16a8f88ae5 [Commands] Cleanup #haste Command (#3042)
* [Commands] Cleanup #haste Command

# Notes
- Cleanup messages and logic.
- No longer requires you to re-equip your weapon for the haste to take effect.
- Can now use on targeted client if you have `#gm on` enabled.

* Update haste.cpp
2023-03-05 22:35:42 -05:00
Alex King 22d7ef6763 [Commands] Cleanup #hideme Command (#3043)
# Notes
- Cleanup messages and logic.
2023-03-05 22:35:30 -05:00
Alex King 457e800c73 [Commands] Cleanup #interrupt Command (#3044)
* [Commands] Cleanup #interrupt Command

# Notes
- Cleanup messages and logic.

* Update command.cpp
2023-03-05 22:35:23 -05:00
Alex King 8393e50aa8 [Commands] Cleanup #level Command (#3045)
# Notes
- Cleanup messages and logic.
- Defaults target to GM so that you don't have to target yourself to use the command.
2023-03-05 22:34:33 -05:00
Alex King b6497cdd6a [Commands] Cleanup #resetaa and #resetaa_timer (#3047)
# Notes
- Cleanup messages and logic.
2023-03-05 22:34:21 -05:00
Alex King 218ef80f96 [Commands] Cleanup #picklock Command (#3046)
* [Commands] Cleanup #picklock Command

# Notes
- Cleanup messages and logic.

* Update picklock.cpp
2023-03-05 22:34:05 -05:00
Alex King a90d41480a [Commands] Cleanup #wc Command (#3049)
# Notes
- Cleanup messages and logic.
2023-03-05 22:18:35 -05:00
Alex King 67df6f62b7 [Cleanup] Remove unused ^evacuate and ^succor subcommands from bot_command.h (#3039)
# Notes
- These are unused.
2023-03-05 12:19:58 -05:00
Alex King 4572dbc426 [Cleanup] Remove unused BotAA struct in bot_structs.h (#3038)
# Notes
- This is unused.
2023-03-05 12:19:52 -05:00
Alex King e8cc160572 [Cleanup] Remove unused bot structs in bot_structs.h (#3037)
# Notes
- These are unused.
2023-03-05 12:19:42 -05:00
Alex King 8c9adca852 [Cleanup] Utilize SetFilter in client.cpp (#3036)
# Notes
- This function was unused, make use of it.
2023-03-05 12:19:22 -05:00
Alex King b53310e23b [Cleanup] Remove unused AbilityTimer variable in client.h (#3035)
# Notes
- This is unused.
2023-03-05 12:19:16 -05:00
Alex King 14f01dc2d7 [Cleanup] Remove unused client queued work variable in client.cpp/client.h (#3034)
# Notes
- This is unused.
2023-03-05 12:19:09 -05:00
Alex King a4d6509e6d [Cleanup] Remove unused player update variables in client.cpp/client.h (#3033)
# Notes
- These are unused.
2023-03-05 12:18:56 -05:00
Alex King fc835bfb0e [Cleanup] Remove unused HandleUpdateTasksOnKill in client.h (#3032)
# Notes
- This is unused.
2023-03-05 12:18:51 -05:00
Alex King 9ec4e5ade0 [Cleanup] Remove unused command variables in client.cpp (#3031)
# Notes
- These are unused.
2023-03-05 12:18:36 -05:00
Alex King 6b65e93a06 [Cleanup] Remove unused SaveBackup in client.h (#3030)
# Notes
- This is unused and does nothing in both Perl and Lua.
2023-03-05 12:18:26 -05:00
Chris Miles a0a28fef04 [Strings] Add exception handling to converters themselves (#3029) 2023-03-04 19:39:55 -06:00
Trent 034feb4ff4 [Bots] Place BOT_COMMAND_CHAR inside messages (#3027)
* Fix bot depart list

* Update bot_command.cpp

* Update bot_command.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-03-04 20:02:04 -05:00
nytmyr 65c14b160e [Rules] Add ResurrectionEffectsBlock (#2990)
* [Rules] Add ResurrectionEffectsBlock

Notes:

This adds the rule Spells:ResurrectionEffectsBlock that will prevent anything from overwrites Resurrection Sickness Effects. Currently they are able to be overwritten by certain spells.

Default state: Disabled/False.

* Update ruletypes.h

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2023-03-04 17:24:29 -06:00
Alex King c21d47f450 [Scaling] Add support for pipe-separated zone IDs and versions (#3015)
* [Scaling] Add support for pipe-separated zone IDs and versions

# Notes
- Allows `|` separated zone IDs and instance versions within the scaling data.
- Loads scaling data on zone bootup as well, without needing to repop for it to initialize.

* Cleanup
2023-03-04 17:24:16 -06:00
Aeadoin 83ea9816b8 [Rules] Add Multiplier for Heroic Stats. (#3014)
* initial work

* [Rules] Add Multiplier for Heroic Stats.

* Add bots

* update SendStatsWindow

* fix SendStatsWindow
2023-03-04 17:09:44 -06:00
Chris Miles e3f9b396ab [Console] Add IS_TTY to force terminal coloring output (#3021) 2023-03-04 17:01:39 -06:00
Alex King 2a6cf8c8e7 [Strings] Add more number formatters (#2873)
* [Strings] Add more number formatters

# Notes
- Adds `Strings::ToUnsignedInt` for `uint32` support.
- Adds `Strings::ToBigInt` for `int64` support.
- Adds `Strings::ToUnsignedBigInt` for `uint64` support.
- Adds `Strings::ToFloat` for `float` support.
- Replaces all `std::stoi` references with `Strings::ToInt`.
- Replaces all `atoi` references with `Strings::ToInt`.
- Replaces all `std::stoul` references with `Strings::ToUnsignedInt`.
- Replaces all `atoul` references with `Strings::ToUnsignedInt`.
- Replaces all `std::stoll` references with `Strings::ToBigInt`.
- Replaces all `atoll` references with `Strings::ToBigInt`.
- Replaces all `std::stoull` references with `Strings::ToUnsignedBigInt`.
- Replaces all `atoull` references with `Strings::ToUnsignedBigInt`.
- Replaces all `std::stof` references with `Strings::ToFloat`.

* [Strings] Add more number formatters

- Adds `Strings::ToUnsignedInt` for `uint32` support.
- Adds `Strings::ToBigInt` for `int64` support.
- Adds `Strings::ToUnsignedBigInt` for `uint64` support.
- Adds `Strings::ToFloat` for `float` support.
- Replaces all `std::stoi` references with `Strings::ToInt`.
- Replaces all `atoi` references with `Strings::ToInt`.
- Replaces all `std::stoul` references with `Strings::ToUnsignedInt`.
- Replaces all `atoul` references with `Strings::ToUnsignedInt`.
- Replaces all `std::stoll` references with `Strings::ToBigInt`.
- Replaces all `atoll` references with `Strings::ToBigInt`.
- Replaces all `std::stoull` references with `Strings::ToUnsignedBigInt`.
- Replaces all `atoull` references with `Strings::ToUnsignedBigInt`.
- Replaces all `std::stof` references with `Strings::ToFloat`.

* Rebase cleanup

* Changes/benchmarks/tests

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-03-04 17:01:19 -06:00
cybernine186 be567af70d [Bug Fix] Cursor Coin Upon Death (#3020)
* Update corpse.cpp

* Add rule toggle.

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-03-04 17:45:42 -05:00
Alex King 6494fbf916 [Bug Fix] Fix Discovered Items with Alternate Currency and LDoN Adventure Merchants (#3026)
* [Bug Fix] Fix Discovered Items with Alternate Currency Merchants

# Notes
- Before now, alternate currency merchants did not trigger item discovery.

* Update client_packet.cpp
2023-03-04 13:09:27 -05:00
catapultam-habeo 2cc61ef8c1 [Bug Fix] Ensure synchronization of pet taunt state with UI (#3025)
* fix to desync between pet taunt state and button

* Update npc.h

* Update npc.cpp

* Update npc.h

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-03-04 11:40:29 -05:00
dependabot[bot] 5d7a7bb4b2 Bump golang.org/x/crypto in /utils/scripts/build/should-release (#3024)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.0.0-20210817164053-32db794688a5 to 0.1.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/commits/v0.1.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-03 17:37:58 -06:00
dependabot[bot] 00f82f43a6 Bump golang.org/x/net in /utils/scripts/build/should-release (#3023)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20210226172049-e18ecbb05110 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/commits/v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-03 17:23:13 -06:00
Chris Miles d3ca636a70 [Release] 22.4.5 (#3022) 2023-03-03 17:09:39 -06:00
Vayle 01855d40df [Bug Fix] Fix log messages when players join channel (#2992)
* Fix log message when players join channels

* Formatting

* More formatting

* Update CurrentPlayerChannels to use vector of channel names

* Put log statement back in place

* Remove channel limit in db query

* Formatting tweak
2023-03-03 11:54:56 -06:00
Paul Coene 748602b04e [Bug Fix] Fix an issue where EVENT_TIMER timers would not be cleaned up after zone (#3018)
* [Bug Fix] Dangling client timers fixed.

* Remove all timers from mob in destructor instead of in QuestMgr::Process
2023-03-03 11:54:14 -06:00
Alex King a97a9a0d1c [Bug Fix] Fix npcfeature and playerfeature (#3017) 2023-03-01 20:42:37 -05:00
Aeadoin a78c754c0e [Cleanup] Remove unused iterator from LoadCharacterDisciplines (#3012) 2023-03-01 20:35:28 -05:00
Alex King ef214f91e9 [Bug Fix] Fix DoAnim quest method default speed (#3016)
# Notes
- Sets default speed to `0` which makes the animations run at normal speed instead of `1` that makes them run is slow motion.
2023-03-01 17:47:27 -05:00
Aeadoin 04a74df0b2 [Bots] Add additional Heroic Sta/Wis/Int bonuses for Bots. (#3013) 2023-03-01 10:58:04 -05:00
Chris Miles c15bfe12eb [Fix] Fix issue where quest saylink responses would occur before the NPC's response (#3010)
* [Fix] Fix issue where quest saylink responses would occur before the NPC's response

* Update client_packet.cpp

* Revert "[Fix] Fix issue where quest saylink responses would occur before the NPC's response"

This reverts commit a09e1bbbe9.
2023-02-28 21:27:05 -05:00
Alex King 5702f7bcd1 [Quest API] Add IsFindable() and IsTrackable() to Perl/Lua (#2996)
# Perl
- Add `$mob->IsFindable()`.
- Add `$mob->IsTrackable()`.

# Lua
- Add `mob:IsFindable()`.
- Add `mob:IsTrackable()`.

# Notes
- Allows operators to see if a mob is findable or trackable.
2023-02-28 21:26:11 -05:00
Alex King 9a5bf53e11 [Quest API] Add IsUnderwaterOnly() to Perl/Lua (#2995)
# Perl
- Add `$npc->IsUnderwaterOnly()`.

# Lua
- Add `npc:IsUnderwaterOnly()`.

# Notes
- Allows operators to chec k if an NPC is underwater only.
2023-02-28 21:13:43 -05:00
Alex King 69c6a7b89a [Quest API] Add IsBerserk() to Perl/Lua (#2997)
* [Quest API] Add IsBerserk() to Perl/Lua

# Perl
- Add `$client->IsBerserk()`.

# Lua
- Add `client:IsBerserk()`.
- Remove `mob:IsBerserk()` to move to client.

# Notes
- Allows operators to check if a client is berserk.

* Move to Mob.

* Update lua_client.cpp
2023-02-28 20:31:20 -05:00
Aeadoin 2f0dbc5d15 [Bug Fix] Fix for Discipline Loading from Database causing issues with slot_ids (#3008)
* [Bug Fix] Fix for Discipline Loading from Database causing issues with slot_ids

* cleanup per comments
2023-02-28 16:55:22 -05:00
Aeadoin 93c79817cd [Crash] Fix crash in CheckTradeskillLoreConflict (#3009) 2023-02-27 19:24:05 -06:00
Aeadoin 3296287d70 [Bug Fix] Fix for Lore Components where component is returned. (#3005)
* [Bug Fix] Fix for Lore Components where component is returned.

* Refactor, and take into account loregroups above 0 properly

* Update tradeskills.cpp

* formatting for suggestions.

* commenting, update formatting.

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-02-27 12:36:35 -06:00
Alex King 774a7fa779 [Cleanup] Delete unused zone/skills.h (#3007)
# Notes
- This is unused.
2023-02-26 21:35:49 -05:00
Alex King 1ff4541a9f [Cleanup] Remove NumberOfAvailableTitles() from titles.h (#3006)
# Notes
- This is unused.
2023-02-26 21:35:43 -05:00
Alex King 3448758c03 [Quest API] Add HasSpecialAbilities() to Perl/Lua (#2994)
* [Quest API] Add HasSpecialAbilities() to Perl/Lua

# Perl
- Add `$mob->HasSpecialAbilities()`.

# Lua
- Add `mob:HasSpecialAbilities()`

# Notes
- Allows operators to check if a mob has special abilities

* Move to NPC.

* Update lua_mob.cpp
2023-02-26 21:35:10 -05:00
Alex King ff4ccfa98f [Quest API] Add GetDefaultRaceSize() to Perl/Lua (#2993)
# Perl
- Add `$mob->GetDefaultRaceSize()`.

# Lua
- Add `mob:GetDefaultRaceSize()`.

# Notes
- Allows operators to get the default race size of a race if they want to use it in a script.
2023-02-26 21:35:03 -05:00
Aeadoin d2c3c14ae0 [Bots] Cleanup AI_IdleCastCheck Logic (#3004)
* [Bots] Cleanup AI_IdleCastCheck Logic

* cleanup logic
2023-02-25 20:16:09 -05:00
Alex King a470931fdd [Cleanup] Remove class EGNode from mob.h (#3003)
# Notes
- This is unused.
2023-02-25 20:10:23 -05:00
Alex King 078db3460d [Cleanup] Remove ReturnItemPacket from client.h/inventory.cpp (#3002)
# Notes
- This is unused.
2023-02-25 20:10:08 -05:00
Alex King 0980a780d0 [Cleanup] Remove GetDamageMultiplier() from client.h (#3001)
# Notes
- This is unused.
2023-02-25 19:50:42 -05:00
Alex King 7f01bb509c [Cleanup] Remove DumpPacketProfile() from client.h (#3000)
# Notes
- This is unused.
2023-02-25 19:38:09 -05:00
Alex King 4bb189cbf4 [Cleanup] Remove GetCombinedAC_TEST() from client.h (#2999)
# Notes
- This is unused.
2023-02-25 19:38:03 -05:00
Alex King b03e8ff0fb [Cleanup] Remove unused ClientFactory in client.h (#2998)
# Notes
- This is unused.
2023-02-25 19:37:57 -05:00
Aeadoin 6179b7481e [Bug Fix] Account for bad data in Tradeskill Recipe Entries (#2991) 2023-02-25 10:52:17 -06:00
Chris Miles 5f68e4a41a [Release] 24.4.4 (#2989) 2023-02-24 20:51:45 -06:00
Chris Miles e103422ca5 [Pathing] More z-clip improvements, Wurm and Spectral Iksar race adjustments (#2988) 2023-02-24 20:27:28 -06:00
Akkadius 0cbfad975d [Hotfix] Adjust database manifest to include .sql extension 2023-02-24 20:20:21 -06:00
Alex King 2a20c69c69 [Scaling] Add support for zone ID and instance version to NPC Scaling (#2968)
* [Scaling] Add support for zone ID and instance version to NPC Scaling

# Notes
- Adds `zone_id` and `instance_version` to `npc_scale_global_base` table to allow for zone and version-specific scaling.
- Defaults back to `zone_id` of `0` and `instance_version` of `0` for global scaling.
- Scaling load precedence is as follows:
- `zone_id` of current zone and `instance_version` of current instance
- `zone_id` of current zone and `instance_version` of `0`
- `zone_id` of `0` and `instance_version` of `0`

* Remove debug comment.

* Use zone not NPC.

* SQL
2023-02-24 20:17:07 -06:00
Alex de2dfc1a7e [Bug Fix] Fix for undefined MySQL library behavior. (#2834)
* MYSQL objects cannot be copied in a well defined way, this removes the copy and replaces it with another connection

* Change to share underlying pointers.

* Push up mutex changes

* Post rebase

* Formatting

---------

Co-authored-by: KimLS <KimLS@peqtgc.com>
Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-24 20:14:55 -06:00
Chris Miles bad631df59 [Player Events] Add QS processing, mutex tweaks (#2984)
* [Player Events] Add QS processing, mutex tweaks

* Update ucs.cpp

* Move the size process check out of the server to server networking thread
2023-02-24 18:01:59 -06:00
Chris Miles e8f1aa253a [Pathing] Smoother pathing z-correction (#2982) 2023-02-24 14:07:44 -06:00
Chris Miles 889e57a5af [Pathing] Improve roambox logic (#2983)
* [Pathing] Improve roambox logic

* Cleanup roambox logic
2023-02-24 14:07:34 -06:00
Aeadoin 5cfdeb928e [Bug Fix] Fix Beneficial Target of Target procs (#2987) 2023-02-24 13:23:29 -06:00
Chris Miles 7519b0225e [Doors] Fix doors triggering invalid zone fetches of dest_zone of "none" (#2985)
* [Doors] Fix doors triggering invalid zone fetches of dest_zone of "none"

* Update doors.cpp

* Tweaks

* PR comments
2023-02-24 13:22:56 -06:00
Chris Miles 04fdc54522 [Quest API] Fix EVENT_TIMER crash when entity is no longer available (#2986)
* [Quest API] Fix EVENT_TIMER crash when entity is no longer available

* Update questmgr.cpp
2023-02-24 13:22:47 -06:00
Aeadoin f39155952f [Tradeskills] Fix for Lore Conflict (#2977)
* [Tradeskills] Fix for Lore Conflict

* Cleanup

* formatting

* it's beautiful

* container fix
2023-02-24 14:14:36 -05:00
Aeadoin 5acc181d64 [Bots] Cleanup BotDatabase::LoadBuffs (#2981)
* [Bots] Cleanup BotDatabae::LoadBuffs

* cleanup formatting/syntax
2023-02-24 12:58:54 -05:00
nytmyr 2ae0b7dd3e [Bug Fix] Correct Mend reuse time and add reduction support. (#2972)
Notes:

Previously, the server-side reuse of Mend was set to 290 seconds rather than 360 seconds (6 minutes).

Mend was not accepting reduction timers from potential items, buffs or AAs (Hastened Mend).

Mend was outputting duplicate success messages on critical mends, it will now only output a regular Mend message upon success (You mend your wounds and heal some damage) or the critical message upon critical success (You magically mend your wounds and heal considerable damage), not both.

Co-authored-by: toxin06 <53322305+toxin06@users.noreply.github.com>
2023-02-23 02:39:45 -06:00
Alex King b0d4f095ef [Commands] Cleanup #peekinv Command (#2969)
* [Commands] Cleanup #peekinv Command

# Notes
- Cleanup messages and logic.

* Update peekinv.cpp
2023-02-23 02:38:37 -06:00
Aeadoin 7c7a88650b [Bots] Verify Bots Group Integrity on join (#2980) 2023-02-23 02:36:43 -06:00
Aeadoin afaa8f4100 [Bots] Add Caster Range Command, and IsValidSpellRange Checks (#2942)
* [Bots] Add Caster Range Command, and IsValidSpellRange Checks

* remove/add exceptions where makes sense like buffs

* fixes

* fixes
2023-02-23 02:36:17 -06:00
Alex King 0d72295cc9 [Quest API] Add IsAutoAttackEnabled() to Perl/Lua (#2979)
# Perl
- Add `$client->IsAutoAttackEnabled()`.

# Lua
- Add `client:IsAutoAttackEnabled()`.

# Notes
- Allows operators to check if a client has auto attack enabled.
2023-02-23 02:31:35 -06:00
Alex King 9d4f231619 [Quest API] Add IsAutoFireEnabled() to Perl/Lua (#2978)
# Perl
- Add `$client->IsAutoFireEnabled()`.

# Lua
- Add `client:IsAutoFireEnabled()`.

# Notes
- Allows operators to check if a client has auto fire enabled.
2023-02-22 23:30:04 -05:00
Chris Miles fcb0a47280 [Release] 22.4.3 (#2976) 2023-02-21 10:42:43 -06:00
Chris Miles 1e50f19f7e [Pathing] Improvements to z-clipping, z-recovery and z-calculations (#2975)
* zclip adjustments

* Remove debug
2023-02-21 10:24:25 -06:00
Chris Miles 33bb5aa8e5 [Database] Address deadlock in player events (#2974)
* DB mutex testing

* Mutex tweaks, native string escaping
2023-02-20 22:32:29 -06:00
Aeadoin 6a668f8aa5 [Crash] Fix crash with EVENT_UNEQUIP_ITEM_BOT (#2973) 2023-02-20 17:31:15 -05:00
Alex King df499b22ab [Bug Fix] Fix MIR LDoN Theme Items on LDoN Merchants (#2971)
# Notes
- These items weren't showing as MIR due to this condition being typo'd in https://github.com/EQEmu/Server/pull/1611/files.
2023-02-19 21:51:37 -05:00
Alex King 7bc00cb466 [Bug Fix] Fix OOCMute not functioning (#2970)
# Notes
- #oocmute was not functioning as the packet wasn't being handled by the server.
2023-02-19 20:39:24 -05:00
Paul Coene 51f6108aab [Pets] Client Pet summoned by NPC should not change guard location. (#2967)
* [Pets] Client Pet summoned by NPC should not change guard location.

* Update mob.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-02-19 16:56:34 -05:00
Aeadoin c13f9f80d9 [Bots] Change HasBotItem(item_id) to return slot_id instead of bool. (#2966) 2023-02-19 16:13:28 -05:00
JJ 443abf9199 [SQL] Add date to optional Drakkin Guktan Faction Update (#2965) 2023-02-19 16:11:07 -05:00
Alex King 1556e05b2f [Quest API] Add client->SignalClient() overload to Perl (#2963)
# Notes
- Fixes an issue with Guild Lobby quests not properly using `client` as first parameter in `mob->SignalClient(client, signal_id)` method.
2023-02-19 15:20:28 -05:00
Alex King 1d645aa5f6 [Quest API] Fix Perl SetSimpleRoamBox Overloads (#2961)
# Notes
- These overloads were non-functional as they didn't have a method to actually fall back to.
2023-02-19 11:17:35 -05:00
Chris Miles 9f42da5bad [Crash] Fix world crash in player event processing (#2960)
* [Crash] Fix world crash in player event processing

* Add rule BatchPlayerEventProcessChunkSize
2023-02-18 16:06:16 -06:00
Aeadoin 4a8222f243 [Bots] Fix output of ^spells while ^Enforcespellsettings is enabled (#2959) 2023-02-18 16:06:06 -06:00
Chris Miles db4c515853 [Player Events] Create new event ITEM_CREATION (#2944) 2023-02-18 16:05:23 -06:00
Chris Miles 462656a201 [Reload API] Add world handlers for certain opcodes (#2958) 2023-02-18 15:58:29 -06:00
Aeadoin ddd98be383 [Bot] Change SaveTimers to Replace instead of Insert. (#2951)
* [Bot] Change SaveTimers to Replace instead of Insert.

* [Bot] Change SaveTimers to Replace instead of Insert.

* fix formatting
2023-02-18 16:13:36 -05:00
Chris Miles 4ad3ebf36a [Release] 22.4.2 (#2957) 2023-02-18 10:18:32 -06:00
Chris Miles b5a2713a3a [Player Events] Add logging category to hold processing batch logs (#2954)
* [Player Events] Add logging category to hold processing batch logs

* Update player_event_logs.cpp
2023-02-18 05:41:14 -06:00
Chris Miles 999fe10d86 [Content] Added optional SQL 2023_02_17_fix_sseru_mischief_doors.sql to fix sseru/mischief doors (#2955) 2023-02-18 05:41:05 -06:00
Chris Miles ce1472db1e [MySQL] Add keepalives to UCS and Loginserver (#2953) 2023-02-18 05:40:51 -06:00
Chris Miles d6c6b78d8a [Logging] Remove noisy raid/group/forage errors (#2952) 2023-02-18 05:40:41 -06:00
Aeadoin ee6c9a2ad7 [Tradeskills] Fix regression caused by #2932 (#2956) 2023-02-18 05:40:15 -06:00
Chris Miles 3e4767269e [Release] 22.4.1 (#2950) 2023-02-17 14:48:46 -06:00
Aeadoin e0eb145081 [Bots] Set Taunt to enabled for SK/Paladin Bots by Default. (#2941) 2023-02-17 10:46:49 -05:00
Chris Miles a6dd65435f [DevTools] Fix NPC targetting dev tools display window (#2943) 2023-02-17 06:07:20 -06:00
Chris Miles 26dc05c0dc [Player Events] Fix issue with item instances not being validated properly before accessing causing crashes on handin (#2945) 2023-02-17 06:07:02 -06:00
Chris Miles da20a6ab67 [Player Events] Fix rare out of bound issue when loading event types (#2946) 2023-02-17 06:06:53 -06:00
Chris Miles 3949a31246 [Fix] Issue with AssignRaidToInstance that was using the groups repository instead of raid (#2947) 2023-02-17 06:06:45 -06:00
Chris Miles e898be1ce9 [Player Events] Turn off KILLED_NPC (trash) off by default (#2948) 2023-02-17 06:05:43 -06:00
Akkadius 2962575dda [Hotfix] Missing comma in schema list breaking dumps 2023-02-16 22:27:09 -06:00
Akkadius 6a6045a21c [Release] Update should-release 2023-02-16 13:23:53 -06:00
Akkadius 717fe7dc8c [Release] 22.4.0 2023-02-16 10:24:45 -06:00
Chris Miles df69d12c0c [Release] 22.4.0 (#2940)
* [Release] 22.4.0

* Update changelog notes [skip ci]
2023-02-16 10:23:01 -06:00
Aeadoin 99e49cb2ec [Tradeskills] Check if combine would result in lore conflict (#2932)
* [Tradeskills] Check if Combine would result in Lore Conflict.

* formatting

* Add Saylinks to lore message output.

* Aknowledgement packets to prevent client issues.
2023-02-15 21:03:16 -06:00
Aeadoin 5ee2856133 [Bug Fix] Replace uses of SPELL_UNKNOWN with IsValidSpell() (#2938) 2023-02-15 21:01:35 -06:00
JJ 4a64048744 [Crash] Fix crash issue with dropping items and order of operations (#2939)
Should wait to null out invalid_drop until after it is used in log message.
2023-02-15 20:55:15 -06:00
Chris Miles 2ae795fd61 [Crash] Crash fix where invalid input to #heromodel would crash zone (#2937) 2023-02-15 14:36:09 -05:00
Chris Miles 0829bc08b8 [Doors] Fix issue where NPC's wouldn't open doors because door param overflow (#2934) 2023-02-15 10:59:38 -06:00
Chris Miles 903a385229 [Hotfix] Fix crash where dropped items crash Lua logic (#2936) 2023-02-15 10:57:05 -06:00
Chris Miles fafa33e190 [Groundspawns] Fix issue where groundspawns appear floating high off the ground (#2930) 2023-02-15 10:52:03 -06:00
Chris Miles 90a01f7c53 [Quest] Fix SetSimpleRoamBox in Perl to have optional params again (#2935) 2023-02-15 10:49:33 -06:00
Alex King 19434197d4 [Bug Fix] Fix crash in EVENT_DISCOVER_ITEM (#2933)
* [Bug Fix] Fix crash in EVENT_DISCOVER_ITEM

# Notes
- `const` didn't like the `std::any_cast`, also was passing `EQ::ItemData*` instead of `EQ::ItemInstance*`.

* Update client.cpp
2023-02-15 10:49:14 -06:00
Paul Coene 18b62667f0 [Bug Fix] Self Only Spells will no longer check target level or buff restrictions (#2931)
* [Bug Fix] Self Only Spells now work again (BuffSpellRestrictions)

* Moved variables under quick checks per review
2023-02-14 19:47:32 -05:00
Akkadius 8ed7ca977f [Hotfix] Another doors fix 2023-02-14 06:28:42 -06:00
Chris Miles 665e336946 [Fix] Fix issue where Lore groundspawn pickups will desync ROF2+ (#2929)
* [Fix] Fix issue where Lore groundspawn pickups will desync ROF2+

* Update object.cpp
2023-02-14 04:36:22 -06:00
Chris Miles ccf8504dec [Hotfix] Fix EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE regression caused by #2897 (#2928)
* [Hotfix] Fix EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE regression caused by  #2897

* Update client_packet.cpp
2023-02-14 04:36:10 -06:00
Akkadius d107213fe1 [Cleanup] Doors EVENT_CLICK_DOOR syntax adjustment 2023-02-14 04:10:15 -06:00
Akkadius c115cbcd6a [Hotfix] Fix Door opening regression caused by #2880 2023-02-14 01:36:03 -06:00
Chris Miles 064ae7ba89 [Hotfix] Fix HP_EVENT regression (#2927)
* [Hotfix] Fix HP_EVENT regression

* Update mob.cpp
2023-02-13 23:28:40 -05:00
Chris Miles 02302802b8 [CI] Fix Windows stderr not bubbling properly (#2925)
* [CI] Fix Windows stderr not bubbling properly

* Update windows-build.ps1
2023-02-13 21:41:29 -06:00
Chris Miles 536e248424 [Windows] Fix MSVC compilation bug via workaround (#2926) 2023-02-13 21:21:05 -06:00
Chris Miles 5b56a23a8a [Hotfix] Fix issue with EVENT_HP firing regression from #2904 (#2924)
* [Hotfix] Fix issue with EVENT_HP firing from https://github.com/EQEmu/Server/pull/2904

* Fix

* Fix
2023-02-13 22:02:18 -05:00
Alex King 97edb09fba [Rules] Add Group/Raid Experience Rules (#2850)
# Notes
- Add `Character:EnableGroupMemberEXPModifier`, enables or disables member-based experience modifiers in groups, default `true`.
- Add `Character:EnableRaidEXPModifier`, enables or disables member-based experience modifiers in raids, default `true`.
- Add `Character:EnableRaidMemberEXPModifier`, enables or disables member-based experience modifiers in raids, default `true`.
2023-02-13 00:25:59 -06:00
Alex King 85f7b10f90 [Cleanup] Remove Unused Mod Hooks (#2856)
- Removes old `mod_` hooks that have gone unused for years in favor of Lua mods.
2023-02-13 00:24:23 -06:00
Aeadoin 0f49fbcfcd [Bots] Add Support for TryTriggerOnCastFocusEffect (#2864) 2023-02-13 00:19:50 -06:00
Vayle e57979c3a8 [Quest API] Add Additional XP Events EVENT_AA_EXP_GAIN, EVENT_EXP_GAIN (#2865)
* Add XP Events

* Tweak

* Formatting

* Additional tweak

* Adjustment

* Update export naming

* Formatting

* Indenting

* Finalizing formatting

* Indenting adjustments

* Use tab character setting

* Remove double tabs

* Update exp.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-02-13 00:19:02 -06:00
Aeadoin fc7c30977a [Bots & Mercs] Add Support for TrySympatheticProc (#2866)
* [Bots & Merrcs] Add Support for TrySympatheticProc

* [Bots & Merrcs] Add Support for TrySympatheticProc

* [Bots & Merrcs] Add Support for TrySympatheticProc

* Cleanup

* formatting

* auto
2023-02-13 00:16:18 -06:00
Aeadoin b3fd9dd88a [Crash] Fix Crash in FindType (#2867) 2023-02-13 00:15:40 -06:00
Alex King 4df9661903 [Quest API] Add EVENT_DROP_ITEM_CLIENT to Perl/Lua (#2869)
* [Quest API] Add EVENT_DROP_ITEM_CLIENT to Perl/Lua

- Add `EVENT_DROP_ITEM_CLIENT`, exports `$quantity,` $item_name`, `$item_id`, `$spell_id`, `$slot_id`, and `$item`.

- Add `event_drop_item_client`, exports `e.quantity`, `e.item_name`, `e.item_id`, `e.spell_id`, `e.slot_id`, and `e.item`.

* Update inventory.cpp

* Update inventory.cpp

* Update lua_general.cpp

* Update inventory.cpp
2023-02-13 00:15:19 -06:00
Alex King 8c363320d8 [Quest API] Export target to EVENT_TARGET_CHANGE in Perl/Lua. (#2870)
* [Quest API] Export target to EVENT_TARGET_CHANGE in Perl/Lua.

- Export `$target` to `EVENT_TARGET_CHANGE`.

- Export `e.other` to `event_target_change`.

- Allows operators to not have to grab bot, Client, or NPC's target in Perl with `GetTarget()`.
- Allows operators to not have to grab Client's target in Lua with `GetTarget()`.

* Update mob.cpp

* Update mob.cpp

* Update mob.cpp
2023-02-13 00:03:52 -06:00
Alex King d4afc78982 [Quest API] Add EVENT_DESTROY_ITEM_CLIENT to Perl/Lua. (#2871)
* [Quest API] Add EVENT_DESTROY_ITEM_CLIENT to Perl/Lua.

- Add `EVENT_DESTROY_ITEM_CLIENT`, exports `$item_id`, `$item_name`, `$quantity`, and `$item`.

- Add `event_destroy_item_client`, exports `e.item_id`, `e.item_name`, `e.quantity`, and `e.item`.

- Allows operators to use player scripts for item destroys.

* Update lua_parser_events.h

* Update inventory.cpp
2023-02-12 23:58:27 -06:00
Aeadoin 24de1d948a [Crash] Fix crash in Mob::CommonDamage when attacker was null (#2872) 2023-02-12 23:53:29 -06:00
Alex King ca0e85b4bc [Quest API] Export $item to EVENT_PLAYER_PICKUP in Perl. (#2875)
* [Quest API] Export $item to EVENT_PLAYER_PICKUP in Perl.

# Notes
- Exports `$item` to `EVENT_PLAYER_PICKUP` in Perl so that you have access to the item itself.

* Optional parsing.

* Update object.cpp

* Update object.cpp
2023-02-12 23:52:47 -06:00
Alex King 5b24d38d1e [Quest API] Export $item to Fishing and Forage Events in Perl (#2876)
* [Quest API] Export $item to Fishing and Forage Events in Perl

# Notes
- Exports `$item` to `EVENT_FISH_SUCCESS` in Perl.
- Exports `$item` to `EVENT_FORAGE_SUCCESS` in Perl.

* Add optional parsing to fish/forage events.

* Update forage.cpp

* Fix missing event param

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 23:50:21 -06:00
Alex King 4a1d026215 [Quest API] Export $spawned to EVENT_SPAWN_ZONE in Perl (#2877)
* [Quest API] Export $spawned to EVENT_SPAWN_ZONE in Perl

# Notes
- Exports `$spawned` to `EVENT_SPAWN_ZONE` in Perl.
- Allows operators to use the mob reference instead of having to grab it from entity list.

* Optional parsing.
2023-02-12 23:46:01 -06:00
Alex King 5ef8f8c3a8 [Quest API] Export $item and $corpse to EVENT_LOOT and EVENT_LOOT_ZONE in Perl (#2878)
* [Quest API] Export $item and $corpse to EVENT_LOOT and EVENT_LOOT_ZONE in Perl

# Notes
- Exports `$item` and `$corpse` to `EVENT_LOOT` in Perl.
- Exports `$item` and `$corpse` to `EVENT_LOOT_ZONE` in Perl.

* Optional parsing.

* Update corpse.cpp

* Cleanup

* Export changes

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 23:45:26 -06:00
Alex King 384de31989 [Quest API] (Performance) Check event exists before export and execute EVENT_BOT_CREATE (#2886)
* [Quest API] Optionally parse EVENT_BOT_CREATE

- Optionally parse this event instead of always doing so.

* Cleanup

* Cleanup
2023-02-12 23:40:03 -06:00
Alex King 5be3780a54 [Quest API] (Performance) Check event exists before export and execute EVENT_LEVEL_UP and EVENT_LEVEL_DOWN (#2889)
* [Quest API] Optionally parse EVENT_LEVEL_UP and EVENT_LEVEL_DOWN

- Optionally parses these events instead of always doing so.

* [Quest API] Optionally parse EVENT_LEVEL_UP and EVENT_LEVEL_DOWN

- Optionally parses these events instead of always doing so.
2023-02-12 23:36:45 -06:00
Alex King 21e42714eb [Quest API] (Performance) Check merchant events exist before export and execute (#2893)
* [Quest API] Optionally parse merchant events

- Optionally parse these events instead of always doing so.

* Cleanup
2023-02-12 23:33:32 -06:00
Alex King 3474c00e7a [Quest API] (Performance) Check event EVENT_LANGUAGE_SKILL_UP, EVENT_SKILL_UP, or EVENT_USE_SKILL exist before export and execute (#2894)
* [Quest API] Optionally parse EVENT_LANGUAGE_SKILL_UP, EVENT_SKILL_UP, and EVENT_USE_SKILL

- Optionally parse these events instead of always doing so.

* Cleanup
2023-02-12 23:30:48 -06:00
Alex King 3d6b0e5f74 [Quest API] (Performance) Check event EVENT_COMBINE, EVENT_COMBINE_SUCCESS, EVENT_COMBINE_FAILURE, or EVENT_COMBINE_VALIDATE exist before export and execute (#2896)
* [Quest API] Optionally parse EVENT_COMBINE_SUCCESS and EVENT_COMBINE_FAILURE

- Optionally parse these events instead of always doing so.

* Update tradeskills.cpp

* Update tradeskills.cpp
2023-02-12 23:28:27 -06:00
Alex King 9f619859d1 [Quest API] (Performance) Check spell or cast events exist before export and execute (#2897)
* [Quest API] Optionally parse spell/cast events

# Notes
- Optionally parses `EVENT_CAST`, `EVENT_CAST_BEGIN`, `EVENT_CAST_ON`, `EVENT_SPELL_EFFECT_NPC`, `EVENT_SPELL_EFFECT_CLIENT`, `EVENT_SPELL_EFFECT_BOT`, `EVENT_SPELL_EFFECT_BUFF_TIC_CLIENT`, `EVENT_SPELL_EFFECT_BUFF_TIC_NPC`, `EVENT_SPELL_EFFECT_BUFF_TIC_BOT`, `EVENT_SPELL_FADE`, and `EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE`.

* Cleanup

* PR comment fixes

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 23:26:17 -06:00
Alex King 805a9c5f59 [Quest API] (Performance) Check event EVENT_DEATH, EVENT_DEATH_COMPLETE, or EVENT_DEATH_ZONE exist before export and execute (#2909)
* [Quest API] Optionally parse EVENT_DEATH and EVENT_DEATH_COMPLETE

- Optionally parse these events instead of always doing so.

* Update attack.cpp

* Update attack.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 23:15:57 -06:00
Alex King 43329dc583 [Quest API] (Performance) Check event exists before export and execute EVENT_KILLED_MERIT (#2911)
- Optionally parse this event instead of always doing so.
2023-02-12 23:09:34 -06:00
Alex King 66fee56c47 [Quest API] (Performance) Check event exists before export and execute EVENT_DISCOVER_ITEM (#2912)
- Optionally parse this event instead of always doing so.
2023-02-12 23:07:32 -06:00
Alex King efb2ab57aa [Quest API] Optionally parse EVENT_CONNECT and EVENT_DISCONNECT (#2913)
- Optionally parse these events instead of always doing so.
2023-02-12 23:01:48 -06:00
Alex King 0a7d482299 [Quest API] (Performance) Check event EVENT_ENVIRONMENTAL_DAMAGE exists before export and execute (#2899)
* [Quest API] Optionally parse EVENT_ENVIRONMENTAL_DAMAGE

# Notes
- Optionally parses this event instead of always doing so.

* Update client_packet.cpp
2023-02-12 23:00:04 -06:00
Alex King de047fb851 [Quest API] (Performance) Check event EVENT_FEIGN_DEATH exists before export and execute (#2916)
* [Quest API] Optionally parse EVENT_FEIGN_DEATH

# Notes
- Optionally parse this event instead of always doing so.

* Remove unused reference, fix other PR

* Update task_client_state.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 22:59:14 -06:00
Natedog2012 9836b5cf67 [Bug Fix] Fix for interrupting item casts to no longer lock the client if cast time of item greater than 0 (#2921) 2023-02-12 22:49:59 -06:00
Alex King c64591b8f7 [Quest API] Export $killed_npc to EVENT_NPC_SLAY to Perl (#2879)
# Notes
- Exports `$killed_npc` to `EVENT_NPC_SLAY` to Perl.
- Allows operators to use NPC reference in event instead of just NPC ID.
2023-02-12 22:49:16 -06:00
Alex King 3813162bac [Quest API] (Performance) Check task events exist before export and execute (#2883)
* [Quest API] Optionally parse task events

- Optionally parses these events instead of always doing so.

* Update task_client_state.cpp

* Cleanup

* Update task_client_state.cpp

* [Quest API] Optionally parse task events

- Optionally parses these events instead of always doing so.

* Update task_client_state.cpp

* Cleanup
2023-02-12 22:48:51 -06:00
Alex King 7099e17c7e [Quest API] Export $hate_entity to EVENT_HATE_LIST in Perl (#2885)
# Notes
- Exports `$hate_entity` to `EVENT_HATE_LIST`.
- Allows operators to see which mob is joining/leaving an NPC's hatelist.
2023-02-12 22:44:31 -06:00
Alex King 2c75e8fcd4 [Quest API] Add $target export to EVENT_INSPECT in Perl (#2891)
* [Quest API] Add $target export to EVENT_INSPECT in Perl

# Notes
- Exports `$target` to `EVENT_INSPECT`.
- Allows operators to get information from target directly instead of using entity list.

* Update client_packet.cpp
2023-02-12 22:43:38 -06:00
Alex King e8f01fb6ac [Quest API] Export $item and $augment to augment events in Perl (#2895)
* [Quest API] Export $item and $augment to augment events in Perl

# Notes
- Exports `$item` and `$augment` to `EVENT_AUGMENT_INSERT_CLIENT` in Perl.
- Exports `$item` and `$augment` to `EVENT_AUGMENT_REMOVE_CLIENT` in Perl.
- Allows operators to use item and augment reference instead of just item IDs.

* Cleanup
2023-02-12 22:42:27 -06:00
Alex King fd0764d4cb [Quest API] (Performance) Check event exists before export and execute EVENT_TIMER (#2903)
# Notes
- Parse this event optionally instead of always doing so.
2023-02-12 22:33:33 -06:00
Alex King 71b2bf6a64 [Quest API] (Performance) Check event exists before export and execute EVENT_ENTER_ZONE and EVENT_ZONE (#2900)
# Notes
- Optionally parse these events instead of always doing so.
2023-02-12 22:32:37 -06:00
Alex King 2dcff247c8 [Quest API] Export targets to EVENT_CONSIDER and EVENT_CONSIDER_CORPSE (#2908)
# Perl
- Export `$target` to `EVENT_CONSIDER`.
- Export `$corpse` to `EVENT_CONSIDER_CORPSE`.

# Lua
- Export `e.other` to `EVENT_CONSIDER`.
- Export `e.corpse` to `EVENT_CONSIDER_CORPSE`.

 # Notes
- Allows operators to grab the target or corpse a player is considering.
2023-02-12 22:32:04 -06:00
Alex King 93f19d3971 [Quest API] (Performance) Check event EVENT_AGGRO, EVENT_ATTACK, or EVENT_COMBAT exist before export and execute (#2901)
* [Quest API] Optionally parse EVENT_COMBAT

# Notes
- Optionally parse this event instead of always doing so.

* Optional EVENT_ATTACK

* Update attack.cpp
2023-02-12 22:30:24 -06:00
Alex King bad44f35e2 [Quest API] (Performance) Check event EVENT_PAYLOAD or EVENT_SIGNAL exist before export and execute (#2902)
* [Quest API] Optionally parse EVENT_PAYLOAD and EVENT_SIGNAL

# Notes
- Optionally parse these events instead of always doing so.

* Update bot.cpp
2023-02-12 22:28:50 -06:00
Alex King 4a339d49df [Quest API] (Performance) Check event exists before export and execute EVENT_HP (#2904)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:27:57 -06:00
Alex King 57d0420399 [Quest API] (Performance) Check event EVENT_WAYPOINT_ARRIVE or EVENT_WAYPOINT_DEPART exist before export and execute (#2905)
* [Quest API] Optionally parse EVENT_WAYPOINT_ARRIVE and EVENT_WAYPOINT_DEPART

# Notes
- Optionally parse these events instead of always doing so.

* [Quest API] Optionally parse EVENT_WARP

# Notes
- Optionally parse this event instead of always doing so.

* Revert "[Quest API] Optionally parse EVENT_WARP"

This reverts commit d8acb9883d.
2023-02-12 22:27:15 -06:00
Alex King 90def9b882 [Quest API] (Performance) Check event exists before export and execute EVENT_TRADE (#2906)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:26:21 -06:00
Alex King 84156829a7 [Quest API] (Performance) Check event exists before export and execute EVENT_WARP (#2907)
# Notes
- Parse this event optionally instead of always doing so.
2023-02-12 22:25:42 -06:00
Alex King d210b1e5ff [Quest API] (Performance) Check event EVENT_SLAY exists before export and execute (#2910)
* [Quest API] Optionally parse EVENT_SLAY

# Notes
- Optionally parse this event instead of always doing so.

* Update attack.cpp
2023-02-12 22:24:38 -06:00
Alex King 086538754e [Quest API] (Performance) Check event EVENT_ITEM_TICK or EVENT_WEAPON_PROC exist before export and execute (#2914)
* [Quest API] Optionally parse EVENT_ITEM_TICK

# Notes
- Optionally parse this event instead of always doing so.

* Update mob.cpp
2023-02-12 22:22:22 -06:00
Alex King 241f900dc4 [Quest API] (Performance) Check event exists before export and execute EVENT_DUEL_LOSE and EVENT_DUEL_WIN (#2915)
# Notes
- Optionally parse these events instead of always doing so.
2023-02-12 22:21:21 -06:00
Alex King 604256a223 [Quest API] (Performance) Check event exists before export and execute EVENT_RESPAWN (#2917)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:19:23 -06:00
Alex King 2dffc66c6f [Quest API] (Performance) Check event exists before export and execute EVENT_UNHANDLED_OPCODE (#2918)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:18:57 -06:00
Alex King 1bf24273d2 [Quest API] (Performance) Check event exists before export and execute EVENT_TICK (#2919)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:16:39 -06:00
Alex King c060280417 [Quest API] Optionally parse EVENT_TEST_BUFF (#2920)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:16:17 -06:00
Alex King bc6efd5f74 [Quest API] (Performance) Check equip or scale item events exist before export and execute (#2898)
* [Quest API] Optional parse equip and scale item events

# Notes
- Optionally parse `EVENT_SCALE_CALC`, `EVENT_ITEM_ENTER_ZONE`, `EVENT_UNEQUIP_ITEM_BOT`, `EVENT_EQUIP_ITEM_BOT`, `EVENT_EQUIP_ITEM`, `EVENT_UNEQUIP_ITEM`, `EVENT_EQUIP_ITEM_CLIENT`, `EVENT_UNEQUIP_ITEM_CLIENT`

* Cleanup
2023-02-12 22:15:54 -06:00
Alex King efd6d2f9b1 [Quest API] (Performance) Check event EVENT_AA_BUY or EVENT_AA_GAIN exist before export and execute (#2892)
* [Quest API] Optionally parse EVENT_AA_BUY and EVENT_AA_GAIN

# Notes
- Optionally parse these events instead of always doing so.

* Cleanup
2023-02-12 22:04:54 -06:00
Alex King 9dd4cf71f1 [Quest API] (Performance) Check event exists before export and execute EVENT_GM_COMMAND (#2890)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:03:51 -06:00
Alex King cfec31457c [Quest API] (Performance) Check event exists before export and execute area events (#2888)
* [Quest API] Optionally parse area events

# Notes
- Optionally parse these events instead of always doing so.

* Update entity.cpp
2023-02-12 22:01:28 -06:00
Alex King 5ac5beb456 [Quest API] (Performance) Check event exists before export and execute EVENT_DESPAWN and EVENT_DESPAWN_ZONE (#2887)
# Notes
- Optionally parse these events instead of always doing so.
2023-02-12 21:59:01 -06:00
Alex King 0e51131d67 [Quest API] (Performance) Check event exists before export and execute EVENT_GROUP_CHANGE (#2884)
* [Quest API] Optionally parse EVENT_GROUP_CHANGE

# Notes
- Optionally parse this event instead of always doing so.

* Update embparser.cpp
2023-02-12 21:56:25 -06:00
Alex King f9a87e26c9 [Quest API] (Performance) Check event exists before export and execute EVENT_AGGRO_SAY, EVENT_SAY, and EVENT_PROXIMITY_SAY (#2882)
* [Quest API] Add optional parsing to EVENT_AGGRO_SAY and EVENT_SAY

# Notes
- Optionally parse these events instead of always doing so.

* Optionally parse EVENT_PROXIMITY_SAY
2023-02-12 21:54:20 -06:00
Alex King 9e16cd8ae8 [Quest API] (Performance) Check event exists before export and execute EVENT_POPUP_RESPONSE (#2881)
# Notes
- Optionally parses this event instead of always doing so.
2023-02-12 21:48:23 -06:00
Alex King 9644f14746 [Quest API] (Performance) Check event exists before export and execute EVENT_CLICK_DOOR and EVENT_CLICK_OBJECT (#2880)
* [Quest API] Add optional parsing to EVENT_CLICK_DOOR.

# Notes
- Optional parses this event instead of always doing so.

* Update client_packet.cpp
2023-02-12 21:47:17 -06:00
Chris Miles d9f545a5ec [Logging] Implement Player Event Logging system (#2833)
* Plumbing

* Batch processing in world

* Cleanup

* Cleanup

* Update player_event_logs.cpp

* Add player zoning event

* Use generics

* Comments

* Add events

* Add more events

* AA_GAIN, AA_PURCHASE, FORAGE_SUCCESS, FORAGE_FAILURE

* FISH_SUCCESS, FISH_FAILURE, ITEM_DESTROY

* Add charges to ITEM_DESTROY

* WENT_ONLINE, WENT_OFFLINE

* LEVEL_GAIN, LEVEL_LOSS

* LOOT_ITEM

* MERCHANT_PURCHASE

* MERCHANT_SELL

* SKILL_UP

* Add events

* Add more events

* TASK_ACCEPT, TASK_COMPLETE, and TASK_UPDATE

* GROUNDSPAWN_PICKUP

* SAY

* REZ_ACCEPTED

* COMBINE_FAILURE and COMBINE_SUCCESS

* DROPPED_ITEM

* DEATH

* SPLIT_MONEY

* TRADER_PURCHASE and TRADER_SELL

* DISCOVER_ITEM

* Convert GM_COMMAND to use new macro

* Convert ZONING event to use macro

* Revert some code changes

* Revert "Revert some code changes"

This reverts commit d53682f997e89a053a660761085913245db91e9d.

* Add cereal generation support to repositories

* TRADE

* Formatting

* Cleanup

* Relocate discord_manager to discord folder

* Discord sending plumbing

* Rename UCS's Database class to UCSDatabase to be more specific and not collide with base Database class for repository usage

* More discord sending plumbing

* More discord message formatting work

* More discord formatting work

* Discord formatting of events

* Format WENT_ONLINE, WENT_OFFLINE

* Add merchant purchase event

* Handle Discord MERCHANT_SELL formatter

* Update player_event_discord_formatter.cpp

* Tweaks

* Implement retention truncation

* Put mutex locking on batch queue, put processor on its own thread

* Process on initial bootup

* Implement optional QS processing, implement keepalive from world to QS

* Reload player event settings when logs are reloaded in game

* Set settings defaults

* Update player_event_logs.cpp

* Update player_event_logs.cpp

* Set retention days on boot

* Update player_event_logs.cpp

* Player Handin Event Testing.

Testing player handin stuff.

* Cleanup.

* Finish NPC Handin.

* set a reference to the client inside of the trade object as well for plugins to process

* Fix for windows _inline

* Bump to cpp20 default, ignore excessive warnings on windows

* Bump FMT to 6.1.2 for cpp20 compat and swap fmt::join for Strings::Join

* Windows compile fixes

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Create 2022_12_19_player_events_tables.sql

* [Formatters] Work on Discord Formatters

* Handin money.

* Format header

* [Formatters] Work on Discord Formatters

* Format

* Format

* [Formatters] More Formatter work, need to test further.

* [Formatters] More Work on Formatters.

* Add missing #endif

* [Formatters] Work on Formatters, fix Bot formatting in ^create help

* NPC Handin Discord Formatter

* Update player_event_logs.cpp

* Discover Item Discord Formatter

* Dropped Item Discord Formatter

* Split Money Discord Formatter

* Trader Discord Formatters

* Cleanup.

* Trade Event Discord Formatter Groundwork

* SAY don't record GM commands

* GM_Command don't record #help

* Update player_event_logs.cpp

* Fill in more event data

* Post rebase fixes

* Post rebase fix

* Discord formatting adjustments

* Add event deprecation or unimplemented tag support

* Trade events

* Add return money and sanity checks.

* Update schema

* Update ucs.cpp

* Update client.cpp

* Update 2022_12_19_player_events_tables.sql

* Implement archive single line

* Replace hackers table and functions with PossibleHack player event

* Replace very old eventlog table since the same events are covered by player event logs

* Update bot_command.cpp

* Record NPC kill events ALL / Named / Raid

* Add BatchEventProcessIntervalSeconds rule

* Naming

* Update CMakeLists.txt

* Update database_schema.h

* Remove logging function and methods

* DB version

* Cleanup SendPlayerHandinEvent

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
2023-02-12 21:31:01 -06:00
Aeadoin 1cc32d92cf [Bots] Add Lore Check for Augments. (#2874)
* [Bots] Add Lore Check for Augments.

* Add bot name
2023-02-12 16:43:58 -05:00
Aeadoin 924e91cf64 [Crash] Fix Bot Crash in Bot::Bot Constructor. (#2868)
* [Crash] Fix Bot Crash in Bot::Bot Constructor.

* fix another potential crash in bot contructor.
2023-02-12 14:27:29 -05:00
Aeadoin 9825c61a13 [Bots] Add Pet Power Support for Temp Pets. (#2853) 2023-02-11 10:57:02 -05:00
Alex King 5a0a1b1ffd [Quest API] Export $item to EVENT_DISCOVER_ITEM in Perl (#2863)
# Notes
- Exports `$item` to `EVENT_DISCOVER_ITEM`.
2023-02-10 23:56:50 -05:00
Alex King a3bb7e7741 [Quest API] Export $item to Client/Bot Equip Events in Perl (#2860)
* [Quest API] Add $item Export to Client/Bot Equip Events

# Notes
- Adds `$item` export to `EVENT_ITEM_EQUIP_CLIENT`, `EVENT_ITEM_UNEQUIP_CLIENT`, `EVENT_ITEM_EQUIP_BOT`, and `EVENT_UNEQUIP_ITEM_BOT`.

* Update bot.cpp

* Update embparser.cpp
2023-02-10 23:56:36 -05:00
Alex King a1251bdda8 [Quest API] Export $door to EVENT_CLICKDOOR in Perl (#2861)
# Notes
- Exports `$door` object to `EVENT_CLICKDOOR` in Perl so you don't have to grab it from entity list.
2023-02-10 23:56:24 -05:00
Alex King b90082d694 [Quest API] Export $object to EVENT_CLICK_OBJECT in Perl (#2862)
# Notes
- Exports `$object` to `EVENT_CLICK_OBJECT` in Perl so you don't have to grab it from entity list.
2023-02-10 23:34:52 -05:00
Aeadoin a49fa42f35 [Bots] Update ResistSpell to use temp_level_diff client formula (#2851) 2023-02-09 10:36:15 -05:00
Aeadoin 7064a4156f [Bots] Add IsBot() to methods in attack.cpp where applicable. (#2840)
* [Bots] add IsBot() to methods in attack.cpp where applicable.

* Add mercs where applicable

* Cleanup verbose if statements

* typo

* Fix other spots missed.
2023-02-09 10:36:01 -05:00
Aeadoin 106cb45b57 [Crash] Fix potential crash in Mob::CommonDamage (#2848)
out of bounds memory access.
2023-02-09 10:35:51 -05:00
Aeadoin 9a544650ee [Bots] ST_AreaClientOnly spells to land on Bots (#2849) 2023-02-09 10:35:38 -05:00
Aeadoin 032d423add [Bots] Add TotalDominationBonus modifiers. (#2852) 2023-02-09 10:35:26 -05:00
Akkadius 760b30ca0a [Crash] Fix issue where long short names overflow file_name 2023-02-09 01:03:51 -06:00
Chris Miles 6b08ca51cc [Logging] Add raw opcode when emu translated opcode is not found (OP_Unknown) via (C->S) (#2847) 2023-02-07 21:23:24 -06:00
Alex King 268879b414 [Quest API] Add Recipe-based methods to Perl/Lua. (#2844)
* [Quest API] Add Recipe-based methods to Perl/Lua.

# Perl
- Add `quest::get_recipe_component_item_ids(recipe_id)`.
- Add `quest::get_recipe_container_item_ids(recipe_id)`.
- Add `quest::get_recipe_fail_item_ids(recipe_id)`.
- Add `quest::get_recipe_salvage_item_ids(recipe_id)`.
- Add `quest::get_recipe_success_item_ids(recipe_id)`.
- Add `quest::get_recipe_component_count(recipe_id, item_id)`.
- Add `quest::get_recipe_fail_count(recipe_id, item_id)`.
- Add `quest::get_recipe_salvage_count(recipe_id, item_id)`.
- Add `quest::get_recipe_success_count(recipe_id, item_id)`.

# Lua
- Add `eq.get_recipe_component_item_ids(recipe_id)`.
- Add `eq.get_recipe_container_item_ids(recipe_id)`.
- Add `eq.get_recipe_fail_item_ids(recipe_id)`.
- Add `eq.get_recipe_salvage_item_ids(recipe_id)`.
- Add `eq.get_recipe_success_item_ids(recipe_id)`.
- Add `eq.get_recipe_component_count(recipe_id, item_id)`.
- Add `eq.get_recipe_fail_count(recipe_id, item_id)`.
- Add `eq.get_recipe_salvage_count(recipe_id, item_id)`.
- Add `eq.get_recipe_success_count(recipe_id, item_id)`.

# Notes
- Before these methods, you would have to use DBI from Perl or Lua in order to get the components and their counts, these methods allow easy access to these values via the scripting API.
- These should be used sparingly as they're each an individual database hit and could go crazy in a hot path.

* Update eq_constants.h

* Update zonedb.h

* Update tradeskills.cpp

* Reserve.
2023-02-07 21:42:34 -05:00
Alex King 4c6dc960e4 [Bug Fix] Fix CheckNumHitsRemaining() with 1H Blunt (#2846)
# Notes
- CheckNumHitsRemaining() wasn't working when skill ID was `0` (1H Blunt).
2023-02-06 23:41:32 -05:00
Aeadoin cc46b54f7f [Bots] Add Additional HeroicAgi/Dex Modifiers. (#2838)
* [Bots] Add Additional HeroicAgi/Dex Modifiers.

* Typo
2023-02-06 22:31:02 -05:00
Aeadoin 9e3b363d4a [Code] Add IsOfClientBot() virtual method. (#2845) 2023-02-06 22:30:49 -05:00
Aeadoin b0d1dc5f04 [Bots/Mercs] Add 100% Hit chance if sitting while attacked. (#2839)
* [BOT] Add 100% Hit chance if sitting while attacked.

* [BOT] Add 100% Hit chance if sitting while attacked.

* Add Mercs correctly

* Missed usage of IsSitting() in Mob::RollD20
2023-02-06 22:30:33 -05:00
Chris Miles 158396937a [Release] 22.3.0 (#2842)
* [Release] 22.3.0

* Update version.h

* Redirect stderr

* Update should-release to filter non-master

* Update should-release
2023-02-06 20:12:04 -06:00
Aeadoin fb1467284c [Bots] Add Additional HeroicStr modifiers. (#2837) 2023-02-06 21:07:38 -05:00
Aeadoin 14addd4869 [Feature] Add IsOfClientBotMerc() virtual method. (#2843) 2023-02-06 21:03:48 -05:00
Chris Miles 0a114fae9a [Doors] Have NPCs trigger double doors (#2821) 2023-02-06 17:47:03 -06:00
Chris Miles 2b224d42ad [Rules] Fix rule updates that affected bot booting checks (#2841) 2023-02-06 17:31:50 -06:00
Natedog2012 155ec9ac0d [Quest API] Add rule AlternateAugmentationSealer for using a different bagtype (#2831)
* [Quest API] Add rule AlternateAugmentationSealer for using a different bagtype as an alternate augmentation sealer. Use EVENT_COMBINE with UseAugmentContainer

* Default it to be off or bagtype 53 (BagTypeAugmentationSealer)
2023-02-06 17:30:16 -06:00
Chris Miles 25b4b97c41 [DB Updates] Add Windows MySQL path auto detection for users where the path is not found (#2836) 2023-02-06 17:25:34 -06:00
Joel 839f31b24d [Rule] Added rule to bypass level based haste caps (#2835) 2023-02-06 17:25:17 -06:00
Chris Miles 20728c31c4 [Crash] Fix crash in bot command botdyearmor (#2832)
* [Crash] Fix crash in bot command botdyearmor

* Update bot_command.cpp
2023-02-06 17:24:49 -06:00
Chris Miles c6eb12ac16 [Crash] Fix IsUnderwaterOnly crash where npc data references can be stale (#2830)
* [Crash] Fix IsUnderwaterOnly crash where npc data references can be stale

* m_ prefix
2023-02-06 17:24:38 -06:00
Chris Miles 34d21d4056 [Crash] Fix command crash with #npcedit weapon when second weapon not passed ni (#2829) 2023-02-06 17:24:24 -06:00
Chris Miles d369b47ef4 [Tasks] Implement alternate currency rewards (#2827)
* Reward currency on task completion

* Handle reward window

* Tweaks
2023-02-06 17:24:13 -06:00
Chris Miles 404f7cada8 [Pathing] Improvements to handling tight corridors pathing, clipping detection and recovery (#2826) 2023-02-06 17:24:03 -06:00
Chris Miles 823e73336d [Command] #list now searches without case sensitivity (#2825) 2023-02-06 17:23:50 -06:00
Chris Miles 0da6391be3 [Doors] Remove door dev tools spam on client controlled doors (#2824)
* [Doors] Remove door dev tools spam on client controlled doors

* Update client_packet.cpp

* Update client_packet.cpp

* Update ruletypes.h
2023-02-06 17:23:40 -06:00
Chris Miles 0348cb6b8e [Fix] Fix NPC ghosting at safe coordinates (#2823)
* [Fix] Fix NPC ghosting at safe coordinates

* Tweak order

* Handle another case
2023-02-06 17:23:29 -06:00
Vayle b385a4385f [Rules] Add rule to ignore name filter on chat channel creation. (#2820)
* [Rules] Add rule to ignore name filter on chat channel creation.

* Conditional reorder
2023-02-06 17:22:12 -06:00
Chris Miles 6a9228ed6e [Lua] Resolve stoi Exception (#2736)
* [Lua] Resolve stoi Exception

* Change fallback for wp, not really needed for safety

* Change to Strings::ToInt
2023-02-06 17:22:01 -06:00
Vayle 8031bf0bcb [Quest API] Add EVENT_TASKACCEPTED to Player scope (#2822)
* Add EVENT_TASKACCEPTED to player scope

* Formatting
2023-02-05 22:53:37 -05:00
Alex King c1584da9cc [Quest API] Default ScaleNPC to always scale. (#2818)
* [Quest API] Default ScaleNPC to always scale.

# Notes
- ScaleNPC will now always override stats, with the option to override special abilities.

* Update npc_scale_manager.h
2023-02-05 22:52:52 -05:00
Alex King ee6f6f683c [Commands] Remove extraneous else from #weather (#2819)
# Notes
- Condition falls back to sending message and can't turn weather off.
2023-02-01 06:05:32 -05:00
Akkadius 60707a14db [Hotfix] Post revert build fix for https://github.com/EQEmu/Server/commit/54050924d81d1f83268fe01f9c2b36fe10626601 2023-01-31 20:37:13 -06:00
Akkadius 54050924d8 Revert "[Quest API] Cleanup string copies and push_backs. (#2807)"
This reverts commit bcc2e022dc.
2023-01-31 20:30:34 -06:00
Aeadoin f727c9f75a [Bug Fix] Fix does_augment_fit_slot method. (#2817)
* [Bug Fix] DoesAugmentFit finds if an Aug Slot is free, changed overload method to check if Aug fits slot.

* Tweak/add lua
2023-01-31 21:11:12 -05:00
Alex King f410c89815 [Quest API] Add Override Parameters to ScaleNPC() in Perl/Lua. (#2816)
# Perl
- Add `$npc->ScaleNPC(level, always_scale_stats)`.
- Add `$npc->ScaleNPC(level, always_scale_stats, always_scale_special_abilities)`.

# Lua
- Add `npc:ScaleNPC(level, always_scale_stats)`.
- Add `npc:ScaleNPC(level, always_scale_stats, always_scale_special_abilities)`.

# Notes
- Allows operators to not have to set stats to 0 in order for scaling to kick in when scripting.
- Special ability override is separate in case you don't want to override some inherent special abilities the NPC has from a script or otherwise.
2023-01-31 21:11:05 -05:00
Natedog2012 2e575652f6 [Bug fix]#reload static should now properly fill the entity_lists for… (#2815)
* [Bug fix]#reload static should now properly fill the entity_lists for objects / doors / groundspawns
The individual #reload commands WILL still have issues when trying to use #list afterwards!

* Point ReloadDoors, ReloadGroundSpawns, ReloadObjects all to reload static to avoid entity_list data missing
2023-01-31 16:32:25 -06:00
Natedog2012 8e831dce36 [Bug fix]#reload aa will now refresh the AA table properly for every client when changes are made (#2814) 2023-01-30 20:24:02 -06:00
Alex King 040c092795 [Quest API] Add Augment Slot support to does_augment_fit (#2813)
* [Quest API] Add Augment Slot support to does_augment_fit

# Notes
- Allows you to check if the supplied augment ID fits in the specified augment slot of the item instance provided.

* Update item_instance.cpp
2023-01-30 21:18:16 -05:00
Alex King a25952910a [Quest API] Add EVENT_ITEM_CLICK_CLIENT and EVENT_ITEM_CLICK_CAST_CLIENT to Perl/Lua. (#2810)
* [Quest API] Add EVENT_ITEM_CLICK_CLIENT and EVENT_ITEM_CLICK_CAST_CLIENT to Perl/Lua.

# Perl
- Add `EVENT_ITEM_CLICK_CLIENT`.
- Add `EVENT_ITEM_CLICK_CAST_CLIENT`.
- Both events export `$item_id`, `$item_name`, `$slot_id`, and `$spell_id`.

# Lua
- Add `event_item_click_client`.
- Add `event_item_click_cast_client`.
- Both events export `e.item_id`, `e.item_name`, `e.slot_id`, `e.spell_id`, and `e.item`.

# Notes
- Allows operators to handle item clicks in player scripts instead of item-specific scripts.

* Update lua_parser_events.cpp

* Remove optional bool.
2023-01-30 05:01:12 -06:00
Natedog2012 66896a3121 [Quest API] Add GetItemCooldown to return the time remaining on items… (#2811)
* [Quest API] Add GetItemCooldown to return the time remaining on items in seconds

* Change GetItemCooldown to uint32 for timers up to 130 years
2023-01-30 00:04:06 -06:00
Paul Coene 4d2418af9d [Bug Fix] BuffLevelRestrictions were restricting group buffs if mob targeted (#2809) 2023-01-29 18:52:03 -05:00
Chris Miles 265b32f46f [Readme] Update build badges with Drone 2023-01-29 17:06:48 -06:00
Alex King 1cde55c535 [Quest API] Add LDoN Methods to Perl/Lua (#2799)
# Perl
- Add `$npc->GetLDoNLockedSkill()`.
- Add `$npc->GetLDoNTrapType()`.
- Add `$npc->GetLDoNTrapSpellID()`.
- Add `$npc->IsLDoNLocked()`.
- Add `$npc->IsLDoNTrapped()`.
- Add `$npc->IsLDoNTrapDetected()`.
- Add `$npc->SetLDoNLocked(is_locked)`.
- Add `$npc->SetLDoNLockedSkill(skill_value)`.
- Add `$npc->SetLDoNTrapped(is_trapped)`.
- Add `$npc->SetLDoNTrapDetected(is_detected)`.
- Add `$npc->SetLDoNTrapSpellID(spell_id)`.
- Add `$npc->SetLDoNTrapType(trap_type)`.

# Lua
- Add `npc:GetLDoNLockedSkill()`.
- Add `npc:GetLDoNTrapType()`.
- Add `npc:GetLDoNTrapSpellID()`.
- Add `npc:IsLDoNLocked()`.
- Add `npc:IsLDoNTrapped()`.
- Add `npc:IsLDoNTrapDetected()`.
- Add `npc:SetLDoNLocked(is_locked)`.
- Add `npc:SetLDoNLockedSkill(skill_value)`.
- Add `npc:SetLDoNTrapped(is_trapped)`.
- Add `npc:SetLDoNTrapDetected(is_detected)`.
- Add `npc:SetLDoNTrapSpellID(spell_id)`.
- Add `npc:SetLDoNTrapType(trap_type)`.

# Notes
- Adds these methods to allow LDoN traps to be set by a script.
2023-01-29 14:29:31 -06:00
Michael 369b5c2921 [Bug] Fixing % based mob see invis (#2802)
This was preventing anything other than 0 or 1 to be passed, but per the current design, the see_invis can be anything from 0 to MAX 25499, which can give you level 254 invis. See design notes in Mob::GetSeeInvisibleLevelFromNPCStat.
2023-01-29 14:26:55 -06:00
Alex King bcc2e022dc [Quest API] Cleanup string copies and push_backs. (#2807)
# Notes
- Several places use `push_back` instead of `emplace_back`.
- Several places use `std::string` instead of `const std::string&`.
2023-01-29 15:14:49 -05:00
Alex King 0fef46a6c1 [Feature] Add Min/Max Status to Merchants (#2806)
# Notes
- Allows operators to set a minimum and maximum status that an item will show for players.
- Allows operators to have items on a merchant that only a GM can see.
- Some servers may use status for different things, so having a minimum and a maximum will allow for more functionality.
- Default of `min_status` is `0` (Player) and default of `max_status` is `255` (Max).
2023-01-29 15:03:41 -05:00
Alex King b867d40774 [Quest API] Add EVENT_DAMAGE_GIVEN and EVENT_DAMAGE_TAKEN to Perl/Lua. (#2804)
* [Quest API] Add EVENT_DAMAGE_GIVEN and EVENT_DAMAGE_TAKEN to Perl/Lua.

# Perl
- Add `EVENT_DAMAGE_GIVEN`.
- Add `EVENT_DAMAGE_TAKEN`.
- Both events export `$entity_id`, `$damage`, `$spell_id`, `$skill_id`, `$is_damage_shield`, `$is_avoidable`, `$buff_slot`, `$is_buff_tic`, `$special_attack`.

# Lua
- Add `event_damage_given`.
- Add `event_damage_taken`.
- Both events export `e.entity_id`, `e.damage`, `e.spell_id`, `e.skill_id`, `e.is_damage_shield`, `e.is_avoidable`, `e.buff_slot`, `e.is_buff_tic`, `e.special_attack`, and `e.other`.

# Notes
- These events allow operators to have events fire based on damage given or taken, as well as keep better track of a Bot, Client, or NPC's damage per second or otherwise.
- Special Attack is only useful for NPCs, but allows you to see if the attack is Rampage, AERampage, or Chaotic Stab.

* Cleanup.
2023-01-29 14:35:17 -05:00
Aeadoin a489290eba [Bots] Add GetAugmentIDsBySlotID & AddItem with table ref Methods. (#2805)
* [Bots] Add GetAugmentIDsBySlotID & AddItem with table ref Methods.

* Return invalid slots to owner.
2023-01-29 12:49:44 -05:00
Alex King 549d731849 [Bug Fix] Resolve issue with max buff count being 25 in ROF2. (#2800)
# Notes
- This allows ROF2 to properly utilize their max buff count.
- May cause issues with older clients.
2023-01-28 17:40:11 -06:00
Natedog2012 68a34565f9 [Bugfix] Add SetItemCooldown to tell client exact timer of item when clicked and export to perl and lua (#2795)
Items that are on cooldown but client doesn't show.. clicking item will fix the timer in client
2023-01-27 17:31:14 -06:00
Aeadoin c05f951f81 [Bots] Add Override methods for GetMax Buffs/Songs/Total slots (#2801) 2023-01-27 18:00:50 -05:00
Akkadius dc64561b3c [Release] 22.2.0 2023-01-27 01:13:38 -06:00
Akkadius cb2aee2713 [Release] 22.2.0 2023-01-27 01:12:30 -06:00
Chris Miles 0730b6b588 [Crash] Fix crash issue with log formatting during character creation (#2798) 2023-01-26 20:40:58 -06:00
Aeadoin 826550acac [Bots] Add EVENT_UNEQUIP_ITEM_BOT & EVENT_EQUIP_ITEM_BOT (#2796)
* Initial Commit, need to test.

* Add unequip events.

* const auto
2023-01-26 19:49:20 -05:00
Alex King b71b3f5be0 [Bots] ^create and ^viewcombos popup messages fix. (#2797)
# Notes
- These messages were showing weirdly and inconsistently, cleaned them up to show at max 4 per line.
- `^viewcombos` now shows class name and ID in the popup title.
- `^create help` now shows proper class names and IDs instead of `{}`.
2023-01-26 18:44:21 -05:00
Natedog2012 1fe79f430c [Feature] ResetItemCooldown added to lua/perl and fix item re-cast times to show properly (#2793)
* Testing.

* Add ResetItemCooldown and port it over to perl

* This flag needs to be set for updating shared item cooldowns

* Properly set item recast for all item types, on corpses, on looting

* SummonItem properly sets recast timers of summoned items

* Rename variable to avoid confusion and change manifest to be more specific

* Sanity check item_d

* Recast -1 added as RECAST_TYPE_UNLINKED_ITEM
ResetItemCooldown will still remove cooldown of item that we don't have so when we acquire it the cooldown is reset

* change magic numbers

* more magic numbers

* More constants yay

* Remove unneeded export DeleteItemRecastTimer

* Remove duplicate message, this is handled by the client in this part of the code

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-01-25 20:09:08 -06:00
Alex King e5dabe0afc [Git] Add CMake Files to .gitignore (#2792)
* [Git] Add CMake Files to GitIgnore

* Update .drone.yml
2023-01-24 18:37:14 -06:00
Alex King 5720ffbcb6 [Release] 22.1.2 (#2791) 2023-01-24 17:18:42 -06:00
Alex King 2b0c778ad1 [Bug Fix] Fix nullptr spell in BCSpells::Load() (#2790)
* [Bug Fix] Fix nullptr spell in BCSpells::Load()

# Notes
- Fix possible `nullptr` where we didn't check if spell was valid before using it.

* Cleanup.
2023-01-24 17:57:12 -05:00
Alex King bf39a0540c [Cleanup] Cleanup #door Command. (#2783)
* [Cleanup] Cleanup #door Command.

# Notes
- Resolves an issue with `.1` versus `0.1`.
- Resolves an issue with updating a pre-existing door.
- Adds `heading` to the update/insert.

* Update doors.cpp
2023-01-24 16:37:21 -06:00
Chris Miles 08c8393988 [CI/CD] Build / Release Pipeline Changes (#2788)
* Test

* Test

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* Kill excessive warnings

* Split

* Remove 7z from build scripts

* Linux

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Test

* Update .drone.yml

* Naming

* Test upload

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Yolo

* Yolo

* Update .drone.yml

* Update .drone.yml

* Copy

* Yolo

* Release without bots

* Update .drone.yml

* Update .drone.yml

* Test pipeline

* Remove debug

* Update .drone.yml

* Filter pipeline stage

* Update .drone.yml

* Test

* Bots release 22.0.5 (Test)

* Release bot test #2

* Check if release

* Update .drone.yml

* Update .drone.yml

* exit 78

* Update .drone.yml

* Update .drone.yml

* Add version checks

* Update .drone.yml

* Update .drone.yml

* Test

* Update build-release.bat

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update build-release.bat

* Update build-release.bat

* Test pipeline

* Update CHANGELOG.md

* Bump

* Update build-release.bat

* Update build-release.bat

* Shuffle

* Take #45354

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* F

* Update windows-build.ps1

* Consolidate

* Run it

* Pop cache back in

* Update linux-build.sh

* Another release test

* Update linux-build.sh

* Update linux-build.sh

* Update CMakeLists.txt

* Trim windows assets

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* [22.1.0] Release

* Crash reporting

* Add version tag injection in the build pipeline

* Update windows-build.ps1

* Test

* Test

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* Kill excessive warnings

* Split

* Remove 7z from build scripts

* Linux

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Test

* Update .drone.yml

* Naming

* Test upload

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Yolo

* Yolo

* Update .drone.yml

* Update .drone.yml

* Copy

* Yolo

* Release without bots

* Update .drone.yml

* Update .drone.yml

* Test pipeline

* Remove debug

* Update .drone.yml

* Filter pipeline stage

* Update .drone.yml

* Test

* Bots release 22.0.5 (Test)

* Release bot test #2

* Check if release

* Update .drone.yml

* Update .drone.yml

* exit 78

* Update .drone.yml

* Update .drone.yml

* Add version checks

* Update .drone.yml

* Update .drone.yml

* Test

* Update build-release.bat

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update build-release.bat

* Update build-release.bat

* Test pipeline

* Update CHANGELOG.md

* Bump

* Update build-release.bat

* Update build-release.bat

* Shuffle

* Take #45354

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* F

* Update windows-build.ps1

* Consolidate

* Run it

* Pop cache back in

* Update linux-build.sh

* Another release test

* Update linux-build.sh

* Update linux-build.sh

* Update CMakeLists.txt

* Trim windows assets

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* [22.1.0] Release

* Crash reporting

* Add version tag injection in the build pipeline

* Update windows-build.ps1

* Full crash report on windows.

* Update endpoint

* [22.1.1] Release

* [skip ci] update .drone.yml

* Filter

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update CHANGELOG.md

Co-authored-by: KimLS <KimLS@peqtgc.com>
2023-01-24 16:37:04 -06:00
Alex King 8c12f7b431 [Bug Fix] Remove duplicate logic in GetActSpellHealing reducing HOT criticals (#2786)
# Notes
- Removes duplicate critical chance roll in `Mob::GetActSpellHealing`.
- Not sure if this was Live-like or an oversight, but it seems to drastically reduce the possibility of a HOT getting a critical.
- A 1% chance becomes a 0.01% chance being we have to roll twice.
2023-01-24 12:39:46 -06:00
Chris Miles 037be84f38 [Crash] Fix rarer world crash issue where scheduler database was not available (#2789) 2023-01-24 12:38:26 -06:00
Aeadoin 4d355afe9d [Bug Fix] Fix scenario where dereferenced object could be null. (#2784) 2023-01-23 18:40:23 -05:00
Aeadoin 93eddf603b [Bug Fix] Fix botgrouplist to display unique entries. (#2785) 2023-01-23 18:39:55 -05:00
Aeadoin 293f79268d [Bots] Fix Slow Query in QueryNameAvailablity (#2781) 2023-01-22 18:26:57 -05:00
Chris Miles 7e35d5aa79 [AA] Fix AA tables dump (#2769) 2023-01-22 12:57:08 -05:00
Alex King f7e4fba584 [Bug Fix] Fix bots equipping augments. (#2772)
# Notes
- Bots didn't check if the item was an augment before equipping, this stops them from equipping them.
2023-01-22 12:57:00 -05:00
Alex King 01a0f906e1 [Bots] Add Bot Command Reloading (#2773)
# Notes
- Adds `bot_command_init` to `#reload commands` so that operators can reload bot commands if they enable/disable bots while the server is running.
2023-01-22 12:56:55 -05:00
Alex King 0a11eaa092 [Bug Fix] Fix #findaa and GetAAName(). (#2774)
# Notes
- These were not properly checking every possible AA ID.
2023-01-22 12:56:49 -05:00
Alex King d0edb93d62 [Commands] Remove #guildapprove, #guildcreate, and #guildlist Commands (#2775)
# Notes
- Removes `#guildapprove`, `#guildcreate`, and `#guildlist`.
- Removes associated functions, classes, etc. that were only used in these commands.
- These commands are unused and/or covered by the general `#guild` command.
- Approvals don't really seem to be a thing anymore and the variable itself doesn't exist in stock PEQ database anyway.
2023-01-22 12:56:42 -05:00
Alex King 35c3778baf [Commands] Remove #undyeme Command. (#2776)
# Notes
- Removes redundant `#undyeme` command.
- Adds `GetGM()` check to `#undye` so players can't undye other players.
2023-01-22 12:56:36 -05:00
Alex King abb41840f8 [Commands] Cleanup #appearanceeffects Command. (#2777)
# Notes
- Cleanup messages and logic.
2023-01-22 12:56:26 -05:00
Aeadoin cd63047e60 [Bug Fix] Fix Bot Group Loading (#2780)
* [Bots] Fix Bot Groups

* unsigned.
2023-01-22 12:06:13 -05:00
Paul Coene 4fe5522212 [Bug Fix] #scribespells triggered error on mysql keyword rank (#2779) 2023-01-21 18:02:27 -05:00
Akkadius 0ccb18d017 [Hotfix] Remove appveyor fetch bots 2023-01-20 20:56:19 -06:00
Aeadoin e010e41a83 [Bots] Add Virtual Override for Bot::Attack (#2771) 2023-01-20 17:13:40 -05:00
Aeadoin 886f80117c [Cleanup] Merge Client::Attack and Bot::Attack into Mob::Attack (#2756)
* [Cleanup] Merge Client::Attack and Bot::Attack into Mob::Attack (#11)

* Remove #ifdef Bots to go along with KK fix

* Remove method in logging

* remove method from logging

* Fixes

* Rename
2023-01-20 15:52:45 -05:00
Chris Miles 5c095ab87a [Bots] Post pre-processor fixes (#2770)
* Fixes

* Update main.cpp
2023-01-20 13:28:39 -06:00
Akkadius e8ca3f6942 [eqemu_server.pl Swap out binary source 2023-01-20 12:56:37 -06:00
Akkadius 706a06efb6 [Appveyor] Remove bots preprocessor 2023-01-20 12:42:35 -06:00
Alex King 3335cacac1 [Bots] Cleanup and remove preprocessors. (#2757)
* [Bots] Cleanup and remove preprocessors.

- Removes every `#ifdef BOTS` we have and locks bots behind `Bots:AllowBots` rule.
- Bot updates are now done by default similar to regular database updates.
- Modify `CMakeLists.txt`, `.drone.yml`, and `BUILD.md` to match the removal of `EQEMU_ENABLE_BOTS`.

* Cleanup

- Add SQL for enabling bots for servers with bots.
- Add message that tells players/operators bots are disabled.

* Suggested changes.

* Bot injection stuff

* Change SQL to bot SQL.

* Tweaks

* Remove `is_bot`

* Update version.h

* Update main.cpp

* Update database.cpp

* Fix name availability crash

* Remove bots from update script

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-01-20 12:35:33 -06:00
Akkadius 1f0b2a8991 [Hotfix] Make sure we have a proper split size before assuming we can split it 2023-01-20 12:25:49 -06:00
Aeadoin a16f21d6fe [Bots] Add Support for AA bonuses that were missing. (#2764)
* [Bots] Add Support for AA bonuses that were missing.

* Fix GetFocusEffect, add virtual override to Bot to prevent using NPC
2023-01-19 22:45:09 -06:00
Chris Miles 900837f633 [Logging] Improvements to GM Say Logging (#2765) 2023-01-19 22:24:57 -06:00
Chris Miles d3e756287e [Logging] Remove function prefixes (#2766) 2023-01-19 22:24:50 -06:00
Vayle 7d0dd13d17 [Bug Fix] Add omitted function call in UCS (#2768) 2023-01-19 22:24:39 -06:00
Vayle ba5b901c16 [Optimization] Handle channel name filter checks in memory (#2767)
* Handle channel name filter checks in memory

With this commit, name filters are loaded into memory when the server loads and new channels are compared against these memory values VS hitting the database each time.

* Minor formatting tweaks
2023-01-19 21:23:11 -06:00
Akkadius 3424ae2dde [Hotfix] Fix door click crash issue if destination zone doesn't exist 2023-01-19 19:06:58 -06:00
Chris Miles 9aad8ae54c [Logging] Force crash logs to always be on regardless of setting (#2762) 2023-01-19 18:21:44 -06:00
JJ 7cd6b4b8ab [SQL] Update 2023_01_15_merc_data.sql (#2763)
Odd spacing. Someone fell asleep on the keyboard.
2023-01-19 18:20:46 -06:00
Aeadoin 090019cf83 [Bot] Restrict Bot Groups from spawning while Feigned. (#2761) 2023-01-19 16:52:20 -06:00
Chris Miles d93ea9ed86 [Zone Flags] Use database connection, not content connection (#2759) 2023-01-19 15:11:40 -06:00
Chris Miles a7b35594f8 [Fix] Zone Flags Regression (#2760) 2023-01-19 15:11:32 -06:00
Vayle 29473aa7f5 [Rules] Add rule to allow players to permanently save chat channels to database, up to a limit. (#2706)
* Initial code

* Tweak

* Rule description tweak

* More channel work

* More adjustments

* Auto-join saved permanent player channels

* Fix UCS crash if player has no channels to load from table.

* Implemented channel blocking feature

* Update database when player channel's owner or password change

* First round of requested changes.

* Logic tweak to ensure player channels are sets to permanent when appropraite

* name_filter table integration and some refactoring

* Use new `reserved_channel_names` table to block specific channel names.

* Remove some legacy channel block code

* Setup required SQL update to create  `reserved_channel_names`  table.

* Update db_update_manifest.txt

* Update db_update_manifest.txt

* Update chatchannel.cpp

* Code review

* Database to UCSDatabase

* Repository SaveChatChannel

* CurrentPlayerChannelCount repository

* Cleanup name filter

* CreateChannel

* Update websocketpp

* Increment CURRENT_BINARY_DATABASE_VERSION

Set to 9216

* Minor tweaks to blocked channel name checks & other related areas.

- Enforce blocked channel names on channel creation.
- Also enforce blocked channel names on channel join.
- Add channel status check to Debug logging.
- Minor formatting adjustments.
- Add single quotes to column name value in query.

* Minor log change

* Increment DB Version

* Formatting Tweaks

- Made formatting adjustments consistent with KinglyKrab's recommended changes.
- This compiles successfully with these changes, but unable to test the changes until this weekend.

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-01-18 22:42:09 -06:00
Aeadoin 03a27b02ff [Hotfix] Login Server failing to compile on Windows. (#2758) 2023-01-18 21:21:36 -05:00
Akkadius f9ea7ddb62 [Logging] Reset stream so we don't bold the whole line 2023-01-17 21:39:18 -06:00
Chris Miles 40d1c33351 [Logging] Logging Improvements (#2755)
* Console logging improvements

* stderr handling

* Add origination information

* Formatting

* Update zoneserver.cpp

* Update eqemu_logsys.cpp

* Remove semicolon from MySQLQuery log output

* Remove IsRfc5424LogCategory

* Remove no longer used functions

* Remove definition BUILD_LOGGING

* Deprecate categories UCSServer & WorldServer

* Deprecate UCS / World Server / Zone Server categories

* Deprecate Status, QSServer, Normal

* Update login_server.cpp

* Deprecate Emergency, Alert, Critical, Notice

* Deprecate Alert

* Fix terminal color resetting

* Deprecate headless client

* Move LogAIModerate to Detail

* Deprecate moderate logging level for detail

* Update logs.cpp

* Logs list simplify

* Update logs.cpp

* Add discord to log command

* Remove unused headers

* Windows fix

* Error in world when zones fail to load

* Show warning color properly

* Keep loginserver thread log from colliding with other logs during startup

* Deprecate Loginserver category
2023-01-17 21:18:40 -06:00
Michael Cook (mackal) ee2079ec35 [C++20] Arithmetic on different enums is deprecated (#2752)
Just do some casts and add some constants to make life easier
2023-01-17 15:21:01 -06:00
Xackery a90c760186 [Code] Removed vscode setting (#2753) 2023-01-17 15:20:36 -06:00
Alex King fbb36a3e75 [Mercs] Add Mercenary Support (#2745)
* [Mercs] Add Mercenary Support

# Notes
- Adds `--merc-tables` support to database dumper.
- Adds Mercenary-based repositories.
- Adds required SQL `2023_01_15_merc_data.sql` to insert the tables for those who don't already have them.
- Adds optional SQL `2023_01_15_merc_liaisons.sql` to change NPCs to the Mercenary Liaison class optionally.

* Inline.

* Trim tables_to_dump output

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-01-17 16:19:55 -05:00
Aeadoin bd29f1c5bb [Bug Fix] Handle_OP_AugmentItem could cause Zone crash (#2750) 2023-01-17 14:34:28 -05:00
Natedog2012 a99e0a4b2c [Bug Fix] Move EVENT_SPAWN for adding NPCs back to original spot, also add NPCs… (#2749)
* Move EVENT_SPAWN for adding NPCs back to original spot, also add NPCs to npc/mob list before parsing

* Adjust bots EVENT_SPAWN before spawn packet
2023-01-16 22:32:19 -05:00
Aeadoin be03628aa9 [Bug Fix] Fix Group XP not working. (#2748) 2023-01-16 19:10:19 -05:00
Aeadoin f1a6006ee1 [Hotfix] Resolve Zone Crashing when grouped with Bots. (#2747)
* [Hotfix] Resolve Zone Crashing when grouped with Bots.

* Fixed SpawnBotGroupByName as well.

* rename variables
2023-01-16 16:50:38 -05:00
Aeadoin dd40f2a0e6 [Bug Fix] Fix ST_TargetsTarget Spells with Restrictions (#2746) 2023-01-15 17:55:34 -05:00
Aeadoin 7fa421d848 [Bug Fix] HasPet() Zone Crashes (#2744)
* [Bug Fixes] Fix for HasPet() Zone Crashes

* HasPets const

* Remove checking This

* formatting
2023-01-15 17:16:17 -05:00
Alex King 00658632de [Cleanup] Make use of std::abs where possible. (#2739)
# Notes
- Resolves https://github.com/EQEmu/Server/issues/338
2023-01-15 17:02:13 -05:00
Alex King eed45e5250 [Quest API] Add SendPath() to Perl/Lua. (#2740)
* [Quest API] Add SendPath() to Perl/Lua.

# Perl
- Add `$client->SendPath(target)`.

# Lua
- Add `client:SendPath(target)`.

# Notes
- Allows operators to send a path to a target arbitrarily with a script.

* Update client.cpp
2023-01-15 17:02:06 -05:00
Alex King 64c62c4f0a [Feature] Add Rule to Disable Group EXP Modifier. (#2741)
# Notes
- Adds `Character:EnableGroupEXPModifier`, defaults to `true`.
- Adds `Character:GroupMemberEXPModifier`, defaults to `0.2`.
- Adds `Character:FullGroupEXPModifier`, defaults to `2.16`.
- Allows operators to enable or disable the group experience modifier based on number of members.
- Allows operators to change the modifier per member in the group between `2` and `5`.
- Allows operators to change the full group experience modifier.
2023-01-15 17:01:59 -05:00
Paul Coene ca0ae3cb98 [Rule] Add rule for NPC Level Based Buff Restrictions. (#2708)
* [Rule] Add rule for NPC Level Based Buff Restrictions.

* Erroneous whitespace

* Change prefix on log message

* Added log message when GM casts
2023-01-15 15:30:42 -06:00
Chris Miles 9e3539295b [QS] Database class name change (#2743) 2023-01-15 14:37:39 -06:00
Chris Miles 7aa25f17f6 [UCS] Database class name change (#2742) 2023-01-15 14:16:23 -06:00
Chris Miles e1c1d55ca5 [Websocket] Fix cpp20/gcc11 compile failure (#2737) 2023-01-15 11:00:24 -06:00
Aeadoin 403c54362e [Bot/Merc] Cleanup methods, and virtual overrides. (#2734)
* [Bot] Cleanup methods, and virtual overrides.

* Remove Bot::CheckAggroAmount & Bot::CheckHealAggroAmount

* formatting
2023-01-14 23:32:19 -05:00
Alex King a422484307 [Quest API] Add Client Augment Events to Perl/Lua. (#2735)
* [Quest API] Add Client Augment Events to Perl/Lua.

# Perl
- Add `EVENT_AUGMENT_INSERT_CLIENT`.
- Add `EVENT_AUGMENT_REMOVE_CLIENT`.

# Lua
- Add `event_augment_insert_client`.
- Add `event_augment_remove_client`.

# Notes
- Allows operators to use augment insert and augment remove events outside of an item script.
2023-01-14 23:23:48 -05:00
Alex King c41f375129 [Bug Fix] Fix issue with Bot::LoadAndSpawnAllZonedBots. (#2733)
* [Bug Fix] Fix issue with Bot:;LoadAndSpawnAllZonedBots.

# Notes
- Bots could spawn beyond class/global limits due to being stuck in group limbo and spawning when you enter a zone properly.

* Debug messages.

* Remove unspawned bots from group.

* Update bot.cpp

* Update bot.cpp

* Update bot.cpp

* Update bot.cpp

* >= 0
2023-01-14 23:15:26 -05:00
Alex King bd3e8b2afc [Quest API] Add Bot Methods to Lua. (#2731)
# Perl
- Minor cleanup of variable types.

 # Lua
- Add `bot:GetAugmentAt(slot_id, augment_index)`.
- Add `bot:GetItemAt(slot_id)`.
- Add `bot:SendSpellAnim(target_id, spell_id)`.
- Properly implemented `bot:GetItemIDAt(slot_id)`.

# Notes
- `bot:GetItemIDAt` existed in Lua, but didn't have a bind definition, so was non-functional.
- This makes Perl/Lua bot methods 1:1 as Perl had 75 and Lua had 72, they now both have 75.
2023-01-14 09:16:11 -06:00
Alex King f5523b40d2 [Quest API] Add CampAllBots() to Perl/Lua. (#2732)
# Perl
- Add `$client->CampAllBots()`.
- Add `$client->CampAllBots(class_id)`.

# Lua
- Add `client:CampAllBots()`.
- Add `client:CampAllBots(class_id)`.

# Notes
- Adds constants for `NO_CLASS` which is class `0` and uses `RACE_DOUG_0` for any spots that use race ID `0`.
- Cleans up magic number usage of race/class of `0`.
2023-01-14 09:14:50 -06:00
Alex King 095f4fb56c [Quest API] Add SignalAllBotsByOwnerName() to Perl/Lua. (#2730)
# Perl
- Add `$entity_list->SignalAllBotsByOwnerName(owner_name)`.

# Lua
- Add `eq.get_entity_list():SignalAllBotsByOwnerName(owner_name)`.

# Notes
- Adds a way to signal all bots by owner name instead of only character ID.
2023-01-13 04:54:20 -06:00
Alex King f8afadf0a9 [Cleanup] Remove unused basic_functions.h (#2729)
# Notes
- This file is unused and not included in any other files.
2023-01-13 04:52:32 -06:00
Alex King 9c23882d67 [Cleanup] Remove unused maxskill.h. (#2728)
# Notes
- This file is unused, noticed it when looking through source. Nothing calls this method or includes this file.
2023-01-13 04:52:08 -06:00
Aeadoin 3510ba2493 [Bug Fix] Fix Aug Clicks where item has no click effect. (#2725) 2023-01-12 12:46:42 -05:00
Chris Miles db7ab7a3ef [Diawind] Plus sign markdown fix (#2727) 2023-01-12 10:39:59 -06:00
Cole-SoD 6d13f46c40 [Bug Fix] Fix luamod GetExperienceForKill return value 2023-01-12 08:34:49 -05:00
Alex King 2f90f26351 [Quest API] Add Door Methods to Perl/Lua. (#2724)
# Perl
- Add `$door->ForceClose(sender)`.
- Add `$door->ForceClose(sender, alt_mode)`.
- Add `$door->ForceOpen(sender)`.
- Add `$door->ForceOpen(sender, alt_mode)`.
- Add `$door->GetDisableTimer()`.
- Add `$door->SetDisableTimer(disable_timer)`.

# Lua
- Add `door:GetID()`.

# Notes
- Makes Perl/Lua Door scripting capabilities 1:1.
2023-01-11 19:10:38 -05:00
Natedog2012 3341c0b7ab [Luamod] Add CalcSpellEffectValue_formula to luamods (#2721)
* [Luamod] Add CalcSpellEffectValue_formula to luamods with example code in utils/mods/spell_formula.lua

* Fix typo

* Change formula down to uint32, fix format issues and remove debug on lua file
2023-01-11 17:49:35 -06:00
Aeadoin 2587a7fed5 out of bound (#2723) 2023-01-11 17:54:42 -05:00
Aeadoin 46fa2e589e [Bug Fix] Add Complete Heal Spell back to IsCompleteHealSpell Method (#2722)
* [Bug Fix] Add Complete Heal Spell back to IsCompleteHealSpell Method

* Typo
2023-01-11 12:02:46 -05:00
Chris Miles fc020b7580 [API] Reload API (#2716)
* [API] Reload API

* Update eqemu_api_world_data_service.cpp

* Add api get_reload_types

* Update eqemu_api_world_data_service.cpp
2023-01-11 07:45:48 -06:00
Alex King 933293098b [Bug Fix] Fix Bot "Failed to Load" Messages. (#2719)
* [Bug Fix] Fix Bot "Failed to Load" Messages.

# Notes
- Bots were producing error messages for "failing to load" spells and inventory when the bot had no spells, like a Warrior, or when the bot was naked, like a newly created bot.

* Update botspellsai.cpp
2023-01-10 21:45:04 -05:00
Alex King 4df9fa89bc [Quest API] Add Bot::Camp() to Perl/Lua. (#2718)
# Perl
- Add `$bot->Camp()`.
- Add `$bot->Camp(save_to_database)`.

# Lua
- Add `bot:Camp()`.
- Add `bot:Camp(save_to_database)`.

# Notes
- Saves to database by default, overload is for edge case where a user may not want bot to save to database.
2023-01-10 21:44:55 -05:00
Alex King 09d1dc6a24 [Lua Bind] Fix INT64 Support for Windows. (#2717)
# Notes
- Temporary fix for `int64` and `uint64` support in Lua on Windows.
2023-01-10 21:28:45 -05:00
Aeadoin 8fe02b5ed1 [Bot] Add GetBotOwnerByBotID Method (#2715)
* [Bot] Add GetBotOwnerByBotID Method

* Cleanup.

* Remove EVENT_DESPAWN exports in Lua.

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-01-10 21:14:42 -05:00
Alex King 0d23ffe5e5 [Zones] Add Max Level Check to Zones. (#2714)
* [Zones] Add Max Level Check to Zones.

# Perl
- Add `$client->CanEnterZone(zone_short_name)`.
- Add `$client->CanEnterZone(zone_short_name, instance_version)`.

# Lua
- Add `client:CanEnterZone(zone_short_name)`.
- Add `client:CanEnterZone(zone_short_name, instance_version)`.

# Notes
- Allows operators to limit zones to a maximum level.
- Allows operators to see if a player can enter a zone before sending them.
- Keeps players from entering via `#peqzone` and `#zone` as well if they do not meet the requirements or are not high enough status to bypass the requirements.

* Cleanup.
2023-01-10 20:47:37 -05:00
Alex King 4c8b65ecc6 [Quest API] Add EVENT_BOT_CREATE to Perl/Lua (#2713)
* [Quest API] Add EVENT_BOT_CREATE to Perl/Lua

# Perl
- Add `EVENT_BOT_CREATE`.
- Exports `$bot_id`, `$bot_name`, `$bot_class`, `$bot_race`, and `$bot_gender`.

# Lua
- Add `event_bot_create`.
- Exports `e.bot_id`, `e.bot_name`, `e.bot_class`, `e.bot_race`, and `e.bot_gender`.
2023-01-08 21:46:40 -05:00
Alex King 0c105a2b91 [Bug Fix] Fix NPC Reference in EVENT_SPAWN (#2712)
* [Bug Fix] Fix NPC Reference in EVENT_SPAWN

# Notes
- Event parsing was too early and memory wasn't fully allocated, meaning that sometimes you could use the NPC reference and other times you couldn't.
- Most people worked around this by setting timers in `EVENT_SPAWN` then using `EVENT_TIMER` to handle the stuff they wanted to do on spawn.

# Example Code in Perl
```pl
sub EVENT_SPAWN {
	quest::shout($npc->GetCleanName() . " just spawned with an ID of " . $npc->GetID() . " and an NPC Type ID of " . $npc->GetNPCTypeID() . ".");
}```

* Update bot.cpp
2023-01-08 11:27:17 -05:00
Aeadoin 2253e43d2c [AI] Add Support to Heals to allow Trigger based spells (#2709) 2023-01-07 19:04:41 -05:00
Aeadoin 5f244c2dd2 [Bots] Fix Bot Spell Type "In Combat Buffs" (#2711) 2023-01-07 19:04:29 -05:00
Paul Coene 9e5a530f0f [Bug Fix] #npcstats command displaying incorrect faction (#2710) 2023-01-07 19:02:19 -05:00
Vayle ebf69e9b6e [Bug Fix] Resolve XP Calculation Bug introduced w/ recent Rule addition (#2703)
* [Bug Fix] Resolve XP Calculation Bug introduced w/ recent Rule addition

* Camel case.

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-01-07 12:04:52 -05:00
Alex King c1ad086eaf [Quest API] Add Despawn Events to Perl/Lua. (#2707)
# Perl
- Add `$bot->GetBotID()`.
- Add `EVENT_DESPAWN`.
- Add `EVENT_DESPAWN_ZONE`.

# Lua
- Add `bot:GetBotID()`.
- Add `event_despawn`.
- Add `event_despawn_zone`.

# Notes
- Allows operators to determine when a Bot or an NPC has been despawned via Depop.
- Bots call NPC::Depop on ^camp so we just put the code there.
- Adds the ability to get a bot's ID using their reference in case you're looping a list and need that value.
- Moves `DispatchZoneControllerEvent` from NPC to Mob so it can be used by any type.
2023-01-07 12:04:33 -05:00
Aeadoin 143c4fe6aa [Quest API] Add option to Ignore Mods to CalcEXP (#2704)
# Perl
- Add `$client->CalcEXP(consider_level, ignore_modifiers)`.

# Lua
- Add `client:CalcEXP(consider_level)`.
- Add `client:CalcEXP(consider_level, ignore_modifiers)`.

# Notes
- Allows operators to calculate experience based on consider level as well as ignore modifiers to get a baseline of experience that should be expected when killing a mob.
2023-01-05 20:38:08 -05:00
Alex King d9f437d90f [Commands] Cleanup #guild Command (#2693)
# Commands
- Adds `#guild search [Search Criteria]` sub command.

# Notes
- Allows operators to search for a guild instead of listing all guilds at once.
- Adds a method for sending guild sub commands to make code drier.
2023-01-04 16:20:43 -05:00
Aeadoin b15e73e1b2 [Bug Fix] AltCurrencySelectItemReply_Struct was not handled correctly. (#2702) 2023-01-04 14:49:43 -05:00
Vayle 6e1c4b768f [Quest API] Add GetLeader() and GetLeaderName() to Perl/Lua. (#2701)
* [Quest API] Add $raid->GetLeader() and $raid->GetLeaderName()

* Remove semicolon

* Tweaks

* Remove inline

* Add LUA compatibility

* Add GetLeaderName() to LUA

* Cast leadername to string

* Fix GetLeaderName return type

* Tweak
2023-01-03 20:17:19 -05:00
Alex King a80a6de59f [Commands] Add #findcharacter Command. (#2692)
# Commands
- Add `#findcharacter [Search Criteria]`.

# Notes
- Allows operators to search for characters by ID or a portion of their name to easily get ID/Name.
2023-01-03 14:32:21 -05:00
Alex King af4ee9f8d8 [Rules] Add LDoN Loot Count Modifier Rule (#2694)
# Notes
- Adds a rule for LDoN Adventure Loot.
2023-01-03 14:32:13 -05:00
Alex King c7dde7832d [Commands] Add #setanon Command (#2690)
* [Commands] Add #setanon Command.

# Commands
- Adds `#setanon [Anonymous Flag]`.

# Notes
- Allows operators to turn on/off a player's anonymous flag so they can view their Magelo.

* Update eq_constants.h

* Add character ID support.

* Update setanon.cpp
2023-01-03 12:06:20 -05:00
Vayle 8c939ad8da [Bug Fix] Fixed message on promote/demote permissions check. (#2700)
* [Bug Fix] Fixed message on demote permissions check.

* Included promote fix

* Formatting consistency, grammar, use constants

* Further use of constants/consistency of error/failure message colors
2023-01-02 13:08:47 -05:00
Alex King f322e85d4e [Bug Fix] Fix #door Save (#2699)
* [Bug Fix] Fix #door Create

# Notes
- Using `#door create` then `#door save` was overwriting doors instead of using the next highest ID.
- Remove the following unused commands.
```cpp
uint32 GetGuildEQID(uint32 guilddbid);
void UpdateDoorGuildID(int doorid, int guild_id);
int32 GetDoorsCount(uint32* oMaxID, const char *zone_name, int16 version);```

* Update doors.cpp

* Update doors.cpp

* Update doors.cpp
2023-01-01 22:53:34 -05:00
Alex King 7e13d07108 [Bug Fix] EVENT_ENTER_AREA/EVENT_LEAVE_AREA. (#2698)
Should be EventPlayer, not EventNPC.
2023-01-01 19:43:42 -06:00
Alex King 3e4231c662 [Quest API] Cleanup Proximity Events (#2697)
* [Quest API] Cleanup Proximity Events

# Perl
- Add `$area_id` export to EVENT_ENTER_AREA.
- Add `$area_type` export to EVENT_ENTER_AREA.
- Add `$area_id` export to EVENT_LEAVE_AREA.
- Add `$area_type` export to EVENT_LEAVE_AREA.

# Notes
- This is so Spire will parse these events properly.

* Update entity.cpp

* Update entity.cpp

* Update entity.cpp

* Update entity.cpp
2023-01-01 18:07:14 -06:00
Alex King 039d4f09e3 [Hotfix] Lua Parser Needs Lua_ItemInst (#2696) 2023-01-01 16:00:58 -06:00
Alex King c544221838 [Bug Fix] Fix #zone 0. (#2691)
# Notes
- `#zone 0` was used to send you to safe coordinates, this has been broken for a while now.
2023-01-01 13:55:17 -05:00
Alex King 16103b510d [Hotfix] Blocks are nested too deeply. (#2689) 2023-01-01 12:40:31 -05:00
Alex King 0b8b363c13 [Quest API] Add DoesAugmentFit() to Perl/Lua. (#2688)
# Perl
- Add `quest::does_augment_fit(item, augment_id)`.

# Lua
- Add `eq.does_augment_fit(item, augment_id)`.

# Notes
- Returns the augment slot index where the augment fits within the item instance provided, returns `-1` if it doesn't fit or has no open slot to fit in.
2023-01-01 12:20:07 -05:00
Alex King 1531650b3a [Quest API] Add Augment Slot Type/Visible to GetItemStat (#2686)
* [Quest API] Add Augment Slot Type/Visible to GetItemStat

# Notes
- Adds the ability to get an item's augment slot types and augment slot visibility information.

* const
2023-01-01 11:35:15 -05:00
Alex King 3a4ba6f422 [Quest API] Add DoAugmentSlotsMatch() to Perl/Lua. (#2687)
# Perl
- Add `quest::do_augment_slots_match(item_one, item_two)`.

# Lua
- Add `eq.do_augment_slots_match(item_one, item_two)`.

# Notes
- Allows operators to see if augments slots across two items match for something like moving augments from one item to another.
2023-01-01 11:25:37 -05:00
Alex King 501ea4b736 [Quest API] Add Charges/Augment/Attuned Support to Varlink. (#2685)
# Perl
- Add `quest::varlink(item_id, charges)`.
- Add `quest::varlink(item_id, charges, aug1)`.
- Add `quest::varlink(item_id, charges, aug1, aug2)`.
- Add `quest::varlink(item_id, charges, aug1, aug2, aug3)`.
- Add `quest::varlink(item_id, charges, aug1, aug2, aug3, aug4)`.
- Add `quest::varlink(item_id, charges, aug1, aug2, aug3, aug4, aug5)`.
- Add `quest::varlink(item_id, charges, aug1, aug2, aug3, aug4, aug5, aug6)`.
- Add `quest::varlink(item_id, charges, aug1, aug2, aug3, aug4, aug5, aug6, attuned)`.

# Lua
- Add `eq.item_link(item_id, charges)`.
- Add `eq.item_link(item_id, charges, aug1)`.
- Add `eq.item_link(item_id, charges, aug1, aug2)`.
- Add `eq.item_link(item_id, charges, aug1, aug2, aug3)`.
- Add `eq.item_link(item_id, charges, aug1, aug2, aug3, aug4)`.
- Add `eq.item_link(item_id, charges, aug1, aug2, aug3, aug4, aug5)`.
- Add `eq.item_link(item_id, charges, aug1, aug2, aug3, aug4, aug5, aug6)`.
- Add `eq.item_link(item_id, charges, aug1, aug2, aug3, aug4, aug5, aug6, attuned)`.

# Notes
- Allows operators to link items with specific charges, augments, and attuned flag.
- Gives much more versatility to the varlink/item_link methods.
2023-01-01 10:49:07 -05:00
Aeadoin aeda7127ec [Git] Add Clangd Generated Files to .gitignore (#2684) 2022-12-31 12:24:13 -05:00
Aeadoin 9c3c5b5230 [Experience] Change Exp Calculations to be 64 bit where needed. (#2677)
* [Experience] Change Exp Calculations to be 64 bit where needed.

* Fix lua values

* Formatting
2022-12-30 22:03:30 -05:00
Aeadoin f962466573 [Hotfix] Corrected misnamed Database Query file for Experience Toggle (#2683)
* [Hotfix] Correct misnamed DB script

* [Hotfix] Fix misnamed DB file
2022-12-30 21:50:35 -05:00
Alex King a6fa6084fa [Feature] Add Experience Gain Toggle. (#2676)
* [Feature] Add Experience Gain Toggle.

# Perl
- Add `$client->IsEXPEnabled()`.
- Add `$client->SetEXPEnabled(is_exp_enabled)`.

# Lua
- Add `client:IsEXPEnabled()`.
- Add `client:SetEXPEnabled(is_exp_enabled)`.

# Commands
- Add `#exptoggle [Toggle] - Toggle your or your target's experience gain.`.

# Notes
- Allows operators to turn on/off a player's experience gain individually without changing their rule values.
- The command allows operators to give players access to the command to disable their own experience gain.
2022-12-30 17:30:23 -05:00
Aeadoin 0c9c78fbab [Bot Commands] Toggle Enforce Spell Settings (#2682)
* [Bot Commands] Toggle enforcespellsettings

* Cleanup

* Update bot_command.cpp

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2022-12-30 17:18:05 -05:00
Aeadoin 8fc665a3c1 [Bug Fix] NPC Constructor was passing hp_regen_per_second out of order to Mob(). (#2681) 2022-12-29 15:29:52 -05:00
Alex King 7e7485be77 [Quest API] Add BuffCount() Overloads to Perl/Lua. (#2679)
# Perl
- Add `$mob->BuffCount(is_beneficial)`.
- Add `$mob->BuffCount(is_beneficial, is_detrimental)`.

# Lua
- Add `mob:BuffCount(is_beneficial)`.
- Add `mob:BuffCount(is_beneficial, is_detrimental)`.

 # Notes
- Allows operators to count only beneficial or detrimental buffs a mob has instead of always counting all buffs.
2022-12-29 11:58:38 -05:00
Alex King a590ea1d52 [Feature] Add "Keeps Sold Items" Flag to NPCs (#2671)
# Perl
- Add `$npc->GetKeepsSoldItems()`.
- Add `$npc->SetKeepsSoldItems(keeps_sold_items)`.

# Lua
- Add `npc:GetKeepsSoldItems()`.
- Add `npc:SetKeepsSoldItems(keeps_sold_items)`.

# Notes
- Allows operators to keep specific NPCs from keeping items sold to them.
- Keeps NPCs from being cluttered with stuff like Cloth Caps, Bone Chips, etc.
2022-12-25 16:36:20 -05:00
Alex King 2ed73199bf [Quest API] Add IsAttackAllowed() to Perl/Lua. (#2672)
# Perl
- Add `$mob->IsAttackAllowed(target)`.
- Add `$mob->IsAttackAllowed(target, is_spell_attack)`.

# Lua
- Add `mob:IsAttackAllowed(target)`.

# Notes
- Lua had `mob:IsAttackAllowed(target, is_spell_attack)` but not the other overload.
- Perl had neither.
2022-12-25 16:18:00 -05:00
Alex King d1430f6834 [Quest API] Add IsAttackAllowed() to Perl/Lua. (#2672)
# Perl
- Add `$mob->IsAttackAllowed(target)`.
- Add `$mob->IsAttackAllowed(target, is_spell_attack)`.

# Lua
- Add `mob:IsAttackAllowed(target)`.

# Notes
- Lua had `mob:IsAttackAllowed(target, is_spell_attack)` but not the other overload.
- Perl had neither.
2022-12-25 16:17:46 -05:00
Aeadoin 860b545fe3 [Rules] Change TradeskillUp Rules to be Floats (#2674)
* [Rules] Change TradeskillUp Rules to be Floats

* update rule values so it's obvious they are floats.
2022-12-25 16:09:16 -05:00
Vayle 8219cc9ea0 [Rules] Rule to allow cap on % XP gain per kill (#2667)
* [Rules] Add rule to limit single kill xp gain

Adds a rule to allow server operators to restrict XP gain/kill to a specified % of their current level.

* Logic correction

* Commenting

* Logic tweaks

* Rule description update

* Logic adjustment

Changed to allow xp cap > 100% and -1 = disabled

* Formatting

* Removed extra space

* Formatting

Renamed rule to be more clear.
Updated rule description.
Minor formatting tweaks.
Implemented use of descriptive bools.

* Data type adjustment

* Removed Bools

* Update exp.cpp

* Update exp.cpp

* Update exp.cpp

* Update exp.cpp

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2022-12-25 15:59:05 -05:00
Alex King d7ae3d5c6d [Quest API] Add GetAugmentIDsBySlotID() to Perl/Lua. (#2673)
* [Quest API] Add GetAugmentIDsBySlotID() to Perl/Lua.

# Perl
- Add `$client->GetAugmentIDsBySlotID(slot_id)`.
- Add `$inventory->GetAugmentIDsBySlotID(slot_id)`.

# Lua
- Add `client:GetAugmentIDsBySlotID(slot_id)`.
- Add `inventory:GetAugmentIDsBySlotID(slot_id)`.

# Notes
- Allows operators to get a list of augments from a specific slot instead of having to build a plugin or something to do it.
- Fix issue with Lua tables starting at index `1` versus index `0`, so you lost the first value of the table due to this.

* Update inventory_profile.cpp
2022-12-25 15:14:54 -05:00
Aeadoin 6229852331 [Commands] #reload level_mods could cause Non-Booted zones to crash. (#2670) 2022-12-24 12:50:04 -05:00
Aeadoin 5bb27dd4c0 [Commands] Fix Flymode Command Help Prompt (#2669) 2022-12-22 19:37:54 -05:00
Aeadoin 2f9a6daab5 [Client] Remove unimplemented Client Insight Method. (#2663)
* [Cleanup] Remove unused Insight Method, and cleanup Magic Numbers

* change emu->NPC back to 0, not Doug
2022-12-21 18:41:56 -05:00
Vayle d5aecb228a [Rules] Add Backstab Rules (#2666)
* [Rules] Add backstab rules

Add rules to disable elemental and bane damage on backstab.

* Update special_attacks.cpp

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2022-12-21 18:41:25 -05:00
Aeadoin e811cb1e85 [Hotfox] Compiling fails on FMT 9.1 with Bots (#2665) 2022-12-21 16:20:47 -05:00
Chris Miles c236c57a2c [C++20] Enable C++20 + Fixes + FMT 9.1 (#2664)
* [CPP] Enable and build compliance with cpp20

* Windows build fix

* bump fmt version

* Updated fmt to 9.1, updated cmake minimum and verified preprocessor stuff works.

* Missing :

* Fix warning: top-level comma expression in array subscript is deprecated

* Fix warning: top-level comma expression in array subscript is deprecated

Co-authored-by: KimLS <KimLS@peqtgc.com>
2022-12-20 21:52:36 -06:00
Chris Miles db12c069ef [Luabind] Silence deprecation warning (#2657)
* [Luabind] Silence deprecation warning

* [libuv] Bump to v1.44.2 from v1.26.0

* Revert "[libuv] Bump to v1.44.2 from v1.26.0"

This reverts commit c794735d16.

* Update libuv
2022-12-20 13:13:04 -06:00
Chris Miles 4ea38bf896 [libuv] Bump to v1.44.2 from v1.26.0 (#2658) 2022-12-20 13:12:55 -06:00
Chris Miles 0d1fa9e96e [Repositories] Add Cereal support to repository generator (#2660)
* [Repositories] Add Cereal support to repository generator

* Update base_repository.template
2022-12-20 13:12:44 -06:00
Chris Miles 51c62d3b3e [Cereal] Bump to v1.3.2 from v1.2.2 (#2654) 2022-12-20 13:12:35 -06:00
Aeadoin 900e1aecf6 [Cleanup] Cleanup magic numbers (#2662)
* [Cleanup] Cleanup magic numbers

* renamed RACE_NODE
2022-12-20 11:31:42 -05:00
Aeadoin ed6194ad19 [Aggro] Cleanup Mob::CombatRange (#2652)
* [Aggro] Cleanup Mob::CombatRange

* Change to Race_ constants
2022-12-19 21:08:50 -06:00
Michael e6f58382de [Rule] Add ManaOnDeath and EndurOnDeath (#2661)
* [Rule] Add ManaOnDeath and EndurOnDeath
This rule allows death to fully fill Mana or Endurance.

* Updates rules to live-like

* Adjust rule names to be more descriptive of their intent, remove else cases

Co-authored-by: Akkadius <akkadius1@gmail.com>
2022-12-19 21:04:03 -06:00
Aeadoin 083d44d4fe [Bug Fix] Resolve Warning due to Virtual Mob Method GetInv() (#2650) 2022-12-19 16:51:05 -05:00
Aeadoin f12090d109 [Bots] Cleanup various Bot Spell Focus methods (#2649)
* [Bots] Cleanup GetFocusEffect & GetActSpellDamage

* Remove unused CalcBotFocusEffect

* Cleanup unneeded derived class methods

* compile error
2022-12-16 17:21:37 -05:00
Paul Coene f188c1394a Add ground spawns to discovered items feature. (#2648)
* Add ground spawns to discovered items feature.

* Add {}
2022-12-16 16:11:58 -05:00
Chris Miles d9e5056657 [Repositories] Migrate LoadPerlEventExportSettings to use repositories (#2637)
* [Repositories] Migrate LoadPerlEventExportSettings to use repositories

* Update quest_parser_collection.cpp
2022-12-14 22:26:14 -06:00
Chris Miles dce5f03e74 [Commands] Nested Command Aliases (#2636) 2022-12-14 22:26:05 -06:00
Chris Miles 6ddd5db480 [Quests] Improve Quest Error Handling - Add back in process based syntax validation (#2646) 2022-12-14 23:20:00 -05:00
nytmyr 1338d21823 [Bug Fix] Fix trading with bots when in an illusion. (#2645)
Trade check was not checking GetBaseRace and would fail if the bot's illusion couldn't equip the item.

Co-authored-by: toxin06 <53322305+toxin06@users.noreply.github.com>
2022-12-14 21:32:34 -05:00
Aeadoin 0fd4d82553 [Bots] Resolve incorrect values on Bot Creation (#2644) 2022-12-14 18:03:56 -05:00
Alex King bca04b969f [Bug Fix] Remove Unnecessary Attack Log (#2643)
# Notes
- This log fires every time for no reason.
2022-12-14 17:31:28 -05:00
Alex King 89ba1270d9 [Bug Fix] Remove unnecessary log messages. (#2642) 2022-12-14 17:31:21 -05:00
Alex King 337dc54eb9 [Bug Fix] Allow High Level Spells to be Unmemorized. (#2641)
* [Bug Fix] Allow High Level Spells to be Unmemorized.

# Notes
- If you deleveled below a spell's level, you couldn't unmemorize it, this fixes that.

* Update client_process.cpp
2022-12-14 17:18:51 -05:00
nytmyr bc277ac296 [Commands] Add max_hp back to #modifynpcstat command. (#2638)
Restores max_hp back to the #modifynpcstat command to adjust the target's HPs.

Co-authored-by: toxin06 <53322305+toxin06@users.noreply.github.com>
2022-12-13 11:41:10 -05:00
nytmyr 7189bab848 [Bots] Fix Gender not saving as GetBaseGender on BotSave (#2639)
Bots were not saving their Base Gender when saving. This could result in bots with illusions saving as gender 2 and becoming a male human model upon illusion fade.

Co-authored-by: toxin06 <53322305+toxin06@users.noreply.github.com>
2022-12-13 11:40:59 -05:00
Chris Miles c3cb0b8cdf [Quests] Improve Quest Error Handling (#2635)
* Improve Quest Error handling

* Update embperl.cpp

* Bench test (temp)

* Swap log category for benchmark

* Swap external process invocation for native Perl eval throw
2022-12-12 19:21:33 -06:00
Aeadoin ae4908b40c [Bots] Add Quest API Methods (#2631)
* [Bots] Add Quest API Methods

* Cleanup unneeded methods.
2022-12-12 17:25:36 -06:00
Aeadoin 13a3afbfac [Bots] Add Event_Trade Support for ^inventorygive Command (#2628) 2022-12-11 16:25:47 -05:00
Chris Miles f5126222c2 [Process] Process Execution Refactor (#2632)
* Swap execute output method

* Create "Process" class and move random string to Strings

* test

* Tweaks
2022-12-11 14:08:55 -05:00
Alex King 70719852d6 [Quest API] Fix Lua Door/Object Create Methods. (#2633)
# Notes
- Lua door/object create methods were `void` type instead of `uint16`, so you couldn't get the entity ID of the door you created.
- Converted Perl's door/object create methods to return `uint16` instead of `int` as well.
2022-12-11 14:08:43 -05:00
Alex King 46f993ef71 [Quest API] Add EVENT_GM_COMMAND to Perl/Lua. (#2634)
# Perl
- Add `EVENT_GM_COMMAND`, exports `$message`.

# Lua
- Add `event_gm_command`, exports `e.message`.

# Notes
- Only parses with real GM commands such as `#reload quest`.
2022-12-11 14:08:38 -05:00
Alex King 20efa83f73 [Bug Fix] Fix possible crash in ProcessSpecialAbilities. (#2630)
* [Bug Fix] Fix possible crash in ProcessSpecialAbilities.

# Notes
- Passing an invalid special ability along such as `4,1,,-1,100` currently causes a crash since every `,` assumes it's followed by a number.
- Fixed by making sure first and second parameters are numbers and then when looping additional parameters we also check if they are numbers.

* Update mob.cpp
2022-12-11 09:07:06 -05:00
Alex King d3fac8a0cb [Quest API] Add EVENT_LEVEL_DOWN to Perl/Lua. (#2620)
* [Quest API] Add EVENT_LEVEL_DOWN to Perl/Lua.

# Perl
- Add `EVENT_LEVEL_DOWN`, exports `$levels_lost`.
- Add `$levels_gained` export to `EVENT_LEVEL_UP`.

# Lua
- Add `event_level_down`, exports `e.levels_lost`.
- Add `e.levels_gained` export to `event_level_up`.

# Notes
- Allows operators to perform actions on level down.
- Allows operators to tell how many levels were lost or gained in case people are gaining/losing multiple levels and they want to keep track or use this as a mechanic in their code somewhere.

* Update exp.cpp

* Update embparser.cpp
2022-12-10 19:22:31 -05:00
Alex King 8c707f9fe5 [Commands] Add #suspendmulti Command. (#2619)
* [Commands] Add #suspendmulti Command.

# Notes
- Allows operators to suspend multiple people at once in case they have  a player who is boxing and want to suspend them all at once.

* To lower.

* Update command.cpp

* Update suspendmulti.cpp

* Create suspendmulti.cpp
2022-12-10 18:07:33 -06:00
Aeadoin c8218574cc [Logging] More AI Logging Cleanup (#2616)
* [Logging] Additional AI Cleanup

* More cleanup/formatting fixes

* Typo
2022-12-10 17:36:40 -06:00
Chris Miles 3dfeda9cea [Tasks] Crash fix with data input sanitization (#2629) 2022-12-10 18:31:18 -05:00
Alex King 1d06a4117a [Quest API] Add DoAnim Overloads to Perl/Lua. (#2627)
# Perl
- Add `$mob->DoAnim(animation_id, animation_speed, ackreq)`.
- Add `$mob->DoAnim(animation_id, animation_speed, ackreq, filter)`.
- Add `quest::doanim(animation_id, animation_speed)`.
- Add `quest::doanim(animation_id, animation_speed, ackreq)`.
- Add `quest::doanim(animation_id, animation_speed, ackreq, filter)`.

# Lua
- Add `eq.do_anim(animation_id)`.
- Add `eq.do_anim(animation_id, animation_speed)`.
- Add `eq.do_anim(animation_id, animation_speed, ackreq)`.
- Add `eq.do_anim(animation_id, animation_speed, ackreq, filter)`.

# Notes
- Adds overloads and cleans up spots where `animation_speed` was named `type` erroneously.
2022-12-10 17:30:40 -06:00
Alex King b1c4e7c23f [Commands] Cleanup #rules Command. (#2593)
* [Commands] Cleanup #rules Command.

- Cleanup messages and logic.
- Rewrite all rules logic to use `std::string` and repositories.

* References

* Update rules.cpp

* Strings::Equal and Strings::EqualFold.

* Cleanup.

* Update rulesys.cpp

* Update rulesys.cpp

Co-authored-by: Akkadius <akkadius1@gmail.com>
2022-12-10 18:08:55 -05:00
Michael 3872555332 [Rules] Rule Gate Pet Zoning (#2625)
Allows preventing pet zoning from happening for more classic servers.
2022-12-07 18:50:02 -05:00
Aeadoin 86af0f0759 [Bots] Cleanup Fast Rest Regen (#2626) 2022-12-07 17:21:50 -05:00
Alex King 88e8b25fa1 [Bug Fix] Data Bucket Permanent Duration String (#2624)
# Notes
- "F" or "f" weren't handled in this method, so they weren't working properly.
- Most people don't provide this parameter when setting a permanent data bucket, so wasn't noticed in testing.
2022-12-06 09:28:38 -05:00
Alex King f7fb1c9fe1 [Quest API] Add MaxSkills() to Perl/Lua. (#2621)
* [Quest API] Add MaxSkills() to Perl/Lua.

# Perl
- Add `$client->MaxSkills()`.

# Lua
- Add `client:MaxSkills()`.

# Notes
- Allows operators an easy short hand for maxing a player's skills for their level without needing to do all the looping and stuff on their own.

* Cleanup.

* Only set if it's higher than skill level player has.

* Add constant.
2022-12-06 08:46:21 -05:00
Alex King 91ea6462f2 [Quest API] Add CopyHateList() to Perl/Lua. (#2623)
* [Quest API] Add CopyHateList() to Perl/Lua.

# Perl
- Add `$mob->CopyHateList(to_mob)`.

# Lua
- Add `mob:CopyHateList(to_mob)`.

# Notes
- Allows operators to easily copy and entire hatelist from one mob to another.

* Update mob.cpp
2022-12-06 08:38:51 -05:00
Alex King 3774dc50d9 [Quest API] Add Fling Overloads to Perl/Lua. (#2622)
* [Quest API] Add Fling Overload to Perl/Lua.

# Perl
- Add `$client->Fling(target_x, target_y, target_z)`.
- Add `$client->Fling(target_x, target_y, target_z, ignore_los)`.
- Add `$client->Fling(target_x, target_y, target_z, ignore_los, clipping)`.

# Lua
- Add `client:Fling(target_x, target_y, target_z)`.
- Add `client:Fling(target_x, target_y, target_z, ignore_los)`.
- Add `client:Fling(target_x, target_y, target_z, ignore_los, clipping)`.

# Notes
- These overloads calculate the speed based on the distance automatically.

* Update client.cpp

* Update client.cpp

* Update client.cpp

* clip_through_walls
2022-12-06 08:38:33 -05:00
Alex King 0455868f66 [Commands] Cleanup #scale Command. (#2591)
* [Commands] Cleanup #scale Command.

- Cleanup messages and logic.

* One line message.
2022-12-04 23:17:56 -06:00
Alex King ef42e00df8 [Bug Fix] Fix case-sensitivity in #suspend Command. (#2613)
* [Bug Fix] Fix case-sensitivity in #suspend Command.

# Notes
- This command required you to properly send the name as it appears in the database otherwise it wouldn't kick the player.
- Solution is to `Strings::ToLower` then `Strings::UcFirst`.

* To lower.
2022-12-04 23:17:17 -06:00
Alex King a9c161011e [Hot Fix] Fix Bot Data Repository (#2618)
* [Hot Fix] Fix Bot Data Repository

Query was in wrong order.

* Update base_repository.template
2022-12-04 22:35:17 -05:00
Alex King 423e6ae751 [Bots] Convert Load, Save, SaveNew, and Delete to Repositories. (#2614)
* [Bots] Convert Load, Save, SaveNew, and Delete to Repositories.

# Notes
- General code cleanup, as manually adding to these queries doesn't scale very well.

* FindOne.

* Update base_bot_data_repository.h

* Update template.
2022-12-04 18:22:35 -05:00
Alex King 9a35cacf27 [Quest API] Add EVENT_PAYLOAD to Perl/Lua. (#2611)
* [Quest API] Add EVENT_PAYLOAD to Perl/Lua.

# Perl
- Add `$bot->SendPayload(payload_id)`.
- Add `$bot->SendPayload(payload_id, payload_value)`.
- Add `$client->SendPayload(payload_id)`.
- Add `$client->SendPayload(payload_id, payload_value)`.
- Add `$mob->SendPayload(payload_id)`.
- Add `$mob->SendPayload(payload_id, payload_value)`.
- Add `$npc->SendPayload(payload_id)`.
- Add `$npc->SendPayload(payload_id, payload_value)`.

# Lua
- Add `bot:SendPayload(payload_id)`.
- Add `bot:SendPayload(payload_id, payload_value)`.
- Add `client:SendPayload(payload_id)`.
- Add `client:SendPayload(payload_id, payload_value)`.
- Add `mob:SendPayload(payload_id)`.
- Add `mob:SendPayload(payload_id, payload_value)`.
- Add `npc:SendPayload(payload_id)`.
- Add `npc:SendPayload(payload_id, payload_value)`.

# Notes
- Allows operators to send payload IDs with a payload value, the value can be a comma separated value, JSON, etc.
- The idea is to allow a more configurable event for operators to send information to/from entities.

* Cleanup parser events.
2022-12-04 17:47:49 -05:00
Alex King e1d5274bd5 [Quest API] Cleanup Signal Methods in Perl/Lua. (#2604)
# Perl
- Add `$client->Signal(signal_id)`.

# Notes
- Some places still had signal as `uint32` versus `int`.
- Rename `signal` to `signal_id` where valid so we don't have conflicts.
2022-12-04 17:40:48 -05:00
Aeadoin ede3ed4df3 [HotFix] Resolve issue with Bot Casting after zoning. (#2617) 2022-12-04 15:43:38 -06:00
Aeadoin 318e487515 [Logging] Cleanup AI Logging Events (#2615) 2022-12-04 14:22:53 -05:00
Aeadoin 7e0fe93039 [Bots] Save Bot Toggle Archer Setting between Loads. (#2612)
* [Bots] Save Bot Toggle Archer Setting between Loads.

* [Bots] Save Bot Toggle Archer Setting between Loads.

* Typo
2022-12-04 13:23:25 -05:00
Alex King 7abc084cd1 [Quest API] Add Entity Variable Methods to Perl/Lua. (#2609)
* [Quest API] Add Entity Variable Methods to Perl/Lua.

# Perl
- Add `$mob->ClearEntityVariables()`.
- Add `$mob->DeleteEntityVariable(variable_name)`.
- Add `$object->ClearEntityVariables()`.
- Add `$object->DeleteEntityVariable(variable_name)`.

# Lua
- Add `mob:ClearEntityVariables()`.
- Add `mob:DeleteEntityVariable(variable_name)`.
- Add `object:ClearEntityVariables()`.
- Add `object:DeleteEntityVariable(variable_name)`.

# Notes
- Allows operators to clear all entity variables or delete one by name, previously you just had to set to an empty value to clear after being set.

* Cleanup.
2022-12-04 12:18:27 -05:00
Alex King 5d5c2a4194 [Quest API] Add GetGuildPublicNote() to Perl/Lua. (#2608)
# Perl
- Add `$client->GetGuildPublicNote()`.

# Lua
- Add `client:GetGuildPublicNote()`.

# Notes
- Allows operators to grab a player's public note in there guild if they wanted to.
2022-12-04 12:18:18 -05:00
Aeadoin 80fffb57b1 [Bots] Cleanup Spell Settings Commands (#2607)
* [Bots] Cleanup Spell Settings Commands

* Update Bot DB version

* typo
2022-12-03 19:49:45 -05:00
Aeadoin 61b91d92c3 [Bots] Expanded Bot Spell Settings List. (#2606)
* [Bots] Expanded Bot Spell List Settings

* [Bots] Expanded Bot Spell List Settings

* Fixes/formatting

* typo

* Formatting & update SpellInfo Command

* Spelling

* Typo
2022-12-03 12:15:57 -05:00
Aeadoin 35d22913b9 [Bug Fix] Fix Bot ^spellsettingsadd command (#2603) 2022-12-01 14:25:23 -05:00
Alex King dbba22b153 [Bug Fix] Add SE_MakeDrunk to avoid error message. (#2601)
* [Bug Fix] Add SE_MakeDrunk to avoid error message.

Currently sends error message about unknown spell effect ID.

* Message types cleanup.

* Update spdat.cpp
2022-11-30 22:09:59 -05:00
JJ de7a632d67 [SQL] Bugs Table Migration (#2559) (#2602)
Copies bugs from `bugs` to `bug_reports`
2022-11-30 22:09:49 -05:00
Alex King 85ae36ede5 [Bug Fix] Fix Instance Repository (#2598)
Instance code used to use a `REPLACE INTO`, add an extended repository method to do this so we're not getting `DUPLICATE` errors.
2022-11-30 21:31:39 -05:00
Alex King ecc34940b4 [Bug Fix] Fix IDFile Crash with spaces or invalid data. (#2597)
* [Bug Fix] Fix IDFile Crash with spaces or invalid data.

* Update mob_appearance.cpp
2022-11-30 21:31:28 -05:00
Alex King a9cfacf54b [Quest API] Add WearChange Overloads to Perl/Lua. (#2600)
* [Quest API] Add WearChange Overloads to Perl/Lua.

# Perl
- Add `$mob->WearChange(slot, texture)`.

# Lua
- Add `mob:WearChange(slot, texture)`.
- Add `mob:WearChange(slot, texture, color, heros_forge_model)`.

# Notes
- These overloads allow you to not have to send color.
- Lua didn't have an overload with Hero's Forge Model.

* Fix variable types.
2022-11-30 21:31:22 -05:00
Aeadoin e7704f00f3 [Bots] Melee Bot Support for Spell Settings Commands (#2599) 2022-11-30 19:35:17 -05:00
Aeadoin 639f8e184a [Fix] Clamp Item Ldon Sell Back Rates. (#2592)
* [Fix] Clamp ldonsellbackrates to prevent abuse.

* Change cast to uint32

* Fix issues with Clamp not functioning correctly.

* Fix missed clamp

* change price is unsigned int to prevent potential overflow

* Formatting

* Formatting fix

* Update client_packet.cpp

* Update client_packet.cpp

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2022-11-30 18:02:36 -05:00
Michael 1d302f512e [Quest API] Adjustment to depop_all function. (#2595)
* [Quest API] Adjustment to depop_all function.

Adjustment to depop_all function to no longer require an owner under all conditions (allows use inside encounters)

* More simplification

* Update questmgr.cpp

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2022-11-29 23:57:19 -05:00
Michael 02c0a8fa7f [Command] Adding movespeed to #showstats output (#2596) 2022-11-29 23:51:33 -05:00
Aeadoin e928754df3 [Bot] Add Buff support for Bards under AI_IdleCastChecks (#2590)
* [Bot] Add Buff support for Bards under AI_IdleCastChecks

* Add InCombatBuffSong to Idle Bard cast Logic

* Fixes a number of Buffs that would fail to land on the Bot, causing casting loops

* Accidently removed If Statement added back.

* Update bot.cpp

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2022-11-28 16:35:51 -05:00
Alex King 200c6cccaf [Bots] Optimize inventory loading. (#2588)
* [Bots] Optimize inventory loading.

# Notes
- Bots previously were running 23 individual queries to load their inventory versus grabbing their inventory all at once and referencing it in memory.

* Typo.

* Update bot_database.cpp

* Update bot_database.cpp

* Update bot.cpp
2022-11-27 19:07:24 -05:00
Alex King d6db35b84e [Commands] Cleanup #gearup Command. (#2589)
# Notes
- Cleanup messages and logic.
- Add support for gearing up target client (with #gm on) and/or target bots.
2022-11-27 18:56:40 -05:00
Alex King d0e7e8c4c4 [Quest API] Add Group/Raid Overloads to Perl/Lua. (#2587)
# Perl
- Add `$group->IsGroupMember(name)`.
- Add `$group->IsLeader(name)`.
- Add `$raid->IsRaidMember(c)`.
- Add `$raid->IsGroupLeader(c)`.

# Lua
- Add `group:IsGroupMember(name)`.
- Add `group:IsLeader(name)`.
- Add `raid:IsGroupLeader(client)`.
- Add `raid:IsLeader(client)`.
- Add `raid:IsRaidMember(client)`.

# Notes
- Adds overloads to these methods allowing operators to get by name or reference.
2022-11-27 15:57:01 -05:00
Aeadoin 29247a0f45 [Bot] Add Support for Bots to receive Auras, and other AoE Buffs. (#2586) 2022-11-27 15:49:38 -05:00
Alex King 2d364e2fd1 [Bots] Add Bot-specific Spell Settings. (#2553)
* [Bots] Add Bot-specific Spell Settings.

# Notes
- Allows players to set `priority`, `min_level`, `max_level`, `min_hp`, `max_hp`, and `is_enabled` settings per spell based on targeted bot.
- Lets players disable spells they don't want their bots casting or change the criteria they cast them at if they want.

* Update botspellsai.cpp

* Update 2022_11_19_bot_spell_settings.sql

* Typo.

* Update botspellsai.cpp

* Cleanup and add Reload Methods to Perl/Lua.
2022-11-27 14:46:36 -05:00
Aeadoin f6c5560e9c [Bot] Update Bot Logic to ignore ST_TargetsTarget when buffing (#2584)
* [Bot] Update Bot Logic to ignore ST_TargetsTarget when buffing

* Fix Not Operator

* Update botspellsai.cpp

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2022-11-27 14:39:34 -05:00
Alex King fb4d4e1382 [Quest API] Fix Perl EVENT_HP double parsing in Spire. (#2585)
This condition caused the variables to show twice due to the way Sprie parses the source code, and the condition itself is unnecessary since we can just use an inline ternary in this case.
2022-11-27 14:27:27 -05:00
Aeadoin 9a7770377d [Bots] Move Bot Spell Loading process to constructor from calcbotstats() (#2583) 2022-11-27 11:41:10 -05:00
Alex King 15b2baa663 [Commands] Cleanup #npcedit Command. (#2582)
* [Commands] Cleanup #npcedit Command.

- Make use of repositories and cleanup logic.

* Remove accidental change.
2022-11-27 11:37:22 -05:00
Alex King 253f4c07e0 [Commands] Cleanup #chat Command. (#2581)
- Cleanup messages and logic.
2022-11-26 19:28:28 -05:00
Alex King f7ae5850f0 [Quest API] Add Time String to Seconds Method to Perl/Lua. (#2580)
* [Quest API] Add Time String to Seconds Method to Perl/Lua.

# Perl
- Add `quest::timetoseconds(time_string)`.

# Lua
- Add `eq.time_to_seconds(time_string)`.

# Notes
- Allows operators to use this method in place of hardcoded values like `3600`.

* Remove unused method.
2022-11-26 19:28:21 -05:00
Aeadoin ea9a02bec4 [Bots] Add Rule Allowing Bots to Equip Any Race Items (#2578)
* [Bots] Add Rule AllowBotEquipAnyRaceGear

* Fix formatting

* Update item_instance.cpp

* Update bot.cpp

* Update item_data.h

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2022-11-26 17:39:31 -05:00
Alex King 31d57342e1 [Quest API] Add Entity Variable Methods to Perl/Lua. (#2579)
* [Quest API] Add Entity Variable Methods to Perl/Lua.

# Perl
- Add `$mob->GetEntityVariables()`.
- Add `$object->GetEntityVariables()`.

# Lua
- Add `mob:GetEntityVariables()`.
- Add `object:GetEntityVariables()`.

# Notes
- Convert all overloads and methods to use `std::string` for entity variables.
- Allows operators to get a list of a Mob's entity variables.

* Update loottables.cpp
2022-11-26 16:24:01 -05:00
Alex King 290ebf3b26 [Quest API] Add GetBotListByClientName() Class Overload to Perl/Lua. (#2577)
# Perl
- Add `$entity_list->GetBotListByClientName(client_name, class_id)`.

# Lua
- Add `eq.get_entity_list():GetBotListByClientName(client_name, class_id)`.

# Notes
- Adds overload to get bots by client name and class ID.
2022-11-26 15:47:45 -05:00
Alex King 25f8ee2084 [Hotfix] Instances Repository Fix (#2576)
Need to use `this` pointer.
2022-11-26 12:31:51 -05:00
Alex King 1002a5659b [Hot Fix] Fix non-Bot Compile. (#2575)
#ifdef BOTS is needed for non-Bots compile.
2022-11-26 11:13:57 -05:00
Alex King dced08cf97 [Quest API] Add Zone Flag Methods to Perl/Lua. (#2574)
* [Quest API] Add Zone Flag Methods to Perl/Lua.

# Perl
- Add `$client->GetPEQZoneFlags()`.
- Add `$client->GetZoneFlags()`.

# Lua
- Add `client:GetPEQZoneFlags()`.
- Add `client:GetZoneFlags()`.

# Notes
- Allows operators to get a list of all PEQ/zone flags to be looped through or listed out easily without having to have a list of individual zone IDs to check or otherwise.

* Update zoning.cpp

* Repositories and cleanup.
2022-11-26 11:13:46 -05:00
Alex King b91d879662 [Quest API] Add Instance Methods to Perl/Lua. (#2573)
* [Quest API] Add Instance Methods to Perl/Lua.

# Perl
- Add `quest::GetInstanceIDs(zone_name)`.
- Add `quest::GetInstanceIDsByCharID(zone_name, character_id)`.
- Add `quest::GetInstanceVersionByID(instance_id)`.
- Add `quest::GetInstanceZoneIDByID(instance_id)`.

# Lua
- Add `eq.get_instance_ids(zone_name)`.
- Add `eq.get_instance_ids_by_char_id(zone_name, character_id)`.
- Add `eq.get_instance_version_by_id(instance_id)`.
- Add `eq.get_instance_zone_id_by_id(instance_id)`.

# Notes
- The instance IDs methods return arrays of IDs for looping so you can check on mass the instances a player has for a zone.
- Keeps operators from having to guess which possible versions of a zone a player has an instance for or loop through them all to find out.
- Cleanup `common/database_instances.cpp` to mostly use repositories where possible.

* Update database.h

* Update character_corpses_repository.h
2022-11-26 10:43:29 -05:00
Alex King 1d1ffc66fe [Quest API] Add Proximity Range Methods to Perl/Lua. (#2572)
# Perl
- Add `quest::set_proximity_range(x_range, y_range)`.
- Add `quest::set_proximity_range(x_range, y_range, z_range)`.
- Add `quest::set_proximity_range(x_range, y_range, z_range, enable_say)`.

# Lua
- Add `eq.set_proximity_range(x_range, y_range)`.
- Add `eq.set_proximity_range(x_range, y_range, z_range)`.
- Add `eq.set_proximity_range(x_range, y_range, z_range, enable_say)`.

# Notes
- Allows a shorthand for setting proximities.
- Automatically uses NPC's current location versus having to provide it.
2022-11-26 10:11:40 -05:00
Aeadoin 4423a9f160 [Bots] Add Melee Support for Casting, Cleanup Bot Casting Logic (#2571)
* [Bots] Add Melee Support for Casting, Cleanup Logic

* Formatting

* More Logic Changes

* formatting
2022-11-25 16:23:00 -05:00
Aeadoin 217a6b6344 [Merchant] LDoNSellBackRate support for Rule Merchant:EnableAltCurrencySell (#2570) 2022-11-25 16:16:59 -05:00
Aeadoin 99052aec8b [Bot] Add EVENT_TRADE Support to Bots. (#2560)
* [Bot] Add EVENT_TRADE Support to Bots.

* Fixed issue with duplicate items after Event Trade

* Update logic

* Add CalcBotStats call after Bot Trade Event

* Fix Lua EVENT_TRADE.

* Formatting.

* More formatting.

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2022-11-25 15:09:08 -05:00
Aeadoin 45c4fe55f0 [Quest API] Add HasBotSpellEntry() to Perl/Lua. (#2563)
* [Bots] Quest API Check Spell in Bot_Spell_Entries

* Add to luabind and packages

* Change Method to be HasBotSpellEntry, change SpellID to uint16

* Ordering, and removed unused logging
2022-11-24 22:29:38 -05:00
Kinglykrab 52e1bc943a [Commands] Add #bugs Command. (#2559)
* [Commands] Add #bugs Command.

- Adds a #bugs command for viewing bug reports.
- Remove unused bug related rules in favor of hard-coding the new system.

* Cleanup.

* Typo.

* Push.

* Lower status so it fits with message.
2022-11-22 17:32:26 -05:00
Kinglykrab dd3c76e9d2 [Bug Fix] Fix EntityList::GetBotListByCharacterID() (#2569)
- Class ID wasn't being checked, must've been left out of commit.
2022-11-22 17:03:43 -05:00
Kinglykrab 5e6741cf17 [Quest API] Add Overloads to MoveZone Methods in Perl/Lua. (#2551)
# Perl
- Add `$client->MoveZone(zone_name, x, y, z)`.
- Add `$client->MoveZone(zone_name, x, y, z, h)`.
- Add `$client->MoveZoneGroup(zone_name, x, y, z)`.
- Add `$client->MoveZoneGroup(zone_name, x, y, z, h)`.
- Add `$client->MoveZoneRaid(zone_name, x, y, z)`.
- Add `$client->MoveZoneRaid(zone_name, x, y, z, h)`.
- Add `$client->MoveZoneInstance(instance_id, x, y, z)`.
- Add `$client->MoveZoneInstance(instance_id, x, y, z, h)`.
- Add `$client->MoveZoneInstanceGroup(instance_id, x, y, z)`.
- Add `$client->MoveZoneInstanceGroup(instance_id, x, y, z, h)`.
- Add `$client->MoveZoneInstanceRaid(instance_id, x, y, z)`.
- Add `$client->MoveZoneInstanceRaid(instance_id, x, y, z, h)`.

# Lua
- Add `client:MoveZone(zone_name, x, y, z)`.
- Add `client:MoveZone(zone_name, x, y, z, h)`.
- Add `client:MoveZoneGroup(zone_name, x, y, z)`.
- Add `client:MoveZoneGroup(zone_name, x, y, z, h)`.
- Add `client:MoveZoneRaid(zone_name, x, y, z)`.
- Add `client:MoveZoneRaid(zone_name, x, y, z, h)`.
- Add `client:MoveZoneInstance(instance_id, x, y, z)`.
- Add `client:MoveZoneInstance(instance_id, x, y, z, h)`.
- Add `client:MoveZoneInstanceGroup(instance_id, x, y, z)`.
- Add `client:MoveZoneInstanceGroup(instance_id, x, y, z, h)`.
- Add `client:MoveZoneInstanceRaid(instance_id, x, y, z)`.
- Add `client:MoveZoneInstanceRaid(instance_id, x, y, z, h)`.

# Notes
- Adds XYZ/XYZH overloads to these methods so it no longer assumes safe coordinates unless position isn't specified.
2022-11-22 16:48:05 -05:00
Kinglykrab 8373dd1cb9 [Commands] Cleanup #timers Command. (#2562)
- Cleanup popup window and add a message for if there are no recast timers.
2022-11-22 09:17:09 -05:00
Kinglykrab 9f65159cb2 [Commands] Cleanup #serverinfo Command. (#2568)
- Cleanup messages.
- Use new dialogue window methods.
2022-11-22 09:14:22 -05:00
Kinglykrab f143d0a75f [Commands] Cleanup #delacct Command. (#2567)
- Cleanup messages and logic.
- Use repositories.
2022-11-22 09:14:15 -05:00
Kinglykrab 19e7f0a6b1 [Commands] Cleanup #heromodel Command. (#2566)
- Cleanup messages and logic.
2022-11-22 09:14:08 -05:00
Kinglykrab 3c361be739 [Commands] Remove #iteminfo Command. (#2565)
- Command is unused and doesn't have most of the item data anyway, seems like a command for back when items weren't fully working.
2022-11-22 09:13:59 -05:00
Kinglykrab 3424fe78f5 [Commands] Cleanup #suspend Command. (#2564)
- Cleanup messages and logic.
- Use repositories.
2022-11-22 09:13:37 -05:00
Kinglykrab 0dfa067974 [Quest API] Add Hotzone Methods to Perl/Lua. (#2558)
# Perl
- Add `quest::ishotzone()`.
- Add `quest::sethotzone(is_hotzone)`.

# Lua
- Add `eq.is_hotzone()`.
- Add `quest::set_hotzone(is_hotzone)`.

# Notes
- Allows operators to toggle hotzone flags within a script dynamically, for stuff like making an instance a hotzone, but not necessarily all versions of the zone.
2022-11-22 09:11:53 -05:00
Kinglykrab 0c56586f3b [Quest API] Add Client Spell Methods to Perl/Lua. (#2550)
* [Quest API] Add Client Spell Methods to Perl/Lua.

# Perl
- Add `$client->ApplySpell(spell_id)`.
- Add `$client->ApplySpell(spell_id, duration)`.
- Add `$client->ApplySpell(spell_id, duration, allow_pets)`.
- Add `$client->ApplySpell(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `$client->ApplySpell(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `$client->ApplySpellGroup(spell_id)`.
- Add `$client->ApplySpellGroup(spell_id, duration)`.
- Add `$client->ApplySpellGroup(spell_id, duration, allow_pets)`.
- Add `$client->ApplySpellGroup(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `$client->ApplySpellGroup(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `$client->ApplySpellRaid(spell_id)`.
- Add `$client->ApplySpellRaid(spell_id, duration)`.
- Add `$client->ApplySpellRaid(spell_id, duration, allow_pets)`.
- Add `$client->ApplySpellRaid(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `$client->ApplySpellRaid(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `$client->SetSpellDuration(spell_id)`.
- Add `$client->SetSpellDuration(spell_id, duration)`.
- Add `$client->SetSpellDuration(spell_id, duration, allow_pets)`.
- Add `$client->SetSpellDuration(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `$client->SetSpellDuration(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `$client->SetSpellDurationGroup(spell_id)`.
- Add `$client->SetSpellDurationGroup(spell_id, duration)`.
- Add `$client->SetSpellDurationGroup(spell_id, duration, allow_pets)`.
- Add `$client->SetSpellDurationGroup(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `$client->SetSpellDurationGroup(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `$client->SetSpellDurationRaid(spell_id)`.
- Add `$client->SetSpellDurationRaid(spell_id, duration)`.
- Add `$client->SetSpellDurationRaid(spell_id, duration, allow_pets)`.
- Add `$client->SetSpellDurationRaid(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `$client->SetSpellDurationRaid(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.

# Lua
- Add `client:ApplySpell(spell_id)`.
- Add `client:ApplySpell(spell_id, duration)`.
- Add `client:ApplySpell(spell_id, duration, allow_pets)`.
- Add `client:ApplySpell(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `client:ApplySpell(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `client:ApplySpellGroup(spell_id)`.
- Add `client:ApplySpellGroup(spell_id, duration)`.
- Add `client:ApplySpellGroup(spell_id, duration, allow_pets)`.
- Add `client:ApplySpellGroup(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `client:ApplySpellGroup(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `client:ApplySpellRaid(spell_id)`.
- Add `client:ApplySpellRaid(spell_id, duration)`.
- Add `client:ApplySpellRaid(spell_id, duration, allow_pets)`.
- Add `client:ApplySpellRaid(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `client:ApplySpellRaid(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `client:SetSpellDuration(spell_id)`.
- Add `client:SetSpellDuration(spell_id, duration)`.
- Add `client:SetSpellDuration(spell_id, duration, allow_pets)`.
- Add `client:SetSpellDuration(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `client:SetSpellDuration(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `client:SetSpellDurationGroup(spell_id)`.
- Add `client:SetSpellDurationGroup(spell_id, duration)`.
- Add `client:SetSpellDurationGroup(spell_id, duration, allow_pets)`.
- Add `client:SetSpellDurationGroup(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `client:SetSpellDurationGroup(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.
- Add `client:SetSpellDurationRaid(spell_id)`.
- Add `client:SetSpellDurationRaid(spell_id, duration)`.
- Add `client:SetSpellDurationRaid(spell_id, duration, allow_pets)`.
- Add `client:SetSpellDurationRaid(spell_id, duration, allow_pets, is_raid_group_only)`.
- Add `client:SetSpellDurationRaid(spell_id, duration, allow_pets, is_raid_group_only, allow_bots)`.

# Notes
- Allows operators extremely easy shorthands to cast on entire groups and raid groups and optionally include their bots and pets.
- Default functionality for Raid is that it only casts on your group, set `is_raid_group_only` to `false` to cast on the entire Raid.

* Cleanup.

* Remove Raid parameter from Solo/Group methods.
2022-11-22 09:11:36 -05:00
Kinglykrab 37af643b61 [Bots] Cleanup Say Event Parse. (#2557) 2022-11-20 14:28:46 -06:00
Kinglykrab f67767f28e [Cleanup] Extra Space in NPC::AISpellsList(). (#2555) 2022-11-20 09:59:59 -05:00
Kinglykrab e2dfbeb116 [Bug Fix] Fix Flag Updating with SetGMStatus() in Lua. (#2554)
# Notes
- Perl was sending `UpdateAdmin()` after `SetGMStatus()`, Lua wasn't, so only Perl was updating properly.
- Fix is to just put `UpdateAdmin()` inside `SetGMStatus()`.
2022-11-19 22:05:01 -05:00
Aeadoin 5173a9179b [Hotfix] Fix issue with Bot Loading with 0 Health causing buffs to be lost. (#2552) 2022-11-18 17:27:59 -05:00
Kinglykrab 0003f6f863 [Quest API] Add Area Damage Methods to Perl/Lua. (#2549)
* [Quest API] Add Area Damage Methods to Perl/Lua.

# Perl
- Add `$mob->DamageArea(damage)`.
- Add `$mob->DamageArea(damage, distance)`.
- Add `$mob->DamageAreaBots(damage)`.
- Add `$mob->DamageAreaBots(damage, distance)`.
- Add `$mob->DamageAreaClients(damage)`.
- Add `$mob->DamageAreaClients(damage, distance)`.
- Add `$mob->DamageAreaNPCs(damage)`.
- Add `$mob->DamageAreaNPCs(damage, distance)`.
- Add `$mob->DamageAreaPercentage(damage)`.
- Add `$mob->DamageAreaPercentage(damage, distance)`.
- Add `$mob->DamageAreaBotsPercentage(damage)`.
- Add `$mob->DamageAreaBotsPercentage(damage, distance)`.
- Add `$mob->DamageAreaClientsPercentage(damage)`.
- Add `$mob->DamageAreaClientsPercentage(damage, distance)`.
- Add `$mob->DamageAreaNPCsPercentage(damage)`.
- Add `$mob->DamageAreaNPCsPercentage(damage, distance)`.

# Lua
- Add `mob:DamageArea(damage)`.
- Add `mob:DamageArea(damage, distance)`.
- Add `mob:DamageAreaBots(damage)`.
- Add `mob:DamageAreaBots(damage, distance)`.
- Add `mob:DamageAreaClients(damage)`.
- Add `mob:DamageAreaClients(damage, distance)`.
- Add `mob:DamageAreaNPCs(damage)`.
- Add `mob:DamageAreaNPCs(damage, distance)`.
- Add `mob:DamageAreaPercentage(damage)`.
- Add `mob:DamageAreaPercentage(damage, distance)`.
- Add `mob:DamageAreaBotsPercentage(damage)`.
- Add `mob:DamageAreaBotsPercentage(damage, distance)`.
- Add `mob:DamageAreaClientsPercentage(damage)`.
- Add `mob:DamageAreaClientsPercentage(damage, distance)`.
- Add `mob:DamageAreaNPCsPercentage(damage)`.
- Add `mob:DamageAreaNPCsPercentage(damage, distance)`.

# Notes
- Cleanup parameter order of damage methods.
- These methods allow you to damage all Bots, Clients, Mobs, or NPCs in a zone or by distance from the Mob.
- Fix math with percentage damage.

* Update entity.cpp
2022-11-16 21:11:01 -06:00
Kinglykrab 856aa51cb8 [Bots] Add support for Bot scripting. (#2515)
* [Bots] Add support for Bot scripting.

# Perl
- Add support for `zone/bot.pl` and `zone/bot_v#.pl`.
- Add support for `global/global_bot.pl`.
- Add `$bot->SignalBot(signal_id)` to Perl.
- Add `$bot->OwnerMessage(message)` to Perl.
- Add `$entity_list->SignalAllBotsByOwnerCharacterID(character_id, signal_id)` to Perl.
- Add `$entity_list->SignalBotByBotID(bot_id, signal_id)` to Perl.
- Add `$entity_list->SignalBotByBotName(bot_name, signal_id)` to Perl.
- Add `EVENT_SPELL_EFFECT_BOT` to Perl.
- Add `EVENT_SPELL_EFFECT_BUFF_TIC_BOT` to Perl.

# Lua
- Add support for `zone/bot.lua` and `zone/bot_v#.lua`.
- Add support for `global/global_bot.lua`.
- Add `bot:SignalBot(signal_id)` to Lua.
- Add `bot:OwnerMessage(message)` to Lua.
- Add `entity_list:SignalAllBotsByOwnerCharacterID(character_id, signal_id)` to Lua.
- Add `entity_list:SignalBotByBotID(bot_id, signal_id)` to Lua.
- Add `entity_list:SignalBotByBotName(bot_name, signal_id)` to Lua.
- Add `EVENT_SPELL_EFFECT_BOT` to Lua.
- Add `EVENT_SPELL_EFFECT_BUFF_TIC_BOT` to Lua.

# Supported Bot Events
1. `EVENT_CAST`
2. `EVENT_CAST_BEGIN`
3. `EVENT_CAST_ON`
4. `EVENT_COMBAT`
5. `EVENT_DEATH`
6. `EVENT_DEATH_COMPLETE`
7. `EVENT_SAY`
8. `EVENT_SIGNAL`
9. `EVENT_SLAY`
10. `EVENT_SLAY_NPC`
11. `EVENT_SPAWN`
12. `EVENT_TARGET_CHANGE`
13. `EVENT_TIMER`
14. `EVENT_USE_SKILL`

# Common
- Convert NPC pointers in common events to Mob pointers so bots are supported.
- Convert signal IDs to `int` where it wasn't already, allowing negative signals to be sent properly.

* Add EVENT_POPUP_RESPONSE.

* Cleanup and fix EVENT_COMBAT/EVENT_SLAY/EVENT_NPC_SLAY.

* Fix DoNPCEmote calls.

* Update attack.cpp

* Update event_codes.h

* Update bot_command.cpp
2022-11-16 21:02:16 -06:00
Kinglykrab 7ea77ee027 [Bots] Add Quest API Support for Limits. (#2522)
* [Bots] Add Quest API Support for Limits.

# Perl
- Add `$client->GetBotCreationLimit()` to Perl.
- Add `$client->GetBotCreationLimit(class_id)` to Perl.
- Add `$client->GetBotRequiredLevel()` to Perl.
- Add `$client->GetBotRequiredLevel(class_id)` to Perl.
- Add `$client->GetBotSpawnLimit()` to Perl.
- Add `$client->GetBotSpawnLimit(class_id)` to Perl.
- Add `$client->SetBotCreationLimit(creation_limit)` to Perl.
- Add `$client->SetBotCreationLimit(creation_limit, class_id)` to Perl.
- Add `$client->SetBotRequiredLevel(required_level)` to Perl.
- Add `$client->SetBotRequiredLevel(required_level, class_id)` to Perl.
- Add `$client->SetBotSpawnLimit(spawn_limit)` to Perl.
- Add `$client->SetBotSpawnLimit(spawn_limit, class_id)` to Perl.
- Add `$entity_list->GetBotListByCharacterID(character_id, class_id)` to Perl.

# Lua
- Add `client:GetBotCreationLimit()` to Lua.
- Add `client:GetBotCreationLimit(class_id)` to Lua.
- Add `client:GetBotRequiredLevel()` to Lua.
- Add `client:GetBotRequiredLevel(class_id)` to Lua.
- Add `client:GetBotSpawnLimit()` to Lua.
- Add `client:GetBotSpawnLimit(class_id)` to Lua.
- Add `client:SetBotCreationLimit(creation_limit)` to Lua.
- Add `client:SetBotCreationLimit(creation_limit, class_id)` to Lua.
- Add `client:SetBotRequiredLevel(required_level)` to Lua.
- Add `client:SetBotRequiredLevel(required_level, class_id)` to Lua.
- Add `client:SetBotSpawnLimit(spawn_limit)` to Lua.
- Add `client:SetBotSpawnLimit(spawn_limit, class_id)` to Lua.
- Add `entity_list:GetBotListByCharacterID(character_id, class_id)` to Lua.

# Notes
- Allows operators to set creation and spawn limits based on class, as well as required level.
- Using the class-inspecific methods sets the global limit or required level.
- Global limits are checked prior to class-specific limits and if they are not met, creation or spawn is disallowed.
- Modified preexisting Quest API to make use of this new stuff under the hood.

* Update bot_command.cpp

* Add client bot file.
2022-11-16 19:51:13 -05:00
Kinglykrab ce4d96dc91 [Commands] Cleanup #xtargets Command. (#2545)
* [Commands] Cleanup #xtargets Command.

- Cleanup messages and logic.

* Update client.cpp

* Update client.cpp
2022-11-16 19:11:35 -05:00
Kinglykrab bd95daa1f3 [Quest API] Add GetRandomBot() to Perl/Lua (#2543)
* [Quest API] Add GetRandomBot() to Perl/lua.

# Perl
- Add `$entity_list->GetRandomBot()` to Perl.
- Add `$entity_list->GetRandomBot(x, y, z, distance)` to Perl.
- Add `$entity_list->GetRandomBot(x, y, z, distance, exclude_bot)` to Perl.

# Lua
- Add `eq.get_entity_list():GetRandomBot()` to Lua.
- Add `eq.get_entity_list():GetRandomBot(x, y, z, distance)` to Lua.
- Add `eq.get_entity_list():GetRandomBot(x, y, z, distance, exclude_bot)` to Lua.

# Notes
- Allows operators to grab a random Bot from entity list similar to Client, Mob, and NPC.

* Cleanup and fix Perl distance.

- Perl distance was sending as already squared, Lua was not.
- Send as non-squared and square in the method so that both work the same.

* Update entity.cpp

* Update entity.cpp
2022-11-16 18:54:15 -05:00
Kinglykrab 93d8471487 [Commands] Cleanup #opcode Command. (#2547)
* [Commands] Cleanup #opcode Command.

- Cleanup logic.

* Update command.cpp
2022-11-16 08:30:35 -06:00
Kinglykrab 730cd3f28a [Bots] Add Expansion Bitmask Quest APIs. (#2523)
* [Bots] Add Expansion Bitmask Quest APIs.

- Add `$bot->GetExpansionBitmask()` to Perl.
- Add `$bot->SetExpansionBitmask(expansion_bitmask)` to Perl.

- Add `bot:GetExpansionBitmask()` to Lua.
- Add `bot:SetExpansionBitmask(expansion_bitmask)` to Lua.

- Adds `expansion_bitmask` column to `bot_data` table.
- Allows server operators to limit expansion settings on a bot-by-bot basis.
- Allows limiting or allowing of AAs in `Bot::LoadAAs()` based on expansion bitmask.
- Default value is `-1` which just defaults to the `Bots:BotExpansionSettings` rule value.
- Setting bitmask saves to database and reloads AAs so bots automatically recalculate bonuses.

* Add save parameter.

* Typo.
2022-11-16 07:29:50 -06:00
Kinglykrab bb58a9cd20 [Quest API] Add Marquee methods to Perl/Lua. (#2544)
* [Quest API] Add zonemarquee to Perl/Lua.

# Perl
- Add `quest::zonemarquee(type, priority, fade_in, fade_out, duration, message)` to Perl.

# Lua
- Add `eq.zone_marquee(type, priority, fade_in, fade_out, duration, message)` to Lua.

# Notes
- Allows operators to easily send a zone-wide marquee, similar to `quest::ze`/`eq.zone_emote`.

* Update lua_general.cpp

* Add other methods.

* Add entity list marquee

* Update client.cpp

* Add more shorthands.
2022-11-16 07:23:39 -06:00
Kinglykrab 8c994fef97 [Quest API] Add Mob Hate Methods to Perl/Lua. (#2548)
* [Quest API] Add Mob Hate Methods to Perl/Lua.

# Perl
- Add `$mob->DamageHateList(damage)` to Perl.
- Add `$mob->DamageHateList(damage, distance)` to Perl.
- Add `$mob->DamageHateListPercentage(damage)` to Perl.
- Add `$mob->DamageHateListPercentage(damage, distance)` to Perl.
- Add `$mob->DamageHateListBots(damage)` to Perl.
- Add `$mob->DamageHateListBots(damage, distance)` to Perl.
- Add `$mob->DamageHateListBotsPercentage(damage)` to Perl.
- Add `$mob->DamageHateListBotsPercentage(damage, distance)` to Perl.
- Add `$mob->DamageHateListClients(damage)` to Perl.
- Add `$mob->DamageHateListClients(damage, distance)` to Perl.
- Add `$mob->DamageHateListClientsPercentage(damage)` to Perl.
- Add `$mob->DamageHateListClientsPercentage(damage, distance)` to Perl.
- Add `$mob->DamageHateListNPCs(damage)` to Perl.
- Add `$mob->DamageHateListNPCs(damage, distance)` to Perl.
- Add `$mob->DamageHateListNPCsPercentage(damage)` to Perl.
- Add `$mob->DamageHateListNPCsPercentage(damage, distance)` to Perl.
- Add `$mob->GetHateListBots()` to Perl.
- Add `$mob->GetHateListBots(distance)` to Perl.
- Add `$mob->GetHateListClients()` to Perl.
- Add `$mob->GetHateListClients(distance)` to Perl.
- Add `$mob->GetHateListNPCs()` to Perl.
- Add `$mob->GetHateListNPCs(distance)` to Perl.

# Lua
- Add `mob:DamageHateList(damage)` to Lua.
- Add `mob:DamageHateList(damage, distance)` to Lua.
- Add `mob:DamageHateListPercentage(damage)` to Lua.
- Add `mob:DamageHateListPercentage(damage, distance)` to Lua.
- Add `mob:DamageHateListBots(damage)` to Lua.
- Add `mob:DamageHateListBots(damage, distance)` to Lua.
- Add `mob:DamageHateListBotsPercentage(damage)` to Lua.
- Add `mob:DamageHateListBotsPercentage(damage, distance)` to Lua.
- Add `mob:DamageHateListClients(damage)` to Lua.
- Add `mob:DamageHateListClients(damage, distance)` to Lua.
- Add `mob:DamageHateListClientsPercentage(damage)` to Lua.
- Add `mob:DamageHateListClientsPercentage(damage, distance)` to Lua.
- Add `mob:DamageHateListNPCs(damage)` to Lua.
- Add `mob:DamageHateListNPCs(damage, distance)` to Lua.
- Add `mob:DamageHateListNPCsPercentage(damage)` to Lua.
- Add `mob:DamageHateListNPCsPercentage(damage, distance)` to Lua.
- Add `mob:GetHateListBots()` to Lua.
- Add `mob:GetHateListBots(distance)` to Lua.
- Add `mob:GetHateListClients()` to Lua.
- Add `mob:GetHateListClients(distance)` to Lua.
- Add `mob:GetHateListNPCs()` to Lua.
- Add `mob:GetHateListNPCs(distance)` to Lua.

# Notes
- Offers an extreme amount of short hands when grabbing hate list entities by a specific type or damaging a specific type of entity on an NPC's hatelist.
- Should save operators having to use `GetHateList()` then loop it to get the entries they want to do something.

* Cleanup.
2022-11-16 07:16:47 -06:00
Kinglykrab 6ff52f94c4 [Repositories] Add Bot Repositories. (#2529)
* [Repositories] Add Bot Repositories.

* Remove unnecessary table.

* Add back table.
2022-11-16 07:15:48 -06:00
Kinglykrab b5035d7e03 [Commands] Remove #profiledump and #profilereset Commands. (#2546)
- These commands don't seem to be used anymore.
2022-11-16 07:15:03 -06:00
Kinglykrab 8f1b87c5e4 [Quest API] Add Owner methods to Perl/Lua. (#2542)
* [Quest API] Add Owner methods to Perl/Lua.

# Perl
- Add `$mob->GetOwner()` to Perl.

# Lua
- Add `mob:GetOwnerID()` to Lua.

# Notes
- `GetOwner()` exists in Lua, but not Perl.
- `GetOwnerID()` exists in Perl, but not Lua.

* Update lua_mob.cpp
2022-11-14 18:03:26 -05:00
Kinglykrab e72ec4ae56 [Quest API] Add RandomizeFeature() overloads to Perl/Lua. (#2532)
# Perl
- Add `$mob->RandomizeFeatures()` to Perl.
- Add `$mob->RandomizeFeatures(send_illusion)` to Perl.
- Add `$mob->RandomizeFeatures(send_illusion, set_variables)` to Perl.

# Lua
- Add `mob:RandomizeFeatures()` to Lua.
- Add `mob:RandomizeFeatures(send_illusion)` to Lua.
- Add `mob:RandomizeFeatures(send_illusion, set_variables)` to Lua.

# Notes
- Previous overload required `send_illusion` and `set_variables` despite both default values being `true`, this will allow you to just send nothing if you want both to be `true`.
- Change `RandomizeFeatures()` type to `bool` from `void` to match source method, returns `false` when used on a race that has no features to randomize.
- This allows operators to do something different if the NPC can't use this method.
2022-11-14 16:59:17 -05:00
Kinglykrab fd2fc76706 [Commands] Cleanup #depopzone Command. (#2537)
* [Commands] Cleanup #depopzone Command.

- Cleanup messages and logic.
- Add optional `start_spawn_timers` parameter to start spawn timers of NPCs when depopped.

* Update depopzone.cpp
2022-11-14 16:47:20 -05:00
Kinglykrab f668949c24 [Quest API] Add SendGMCommand() to Perl/Lua. (#2527)
* [Quest API] Add SendGMCommand() to Perl/Lua.

# Perl
- Add `$client->SendGMCommand(message)` to Perl.
- Add `$client->SendGMCommand(message, ignore_status)` to Perl.

# Lua
- Add `client:SendGMCommand(message)` to Lua.
- Add `client:SendGMCommand(message, ignore_status)` to Lua.

# Notes
- `ignore_status` allows you to have players use GM commands that they are not the required status level for through the Quest API.
- `ignore_status` is default false, so if you don't send it, it checks and makes sure the player can use the command you're sending before allowing it.

* Typo.

* Formatting.
2022-11-14 16:47:02 -05:00
Kinglykrab 36887203d3 [Commands] Cleanup #doanim Command. (#2540)
* [Commands] Cleanup #doanim Command.

- Cleanup messages and logic.
- Allow you to use animation names or IDs, could possibly extend this to quest API in the future.

* Update dialogue_window.h
2022-11-14 16:38:05 -05:00
Kinglykrab e5ad9264d0 [Quest API] Add GetRandomClient(), GetRandomMob() and GetRandomNPC() overloads to Perl/Lua. (#2541)
* [Quest API] Add GetRandomClient(), GetRandomMob() and GetRandomNPC() overloads to Perl/Lua.

# Perl
- Add `$entity_list->GetRandomClient()` to Perl.
- Add `$entity_list->GetRandomMob()` to Perl.
- Add `$entity_list->GetRandomNPC()` to Perl.

# Lua
- Add `eq.get_entity_list():GetRandomClient()` to Lua.
- Add `eq.get_entity_list():GetRandomMob()` to Lua.
- Add `eq.get_entity_list():GetRandomNPC()` to Lua.

# Notes
- We didn't have overloads before without XYZ, so was harder to do a zone-wide random.

* Update lua_entity_list.cpp
2022-11-14 14:08:02 -05:00
Kinglykrab df57138a61 [Commands] Cleanup #devtools Command. (#2538)
* [Commands] Cleanup #devtools Command.

- Cleanup messages and logic.

* Update client.cpp
2022-11-14 14:06:36 -05:00
Kinglykrab aa506110e1 [Commands] Cleanup #depop Command. (#2536)
* [Commands] Cleanup #depop Command.

- Cleanup messages and logic.
- Add optional `start_spawn_timer` parameter to start spawn timer of NPC when depopped.

* Update command.cpp
2022-11-14 14:05:48 -05:00
Kinglykrab 2c656c4110 [Commands] Cleanup #emote Command. (#2535)
* [Commands] Cleanup #emote Command.

- Cleanup messages and logic.
- Allow `^` separator to send multiple messages by name, world, or zone.

* Update emote.cpp
2022-11-14 14:05:40 -05:00
Kinglykrab 8d184fc6c0 [Commands] Cleanup #scribespell and #scribespells Commands. (#2534)
- Cleanup messages and logic.
2022-11-14 14:05:34 -05:00
Kinglykrab 9c967c24b8 [Quest API] Add Popup methods to Perl/Lua. (#2533)
* [Quest API] Add Popup methods to Perl/Lua.

# Perl
- Add `quest::popupcentermessage(message)` to Perl.
- Add `quest::popupcolormessage(color, message)` to Perl.
- Add `quest::popupindent()` to Perl.
- Add `quest::popuplink(link)` to Perl.
- Add `quest::popuplink(link, message)` to Perl.

# Lua
- Add `eq.popup(title, message)` to Lua.
- Add `eq.popup(title, message, popup_id)` to Lua.
- Add `eq.popup(title, message, popup_id, buttons)` to Lua.
- Add `eq.popup_center_message(message)` to Lua.
- Add `eq.popup_color_message(color, message)` to Lua.
- Add `eq.popup_indent()` to Lua.
- Add `eq.popup_link(link)` to Lua.
- Add `eq.popup_link(link, message)` to Lua.

# Notes
- Adds the Perl plugins like PWAutoCenter, PWIndent, and PWHyperlink.
- Parses out HTML `<>` tags automatically in `popupautocenter` to properly center stuff like colored messages. (Doesn't work with links)
- This lets Lua users have similar functionality to Perl users.

* Add tables and break.

* Add indent_count to indent method.

* Move to Dialogue Window.
2022-11-14 14:05:24 -05:00
Kinglykrab 31e5622dad [Quest API] Add CloneAppearance() to Perl/Lua. (#2531)
* [Quest API] Add CloneAppearance() to Perl/Lua.

# Perl
- Add `$client->CloneAppearance(other)` to Perl.
- Add `$client->CloneAppearance(other, clone_name)` to Perl.

# Lua
- Add `client:CloneAppearance(other)` to Lua.
- Add `client:CloneAppearance(other, clone_name)` to Lua.

# Notes
- Allows operators to easily clone appearance between mobs in a script without relying on a plugin or module.

* Update mob_appearance.cpp

* Update mob.cpp
2022-11-14 14:05:05 -05:00
Kinglykrab 8a449b0152 [Repositories] Update Character EXP Modifiers Repository (#2530) 2022-11-14 14:04:55 -05:00
Kinglykrab 5f4a8d17f5 [Quest API] Add SplitMoney() with Client splitter to Perl. (#2525)
# Perl
- Add `$group->SplitMoney(copper, silver, gold, platinum, splitter)` to Perl.
- Add `$raid->SplitMoney(group_id, copper, silver, gold, platinum, splitter)` to Perl.
2022-11-14 14:04:44 -05:00
Kinglykrab c5c57b7541 [Quest API] Add Group/Raid overloads to Perl/Lua. (#2526)
# Perl
- Add `$raid->GetGroup(client)` to Perl.
- Add `$raid->GetGroupMember(member_index)` to Perl.
- Add `$raid->IsLeader(client)` to Perl.

# Lua
- Add `group:GroupMessage(sender, message)` to Lua.
2022-11-14 14:04:38 -05:00
Kinglykrab 3cb13969ff [Quest API] Add GetAverageLevel() to Perl/Lua. (#2524)
# Perl
- Add `$group->GetAverageLevel()` to Perl.

# Lua
- Add `group:GetAverageLevel()` to Lua.
- Convert `group:GetHighestLevel()` from `int` to `uint32` in Lua.
- Convert `group:GetLowestLevel()` from `int` to `uint32` in Lua.
2022-11-14 14:04:14 -05:00
Kinglykrab fca99bb274 [Bots] Hotfix for possible crash. (#2539)
* [Bots] Hotfix for possible crash.

Possible crash due to 4 nullable columns in `bot_spells_entries` table.

* Update 2022_11_13_bot_spells_entries.sql
2022-11-13 20:44:07 -05:00
Kinglykrab 815593b9bc [Cleanup] Remove unusued Max Item ID Constant (#2528) 2022-11-08 14:59:24 -05:00
Aeadoin 33b95c42c2 [Feature] Change #scribespells to be aware of spellgroups & ranks (#2501)
* Change #scribespells to be aware of spellgroups & ranks

* Formatting

* Fix Formatting, and change stored return  data type to match function return type.

* Compact If Statements

* Implemented SQL Query to reduce number of iterations required.

* Cleaned up Query, and improved performance

* Cleaned up SQL Queries

* Formatting

* Indenting fix.

* Update client.cpp

* Fix Formatting in spells.cpp

* Fix ValueWithin.

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Kinglykrab <89047260+Kinglykrab@users.noreply.github.com>
2022-11-06 18:01:58 -05:00
hg e01ac39887 [Quest API] Send delivered task items in trade events (#2518)
This restores sending items to EVENT_TRADE that are updated by source
controlled delivery tasks which was removed in 7cf96ca2d8.

That patch filtered out items consumed by task updates to fix a few bugs
with items being returned despite incrementing a task:

  - If an npc without a quest trade event handler was the target of a
    delivery task for a NoDrop/non-Quest item, the npc would auto return
    it due to the `ReturnNonQuestNoDropItems` rule.

  - If an npc without a quest trade event handler was the target of a
    delivery task for a non-NoDrop item, the item would be added to the
    npc's loot.

  - If an npc with an EVENT_ITEM/EVENT_TRADE quest handler used the Lua
    or Perl trade plugins, the plugins would return task items unless
    specific checks for the turned in slots existed.

The quest plugin item returns are problematic for this since they just
summon to return items not handled by the script

  e.g. For a task to deliver N Large Fruit Bat Wings (item id 19616),
  if a player turned in 1 Wing in slot 1 and a stack of 20 Wings in slot
  2, the task would be incremented 21 times and the following Lua trade
  handler would return the stack of 20 from the 2nd trade slot:

  ```lua
    function event_trade(e)
      local item_lib = require("items")
      if item_lib.check_turn_in(e.trade, { item1 = 19616 }) then
        eq.debug("Lua consumed 1 slot and will return other slots")
      end
      item_lib.return_items(e.self, e.other, e.trade)
    end
  ```

  This also occured with the perl plugin though slightly differently
  since that plugin returns all slots unless the exact handin slot count
  matches (requiring check_handin conditions for all slots):

  ```perl
    sub EVENT_ITEM {
      if (plugin::check_handin(\%itemcount, 19616 => 1)) {
        # No issue if only one slot used for trade (item not returned)
      }
      # Perl fails handin check if multiple slots not checked and returns all
      plugin::return_items(\%itemcount);
    }
  ```

While that patch solved the issue, it's inconvenient and wrong to not
receive items in trade events used in a source task update. It breaks
existing trade scripts for tasks that aren't quest controlled and it
forces tasks to be changed to quest controlled and manually updated to
script any extra behavior.

This patch stores the task update count on the item instance before
dispatching it to quests. The burden is now on quests and plugins to
use that value in order to prevent returning items consumed by tasks.

`ItemInstance::RemoveTaskDeliveredItems` has been added to simplify
handling this in plugins which is also used for non-quest item returns.
2022-11-06 17:10:30 -05:00
Aeadoin 7e7358e9b6 [Bots] Add Data Bucket support to Bot Spell Entries. (#2505)
* [Bots] Add Data Bucket support to Bot Spell Entries.

* Cleanup Formatting and Functions

* Consolidated "CheckDataBucket" Functions

* Remove unneeded CastToClient

* Add choice to format data buckets as either "character-id" or "bot-id" to Bot spells

* Fix Formatting

* Clean up.

* Update npc.h

* Fix Bot Casting issues

* Formatting

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Kinglykrab <89047260+Kinglykrab@users.noreply.github.com>
2022-11-06 17:06:01 -05:00
hg de63eaa4b2 [Quest API] Add apis to end shared tasks (#2521)
This required some minor shared task refactoring

- Shared task expiration handling was moved to world. Previously this
  was handled by zone and had clients self remove when a shared task
  expired. This resulted in wrong messages when a task ended.

- FailTask is now implemented for shared tasks which previously only
  made the client quit the shared task. It now fails the task for all
  members by ending the shared task.

The `Client::EndSharedTask` api will end the client's current shared
task (removing all members). This is similiar to the `FailTask` api
except it doesn't require a `task_id` and the red task fail banner is
optional (live doesn't use it for shared tasks).

The global `end_dz_task` api was added for when a client context isn't
available. This will end a shared task if the current zone is a dynamic
zone for a shared task mission. Currently only shared tasks use dynamic
zones but this api can be expanded if support is added for tasks/quests.

The global `get_dz_task_id` was added to conveniently get the task id
for the current dynamic zone if it's used for a mission. Note this is
a database hit since that information is not available at zone level.
2022-11-06 11:04:39 -05:00
hg 3d7c43e92f [Quest API] Add ResetDecayTimer() to Perl/Lua. (#2520) 2022-11-06 10:48:10 -05:00
hg 69e90c1739 [Quest API] Export corpse in EVENT_DEATH_COMPLETE (#2519)
It wasn't possible to easily obtain the corpse from post-death events
because the killed entity id is assigned to the corpse and reset to 0
on the entity before the events are dispatched.

This exposes the killed entity's corpse to EVENT_DEATH_COMPLETE and
EVENT_DEATH_ZONE. Lua exports a Corpse object and perl exports a corpse
entity id.

The purpose of this is to make it easier to add items dynamically on
death. Ideally this would be done in EVENT_DEATH before the corpse is
made, but there's currently some combat system bugs that make that event
unusable since it can be dispatched multiple times.

A follow up will provide an api to reset corpse decay times since adding
items after corpse creation will require quests to manually reset the
decay timer in case the corpse had zero items.
2022-11-06 10:36:57 -05:00
Kinglykrab 13b2af1a91 [Quest API] Add Instance ID/Version exports to EVENT_ZONE. (#2502)
# Perl
- Add `$from_instance_id` to EVENT_ZONE in Perl.
- Add `$from_instance_version` to EVENT_ZONE in Perl.
- Add `$target_instance_id` to EVENT_ZONE in Perl.
- Add `$target_instance_version` to EVENT_ZONE in Perl.

# Lua
- Add `e.from_instance_id` to EVENT_ZONE in Lua.
- Add `e.from_instance_version` to EVENT_ZONE in Lua.
- Add `e.instance_id` to EVENT_ZONE in Lua.
- Add `e.instance_version` to EVENT_ZONE in Lua.

# Notes
- This will allow Operators to prevent people from entering zones by Instance ID or Instance Version.
2022-11-05 11:38:03 -04:00
hg 9c7dd70b5f [Quest API] Add Lua handlers for zone controller events (#2514)
This cleans up some of the NPC::Death event dispatch code.

Adds handlers for EVENT_SPAWN_ZONE and EVENT_DEATH_ZONE used by zone
controller and fixes the death handler exports which were incorrect.
2022-11-05 11:13:39 -04:00
hg 070bf64d6a [Tasks] Only update loot tasks for NPC corpses (#2513)
This fixes a bug that allowed looting items from a player's corpse to
increment a task if it didn't have an npc target defined. It looks
like this bug existed before the changes in 7482cfc0.

This also now passes count for task loot updates to handle item stacks.

Also fixes incorrectly casting Corpse to NPC on loot update
2022-11-05 11:13:02 -04:00
Kinglykrab f6dbdf5db8 [Quest API] Add EVENT_AA_BUY and EVENT_AA_GAIN to Perl/Lua. (#2504)
# Perl
- Add EVENT_AA_BUY to Perl.
  - Exports `$aa_cost`, `$aa_id`, `$aa_previous_id`, and `$aa_next_id`
- Add EVENT_AA_GAIN to Perl.
  - Exports `$aa_gained`
- Add quest::getaaname(aa_id) to Perl.

# Lua
- Add event_aa_buy to Lua.
  - Exports `e.aa_cost`, `e.aa_id`, `e.aa_previous_id`, and `e.aa_next_id`
- Add event_aa_gain to Lua.
  - Exports `e.aa_gained`
- Add eq.get_aa_name(aa_id) to Lua.
2022-11-05 11:09:47 -04:00
Kinglykrab a3928ec504 [Quest API] Add GetUltimateOwner() to Perl/Lua. (#2516)
# Perl
- Add `$mob->GetUltimateOwner()` to Perl.

# Lua
- Add `mob:GetUltimateOwner()` to Lua.

# Notes
- Allows operators to get ultimate owner of something like a pet's pet or a pet's swarm pet.
2022-11-05 08:35:14 -04:00
Kinglykrab 8d1dd52db3 [Quest API] Add GetLowestLevel() to Perl. (#2517)
# Perl
- Add `$group->GetLowestLevel()` to Perl.

# Notes
- This exists in Lua, but not Perl.
2022-11-05 08:34:29 -04:00
1243 changed files with 113167 additions and 124152 deletions
-21
View File
@@ -1,21 +0,0 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.101.1/containers/ubuntu-18.04-git
{
"name": "Ubuntu 18.04 EQEMU",
// Moved from dockerfile to image so it builds faster
"image": "eqemu/devcontainer:0.0.2",
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["ms-vscode.cpptools", "ms-azuretools.vscode-docker"],
"mounts": ["source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"],
"remoteEnv": {
"HOST_PROJECT_PATH": "${localWorkspaceFolder}"
}
}
+80 -9
View File
@@ -1,7 +1,8 @@
---
kind: pipeline
type: docker
name: EQEmulator Server Linux CI
name: Build Linux
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
concurrency:
@@ -10,18 +11,88 @@ concurrency:
volumes:
- name: cache
host:
path: /var/lib/cache
path: /var/lib/cache-release
steps:
- name: server-build
# Source build script https://github.com/Akkadius/akk-stack/blob/master/containers/eqemu-server/Dockerfile#L20
- name: Build Linux X64
image: akkadius/eqemu-server:v11
environment:
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
commands:
- sudo chown eqemu:eqemu /drone/src/ * -R
- sudo chown eqemu:eqemu /home/eqemu/.ccache/ * -R
- git submodule init && git submodule update && mkdir -p build && cd build && cmake -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LUA=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O0 -g -DNDEBUG" -G 'Unix Makefiles' .. && make -j$((`nproc`-4))
- curl https://raw.githubusercontent.com/Akkadius/eqemu-install-v2/master/eqemu_config.json --output eqemu_config.json
- ./bin/tests
- ./utils/scripts/build/linux-build.sh
volumes:
- name: cache
path: /home/eqemu/.ccache/
---
kind: pipeline
type: exec
name: Build Windows
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
concurrency:
limit: 1
platform:
os: windows
arch: amd64
steps:
- name: Build Windows X64
environment:
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
commands:
- .\utils\scripts\build\windows-build.ps1
---
kind: pipeline
type: docker
name: Publish Artifacts to Github
steps:
- name: Upload Artifacts
image: akkadius/eqemu-build-releaser:v3
environment:
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
GH_RELEASE_GITHUB_API_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
commands:
- ./utils/scripts/build/should-release/should-release
- rclone config create remote ftp env_auth true > /dev/null
- |
rclone copy remote: --include "eqemu-server*.zip" .
- gh-release --assets=eqemu-server-linux-x64.zip,eqemu-server-windows-x64.zip -y
- |
rclone delete remote: --include "eqemu-server*.zip"
trigger:
branch:
- master
event:
- push
depends_on:
- Build Windows
- Build Linux
+15
View File
@@ -56,3 +56,18 @@ bin/
/client_files/**/CMakeFiles/
.idea
# Clangd Generated Files.
compile_flags.txt
.cache/
# vscode generated settings
.vscode/
# Build pipeline
!utils/scripts/build/
!utils/scripts/build/should-release/should-release
!utils/scripts/build/should-release/should-release.exe
# CMake Files
cmake-build-relwithdebinfo/*
-16
View File
@@ -1,16 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/usr/include/mysql"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
}
-164
View File
@@ -1,164 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "make",
"type": "shell",
"command": "cd bin && make",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "make clean",
"type": "shell",
"command": "cd bin && make clean",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "cmake",
"type": "shell",
"command": "mkdir -p bin && cd bin && rm CMakeCache.txt && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -G 'Unix Makefiles' ..",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher":{
"owner": "cpp",
"fileLocation": "relative",
"pattern":[
{
"regexp": "([\\w+|\\\\]*\\.\\w+)\\((\\d+)\\)\\: (warning|error) (.*)$",
"file": 1,
"location": 2,
"severity": 3,
"message": 4
}
]
}
},
{
"label": "download maps",
"type": "shell",
"command": "mkdir -p bin && cd bin && wget https://codeload.github.com/Akkadius/EQEmuMaps/zip/master -O maps.zip && unzip -o maps.zip && rm ./maps -rf && mv EQEmuMaps-master maps && rm maps.zip",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "download quests",
"type": "shell",
"command": "mkdir -p bin && cd bin && cd server && git -C ./quests pull 2> /dev/null || git clone https://github.com/ProjectEQ/projecteqquests.git quests",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "download eqemu_config",
"type": "shell",
"command": "mkdir -p bin && cd bin && wget --no-check-certificate https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/eqemu_config_docker.json -O eqemu_config.json",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "rebuild database (mariadb must be started)",
"type": "shell",
"command": "mkdir -p bin && cd bin && docker run -i --rm --privileged -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu -it eqemu/server:0.0.3 bash -c './eqemu_server.pl source_peq_db && ./eqemu_server.pl check_db_updates && ./eqemu_server.pl linux_login_server_setup'",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
},
{
"label": "zone 7000",
"type": "shell",
"command": "docker stop zone7000 | true && docker network create eqemu | true && docker run -i --rm --name zone7000 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7000:7000/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7000:7000",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "zone 7001",
"type": "shell",
"command": "docker stop zone7001 | true && docker network create eqemu | true && docker run -i --rm --name zone7001 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7001:7001/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7001:7001",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "loginserver",
"type": "shell",
"command": "docker stop loginserver | true && docker network create eqemu | true && docker run -i --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu --name loginserver -p 5999:5999/udp -p 5998:5998/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./loginserver",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "shared_memory, world",
"type": "shell",
"command": "docker stop sharedmemory | true && docker stop world | true && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu --name sharedmemory eqemu/server:0.0.3 ./shared_memory && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name world -p 9000:9000 -p 9000:9000/udp -p 9001:9001 -p 9080:9080 eqemu/server:0.0.3 gdb -ex run ./world",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "queryserv",
"type": "shell",
"command": "docker stop queryserv | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name queryserv eqemu/server:0.0.3 gdb -ex run ./queryserv",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "mariadb",
"type": "shell",
"command": "docker stop mariadb | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin/db:/bitnami/mariadb -p 3306:3306 -e MARIADB_DATABASE=peq -e MARIADB_USER=eqemu -e MARIADB_PASSWORD=eqemupass -e ALLOW_EMPTY_PASSWORD=yes --name mariadb --network=eqemu bitnami/mariadb:latest",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "ucs",
"type": "shell",
"command": "docker stop ucs | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src -p 7778:7778 --name ucs --network=eqemu eqemu/server:0.0.3 gdb -ex run ./ucs",
"group": {
"kind": "test",
"isDefault": true
}
}
]
}
+2 -2
View File
@@ -40,14 +40,14 @@ Assuming it is starting in c:/projects/eqemu and the x64 dependencies were extra
mkdir build
cd build
cmake -G "Visual Studio 15 2017 Win64" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON -DEQEMU_ENABLE_BOTS=ON -DCMAKE_TOOLCHAIN_FILE="c:/projects/eqemu/vcpkg/vcpkg-export-20180828-145455/scripts/buildsystems/vcpkg.cmake" ..
cmake -G "Visual Studio 15 2017 Win64" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON -DCMAKE_TOOLCHAIN_FILE="c:/projects/eqemu/vcpkg/vcpkg-export-20180828-145455/scripts/buildsystems/vcpkg.cmake" ..
##### Linux
Similarly to Windows running CMake on Linux is simple it just omits the toolchain file and uses a different generator.
mkdir build
cd build
cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON ..
cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON ..
### Building
+1975
View File
File diff suppressed because it is too large Load Diff
+19 -12
View File
@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.7)
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH})
@@ -12,17 +12,27 @@ IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
ENDIF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD 20)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF)
OPTION(EQEMU_BUILD_STATIC "Build with static linking" OFF)
IF (EQEMU_BUILD_STATIC)
SET(BUILD_SHARED_LIBS OFF)
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".a")
MESSAGE(STATUS "Building with static linking")
SET(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
ENDIF(EQEMU_BUILD_STATIC)
IF(MSVC)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-DNOMINMAX)
ADD_DEFINITIONS(-DCRASH_LOGGING)
ADD_DEFINITIONS(-D_HAS_AUTO_PTR_ETC) # for Luabind on C++17
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
ADD_DEFINITIONS( "/W0 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo /Os")
ELSE(MSVC)
ADD_DEFINITIONS(-DHAS_UNION_SEMUN)
ENDIF(MSVC)
@@ -122,7 +132,6 @@ ENDIF()
MESSAGE(STATUS "**************************************************")
#options
OPTION(EQEMU_ENABLE_BOTS "Enable Bots" OFF)
OPTION(EQEMU_COMMANDS_LOGGING "Enable GM Command logs" ON)
OPTION(EQEMU_BUILD_SERVER "Build the game server." ON)
OPTION(EQEMU_BUILD_LOGIN "Build the login server." ON)
@@ -176,10 +185,6 @@ IF(EQEMU_COMMANDS_LOGGING)
ADD_DEFINITIONS(-DCOMMANDS_LOGGING)
ENDIF(EQEMU_COMMANDS_LOGGING)
IF(EQEMU_ENABLE_BOTS)
ADD_DEFINITIONS(-DBOTS)
ENDIF(EQEMU_ENABLE_BOTS)
#database
IF(MySQL_FOUND AND MariaDB_FOUND)
SET(DATABASE_LIBRARY_SELECTION MariaDB CACHE STRING "Database library to use:
@@ -311,6 +316,10 @@ ELSE()
SET(ZLIB_LIBRARY_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
ENDIF()
IF (EQEMU_BUILD_STATIC)
SET(ZLIB_LIBRARY_LIBS libz.a)
ENDIF(EQEMU_BUILD_STATIC)
MESSAGE(STATUS "")
MESSAGE(STATUS "**************************************************")
MESSAGE(STATUS "* Library Usage *")
@@ -340,10 +349,8 @@ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigat
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/Recast/Include")
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/websocketpp")
OPTION(EQEMU_BUILD_LOGGING "Build Logging (To speed up compilation)" ON)
IF(EQEMU_BUILD_LOGGING)
ADD_DEFINITIONS(-DBUILD_LOGGING)
ENDIF()
# silence obnoxious deprecation message
ADD_DEFINITIONS(-DBOOST_BIND_GLOBAL_PLACEHOLDERS)
IF(TLS_LIBRARY_ENABLED)
SET(SERVER_LIBS ${SERVER_LIBS} ${TLS_LIBRARY_LIBS})
+3 -3
View File
@@ -1,7 +1,7 @@
# EQEmulator Core Server
|Travis CI (Linux)|Appveyor (Windows x86) |Appveyor (Windows x64) |
|:---:|:---:|:---:|
|[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/v3utuu0dttm2cqd0?svg=true)](https://ci.appveyor.com/project/KimLS/server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp) |
| Drone (Linux x64) | Drone (Windows x64) |
|:---:|:---:|
|[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |
***
-21
View File
@@ -1,21 +0,0 @@
version: 1.0.{build}
branches:
only:
- master
image: Visual Studio 2017
configuration: RelWithDebInfo
clone_folder: c:\projects\eqemu
init:
- ps: git config --global core.autocrlf input
cache: c:\tools\vcpkg\installed\
before_build:
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -EQEMU_ENABLE_BOTS=ON -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
build:
project: C:\projects\eqemu\build\EQEmu.sln
parallel: true
verbosity: minimal
after_build:
- cmd: >-
7z a build_x64-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
appveyor PushArtifact build_x64-bots.zip
-21
View File
@@ -1,21 +0,0 @@
version: 1.0.{build}
branches:
only:
- master
image: Visual Studio 2017
configuration: RelWithDebInfo
clone_folder: c:\projects\eqemu
init:
- ps: git config --global core.autocrlf input
cache: c:\tools\vcpkg\installed\
before_build:
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -EQEMU_ENABLE_BOTS=OFF -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
build:
project: C:\projects\eqemu\build\EQEmu.sln
parallel: true
verbosity: minimal
after_build:
- cmd: >-
7z a build_x64-no-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
appveyor PushArtifact build_x64-no-bots.zip
+1 -1
View File
@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
SET(export_sources
main.cpp
+3 -3
View File
@@ -86,7 +86,7 @@ int main(int argc, char **argv)
return 1;
}
} else {
content_db.SetMysql(database.getMySQL());
content_db.SetMySQL(database);
}
LogSys.SetDatabase(&database)
@@ -183,7 +183,7 @@ bool SkillUsable(SharedDatabase *db, int skill_id, int class_id)
}
auto row = results.begin();
if (row[0] && atoi(row[0]) > 0) {
if (row[0] && Strings::ToInt(row[0]) > 0) {
return true;
}
@@ -207,7 +207,7 @@ int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level)
}
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
void ExportSkillCaps(SharedDatabase *db)
+1 -1
View File
@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
SET(import_sources
main.cpp
+17 -17
View File
@@ -83,7 +83,7 @@ int main(int argc, char **argv) {
return 1;
}
} else {
content_db.SetMysql(database.getMySQL());
content_db.SetMySQL(database);
}
LogSys.SetDatabase(&database)
@@ -241,10 +241,10 @@ void ImportSkillCaps(SharedDatabase *db) {
}
int class_id, skill_id, level, cap;
class_id = atoi(split[0].c_str());
skill_id = atoi(split[1].c_str());
level = atoi(split[2].c_str());
cap = atoi(split[3].c_str());
class_id = Strings::ToInt(split[0].c_str());
skill_id = Strings::ToInt(split[1].c_str());
level = Strings::ToInt(split[2].c_str());
cap = Strings::ToInt(split[3].c_str());
std::string sql = StringFormat("INSERT INTO skill_caps(class, skillID, level, cap) VALUES(%d, %d, %d, %d)",
class_id, skill_id, level, cap);
@@ -280,16 +280,16 @@ void ImportBaseData(SharedDatabase *db) {
int level, class_id;
double hp, mana, end, unk1, unk2, hp_fac, mana_fac, end_fac;
level = atoi(split[0].c_str());
class_id = atoi(split[1].c_str());
hp = atof(split[2].c_str());
mana = atof(split[3].c_str());
end = atof(split[4].c_str());
unk1 = atof(split[5].c_str());
unk2 = atof(split[6].c_str());
hp_fac = atof(split[7].c_str());
mana_fac = atof(split[8].c_str());
end_fac = atof(split[9].c_str());
level = Strings::ToInt(split[0].c_str());
class_id = Strings::ToInt(split[1].c_str());
hp = Strings::ToFloat(split[2].c_str());
mana = Strings::ToFloat(split[3].c_str());
end = Strings::ToFloat(split[4].c_str());
unk1 = Strings::ToFloat(split[5].c_str());
unk2 = Strings::ToFloat(split[6].c_str());
hp_fac = Strings::ToFloat(split[7].c_str());
mana_fac = Strings::ToFloat(split[8].c_str());
end_fac = Strings::ToFloat(split[9].c_str());
sql = StringFormat("INSERT INTO base_data(level, class, hp, mana, end, unk1, unk2, hp_fac, "
"mana_fac, end_fac) VALUES(%d, %d, %f, %f, %f, %f, %f, %f, %f, %f)",
@@ -339,8 +339,8 @@ void ImportDBStrings(SharedDatabase *db) {
int id, type;
std::string value;
id = atoi(split[0].c_str());
type = atoi(split[1].c_str());
id = Strings::ToInt(split[0].c_str());
type = Strings::ToInt(split[1].c_str());
if(split.size() >= 3) {
value = ::Strings::Escape(split[2]);
+25 -9
View File
@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
SET(common_sources
base_packet.cpp
@@ -15,6 +15,9 @@ SET(common_sources
database.cpp
database_conversions.cpp
database_instances.cpp
database/database_update_manifest.cpp
database/database_update_manifest_bots.cpp
database/database_update.cpp
dbcore.cpp
deity.cpp
dynamic_zone_base.cpp
@@ -33,9 +36,11 @@ SET(common_sources
eq_stream_proxy.cpp
eqtime.cpp
event_sub.cpp
events/player_event_logs.cpp
events/player_event_discord_formatter.cpp
expedition_lockout_timer.cpp
extprofile.cpp
discord_manager.cpp
discord/discord_manager.cpp
faction.cpp
file.cpp
guild_base.cpp
@@ -64,6 +69,7 @@ SET(common_sources
path_manager.cpp
perl_eqdb.cpp
perl_eqdb_res.cpp
process/process.cpp
proc_launcher.cpp
profanity_manager.cpp
ptimer.cpp
@@ -181,6 +187,8 @@ SET(repositories
repositories/base/base_char_create_combinations_repository.h
repositories/base/base_char_create_point_allocations_repository.h
repositories/base/base_char_recipe_list_repository.h
repositories/base/base_chatchannels_repository.h
repositories/base/base_chatchannel_reserved_names_repository.h
repositories/base/base_completed_shared_tasks_repository.h
repositories/base/base_completed_shared_task_activity_state_repository.h
repositories/base/base_completed_shared_task_members_repository.h
@@ -195,7 +203,6 @@ SET(repositories
repositories/base/base_dynamic_zones_repository.h
repositories/base/base_dynamic_zone_members_repository.h
repositories/base/base_dynamic_zone_templates_repository.h
repositories/base/base_eventlog_repository.h
repositories/base/base_expeditions_repository.h
repositories/base/base_expedition_lockouts_repository.h
repositories/base/base_faction_association_repository.h
@@ -215,7 +222,6 @@ SET(repositories
repositories/base/base_guilds_repository.h
repositories/base/base_guild_ranks_repository.h
repositories/base/base_guild_relations_repository.h
repositories/base/base_hackers_repository.h
repositories/base/base_horses_repository.h
repositories/base/base_instance_list_repository.h
repositories/base/base_instance_list_player_repository.h
@@ -261,6 +267,8 @@ SET(repositories
repositories/base/base_pets_equipmentset_repository.h
repositories/base/base_pets_equipmentset_entries_repository.h
repositories/base/base_player_titlesets_repository.h
repositories/base/base_player_event_log_settings_repository.h
repositories/base/base_player_event_logs_repository.h
repositories/base/base_quest_globals_repository.h
repositories/base/base_raid_details_repository.h
repositories/base/base_raid_members_repository.h
@@ -357,6 +365,8 @@ SET(repositories
repositories/char_create_combinations_repository.h
repositories/char_create_point_allocations_repository.h
repositories/char_recipe_list_repository.h
repositories/chatchannels_repository.h
repositories/chatchannel_reserved_names_repository.h
repositories/completed_shared_tasks_repository.h
repositories/completed_shared_task_activity_state_repository.h
repositories/completed_shared_task_members_repository.h
@@ -371,7 +381,6 @@ SET(repositories
repositories/dynamic_zones_repository.h
repositories/dynamic_zone_members_repository.h
repositories/dynamic_zone_templates_repository.h
repositories/eventlog_repository.h
repositories/expeditions_repository.h
repositories/expedition_lockouts_repository.h
repositories/faction_association_repository.h
@@ -391,7 +400,6 @@ SET(repositories
repositories/guilds_repository.h
repositories/guild_ranks_repository.h
repositories/guild_relations_repository.h
repositories/hackers_repository.h
repositories/horses_repository.h
repositories/instance_list_repository.h
repositories/instance_list_player_repository.h
@@ -437,6 +445,8 @@ SET(repositories
repositories/pets_equipmentset_repository.h
repositories/pets_equipmentset_entries_repository.h
repositories/player_titlesets_repository.h
repositories/player_event_log_settings_repository.h
repositories/player_event_logs_repository.h
repositories/quest_globals_repository.h
repositories/raid_details_repository.h
repositories/raid_members_repository.h
@@ -499,10 +509,11 @@ SET(common_headers
data_verification.h
database.h
database_schema.h
database/database_update.h
dbcore.h
deity.h
discord/discord.h
discord_manager.h
discord/discord_manager.h
dynamic_zone_base.h
emu_constants.h
emu_limits.h
@@ -525,6 +536,9 @@ SET(common_headers
eq_stream_locator.h
eq_stream_proxy.h
eqtime.h
events/player_event_logs.h
events/player_event_discord_formatter.h
events/player_events.h
errmsg.h
event_sub.h
expedition_lockout_timer.h
@@ -568,6 +582,7 @@ SET(common_headers
packet_functions.h
path_manager.cpp
platform.h
process/process.h
proc_launcher.h
profanity_manager.h
profiler.h
@@ -597,11 +612,11 @@ SET(common_headers
unix.h
useperl.h
version.h
zone_numbers.h
zone_store.h
event/event_loop.h
event/task.h
event/timer.h
json/json_archive_single_line.h
json/json.h
json/json-forwards.h
net/console_server.h
@@ -650,12 +665,13 @@ SET(common_headers
patches/uf_limits.h
patches/uf_ops.h
patches/uf_structs.h
termcolor/rang.hpp
stacktrace/backward.hpp
StackWalker/StackWalker.h
util/memory_stream.h
util/directory.h
util/uuid.h
)
)
SOURCE_GROUP(Event FILES
event/event_loop.h
+78
View File
@@ -17,6 +17,7 @@
*/
#include "../common/global_define.h"
#include "../common/classes.h"
#include "data_verification.h"
const char *GetClassIDName(uint8 class_id, uint8 level)
{
@@ -630,6 +631,20 @@ bool IsINTCasterClass(uint8 class_id)
}
}
bool IsHeroicINTCasterClass(uint8 class_id)
{
switch (class_id) {
case NECROMANCER:
case WIZARD:
case MAGICIAN:
case ENCHANTER:
case SHADOWKNIGHT:
return true;
default:
return false;
}
}
bool IsWISCasterClass(uint8 class_id)
{
switch (class_id) {
@@ -642,6 +657,21 @@ bool IsWISCasterClass(uint8 class_id)
}
}
bool IsHeroicWISCasterClass(uint8 class_id)
{
switch (class_id) {
case CLERIC:
case DRUID:
case SHAMAN:
case PALADIN:
case BEASTLORD:
case RANGER:
return true;
default:
return false;
}
}
bool IsPlateClass(uint8 class_id)
{
switch (class_id) {
@@ -721,3 +751,51 @@ uint8 ClassArmorType(uint8 class_id)
return ARMOR_TYPE_UNKNOWN;
}
}
const std::string GetPlayerClassAbbreviation(uint8 class_id)
{
if (!EQ::ValueWithin(class_id, WARRIOR, BERSERKER)) {
return std::string("UNK");
}
switch (class_id) {
case WARRIOR:
return "WAR";
case CLERIC:
return "CLR";
case PALADIN:
return "PAL";
case RANGER:
return "RNG";
case SHADOWKNIGHT:
return "SHD";
case DRUID:
return "DRU";
case MONK:
return "MNK";
case BARD:
return "BRD";
case ROGUE:
return "ROG";
case SHAMAN:
return "SHM";
case NECROMANCER:
return "NEC";
case WIZARD:
return "WIZ";
case MAGICIAN:
return "MAG";
case ENCHANTER:
return "ENC";
case BEASTLORD:
return "BST";
case BERSERKER:
return "BER";
}
return std::string("UNK");
}
bool IsPlayerClass(uint8 class_id) {
return EQ::ValueWithin(class_id, WARRIOR, BERSERKER);
}
+7 -1
View File
@@ -19,7 +19,9 @@
#define CLASSES_CH
#include "../common/types.h"
#include <string>
#define NO_CLASS 0
#define WARRIOR 1
#define CLERIC 2
#define PALADIN 3
@@ -126,6 +128,9 @@
const char* GetClassIDName(uint8 class_id, uint8 level = 0);
const char* GetPlayerClassName(uint32 player_class_value, uint8 level = 0);
bool IsPlayerClass(uint8 class_id);
const std::string GetPlayerClassAbbreviation(uint8 class_id);
uint32 GetPlayerClassValue(uint8 class_id);
uint32 GetPlayerClassBit(uint8 class_id);
@@ -139,7 +144,8 @@ bool IsHybridClass(uint8 class_id);
bool IsCasterClass(uint8 class_id);
bool IsINTCasterClass(uint8 class_id);
bool IsWISCasterClass(uint8 class_id);
bool IsHeroicINTCasterClass(uint8 class_id);
bool IsHeroicWISCasterClass(uint8 class_id);
bool IsPlateClass(uint8 class_id);
bool IsChainClass(uint8 class_id);
bool IsLeatherClass(uint8 class_id);
+2 -2
View File
@@ -77,7 +77,7 @@ namespace EQEmuCommand {
index++;
}
if (!arguments_filled || argc == 2 || cmd[{"-h", "--help"}]) {
if (!arguments_filled || (argc == 2 && !cmd[{"-h", "--help"}]) || (argc == 3 && cmd[{"-h", "--help"}])) {
std::string arguments_string;
for (auto &arg : arguments) {
arguments_string += " " + arg;
@@ -160,7 +160,7 @@ namespace EQEmuCommand {
*/
std::string command_section;
for (auto &it: in_function_map) {
description = "";
description.clear();
(it.second)(argc, argv, cmd, description);
+1 -1
View File
@@ -120,7 +120,7 @@ std::vector<std::string> WorldContentService::GetContentFlagsDisabled()
/**
* @param content_flags
*/
void WorldContentService::SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags)
void WorldContentService::SetContentFlags(const std::vector<ContentFlagsRepository::ContentFlags>& content_flags)
{
WorldContentService::content_flags = content_flags;
}
+1 -1
View File
@@ -167,7 +167,7 @@ public:
std::vector<std::string> GetContentFlagsDisabled();
bool IsContentFlagEnabled(const std::string& content_flag);
bool IsContentFlagDisabled(const std::string& content_flag);
void SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags);
void SetContentFlags(const std::vector<ContentFlagsRepository::ContentFlags>& content_flags);
void ReloadContentFlags();
WorldContentService * SetExpansionContext();
+121 -47
View File
@@ -1,47 +1,94 @@
#include "global_define.h"
#include "eqemu_logsys.h"
#include "crash.h"
#include "strings.h"
#include "process/process.h"
#include "http/httplib.h"
#include "http/uri.h"
#include "json/json.h"
#include "version.h"
#include "eqemu_config.h"
#include "serverinfo.h"
#include "rulesys.h"
#include "platform.h"
inline std::string random_string(size_t length)
{
auto randchar = []() -> char {
const char charset[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[static_cast<size_t>(std::rand()) % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
}
#include <cstdio>
#include <vector>
std::string execute(const std::string &cmd, bool return_result = true)
{
std::string random = "/tmp/" + random_string(25);
const char *file_name = random.c_str();
if (return_result) {
#ifdef _WINDOWS
std::system((cmd + " > " + file_name + " 2>&1").c_str());
#else
std::system((cmd + " > " + file_name + " 2>&1").c_str());
#if WINDOWS
#define popen _popen
#endif
void SendCrashReport(const std::string &crash_report)
{
// can configure multiple endpoints if need be
std::vector<std::string> endpoints = {
"http://spire.akkadius.com/api/v1/analytics/server-crash-report",
// "http://localhost:3010/api/v1/analytics/server-crash-report", // development
};
auto config = EQEmuConfig::get();
for (auto &e: endpoints) {
uri u(e);
std::string base_url = fmt::format("{}://{}", u.get_scheme(), u.get_host());
if (u.get_port()) {
base_url += fmt::format(":{}", u.get_port());
}
// client
httplib::Client r(base_url);
r.set_connection_timeout(1, 0);
r.set_read_timeout(1, 0);
r.set_write_timeout(1, 0);
// os info
auto os = EQ::GetOS();
auto cpus = EQ::GetCPUs();
auto process_id = EQ::GetPID();
auto rss = EQ::GetRSS() / 1048576.0;
auto uptime = static_cast<uint32>(EQ::GetUptime());
// payload
Json::Value p;
p["platform_name"] = GetPlatformName();
p["crash_report"] = crash_report;
p["server_version"] = CURRENT_VERSION;
p["compile_date"] = COMPILE_DATE;
p["compile_time"] = COMPILE_TIME;
p["server_name"] = config->LongName;
p["server_short_name"] = config->ShortName;
p["uptime"] = uptime;
p["os_machine"] = os.machine;
p["os_release"] = os.release;
p["os_version"] = os.version;
p["os_sysname"] = os.sysname;
p["process_id"] = process_id;
p["rss_memory"] = rss;
p["cpus"] = cpus.size();
p["origination_info"] = "";
if (!LogSys.origination_info.zone_short_name.empty()) {
p["origination_info"] = fmt::format(
"{} ({}) instance_id [{}]",
LogSys.origination_info.zone_short_name,
LogSys.origination_info.zone_long_name,
LogSys.origination_info.instance_id
);
}
std::stringstream payload;
payload << p;
if (auto res = r.Post(e, payload.str(), "application/json")) {
if (res->status == 200) {
LogInfo("Sent crash report");
}
else {
LogError("Failed to send crash report to [{}]", e);
}
}
}
else {
std::system((cmd).c_str());
}
std::string result;
if (return_result) {
std::ifstream file(file_name);
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
std::remove(file_name);
}
return result;
}
#if defined(_WINDOWS) && defined(CRASH_LOGGING)
@@ -54,22 +101,30 @@ public:
EQEmuStackWalker(DWORD dwProcessId, HANDLE hProcess) : StackWalker(dwProcessId, hProcess) { }
virtual void OnOutput(LPCSTR szText) {
char buffer[4096];
for(int i = 0; i < 4096; ++i) {
if(szText[i] == 0) {
for (int i = 0; i < 4096; ++i) {
if (szText[i] == 0) {
buffer[i] = '\0';
break;
}
if(szText[i] == '\n' || szText[i] == '\r') {
if (szText[i] == '\n' || szText[i] == '\r') {
buffer[i] = ' ';
} else {
}
else {
buffer[i] = szText[i];
}
}
std::string line = buffer;
_lines.push_back(line);
Log(Logs::General, Logs::Crash, buffer);
StackWalker::OnOutput(szText);
}
const std::vector<std::string>& GetLines() { return _lines; }
private:
std::vector<std::string> _lines;
};
LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
@@ -143,7 +198,20 @@ LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
if(EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode)
{
EQEmuStackWalker sw; sw.ShowCallstack(GetCurrentThread(), ExceptionInfo->ContextRecord);
EQEmuStackWalker sw;
sw.ShowCallstack(GetCurrentThread(), ExceptionInfo->ContextRecord);
if (RuleB(Analytics, CrashReporting)) {
std::string crash_report;
auto& lines = sw.GetLines();
for (auto& line : lines) {
crash_report += line;
crash_report += "\n";
}
SendCrashReport(crash_report);
}
}
return EXCEPTION_EXECUTE_HANDLER;
@@ -167,7 +235,7 @@ void set_exception_handler() {
void print_trace()
{
bool does_gdb_exist = execute("gdb -v").find("GNU") != std::string::npos;
bool does_gdb_exist = Strings::Contains(Process::execute("gdb -v"), "GNU");
if (!does_gdb_exist) {
LogCrash(
"[Error] GDB is not installed, if you want crash dumps on Linux to work properly you will need GDB installed"
@@ -176,12 +244,12 @@ void print_trace()
}
auto uid = geteuid();
std::string temp_output_file = "/tmp/dump-output";
std::string temp_output_file = fmt::format("/tmp/dump-output-{}", Strings::Random(10));
// check for passwordless sudo if not root
if (uid != 0) {
bool has_passwordless_sudo = execute("sudo -n true").find("a password is required") == std::string::npos;
if (!has_passwordless_sudo) {
bool sudo_password_required = Strings::Contains(Process::execute("sudo -n true"), "a password is required");
if (sudo_password_required) {
LogCrash(
"[Error] Current user does not have passwordless sudo installed. It is required to automatically process crash dumps with GDB as non-root."
);
@@ -210,16 +278,22 @@ void print_trace()
abort(); /* If gdb failed to start */
}
else {
waitpid(child_pid, NULL, 0);
waitpid(child_pid, nullptr, 0);
}
std::ifstream input(temp_output_file);
std::string crash_report;
for (std::string line; getline(input, line);) {
LogCrash("{}", line);
crash_report += fmt::format("{}\n", line);
}
std::remove(temp_output_file.c_str());
if (RuleB(Analytics, CrashReporting)) {
SendCrashReport(crash_report);
}
exit(1);
}
+1 -1
View File
@@ -313,7 +313,7 @@ namespace cron
{
try
{
return static_cast<cron_int>(std::stoul(text.data()));
return static_cast<cron_int>(Strings::ToUnsignedInt(text.data()));
}
catch (std::exception const & ex)
{
+290 -255
View File
@@ -71,11 +71,11 @@ bool Database::Connect(const char* host, const char* user, const char* passwd, c
uint32 errnum= 0;
char errbuf[MYSQL_ERRMSG_SIZE];
if (!Open(host, user, passwd, database, port, &errnum, errbuf)) {
LogError("[MySQL] Connection [{}] Failed to connect to database: Error [{}]", connection_label, errbuf);
LogError("Connection [{}] Failed to connect to database Error [{}]", connection_label, errbuf);
return false;
}
else {
LogInfo("[MySQL] Connection [{}] database [{}] at [{}]:[{}]", connection_label, database, host,port);
LogInfo("Connected to database [{}] [{}] @ [{}:{}]", connection_label, database, host,port);
return true;
}
}
@@ -121,10 +121,10 @@ uint32 Database::CheckLogin(const char* name, const char* password, const char *
auto row = results.begin();
auto id = std::stoul(row[0]);
auto id = Strings::ToUnsignedInt(row[0]);
if (oStatus) {
*oStatus = std::stoi(row[1]);
*oStatus = Strings::ToInt(row[1]);
}
return id;
@@ -202,11 +202,11 @@ int16 Database::CheckStatus(uint32 account_id)
}
auto row = results.begin();
int16 status = std::stoi(row[0]);
int16 status = Strings::ToInt(row[0]);
int32 date_diff = 0;
if (row[1]) {
date_diff = std::stoi(row[1]);
date_diff = Strings::ToInt(row[1]);
}
if (date_diff > 0) {
@@ -345,7 +345,7 @@ bool Database::ReserveName(uint32 account_id, char* name) {
std::string query = StringFormat("SELECT `account_id`, `name` FROM `character_data` WHERE `name` = '%s'", name);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
if (row[0] && atoi(row[0]) > 0){
if (row[0] && Strings::ToInt(row[0]) > 0){
LogInfo("Account: [{}] tried to request name: [{}], but it is already taken", account_id, name);
return false;
}
@@ -353,7 +353,7 @@ bool Database::ReserveName(uint32 account_id, char* name) {
query = StringFormat("INSERT INTO `character_data` SET `account_id` = %i, `name` = '%s'", account_id, name);
results = QueryDatabase(query);
if (!results.Success() || results.ErrorMessage() != ""){ return false; }
if (!results.Success() || !results.ErrorMessage().empty()){ return false; }
// Put character into the default guild if rule is being used.
int guild_id = RuleI(Character, DefaultGuild);
@@ -363,7 +363,7 @@ bool Database::ReserveName(uint32 account_id, char* name) {
if (character_id > -1) {
query = StringFormat("INSERT INTO `guild_members` SET `char_id` = %i, `guild_id` = '%i'", character_id, guild_id);
results = QueryDatabase(query);
if (!results.Success() || results.ErrorMessage() != ""){
if (!results.Success() || !results.ErrorMessage().empty()){
LogInfo("Could not put character [{}] into default Guild", name);
}
}
@@ -387,19 +387,14 @@ bool Database::DeleteCharacter(char *character_name)
std::string query = StringFormat("SELECT `id` from `character_data` WHERE `name` = '%s'", character_name);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
character_id = atoi(row[0]);
character_id = Strings::ToUnsignedInt(row[0]);
}
if (character_id <= 0) {
LogError("[DeleteCharacter] Invalid Character ID [{}]", character_name);
LogError("Invalid Character ID [{}]", character_name);
return false;
}
#ifdef BOTS
query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", character_id); // note: only use of GetMobTypeById()
QueryDatabase(query);
#endif
std::string delete_type = "hard-deleted";
if (RuleB(Character, SoftDeletes)) {
delete_type = "soft-deleted";
@@ -418,21 +413,26 @@ bool Database::DeleteCharacter(char *character_name)
QueryDatabase(query);
#ifdef BOTS
query = fmt::format(
SQL(
UPDATE
bot_data
SET
name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64)
WHERE
owner_id = '{}'
),
character_id
);
QueryDatabase(query);
LogInfo("[DeleteCharacter] character_name [{}] ({}) bots are being [{}]", character_name, character_id, delete_type);
#endif
if (RuleB(Bots, Enabled)) {
query = fmt::format(
SQL(
UPDATE
bot_data
SET
name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64)
WHERE
owner_id = '{}'
),
character_id
);
QueryDatabase(query);
LogInfo(
"[DeleteCharacter] character_name [{}] ({}) bots are being [{}]",
character_name,
character_id,
delete_type
);
}
return true;
}
@@ -444,12 +444,13 @@ bool Database::DeleteCharacter(char *character_name)
QueryDatabase(fmt::format("DELETE FROM {} WHERE {} = {}", table_name, character_id_column_name, character_id));
}
LogInfo("[DeleteCharacter] character_name [{}] ({}) is being [{}]", character_name, character_id, delete_type);
LogInfo("character_name [{}] ({}) is being [{}]", character_name, character_id, delete_type);
return true;
}
bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp){
bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp)
{
std::string query = StringFormat(
"REPLACE INTO `character_data` ("
"id,"
@@ -634,101 +635,102 @@ bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, Playe
"%u," // guild_auto_consent
"%u" // RestTimer
")",
character_id, // " id, "
account_id, // " account_id, "
Strings::Escape(pp->name).c_str(), // " `name`, "
character_id, // " id, "
account_id, // " account_id, "
Strings::Escape(pp->name).c_str(), // " `name`, "
Strings::Escape(pp->last_name).c_str(), // " last_name, "
pp->gender, // " gender, "
pp->race, // " race, "
pp->class_, // " class, "
pp->level, // " `level`, "
pp->deity, // " deity, "
pp->birthday, // " birthday, "
pp->lastlogin, // " last_login, "
pp->timePlayedMin, // " time_played, "
pp->pvp, // " pvp_status, "
pp->level2, // " level2, "
pp->anon, // " anon, "
pp->gm, // " gm, "
pp->intoxication, // " intoxication, "
pp->haircolor, // " hair_color, "
pp->beardcolor, // " beard_color, "
pp->eyecolor1, // " eye_color_1, "
pp->eyecolor2, // " eye_color_2, "
pp->hairstyle, // " hair_style, "
pp->beard, // " beard, "
pp->ability_time_seconds, // " ability_time_seconds, "
pp->ability_number, // " ability_number, "
pp->ability_time_minutes, // " ability_time_minutes, "
pp->ability_time_hours, // " ability_time_hours, "
pp->gender, // " gender, "
pp->race, // " race, "
pp->class_, // " class, "
pp->level, // " `level`, "
pp->deity, // " deity, "
pp->birthday, // " birthday, "
pp->lastlogin, // " last_login, "
pp->timePlayedMin, // " time_played, "
pp->pvp, // " pvp_status, "
pp->level2, // " level2, "
pp->anon, // " anon, "
pp->gm, // " gm, "
pp->intoxication, // " intoxication, "
pp->haircolor, // " hair_color, "
pp->beardcolor, // " beard_color, "
pp->eyecolor1, // " eye_color_1, "
pp->eyecolor2, // " eye_color_2, "
pp->hairstyle, // " hair_style, "
pp->beard, // " beard, "
pp->ability_time_seconds, // " ability_time_seconds, "
pp->ability_number, // " ability_number, "
pp->ability_time_minutes, // " ability_time_minutes, "
pp->ability_time_hours, // " ability_time_hours, "
Strings::Escape(pp->title).c_str(), // " title, "
Strings::Escape(pp->suffix).c_str(), // " suffix, "
pp->exp, // " exp, "
pp->points, // " points, "
pp->mana, // " mana, "
pp->cur_hp, // " cur_hp, "
pp->STR, // " str, "
pp->STA, // " sta, "
pp->CHA, // " cha, "
pp->DEX, // " dex, "
pp->INT, // " `int`, "
pp->AGI, // " agi, "
pp->WIS, // " wis, "
pp->face, // " face, "
pp->y, // " y, "
pp->x, // " x, "
pp->z, // " z, "
pp->heading, // " heading, "
pp->pvp2, // " pvp2, "
pp->pvptype, // " pvp_type, "
pp->autosplit, // " autosplit_enabled, "
pp->zone_change_count, // " zone_change_count, "
pp->drakkin_heritage, // " drakkin_heritage, "
pp->drakkin_tattoo, // " drakkin_tattoo, "
pp->drakkin_details, // " drakkin_details, "
pp->toxicity, // " toxicity, "
pp->hunger_level, // " hunger_level, "
pp->thirst_level, // " thirst_level, "
pp->ability_up, // " ability_up, "
pp->zone_id, // " zone_id, "
pp->zoneInstance, // " zone_instance, "
pp->leadAAActive, // " leadership_exp_on, "
pp->ldon_points_guk, // " ldon_points_guk, "
pp->ldon_points_mir, // " ldon_points_mir, "
pp->ldon_points_mmc, // " ldon_points_mmc, "
pp->ldon_points_ruj, // " ldon_points_ruj, "
pp->ldon_points_tak, // " ldon_points_tak, "
pp->ldon_points_available, // " ldon_points_available, "
pp->tribute_time_remaining, // " tribute_time_remaining, "
pp->showhelm, // " show_helm, "
pp->career_tribute_points, // " career_tribute_points, "
pp->tribute_points, // " tribute_points, "
pp->tribute_active, // " tribute_active, "
pp->endurance, // " endurance, "
pp->group_leadership_exp, // " group_leadership_exp, "
pp->raid_leadership_exp, // " raid_leadership_exp, "
pp->group_leadership_points, // " group_leadership_points, "
pp->raid_leadership_points, // " raid_leadership_points, "
pp->air_remaining, // " air_remaining, "
pp->PVPKills, // " pvp_kills, "
pp->PVPDeaths, // " pvp_deaths, "
pp->PVPCurrentPoints, // " pvp_current_points, "
pp->PVPCareerPoints, // " pvp_career_points, "
pp->PVPBestKillStreak, // " pvp_best_kill_streak, "
pp->PVPWorstDeathStreak, // " pvp_worst_death_streak, "
pp->PVPCurrentKillStreak, // " pvp_current_kill_streak, "
pp->aapoints_spent, // " aa_points_spent, "
pp->expAA, // " aa_exp, "
pp->aapoints, // " aa_points, "
pp->groupAutoconsent, // " group_auto_consent, "
pp->raidAutoconsent, // " raid_auto_consent, "
pp->guildAutoconsent, // " guild_auto_consent, "
pp->RestTimer // " RestTimer) "
pp->exp, // " exp, "
pp->points, // " points, "
pp->mana, // " mana, "
pp->cur_hp, // " cur_hp, "
pp->STR, // " str, "
pp->STA, // " sta, "
pp->CHA, // " cha, "
pp->DEX, // " dex, "
pp->INT, // " `int`, "
pp->AGI, // " agi, "
pp->WIS, // " wis, "
pp->face, // " face, "
pp->y, // " y, "
pp->x, // " x, "
pp->z, // " z, "
pp->heading, // " heading, "
pp->pvp2, // " pvp2, "
pp->pvptype, // " pvp_type, "
pp->autosplit, // " autosplit_enabled, "
pp->zone_change_count, // " zone_change_count, "
pp->drakkin_heritage, // " drakkin_heritage, "
pp->drakkin_tattoo, // " drakkin_tattoo, "
pp->drakkin_details, // " drakkin_details, "
pp->toxicity, // " toxicity, "
pp->hunger_level, // " hunger_level, "
pp->thirst_level, // " thirst_level, "
pp->ability_up, // " ability_up, "
pp->zone_id, // " zone_id, "
pp->zoneInstance, // " zone_instance, "
pp->leadAAActive, // " leadership_exp_on, "
pp->ldon_points_guk, // " ldon_points_guk, "
pp->ldon_points_mir, // " ldon_points_mir, "
pp->ldon_points_mmc, // " ldon_points_mmc, "
pp->ldon_points_ruj, // " ldon_points_ruj, "
pp->ldon_points_tak, // " ldon_points_tak, "
pp->ldon_points_available, // " ldon_points_available, "
pp->tribute_time_remaining, // " tribute_time_remaining, "
pp->showhelm, // " show_helm, "
pp->career_tribute_points, // " career_tribute_points, "
pp->tribute_points, // " tribute_points, "
pp->tribute_active, // " tribute_active, "
pp->endurance, // " endurance, "
pp->group_leadership_exp, // " group_leadership_exp, "
pp->raid_leadership_exp, // " raid_leadership_exp, "
pp->group_leadership_points, // " group_leadership_points, "
pp->raid_leadership_points, // " raid_leadership_points, "
pp->air_remaining, // " air_remaining, "
pp->PVPKills, // " pvp_kills, "
pp->PVPDeaths, // " pvp_deaths, "
pp->PVPCurrentPoints, // " pvp_current_points, "
pp->PVPCareerPoints, // " pvp_career_points, "
pp->PVPBestKillStreak, // " pvp_best_kill_streak, "
pp->PVPWorstDeathStreak, // " pvp_worst_death_streak, "
pp->PVPCurrentKillStreak, // " pvp_current_kill_streak, "
pp->aapoints_spent, // " aa_points_spent, "
pp->expAA, // " aa_exp, "
pp->aapoints, // " aa_points, "
pp->groupAutoconsent, // " group_auto_consent, "
pp->raidAutoconsent, // " raid_auto_consent, "
pp->guildAutoconsent, // " guild_auto_consent, "
pp->RestTimer // " RestTimer) "
);
auto results = QueryDatabase(query);
QueryDatabase(query);
/* Save Bind Points */
query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)"
query = StringFormat(
"REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)"
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i), "
"(%u, %u, %u, %f, %f, %f, %f, %i), "
"(%u, %u, %u, %f, %f, %f, %f, %i), "
@@ -739,57 +741,73 @@ bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, Playe
character_id, pp->binds[2].zone_id, 0, pp->binds[2].x, pp->binds[2].y, pp->binds[2].z, pp->binds[2].heading, 2,
character_id, pp->binds[3].zone_id, 0, pp->binds[3].x, pp->binds[3].y, pp->binds[3].z, pp->binds[3].heading, 3,
character_id, pp->binds[4].zone_id, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading, 4
); results = QueryDatabase(query);
);
QueryDatabase(query);
/* HoTT Ability */
if(RuleB(Character, GrantHoTTOnCreate))
{
query = StringFormat("INSERT INTO `character_leadership_abilities` (id, slot, `rank`) VALUES (%u, %i, %i)", character_id, 14, 1);
results = QueryDatabase(query);
}
/* HoTT Ability */
if (RuleB(Character, GrantHoTTOnCreate)) {
query = StringFormat(
"INSERT INTO `character_leadership_abilities` (id, slot, `rank`) VALUES (%u, %i, %i)",
character_id,
14,
1
);
QueryDatabase(query);
}
/* Save Skills */
int firstquery = 0;
for (int i = 0; i < MAX_PP_SKILL; i++){
if (pp->skills[i] > 0){
if (firstquery != 1){
int firstquery = 0;
for (int i = 0; i < MAX_PP_SKILL; i++) {
if (pp->skills[i] > 0) {
if (firstquery != 1) {
firstquery = 1;
query = StringFormat("REPLACE INTO `character_skills` (id, skill_id, value) VALUES (%u, %u, %u)", character_id, i, pp->skills[i]);
}
else{
query = StringFormat(
"REPLACE INTO `character_skills` (id, skill_id, value) VALUES (%u, %u, %u)",
character_id,
i,
pp->skills[i]
);
} else {
query = query + StringFormat(", (%u, %u, %u)", character_id, i, pp->skills[i]);
}
}
}
results = QueryDatabase(query);
QueryDatabase(query);
/* Save Language */
firstquery = 0;
for (int i = 0; i < MAX_PP_LANGUAGE; i++){
if (pp->languages[i] > 0){
if (firstquery != 1){
for (int i = 0; i < MAX_PP_LANGUAGE; i++) {
if (pp->languages[i] > 0) {
if (firstquery != 1) {
firstquery = 1;
query = StringFormat("REPLACE INTO `character_languages` (id, lang_id, value) VALUES (%u, %u, %u)", character_id, i, pp->languages[i]);
}
else{
query = StringFormat(
"REPLACE INTO `character_languages` (id, lang_id, value) VALUES (%u, %u, %u)",
character_id,
i,
pp->languages[i]
);
} else {
query = query + StringFormat(", (%u, %u, %u)", character_id, i, pp->languages[i]);
}
}
}
results = QueryDatabase(query);
QueryDatabase(query);
return true;
}
uint32 Database::GetCharacterID(const char *name) {
std::string query = StringFormat("SELECT `id` FROM `character_data` WHERE `name` = '%s'", name);
const auto query = fmt::format(
"SELECT `id` FROM `character_data` WHERE `name` = '{}'",
Strings::Escape(name)
);
auto results = QueryDatabase(query);
auto row = results.begin();
if (results.RowCount() == 1)
{
return atoi(row[0]);
if (!results.Success() || !results.RowCount()) {
return 0;
}
return 0;
auto row = results.begin();
return Strings::ToUnsignedInt(row[0]);
}
/*
@@ -812,10 +830,10 @@ uint32 Database::GetAccountIDByChar(const char* charname, uint32* oCharID) {
auto row = results.begin();
uint32 accountId = atoi(row[0]);
uint32 accountId = Strings::ToUnsignedInt(row[0]);
if (oCharID)
*oCharID = atoi(row[1]);
*oCharID = Strings::ToUnsignedInt(row[1]);
return accountId;
}
@@ -832,7 +850,7 @@ uint32 Database::GetAccountIDByChar(uint32 char_id) {
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
uint32 Database::GetAccountIDByName(std::string account_name, std::string loginserver, int16* status, uint32* lsid) {
@@ -852,14 +870,14 @@ uint32 Database::GetAccountIDByName(std::string account_name, std::string logins
}
auto row = results.begin();
auto account_id = std::stoul(row[0]);
auto account_id = Strings::ToUnsignedInt(row[0]);
if (status) {
*status = static_cast<int16>(std::stoi(row[1]));
*status = static_cast<int16>(Strings::ToInt(row[1]));
}
if (lsid) {
*lsid = row[2] ? std::stoul(row[2]) : 0;
*lsid = row[2] ? Strings::ToUnsignedInt(row[2]) : 0;
}
return account_id;
@@ -880,7 +898,7 @@ void Database::GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID
strcpy(name, row[0]);
if (row[1] && oLSAccountID) {
*oLSAccountID = atoi(row[1]);
*oLSAccountID = Strings::ToUnsignedInt(row[1]);
}
}
@@ -968,13 +986,15 @@ bool Database::LoadVariables() {
std::string key, value;
for (auto row = results.begin(); row != results.end(); ++row) {
varcache.last_update = atoi(row[2]); // ahh should we be comparing if this is newer?
varcache.last_update = Strings::ToUnsignedInt(row[2]); // ahh should we be comparing if this is newer?
key = row[0];
value = row[1];
std::transform(std::begin(key), std::end(key), std::begin(key), ::tolower); // keys are lower case, DB doesn't have to be
varcache.Add(key, value);
}
LogInfo("Loaded [{}] variable(s)", Strings::Commify(std::to_string(results.RowCount())));
return true;
}
@@ -997,7 +1017,7 @@ bool Database::GetVariable(std::string varname, std::string &varvalue)
return false;
}
bool Database::SetVariable(const std::string varname, const std::string &varvalue)
bool Database::SetVariable(const std::string& varname, const std::string &varvalue)
{
std::string escaped_name = Strings::Escape(varname);
std::string escaped_value = Strings::Escape(varvalue);
@@ -1050,15 +1070,15 @@ bool Database::GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zon
auto row = results.begin();
if(graveyard_zoneid != nullptr)
*graveyard_zoneid = atoi(row[0]);
*graveyard_zoneid = Strings::ToUnsignedInt(row[0]);
if(graveyard_x != nullptr)
*graveyard_x = atof(row[1]);
*graveyard_x = Strings::ToFloat(row[1]);
if(graveyard_y != nullptr)
*graveyard_y = atof(row[2]);
*graveyard_y = Strings::ToFloat(row[2]);
if(graveyard_z != nullptr)
*graveyard_z = atof(row[3]);
*graveyard_z = Strings::ToFloat(row[3]);
if(graveyard_heading != nullptr)
*graveyard_heading = atof(row[4]);
*graveyard_heading = Strings::ToFloat(row[4]);
return true;
}
@@ -1166,13 +1186,13 @@ uint32 Database::GetAccountIDFromLSID(
}
for (auto row = results.begin(); row != results.end(); ++row) {
account_id = std::stoi(row[0]);
account_id = Strings::ToUnsignedInt(row[0]);
if (in_account_name) {
strcpy(in_account_name, row[1]);
}
if (in_status) {
*in_status = std::stoi(row[2]);
*in_status = Strings::ToInt(row[2]);
}
}
@@ -1196,7 +1216,7 @@ void Database::GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus) {
if (oAccountName)
strcpy(oAccountName, row[0]);
if (oStatus)
*oStatus = atoi(row[1]);
*oStatus = Strings::ToInt(row[1]);
}
void Database::ClearMerchantTemp(){
@@ -1242,7 +1262,7 @@ uint8 Database::GetServerType() {
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
bool Database::MoveCharacterToZone(uint32 character_id, uint32 zone_id)
@@ -1279,44 +1299,6 @@ bool Database::MoveCharacterToZone(const char *charname, uint32 zone_id)
return results.RowsAffected() != 0;
}
bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
std::string query = StringFormat("INSERT INTO `hackers` (account, name, hacked) values('%s','%s','%s')", accountname, charactername, hacked);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
return results.RowsAffected() != 0;
}
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) {
//Utilize the "hacker" table, but also give zone information.
std::string query = StringFormat("INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone);
auto results = QueryDatabase(query);
if (!results.Success())
{
return false;
}
return results.RowsAffected() != 0;
}
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const std::string &hacked, const char* zone) {
//Utilize the "hacker" table, but also give zone information.
auto query = fmt::format("INSERT INTO hackers(account, name, hacked, zone) values('{}', '{}', '{}', '{}')",
accountname, charactername, hacked, zone);
auto results = QueryDatabase(query);
if (!results.Success())
{
return false;
}
return results.RowsAffected() != 0;
}
uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
{
uint16 race_cap = 0;
@@ -1332,7 +1314,7 @@ uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level)
@@ -1348,12 +1330,12 @@ uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16
if (results.Success() && results.RowsAffected() != 0)
{
auto row = results.begin();
skill_level = atoi(row[0]);
skill_formula = atoi(row[1]);
skill_cap = atoi(row[2]);
if (atoi(row[3]) > skill_cap)
skill_cap2 = (atoi(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
skill_cap3 = atoi(row[4]);
skill_level = Strings::ToUnsignedInt(row[0]);
skill_formula = Strings::ToUnsignedInt(row[1]);
skill_cap = Strings::ToUnsignedInt(row[2]);
if (Strings::ToUnsignedInt(row[3]) > skill_cap)
skill_cap2 = (Strings::ToUnsignedInt(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
skill_cap3 = Strings::ToUnsignedInt(row[4]);
}
int race_skill = GetRaceSkill(skillid,in_race);
@@ -1398,10 +1380,10 @@ uint32 Database::GetCharacterInfo(std::string character_name, uint32 *account_id
}
auto row = results.begin();
auto character_id = std::stoul(row[0]);
*account_id = std::stoul(row[1]);
*zone_id = std::stoul(row[2]);
*instance_id = std::stoul(row[3]);
auto character_id = Strings::ToUnsignedInt(row[0]);
*account_id = Strings::ToUnsignedInt(row[1]);
*zone_id = Strings::ToUnsignedInt(row[2]);
*instance_id = Strings::ToUnsignedInt(row[3]);
return character_id;
}
@@ -1524,7 +1506,7 @@ uint32 Database::GetGroupID(const char* name){
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
std::string Database::GetGroupLeaderForLogin(std::string character_name) {
@@ -1538,7 +1520,7 @@ std::string Database::GetGroupLeaderForLogin(std::string character_name) {
if (results.Success() && results.RowCount()) {
auto row = results.begin();
group_id = std::stoul(row[0]);
group_id = Strings::ToUnsignedInt(row[0]);
}
if (!group_id) {
@@ -1627,7 +1609,7 @@ char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* mainta
strcpy(mentoree, row[5]);
if (mentor_percent)
*mentor_percent = atoi(row[6]);
*mentor_percent = Strings::ToInt(row[6]);
if(GLAA && results.LengthOfColumn(7) == sizeof(GroupLeadershipAA_Struct))
memcpy(GLAA, row[7], sizeof(GroupLeadershipAA_Struct));
@@ -1674,7 +1656,7 @@ uint8 Database::GetAgreementFlag(uint32 acctid) {
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
void Database::SetAgreementFlag(uint32 acctid) {
@@ -1760,7 +1742,7 @@ uint32 Database::GetRaidID(const char* name)
}
if (row[0]) // would it ever be possible to have a null here?
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
return 0;
}
@@ -1843,7 +1825,7 @@ void Database::GetGroupLeadershipInfo(uint32 gid, uint32 rid, char *maintank,
strcpy(mentoree, row[4]);
if (mentor_percent)
*mentor_percent = atoi(row[5]);
*mentor_percent = Strings::ToInt(row[5]);
if (GLAA && results.LengthOfColumn(6) == sizeof(GroupLeadershipAA_Struct))
memcpy(GLAA, row[6], sizeof(GroupLeadershipAA_Struct));
@@ -2016,16 +1998,16 @@ bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
auto row = results.begin();
as->success.guk = atoi(row[0]);
as->success.mir = atoi(row[1]);
as->success.mmc = atoi(row[2]);
as->success.ruj = atoi(row[3]);
as->success.tak = atoi(row[4]);
as->failure.guk = atoi(row[5]);
as->failure.mir = atoi(row[6]);
as->failure.mmc = atoi(row[7]);
as->failure.ruj = atoi(row[8]);
as->failure.tak = atoi(row[9]);
as->success.guk = Strings::ToUnsignedInt(row[0]);
as->success.mir = Strings::ToUnsignedInt(row[1]);
as->success.mmc = Strings::ToUnsignedInt(row[2]);
as->success.ruj = Strings::ToUnsignedInt(row[3]);
as->success.tak = Strings::ToUnsignedInt(row[4]);
as->failure.guk = Strings::ToUnsignedInt(row[5]);
as->failure.mir = Strings::ToUnsignedInt(row[6]);
as->failure.mmc = Strings::ToUnsignedInt(row[7]);
as->failure.ruj = Strings::ToUnsignedInt(row[8]);
as->failure.tak = Strings::ToUnsignedInt(row[9]);
as->failure.total = as->failure.guk + as->failure.mir + as->failure.mmc + as->failure.ruj + as->failure.tak;
as->success.total = as->success.guk + as->success.mir + as->success.mmc + as->success.ruj + as->success.tak;
@@ -2044,7 +2026,7 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
uint32 Database::GetGroupIDByCharID(uint32 character_id)
@@ -2066,7 +2048,7 @@ uint32 Database::GetGroupIDByCharID(uint32 character_id)
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
uint32 Database::GetRaidIDByCharID(uint32 character_id) {
@@ -2079,10 +2061,12 @@ uint32 Database::GetRaidIDByCharID(uint32 character_id) {
character_id
);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
return atoi(row[0]);
if (!results.Success() || !results.RowCount()) {
return 0;
}
return 0;
auto row = results.begin();
return Strings::ToUnsignedInt(row[0]);
}
int Database::CountInvSnapshots() {
@@ -2094,7 +2078,7 @@ int Database::CountInvSnapshots() {
auto row = results.begin();
int64 count = atoll(row[0]);
int64 count = Strings::ToBigInt(row[0]);
if (count > 2147483647)
return -2;
if (count < 0)
@@ -2125,17 +2109,17 @@ struct TimeOfDay_Struct Database::LoadTime(time_t &realtime)
eqTime.day = 1;
eqTime.month = 1;
eqTime.year = 3100;
realtime = time(0);
realtime = time(nullptr);
}
else{
auto row = results.begin();
eqTime.minute = atoi(row[0]);
eqTime.hour = atoi(row[1]);
eqTime.day = atoi(row[2]);
eqTime.month = atoi(row[3]);
eqTime.year = atoi(row[4]);
realtime = atoi(row[5]);
eqTime.minute = Strings::ToUnsignedInt(row[0]);
eqTime.hour = Strings::ToUnsignedInt(row[1]);
eqTime.day = Strings::ToUnsignedInt(row[2]);
eqTime.month = Strings::ToUnsignedInt(row[3]);
eqTime.year = Strings::ToUnsignedInt(row[4]);
realtime = Strings::ToBigInt(row[5]);
}
return eqTime;
@@ -2162,7 +2146,7 @@ int Database::GetIPExemption(std::string account_ip) {
}
auto row = results.begin();
return std::stoi(row[0]);
return Strings::ToInt(row[0]);
}
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
@@ -2176,7 +2160,7 @@ void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
auto results = QueryDatabase(query);
if (results.Success() && results.RowCount()) {
auto row = results.begin();
exemption_id = std::stoul(row[0]);
exemption_id = Strings::ToUnsignedInt(row[0]);
}
query = fmt::format(
@@ -2202,7 +2186,7 @@ int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
if (results.Success() && results.RowCount() > 0) {
auto row = results.begin();
return atoi(row[0]);;
return Strings::ToInt(row[0]);;
}
return 0;
@@ -2308,7 +2292,6 @@ bool Database::CopyCharacter(
new_rows.emplace_back(new_values);
}
std::string insert_values;
std::vector<std::string> insert_rows;
for (auto &r: new_rows) {
@@ -2354,7 +2337,7 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
uri request_uri(url);
LogHTTP(
"[SourceDatabaseTableFromUrl] parsing url [{}] path [{}] host [{}] query_string [{}] protocol [{}] port [{}]",
"parsing url [{}] path [{}] host [{}] query_string [{}] protocol [{}] port [{}]",
url,
request_uri.get_path(),
request_uri.get_host(),
@@ -2364,7 +2347,7 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
);
if (!DoesTableExist(table_name)) {
LogMySQLQuery("Table [{}] does not exist. Downloading from Github and installing...", table_name);
LogMySQLQuery("Table [{}] does not exist. Downloading and installing...", table_name);
// http get request
httplib::Client cli(
@@ -2372,7 +2355,7 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
"{}://{}",
request_uri.get_scheme(),
request_uri.get_host()
).c_str()
)
);
cli.set_connection_timeout(0, 60000000); // 60 sec
@@ -2381,7 +2364,7 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
int sourced_queries = 0;
if (auto res = cli.Get(request_uri.get_path().c_str())) {
if (auto res = cli.Get(request_uri.get_path())) {
if (res->status == 200) {
for (auto &s: Strings::Split(res->body, ';')) {
if (!Strings::Trim(s).empty()) {
@@ -2408,7 +2391,7 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
}
catch (std::invalid_argument iae) {
LogError("[SourceDatabaseTableFromUrl] URI parser error [{}]", iae.what());
LogError("URI parser error [{}]", iae.what());
}
}
@@ -2425,3 +2408,55 @@ uint8 Database::GetMinStatus(uint32 zone_id, uint32 instance_version)
return !zones.empty() ? zones[0].min_status : 0;
}
void Database::SourceSqlFromUrl(std::string url)
{
try {
uri request_uri(url);
LogHTTPDetail(
"parsing url [{}] path [{}] host [{}] query_string [{}] protocol [{}] port [{}]",
url,
request_uri.get_path(),
request_uri.get_host(),
request_uri.get_query(),
request_uri.get_scheme(),
request_uri.get_port()
);
LogInfo("Downloading and installing from [{}]", url);
// http get request
httplib::Client cli(
fmt::format(
"{}://{}",
request_uri.get_scheme(),
request_uri.get_host()
)
);
cli.set_connection_timeout(0, 60000000); // 60 sec
cli.set_read_timeout(60, 0); // 60 seconds
cli.set_write_timeout(60, 0); // 60 seconds
if (auto res = cli.Get(request_uri.get_path())) {
if (res->status == 200) {
auto results = QueryDatabaseMulti(res->body);
if (!results.ErrorMessage().empty()) {
LogError("Error sourcing SQL [{}]", results.ErrorMessage());
return;
}
}
if (res->status == 404) {
LogError("Error retrieving URL [{}]", url);
}
}
else {
LogError("Error retrieving URL [{}]", url);
}
}
catch (std::invalid_argument iae) {
LogError("URI parser error [{}]", iae.what());
}
}
+12 -18
View File
@@ -34,8 +34,6 @@
#include <vector>
#include <map>
//atoi is not uint32 or uint32 safe!!!!
#define atoul(str) strtoul(str, nullptr, 10)
class MySQLRequestResult;
class Client;
@@ -108,9 +106,6 @@ public:
bool MoveCharacterToZone(uint32 character_id, uint32 zone_id);
bool ReserveName(uint32 account_id, char *name);
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp);
bool SetHackerFlag(const char *accountname, const char *charactername, const char *hacked);
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const char *hacked, const char *zone);
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const std::string &hacked, const char *zone);
bool UpdateName(const char *oldname, const char *newname);
bool CopyCharacter(
const std::string& source_character_name,
@@ -145,31 +140,30 @@ public:
/* Instancing */
bool AddClientToInstance(uint16 instance_id, uint32 char_id);
bool CharacterInInstanceGroup(uint16 instance_id, uint32 char_id);
bool AddClientToInstance(uint16 instance_id, uint32 character_id);
bool CheckInstanceByCharID(uint16 instance_id, uint32 character_id);
bool CheckInstanceExists(uint16 instance_id);
bool CheckInstanceExpired(uint16 instance_id);
bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
bool GetUnusedInstanceID(uint16 &instance_id);
bool GlobalInstance(uint16 instance_id);
bool IsGlobalInstance(uint16 instance_id);
bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
bool RemoveClientsFromInstance(uint16 instance_id);
bool VerifyInstanceAlive(uint16 instance_id, uint32 char_id);
bool VerifyInstanceAlive(uint16 instance_id, uint32 character_id);
bool VerifyZoneInstance(uint32 zone_id, uint16 instance_id);
uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version);
uint16 GetInstanceVersion(uint16 instance_id);
std::vector<uint16> GetInstanceIDs(uint32 zone_id, uint32 character_id);
uint8_t GetInstanceVersion(uint16 instance_id);
uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma);
uint32 VersionFromInstanceID(uint16 instance_id);
uint32 ZoneIDFromInstanceID(uint16 instance_id);
uint32 GetInstanceZoneID(uint16 instance_id);
void AssignGroupToInstance(uint32 gid, uint32 instance_id);
void AssignRaidToInstance(uint32 rid, uint32 instance_id);
void BuryCorpsesInInstance(uint16 instance_id);
void DeleteInstance(uint16 instance_id);
void FlagInstanceByGroupLeader(uint32 zone, int16 version, uint32 charid, uint32 gid);
void FlagInstanceByRaidLeader(uint32 zone, int16 version, uint32 charid, uint32 rid);
void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &charid_list);
void FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 charid, uint32 group_id);
void FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 charid, uint32 raid_id);
void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids);
void PurgeExpiredInstances();
void SetInstanceDuration(uint16 instance_id, uint32 new_duration);
@@ -241,7 +235,7 @@ public:
/* Database Variables */
bool GetVariable(std::string varname, std::string &varvalue);
bool SetVariable(const std::string varname, const std::string &varvalue);
bool SetVariable(const std::string& varname, const std::string &varvalue);
bool LoadVariables();
/* General Queries */
@@ -269,7 +263,7 @@ public:
void ClearInvSnapshots(bool from_now = false);
void SourceDatabaseTableFromUrl(std::string table_name, std::string url);
void SourceSqlFromUrl(std::string url);
private:
+137 -138
View File
@@ -27,6 +27,8 @@
#include "../eqemu_config.h"
#include "../database_schema.h"
#include "../file.h"
#include "../process/process.h"
#include "../termcolor/rang.hpp"
#include <ctime>
@@ -35,43 +37,12 @@
#else
#include <sys/time.h>
#include <thread>
#endif
#define DATABASE_DUMP_PATH "backups/"
/**
* @param cmd
* @param return_result
* @return
*/
std::string DatabaseDumpService::execute(const std::string &cmd, bool return_result = true)
{
const char *file_name = "db-exec-result.txt";
if (return_result) {
#ifdef _WINDOWS
std::system((cmd + " > " + file_name + " 2>&1").c_str());
#else
std::system((cmd + " > " + file_name).c_str());
#endif
}
else {
std::system((cmd).c_str());
}
std::string result;
if (return_result) {
std::ifstream file(file_name);
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
std::remove(file_name);
}
return result;
}
/**
* @return bool
*/
@@ -88,7 +59,7 @@ bool DatabaseDumpService::IsMySQLInstalled()
*/
bool DatabaseDumpService::IsTarAvailable()
{
std::string version_output = execute("tar --version");
std::string version_output = Process::execute("tar --version");
return version_output.find("GNU tar") != std::string::npos;
}
@@ -99,7 +70,7 @@ bool DatabaseDumpService::IsTarAvailable()
*/
bool DatabaseDumpService::Is7ZipAvailable()
{
std::string version_output = execute("7z --help");
std::string version_output = Process::execute("7z --help");
return version_output.find("7-Zip") != std::string::npos;
}
@@ -117,11 +88,13 @@ bool DatabaseDumpService::HasCompressionBinary()
*/
std::string DatabaseDumpService::GetMySQLVersion()
{
std::string version_output = execute("mysql --version");
std::string version_output = Process::execute("mysql --version");
return Strings::Trim(version_output);
}
const std::string CREDENTIALS_FILE = "login.my.cnf";
/**
* @return
*/
@@ -130,128 +103,66 @@ std::string DatabaseDumpService::GetBaseMySQLDumpCommand()
auto config = EQEmuConfig::get();
if (IsDumpContentTables() && !config->ContentDbHost.empty()) {
return fmt::format(
"mysqldump -u {} -p{} -h {} --port={} {}",
config->ContentDbUsername,
config->ContentDbPassword,
config->ContentDbHost,
config->ContentDbPort,
"mysqldump --defaults-extra-file={} {}",
CREDENTIALS_FILE,
config->ContentDbName
);
};
return fmt::format(
"mysqldump -u {} -p{} -h {} --port={} {}",
config->DatabaseUsername,
config->DatabasePassword,
config->DatabaseHost,
config->DatabasePort,
"mysqldump --defaults-extra-file={} {}",
CREDENTIALS_FILE,
config->DatabaseDB
);
}
/**
* @return
*/
std::string DatabaseDumpService::GetPlayerTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetPlayerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return Strings::Trim(tables_list);
return Strings::Join(DatabaseSchema::GetPlayerTables(), " ");
}
/**
* @return
*/
std::string DatabaseDumpService::GetBotTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetBotTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return Strings::Trim(tables_list);
return Strings::Join(DatabaseSchema::GetBotTables(), " ");
}
std::string DatabaseDumpService::GetMercTablesList()
{
return Strings::Join(DatabaseSchema::GetMercTables(), " ");
}
/**
* @return
*/
std::string DatabaseDumpService::GetLoginTableList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetLoginTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return Strings::Trim(tables_list);
return Strings::Join(DatabaseSchema::GetLoginTables(), " ");
}
/**
* @return
*/
std::string DatabaseDumpService::GetQueryServTables()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetQueryServerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return Strings::Trim(tables_list);
return Strings::Join(DatabaseSchema::GetQueryServerTables(), " ");
}
/**
* @return
*/
std::string DatabaseDumpService::GetSystemTablesList()
{
std::string tables_list;
auto system_tables = DatabaseSchema::GetServerTables();
auto version_tables = DatabaseSchema::GetVersionTables();
std::vector<std::string> tables = DatabaseSchema::GetServerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
system_tables.insert(
std::end(system_tables),
std::begin(version_tables),
std::end(version_tables)
);
tables = DatabaseSchema::GetVersionTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return Strings::Trim(tables_list);
return Strings::Join(system_tables, " ");
}
/**
* @return
*/
std::string DatabaseDumpService::GetStateTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetStateTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return Strings::Trim(tables_list);
return Strings::Join(DatabaseSchema::GetStateTables(), " ");
}
/**
* @return
*/
std::string DatabaseDumpService::GetContentTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetContentTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return Strings::Trim(tables_list);
return Strings::Join(DatabaseSchema::GetContentTables(), " ");
}
/**
@@ -286,7 +197,7 @@ std::string DatabaseDumpService::GetDumpFileNameWithPath()
return GetSetDumpPath() + GetDumpFileName();
}
void DatabaseDumpService::Dump()
void DatabaseDumpService::DatabaseDump()
{
if (!IsMySQLInstalled()) {
LogError("MySQL is not installed; Please check your PATH for a valid MySQL installation");
@@ -337,6 +248,11 @@ void DatabaseDumpService::Dump()
dump_descriptor += "-bots";
}
if (IsDumpMercTables()) {
tables_to_dump += GetMercTablesList() + " ";
dump_descriptor += "-mercs";
}
if (IsDumpSystemTables()) {
tables_to_dump += GetSystemTablesList() + " ";
dump_descriptor += "-system";
@@ -375,14 +291,6 @@ void DatabaseDumpService::Dump()
pipe_file = fmt::format(" > {}.sql", GetDumpFileNameWithPath());
}
std::string execute_command = fmt::format(
"{} {} {} {}",
GetBaseMySQLDumpCommand(),
options,
tables_to_dump,
pipe_file
);
if (!File::Exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
File::Makedir(GetSetDumpPath());
}
@@ -390,33 +298,65 @@ void DatabaseDumpService::Dump()
if (IsDumpDropTableSyntaxOnly()) {
std::vector<std::string> tables = Strings::Split(tables_to_dump, ' ');
for (auto &table : tables) {
for (auto &table: tables) {
std::cout << "DROP TABLE IF EXISTS `" << table << "`;" << std::endl;
}
if (tables_to_dump.empty()) {
std::cerr << "No tables were specified" << std::endl;
}
return;
}
else {
std::string execution_result = execute(execute_command, IsDumpOutputToConsole());
if (!execution_result.empty()) {
const auto execute_command = fmt::format(
"{} {} {} {}",
GetBaseMySQLDumpCommand(),
options,
tables_to_dump,
pipe_file
);
BuildCredentialsFile();
std::string execution_result = Process::execute(execute_command);
if (!execution_result.empty() && IsDumpOutputToConsole()) {
std::cout << execution_result;
}
}
if (!IsDumpOutputToConsole()) {
LogSys.LoadLogSettingsDefaults();
}
if (!pipe_file.empty()) {
std::string file = fmt::format("{}.sql", GetDumpFileNameWithPath());
auto r = File::GetContents(file);
if (!r.error.empty()) {
LogError("{}", r.error);
}
for (auto &line: Strings::Split(r.contents, "\n")) {
if (Strings::Contains(line, "mysqldump:")) {
LogError("{}", line);
LogError("Database dump failed. Correct the error before continuing or trying again");
LogError("This is to prevent data loss on behalf of the server operator");
RemoveSqlBackup();
std::exit(1);
}
}
}
if (!tables_to_dump.empty()) {
LogInfo("Dumping Tables [{}]", tables_to_dump);
LogInfo("Dumping Tables [{}]", Strings::Trim(tables_to_dump));
}
LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath());
if (IsDumpWithCompression() && !IsDumpOutputToConsole()) {
if (HasCompressionBinary()) {
LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath());
LogInfo("Compression requested. Compressing dump [{}.sql]", GetDumpFileNameWithPath());
if (IsTarAvailable()) {
execute(
Process::execute(
fmt::format(
"tar -zcvf {}.tar.gz -C {} {}.sql",
GetDumpFileNameWithPath(),
@@ -425,9 +365,10 @@ void DatabaseDumpService::Dump()
)
);
LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath());
RemoveSqlBackup();
}
else if (Is7ZipAvailable()) {
execute(
Process::execute(
fmt::format(
"7z a -t7z {}.zip {}.sql",
GetDumpFileNameWithPath(),
@@ -435,6 +376,7 @@ void DatabaseDumpService::Dump()
)
);
LogInfo("Compressed dump created at [{}.zip]", GetDumpFileNameWithPath());
RemoveSqlBackup();
}
else {
LogInfo("Compression requested, but no available compression binary was found");
@@ -445,6 +387,8 @@ void DatabaseDumpService::Dump()
}
}
RemoveCredentialsFile();
// LogDebug("[{}] dump-to-console", IsDumpOutputToConsole());
// LogDebug("[{}] dump-path", GetSetDumpPath());
// LogDebug("[{}] compression", (IsDumpWithCompression() ? "true" : "false"));
@@ -607,3 +551,58 @@ void DatabaseDumpService::SetDumpBotTables(bool dump_bot_tables)
{
DatabaseDumpService::dump_bot_tables = dump_bot_tables;
}
bool DatabaseDumpService::IsDumpMercTables() const
{
return dump_merc_tables;
}
void DatabaseDumpService::SetDumpMercTables(bool dump_merc_tables)
{
DatabaseDumpService::dump_merc_tables = dump_merc_tables;
}
void DatabaseDumpService::RemoveSqlBackup()
{
std::string file = fmt::format("{}.sql", GetDumpFileNameWithPath());
if (File::Exists(file)) {
std::filesystem::remove(file);
}
RemoveCredentialsFile();
}
void DatabaseDumpService::BuildCredentialsFile()
{
auto config = EQEmuConfig::get();
std::ofstream out(CREDENTIALS_FILE);
if (out.is_open()) {
if (IsDumpContentTables() && !config->ContentDbHost.empty()) {
out << "[mysqldump]" << std::endl;
out << "user=" << config->ContentDbUsername << std::endl;
out << "password=" << config->ContentDbPassword << std::endl;
out << "host=" << config->ContentDbHost << std::endl;
out << "port=" << config->ContentDbPort << std::endl;
out << "default-character-set=utf8" << std::endl;
}
else {
out << "[mysqldump]" << std::endl;
out << "user=" << config->DatabaseUsername << std::endl;
out << "password=" << config->DatabasePassword << std::endl;
out << "host=" << config->DatabaseHost << std::endl;
out << "port=" << config->DatabasePort << std::endl;
out << "default-character-set=utf8" << std::endl;
}
out.close();
}
else {
LogError("Failed to open credentials file for writing");
}
}
void DatabaseDumpService::RemoveCredentialsFile()
{
if (File::Exists(CREDENTIALS_FILE)) {
std::filesystem::remove(CREDENTIALS_FILE);
}
}
+8 -2
View File
@@ -24,7 +24,7 @@
class DatabaseDumpService {
public:
void Dump();
void DatabaseDump();
bool IsDumpAllTables() const;
void SetDumpAllTables(bool dump_all_tables);
bool IsDumpWithNoData() const;
@@ -55,6 +55,8 @@ public:
void SetDumpStateTables(bool dump_state_tables);
bool IsDumpBotTables() const;
void SetDumpBotTables(bool dump_bot_tables);
bool IsDumpMercTables() const;
void SetDumpMercTables(bool dump_bot_tables);
private:
bool dump_all_tables = false;
@@ -70,15 +72,16 @@ private:
bool dump_output_to_console = false;
bool dump_drop_table_syntax_only = false;
bool dump_bot_tables = false;
bool dump_merc_tables = false;
std::string dump_path;
std::string dump_file_name;
std::string execute(const std::string &cmd, bool return_result);
bool IsMySQLInstalled();
std::string GetMySQLVersion();
std::string GetBaseMySQLDumpCommand();
std::string GetPlayerTablesList();
std::string GetBotTablesList();
std::string GetMercTablesList();
std::string GetSystemTablesList();
std::string GetStateTablesList();
std::string GetContentTablesList();
@@ -89,6 +92,9 @@ private:
std::string GetDumpFileNameWithPath();
std::string GetSetDumpPath();
std::string GetQueryServTables();
void RemoveSqlBackup();
void BuildCredentialsFile();
void RemoveCredentialsFile();
};
+300
View File
@@ -0,0 +1,300 @@
#include <filesystem>
#include "database_update.h"
#include "../eqemu_logsys.h"
#include "../database.h"
#include "../strings.h"
#include "../rulesys.h"
#include "../http/httplib.h"
#include "database_update_manifest.cpp"
#include "database_update_manifest_bots.cpp"
#include "database_dump_service.h"
constexpr int BREAK_LENGTH = 70;
DatabaseVersion DatabaseUpdate::GetDatabaseVersions()
{
auto results = m_database->QueryDatabase("SELECT `version`, `bots_version` FROM `db_version` LIMIT 1");
if (!results.Success() || !results.RowCount()) {
LogError("Failed to read from [db_version] table!");
return DatabaseVersion{};
}
auto r = results.begin();
return DatabaseVersion{
.server_database_version = Strings::ToInt(r[0]),
.bots_database_version = Strings::ToInt(r[1]),
};
}
DatabaseVersion DatabaseUpdate::GetBinaryDatabaseVersions()
{
return DatabaseVersion{
.server_database_version = CURRENT_BINARY_DATABASE_VERSION,
.bots_database_version = (RuleB(Bots, Enabled) ? CURRENT_BINARY_BOTS_DATABASE_VERSION : 0),
};
}
// the amount of versions we look-back to ensure we have all migrations
// we may not want to force these, but just warn about the look-backs
constexpr int LOOK_BACK_AMOUNT = 10;
// this check will take action
void DatabaseUpdate::CheckDbUpdates()
{
InjectBotsVersionColumn();
auto v = GetDatabaseVersions();
auto b = GetBinaryDatabaseVersions();
if (CheckVersionsUpToDate(v, b)) {
return;
}
if (UpdateManifest(manifest_entries, v.server_database_version, b.server_database_version)) {
LogInfo(
"Updates ran successfully, setting database version to [{}] from [{}]",
b.server_database_version,
v.server_database_version
);
m_database->QueryDatabase(fmt::format("UPDATE `db_version` SET `version` = {}", b.server_database_version));
}
if (b.bots_database_version > 0) {
if (UpdateManifest(bot_manifest_entries, v.bots_database_version, b.bots_database_version)) {
LogInfo(
"Updates ran successfully, setting database version to [{}] from [{}]",
b.bots_database_version,
v.bots_database_version
);
m_database->QueryDatabase(
fmt::format(
"UPDATE `db_version` SET `bots_version` = {}",
b.bots_database_version
)
);
}
}
}
std::string DatabaseUpdate::GetQueryResult(std::string query)
{
auto results = m_database->QueryDatabase(query);
std::vector<std::string> result_lines = {};
for (auto row = results.begin(); row != results.end(); ++row) {
std::vector<std::string> cols;
int field_count = results.ColumnCount();
cols.reserve(field_count);
for (int i = 0; i < field_count; ++i) {
if (row[i] != nullptr) {
cols.emplace_back(row[i]);
}
}
result_lines.emplace_back(Strings::Join(cols, " "));
}
return Strings::Join(result_lines, "\n");
}
bool DatabaseUpdate::ShouldRunMigration(ManifestEntry &e, std::string query_result)
{
std::string r = Strings::Trim(query_result);
if (e.condition == "contains") {
return Strings::Contains(r, e.match);
}
else if (e.condition == "match") {
return r == e.match;
}
else if (e.condition == "missing") {
return !Strings::Contains(r, e.match);
}
else if (e.condition == "empty") {
return r.empty();
}
else if (e.condition == "not_empty") {
return !r.empty();
}
return false;
}
// return true if we ran updates
bool DatabaseUpdate::UpdateManifest(
std::vector<ManifestEntry> entries,
int version_low,
int version_high
)
{
std::vector<int> missing_migrations = {};
if (version_low != version_high) {
LogSys.DisableMySQLErrorLogs();
for (int version = version_low + 1; version <= version_high; ++version) {
for (auto &e: entries) {
if (e.version == version) {
bool has_migration = true;
std::string r = GetQueryResult(e.check);
if (ShouldRunMigration(e, r)) {
has_migration = false;
missing_migrations.emplace_back(e.version);
}
std::string prefix = fmt::format(
"[{}]",
has_migration ? "ok" : "missing"
);
LogInfo(
"[{}] {:>10} | [{}]",
e.version,
prefix,
e.description
);
}
}
}
LogSys.EnableMySQLErrorLogs();
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
if (!missing_migrations.empty()) {
LogInfo("Automatically backing up database before applying updates");
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
auto s = DatabaseDumpService();
s.SetDumpAllTables(true);
s.SetDumpWithCompression(true);
s.DatabaseDump();
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
}
if (!missing_migrations.empty()) {
LogInfo("Running database migrations. Please wait...");
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
}
for (auto &m: missing_migrations) {
for (auto &e: entries) {
if (e.version == m) {
bool errored_migration = false;
auto r = m_database->QueryDatabaseMulti(e.sql);
// ignore empty query result "errors"
if (r.ErrorNumber() != 1065 && !r.ErrorMessage().empty()) {
LogError("(#{}) [{}]", r.ErrorNumber(), r.ErrorMessage());
errored_migration = true;
LogInfo("Required database update failed. This could be a problem");
LogInfo("Would you like to skip this update? [y/n] (Timeout 60s)");
// user input
std::string input;
bool gave_input = false;
time_t start_time = time(nullptr);
time_t wait_time_seconds = 60;
// spawn a concurrent thread that waits for input from std::cin
std::thread t1(
[&]() {
std::cin >> input;
gave_input = true;
}
);
t1.detach();
// check the inputReceived flag once every 50ms for 10 seconds
while (time(nullptr) < start_time + wait_time_seconds && !gave_input) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
// prompt for user skip
if (Strings::Trim(input) == "y") {
errored_migration = false;
LogInfo("Skipping update [{}] [{}]", e.version, e.description);
}
}
LogInfo(
"[{}] [{}] [{}]",
e.version,
e.description,
(errored_migration ? "error" : "ok")
);
if (errored_migration) {
LogError("Fatal | Database migration [{}] failed to run", e.description);
LogError("Fatal | Shutting down");
std::exit(1);
}
}
}
}
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
return true;
}
return false;
}
DatabaseUpdate *DatabaseUpdate::SetDatabase(Database *db)
{
m_database = db;
return this;
}
bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
{
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
LogInfo(
"{:>8} | database [{}] binary [{}] {}",
"Server",
v.server_database_version,
b.server_database_version,
(v.server_database_version == b.server_database_version) ? "up to date" : "checking updates"
);
if (RuleB(Bots, Enabled) && b.bots_database_version > 0) {
LogInfo(
"{:>8} | database [{}] binary [{}] {}",
"Bots",
v.bots_database_version,
b.bots_database_version,
(v.bots_database_version == b.bots_database_version) ? "up to date" : "checking updates"
);
}
LogInfo("{:>8} | [server.auto_database_updates] [<green>true]", "Config");
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
// server database version is required
bool server_up_to_date = v.server_database_version == b.server_database_version;
// bots database version is optional, if not enabled then it is always up-to-date
bool bots_up_to_date = RuleB(Bots, Enabled) ? v.bots_database_version == b.bots_database_version : true;
return server_up_to_date && bots_up_to_date;
}
// checks to see if there are pending updates
// used by zone to prevent launch or boot loop until updates are applied
bool DatabaseUpdate::HasPendingUpdates()
{
auto v = GetDatabaseVersions();
auto b = GetBinaryDatabaseVersions();
return !CheckVersionsUpToDate(v, b);
}
void DatabaseUpdate::InjectBotsVersionColumn()
{
auto r = m_database->QueryDatabase("show columns from db_version where Field like '%bots_version%'");
if (r.RowCount() == 0) {
m_database->QueryDatabase("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version");
}
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef EQEMU_DATABASE_UPDATE_H
#define EQEMU_DATABASE_UPDATE_H
#include "../database.h"
struct ManifestEntry {
int version{}; // database version of the migration
std::string description{}; // description of the migration ex: "add_new_table" or "add_index_to_table"
std::string check{}; // query that checks against the condition
std::string condition{}; // condition or "match_type" - Possible values [contains|match|missing|empty|not_empty]
std::string match{}; // match field that is not always used, but works in conjunction with "condition" values [missing|match|contains]
std::string sql{}; // the SQL DDL that gets ran when the condition is true
};
struct DatabaseVersion {
int server_database_version;
int bots_database_version;
};
class DatabaseUpdate {
public:
DatabaseVersion GetDatabaseVersions();
DatabaseVersion GetBinaryDatabaseVersions();
void CheckDbUpdates();
std::string GetQueryResult(std::string query);
static bool ShouldRunMigration(ManifestEntry &e, std::string query_result);
bool UpdateManifest(std::vector<ManifestEntry> entries, int version_low, int version_high);
DatabaseUpdate *SetDatabase(Database *db);
bool HasPendingUpdates();
private:
Database *m_database;
static bool CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b);
void InjectBotsVersionColumn();
};
#endif //EQEMU_DATABASE_UPDATE_H
File diff suppressed because one or more lines are too long
@@ -0,0 +1,84 @@
#include "database_update.h"
std::vector<ManifestEntry> bot_manifest_entries = {
ManifestEntry{
.version = 9035,
.description = "2022_12_04_bot_archery.sql",
.check = "SHOW COLUMNS FROM `bot_data` LIKE 'archery_setting'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `bot_data`
ADD COLUMN `archery_setting` TINYINT(2) UNSIGNED NOT NULL DEFAULT '0' AFTER `enforce_spell_settings`;
)",
},
ManifestEntry{
.version = 9036,
.description = "2023_01_19_drop_bot_views.sql",
.check = "SHOW TABLES LIKE 'vw_groups'",
.condition = "not_empty",
.match = "",
.sql = R"(
DROP VIEW vw_bot_groups;
DROP VIEW vw_bot_character_mobs;
DROP VIEW vw_groups;
DROP VIEW vw_guild_members;
DROP TABLE bot_guild_members;
)",
},
ManifestEntry{
.version = 9037,
.description = "2023_01_22_add_name_index.sql",
.check = "show index from bot_data WHERE key_name = 'name`",
.condition = "",
.match = "empty",
.sql = R"(
create index `name` on bot_data(`name`);
)",
},
ManifestEntry{
.version = 9038,
.description = "2023_02_16_add_caster_range.sql",
.check = "SHOW COLUMNS FROM `bot_data` LIKE 'caster_range'",
.condition = "",
.match = "empty",
.sql = R"(
ALTER TABLE `bot_data`
ADD COLUMN `caster_range` INT(11) UNSIGNED NOT NULL DEFAULT '300' AFTER `archery_setting`;
)",
},
ManifestEntry{
.version = 9039,
.description = "2023_03_31_remove_bot_groups.sql",
.check = "SHOW TABLES LIKE 'bot_groups'",
.condition = "",
.match = "not_empty",
.sql = R"(
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `bot_groups`;
DROP TABLE IF EXISTS `bot_group_members`;
SET FOREIGN_KEY_CHECKS = 1;
)",
},
// -- template; copy/paste this when you need to create a new entry
// ManifestEntry{
// .version = 9228,
// .description = "some_new_migration.sql",
// .check = "SHOW COLUMNS FROM `table_name` LIKE 'column_name'",
// .condition = "empty",
// .match = "",
// .sql = R"(
//
//)"
};
// see struct definitions for what each field does
// struct ManifestEntry {
// int version{}; // database version of the migration
// std::string description{}; // description of the migration ex: "add_new_table" or "add_index_to_table"
// std::string check{}; // query that checks against the condition
// std::string condition{}; // condition or "match_type" - Possible values [contains|match|missing|empty|not_empty]
// std::string match{}; // match field that is not always used, but works in conjunction with "condition" values [missing|match|contains]
// std::string sql{}; // the SQL DDL that gets ran when the condition is true
// };
File diff suppressed because it is too large Load Diff
+230 -293
View File
@@ -20,8 +20,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/rulesys.h"
#include "../common/strings.h"
#include "../common/timer.h"
#include "../common/repositories/character_corpses_repository.h"
#include "../common/repositories/dynamic_zone_members_repository.h"
#include "../common/repositories/dynamic_zones_repository.h"
#include "../common/repositories/group_id_repository.h"
#include "../common/repositories/instance_list_repository.h"
#include "../common/repositories/instance_list_player_repository.h"
#include "../common/repositories/raid_members_repository.h"
#include "../common/repositories/respawn_times_repository.h"
#include "../common/repositories/spawn_condition_values_repository.h"
#include "database.h"
@@ -41,115 +49,83 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <sys/time.h>
#endif
/**
* @param instance_id
* @param char_id
* @return
*/
bool Database::AddClientToInstance(uint16 instance_id, uint32 char_id)
bool Database::AddClientToInstance(uint16 instance_id, uint32 character_id)
{
std::string query = StringFormat(
"REPLACE INTO `instance_list_player` (id, charid) "
"VALUES "
"(%lu, %lu)",
(unsigned long) instance_id,
(unsigned long) char_id
);
auto e = InstanceListPlayerRepository::NewEntity();
auto results = QueryDatabase(query);
e.id = instance_id;
e.charid = character_id;
return results.Success();
return InstanceListPlayerRepository::ReplaceOne(*this, e);
}
bool Database::CharacterInInstanceGroup(uint16 instance_id, uint32 char_id)
bool Database::CheckInstanceByCharID(uint16 instance_id, uint32 character_id)
{
std::string query = StringFormat("SELECT charid FROM instance_list_player where id=%u AND charid=%u", instance_id, char_id);
auto results = QueryDatabase(query);
if (!results.Success())
if (!instance_id) {
return false;
}
if (results.RowCount() != 1)
auto l = InstanceListPlayerRepository::GetWhere(
*this,
fmt::format(
"id = {} AND charid = {}",
instance_id,
character_id
)
);
if (l.empty()) {
return false;
}
return true;
}
bool Database::CheckInstanceExists(uint16 instance_id) {
std::string query = StringFormat(
"SELECT "
"`id` "
"FROM "
"`instance_list` "
"WHERE "
"`id` = %u",
instance_id
);
auto results = QueryDatabase(query);
if (!results.Success())
bool Database::CheckInstanceExists(uint16 instance_id)
{
if (!instance_id) {
return false;
}
if (results.RowCount() == 0)
auto i = InstanceListRepository::FindOne(*this, instance_id);
if (!i.id) {
return false;
}
return true;
}
bool Database::CheckInstanceExpired(uint16 instance_id)
{
int32 start_time = 0;
int32 duration = 0;
uint32 never_expires = 0;
std::string query = StringFormat(
"SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u",
instance_id
);
auto results = QueryDatabase(query);
if (!results.Success()) {
if (!instance_id) {
return true;
}
if (results.RowCount() == 0) {
auto i = InstanceListRepository::FindOne(*this, instance_id);
if (!i.id) {
return true;
}
auto row = results.begin();
start_time = atoi(row[0]);
duration = atoi(row[1]);
never_expires = atoi(row[2]);
if (never_expires == 1) {
if (i.never_expires) {
return false;
}
timeval tv{};
gettimeofday(&tv, nullptr);
return (start_time + duration) <= tv.tv_sec;
return (i.start_time + i.duration) <= tv.tv_sec;
}
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
{
std::string query = StringFormat(
"INSERT INTO instance_list (id, zone, version, start_time, duration)"
" values (%u, %u, %u, UNIX_TIMESTAMP(), %u)",
instance_id,
zone_id,
version,
duration
);
auto e = InstanceListRepository::NewEntity();
auto results = QueryDatabase(query);
e.id = instance_id;
e.zone = zone_id;
e.version = version;
e.start_time = std::time(nullptr);
e.duration = duration;
return results.Success();
return InstanceListRepository::InsertOne(*this, e).id;
}
bool Database::GetUnusedInstanceID(uint16 &instance_id)
@@ -157,8 +133,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
uint32 max = 32000;
std::string query = StringFormat(
"SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u",
auto query = fmt::format(
"SELECT IFNULL(MAX(id), {}) + 1 FROM instance_list WHERE id > {}",
max_reserved_instance_id,
max_reserved_instance_id
);
@@ -191,8 +167,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
auto row = results.begin();
if (atoi(row[0]) <= max) {
instance_id = atoi(row[0]);
if (Strings::ToInt(row[0]) <= max) {
instance_id = Strings::ToInt(row[0]);
return true;
}
@@ -202,7 +178,7 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
return true;
}
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id);
query = fmt::format("SELECT id FROM instance_list where id > {} ORDER BY id", max_reserved_instance_id);
results = QueryDatabase(query);
if (!results.Success()) {
@@ -216,8 +192,9 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
}
max_reserved_instance_id++;
for (auto row = results.begin(); row != results.end(); ++row) {
if (max_reserved_instance_id < atoi(row[0])) {
for (auto row : results) {
if (max_reserved_instance_id < Strings::ToUnsignedInt(row[0])) {
instance_id = max_reserved_instance_id;
return true;
}
@@ -235,57 +212,45 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
return true;
}
bool Database::GlobalInstance(uint16 instance_id)
bool Database::IsGlobalInstance(uint16 instance_id)
{
std::string query = StringFormat(
"SELECT "
"is_global "
"FROM "
"instance_list "
"WHERE "
"id = %u "
"LIMIT 1 ",
instance_id
);
auto results = QueryDatabase(query);
if (!results.Success())
if (!instance_id) {
return false;
}
if (results.RowCount() == 0)
auto i = InstanceListRepository::FindOne(*this, instance_id);
if (!i.id) {
return false;
}
auto row = results.begin();
return (atoi(row[0]) == 1) ? true : false;
return i.is_global;
}
bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id)
{
std::string query = StringFormat("DELETE FROM instance_list_player WHERE id=%lu AND charid=%lu",
(unsigned long)instance_id, (unsigned long)char_id);
auto results = QueryDatabase(query);
return results.Success();
return InstanceListPlayerRepository::DeleteWhere(
*this,
fmt::format(
"id = {} AND charid = {}",
instance_id,
char_id
)
);
}
bool Database::RemoveClientsFromInstance(uint16 instance_id)
{
std::string query = StringFormat("DELETE FROM instance_list_player WHERE id=%lu", (unsigned long)instance_id);
auto results = QueryDatabase(query);
return results.Success();
return InstanceListPlayerRepository::DeleteOne(*this, instance_id);
}
bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 char_id)
bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 character_id)
{
//we are not saved to this instance so set our instance to 0
if (!GlobalInstance(instance_id) && !CharacterInInstanceGroup(instance_id, char_id))
if (!IsGlobalInstance(instance_id) && !CheckInstanceByCharID(instance_id, character_id)) {
return false;
}
if (CheckInstanceExpired(instance_id))
{
if (CheckInstanceExpired(instance_id)) {
DeleteInstance(instance_id);
return false;
}
@@ -295,99 +260,102 @@ bool Database::VerifyInstanceAlive(uint16 instance_id, uint32 char_id)
bool Database::VerifyZoneInstance(uint32 zone_id, uint16 instance_id)
{
std::string query = StringFormat("SELECT id FROM instance_list where id=%u AND zone=%u", instance_id, zone_id);
auto results = QueryDatabase(query);
if (!results.Success())
return false;
if (results.RowCount() == 0)
auto l = InstanceListRepository::GetWhere(
*this,
fmt::format(
"id = {} AND zone = {}",
instance_id,
zone_id
)
);
if (l.empty()) {
return false;
}
return true;
}
uint16 Database::GetInstanceID(uint32 zone, uint32 character_id, int16 version)
uint16 Database::GetInstanceID(uint32 zone_id, uint32 character_id, int16 version)
{
if (!zone)
if (!zone_id) {
return 0;
}
std::string query = StringFormat(
"SELECT "
"instance_list.id "
"FROM "
"instance_list, "
"instance_list_player "
"WHERE "
"instance_list.zone = %u "
"AND instance_list.version = %u "
"AND instance_list.id = instance_list_player.id "
"AND instance_list_player.charid = %u "
"LIMIT 1; ",
zone,
const auto query = fmt::format(
"SELECT instance_list.id FROM "
"instance_list, instance_list_player WHERE "
"instance_list.zone = {} AND "
"instance_list.version = {} AND "
"instance_list.id = instance_list_player.id AND "
"instance_list_player.charid = {} "
"LIMIT 1;",
zone_id,
version,
character_id
);
);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
if (!results.Success() || !results.RowCount()) {
return 0;
}
auto row = results.begin();
return atoi(row[0]);
return static_cast<uint16>(Strings::ToUnsignedInt(row[0]));
}
uint16 Database::GetInstanceVersion(uint16 instance_id) {
if (instance_id == 0)
return 0;
std::vector<uint16> Database::GetInstanceIDs(uint32 zone_id, uint32 character_id)
{
std::vector<uint16> l;
std::string query = StringFormat("SELECT version FROM instance_list where id=%u", instance_id);
if (!zone_id) {
return l;
}
const auto query = fmt::format(
"SELECT instance_list.id FROM "
"instance_list, instance_list_player WHERE "
"instance_list.zone = {} AND "
"instance_list.id = instance_list_player.id AND "
"instance_list_player.charid = {}",
zone_id,
character_id
);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (!results.Success() || !results.RowCount()) {
return l;
}
if (results.RowCount() == 0)
return 0;
for (auto row : results) {
l.push_back(static_cast<uint16>(Strings::ToUnsignedInt(row[0])));
}
auto row = results.begin();
return atoi(row[0]);
return l;
}
uint8_t Database::GetInstanceVersion(uint16 instance_id) {
if (!instance_id) {
return 0;
}
auto i = InstanceListRepository::FindOne(*this, instance_id);
if (!i.id) {
return 0;
}
return i.version;
}
uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
{
uint32 start_time = 0;
uint32 duration = 0;
uint32 never_expires = 0;
std::string query = StringFormat("SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id);
auto results = QueryDatabase(query);
if (!results.Success())
{
auto i = InstanceListRepository::FindOne(*this, instance_id);
if (!i.id) {
is_perma = false;
return 0;
}
if (results.RowCount() == 0)
{
is_perma = false;
return 0;
}
auto row = results.begin();
start_time = atoi(row[0]);
duration = atoi(row[1]);
never_expires = atoi(row[2]);
if (never_expires == 1)
{
if (i.never_expires) {
is_perma = true;
return 0;
}
@@ -396,204 +364,173 @@ uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
timeval tv;
gettimeofday(&tv, nullptr);
return ((start_time + duration) - tv.tv_sec);
return ((i.start_time + i.duration) - tv.tv_sec);
}
uint32 Database::VersionFromInstanceID(uint16 instance_id)
uint32 Database::GetInstanceZoneID(uint16 instance_id)
{
std::string query = StringFormat("SELECT version FROM instance_list where id=%u", instance_id);
auto results = QueryDatabase(query);
if (!results.Success())
if (!instance_id) {
return 0;
}
if (results.RowCount() == 0)
auto i = InstanceListRepository::FindOne(*this, instance_id);
if (!i.id) {
return 0;
}
auto row = results.begin();
return atoi(row[0]);
}
uint32 Database::ZoneIDFromInstanceID(uint16 instance_id)
{
std::string query = StringFormat("SELECT zone FROM instance_list where id=%u", instance_id);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
return atoi(row[0]);
return i.zone;
}
void Database::AssignGroupToInstance(uint32 group_id, uint32 instance_id)
{
auto zone_id = GetInstanceZoneID(instance_id);
auto version = GetInstanceVersion(instance_id);
uint32 zone_id = ZoneIDFromInstanceID(instance_id);
uint16 version = VersionFromInstanceID(instance_id);
std::string query = StringFormat("SELECT `charid` FROM `group_id` WHERE `groupid` = %u", group_id);
auto results = QueryDatabase(query);
if (!results.Success())
auto l = GroupIdRepository::GetWhere(
*this,
fmt::format(
"groupid = {}",
group_id
)
);
if (l.empty()) {
return;
}
for (auto row = results.begin(); row != results.end(); ++row)
{
uint32 charid = atoi(row[0]);
if (GetInstanceID(zone_id, charid, version) == 0)
AddClientToInstance(instance_id, charid);
for (const auto& e : l) {
if (!GetInstanceID(zone_id, e.charid, version)) {
AddClientToInstance(instance_id, e.charid);
}
}
}
void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
{
auto zone_id = GetInstanceZoneID(instance_id);
auto version = GetInstanceVersion(instance_id);
uint32 zone_id = ZoneIDFromInstanceID(instance_id);
uint16 version = VersionFromInstanceID(instance_id);
std::string query = StringFormat("SELECT `charid` FROM `raid_members` WHERE `raidid` = %u", raid_id);
auto results = QueryDatabase(query);
if (!results.Success())
return;
for (auto row = results.begin(); row != results.end(); ++row)
{
uint32 charid = atoi(row[0]);
if (GetInstanceID(zone_id, charid, version) == 0)
AddClientToInstance(instance_id, charid);
}
}
void Database::BuryCorpsesInInstance(uint16 instance_id) {
QueryDatabase(
auto l = RaidMembersRepository::GetWhere(
*this,
fmt::format(
"UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id = {}",
instance_id
"raidid = {}",
raid_id
)
);
if (l.empty()) {
return;
}
for (const auto& e : l) {
if (!GetInstanceID(zone_id, e.charid, version)) {
AddClientToInstance(instance_id, e.charid);
}
}
}
void Database::DeleteInstance(uint16 instance_id)
{
std::string query;
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id);
QueryDatabase(query);
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
query = StringFormat("DELETE FROM respawn_times WHERE instance_id=%u", instance_id);
QueryDatabase(query);
query = StringFormat("DELETE FROM spawn_condition_values WHERE instance_id=%u", instance_id);
QueryDatabase(query);
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
BuryCorpsesInInstance(instance_id);
CharacterCorpsesRepository::BuryInstance(*this, instance_id);
}
void Database::FlagInstanceByGroupLeader(uint32 zone, int16 version, uint32 charid, uint32 gid)
void Database::FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 group_id)
{
uint16 id = GetInstanceID(zone, charid, version);
if (id != 0)
auto instance_id = GetInstanceID(zone_id, character_id, version);
if (instance_id) {
return;
}
char ln[128];
memset(ln, 0, 128);
GetGroupLeadershipInfo(gid, ln);
uint32 l_charid = GetCharacterID((const char*)ln);
uint16 l_id = GetInstanceID(zone, l_charid, version);
GetGroupLeadershipInfo(group_id, ln);
if (l_id == 0)
auto group_leader_id = GetCharacterID((const char*)ln);
auto group_leader_instance_id = GetInstanceID(zone_id, group_leader_id, version);
if (!group_leader_instance_id) {
return;
}
AddClientToInstance(l_id, charid);
AddClientToInstance(group_leader_instance_id, character_id);
}
void Database::FlagInstanceByRaidLeader(uint32 zone, int16 version, uint32 charid, uint32 rid)
void Database::FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 raid_id)
{
uint16 id = GetInstanceID(zone, charid, version);
if (id != 0)
uint16 instance_id = GetInstanceID(zone_id, character_id, version);
if (instance_id) {
return;
}
uint32 l_charid = GetCharacterID(GetRaidLeaderName(rid));
uint16 l_id = GetInstanceID(zone, l_charid, version);
auto raid_leader_id = GetCharacterID(GetRaidLeaderName(raid_id));
auto raid_leader_instance_id = GetInstanceID(zone_id, raid_leader_id, version);
if (l_id == 0)
if (!raid_leader_instance_id) {
return;
}
AddClientToInstance(l_id, charid);
AddClientToInstance(raid_leader_instance_id, character_id);
}
void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &charid_list) {
std::string query = StringFormat("SELECT `charid` FROM `instance_list_player` WHERE `id` = %u", instance_id);
auto results = QueryDatabase(query);
if (!results.Success())
void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids)
{
auto l = InstanceListPlayerRepository::GetWhere(*this, fmt::format("id = {}", instance_id));
if (l.empty()) {
return;
}
for (auto row = results.begin(); row != results.end(); ++row)
charid_list.push_back(atoi(row[0]));
for (const auto& e : l) {
character_ids.push_back(e.charid);
}
}
void Database::PurgeExpiredInstances()
{
/**
* Delay purging by a day so that we can continue using adjacent free instance id's
* from the table without risking the chance we immediately re-allocate a zone that freshly expired but
* has not been fully de-allocated
*/
std::string query =
SQL(
SELECT
id
FROM
instance_list
where
(start_time + duration) <= (UNIX_TIMESTAMP() - 86400)
and never_expires = 0
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return;
}
if (results.RowCount() == 0) {
auto l = InstanceListRepository::GetWhere(
*this,
"(start_time + duration) <= (UNIX_TIMESTAMP() - 86400) AND never_expires = 0"
);
if (l.empty()) {
return;
}
std::vector<std::string> instance_ids;
for (auto row = results.begin(); row != results.end(); ++row) {
instance_ids.emplace_back(row[0]);
for (const auto& e : l) {
instance_ids.emplace_back(std::to_string(e.id));
}
std::string imploded_instance_ids = Strings::Implode(",", instance_ids);
const auto imploded_instance_ids = Strings::Implode(",", instance_ids);
QueryDatabase(fmt::format("DELETE FROM instance_list WHERE id IN ({})", imploded_instance_ids));
QueryDatabase(fmt::format("DELETE FROM instance_list_player WHERE id IN ({})", imploded_instance_ids));
QueryDatabase(fmt::format("DELETE FROM respawn_times WHERE instance_id IN ({})", imploded_instance_ids));
QueryDatabase(fmt::format("DELETE FROM spawn_condition_values WHERE instance_id IN ({})", imploded_instance_ids));
QueryDatabase(fmt::format("UPDATE character_corpses SET is_buried = 1, instance_id = 0 WHERE instance_id IN ({})", imploded_instance_ids));
InstanceListRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids));
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids));
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
CharacterCorpsesRepository::BuryInstances(*this, imploded_instance_ids);
DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids);
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
}
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
{
std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), "
"duration=%u WHERE id=%u", new_duration, instance_id);
auto results = QueryDatabase(query);
auto i = InstanceListRepository::FindOne(*this, instance_id);
if (!i.id) {
return;
}
i.start_time = std::time(nullptr);
i.duration = new_duration;
InstanceListRepository::UpdateOne(*this, i);
}
+30 -9
View File
@@ -68,7 +68,7 @@ namespace DatabaseSchema {
{"character_spells", "id"},
{"character_task_timers", "character_id"},
{"character_tasks", "charid"},
{"character_tribute", "id"},
{"character_tribute", "character_id"},
{"completed_tasks", "charid"},
{"data_buckets", "id"},
{"faction_values", "char_id"},
@@ -256,7 +256,9 @@ namespace DatabaseSchema {
{
return {
"chatchannels",
"chatchannel_reserved_names",
"command_settings",
"command_subsettings",
"content_flags",
"db_str",
"eqtime",
@@ -321,18 +323,18 @@ namespace DatabaseSchema {
"discord_webhooks",
"dynamic_zone_members",
"dynamic_zones",
"eventlog",
"expedition_lockouts",
"expeditions",
"gm_ips",
"group_id",
"group_leaders",
"hackers",
"instance_list",
"ip_exemptions",
"item_tick",
"lfguild",
"merc_buffs",
"merchantlist_temp",
"mercs",
"object_contents",
"raid_details",
"raid_leaders",
@@ -341,6 +343,8 @@ namespace DatabaseSchema {
"respawn_times",
"saylink",
"server_scheduled_events",
"player_event_log_settings",
"player_event_logs",
"shared_task_activity_state",
"shared_task_dynamic_zones",
"shared_task_members",
@@ -390,9 +394,6 @@ namespace DatabaseSchema {
"bot_command_settings",
"bot_create_combinations",
"bot_data",
"bot_group_members",
"bot_groups",
"bot_guild_members",
"bot_heal_rotation_members",
"bot_heal_rotation_targets",
"bot_heal_rotations",
@@ -403,11 +404,31 @@ namespace DatabaseSchema {
"bot_pet_inventories",
"bot_pets",
"bot_spell_casting_chances",
"bot_spell_settings",
"bot_spells_entries",
"bot_stances",
"bot_timers",
"vw_bot_character_mobs",
"vw_bot_groups"
"bot_timers"
};
}
static std::vector<std::string> GetMercTables()
{
return {
"merc_armorinfo",
"merc_inventory",
"merc_merchant_entries",
"merc_merchant_template_entries",
"merc_merchant_templates",
"merc_name_types",
"merc_npc_types",
"merc_spell_list_entries",
"merc_spell_lists",
"merc_stance_entries",
"merc_stats",
"merc_subtypes",
"merc_templates",
"merc_types",
"merc_weaponinfo"
};
}
+190 -52
View File
@@ -13,6 +13,7 @@
#include <iostream>
#include <mysqld_error.h>
#include <string.h>
#include "strings.h"
#ifdef _WINDOWS
#define snprintf _snprintf
@@ -34,14 +35,16 @@
DBcore::DBcore()
{
mysql_init(&mysql);
pHost = nullptr;
pUser = nullptr;
pPassword = nullptr;
pDatabase = nullptr;
pCompress = false;
pSSL = false;
pStatus = Closed;
mysql = mysql_init(nullptr);
mysqlOwner = true;
pHost = nullptr;
pUser = nullptr;
pPassword = nullptr;
pDatabase = nullptr;
pCompress = false;
pSSL = false;
pStatus = Closed;
m_mutex = new Mutex;
}
DBcore::~DBcore()
@@ -51,16 +54,10 @@ DBcore::~DBcore()
* are re-using the default database connection pointer when we dont have an
* external configuration setup ex: (content_database)
*/
std::string mysql_connection_host;
if (mysql.host) {
mysql_connection_host = mysql.host;
if (mysqlOwner) {
mysql_close(mysql);
}
if (GetOriginHost() != mysql_connection_host) {
return;
}
mysql_close(&mysql);
safe_delete_array(pHost);
safe_delete_array(pUser);
safe_delete_array(pPassword);
@@ -70,20 +67,21 @@ DBcore::~DBcore()
// Sends the MySQL server a keepalive
void DBcore::ping()
{
if (!MDatabase.trylock()) {
if (!m_mutex->trylock()) {
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
return;
}
mysql_ping(&mysql);
MDatabase.unlock();
mysql_ping(mysql);
m_mutex->unlock();
}
MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce)
MySQLRequestResult DBcore::QueryDatabase(const std::string& query, bool retryOnFailureOnce)
{
return QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
auto r = QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
return r;
}
bool DBcore::DoesTableExist(std::string table_name)
bool DBcore::DoesTableExist(const std::string& table_name)
{
auto results = QueryDatabase(fmt::format("SHOW TABLES LIKE '{}'", table_name));
@@ -95,18 +93,16 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
BenchTimer timer;
timer.reset();
LockMutex lock(&MDatabase);
LockMutex lock(m_mutex);
// Reconnect if we are not connected before hand.
if (pStatus != Connected) {
Open();
}
// request query. != 0 indicates some kind of error.
if (mysql_real_query(&mysql, query, querylen) != 0) {
unsigned int errorNumber = mysql_errno(&mysql);
if (mysql_real_query(mysql, query, querylen) != 0) {
unsigned int errorNumber = mysql_errno(mysql);
if (errorNumber == CR_SERVER_GONE_ERROR) {
pStatus = Error;
@@ -130,26 +126,26 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(&mysql), errorBuffer);
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(mysql), errorBuffer);
}
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
/**
* Error logging
*/
if (mysql_errno(&mysql) > 0 && strlen(query) > 0) {
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(&mysql), mysql_error(&mysql), query);
if (mysql_errno(mysql) > 0 && query[0] != '\0') {
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(mysql), mysql_error(mysql), query);
}
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer);
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(mysql), errorBuffer);
}
// successful query. get results.
MYSQL_RES *res = mysql_store_result(&mysql);
MYSQL_RES *res = mysql_store_result(mysql);
uint32 rowCount = 0;
if (res != nullptr) {
@@ -158,16 +154,16 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
MySQLRequestResult requestResult(
res,
(uint32) mysql_affected_rows(&mysql),
(uint32) mysql_affected_rows(mysql),
rowCount,
(uint32) mysql_field_count(&mysql),
(uint32) mysql_insert_id(&mysql)
(uint32) mysql_field_count(mysql),
(uint32) mysql_insert_id(mysql)
);
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
if ((strncasecmp(query, "select", 6) == 0)) {
LogMySQLQuery(
"{0}; -- ({1} row{2} returned) ({3}s)",
"{0} -- ({1} row{2} returned) ({3}s)",
query,
requestResult.RowCount(),
requestResult.RowCount() == 1 ? "" : "s",
@@ -176,7 +172,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
}
else {
LogMySQLQuery(
"{0}; -- ({1} row{2} affected) ({3}s)",
"{0} -- ({1} row{2} affected) ({3}s)",
query,
requestResult.RowsAffected(),
requestResult.RowsAffected() == 1 ? "" : "s",
@@ -207,7 +203,7 @@ uint32 DBcore::DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen)
{
// No good reason to lock the DB, we only need it in the first place to check char encoding.
// LockMutex lock(&MDatabase);
return mysql_real_escape_string(&mysql, tobuf, frombuf, fromlen);
return mysql_real_escape_string(mysql, tobuf, frombuf, fromlen);
}
bool DBcore::Open(
@@ -222,7 +218,7 @@ bool DBcore::Open(
bool iSSL
)
{
LockMutex lock(&MDatabase);
LockMutex lock(m_mutex);
safe_delete_array(pHost);
safe_delete_array(pUser);
safe_delete_array(pPassword);
@@ -242,13 +238,13 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
if (errbuf) {
errbuf[0] = 0;
}
LockMutex lock(&MDatabase);
LockMutex lock(m_mutex);
if (GetStatus() == Connected) {
return true;
}
if (GetStatus() == Error) {
mysql_close(&mysql);
mysql_init(&mysql); // Initialize structure again
mysql_close(mysql);
mysql_init(mysql); // Initialize structure again
}
if (!pHost) {
return false;
@@ -265,7 +261,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
if (pSSL) {
flags |= CLIENT_SSL;
}
if (mysql_real_connect(&mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
if (mysql_real_connect(mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
pStatus = Connected;
std::string connected_origin_host = pHost;
@@ -275,21 +271,16 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
}
else {
if (errnum) {
*errnum = mysql_errno(&mysql);
*errnum = mysql_errno(mysql);
}
if (errbuf) {
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
}
pStatus = Error;
return false;
}
}
void DBcore::SetMysql(MYSQL *mysql)
{
DBcore::mysql = *mysql;
}
const std::string &DBcore::GetOriginHost() const
{
return origin_host;
@@ -299,3 +290,150 @@ void DBcore::SetOriginHost(const std::string &origin_host)
{
DBcore::origin_host = origin_host;
}
std::string DBcore::Escape(const std::string& s)
{
const std::size_t s_len = s.length();
std::vector<char> temp((s_len * 2) + 1, '\0');
mysql_real_escape_string(mysql, temp.data(), s.c_str(), s_len);
return temp.data();
}
void DBcore::SetMutex(Mutex *mutex)
{
safe_delete(m_mutex);
DBcore::m_mutex = mutex;
}
// executes multiple statements in one query
// do not use this in application logic
// this was built and maintained for database migrations only
MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
{
SetMultiStatementsOn();
BenchTimer timer;
timer.reset();
LockMutex lock(m_mutex);
// Reconnect if we are not connected before hand.
if (pStatus != Connected) {
Open();
}
auto r = MySQLRequestResult{};
int status = mysql_real_query(mysql, query.c_str(), query.length());
// process single result
if (status != 0) {
unsigned int error_number = mysql_errno(mysql);
if (error_number == CR_SERVER_GONE_ERROR) {
pStatus = Error;
}
// error logging
if (mysql_errno(mysql) > 0 && query.length() > 0 && mysql_errno(mysql) != 1065) {
std::string error_raw = fmt::format("{}", mysql_error(mysql));
std::string mysql_err = Strings::Trim(error_raw);
std::string clean_query = Strings::Replace(query, "\n", "");
LogMySQLError("[{}] ({}) query [{}]", mysql_err, mysql_errno(mysql), clean_query);
MYSQL_RES *res = mysql_store_result(mysql);
uint32 row_count = 0;
if (res) {
row_count = (uint32) mysql_num_rows(res);
}
r = MySQLRequestResult(
res,
(uint32) mysql_affected_rows(mysql),
row_count,
(uint32) mysql_field_count(mysql),
(uint32) mysql_insert_id(mysql)
);
std::string error_message = mysql_error(mysql);
r.SetErrorMessage(error_message);
r.SetErrorNumber(mysql_errno(mysql));
if (res) {
mysql_free_result(res);
}
SetMultiStatementsOff();
return r;
}
}
int index = 0;
// there could be a query with a semicolon in the actual data, this is best effort for
// logging / display purposes
// rare that we see this when this is only used in DDL statements
auto pieces = Strings::Split(query, ";");
// process each statement result
do {
uint32 row_count = 0;
MYSQL_RES *res = mysql_store_result(mysql);
r = MySQLRequestResult(
res,
(uint32) mysql_affected_rows(mysql),
row_count,
(uint32) mysql_field_count(mysql),
(uint32) mysql_insert_id(mysql)
);
if (pieces.size() >= index) {
auto piece = pieces[index];
LogMySQLQuery(
"{} -- ({} row{} affected) ({}s)",
piece,
r.RowsAffected(),
r.RowsAffected() == 1 ? "" : "s",
std::to_string(timer.elapsed())
);
}
if (res) {
row_count = (uint32) mysql_num_rows(res);
}
// more results? -1 = no, >0 = error, 0 = yes (keep looping)
if ((status = mysql_next_result(mysql)) > 0) {
if (mysql_errno(mysql) > 0) {
LogMySQLError("[{}] [{}]", mysql_errno(mysql), mysql_error(mysql));
}
mysql_free_result(res);
// error logging
std::string error_message = mysql_error(mysql);
r.SetErrorMessage(error_message);
r.SetErrorNumber(mysql_errno(mysql));
SetMultiStatementsOff();
// we handle errors elsewhere
return r;
}
if (res) {
mysql_free_result(res);
}
index++;
} while (status == 0);
SetMultiStatementsOff();
return r;
}
+30 -7
View File
@@ -12,6 +12,7 @@
#include <mysql.h>
#include <string.h>
#include <mutex>
class DBcore {
public:
@@ -23,19 +24,26 @@ public:
~DBcore();
eStatus GetStatus() { return pStatus; }
MySQLRequestResult QueryDatabase(const char *query, uint32 querylen, bool retryOnFailureOnce = true);
MySQLRequestResult QueryDatabase(std::string query, bool retryOnFailureOnce = true);
MySQLRequestResult QueryDatabase(const std::string& query, bool retryOnFailureOnce = true);
MySQLRequestResult QueryDatabaseMulti(const std::string &query);
void TransactionBegin();
void TransactionCommit();
void TransactionRollback();
std::string Escape(const std::string& s);
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
void ping();
MYSQL *getMySQL() { return &mysql; }
void SetMysql(MYSQL *mysql);
const std::string &GetOriginHost() const;
void SetOriginHost(const std::string &origin_host);
bool DoesTableExist(std::string table_name);
bool DoesTableExist(const std::string& table_name);
void SetMySQL(const DBcore &o)
{
mysql = o.mysql;
mysqlOwner = false;
}
void SetMutex(Mutex *mutex);
protected:
bool Open(
@@ -53,10 +61,13 @@ protected:
private:
bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr);
MYSQL mysql;
Mutex MDatabase;
MYSQL* mysql;
bool mysqlOwner;
Mutex *m_mutex;
eStatus pStatus;
std::mutex m_query_lock{};
std::string origin_host;
char *pHost;
@@ -67,8 +78,20 @@ private:
uint32 pPort;
bool pSSL;
// allows multiple queries to be executed within the same query
// do not use this under normal operation
// we use this during database migrations only currently
void SetMultiStatementsOn()
{
mysql_set_server_option(mysql, MYSQL_OPTION_MULTI_STATEMENTS_ON);
}
// disables multiple statements to be executed in one query
void SetMultiStatementsOff()
{
mysql_set_server_option(mysql, MYSQL_OPTION_MULTI_STATEMENTS_OFF);
}
};
#endif
+69 -119
View File
@@ -11,7 +11,7 @@
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@@ -19,131 +19,81 @@
#include "deity.h"
EQ::deity::DeityTypeBit EQ::deity::ConvertDeityTypeToDeityTypeBit(DeityType deity_type)
EQ::deity::DeityTypeBit EQ::deity::GetDeityBitmask(DeityType deity_type)
{
switch (deity_type) {
case DeityBertoxxulous:
return bit_DeityBertoxxulous;
case DeityBrellSirilis:
return bit_DeityBrellSirilis;
case DeityCazicThule:
return bit_DeityCazicThule;
case DeityErollisiMarr:
return bit_DeityErollisiMarr;
case DeityBristlebane:
return bit_DeityBristlebane;
case DeityInnoruuk:
return bit_DeityInnoruuk;
case DeityKarana:
return bit_DeityKarana;
case DeityMithanielMarr:
return bit_DeityMithanielMarr;
case DeityPrexus:
return bit_DeityPrexus;
case DeityQuellious:
return bit_DeityQuellious;
case DeityRallosZek:
return bit_DeityRallosZek;
case DeityRodcetNife:
return bit_DeityRodcetNife;
case DeitySolusekRo:
return bit_DeitySolusekRo;
case DeityTheTribunal:
return bit_DeityTheTribunal;
case DeityTunare:
return bit_DeityTunare;
case DeityVeeshan:
return bit_DeityVeeshan;
case DeityAgnostic_LB:
case DeityAgnostic:
return bit_DeityAgnostic;
default:
return bit_DeityAll;
};
case DeityBertoxxulous:
return bit_DeityBertoxxulous;
case DeityBrellSirilis:
return bit_DeityBrellSirilis;
case DeityCazicThule:
return bit_DeityCazicThule;
case DeityErollisiMarr:
return bit_DeityErollisiMarr;
case DeityBristlebane:
return bit_DeityBristlebane;
case DeityInnoruuk:
return bit_DeityInnoruuk;
case DeityKarana:
return bit_DeityKarana;
case DeityMithanielMarr:
return bit_DeityMithanielMarr;
case DeityPrexus:
return bit_DeityPrexus;
case DeityQuellious:
return bit_DeityQuellious;
case DeityRallosZek:
return bit_DeityRallosZek;
case DeityRodcetNife:
return bit_DeityRodcetNife;
case DeitySolusekRo:
return bit_DeitySolusekRo;
case DeityTheTribunal:
return bit_DeityTheTribunal;
case DeityTunare:
return bit_DeityTunare;
case DeityVeeshan:
return bit_DeityVeeshan;
case DeityAgnostic_LB:
case DeityAgnostic:
return bit_DeityAgnostic;
default:
return bit_DeityAll;
}
}
EQ::deity::DeityType EQ::deity::ConvertDeityTypeBitToDeityType(DeityTypeBit deity_type_bit)
const std::map<EQ::deity::DeityType, std::string>& EQ::deity::GetDeityMap()
{
switch (deity_type_bit) {
case bit_DeityAgnostic:
return DeityAgnostic;
case bit_DeityBertoxxulous:
return DeityBertoxxulous;
case bit_DeityBrellSirilis:
return DeityBrellSirilis;
case bit_DeityCazicThule:
return DeityCazicThule;
case bit_DeityErollisiMarr:
return DeityErollisiMarr;
case bit_DeityBristlebane:
return DeityBristlebane;
case bit_DeityInnoruuk:
return DeityInnoruuk;
case bit_DeityKarana:
return DeityKarana;
case bit_DeityMithanielMarr:
return DeityMithanielMarr;
case bit_DeityPrexus:
return DeityPrexus;
case bit_DeityQuellious:
return DeityQuellious;
case bit_DeityRallosZek:
return DeityRallosZek;
case bit_DeityRodcetNife:
return DeityRodcetNife;
case bit_DeitySolusekRo:
return DeitySolusekRo;
case bit_DeityTheTribunal:
return DeityTheTribunal;
case bit_DeityTunare:
return DeityTunare;
case bit_DeityVeeshan:
return DeityVeeshan;
default:
return DeityUnknown;
static const std::map<EQ::deity::DeityType, std::string> deity_map = {
{ DeityAgnostic, "Agnostic" },
{ DeityAgnostic_LB, "Agnostic" },
{ DeityBertoxxulous, "Bertoxxulous" },
{ DeityBrellSirilis, "Brell Serilis" },
{ DeityBristlebane, "Bristlebane" },
{ DeityCazicThule, "Cazic-Thule" },
{ DeityErollisiMarr, "Erollisi Marr" },
{ DeityInnoruuk, "Innoruuk" },
{ DeityKarana, "Karana" },
{ DeityMithanielMarr, "Mithaniel Marr" },
{ DeityPrexus, "Prexus" },
{ DeityQuellious, "Quellious" },
{ DeityRallosZek, "Rallos Zek" },
{ DeityRodcetNife, "Rodcet Nife" },
{ DeitySolusekRo, "Solusek Ro" },
{ DeityTheTribunal, "The Tribunal" },
{ DeityTunare, "Tunare" },
{ DeityVeeshan, "Veeshan" }
};
return deity_map;
}
const char* EQ::deity::DeityName(DeityType deity_type)
std::string EQ::deity::GetDeityName(DeityType deity_type)
{
switch (deity_type) {
case DeityBertoxxulous:
return "Bertoxxulous";
case DeityBrellSirilis:
return "Brell Serilis";
case DeityCazicThule:
return "Cazic-Thule";
case DeityErollisiMarr:
return "Erollisi Marr";
case DeityBristlebane:
return "Bristlebane";
case DeityInnoruuk:
return "Innoruuk";
case DeityKarana:
return "Karana";
case DeityMithanielMarr:
return "Mithaniel Marr";
case DeityPrexus:
return "Prexus";
case DeityQuellious:
return "Quellious";
case DeityRallosZek:
return "Rallos Zek";
case DeityRodcetNife:
return "Rodcet Nife";
case DeitySolusekRo:
return "Solusek Ro";
case DeityTheTribunal:
return "The Tribunal";
case DeityTunare:
return "Tunare";
case DeityVeeshan:
return "Veeshan";
case DeityAgnostic_LB:
case DeityAgnostic:
return "Agnostic";
default:
return "Unknown";
};
if (EQ::deity::GetDeityMap().find(deity_type) != EQ::deity::GetDeityMap().end()) {
return EQ::deity::GetDeityMap().find(deity_type)->second;
}
return std::string();
}
+22 -21
View File
@@ -21,6 +21,8 @@
#define COMMON_DEITY_H
#include "types.h"
#include <map>
#include <string>
namespace EQ
@@ -49,30 +51,29 @@ namespace EQ
};
enum DeityTypeBit : uint32 {
bit_DeityNone = 0x00000000,
bit_DeityAgnostic = 0x00000001,
bit_DeityBertoxxulous = 0x00000002,
bit_DeityBrellSirilis = 0x00000004,
bit_DeityCazicThule = 0x00000008,
bit_DeityErollisiMarr = 0x00000010,
bit_DeityBristlebane = 0x00000020,
bit_DeityInnoruuk = 0x00000040,
bit_DeityKarana = 0x00000080,
bit_DeityAgnostic = 0x00000001,
bit_DeityBertoxxulous = 0x00000002,
bit_DeityBrellSirilis = 0x00000004,
bit_DeityCazicThule = 0x00000008,
bit_DeityErollisiMarr = 0x00000010,
bit_DeityBristlebane = 0x00000020,
bit_DeityInnoruuk = 0x00000040,
bit_DeityKarana = 0x00000080,
bit_DeityMithanielMarr = 0x00000100,
bit_DeityPrexus = 0x00000200,
bit_DeityQuellious = 0x00000400,
bit_DeityRallosZek = 0x00000800,
bit_DeityRodcetNife = 0x00001000,
bit_DeitySolusekRo = 0x00002000,
bit_DeityTheTribunal = 0x00004000,
bit_DeityTunare = 0x00008000,
bit_DeityVeeshan = 0x00010000,
bit_DeityAll = 0xFFFFFFFF
bit_DeityPrexus = 0x00000200,
bit_DeityQuellious = 0x00000400,
bit_DeityRallosZek = 0x00000800,
bit_DeityRodcetNife = 0x00001000,
bit_DeitySolusekRo = 0x00002000,
bit_DeityTheTribunal = 0x00004000,
bit_DeityTunare = 0x00008000,
bit_DeityVeeshan = 0x00010000,
bit_DeityAll = UINT32_MAX
};
extern DeityTypeBit ConvertDeityTypeToDeityTypeBit(DeityType deity_type);
extern DeityType ConvertDeityTypeBitToDeityType(DeityTypeBit deity_type_bit);
extern const char* DeityName(DeityType deity_type);
extern DeityTypeBit GetDeityBitmask(DeityType deity_type);
extern std::string GetDeityName(DeityType deity_type);
extern const std::map<DeityType, std::string>& GetDeityMap();
} /*deity*/
+89 -15
View File
@@ -1,22 +1,17 @@
#include <cereal/archives/json.hpp>
#include <cereal/archives/binary.hpp>
#include "discord.h"
#include "../http/httplib.h"
#include "../json/json.h"
#include "../strings.h"
#include "../eqemu_logsys.h"
#include "../events/player_event_logs.h"
constexpr int MAX_RETRIES = 10;
void Discord::SendWebhookMessage(const std::string &message, const std::string &webhook_url)
{
// validate
if (webhook_url.empty()) {
LogDiscord("[webhook_url] is empty");
return;
}
// validate
if (webhook_url.find("http://") == std::string::npos && webhook_url.find("https://") == std::string::npos) {
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
if (!ValidateWebhookUrl(webhook_url)) {
return;
}
@@ -28,13 +23,10 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
// client
httplib::Client cli(base_url.c_str());
httplib::Client cli(base_url);
cli.set_connection_timeout(0, 15000000); // 15 sec
cli.set_read_timeout(15, 0); // 15 seconds
cli.set_write_timeout(15, 0); // 15 seconds
httplib::Headers headers = {
{"Content-Type", "application/json"}
};
// payload
Json::Value p;
@@ -46,7 +38,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
int retries = 0;
int retry_timer = 1000;
while (retry) {
if (auto res = cli.Post(endpoint.c_str(), payload.str(), "application/json")) {
if (auto res = cli.Post(endpoint, payload.str(), "application/json")) {
if (res->status != 200 && res->status != 204) {
LogError("[Discord Client] Code [{}] Error [{}]", res->status, res->body);
}
@@ -62,7 +54,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
}
retry_timer = std::stoi(response["retry_after"].asString()) + 500;
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500;
}
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
@@ -81,6 +73,71 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
}
}
void Discord::SendPlayerEventMessage(
const PlayerEvent::PlayerEventContainer &e,
const std::string &webhook_url
)
{
if (!ValidateWebhookUrl(webhook_url)) {
return;
}
auto s = Strings::Split(webhook_url, '/');
// url
std::string base_url = fmt::format("{}//{}", s[0], s[2]);
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
// client
httplib::Client cli(base_url);
cli.set_connection_timeout(0, 15000000); // 15 sec
cli.set_read_timeout(15, 0); // 15 seconds
cli.set_write_timeout(15, 0); // 15 seconds
std::string payload = PlayerEventLogs::GetDiscordPayloadFromEvent(e);
if (payload.empty()) {
return;
}
bool retry = true;
int retries = 0;
int retry_timer = 1000;
while (retry) {
if (auto res = cli.Post(endpoint, payload, "application/json")) {
if (res->status != 200 && res->status != 204) {
LogError("Code [{}] Error [{}]", res->status, res->body);
}
if (res->status == 429) {
if (!res->body.empty()) {
std::stringstream ss(res->body);
Json::Value response;
try {
ss >> response;
}
catch (std::exception const &ex) {
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
}
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500;
}
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
std::this_thread::sleep_for(std::chrono::milliseconds(retry_timer + 500));
}
if (res->status == 204) {
retry = false;
}
if (retries > MAX_RETRIES) {
LogDiscord("Retries exceeded for player event message");
retry = false;
}
retries++;
}
}
}
std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string &message)
{
if (category_id == Logs::LogCategory::MySQLQuery) {
@@ -89,3 +146,20 @@ std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string
return message + "\n";
}
bool Discord::ValidateWebhookUrl(const std::string &webhook_url)
{
// validate
if (webhook_url.empty()) {
LogDiscord("[webhook_url] is empty");
return false;
}
// validate
if (!Strings::Contains(webhook_url, "http://") && !Strings::Contains(webhook_url, "https://")) {
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
return false;
}
return true;
}
+5
View File
@@ -4,11 +4,16 @@
#include <string>
#include "../types.h"
#include "../http/httplib.h"
#include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h"
class Discord {
public:
static void SendWebhookMessage(const std::string& message, const std::string& webhook_url);
static std::string FormatDiscordMessage(uint16 category_id, const std::string& message);
static void SendPlayerEventMessage(const PlayerEvent::PlayerEventContainer& e, const std::string &webhook_url);
static bool ValidateWebhookUrl(const std::string &webhook_url);
};
@@ -1,7 +1,6 @@
#include "discord_manager.h"
#include "../common/discord/discord.h"
#include "../common/eqemu_logsys.h"
#include "../common/strings.h"
#include "../../common/discord/discord.h"
#include "../events/player_event_logs.h"
void DiscordManager::QueueWebhookMessage(uint32 webhook_id, const std::string &message)
{
@@ -38,7 +37,7 @@ void DiscordManager::ProcessMessageQueue()
message,
webhook.webhook_url
);
message = "";
message.clear();
}
message += m;
@@ -52,10 +51,9 @@ void DiscordManager::ProcessMessageQueue()
webhook.webhook_url
);
}
message = "";
message.clear();
}
}
// final flush
if (!message.empty()) {
Discord::SendWebhookMessage(
@@ -67,3 +65,11 @@ void DiscordManager::ProcessMessageQueue()
webhook_message_queue.clear();
webhook_queue_lock.unlock();
}
void DiscordManager::QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e)
{
auto w = player_event_logs.GetDiscordWebhookUrlFromEventType(e.player_event_log.event_type_id);
if (!w.empty()) {
Discord::SendPlayerEventMessage(e, w);
}
}
@@ -4,12 +4,15 @@
#include <mutex>
#include <map>
#include <vector>
#include "../common/types.h"
#include "../../common/types.h"
#include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h"
class DiscordManager {
public:
void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
void ProcessMessageQueue();
void QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e);
private:
std::mutex webhook_queue_lock{};
std::map<uint32, std::vector<std::string>> webhook_message_queue{};
+34 -33
View File
@@ -197,11 +197,11 @@ const std::map<int, std::string>& EQ::constants::GetLanguageMap()
std::string EQ::constants::GetLanguageName(int language_id)
{
if (EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
return EQ::constants::GetLanguageMap().find(language_id)->second;
if (!EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
return std::string();
}
return std::string();
return EQ::constants::GetLanguageMap().find(language_id)->second;
}
const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
@@ -220,11 +220,11 @@ const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
{
if (EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
if (!EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
return std::string();
}
return std::string();
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
}
const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
@@ -243,11 +243,11 @@ const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
std::string EQ::constants::GetFlyModeName(int8 flymode_id)
{
if (EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) {
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
if (!EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) {
return std::string();
}
return std::string();
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
}
const std::map<bodyType, std::string>& EQ::constants::GetBodyTypeMap()
@@ -365,11 +365,11 @@ const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
std::string EQ::constants::GetConsiderLevelName(uint8 faction_consider_level)
{
if (EQ::constants::GetConsiderLevelMap().find(faction_consider_level) != EQ::constants::GetConsiderLevelMap().end()) {
return EQ::constants::GetConsiderLevelMap().find(faction_consider_level)->second;
if (!EQ::ValueWithin(faction_consider_level, ConsiderLevel::Ally, ConsiderLevel::Scowls)) {
return std::string();;
}
return std::string();
return EQ::constants::GetConsiderLevelMap().find(faction_consider_level)->second;
}
const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap()
@@ -386,11 +386,11 @@ const std::map<uint8, std::string>& EQ::constants::GetEnvironmentalDamageMap()
std::string EQ::constants::GetEnvironmentalDamageName(uint8 damage_type)
{
if (EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) {
return EQ::constants::GetEnvironmentalDamageMap().find(damage_type)->second;
if (!EQ::ValueWithin(damage_type, EnvironmentalDamage::Lava, EnvironmentalDamage::Trap)) {
return std::string();
}
return std::string();
return EQ::constants::GetEnvironmentalDamageMap().find(damage_type)->second;
}
const std::map<uint8, std::string>& EQ::constants::GetStuckBehaviorMap()
@@ -407,11 +407,11 @@ const std::map<uint8, std::string>& EQ::constants::GetStuckBehaviorMap()
std::string EQ::constants::GetStuckBehaviorName(uint8 behavior_id)
{
if (EQ::ValueWithin(behavior_id, StuckBehavior::RunToTarget, StuckBehavior::EvadeCombat)) {
return EQ::constants::GetStuckBehaviorMap().find(behavior_id)->second;
if (!EQ::ValueWithin(behavior_id, StuckBehavior::RunToTarget, StuckBehavior::EvadeCombat)) {
return std::string();
}
return std::string();
return EQ::constants::GetStuckBehaviorMap().find(behavior_id)->second;
}
const std::map<uint8, std::string>& EQ::constants::GetSpawnAnimationMap()
@@ -429,11 +429,11 @@ const std::map<uint8, std::string>& EQ::constants::GetSpawnAnimationMap()
std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id)
{
if (EQ::ValueWithin(animation_id, SpawnAnimations::Standing, SpawnAnimations::Looting)) {
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
if (!EQ::ValueWithin(animation_id, SpawnAnimations::Standing, SpawnAnimations::Looting)) {
return std::string();
}
return std::string();
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
}
const std::map<int, std::string>& EQ::constants::GetObjectTypeMap()
@@ -507,11 +507,12 @@ const std::map<int, std::string>& EQ::constants::GetObjectTypeMap()
std::string EQ::constants::GetObjectTypeName(int object_type)
{
if (EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) {
return EQ::constants::GetObjectTypeMap().find(object_type)->second;
if (!EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) {
return std::string();
}
return std::string();
return EQ::constants::GetObjectTypeMap().find(object_type)->second;
}
const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
@@ -527,11 +528,11 @@ const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
std::string EQ::constants::GetWeatherTypeName(uint8 weather_type)
{
if (EQ::ValueWithin(weather_type, WeatherTypes::None, WeatherTypes::Snowing)) {
return EQ::constants::GetWeatherTypeMap().find(weather_type)->second;
if (!EQ::ValueWithin(weather_type, WeatherTypes::None, WeatherTypes::Snowing)) {
return std::string();
}
return std::string();
return EQ::constants::GetWeatherTypeMap().find(weather_type)->second;
}
const std::map<uint8, std::string> &EQ::constants::GetEmoteEventTypeMap()
@@ -553,11 +554,11 @@ const std::map<uint8, std::string> &EQ::constants::GetEmoteEventTypeMap()
std::string EQ::constants::GetEmoteEventTypeName(uint8 emote_event_type)
{
if (EQ::ValueWithin(emote_event_type, EmoteEventTypes::LeaveCombat, EmoteEventTypes::OnDespawn)) {
return EQ::constants::GetEmoteEventTypeMap().find(emote_event_type)->second;
if (!EQ::ValueWithin(emote_event_type, EmoteEventTypes::LeaveCombat, EmoteEventTypes::OnDespawn)) {
return std::string();
}
return std::string();
return EQ::constants::GetEmoteEventTypeMap().find(emote_event_type)->second;
}
const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap()
@@ -573,9 +574,9 @@ const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap()
std::string EQ::constants::GetEmoteTypeName(uint8 emote_type)
{
if (EQ::ValueWithin(emote_type, EmoteTypes::Emote, EmoteTypes::Proximity)) {
return EQ::constants::GetEmoteTypeMap().find(emote_type)->second;
if (!EQ::ValueWithin(emote_type, EmoteTypes::Emote, EmoteTypes::Proximity)) {
return std::string();
}
return std::string();
return EQ::constants::GetEmoteTypeMap().find(emote_type)->second;
}
+40 -2
View File
@@ -334,7 +334,7 @@ namespace EQ
enum WeatherTypes : uint8 {
None,
Raining,
Snowing
Snowing
};
enum EmoteEventTypes : uint8 {
@@ -567,7 +567,7 @@ enum ReloadWorld : uint8 {
ForceRepop
};
enum MerchantBucketComparison : uint8 {
enum BucketComparison : uint8 {
BucketEqualTo = 0,
BucketNotEqualTo,
BucketGreaterThanOrEqualTo,
@@ -580,4 +580,42 @@ enum MerchantBucketComparison : uint8 {
BucketIsNotBetween
};
enum class EntityFilterType {
All,
Bots,
Clients,
NPCs
};
enum class ApplySpellType {
Solo,
Group,
Raid
};
namespace HeroicBonusBucket
{
const std::string WisMaxMana = "HWIS-MaxMana";
const std::string WisManaRegen = "HWIS-ManaRegen";
const std::string WisHealAmt = "HWIS-HealAmt";
const std::string IntMaxMana = "HINT-MaxMana";
const std::string IntManaRegen = "HINT-ManaRegen";
const std::string IntSpellDmg = "HINT-SpellDmg";
const std::string StrMeleeDamage = "HSTR-MeleeDamage";
const std::string StrShieldAC = "HSTR-ShieldAC";
const std::string StrMaxEndurance = "HSTR-MaxEndurance";
const std::string StrEnduranceRegen = "HSTR-EnduranceRegen";
const std::string StaMaxHP = "HSTA-MaxHP";
const std::string StaHPRegen = "HSTA-HPRegen";
const std::string StaMaxEndurance = "HSTA-MaxEndurance";
const std::string StaEnduranceRegen = "HSTA-EnduranceRegen";
const std::string AgiAvoidance = "HAGI-Avoidance";
const std::string AgiMaxEndurance = "HAGI-MaxEndurance";
const std::string AgiEnduranceRegen = "HAGI-EnduranceRegen";
const std::string DexRangedDamage = "HDEX-RangedDamage";
const std::string DexMaxEndurance = "HDEX-MaxEndurance";
const std::string DexEnduranceRegen = "HDEX-EnduranceRegen";
}
#endif /*COMMON_EMU_CONSTANTS_H*/
+4 -1
View File
@@ -35,7 +35,7 @@ N(OP_AltCurrencyMerchantRequest),
N(OP_AltCurrencyPurchase),
N(OP_AltCurrencyReclaim),
N(OP_AltCurrencySell),
N(OP_AltCurrencySellSelection),
N(OP_AltCurrencySellSelection), // Used by eqstr_us.txt 8066, 8068, 8069
N(OP_Animation),
N(OP_AnnoyingZoneUnknown),
N(OP_ApplyPoison),
@@ -316,6 +316,7 @@ N(OP_LootRequest),
N(OP_ManaChange),
N(OP_ManaUpdate),
N(OP_MarkNPC),
N(OP_MarkRaidNPC),
N(OP_Marquee),
N(OP_MemorizeSpell),
N(OP_Mend),
@@ -398,6 +399,8 @@ N(OP_PVPLeaderBoardRequest),
N(OP_PVPStats),
N(OP_QueryResponseThing),
N(OP_QueryUCSServerStatus),
N(OP_RaidDelegateAbility),
N(OP_RaidClearNPCMarks),
N(OP_RaidInvite),
N(OP_RaidJoin),
N(OP_RaidUpdate),
+44 -8
View File
@@ -79,6 +79,8 @@
#define ANIM_DEATH 0x73
#define ANIM_LOOT 0x69
constexpr int16 RECAST_TYPE_UNLINKED_ITEM = -1;
typedef enum {
eaStanding = 0,
eaSitting, //1
@@ -684,14 +686,6 @@ namespace Zones {
constexpr uint16 APPRENTICE = 999; // Designer Apprentice
}
//ZoneChange_Struct->success values
#define ZONE_ERROR_NOMSG 0
#define ZONE_ERROR_NOTREADY -1
#define ZONE_ERROR_VALIDPC -2
#define ZONE_ERROR_STORYZONE -3
#define ZONE_ERROR_NOEXPANSION -6
#define ZONE_ERROR_NOEXPERIENCE -7
typedef enum {
FilterNone = 0,
@@ -1016,4 +1010,46 @@ enum FVNoDropFlagRule
AdminOnly = 2
};
enum Anonymity : uint8
{
NotAnonymous,
Anonymous,
Roleplaying
};
enum ZoningMessage : int8 {
ZoneNoMessage = 0,
ZoneSuccess = 1,
ZoneNotReady = -1,
ZoneValidPC = -2,
ZoneStoryZone = -3,
ZoneNoExpansion = -6,
ZoneNoExperience = -7
};
enum class RecipeCountType : uint8
{
Component,
Container,
Fail,
Salvage,
Success
};
#define ALT_CURRENCY_ID_RADIANT 4
#define ALT_CURRENCY_ID_EBON 5
enum ResurrectionActions
{
Decline,
Accept
};
enum ScribeSpellActions
{
Scribe,
Memorize,
Unmemorize
};
#endif /*COMMON_EQ_CONSTANTS_H*/
+1 -1
View File
@@ -129,7 +129,7 @@ namespace EQ
LookupEntry(const LookupEntry *lookup_entry) { }
LookupEntry(
InventoryTypeSize_Struct InventoryTypeSize,
const InventoryTypeSize_Struct& InventoryTypeSize,
uint64 EquipmentBitmask,
uint64 GeneralBitmask,
uint64 CursorBitmask,
+1 -138
View File
@@ -236,26 +236,6 @@ uint32 EQApplicationPacket::serialize(uint16 opcode, unsigned char *dest) const
return size+OpCodeBytes;
}
/*EQProtocolPacket::EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len)
: BasePacket(buf, len),
opcode(op)
{
uint32 offset;
opcode=ntohs(*(const uint16 *)buf);
offset=2;
if (len-offset) {
pBuffer= new unsigned char[len-offset];
memcpy(pBuffer,buf+offset,len-offset);
size=len-offset;
} else {
pBuffer=nullptr;
size=0;
}
OpMgr=&RawOpcodeManager;
}*/
bool EQProtocolPacket::combine(const EQProtocolPacket *rhs)
{
bool result=false;
@@ -287,74 +267,6 @@ bool result=false;
}
/*
this is the code to do app-layer combining, instead of protocol layer.
this was taken out due to complex interactions with the opcode manager,
and will require a bit more thinking (likely moving into EQStream) to
get running again... but might be a good thing some day.
bool EQApplicationPacket::combine(const EQApplicationPacket *rhs)
{
uint32 newsize=0, offset=0;
unsigned char *tmpbuffer=nullptr;
if (opcode!=OP_AppCombined) {
newsize=app_opcode_size+size+(size>254?3:1)+app_opcode_size+rhs->size+(rhs->size>254?3:1);
tmpbuffer=new unsigned char [newsize];
offset=0;
if (size>254) {
tmpbuffer[offset++]=0xff;
*(uint16 *)(tmpbuffer+offset)=htons(size);
offset+=1;
} else {
tmpbuffer[offset++]=size;
}
offset+=serialize(tmpbuffer+offset);
} else {
newsize=size+app_opcode_size+rhs->size+(rhs->size>254?3:1);
tmpbuffer=new unsigned char [newsize];
memcpy(tmpbuffer,pBuffer,size);
offset=size;
}
if (rhs->size>254) {
tmpbuffer[offset++]=0xff;
*(uint16 *)(tmpbuffer+offset)=htons(rhs->size);
offset+=1;
} else {
tmpbuffer[offset++]=rhs->size;
}
offset+=rhs->serialize(tmpbuffer+offset);
size=offset;
opcode=OP_AppCombined;
delete[] pBuffer;
pBuffer=tmpbuffer;
return true;
}
*/
bool EQProtocolPacket::ValidateCRC(const unsigned char *buffer, int length, uint32 Key)
{
bool valid=false;
// OP_SessionRequest, OP_SessionResponse, OP_OutOfSession are not CRC'd
if (buffer[0]==0x00 && (buffer[1]==OP_SessionRequest || buffer[1]==OP_SessionResponse || buffer[1]==OP_OutOfSession)) {
valid=true;
} else {
uint16 comp_crc=CRC16(buffer,length-2,Key);
uint16 packet_crc=ntohs(*(const uint16 *)(buffer+length-2));
#ifdef EQN_DEBUG
if (packet_crc && comp_crc != packet_crc) {
std::cout << "CRC mismatch: comp=" << std::hex << comp_crc << ", packet=" << packet_crc << std::dec << std::endl;
}
#endif
valid = (!packet_crc || comp_crc == packet_crc);
}
return valid;
}
uint32 EQProtocolPacket::Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize)
{
uint32 newlen=0;
@@ -403,55 +315,6 @@ uint32 flag_offset=1,newlength;
return newlength;
}
void EQProtocolPacket::ChatDecode(unsigned char *buffer, int size, int DecodeKey)
{
if ((size >= 2) && buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
int Key=DecodeKey;
unsigned char *test=(unsigned char *)malloc(size);
buffer+=2;
size-=2;
int i;
for (i = 0 ; i+4 <= size ; i+=4)
{
int pt = (*(int*)&buffer[i])^(Key);
Key = (*(int*)&buffer[i]);
*(int*)&test[i]=pt;
}
unsigned char KC=Key&0xFF;
for ( ; i < size ; i++)
{
test[i]=buffer[i]^KC;
}
memcpy(buffer,test,size);
free(test);
}
}
void EQProtocolPacket::ChatEncode(unsigned char *buffer, int size, int EncodeKey)
{
if (buffer[1]!=0x01 && buffer[0]!=0x02 && buffer[0]!=0x1d) {
int Key=EncodeKey;
char *test=(char*)malloc(size);
int i;
buffer+=2;
size-=2;
for ( i = 0 ; i+4 <= size ; i+=4)
{
int pt = (*(int*)&buffer[i])^(Key);
Key = pt;
*(int*)&test[i]=pt;
}
unsigned char KC=Key&0xFF;
for ( ; i < size ; i++)
{
test[i]=buffer[i]^KC;
}
memcpy(buffer,test,size);
free(test);
}
}
EQApplicationPacket *EQApplicationPacket::Copy() const {
return(new EQApplicationPacket(*this));
}
@@ -515,4 +378,4 @@ std::string DumpPacketToString(const EQApplicationPacket* app){
std::ostringstream out;
out << DumpPacketHexToString(app->pBuffer, app->size);
return out.str();
}
}
-3
View File
@@ -80,11 +80,8 @@ public:
protected:
static bool ValidateCRC(const unsigned char *buffer, int length, uint32 Key);
static uint32 Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
static uint32 Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize);
static void ChatDecode(unsigned char *buffer, int size, int DecodeKey);
static void ChatEncode(unsigned char *buffer, int size, int EncodeKey);
uint16 GetRawOpcode() const { return(opcode); }
+40 -19
View File
@@ -29,7 +29,7 @@
#include "textures.h"
static const uint32 BUFF_COUNT = 25;
static const uint32 BUFF_COUNT = 42;
static const uint32 PET_BUFF_COUNT = 30;
static const uint32 MAX_MERC = 100;
static const uint32 MAX_MERC_GRADES = 10;
@@ -1793,6 +1793,17 @@ struct GMSummon_Struct {
/*104*/ uint32 unknown2; // E0 E0 56 00
};
struct GMFind_Struct {
char charname[64];
char gmname[64];
uint32 success;
uint32 zoneID;
float x;
float y;
float z;
uint32 unknown2;
};
struct GMGoto_Struct { // x,y is swapped as compared to summon and makes sense as own packet
/* 0*/ char charname[64];
@@ -3632,17 +3643,19 @@ struct LevelAppearance_Struct { //Sends a little graphic on level up
};
struct MerchantList {
uint32 id;
uint32 slot;
uint32 item;
int16 faction_required;
int8 level_required;
uint16 alt_currency_cost;
uint32 classes_required;
uint8 probability;
uint32 id;
uint32 slot;
uint32 item;
int16 faction_required;
int8 level_required;
uint8 min_status;
uint8 max_status;
uint16 alt_currency_cost;
uint32 classes_required;
uint8 probability;
std::string bucket_name;
std::string bucket_value;
uint8 bucket_comparison;
uint8 bucket_comparison;
};
struct TempMerchantList {
@@ -4092,7 +4105,9 @@ struct UpdateLeadershipAA_Struct {
enum
{
GroupLeadershipAbility_MarkNPC = 0
GroupLeadershipAbility_MarkNPC = 0,
RaidLeadershipAbility_MarkNPC = 16,
RaidLeadershipAbility_MainAssist = 19
};
struct DoGroupLeadershipAbility_Struct
@@ -4136,8 +4151,10 @@ struct InspectBuffs_Struct {
struct RaidGeneral_Struct {
/*00*/ uint32 action; //=10
/*04*/ char player_name[64]; //should both be the player's name
/*64*/ char leader_name[64];
/*132*/ uint32 parameter;
/*68*/ uint32 unknown1;
/*72*/ char leader_name[64];
/*136*/ uint32 parameter;
/*200*/ char note[64];
};
struct RaidAddMember_Struct {
@@ -4545,7 +4562,7 @@ struct ItemVerifyReply_Struct {
struct ItemRecastDelay_Struct {
/*000*/ uint32 recast_delay; // in seconds
/*004*/ uint32 recast_type;
/*008*/ uint32 unknown008;
/*008*/ bool ignore_casting_requirement; //Ignores recast times allows items to be reset?
/*012*/
};
@@ -5163,10 +5180,10 @@ struct AltCurrencySelectItemReply_Struct {
/*000*/ uint32 unknown000;
/*004*/ uint8 unknown004; //0xff
/*005*/ uint8 unknown005; //0xff
/*006*/ uint8 unknown006; //0xff
/*007*/ uint8 unknown007; //0xff
/*008*/ char item_name[64];
/*072*/ uint32 unknown074;
/*006*/ uint16 unknown006; //0xffff
/*008*/ uint16 unknown008; //0xffff
/*010*/ char item_name[64];
/*074*/ uint16 unknown074;
/*076*/ uint32 cost;
/*080*/ uint32 unknown080;
/*084*/ uint32 unknown084;
@@ -5520,7 +5537,11 @@ struct ServerLootItem_Struct {
uint32 aug_4; // uint32 aug_4;
uint32 aug_5; // uint32 aug_5;
uint32 aug_6; // uint32 aug_5;
uint8 attuned;
bool attuned;
std::string custom_data;
uint32 ornamenticon {};
uint32 ornamentidfile {};
uint32 ornament_hero_model {};
uint16 trivial_min_level;
uint16 trivial_max_level;
uint16 npc_min_level;
+2 -2
View File
@@ -26,7 +26,7 @@ EQStreamIdentifier::~EQStreamIdentifier() {
}
}
void EQStreamIdentifier::RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
void EQStreamIdentifier::RegisterPatch(EQStreamInterface::Signature sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) {
auto p = new Patch;
p->signature = sig;
p->name = name;
@@ -145,7 +145,7 @@ void EQStreamIdentifier::Process() {
}
void EQStreamIdentifier::AddStream(std::shared_ptr<EQStreamInterface> eqs) {
m_streams.push_back(Record(eqs));
m_streams.emplace_back(Record(eqs));
eqs = nullptr;
}
+1 -1
View File
@@ -18,7 +18,7 @@ public:
~EQStreamIdentifier();
//registration interface.
void RegisterPatch(const EQStreamInterface::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
void RegisterPatch(EQStreamInterface::Signature sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs);
//main processing interface
void Process();
-3
View File
@@ -23,9 +23,6 @@
EQDB EQDB::s_EQDB;
EQDB::EQDB() {
}
unsigned int EQDB::field_count() {
return mysql_field_count(mysql_ref);
}
+1 -1
View File
@@ -27,7 +27,7 @@
//this is the main object exported to perl.
class EQDB {
EQDB();
EQDB() = default;
public:
static EQDB *Singleton() { return(&s_EQDB); }
+25 -18
View File
@@ -19,6 +19,7 @@
#include "../common/global_define.h"
#include "eqemu_config.h"
#include "misc_functions.h"
#include "strings.h"
#include <iostream>
#include <sstream>
@@ -33,13 +34,13 @@ void EQEmuConfig::parse_config()
LongName = _root["server"]["world"].get("longname", "").asString();
WorldAddress = _root["server"]["world"].get("address", "").asString();
LocalAddress = _root["server"]["world"].get("localaddress", "").asString();
MaxClients = atoi(_root["server"]["world"].get("maxclients", "-1").asString().c_str());
MaxClients = Strings::ToInt(_root["server"]["world"].get("maxclients", "-1").asString());
SharedKey = _root["server"]["world"].get("key", "").asString();
LoginCount = 0;
if (_root["server"]["world"]["loginserver"].isObject()) {
LoginHost = _root["server"]["world"]["loginserver"].get("host", "login.eqemulator.net").asString();
LoginPort = atoi(_root["server"]["world"]["loginserver"].get("port", "5998").asString().c_str());
LoginPort = Strings::ToUnsignedInt(_root["server"]["world"]["loginserver"].get("port", "5998").asString());
LoginLegacy = false;
if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; }
LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString();
@@ -62,7 +63,7 @@ void EQEmuConfig::parse_config()
auto loginconfig = new LoginConfig;
loginconfig->LoginHost = _root["server"]["world"][str].get("host", "login.eqemulator.net").asString();
loginconfig->LoginPort = atoi(_root["server"]["world"][str].get("port", "5998").asString().c_str());
loginconfig->LoginPort = Strings::ToUnsignedInt(_root["server"]["world"][str].get("port", "5998").asString());
loginconfig->LoginAccount = _root["server"]["world"][str].get("account", "").asString();
loginconfig->LoginPassword = _root["server"]["world"][str].get("password", "").asString();
@@ -84,16 +85,22 @@ void EQEmuConfig::parse_config()
//The only way to enable locked is by switching to true, meaning this value is always false until manually set true
Locked = false;
if (_root["server"]["world"].get("locked", "false").asString() == "true") { Locked = true; }
auto_database_updates = false;
if (_root["server"].get("auto_database_updates", "true").asString() == "true") {
auto_database_updates = true;
}
WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
WorldTCPPort = atoi(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str());
WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString());
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
TelnetTCPPort = atoi(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str());
TelnetTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["telnet"].get("port", "9001").asString());
TelnetEnabled = false;
if (_root["server"]["world"]["telnet"].get("enabled", "false").asString() == "true") { TelnetEnabled = true; }
WorldHTTPMimeFile = _root["server"]["world"]["http"].get("mimefile", "mime.types").asString();
WorldHTTPPort = atoi(_root["server"]["world"]["http"].get("port", "9080").asString().c_str());
WorldHTTPPort = Strings::ToUnsignedInt(_root["server"]["world"]["http"].get("port", "9080").asString());
WorldHTTPEnabled = false;
if (_root["server"]["world"]["http"].get("enabled", "false").asString() == "true") {
@@ -108,9 +115,9 @@ void EQEmuConfig::parse_config()
* UCS
*/
ChatHost = _root["server"]["chatserver"].get("host", "eqchat.eqemulator.net").asString();
ChatPort = atoi(_root["server"]["chatserver"].get("port", "7778").asString().c_str());
ChatPort = Strings::ToUnsignedInt(_root["server"]["chatserver"].get("port", "7778").asString());
MailHost = _root["server"]["mailserver"].get("host", "eqmail.eqemulator.net").asString();
MailPort = atoi(_root["server"]["mailserver"].get("port", "7778").asString().c_str());
MailPort = Strings::ToUnsignedInt(_root["server"]["mailserver"].get("port", "7778").asString());
/**
* Database
@@ -118,7 +125,7 @@ void EQEmuConfig::parse_config()
DatabaseUsername = _root["server"]["database"].get("username", "eq").asString();
DatabasePassword = _root["server"]["database"].get("password", "eq").asString();
DatabaseHost = _root["server"]["database"].get("host", "localhost").asString();
DatabasePort = atoi(_root["server"]["database"].get("port", "3306").asString().c_str());
DatabasePort = Strings::ToUnsignedInt(_root["server"]["database"].get("port", "3306").asString());
DatabaseDB = _root["server"]["database"].get("db", "eq").asString();
/**
@@ -127,14 +134,14 @@ void EQEmuConfig::parse_config()
ContentDbUsername = _root["server"]["content_database"].get("username", "").asString();
ContentDbPassword = _root["server"]["content_database"].get("password", "").asString();
ContentDbHost = _root["server"]["content_database"].get("host", "").asString();
ContentDbPort = atoi(_root["server"]["content_database"].get("port", 0).asString().c_str());
ContentDbPort = Strings::ToUnsignedInt(_root["server"]["content_database"].get("port", 0).asString());
ContentDbName = _root["server"]["content_database"].get("db", "").asString();
/**
* QS
*/
QSDatabaseHost = _root["server"]["qsdatabase"].get("host", "localhost").asString();
QSDatabasePort = atoi(_root["server"]["qsdatabase"].get("port", "3306").asString().c_str());
QSDatabasePort = Strings::ToUnsignedInt(_root["server"]["qsdatabase"].get("port", "3306").asString());
QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString();
QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString();
QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString();
@@ -142,9 +149,9 @@ void EQEmuConfig::parse_config()
/**
* Zones
*/
DefaultStatus = atoi(_root["server"]["zones"].get("defaultstatus", 0).asString().c_str());
ZonePortLow = atoi(_root["server"]["zones"]["ports"].get("low", "7000").asString().c_str());
ZonePortHigh = atoi(_root["server"]["zones"]["ports"].get("high", "7999").asString().c_str());
DefaultStatus = Strings::ToUnsignedInt(_root["server"]["zones"].get("defaultstatus", 0).asString());
ZonePortLow = Strings::ToUnsignedInt(_root["server"]["zones"]["ports"].get("low", "7000").asString());
ZonePortHigh = Strings::ToUnsignedInt(_root["server"]["zones"]["ports"].get("high", "7999").asString());
/**
* Files
@@ -174,10 +181,10 @@ void EQEmuConfig::parse_config()
/**
* Launcher
*/
RestartWait = atoi(_root["server"]["launcher"]["timers"].get("restart", "10000").asString().c_str());
TerminateWait = atoi(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString().c_str());
InitialBootWait = atoi(_root["server"]["launcher"]["timers"].get("initial", "20000").asString().c_str());
ZoneBootInterval = atoi(_root["server"]["launcher"]["timers"].get("interval", "2000").asString().c_str());
RestartWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("restart", "10000").asString());
TerminateWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString());
InitialBootWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("initial", "20000").asString());
ZoneBootInterval = Strings::ToInt(_root["server"]["launcher"]["timers"].get("interval", "2000").asString());
#ifdef WIN32
ZoneExe = _root["server"]["launcher"].get("exe", "zone.exe").asString();
#else
+2 -6
View File
@@ -120,6 +120,8 @@ class EQEmuConfig
uint16 ZonePortHigh;
uint8 DefaultStatus;
bool auto_database_updates;
// uint16 DynamicCount;
// map<string,uint16> StaticZones;
@@ -147,12 +149,6 @@ class EQEmuConfig
return (_config);
}
// Allow the use to set the conf file to be used.
static void SetConfigFile(std::string file)
{
EQEmuConfig::ConfigFile = file;
}
// Load the config
static bool LoadConfig(const std::string& path = "")
{
+238 -187
View File
@@ -22,21 +22,19 @@
#include "rulesys.h"
#include "platform.h"
#include "strings.h"
#include "misc.h"
#include "discord/discord.h"
#include "repositories/discord_webhooks_repository.h"
#include "repositories/logsys_categories_repository.h"
#include "termcolor/rang.hpp"
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <time.h>
#include <sys/stat.h>
#include <algorithm>
std::ofstream process_log;
#include <filesystem>
#ifdef _WINDOWS
#include <direct.h>
#include <conio.h>
@@ -52,46 +50,12 @@ std::ofstream process_log;
#endif
/**
* Linux ANSI console color defines
*/
#define LC_RESET "\033[0m"
#define LC_BLACK "\033[30m" /* Black */
#define LC_RED "\033[31m" /* Red */
#define LC_GREEN "\033[32m" /* Green */
#define LC_YELLOW "\033[33m" /* Yellow */
#define LC_BLUE "\033[34m" /* Blue */
#define LC_MAGENTA "\033[35m" /* Magenta */
#define LC_CYAN "\033[36m" /* Cyan */
#define LC_WHITE "\033[37m" /* White */
namespace Console {
enum Color {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
LightMagenta = 13,
Yellow = 14,
White = 15
};
}
/**
* EQEmuLogSys Constructor
*/
EQEmuLogSys::EQEmuLogSys()
{
m_on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
m_on_log_gmsay_hook = [](uint16 log_type, const char *func, const std::string &) {};
m_on_log_console_hook = [](uint16 log_type, const std::string &) {};
}
@@ -120,14 +84,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
/**
* Set Defaults
*/
log_settings[Logs::WorldServer].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::ZoneServer].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::QSServer].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::UCSServer].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Loginserver].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::HeadlessClient].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::HotReload].log_to_console = static_cast<uint8>(Logs::General);
@@ -140,17 +98,15 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::ChecksumVerification].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::CombatRecord].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::Discord].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::QuestErrors].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::QuestErrors].log_to_console = static_cast<uint8>(Logs::General);
/**
* RFC 5424
*/
log_settings[Logs::Emergency].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Alert].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Critical].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Error].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Warning].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Notice].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Info].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Error].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Warning].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Info].log_to_console = static_cast<uint8>(Logs::General);
/**
* Set Category enabled status on defaults
@@ -194,24 +150,6 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
return this;
}
/**
* @param log_category
* @return
*/
bool EQEmuLogSys::IsRfc5424LogCategory(uint16 log_category)
{
return (
log_category == Logs::Emergency ||
log_category == Logs::Alert ||
log_category == Logs::Critical ||
log_category == Logs::Error ||
log_category == Logs::Warning ||
log_category == Logs::Notice ||
log_category == Logs::Info ||
log_category == Logs::Debug
);
}
/**
* @param debug_level
* @param log_category
@@ -242,64 +180,6 @@ void EQEmuLogSys::ProcessLogWrite(
}
}
/**
* @param log_category
* @return
*/
uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category)
{
switch (log_category) {
case Logs::Status:
case Logs::Normal:
return Console::Color::Yellow;
case Logs::MySQLError:
case Logs::Error:
return Console::Color::LightRed;
case Logs::MySQLQuery:
case Logs::Debug:
return Console::Color::LightGreen;
case Logs::Quests:
return Console::Color::LightCyan;
case Logs::Commands:
case Logs::Mercenaries:
return Console::Color::LightMagenta;
case Logs::Crash:
return Console::Color::LightRed;
default:
return Console::Color::Yellow;
}
}
/**
* @param log_category
* @return
*/
std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category)
{
switch (log_category) {
case Logs::Status:
case Logs::Normal:
return LC_YELLOW;
case Logs::MySQLError:
case Logs::Warning:
case Logs::Critical:
case Logs::Error:
return LC_RED;
case Logs::MySQLQuery:
case Logs::Debug:
return LC_GREEN;
case Logs::Quests:
return LC_CYAN;
case Logs::Commands:
case Logs::Mercenaries:
return LC_MAGENTA;
case Logs::Crash:
return LC_RED;
default:
return LC_YELLOW;
}
}
/**
* @param log_category
* @return
@@ -307,11 +187,10 @@ std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category)
uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
{
switch (log_category) {
case Logs::Status:
case Logs::Normal:
return Chat::Yellow;
case Logs::MySQLError:
case Logs::Crash:
case Logs::Error:
case Logs::MySQLError:
case Logs::QuestErrors:
return Chat::Red;
case Logs::MySQLQuery:
case Logs::Debug:
@@ -321,35 +200,206 @@ uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
case Logs::Commands:
case Logs::Mercenaries:
return Chat::Magenta;
case Logs::Crash:
return Chat::Red;
default:
return Chat::Yellow;
}
}
/**
* @param debug_level
* @param log_category
* @param message
*/
void EQEmuLogSys::ProcessConsoleMessage(uint16 log_category, const std::string &message)
void EQEmuLogSys::ProcessConsoleMessage(
uint16 log_category,
const std::string &message,
const char *file,
const char *func,
int line
)
{
#ifdef _WINDOWS
HANDLE console_handle;
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_FONT_INFOEX info = { 0 };
info.cbSize = sizeof(info);
info.dwFontSize.Y = 12; // leave X as zero
info.FontWeight = FW_NORMAL;
wcscpy(info.FaceName, L"Lucida Console");
SetCurrentConsoleFontEx(console_handle, NULL, &info);
SetConsoleTextAttribute(console_handle, EQEmuLogSys::GetWindowsConsoleColorFromCategory(log_category));
std::cout << message << "\n";
SetConsoleTextAttribute(console_handle, Console::Color::White);
#else
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
#endif
bool is_error = (
log_category == Logs::LogCategory::Error ||
log_category == Logs::LogCategory::MySQLError ||
log_category == Logs::LogCategory::Crash ||
log_category == Logs::LogCategory::QuestErrors
);
bool is_warning = (
log_category == Logs::LogCategory::Warning
);
(!is_error ? std::cout : std::cerr)
<< ""
<< rang::fgB::black
<< rang::style::bold
<< fmt::format("{:>6}", GetPlatformName().substr(0, 6))
<< rang::style::reset
<< rang::fgB::gray
<< " | "
<< ((is_error || is_warning) ? rang::fgB::red : rang::fgB::gray)
<< rang::style::bold
<< fmt::format("{:^10}", fmt::format("{}", Logs::LogCategoryName[log_category]).substr(0, 10))
<< rang::style::reset
<< rang::fgB::gray
<< " | "
<< rang::fgB::gray
<< rang::style::bold
<< fmt::format("{}", func)
<< rang::style::reset
<< rang::fgB::gray
<< " ";
if (RuleB(Logging, PrintFileFunctionAndLine)) {
(!is_error ? std::cout : std::cerr)
<< ""
<< rang::fgB::green
<< rang::style::bold
<< fmt::format("{:}", fmt::format("{}:{}:{}", std::filesystem::path(file).filename().string(), func, line))
<< rang::style::reset
<< " | ";
}
if (log_category == Logs::LogCategory::MySQLQuery) {
auto s = Strings::Split(message, "--");
if (s.size() > 1) {
std::string query = Strings::Trim(s[0]);
std::string meta = Strings::Trim(s[1]);
std::cout <<
rang::fgB::green
<<
query
<<
rang::style::reset;
std::cout <<
rang::fgB::black
<<
" -- "
<<
meta
<<
rang::style::reset;
}
}
else if (Strings::Contains(message, "[")) {
for (auto &e: Strings::Split(message, " ")) {
if (Strings::Contains(e, "[") && Strings::Contains(e, "]")) {
e = Strings::Replace(e, "[", "");
e = Strings::Replace(e, "]", "");
bool is_upper = false;
for (int i = 0; i < strlen(e.c_str()); i++) {
if (isupper(e[i])) {
is_upper = true;
}
}
// color matching in []
// ex: [<red>variable] would produce [variable] with red inside brackets
std::map<std::string, rang::fgB> colors = {
{"<black>", rang::fgB::black},
{"<green>", rang::fgB::green},
{"<yellow>", rang::fgB::yellow},
{"<blue>", rang::fgB::blue},
{"<magenta>", rang::fgB::magenta},
{"<cyan>", rang::fgB::cyan},
{"<gray>", rang::fgB::gray},
{"<red>", rang::fgB::red},
};
bool match_color = false;
for (auto &c: colors) {
if (Strings::Contains(e, c.first)) {
e = Strings::Replace(e, c.first, "");
(!is_error ? std::cout : std::cerr)
<< rang::fgB::gray
<< "["
<< rang::style::bold
<< c.second
<< e
<< rang::style::reset
<< rang::fgB::gray
<< "] ";
match_color = true;
}
}
// string match to colors
std::map<std::string, rang::fgB> matches = {
{"missing", rang::fgB::red},
{"error", rang::fgB::red},
{"ok", rang::fgB::green},
};
for (auto &c: matches) {
if (Strings::Contains(e, c.first)) {
(!is_error ? std::cout : std::cerr)
<< rang::fgB::gray
<< "["
<< rang::style::bold
<< c.second
<< e
<< rang::style::reset
<< rang::fgB::gray
<< "] ";
match_color = true;
}
}
// if we don't match a color in either the string matching or
// the color tag matching, we default to yellow inside brackets
// if uppercase, does not get colored
if (!match_color) {
if (!is_upper) {
(!is_error ? std::cout : std::cerr)
<< rang::fgB::gray
<< "["
<< rang::style::bold
<< rang::fgB::yellow
<< e
<< rang::style::reset
<< rang::fgB::gray
<< "] ";
}
else {
(!is_error ? std::cout : std::cerr) << rang::fgB::gray << "[" << e << "] ";
}
}
}
else {
(!is_error ? std::cout : std::cerr)
<< (is_error ? rang::fgB::red : rang::fgB::gray)
<< e
<< " ";
}
}
}
else {
(!is_error ? std::cout : std::cerr)
<< (is_error ? rang::fgB::red : rang::fgB::gray)
<< message
<< " ";
}
if (!origination_info.zone_short_name.empty()) {
(!is_error ? std::cout : std::cerr)
<<
rang::fgB::black
<<
"-- "
<<
fmt::format(
"[{}] ({}) inst_id [{}]",
origination_info.zone_short_name,
origination_info.zone_long_name,
origination_info.instance_id
);
}
(!is_error ? std::cout : std::cerr) << rang::style::reset << std::endl;
m_on_log_console_hook(log_category, message);
}
@@ -363,33 +413,6 @@ constexpr const char *str_end(const char *str)
return *str ? str_end(str + 1) : str;
}
/**
* @param str
* @return
*/
constexpr bool str_slant(const char *str)
{
return *str == '/' ? true : (*str ? str_slant(str + 1) : false);
}
/**
* @param str
* @return
*/
constexpr const char *r_slant(const char *str)
{
return *str == '/' ? (str + 1) : r_slant(str - 1);
}
/**
* @param str
* @return
*/
constexpr const char *base_file_name(const char *str)
{
return str_slant(str) ? r_slant(str_end(str)) : str;
}
/**
* Core logging function
*
@@ -417,12 +440,14 @@ void EQEmuLogSys::Out(
std::string prefix;
if (RuleB(Logging, PrintFileFunctionAndLine)) {
prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
prefix = fmt::format("[{0}::{1}:{2}] ", std::filesystem::path(file).filename().string(), func, line);
}
// remove this when we remove all legacy logs
bool ignore_log_legacy_format = (
log_category == Logs::Netcode ||
log_category == Logs::MySQLQuery ||
log_category == Logs::MySQLError ||
log_category == Logs::PacketServerClient ||
log_category == Logs::PacketClientServer ||
log_category == Logs::PacketServerToServer
@@ -440,11 +465,14 @@ void EQEmuLogSys::Out(
if (l.log_to_console_enabled) {
EQEmuLogSys::ProcessConsoleMessage(
log_category,
fmt::format("[{}] [{}] {}", GetPlatformName(), Logs::LogCategoryName[log_category], prefix + output_message)
output_message,
file,
func,
line
);
}
if (l.log_to_gmsay_enabled) {
m_on_log_gmsay_hook(log_category, output_message);
m_on_log_gmsay_hook(log_category, func, output_message);
}
if (l.log_to_file_enabled) {
EQEmuLogSys::ProcessLogWrite(
@@ -554,10 +582,14 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
*/
void EQEmuLogSys::SilenceConsoleLogging()
{
std::copy(std::begin(log_settings), std::end(log_settings), std::begin(pre_silence_settings));
for (int log_index = Logs::AA; log_index != Logs::MaxCategoryID; log_index++) {
log_settings[log_index].log_to_console = 0;
log_settings[log_index].is_category_enabled = 0;
}
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
}
/**
@@ -565,10 +597,7 @@ void EQEmuLogSys::SilenceConsoleLogging()
*/
void EQEmuLogSys::EnableConsoleLogging()
{
for (int log_index = Logs::AA; log_index != Logs::MaxCategoryID; log_index++) {
log_settings[log_index].log_to_console = Logs::General;
log_settings[log_index].is_category_enabled = 1;
}
std::copy(std::begin(pre_silence_settings), std::end(pre_silence_settings), std::begin(log_settings));
}
EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
@@ -625,7 +654,11 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
bool is_missing_in_database = std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end();
bool is_deprecated_category = Strings::Contains(fmt::format("{}", Logs::LogCategoryName[i]), "Deprecated");
if (!is_missing_in_database && is_deprecated_category) {
LogInfo("Logging category [{}] ({}) is now deprecated, deleting from database", Logs::LogCategoryName[i], i);
LogInfo(
"Logging category [{}] ({}) is now deprecated, deleting from database",
Logs::LogCategoryName[i],
i
);
LogsysCategoriesRepository::DeleteOne(*m_database, i);
}
@@ -658,6 +691,11 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
LogInfo("Loaded [{}] Discord webhooks", webhooks.size());
}
// force override this setting
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Crash].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::Crash].log_to_file = static_cast<uint8>(Logs::General);
return this;
}
@@ -754,10 +792,23 @@ const std::string &EQEmuLogSys::GetLogPath() const
return m_log_path;
}
EQEmuLogSys * EQEmuLogSys::SetLogPath(const std::string &log_path)
EQEmuLogSys *EQEmuLogSys::SetLogPath(const std::string &log_path)
{
EQEmuLogSys::m_log_path = log_path;
return this;
}
void EQEmuLogSys::DisableMySQLErrorLogs()
{
log_settings[Logs::MySQLError].log_to_file = 0;
log_settings[Logs::MySQLError].log_to_console = 0;
log_settings[Logs::MySQLError].log_to_gmsay = 0;
}
void EQEmuLogSys::EnableMySQLErrorLogs()
{
log_settings[Logs::MySQLError].log_to_file = 1;
log_settings[Logs::MySQLError].log_to_console = 1;
log_settings[Logs::MySQLError].log_to_gmsay = 1;
}
+77 -62
View File
@@ -39,8 +39,7 @@
namespace Logs {
enum DebugLevel {
General = 1, // 1 - Low-Level general debugging, useful info on single line
Moderate, // 2 - Informational based, used in functions, when particular things load
Detail // 3 - Use this for extreme detail in logging, usually in extreme debugging in the stack or interprocess communication
Detail // 2 - Use this for very chatty logging you want to leave in but don't want on by default
};
/**
@@ -54,7 +53,7 @@ namespace Logs {
AI,
Aggro,
Attack,
DeprecatedCS,
DeprecatedCS, // deprecated
Combat,
Commands,
Crash,
@@ -65,36 +64,36 @@ namespace Logs {
Inventory,
Launcher,
Netcode,
Normal,
Normal, // deprecated
Object,
Pathing,
QSServer,
QSServer, // deprecated
Quests,
Rules,
Skills,
Spawns,
Spells,
Status,
Status, // deprecated
TCPConnection,
Tasks,
Tradeskills,
Trading,
Tribute,
UCSServer,
WebInterfaceServer,
WorldServer,
ZoneServer,
UCSServer, // deprecated
WebInterfaceServer, // deprecated
WorldServer, // deprecated
ZoneServer, // deprecated
MySQLError,
MySQLQuery,
Mercenaries,
QuestDebug,
DeprecatedSC,
DeprecatedCSU,
DeprecatedSCD,
DeprecatedCSD,
Loginserver,
DeprecatedSC, // deprecated
DeprecatedCSU, // deprecated
DeprecatedSCD, // deprecated
DeprecatedCSD, // deprecated
Loginserver, // deprecated
ClientLogin,
HeadlessClient,
HeadlessClient, // deprecated
HPUpdate,
FixZ,
Food,
@@ -104,10 +103,10 @@ namespace Logs {
MobAppearance,
Info,
Warning,
Critical,
Emergency,
Alert,
Notice,
Critical, // deprecated
Emergency, // deprecated
Alert, // deprecated
Notice, // deprecated
AIScanClose,
AIYellForHelp,
AICastBeneficialClose,
@@ -135,6 +134,10 @@ namespace Logs {
PacketServerClient,
PacketClientServer,
PacketServerToServer,
Bugs,
QuestErrors,
PlayerEvents,
DataBuckets,
MaxCategoryID /* Don't Remove this */
};
@@ -158,52 +161,52 @@ namespace Logs {
"Inventory",
"Launcher",
"Netcode",
"Normal",
"Normal (Deprecated)",
"Object",
"Pathing",
"QS Server",
"QS Server (Deprecated)",
"Quests",
"Rules",
"Skills",
"Spawns",
"Spells",
"Status",
"Status (Deprecated)",
"TCP Connection",
"Tasks",
"Tradeskills",
"Trading",
"Tribute",
"UCS Server",
"WebInterface Server",
"World Server",
"Zone Server",
"MySQL Error",
"MySQL Query",
"UCS Server (Deprecated)",
"Web Interface (Deprecated)",
"World Server (Deprecated)",
"Zone Server (Deprecated)",
"QueryErr",
"Query",
"Mercenaries",
"Quest Debug",
"Deprecated",
"Deprecated",
"Deprecated",
"Deprecated",
"Login Server",
"Legacy Packet Logging (Deprecated)",
"Legacy Packet Logging (Deprecated)",
"Legacy Packet Logging (Deprecated)",
"Legacy Packet Logging (Deprecated)",
"Login Server (Deprecated)",
"Client Login",
"Headless Client",
"Headless Client (Deprecated)",
"HP Update",
"FixZ",
"Food",
"Traps",
"NPC Roam Box",
"NPC Scaling",
"Mob Appearance",
"MobAppearance",
"Info",
"Warning",
"Critical",
"Emergency",
"Alert",
"Notice",
"AI Scan Close",
"AI Yell For Help",
"AI Cast Beneficial Close",
"Critical (Deprecated)",
"Emergency (Deprecated)",
"Alert (Deprecated)",
"Notice (Deprecated)",
"AI Scan",
"AI Yell",
"AI CastBeneficial",
"AOE Cast",
"Entity Management",
"Flee",
@@ -220,14 +223,18 @@ namespace Logs {
"DialogueWindow",
"HTTP",
"Saylink",
"ChecksumVerification",
"ChecksumVer",
"CombatRecord",
"Hate",
"Discord",
"Faction",
"Packet-S->C",
"Packet-C->S",
"Packet-S->S"
"Packet S->C",
"Packet C->S",
"Packet S->S",
"Bugs",
"QuestErrors",
"PlayerEvents",
"DataBuckets",
};
}
@@ -319,6 +326,9 @@ public:
*/
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
// temporary bucket to re-load after silencing
LogSettings pre_silence_settings[Logs::LogCategory::MaxCategoryID]{};
struct LogEnabled {
bool log_to_file_enabled;
bool log_to_console_enabled;
@@ -341,7 +351,7 @@ public:
// gmsay
uint16 GetGMSayColorFromCategory(uint16 log_category);
EQEmuLogSys *SetGMSayHandler(std::function<void(uint16 log_type, const std::string &)> f)
EQEmuLogSys *SetGMSayHandler(const std::function<void(uint16 log_type, const char *func, const std::string &)>& f)
{
m_on_log_gmsay_hook = f;
return this;
@@ -369,25 +379,30 @@ public:
[[nodiscard]] const std::string &GetLogPath() const;
EQEmuLogSys * SetLogPath(const std::string &log_path);
void DisableMySQLErrorLogs();
void EnableMySQLErrorLogs();
private:
// reference to database
Database *m_database;
std::function<void(uint16 log_category, const std::string &)> m_on_log_gmsay_hook;
std::function<void(uint16 log_category, int webhook_id, const std::string &)> m_on_log_discord_hook;
std::function<void(uint16 log_category, const std::string &)> m_on_log_console_hook;
DiscordWebhooks m_discord_webhooks[MAX_DISCORD_WEBHOOK_ID]{};
bool m_file_logs_enabled = false;
int m_log_platform = 0;
std::string m_platform_file_name;
std::string m_log_path;
Database *m_database;
std::function<void(uint16 log_category, const char *func, const std::string &)> m_on_log_gmsay_hook;
std::function<void(uint16 log_category, int webhook_id, const std::string &)> m_on_log_discord_hook;
std::function<void(uint16 log_category, const std::string &)> m_on_log_console_hook;
DiscordWebhooks m_discord_webhooks[MAX_DISCORD_WEBHOOK_ID]{};
bool m_file_logs_enabled = false;
int m_log_platform = 0;
std::string m_platform_file_name;
std::string m_log_path;
std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
void ProcessConsoleMessage(uint16 log_category, const std::string &message);
void ProcessConsoleMessage(
uint16 log_category,
const std::string &message,
const char *file,
const char *func,
int line
);
void ProcessLogWrite(uint16 log_category, const std::string &message);
bool IsRfc5424LogCategory(uint16 log_category);
void InjectTablesIfNotExist();
};
+38 -516
View File
@@ -21,8 +21,6 @@
#ifndef EQEMU_EQEMU_LOGSYS_LOG_ALIASES_H
#define EQEMU_EQEMU_LOGSYS_LOG_ALIASES_H
#ifdef BUILD_LOGGING
#define LogAA(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::AA))\
OutF(LogSys, Logs::General, Logs::AA, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
@@ -38,11 +36,6 @@
OutF(LogSys, Logs::General, Logs::AI, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogAIModerate(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::AI))\
OutF(LogSys, Logs::Moderate, Logs::AI, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogAIDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::AI))\
OutF(LogSys, Logs::Detail, Logs::AI, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
@@ -208,16 +201,6 @@
OutF(LogSys, Logs::Detail, Logs::Pathing, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogQSServer(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::QSServer))\
OutF(LogSys, Logs::General, Logs::QSServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogQSServerDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::QSServer))\
OutF(LogSys, Logs::Detail, Logs::QSServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogQuests(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::Quests))\
OutF(LogSys, Logs::General, Logs::Quests, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
@@ -328,46 +311,6 @@
OutF(LogSys, Logs::Detail, Logs::Tribute, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogUCSServer(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::UCSServer))\
OutF(LogSys, Logs::General, Logs::UCSServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogUCSServerDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::UCSServer))\
OutF(LogSys, Logs::Detail, Logs::UCSServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogWebInterfaceServer(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::WebInterfaceServer))\
OutF(LogSys, Logs::General, Logs::WebInterfaceServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogWebInterfaceServerDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::WebInterfaceServer))\
OutF(LogSys, Logs::Detail, Logs::WebInterfaceServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogWorldServer(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::WorldServer))\
OutF(LogSys, Logs::General, Logs::WorldServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogWorldServerDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::WorldServer))\
OutF(LogSys, Logs::Detail, Logs::WorldServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogZoneServer(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::ZoneServer))\
OutF(LogSys, Logs::General, Logs::ZoneServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogZoneServerDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::ZoneServer))\
OutF(LogSys, Logs::Detail, Logs::ZoneServer, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogMySQLError(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::MySQLError))\
OutF(LogSys, Logs::General, Logs::MySQLError, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
@@ -439,16 +382,6 @@
OutF(LogSys, Logs::Detail, Logs::ClientLogin, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogHeadlessClient(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::HeadlessClient))\
OutF(LogSys, Logs::General, Logs::HeadlessClient, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogHeadlessClientDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::HeadlessClient))\
OutF(LogSys, Logs::Detail, Logs::HeadlessClient, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogHPUpdate(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::HPUpdate))\
OutF(LogSys, Logs::General, Logs::HPUpdate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
@@ -831,9 +764,44 @@
// manually created
#define LogExpeditionsModerate(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Moderate, Logs::Expeditions))\
OutF(LogSys, Logs::Moderate, Logs::Expeditions, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
#define LogBugs(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::Bugs))\
OutF(LogSys, Logs::General, Logs::Bugs, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogBugsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::Bugs))\
OutF(LogSys, Logs::Detail, Logs::Bugs, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogQuestErrors(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::QuestErrors))\
OutF(LogSys, Logs::General, Logs::QuestErrors, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogQuestErrorsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::QuestErrors))\
OutF(LogSys, Logs::Detail, Logs::QuestErrors, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogPlayerEvents(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::PlayerEvents))\
OutF(LogSys, Logs::General, Logs::PlayerEvents, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogPlayerEventsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::PlayerEvents))\
OutF(LogSys, Logs::Detail, Logs::PlayerEvents, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogDataBuckets(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::DataBuckets))\
OutF(LogSys, Logs::General, Logs::DataBuckets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogDataBucketsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::DataBuckets))\
OutF(LogSys, Logs::Detail, Logs::DataBuckets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
@@ -846,451 +814,5 @@
OutF(LogSys, debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#else
#define LogEmergency(message, ...) do {\
} while (0)
#define LogAlert(message, ...) do {\
} while (0)
#define LogCritical(message, ...) do {\
} while (0)
#define LogError(message, ...) do {\
} while (0)
#define LogWarning(message, ...) do {\
} while (0)
#define LogNotice(message, ...) do {\
} while (0)
#define LogInfo(message, ...) do {\
} while (0)
#define LogDebug(message, ...) do {\
} while (0)
/**
* Category
*/
#define LogAA(message, ...) do {\
} while (0)
#define LogAADetail(message, ...) do {\
} while (0)
#define LogAI(message, ...) do {\
} while (0)
#define LogAIDetail(message, ...) do {\
} while (0)
#define LogAggro(message, ...) do {\
} while (0)
#define LogAggroDetail(message, ...) do {\
} while (0)
#define LogAttack(message, ...) do {\
} while (0)
#define LogAttackDetail(message, ...) do {\
} while (0)
#define LogPacketClientServer(message, ...) do {\
} while (0)
#define LogPacketClientServerDetail(message, ...) do {\
} while (0)
#define LogCombat(message, ...) do {\
} while (0)
#define LogCombatDetail(message, ...) do {\
} while (0)
#define LogCommands(message, ...) do {\
} while (0)
#define LogCommandsDetail(message, ...) do {\
} while (0)
#define LogCrash(message, ...) do {\
} while (0)
#define LogCrashDetail(message, ...) do {\
} while (0)
#define LogDoors(message, ...) do {\
} while (0)
#define LogDoorsDetail(message, ...) do {\
} while (0)
#define LogGroup(message, ...) do {\
} while (0)
#define LogGroupDetail(message, ...) do {\
} while (0)
#define LogGuilds(message, ...) do {\
} while (0)
#define LogGuildsDetail(message, ...) do {\
} while (0)
#define LogInventory(message, ...) do {\
} while (0)
#define LogInventoryDetail(message, ...) do {\
} while (0)
#define LogLauncher(message, ...) do {\
} while (0)
#define LogLauncherDetail(message, ...) do {\
} while (0)
#define LogNetcode(message, ...) do {\
} while (0)
#define LogNetcodeDetail(message, ...) do {\
} while (0)
#define LogNormal(message, ...) do {\
} while (0)
#define LogNormalDetail(message, ...) do {\
} while (0)
#define LogObject(message, ...) do {\
} while (0)
#define LogObjectDetail(message, ...) do {\
} while (0)
#define LogPathing(message, ...) do {\
} while (0)
#define LogPathingDetail(message, ...) do {\
} while (0)
#define LogQSServer(message, ...) do {\
} while (0)
#define LogQSServerDetail(message, ...) do {\
} while (0)
#define LogQuests(message, ...) do {\
} while (0)
#define LogQuestsDetail(message, ...) do {\
} while (0)
#define LogRules(message, ...) do {\
} while (0)
#define LogRulesDetail(message, ...) do {\
} while (0)
#define LogSkills(message, ...) do {\
} while (0)
#define LogSkillsDetail(message, ...) do {\
} while (0)
#define LogSpawns(message, ...) do {\
} while (0)
#define LogSpawnsDetail(message, ...) do {\
} while (0)
#define LogSpells(message, ...) do {\
} while (0)
#define LogSpellsDetail(message, ...) do {\
} while (0)
#define LogTCPConnection(message, ...) do {\
} while (0)
#define LogTCPConnectionDetail(message, ...) do {\
} while (0)
#define LogTasks(message, ...) do {\
} while (0)
#define LogTasksDetail(message, ...) do {\
} while (0)
#define LogTradeskills(message, ...) do {\
} while (0)
#define LogTradeskillsDetail(message, ...) do {\
} while (0)
#define LogTrading(message, ...) do {\
} while (0)
#define LogTradingDetail(message, ...) do {\
} while (0)
#define LogTribute(message, ...) do {\
} while (0)
#define LogTributeDetail(message, ...) do {\
} while (0)
#define LogMySQLError(message, ...) do {\
} while (0)
#define LogMySQLErrorDetail(message, ...) do {\
} while (0)
#define LogMySQLQuery(message, ...) do {\
} while (0)
#define LogMySQLQueryDetail(message, ...) do {\
} while (0)
#define LogMercenaries(message, ...) do {\
} while (0)
#define LogMercenariesDetail(message, ...) do {\
} while (0)
#define LogQuestDebug(message, ...) do {\
} while (0)
#define LogQuestDebugDetail(message, ...) do {\
} while (0)
#define LogLoginserver(message, ...) do {\
} while (0)
#define LogLoginserverDetail(message, ...) do {\
} while (0)
#define LogClientLogin(message, ...) do {\
} while (0)
#define LogClientLoginDetail(message, ...) do {\
} while (0)
#define LogHeadlessClient(message, ...) do {\
} while (0)
#define LogHeadlessClientDetail(message, ...) do {\
} while (0)
#define LogHPUpdate(message, ...) do {\
} while (0)
#define LogHPUpdateDetail(message, ...) do {\
} while (0)
#define LogFixZ(message, ...) do {\
} while (0)
#define LogFixZDetail(message, ...) do {\
} while (0)
#define LogFood(message, ...) do {\
} while (0)
#define LogFoodDetail(message, ...) do {\
} while (0)
#define LogTraps(message, ...) do {\
} while (0)
#define LogTrapsDetail(message, ...) do {\
} while (0)
#define LogNPCRoamBox(message, ...) do {\
} while (0)
#define LogNPCRoamBoxDetail(message, ...) do {\
} while (0)
#define LogNPCScaling(message, ...) do {\
} while (0)
#define LogNPCScalingDetail(message, ...) do {\
} while (0)
#define LogMobAppearance(message, ...) do {\
} while (0)
#define LogMobAppearanceDetail(message, ...) do {\
} while (0)
#define LogStatus(message, ...) do {\
} while (0)
#define LogStatusDetail(message, ...) do {\
} while (0)
#define LogAIScanClose(message, ...) do {\
} while (0)
#define LogAIScanCloseDetail(message, ...) do {\
} while (0)
#define LogAIYellForHelp(message, ...) do {\
} while (0)
#define LogAIYellForHelpDetail(message, ...) do {\
} while (0)
#define LogAICastBeneficialClose(message, ...) do {\
} while (0)
#define LogAICastBeneficialCloseDetail(message, ...) do {\
} while (0)
#define LogAoeCast(message, ...) do {\
} while (0)
#define LogAoeCastDetail(message, ...) do {\
} while (0)
#define LogEntityManagement(message, ...) do {\
} while (0)
#define LogEntityManagementDetail(message, ...) do {\
} while (0)
#define LogFlee(message, ...) do {\
} while (0)
#define LogFleeDetail(message, ...) do {\
} while (0)
#define LogAura(message, ...) do {\
} while (0)
#define LogAuraDetail(message, ...) do {\
} while (0)
#define LogHotReload(message, ...) do {\
} while (0)
#define LogHotReloadDetail(message, ...) do {\
} while (0)
#define LogMerchants(message, ...) do {\
} while (0)
#define LogMerchantsDetail(message, ...) do {\
} while (0)
#define LogZonePoints(message, ...) do {\
} while (0)
#define LogZonePointsDetail(message, ...) do {\
} while (0)
#define LogExpeditions(message, ...) do {\
} while (0)
#define LogExpeditionsModerate(message, ...) do {\
} while (0)
#define LogExpeditionsDetail(message, ...) do {\
} while (0)
#define LogDynamicZones(message, ...) do {\
} while (0)
#define LogDynamicZonesDetail(message, ...) do {\
} while (0)
#define LogCheatList(message, ...) do {\
} while (0)
#define LogCheatDetail(message, ...) do {\
} while (0)
#define LogClientList(message, ...) do {\
} while (0)
#define LogClientListDetail(message, ...) do {\
} while (0)
#define LogDiaWind(message, ...) do {\
} while (0)
#define LogDiaWindDetail(message, ...) do {\
} while (0)
#define LogHTTP(message, ...) do {\
} while (0)
#define LogHTTPDetail(message, ...) do {\
} while (0)
#define LogSaylink(message, ...) do {\
} while (0)
#define LogSaylinkDetail(message, ...) do {\
} while (0)
#define LogScheduler(message, ...) do {\
} while (0)
#define LogSchedulerDetail(message, ...) do {\
} while (0)
#define LogCheat(message, ...) do {\
} while (0)
#define LogCheatDetail(message, ...) do {\
} while (0)
#define LogLoot(message, ...) do {\
} while (0)
#define LogLootDetail(message, ...) do {\
} while (0)
#define LogFood(message, ...) do {\
} while (0)
#define LogFoodDetail(message, ...) do {\
} while (0)
#define LogChecksumVerification(message, ...) do {\
} while (0)
#define LogChecksumVerificationDetail(message, ...) do {\
} while (0)
#define LogCombatRecord(message, ...) do {\
} while (0)
#define LogCombatRecordDetail(message, ...) do {\
} while (0)
#define LogHate(message, ...) do {\
} while (0)
#define LogHateDetail(message, ...) do {\
} while (0)
#define LogFaction(message, ...) do {\
} while (0)
#define LogFactionDetail(message, ...) do {\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
} while (0)
#define LogF(debug_level, log_category, message, ...) do {\
} while (0)
#endif
#endif //EQEMU_EQEMU_LOGSYS_LOG_ALIASES_H
+1 -5
View File
@@ -58,10 +58,6 @@ EQTime::EQTime()
SetCurrentEQTimeOfDay(start, time(0));
}
EQTime::~EQTime()
{
}
//getEQTimeOfDay - Reads timeConvert and writes the result to eqTimeOfDay
//This function was written by the ShowEQ Project.
//Input: Current Time (as a time_t), a pointer to the TimeOfDay_Struct that will be written to.
@@ -203,4 +199,4 @@ void EQTime::ToString(TimeOfDay_Struct *t, std::string &str) {
t->month, t->day, t->year, t->hour, t->minute);
buf[127] = '\0';
str = buf;
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ public:
//Constructor/destructor
EQTime(TimeOfDay_Struct start_eq, time_t start_real);
EQTime();
~EQTime();
~EQTime() = default;
//Get functions
int GetCurrentEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(GetCurrentEQTimeOfDay(time(nullptr), eqTimeOfDay)); }
+1 -1
View File
@@ -38,7 +38,7 @@ namespace EQ
_running = true;
for (size_t i = 0; i < threads; ++i) {
_threads.push_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this)));
_threads.emplace_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this)));
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,214 @@
#ifndef EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
#define EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
#include <string>
#include "player_events.h"
#include "../repositories/base/base_player_event_logs_repository.h"
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
struct DiscordField {
std::string name;
std::string value;
bool is_inline;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(name),
CEREAL_NVP(value),
cereal::make_nvp("inline", is_inline)
);
}
};
struct DiscordAuthor {
std::string name;
std::string icon_url;
std::string url;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(name),
CEREAL_NVP(icon_url),
CEREAL_NVP(url)
);
}
};
struct DiscordEmbed {
std::vector<DiscordField> fields;
std::string title;
std::string description;
std::string timestamp;
DiscordAuthor author;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(fields),
CEREAL_NVP(title),
CEREAL_NVP(description),
CEREAL_NVP(timestamp),
CEREAL_NVP(author)
);
}
};
struct DiscordWebhook {
std::vector<DiscordEmbed> embeds;
std::string content;
std::string avatar_url;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(embeds),
CEREAL_NVP(avatar_url),
CEREAL_NVP(content)
);
}
};
class PlayerEventDiscordFormatter {
public:
static std::string GetCurrentTimestamp();
static std::string FormatEventSay(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::SayEvent &e);
static std::string
FormatGMCommand(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::GMCommandEvent &e);
static void BuildDiscordField(
std::vector<DiscordField> *f,
const std::string &name,
const std::string &value,
bool is_inline = true
);
static void BuildBaseEmbed(
std::vector<DiscordEmbed> *e,
const std::vector<DiscordField> &f,
PlayerEvent::PlayerEventContainer c
);
static std::string FormatWithNodata(const PlayerEvent::PlayerEventContainer &c);
static std::string FormatAAGainedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::AAGainedEvent &e
);
static std::string FormatAAPurchasedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::AAPurchasedEvent &e
);
static std::string FormatDeathEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DeathEvent &e
);
static std::string FormatFishSuccessEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::FishSuccessEvent &e
);
static std::string FormatForageSuccessEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ForageSuccessEvent &e
);
static std::string FormatDestroyItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DestroyItemEvent &e
);
static std::string FormatDiscoverItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DiscoverItemEvent &e
);
static std::string FormatDroppedItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DroppedItemEvent &e
);
static std::string FormatLevelGainedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LevelGainedEvent &e
);
static std::string FormatLevelLostEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LevelLostEvent &e
);
static std::string FormatLootItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LootItemEvent &e
);
static std::string FormatGroundSpawnPickupEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::GroundSpawnPickupEvent &e
);
static std::string FormatMerchantPurchaseEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::MerchantPurchaseEvent &e
);
static std::string FormatMerchantSellEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::MerchantSellEvent &e
);
static std::string FormatNPCHandinEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::HandinEvent &e
);
static std::string FormatSkillUpEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::SkillUpEvent &e
);
static std::string FormatTaskAcceptEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskAcceptEvent &e
);
static std::string FormatTaskCompleteEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskCompleteEvent &e
);
static std::string FormatTaskUpdateEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskUpdateEvent &e
);
static std::string FormatTradeEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TradeEvent &e
);
static std::string FormatTraderPurchaseEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TraderPurchaseEvent &e
);
static std::string FormatTraderSellEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TraderSellEvent &e
);
static std::string FormatResurrectAcceptEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ResurrectAcceptEvent &e
);
static std::string FormatSplitMoneyEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::SplitMoneyEvent &e
);
static std::string FormatCombineEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::CombineEvent &e
);
static std::string FormatZoningEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ZoningEvent &e
);
static DiscordWebhook BuildDiscordWebhook(
const PlayerEvent::PlayerEventContainer &p,
std::vector<DiscordEmbed> &embeds
);
};
#endif //EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
+702
View File
@@ -0,0 +1,702 @@
#include <cereal/archives/json.hpp>
#include "player_event_logs.h"
#include "player_event_discord_formatter.h"
#include "../platform.h"
#include "../rulesys.h"
const uint32 PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL = 60 * 60 * 1000; // 1 hour
// general initialization routine
void PlayerEventLogs::Init()
{
m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000);
m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL);
ValidateDatabaseConnection();
// initialize settings array
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].id = i;
m_settings[i].event_name = PlayerEvent::EventName[i];
m_settings[i].event_enabled = 1;
m_settings[i].retention_days = 0;
m_settings[i].discord_webhook_id = 0;
}
SetSettingsDefaults();
// initialize settings from database
auto s = PlayerEventLogSettingsRepository::All(*m_database);
std::vector<int> db{};
db.reserve(s.size());
for (auto &e: s) {
if (e.id >= PlayerEvent::MAX) {
continue;
}
m_settings[e.id] = e;
db.emplace_back(e.id);
}
// insert entries that don't exist in database
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
bool is_in_database = std::find(db.begin(), db.end(), i) != db.end();
bool is_deprecated = Strings::Contains(PlayerEvent::EventName[i], "Deprecated");
bool is_implemented = !Strings::Contains(PlayerEvent::EventName[i], "Unimplemented");
// remove when deprecated
if (is_deprecated && is_in_database) {
LogInfo("[Deprecated] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
}
// remove when unimplemented if present
if (!is_implemented && is_in_database) {
LogInfo("[Unimplemented] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
}
bool is_missing_in_database = std::find(db.begin(), db.end(), i) == db.end();
if (is_missing_in_database && is_implemented && !is_deprecated) {
LogInfo(
"[New] PlayerEvent [{}] ({})",
PlayerEvent::EventName[i],
i
);
auto c = PlayerEventLogSettingsRepository::NewEntity();
c.id = i;
c.event_name = PlayerEvent::EventName[i];
c.event_enabled = m_settings[i].event_enabled;
c.retention_days = m_settings[i].retention_days;
PlayerEventLogSettingsRepository::InsertOne(*m_database, c);
}
}
bool processing_in_world = !RuleB(Logging, PlayerEventsQSProcess) && IsWorld();
bool processing_in_qs = RuleB(Logging, PlayerEventsQSProcess) && IsQueryServ();
// on initial boot process truncation
if (processing_in_world || processing_in_qs) {
ProcessRetentionTruncation();
}
}
// set the database object, during initialization
PlayerEventLogs *PlayerEventLogs::SetDatabase(Database *db)
{
m_database = db;
return this;
}
// validates whether the connection is valid or not, used in initialization
bool PlayerEventLogs::ValidateDatabaseConnection()
{
if (!m_database) {
LogError("No database connection");
return false;
}
return true;
}
// determines if the passed in event is enabled or not
// this is used to gate logic or events from firing off
// this is used prior to building the events, we don't want to
// build the events, send them through the stack in a function call
// only to discard them immediately afterwards, very wasteful on resources
// the quest api currently does this
bool PlayerEventLogs::IsEventEnabled(PlayerEvent::EventType event)
{
return m_settings[event].event_enabled ? m_settings[event].event_enabled : false;
}
// this processes any current player events on the queue
void PlayerEventLogs::ProcessBatchQueue()
{
m_batch_queue_lock.lock();
if (m_record_batch_queue.empty()) {
m_batch_queue_lock.unlock();
return;
}
BenchTimer benchmark;
// flush many
PlayerEventLogsRepository::InsertMany(*m_database, m_record_batch_queue);
LogPlayerEventsDetail(
"Processing batch player event log queue of [{}] took [{}]",
m_record_batch_queue.size(),
benchmark.elapsed()
);
// empty
m_record_batch_queue = {};
m_batch_queue_lock.unlock();
}
// adds a player event to the queue
void PlayerEventLogs::AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &log)
{
m_batch_queue_lock.lock();
m_record_batch_queue.emplace_back(log);
m_batch_queue_lock.unlock();
}
// fills common event data in the SendEvent function
void PlayerEventLogs::FillPlayerEvent(
const PlayerEvent::PlayerEvent &p,
PlayerEventLogsRepository::PlayerEventLogs &n
)
{
n.account_id = p.account_id;
n.character_id = p.character_id;
n.zone_id = p.zone_id;
n.instance_id = p.instance_id;
n.x = p.x;
n.y = p.y;
n.z = p.z;
n.heading = p.heading;
}
// builds the dynamic packet used to ship the player event over the wire
// supports serializing the struct so it can be rebuilt on the other end
std::unique_ptr<ServerPacket>
PlayerEventLogs::BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e)
{
EQ::Net::DynamicPacket dyn_pack;
dyn_pack.PutSerialize(0, e);
auto pack_size = sizeof(ServerSendPlayerEvent_Struct) + dyn_pack.Length();
auto pack = std::make_unique<ServerPacket>(ServerOP_PlayerEvent, static_cast<uint32_t>(pack_size));
auto buf = reinterpret_cast<ServerSendPlayerEvent_Struct *>(pack->pBuffer);
buf->cereal_size = static_cast<uint32_t>(dyn_pack.Length());
memcpy(buf->cereal_data, dyn_pack.Data(), dyn_pack.Length());
return pack;
}
const PlayerEventLogSettingsRepository::PlayerEventLogSettings *PlayerEventLogs::GetSettings() const
{
return m_settings;
}
bool PlayerEventLogs::IsEventDiscordEnabled(int32_t event_type_id)
{
// out of bounds check
if (event_type_id >= PlayerEvent::EventType::MAX) {
return false;
}
// make sure webhook id is set
if (m_settings[event_type_id].discord_webhook_id == 0) {
return false;
}
// ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return true;
}
return false;
}
std::string PlayerEventLogs::GetDiscordWebhookUrlFromEventType(int32_t event_type_id)
{
// out of bounds check
if (event_type_id >= PlayerEvent::EventType::MAX) {
return "";
}
// make sure webhook id is set
if (m_settings[event_type_id].discord_webhook_id == 0) {
return "";
}
// ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url;
}
return "";
}
// GM_COMMAND | [x] Implemented Formatter
// ZONING | [x] Implemented Formatter
// AA_GAIN | [x] Implemented Formatter
// AA_PURCHASE | [x] Implemented Formatter
// FORAGE_SUCCESS | [x] Implemented Formatter
// FORAGE_FAILURE | [x] Implemented Formatter
// FISH_SUCCESS | [x] Implemented Formatter
// FISH_FAILURE | [x] Implemented Formatter
// ITEM_DESTROY | [x] Implemented Formatter
// WENT_ONLINE | [x] Implemented Formatter
// WENT_OFFLINE | [x] Implemented Formatter
// LEVEL_GAIN | [x] Implemented Formatter
// LEVEL_LOSS | [x] Implemented Formatter
// LOOT_ITEM | [x] Implemented Formatter
// MERCHANT_PURCHASE | [x] Implemented Formatter
// MERCHANT_SELL | [x] Implemented Formatter
// GROUP_JOIN | [] Implemented Formatter
// GROUP_LEAVE | [] Implemented Formatter
// RAID_JOIN | [] Implemented Formatter
// RAID_LEAVE | [] Implemented Formatter
// GROUNDSPAWN_PICKUP | [x] Implemented Formatter
// NPC_HANDIN | [x] Implemented Formatter
// SKILL_UP | [x] Implemented Formatter
// TASK_ACCEPT | [x] Implemented Formatter
// TASK_UPDATE | [x] Implemented Formatter
// TASK_COMPLETE | [x] Implemented Formatter
// TRADE | [] Implemented Formatter
// GIVE_ITEM | [] Implemented Formatter
// SAY | [x] Implemented Formatter
// REZ_ACCEPTED | [x] Implemented Formatter
// DEATH | [x] Implemented Formatter
// COMBINE_FAILURE | [x] Implemented Formatter
// COMBINE_SUCCESS | [x] Implemented Formatter
// DROPPED_ITEM | [x] Implemented Formatter
// SPLIT_MONEY | [x] Implemented Formatter
// DZ_JOIN | [] Implemented Formatter
// DZ_LEAVE | [] Implemented Formatter
// TRADER_PURCHASE | [x] Implemented Formatter
// TRADER_SELL | [x] Implemented Formatter
// BANDOLIER_CREATE | [] Implemented Formatter
// BANDOLIER_SWAP | [] Implemented Formatter
// DISCOVER_ITEM | [X] Implemented Formatter
std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e)
{
std::string payload;
switch (e.player_event_log.event_type_id) {
case PlayerEvent::AA_GAIN: {
PlayerEvent::AAGainedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatAAGainedEvent(e, n);
break;
}
case PlayerEvent::AA_PURCHASE: {
PlayerEvent::AAPurchasedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatAAPurchasedEvent(e, n);
break;
}
case PlayerEvent::COMBINE_FAILURE:
case PlayerEvent::COMBINE_SUCCESS: {
PlayerEvent::CombineEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatCombineEvent(e, n);
break;
}
case PlayerEvent::DEATH: {
PlayerEvent::DeathEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDeathEvent(e, n);
break;
}
case PlayerEvent::DISCOVER_ITEM: {
PlayerEvent::DiscoverItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDiscoverItemEvent(e, n);
break;
}
case PlayerEvent::DROPPED_ITEM: {
PlayerEvent::DroppedItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDroppedItemEvent(e, n);
break;
}
case PlayerEvent::FISH_FAILURE:
case PlayerEvent::FORAGE_FAILURE:
case PlayerEvent::WENT_ONLINE:
case PlayerEvent::WENT_OFFLINE: {
payload = PlayerEventDiscordFormatter::FormatWithNodata(e);
break;
}
case PlayerEvent::FISH_SUCCESS: {
PlayerEvent::FishSuccessEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatFishSuccessEvent(e, n);
break;
}
case PlayerEvent::FORAGE_SUCCESS: {
PlayerEvent::ForageSuccessEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatForageSuccessEvent(e, n);
break;
}
case PlayerEvent::ITEM_DESTROY: {
PlayerEvent::DestroyItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDestroyItemEvent(e, n);
break;
}
case PlayerEvent::LEVEL_GAIN: {
PlayerEvent::LevelGainedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLevelGainedEvent(e, n);
break;
}
case PlayerEvent::LEVEL_LOSS: {
PlayerEvent::LevelLostEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLevelLostEvent(e, n);
break;
}
case PlayerEvent::LOOT_ITEM: {
PlayerEvent::LootItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLootItemEvent(e, n);
break;
}
case PlayerEvent::GROUNDSPAWN_PICKUP: {
PlayerEvent::GroundSpawnPickupEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatGroundSpawnPickupEvent(e, n);
break;
}
case PlayerEvent::NPC_HANDIN: {
PlayerEvent::HandinEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatNPCHandinEvent(e, n);
break;
}
case PlayerEvent::SAY: {
PlayerEvent::SayEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatEventSay(e, n);
break;
}
case PlayerEvent::GM_COMMAND: {
PlayerEvent::GMCommandEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatGMCommand(e, n);
break;
}
case PlayerEvent::SKILL_UP: {
PlayerEvent::SkillUpEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatSkillUpEvent(e, n);
break;
}
case PlayerEvent::SPLIT_MONEY: {
PlayerEvent::SplitMoneyEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatSplitMoneyEvent(e, n);
break;
}
case PlayerEvent::TASK_ACCEPT: {
PlayerEvent::TaskAcceptEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskAcceptEvent(e, n);
break;
}
case PlayerEvent::TASK_COMPLETE: {
PlayerEvent::TaskCompleteEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskCompleteEvent(e, n);
break;
}
case PlayerEvent::TASK_UPDATE: {
PlayerEvent::TaskUpdateEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskUpdateEvent(e, n);
break;
}
case PlayerEvent::TRADE: {
PlayerEvent::TradeEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTradeEvent(e, n);
break;
}
case PlayerEvent::TRADER_PURCHASE: {
PlayerEvent::TraderPurchaseEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTraderPurchaseEvent(e, n);
break;
}
case PlayerEvent::TRADER_SELL: {
PlayerEvent::TraderSellEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTraderSellEvent(e, n);
break;
}
case PlayerEvent::REZ_ACCEPTED: {
PlayerEvent::ResurrectAcceptEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatResurrectAcceptEvent(e, n);
break;
}
case PlayerEvent::MERCHANT_PURCHASE: {
PlayerEvent::MerchantPurchaseEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatMerchantPurchaseEvent(e, n);
break;
}
case PlayerEvent::MERCHANT_SELL: {
PlayerEvent::MerchantSellEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatMerchantSellEvent(e, n);
break;
}
case PlayerEvent::ZONING: {
PlayerEvent::ZoningEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatZoningEvent(e, n);
break;
}
default: {
LogInfo(
"Player event [{}] ({}) Discord formatter not implemented",
e.player_event_log.event_type_name,
e.player_event_log.event_type_id
);
}
}
return payload;
}
// general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess
void PlayerEventLogs::Process()
{
if (m_process_batch_events_timer.Check() || m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
ProcessBatchQueue();
}
if (m_process_retention_truncation_timer.Check()) {
ProcessRetentionTruncation();
}
}
void PlayerEventLogs::ProcessRetentionTruncation()
{
LogInfo("Running truncation");
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
if (m_settings[i].retention_days > 0) {
int deleted_count = PlayerEventLogsRepository::DeleteWhere(
*m_database,
fmt::format(
"event_type_id = {} AND created_at < (NOW() - INTERVAL {} DAY)",
i,
m_settings[i].retention_days
)
);
if (deleted_count > 0) {
LogInfo(
"Truncated [{}] events of type [{}] ({}) older than [{}] days",
deleted_count,
PlayerEvent::EventName[i],
i,
m_settings[i].retention_days
);
}
}
}
}
void PlayerEventLogs::ReloadSettings()
{
for (auto &e: PlayerEventLogSettingsRepository::All(*m_database)) {
m_settings[e.id] = e;
}
}
const int32_t RETENTION_DAYS_DEFAULT = 7;
void PlayerEventLogs::SetSettingsDefaults()
{
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
m_settings[PlayerEvent::ZONING].event_enabled = 1;
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
m_settings[PlayerEvent::TRADE].event_enabled = 1;
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SAY].event_enabled = 0;
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
m_settings[PlayerEvent::DEATH].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
}
}
+85
View File
@@ -0,0 +1,85 @@
#ifndef EQEMU_PLAYER_EVENT_LOGS_H
#define EQEMU_PLAYER_EVENT_LOGS_H
#include "../repositories/player_event_log_settings_repository.h"
#include "player_events.h"
#include "../servertalk.h"
#include "../repositories/player_event_logs_repository.h"
#include "../timer.h"
#include "../json/json_archive_single_line.h"
#include <cereal/archives/json.hpp>
#include <mutex>
class PlayerEventLogs {
public:
void Init();
void ReloadSettings();
PlayerEventLogs *SetDatabase(Database *db);
bool ValidateDatabaseConnection();
bool IsEventEnabled(PlayerEvent::EventType event);
void Process();
// batch queue
void AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &logs);
// main event record generic function
// can ingest any struct event types
template<typename T>
std::unique_ptr<ServerPacket> RecordEvent(
PlayerEvent::EventType t,
const PlayerEvent::PlayerEvent &p,
T e
)
{
auto n = PlayerEventLogsRepository::NewEntity();
FillPlayerEvent(p, n);
n.event_type_id = t;
std::stringstream ss;
{
cereal::JSONOutputArchiveSingleLine ar(ss);
e.serialize(ar);
}
n.event_type_name = PlayerEvent::EventName[t];
n.event_data = Strings::Contains(ss.str(), "noop") ? "{}" : ss.str();
n.created_at = std::time(nullptr);
auto c = PlayerEvent::PlayerEventContainer{
.player_event = p,
.player_event_log = n
};
return BuildPlayerEventPacket(c);
}
[[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings *GetSettings() const;
bool IsEventDiscordEnabled(int32_t event_type_id);
std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id);
static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e);
private:
Database *m_database; // reference to database
PlayerEventLogSettingsRepository::PlayerEventLogSettings m_settings[PlayerEvent::EventType::MAX]{};
// batch queue is used to record events in batch
std::vector<PlayerEventLogsRepository::PlayerEventLogs> m_record_batch_queue{};
static void FillPlayerEvent(const PlayerEvent::PlayerEvent &p, PlayerEventLogsRepository::PlayerEventLogs &n);
static std::unique_ptr<ServerPacket>
BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e);
// timers
Timer m_process_batch_events_timer; // events processing timer
Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings
// processing
std::mutex m_batch_queue_lock{};
void ProcessBatchQueue();
void ProcessRetentionTruncation();
void SetSettingsDefaults();
};
extern PlayerEventLogs player_event_logs;
#endif //EQEMU_PLAYER_EVENT_LOGS_H
+971
View File
@@ -0,0 +1,971 @@
#ifndef EQEMU_PLAYER_EVENTS_H
#define EQEMU_PLAYER_EVENTS_H
#include <string>
#include <cereal/cereal.hpp>
#include "../types.h"
#include "../repositories/player_event_logs_repository.h"
namespace PlayerEvent {
enum EventType {
GM_COMMAND = 1,
ZONING,
AA_GAIN,
AA_PURCHASE,
FORAGE_SUCCESS,
FORAGE_FAILURE,
FISH_SUCCESS,
FISH_FAILURE,
ITEM_DESTROY,
WENT_ONLINE,
WENT_OFFLINE,
LEVEL_GAIN,
LEVEL_LOSS,
LOOT_ITEM,
MERCHANT_PURCHASE,
MERCHANT_SELL,
GROUP_JOIN, // unimplemented
GROUP_LEAVE, // unimplemented
RAID_JOIN, // unimplemented
RAID_LEAVE, // unimplemented
GROUNDSPAWN_PICKUP,
NPC_HANDIN,
SKILL_UP,
TASK_ACCEPT,
TASK_UPDATE,
TASK_COMPLETE,
TRADE,
GIVE_ITEM, // unimplemented
SAY,
REZ_ACCEPTED,
DEATH,
COMBINE_FAILURE,
COMBINE_SUCCESS,
DROPPED_ITEM,
SPLIT_MONEY,
DZ_JOIN, // unimplemented
DZ_LEAVE, // unimplemented
TRADER_PURCHASE,
TRADER_SELL,
BANDOLIER_CREATE, // unimplemented
BANDOLIER_SWAP, // unimplemented
DISCOVER_ITEM,
POSSIBLE_HACK,
KILLED_NPC,
KILLED_NAMED_NPC,
KILLED_RAID_NPC,
ITEM_CREATION,
MAX // dont remove
};
// Don't ever remove items, even if they are deprecated
// If event is deprecated just tag (Deprecated) in the name
// If event is unimplemented just tag (Unimplemented) in the name
// Events don't get saved to the database if unimplemented or deprecated
// Events tagged as deprecated will get automatically removed
static const char *EventName[PlayerEvent::MAX] = {
"None",
"GM Command",
"Zoning",
"AA Gain",
"AA Purchase",
"Forage Success",
"Forage Failure",
"Fish Success",
"Fish Failure",
"Item Destroy",
"Went Online",
"Went Offline",
"Level Gain",
"Level Loss",
"Loot Item",
"Merchant Purchase",
"Merchant Sell",
"Group Join (Unimplemented)",
"Group Leave (Unimplemented)",
"Raid Join (Unimplemented)",
"Raid Leave (Unimplemented)",
"Groundspawn Pickup",
"NPC Handin",
"Skill Up",
"Task Accept",
"Task Update",
"Task Complete",
"Trade",
"Given Item (Unimplemented)",
"Say",
"Rez Accepted",
"Death",
"Combine Failure",
"Combine Success",
"Dropped Item",
"Split Money",
"DZ Join (Unimplemented)",
"DZ Leave (Unimplemented)",
"Trader Purchase",
"Trader Sell",
"Bandolier Create (Unimplemented)",
"Bandolier Swap (Unimplemented)",
"Discover Item",
"Possible Hack",
"Killed NPC",
"Killed Named NPC",
"Killed Raid NPC",
"Item Creation"
};
// Generic struct used by all events
struct PlayerEvent {
int64 account_id;
std::string account_name;
int64 character_id;
std::string character_name;
int64 guild_id;
std::string guild_name;
int zone_id;
std::string zone_short_name;
std::string zone_long_name;
int instance_id;
float x;
float y;
float z;
float heading;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(account_id),
CEREAL_NVP(account_name),
CEREAL_NVP(character_id),
CEREAL_NVP(character_name),
CEREAL_NVP(guild_id),
CEREAL_NVP(guild_name),
CEREAL_NVP(zone_id),
CEREAL_NVP(zone_short_name),
CEREAL_NVP(zone_long_name),
CEREAL_NVP(instance_id),
CEREAL_NVP(x),
CEREAL_NVP(y),
CEREAL_NVP(z),
CEREAL_NVP(heading)
);
}
};
// contains metadata in use for things like log/discord formatters
// along with the actual event to be persisted
struct PlayerEventContainer {
PlayerEvent player_event;
PlayerEventLogsRepository::PlayerEventLogs player_event_log;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(player_event),
CEREAL_NVP(player_event_log)
);
}
};
// used in events with no extra data
struct EmptyEvent {
std::string noop; // noop, gets discard upstream
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(noop)
);
}
};
// used in Trade event
struct ItemCreationEvent {
int64 item_id;
std::string item_name;
uint16 to_slot;
int16 charges;
uint32 aug1;
uint32 aug2;
uint32 aug3;
uint32 aug4;
uint32 aug5;
uint32 aug6;
bool attuned;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(to_slot),
CEREAL_NVP(charges),
CEREAL_NVP(aug1),
CEREAL_NVP(aug2),
CEREAL_NVP(aug3),
CEREAL_NVP(aug4),
CEREAL_NVP(aug5),
CEREAL_NVP(aug6),
CEREAL_NVP(attuned)
);
}
};
// used in Trade event
struct TradeItem {
int64 item_id;
std::string item_name;
int32 slot;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(slot)
);
}
};
// used in Trade event
class TradeItemEntry {
public:
uint16 slot;
uint32 item_id;
std::string item_name;
uint16 charges;
uint32 aug_1_item_id;
std::string aug_1_item_name;
uint32 aug_2_item_id;
std::string aug_2_item_name;
uint32 aug_3_item_id;
std::string aug_3_item_name;
uint32 aug_4_item_id;
std::string aug_4_item_name;
uint32 aug_5_item_id;
std::string aug_5_item_name;
uint32 aug_6_item_id;
std::string aug_6_item_name;
bool in_bag;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(slot),
CEREAL_NVP(item_id),
CEREAL_NVP(charges),
CEREAL_NVP(aug_1_item_id),
CEREAL_NVP(aug_2_item_id),
CEREAL_NVP(aug_3_item_id),
CEREAL_NVP(aug_4_item_id),
CEREAL_NVP(aug_5_item_id),
CEREAL_NVP(in_bag)
);
}
};
/**
* Events
*/
struct Money {
int32 platinum;
int32 gold;
int32 silver;
int32 copper;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(platinum),
CEREAL_NVP(gold),
CEREAL_NVP(silver),
CEREAL_NVP(copper)
);
}
};
struct TradeEvent {
uint32 character_1_id;
std::string character_1_name;
uint32 character_2_id;
std::string character_2_name;
Money character_1_give_money;
Money character_2_give_money;
std::vector<TradeItemEntry> character_1_give_items;
std::vector<TradeItemEntry> character_2_give_items;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(character_1_id),
CEREAL_NVP(character_1_name),
CEREAL_NVP(character_2_id),
CEREAL_NVP(character_2_name),
CEREAL_NVP(character_1_give_money),
CEREAL_NVP(character_2_give_money),
CEREAL_NVP(character_1_give_items),
CEREAL_NVP(character_2_give_items)
);
}
};
struct GMCommandEvent {
std::string message;
std::string target;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message),
CEREAL_NVP(target)
);
}
};
struct ZoningEvent {
std::string from_zone_long_name;
std::string from_zone_short_name;
int32 from_zone_id;
int32 from_instance_id;
int32 from_instance_version;
std::string to_zone_long_name;
std::string to_zone_short_name;
int32 to_zone_id;
int32 to_instance_id;
int32 to_instance_version;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_zone_long_name),
CEREAL_NVP(from_zone_short_name),
CEREAL_NVP(from_zone_id),
CEREAL_NVP(from_instance_id),
CEREAL_NVP(from_instance_version),
CEREAL_NVP(to_zone_long_name),
CEREAL_NVP(to_zone_short_name),
CEREAL_NVP(to_zone_id),
CEREAL_NVP(to_instance_id),
CEREAL_NVP(to_instance_version)
);
}
};
struct AAGainedEvent {
uint32 aa_gained;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(CEREAL_NVP(aa_gained));
}
};
struct AAPurchasedEvent {
uint32 aa_id;
int32 aa_cost;
int32 aa_previous_id;
int32 aa_next_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(aa_id),
CEREAL_NVP(aa_cost),
CEREAL_NVP(aa_previous_id),
CEREAL_NVP(aa_next_id)
);
}
};
struct ForageSuccessEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct FishSuccessEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct DestroyItemEvent {
uint32 item_id;
std::string item_name;
int16 charges;
std::string reason;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(reason),
CEREAL_NVP(charges)
);
}
};
struct LevelGainedEvent {
uint32 from_level;
uint8 to_level;
int levels_gained;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_level),
CEREAL_NVP(to_level),
CEREAL_NVP(levels_gained)
);
}
};
struct LevelLostEvent {
uint32 from_level;
uint8 to_level;
int levels_lost;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_level),
CEREAL_NVP(to_level),
CEREAL_NVP(levels_lost)
);
}
};
struct LootItemEvent {
uint32 item_id;
std::string item_name;
int16 charges;
uint32 npc_id;
std::string corpse_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(npc_id),
CEREAL_NVP(corpse_name)
);
}
};
struct MerchantPurchaseEvent {
uint32 npc_id;
std::string merchant_name;
uint32 merchant_type;
uint32 item_id;
std::string item_name;
int16 charges;
uint32 cost;
uint32 alternate_currency_id;
uint64 player_money_balance;
uint64 player_currency_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(merchant_name),
CEREAL_NVP(merchant_type),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(alternate_currency_id),
CEREAL_NVP(player_money_balance),
CEREAL_NVP(player_currency_balance)
);
}
};
struct MerchantSellEvent {
uint32 npc_id;
std::string merchant_name;
uint32 merchant_type;
uint32 item_id;
std::string item_name;
int16 charges;
uint32 cost;
uint32 alternate_currency_id;
uint64 player_money_balance;
uint64 player_currency_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(merchant_name),
CEREAL_NVP(merchant_type),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(alternate_currency_id),
CEREAL_NVP(player_money_balance),
CEREAL_NVP(player_currency_balance)
);
}
};
struct SkillUpEvent {
uint32 skill_id;
int value;
int16 max_skill;
std::string against_who;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(skill_id),
CEREAL_NVP(value),
CEREAL_NVP(max_skill),
CEREAL_NVP(against_who)
);
}
};
struct TaskAcceptEvent {
uint32 npc_id;
std::string npc_name;
uint32 task_id;
std::string task_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(task_id),
CEREAL_NVP(task_name)
);
}
};
struct TaskUpdateEvent {
uint32 task_id;
std::string task_name;
uint32 activity_id;
uint32 done_count;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(task_id),
CEREAL_NVP(task_name),
CEREAL_NVP(activity_id),
CEREAL_NVP(done_count)
);
}
};
struct TaskCompleteEvent {
uint32 task_id;
std::string task_name;
uint32 activity_id;
uint32 done_count;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(task_id),
CEREAL_NVP(task_name),
CEREAL_NVP(activity_id),
CEREAL_NVP(done_count)
);
}
};
struct GroundSpawnPickupEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct SayEvent {
std::string message;
std::string target;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message),
CEREAL_NVP(target)
);
}
};
struct ResurrectAcceptEvent {
std::string resurrecter_name;
std::string spell_name;
uint32 spell_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(resurrecter_name),
CEREAL_NVP(spell_name),
CEREAL_NVP(spell_id)
);
}
};
struct CombineEvent {
uint32 recipe_id;
std::string recipe_name;
uint32 made_count;
uint32 tradeskill_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(recipe_id),
CEREAL_NVP(recipe_name),
CEREAL_NVP(made_count),
CEREAL_NVP(tradeskill_id)
);
}
};
struct DroppedItemEvent {
uint32 item_id;
std::string item_name;
int16 slot_id;
uint32 charges;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(slot_id),
CEREAL_NVP(charges)
);
}
};
struct DeathEvent {
uint32 killer_id;
std::string killer_name;
int64 damage;
uint32 spell_id;
std::string spell_name;
int skill_id;
std::string skill_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(killer_id),
CEREAL_NVP(killer_name),
CEREAL_NVP(damage),
CEREAL_NVP(spell_id),
CEREAL_NVP(spell_name),
CEREAL_NVP(skill_id),
CEREAL_NVP(skill_name)
);
}
};
struct SplitMoneyEvent {
uint32 copper;
uint32 silver;
uint32 gold;
uint32 platinum;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(copper),
CEREAL_NVP(silver),
CEREAL_NVP(gold),
CEREAL_NVP(platinum),
CEREAL_NVP(player_money_balance)
);
}
};
struct TraderPurchaseEvent {
uint32 item_id;
std::string item_name;
uint32 trader_id;
std::string trader_name;
uint32 price;
uint32 charges;
uint32 total_cost;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(trader_id),
CEREAL_NVP(trader_name),
CEREAL_NVP(price),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
};
struct TraderSellEvent {
uint32 item_id;
std::string item_name;
uint32 buyer_id;
std::string buyer_name;
uint32 price;
uint32 charges;
uint32 total_cost;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(buyer_id),
CEREAL_NVP(buyer_name),
CEREAL_NVP(price),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
};
struct DiscoverItemEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
class HandinEntry {
public:
uint32 item_id;
std::string item_name;
uint16 charges;
bool attuned;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(attuned)
);
}
};
class HandinMoney {
public:
uint32 copper;
uint32 silver;
uint32 gold;
uint32 platinum;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(copper),
CEREAL_NVP(silver),
CEREAL_NVP(gold),
CEREAL_NVP(platinum)
);
}
};
struct HandinEvent {
uint32 npc_id;
std::string npc_name;
std::vector<HandinEntry> handin_items;
HandinMoney handin_money;
std::vector<HandinEntry> return_items;
HandinMoney return_money;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(handin_items),
CEREAL_NVP(handin_money),
CEREAL_NVP(return_items),
CEREAL_NVP(return_money)
);
}
};
struct PossibleHackEvent {
std::string message;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message)
);
}
};
struct KilledNPCEvent {
uint32 npc_id;
std::string npc_name;
uint32 combat_time_seconds;
uint64 total_damage_per_second_taken;
uint64 total_heal_per_second_taken;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(combat_time_seconds),
CEREAL_NVP(total_damage_per_second_taken),
CEREAL_NVP(total_heal_per_second_taken)
);
}
};
}
#endif //EQEMU_PLAYER_EVENTS_H
#define RecordPlayerEventLog(event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\
worldserver.SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
GetPlayerEvent(),\
event_data\
).get()\
);\
}\
} while (0)
#define RecordPlayerEventLogWithClient(c, event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\
worldserver.SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
(c)->GetPlayerEvent(),\
event_data\
).get()\
);\
}\
} while (0)
+2 -2
View File
@@ -96,12 +96,12 @@ bool IsOfEqualRace(int r1, int r2)
// TODO: add more values
switch (r1) {
case DARK_ELF:
if (r2 == 77) {
if (r2 == RACE_NERIAK_CITIZEN_77) {
return true;
}
break;
case BARBARIAN:
if (r2 == 90) {
if (r2 == RACE_HALAS_CITIZEN_90) {
return true;
}
}
+19 -33
View File
@@ -132,7 +132,7 @@ enum { //reuse times
InstillDoubtReuseTime = 9,
FishingReuseTime = 11,
ForagingReuseTime = 50,
MendReuseTime = 290,
MendReuseTime = 360,
BashReuseTime = 5,
BackstabReuseTime = 9,
KickReuseTime = 5,
@@ -218,14 +218,14 @@ enum { //some random constants
#define HARD_LEVEL_CAP 127
//the square of the maximum range at whihc you could possibly use NPC services (shop, tribute, etc)
#define USE_NPC_RANGE2 200*200 //arbitrary right now
#define USE_NPC_RANGE2 40000 //arbitrary right now
// Squared range for rampage 75.0 * 75.0 for now
#define NPC_RAMPAGE_RANGE2 5625.0f
//the formula for experience for killing a mob.
//level is the only valid variable to use
#define EXP_FORMULA level*level*75*35/10
#define EXP_FORMULA (level * level * 75 * 35 / 10)
#define HIGHEST_AA_VALUE 35
@@ -240,36 +240,22 @@ enum { //some random constants
//Some hard coded statuses from commands and other places:
enum {
minStatusToBeGM = 40,
minStatusToUseGMCommands = 80,
minStatusToKick = 150,
minStatusToAvoidFalling = 100,
minStatusToHaveInvalidSpells = 80,
minStatusToHaveInvalidSkills = 80,
minStatusToIgnoreZoneFlags = 80,
minStatusToBeGM = 40,
minStatusToUseGMCommands = 80,
minStatusToKick = 150,
minStatusToAvoidFalling = 100,
minStatusToIgnoreZoneFlags = 80,
minStatusToSeeOthersZoneFlags = 80,
minStatusToEditOtherGuilds = 80,
commandMovecharSelfOnly = 80, //below this == only self move allowed
commandMovecharToSpecials = 200, //ability to send people to cshom/load zones
commandZoneToSpecials = 80, //zone to cshome, out of load zones
commandToggleAI = 250, //can turn NPC AI on and off
commandCastSpecials = 100, //can cast special spells
commandInstacast = 100, //insta-cast all #casted spells
commandLevelAboveCap = 100, //can #level players above level cap
commandLevelNPCAboveCap = 100, //can #level NPCs above level cap
commandSetSkillsOther = 100, //ability to setskills on others
commandRaceOthers = 100, //ability to #race on others
commandGenderOthers = 100, //ability to #gender on others
commandTextureOthers = 100, //ability to #texture on others
commandDoAnimOthers = 100, //can #doanim on others
commandLockZones = 101, //can lock or unlock zones
commandEditPlayerCorpses = 150, //can Edit Player Corpses
commandChangeFlags = 200, //ability to set/refresh flags
commandBanPlayers = 100, //can set bans on players
commandChangeDatarate = 201, //edit client's data rate
commandZoneToCoords = 0, //can #zone with coords
commandInterrogateInv = 100, //below this == only log on error state and self-only target dump
commandInvSnapshot = 150 //ability to clear/restore snapshots
minStatusToEditOtherGuilds = 80,
commandMovecharSelfOnly = 80, //below this == only self move allowed
commandMovecharToSpecials = 200, //ability to send people to cshom/load zones
commandCastSpecials = 100, //can cast special spells
commandInstacast = 100, //insta-cast all #casted spells
commandDoAnimOthers = 100, //can #doanim on others
commandLockZones = 101, //can lock or unlock zones
commandEditPlayerCorpses = 150, //can Edit Player Corpses
commandInterrogateInv = 100, //below this == only log on error state and self-only target dump
commandInvSnapshot = 150 //ability to clear/restore snapshots
};
@@ -295,7 +281,7 @@ Developer configuration
#define COMMON_PROFILE
#define PROFILE_DUMP_TIME 3*60
#define PROFILE_DUMP_TIME 180
#endif //EQPROFILE
+24
View File
@@ -37,6 +37,7 @@
#include <fmt/format.h>
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
@@ -80,3 +81,26 @@ std::string File::GetCwd()
{
return fs::current_path().string();
}
FileContentsResult File::GetContents(const std::string &file_name)
{
std::string error;
std::ifstream f;
f.open(file_name);
std::string line;
std::string lines;
if (f.is_open()) {
while (f) {
std::getline(f, line);
lines += line + "\n";
}
}
else {
error = fmt::format("Couldn't open file [{}]", file_name);
}
return FileContentsResult{
.contents = lines,
.error = error,
};
}
+6
View File
@@ -25,10 +25,16 @@
namespace fs = std::filesystem;
struct FileContentsResult {
std::string contents;
std::string error;
};
class File {
public:
static bool Exists(const std::string &name);
static void Makedir(const std::string& directory_name);
static FileContentsResult GetContents(const std::string &file_name);
static std::string FindEqemuConfigPath();
static std::string GetCwd();
};
+22 -38
View File
@@ -61,9 +61,11 @@ bool BaseGuildManager::LoadGuilds() {
}
for (auto row=results.begin();row!=results.end();++row)
_CreateGuild(atoi(row[0]), row[1], atoi(row[2]), atoi(row[3]), row[4], row[5], row[6], row[7]);
_CreateGuild(Strings::ToUnsignedInt(row[0]), row[1], Strings::ToUnsignedInt(row[2]), Strings::ToUnsignedInt(row[3]), row[4], row[5], row[6], row[7]);
query = "SELECT guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
LogInfo("Loaded [{}] Guilds", Strings::Commify(std::to_string(results.RowCount())));
query = "SELECT guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
results = m_db->QueryDatabase(query);
if (!results.Success())
@@ -73,8 +75,8 @@ bool BaseGuildManager::LoadGuilds() {
for (auto row=results.begin();row!=results.end();++row)
{
uint32 guild_id = atoi(row[0]);
uint8 rankn = atoi(row[1]);
uint32 guild_id = Strings::ToUnsignedInt(row[0]);
uint8 rankn = Strings::ToUnsignedInt(row[1]);
if(rankn > GUILD_MAX_RANK) {
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
@@ -129,7 +131,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
auto row = results.begin();
info = _CreateGuild(guild_id, row[0], atoi(row[1]), atoi(row[2]), row[3], row[4], row[5], row[6]);
info = _CreateGuild(guild_id, row[0], Strings::ToUnsignedInt(row[1]), Strings::ToUnsignedInt(row[2]), row[3], row[4], row[5], row[6]);
query = StringFormat("SELECT guild_id, `rank`, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace "
"FROM guild_ranks WHERE guild_id=%lu", (unsigned long)guild_id);
@@ -142,7 +144,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
for (auto row=results.begin();row!=results.end();++row)
{
uint8 rankn = atoi(row[1]);
uint8 rankn = Strings::ToUnsignedInt(row[1]);
if(rankn > GUILD_MAX_RANK) {
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
@@ -785,9 +787,7 @@ bool BaseGuildManager::GetBankerFlag(uint32 CharID)
auto row = results.begin();
bool IsBanker = atoi(row[0]);
return IsBanker;
return Strings::ToBool(row[0]);
}
bool BaseGuildManager::DBSetAltFlag(uint32 charid, bool is_alt)
@@ -815,9 +815,7 @@ bool BaseGuildManager::GetAltFlag(uint32 CharID)
auto row = results.begin();
bool IsAlt = atoi(row[0]);
return IsAlt;
return Strings::ToBool(row[0]);
}
bool BaseGuildManager::DBSetTributeFlag(uint32 charid, bool enabled) {
@@ -864,35 +862,26 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg) {
return(true);
}
//factored out so I dont have to copy this crap.
#ifdef BOTS
#define GuildMemberBaseQuery \
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
" g.`banker`, g.`public_note`, g.`alt`" \
" FROM `vw_bot_character_mobs` AS c LEFT JOIN `vw_guild_members` AS g ON c.`id` = g.`char_id` AND c.`mob_type` = g.`mob_type` "
#else
#define GuildMemberBaseQuery \
"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \
" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \
" g.`banker`, g.`public_note`, g.`alt` " \
" FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` "
#endif
static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into) {
//fields from `characer_`
into.char_id = atoi(row[0]);
into.char_id = Strings::ToUnsignedInt(row[0]);
into.char_name = row[1];
into.class_ = atoi(row[2]);
into.level = atoi(row[3]);
into.time_last_on = atoul(row[4]);
into.zone_id = atoi(row[5]);
into.class_ = Strings::ToUnsignedInt(row[2]);
into.level = Strings::ToUnsignedInt(row[3]);
into.time_last_on = Strings::ToUnsignedInt(row[4]);
into.zone_id = Strings::ToUnsignedInt(row[5]);
//fields from `guild_members`, leave at defaults if missing
into.guild_id = row[6] ? atoi(row[6]) : GUILD_NONE;
into.rank = row[7] ? atoi(row[7]) : (GUILD_MAX_RANK+1);
into.guild_id = row[6] ? Strings::ToUnsignedInt(row[6]) : GUILD_NONE;
into.rank = row[7] ? Strings::ToUnsignedInt(row[7]) : (GUILD_MAX_RANK+1);
into.tribute_enable = row[8] ? (row[8][0] == '0'?false:true) : false;
into.total_tribute = row[9] ? atoi(row[9]) : 0;
into.last_tribute = row[10]? atoul(row[10]) : 0; //timestamp
into.total_tribute = row[9] ? Strings::ToUnsignedInt(row[9]) : 0;
into.last_tribute = row[10]? Strings::ToUnsignedInt(row[10]) : 0; //timestamp
into.banker = row[11]? (row[11][0] == '0'?false:true) : false;
into.public_note = row[12]? row[12] : "";
into.alt = row[13]? (row[13][0] == '0'?false:true) : false;
@@ -967,13 +956,8 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
}
//load up the rank info for each guild.
std::string query;
#ifdef BOTS
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C' AND c.deleted_at IS NULL", char_id);
#else
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id);
#endif
auto results = m_db->QueryDatabase(query);
std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id);
auto results = m_db->QueryDatabase(query);
if (!results.Success()) {
return false;
}
@@ -1270,7 +1254,7 @@ uint32 BaseGuildManager::GetGuildIDByCharacterID(uint32 character_id)
}
auto row = results.begin();
auto guild_id = std::stoul(row[0]);
auto guild_id = Strings::ToUnsignedInt(row[0]);
return guild_id;
}
+8 -6
View File
@@ -272,6 +272,8 @@ inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) {
#include <brotli/encode.h>
#endif
#include "../strings.h"
/*
* Declaration
*/
@@ -3812,12 +3814,12 @@ inline bool brotli_decompressor::decompress(const char *data,
if (std::regex_match(b, e, cm, re_another_range)) {
ssize_t first = -1;
if (!cm.str(1).empty()) {
first = static_cast<ssize_t>(std::stoll(cm.str(1)));
first = static_cast<ssize_t>(Strings::ToBigInt(cm.str(1)));
}
ssize_t last = -1;
if (!cm.str(2).empty()) {
last = static_cast<ssize_t>(std::stoll(cm.str(2)));
last = static_cast<ssize_t>(Strings::ToBigInt(cm.str(2)));
}
if (first != -1 && last != -1 && first > last) {
@@ -6688,7 +6690,7 @@ static WSInit wsinit_;
if (params.empty()) { return Get(path, headers); }
std::string path_with_query = append_query_params(path, params);
return Get(path_with_query.c_str(), headers, progress);
return Get(path_with_query, headers, progress);
}
inline Result ClientImpl::Get(const std::string &path, const Params &params,
@@ -6708,7 +6710,7 @@ static WSInit wsinit_;
}
std::string path_with_query = append_query_params(path, params);
return Get(path_with_query.c_str(), headers, response_handler,
return Get(path_with_query, headers, response_handler,
content_receiver, progress);
}
@@ -6805,7 +6807,7 @@ static WSInit wsinit_;
std::string content_type;
const auto &body = detail::serialize_multipart_formdata(
items, detail::make_multipart_data_boundary(), content_type);
return Post(path, headers, body, content_type.c_str());
return Post(path, headers, body, content_type);
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
@@ -6818,7 +6820,7 @@ static WSInit wsinit_;
std::string content_type;
const auto &body =
detail::serialize_multipart_formdata(items, boundary, content_type);
return Post(path, headers, body, content_type.c_str());
return Post(path, headers, body, content_type);
}
inline Result ClientImpl::Put(const std::string &path) {
+23 -8
View File
@@ -353,7 +353,7 @@ bool EQ::InventoryProfile::SwapItem(
fail_state = swapRaceClass;
return false;
}
if (deity_id && source_item->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & source_item->Deity)) {
if (deity_id && source_item->Deity && !(deity::GetDeityBitmask((deity::DeityType)deity_id) & source_item->Deity)) {
fail_state = swapDeity;
return false;
}
@@ -379,7 +379,7 @@ bool EQ::InventoryProfile::SwapItem(
fail_state = swapRaceClass;
return false;
}
if (deity_id && destination_item->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & destination_item->Deity)) {
if (deity_id && destination_item->Deity && !(deity::GetDeityBitmask((deity::DeityType)deity_id) & destination_item->Deity)) {
fail_state = swapDeity;
return false;
}
@@ -412,11 +412,12 @@ bool EQ::InventoryProfile::DeleteItem(int16 slot_id, int16 quantity) {
// If there are no charges left on the item,
if (item_to_delete->GetCharges() <= 0) {
// If the item is stackable (e.g arrows), or
// the item is not stackable, and is not a charged item, or is expendable, delete it
if (item_to_delete->IsStackable() ||
(!item_to_delete->IsStackable() &&
((item_to_delete->GetItem()->MaxCharges == 0) || item_to_delete->IsExpendable()))
) {
// the item is not a charged item, or is expendable, delete it
if (
item_to_delete->IsStackable() ||
item_to_delete->GetItem()->MaxCharges == 0 ||
item_to_delete->IsExpendable()
) {
// Item can now be destroyed
InventoryProfile::MarkDirty(item_to_delete);
return true;
@@ -1443,7 +1444,7 @@ int16 EQ::InventoryProfile::_PutItem(int16 slot_id, ItemInstance* inst)
}
if (result == INVALID_INDEX) {
LogError("InventoryProfile::_PutItem: Invalid slot_id specified ({}) with parent slot id ({})", slot_id, parentSlot);
LogError("Invalid slot_id specified ({}) with parent slot id ({})", slot_id, parentSlot);
InventoryProfile::MarkDirty(inst); // Slot not found, clean up
}
@@ -1718,3 +1719,17 @@ int16 EQ::InventoryProfile::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 lo
return EQ::invslot::SLOT_INVALID;
}
std::vector<uint32> EQ::InventoryProfile::GetAugmentIDsBySlotID(int16 slot_id)
{
std::vector<uint32> augments;
const auto* item = GetItem(slot_id);
if (item) {
for (uint8 i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++) {
augments.push_back(item->GetAugment(i) ? item->GetAugmentItemID(i) : 0);
}
}
return augments;
}
+13 -7
View File
@@ -26,8 +26,11 @@
#include "item_instance.h"
#include "classes.h"
#include "races.h"
#include <list>
#include <vector>
//FatherNitwit: location bits for searching specific
@@ -129,7 +132,7 @@ namespace EQ
// Swap items in inventory
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel };
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = 0, uint8 class_id = 0, uint16 deity_id = 0, uint8 level = 0);
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = RACE_DOUG_0, uint8 class_id = NO_CLASS, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0);
// Remove item from inventory
bool DeleteItem(int16 slot_id, int16 quantity = 0);
@@ -152,6 +155,9 @@ namespace EQ
// Check how many of a specific augment the player has equipped by Item ID
int CountAugmentEquippedByID(uint32 item_id);
// Get a list of augments from a specific slot ID
std::vector<uint32> GetAugmentIDsBySlotID(int16 slot_id);
// Check whether there is space for the specified number of the specified item.
bool HasSpaceForItem(const ItemData *ItemToTry, int16 Quantity);
@@ -197,12 +203,12 @@ namespace EQ
void dumpBankItems();
void dumpSharedBankItems();
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, std::string value);
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, int value);
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, float value);
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, bool value);
std::string GetCustomItemData(int16 slot_id, std::string identifier);
static int GetItemStatValue(uint32 item_id, const char* identifier);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, const std::string& value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, int value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, float value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, bool value);
std::string GetCustomItemData(int16 slot_id, const std::string& identifier);
static const int GetItemStatValue(uint32 item_id, const std::string& identifier);
protected:
///////////////////////////////
// Protected Methods
+1 -1
View File
@@ -198,7 +198,7 @@ std::string IpUtil::DNSLookupSync(const std::string &addr, int port)
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 1500) {
LogInfo(
"[DNSLookupSync] Deadline exceeded [{}]",
"Deadline exceeded [{}]",
1500
);
running = false;
+24 -2
View File
@@ -169,11 +169,33 @@ uint8 EQ::item::ConvertAugTypeBitToAugType(uint32 aug_type_bit)
bool EQ::ItemData::IsEquipable(uint16 race_id, uint16 class_id) const
{
if (!(Races & GetPlayerRaceBit(race_id)))
if (!(Races & GetPlayerRaceBit(race_id))) {
return false;
}
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id))))
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id)))) {
return false;
}
return true;
}
bool EQ::ItemData::IsClassEquipable(uint16 class_id) const
{
if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id)))) {
return false;
}
return true;
}
bool EQ::ItemData::IsRaceEquipable(uint16 race_id) const
{
if (!(Races & GetPlayerRaceBit(race_id))) {
return false;
}
return true;
}
+167 -160
View File
@@ -131,7 +131,7 @@ namespace EQ
Mounts?
Ornamentations?
GuildBanners?
Collectible?
Collectible?
Placeable?
(others?)
*/
@@ -355,184 +355,191 @@ namespace EQ
struct ItemData {
// Non packet based fields
uint8 MinStatus;
uint8 MinStatus {};
// Packet based fields
uint8 ItemClass; // Item Type: 0=common, 1=container, 2=book
char Name[64]; // Name
char Lore[80]; // Lore Name: *=lore, &=summoned, #=artifact, ~=pending lore
char IDFile[30]; // Visible model
uint32 ID; // Unique ID (also PK for DB)
int32 Weight; // Item weight * 10
uint8 NoRent; // No Rent: 0=norent, 255=not norent
uint8 NoDrop; // No Drop: 0=nodrop, 255=not nodrop
uint8 Size; // Size: 0=tiny, 1=small, 2=medium, 3=large, 4=giant
uint32 Slots; // Bitfield for which slots this item can be used in
uint32 Price; // Item cost (?)
uint32 Icon; // Icon Number
int32 LoreGroup; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295)
bool LoreFlag; // This will be true if LoreGroup is non-zero
bool PendingLoreFlag;
bool ArtifactFlag;
bool SummonedFlag;
uint8 FVNoDrop; // Firiona Vie nodrop flag
uint32 Favor; // Individual favor
uint32 GuildFavor; // Guild favor
uint32 PointType;
uint8 ItemClass {}; // Item Type: 0=common, 1=container, 2=book
char Name[64] {}; // Name
char Lore[80] {}; // Lore Name: *=lore, &=summoned, #=artifact, ~=pending lore
char IDFile[30] {}; // Visible model
uint32 ID {}; // Unique ID (also PK for DB)
int32 Weight {}; // Item weight * 10
uint8 NoRent{} ; // No Rent: 0=norent, 255=not norent
uint8 NoDrop {}; // No Drop: 0=nodrop, 255=not nodrop
uint8 Size {}; // Size: 0=tiny, 1=small, 2=medium, 3=large, 4=giant
uint32 Slots {}; // Bitfield for which slots this item can be used in
uint32 Price {}; // Item cost (?)
uint32 Icon {}; // Icon Number
int32 LoreGroup {}; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295)
bool LoreFlag {}; // This will be true if LoreGroup is non-zero
bool PendingLoreFlag {};
bool ArtifactFlag {};
bool SummonedFlag {};
uint8 FVNoDrop {}; // Firiona Vie nodrop flag
uint32 Favor {}; // Individual favor
uint32 GuildFavor {}; // Guild favor
uint32 PointType {};
//uint32 Unk117;
//uint32 Unk118;
//uint32 Unk121;
//uint32 Unk124;
uint8 BagType; // 0:Small Bag, 1:Large Bag, 2:Quiver, 3:Belt Pouch ... there are 50 types
uint8 BagSlots; // Number of slots: can only be 2, 4, 6, 8, or 10
uint8 BagSize; // 0:TINY, 1:SMALL, 2:MEDIUM, 3:LARGE, 4:GIANT
uint8 BagWR; // 0->100
uint8 BagType {}; // 0:Small Bag, 1:Large Bag, 2:Quiver, 3:Belt Pouch ... there are 50 types
uint8 BagSlots {}; // Number of slots: can only be 2, 4, 6, 8, or 10
uint8 BagSize {}; // 0:TINY, 1:SMALL, 2:MEDIUM, 3:LARGE, 4:GIANT
uint8 BagWR {}; // 0->100
bool BenefitFlag;
bool Tradeskills; // Is this a tradeskill item?
int8 CR; // Save vs Cold
int8 DR; // Save vs Disease
int8 PR; // Save vs Poison
int8 MR; // Save vs Magic
int8 FR; // Save vs Fire
int8 AStr; // Strength
int8 ASta; // Stamina
int8 AAgi; // Agility
int8 ADex; // Dexterity
int8 ACha; // Charisma
int8 AInt; // Intelligence
int8 AWis; // Wisdom
int32 HP; // HP
int32 Mana; // Mana
int32 AC; // AC
uint32 Deity; // Bitmask of Deities that can equip this item
bool BenefitFlag {};
bool Tradeskills {}; // Is this a tradeskill item?
int8 CR {}; // Save vs Cold
int8 DR {}; // Save vs Disease
int8 PR {}; // Save vs Poison
int8 MR {}; // Save vs Magic
int8 FR {}; // Save vs Fire
int8 AStr {}; // Strength
int8 ASta {}; // Stamina
int8 AAgi {}; // Agility
int8 ADex {}; // Dexterity
int8 ACha {}; // Charisma
int8 AInt {}; // Intelligence
int8 AWis {}; // Wisdom
int32 HP {}; // HP
int32 Mana {}; // Mana
int32 AC {}; // AC
uint32 Deity {}; // Bitmask of Deities that can equip this item
//uint32 Unk033
int32 SkillModValue; // % Mod to skill specified in SkillModType
int32 SkillModMax; // Max skill point modification
uint32 SkillModType; // Type of skill for SkillModValue to apply to
uint32 BaneDmgRace; // Bane Damage Race
int32 BaneDmgAmt; // Bane Damage Body Amount
uint32 BaneDmgBody; // Bane Damage Body
bool Magic; // True=Magic Item, False=not
int32 CastTime_;
uint8 ReqLevel; // Required Level to use item
uint32 BardType; // Bard Skill Type
int32 BardValue; // Bard Skill Amount
int8 Light; // Light
uint8 Delay; // Delay * 10
uint8 RecLevel; // Recommended level to use item
uint8 RecSkill; // Recommended skill to use item (refers to primary skill of item)
uint8 ElemDmgType; // Elemental Damage Type (1=magic, 2=fire)
uint8 ElemDmgAmt; // Elemental Damage
uint8 Range; // Range of item
uint32 Damage; // Delay between item usage (in 0.1 sec increments)
uint32 Color; // RR GG BB 00 <-- as it appears in pc
uint32 Classes; // Bitfield of classes that can equip item (1 << class#)
uint32 Races; // Bitfield of races that can equip item (1 << race#)
//uint32 Unk054;
int16 MaxCharges; // Maximum charges items can hold: -1 if not a chargeable item
uint8 ItemType; // Item Type/Skill (itemClass* from above)
int32 SubType; // Some items have sub types that can be used for other things (unbreakable fishing poles, SE_FFItemClass)
uint8 Material; // Item material type
uint32 HerosForgeModel;// Hero's Forge Armor Model Type (2-13?)
float SellRate; // Sell rate
//uint32 Unk059;
int32 SkillModValue {}; // % Mod to skill specified in SkillModType
int32 SkillModMax {}; // Max skill point modification
uint32 SkillModType {}; // Type of skill for SkillModValue to apply to
uint32 BaneDmgRace {}; // Bane Damage Race
int32 BaneDmgAmt {}; // Bane Damage Body Amount
uint32 BaneDmgBody {}; // Bane Damage Body
bool Magic {}; // True=Magic Item, False=not
int32 CastTime_ {};
uint8 ReqLevel {}; // Required Level to use item
uint32 BardType {}; // Bard Skill Type
int32 BardValue {}; // Bard Skill Amount
int8 Light {}; // Light
uint8 Delay {}; // Delay * 10
uint8 RecLevel {}; // Recommended level to use item
uint8 RecSkill {}; // Recommended skill to use item (refers to primary skill of item)
uint8 ElemDmgType {}; // Elemental Damage Type (1=magic, 2=fire)
uint8 ElemDmgAmt {}; // Elemental Damage
uint8 Range {}; // Range of item
uint32 Damage {}; // Delay between item usage (in 0.1 sec increments)
uint32 Color {}; // RR GG BB 00 <-- as it appears in pc
uint32 Classes {}; // Bitfield of classes that can equip item (1 << class#)
uint32 Races {}; // Bitfield of races that can equip item (1 << race#)
//uint32 Unk054 {};
int16 MaxCharges {}; // Maximum charges items can hold: -1 if not a chargeable item
uint8 ItemType {}; // Item Type/Skill (itemClass* from above)
int32 SubType {}; // Some items have sub types that can be used for other things (unbreakable fishing poles, SE_FFItemClass)
uint8 Material {}; // Item material type
uint32 HerosForgeModel {};// Hero's Forge Armor Model Type (2-13?)
float SellRate {}; // Sell rate
//uint32 Unk059 {};
union {
uint32 Fulfilment; // Food fulfilment (How long it lasts)
uint32 CastTime; // Cast Time for clicky effects, in milliseconds
};
uint32 EliteMaterial;
int32 ProcRate;
int8 CombatEffects; // PoP: Combat Effects +
int8 Shielding; // PoP: Shielding %
int8 StunResist; // PoP: Stun Resist %
int8 StrikeThrough; // PoP: Strike Through %
uint32 ExtraDmgSkill;
uint32 ExtraDmgAmt;
int8 SpellShield; // PoP: Spell Shield %
int8 Avoidance; // PoP: Avoidance +
int8 Accuracy; // PoP: Accuracy +
uint32 CharmFileID;
int32 FactionMod1; // Faction Mod 1
int32 FactionMod2; // Faction Mod 2
int32 FactionMod3; // Faction Mod 3
int32 FactionMod4; // Faction Mod 4
int32 FactionAmt1; // Faction Amt 1
int32 FactionAmt2; // Faction Amt 2
int32 FactionAmt3; // Faction Amt 3
int32 FactionAmt4; // Faction Amt 4
char CharmFile[32]; // ?
uint32 AugType;
uint8 AugSlotType[invaug::SOCKET_COUNT]; // RoF: Augment Slot 1-6 Type
uint8 AugSlotVisible[invaug::SOCKET_COUNT]; // RoF: Augment Slot 1-6 Visible
uint8 AugSlotUnk2[invaug::SOCKET_COUNT]; // RoF: Augment Slot 1-6 Unknown Most likely Powersource related
uint32 LDoNTheme;
uint32 LDoNPrice;
uint32 LDoNSold;
uint32 BaneDmgRaceAmt;
uint32 AugRestrict;
int32 Endur;
int32 DotShielding;
int32 Attack;
int32 Regen;
int32 ManaRegen;
int32 EnduranceRegen;
int32 Haste;
int32 DamageShield;
uint32 RecastDelay;
int RecastType;
uint32 AugDistiller;
bool Attuneable;
bool NoPet;
bool PotionBelt;
bool Stackable;
bool NoTransfer;
bool QuestItemFlag;
int16 StackSize;
uint8 PotionBeltSlots;
item::ItemEffect_Struct Click, Proc, Worn, Focus, Scroll, Bard;
uint32 EliteMaterial {};
int32 ProcRate {};
int8 CombatEffects {}; // PoP: Combat Effects +
int8 Shielding {}; // PoP: Shielding %
int8 StunResist {}; // PoP: Stun Resist %
int8 StrikeThrough {}; // PoP: Strike Through %
int32 ExtraDmgSkill {};
int32 ExtraDmgAmt {};
int8 SpellShield {}; // PoP: Spell Shield %
int8 Avoidance {}; // PoP: Avoidance +
int8 Accuracy {}; // PoP: Accuracy +
uint32 CharmFileID {};
int32 FactionMod1 {}; // Faction Mod 1
int32 FactionMod2 {}; // Faction Mod 2
int32 FactionMod3 {}; // Faction Mod 3
int32 FactionMod4 {}; // Faction Mod 4
int32 FactionAmt1 {}; // Faction Amt 1
int32 FactionAmt2 {}; // Faction Amt 2
int32 FactionAmt3 {}; // Faction Amt 3
int32 FactionAmt4 {}; // Faction Amt 4
char CharmFile[32] {}; // ?
uint32 AugType {};
uint8 AugSlotType[invaug::SOCKET_COUNT] {}; // RoF: Augment Slot 1-6 Type
uint8 AugSlotVisible[invaug::SOCKET_COUNT] {}; // RoF: Augment Slot 1-6 Visible
uint8 AugSlotUnk2[invaug::SOCKET_COUNT] {}; // RoF: Augment Slot 1-6 Unknown Most likely Powersource related
uint32 LDoNTheme {};
uint32 LDoNPrice {};
uint32 LDoNSold {};
uint32 BaneDmgRaceAmt {};
uint32 AugRestrict {};
int32 Endur {};
int32 DotShielding {};
int32 Attack {};
int32 Regen {};
int32 ManaRegen {};
int32 EnduranceRegen {};
int32 Haste {};
int32 DamageShield {};
uint32 RecastDelay {};
int RecastType {};
uint32 AugDistiller {};
bool Attuneable {};
bool NoPet {};
bool PotionBelt {};
bool Stackable {};
bool NoTransfer {};
bool QuestItemFlag {};
int16 StackSize {};
uint8 PotionBeltSlots {};
item::ItemEffect_Struct Click {};
item::ItemEffect_Struct Proc {};
item::ItemEffect_Struct Worn {};
item::ItemEffect_Struct Focus {};
item::ItemEffect_Struct Scroll {};
item::ItemEffect_Struct Bard {};
uint8 Book; // 0=Not book, 1=Book
uint32 BookType;
char Filename[33]; // Filename for book data
uint8 Book {}; // 0=Not book, 1=Book
uint32 BookType {};
char Filename[33] {}; // Filename for book data
// Begin SoF Fields
int32 SVCorruption;
uint32 Purity;
uint8 EvolvingItem;
uint32 EvolvingID;
uint8 EvolvingLevel;
uint8 EvolvingMax;
uint32 BackstabDmg;
uint32 DSMitigation;
int32 HeroicStr;
int32 HeroicInt;
int32 HeroicWis;
int32 HeroicAgi;
int32 HeroicDex;
int32 HeroicSta;
int32 HeroicCha;
int32 HeroicMR;
int32 HeroicFR;
int32 HeroicCR;
int32 HeroicDR;
int32 HeroicPR;
int32 HeroicSVCorrup;
int32 HealAmt;
int32 SpellDmg;
uint32 LDoNSellBackRate;
uint32 ScriptFileID;
uint16 ExpendableArrow;
uint32 Clairvoyance;
char ClickName[65];
char ProcName[65];
char WornName[65];
char FocusName[65];
char ScrollName[65];
int32 SVCorruption {};
uint32 Purity {};
uint8 EvolvingItem {};
uint32 EvolvingID {};
uint8 EvolvingLevel {};
uint8 EvolvingMax {};
uint32 BackstabDmg {};
uint32 DSMitigation {};
int32 HeroicStr {};
int32 HeroicInt {};
int32 HeroicWis {};
int32 HeroicAgi {};
int32 HeroicDex {};
int32 HeroicSta {};
int32 HeroicCha {};
int32 HeroicMR {};
int32 HeroicFR {};
int32 HeroicCR {};
int32 HeroicDR {};
int32 HeroicPR {};
int32 HeroicSVCorrup {};
int32 HealAmt {};
int32 SpellDmg {};
uint32 LDoNSellBackRate {};
uint32 ScriptFileID {};
uint16 ExpendableArrow {};
uint32 Clairvoyance {};
char ClickName[65] {};
char ProcName[65] {};
char WornName[65] {};
char FocusName[65] {};
char ScrollName[65] {};
//BardName
bool IsEquipable(uint16 Race, uint16 Class) const;
bool IsClassEquipable(uint16 Class) const;
bool IsRaceEquipable(uint16 Race) const;
bool IsClassCommon() const;
bool IsClassBag() const;
bool IsClassBook() const;
+267 -197
View File
@@ -17,6 +17,7 @@
*/
#include "inventory_profile.h"
#include "../common/data_verification.h"
//#include "classes.h"
//#include "global_define.h"
//#include "item_instance.h"
@@ -57,108 +58,62 @@ static inline int32 GetNextItemInstSerialNumber() {
// class EQ::ItemInstance
//
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
m_use_type = ItemInstNormal;
if(item) {
m_item = new ItemData(*item);
} else {
m_item = nullptr;
}
m_charges = charges;
m_price = 0;
m_attuned = false;
m_merchantslot = 0;
if (m_item && m_item->IsClassCommon())
m_color = m_item->Color;
else
m_color = 0;
m_merchantcount = 1;
m_SerialNumber = GetNextItemInstSerialNumber();
m_exp = 0;
m_evolveLvl = 0;
m_activated = false;
m_scaledItem = nullptr;
m_evolveInfo = nullptr;
m_scaling = false;
m_ornamenticon = 0;
m_ornamentidfile = 0;
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
m_new_id_file = 0;
if (item) {
m_item = new ItemData(*item);
}
m_charges = charges;
if (m_item && m_item->IsClassCommon()) {
m_color = m_item->Color;
}
m_SerialNumber = GetNextItemInstSerialNumber();
}
EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) {
m_use_type = ItemInstNormal;
m_item = db->GetItem(item_id);
if(m_item) {
m_item = db->GetItem(item_id);
if (m_item) {
m_item = new ItemData(*m_item);
}
else {
m_item = nullptr;
}
m_charges = charges;
m_price = 0;
m_merchantslot = 0;
m_attuned=false;
if (m_item && m_item->IsClassCommon())
m_color = m_item->Color;
else
m_color = 0;
m_merchantcount = 1;
m_SerialNumber = GetNextItemInstSerialNumber();
m_exp = 0;
m_evolveLvl = 0;
m_activated = false;
m_scaledItem = nullptr;
m_evolveInfo = nullptr;
m_scaling = false;
m_ornamenticon = 0;
m_ornamentidfile = 0;
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
m_new_id_file = 0;
if (m_item && m_item->IsClassCommon()) {
m_color = m_item->Color;
} else {
m_color = 0;
}
m_SerialNumber = GetNextItemInstSerialNumber();
}
EQ::ItemInstance::ItemInstance(ItemInstTypes use_type) {
m_use_type = use_type;
m_item = nullptr;
m_charges = 0;
m_price = 0;
m_attuned = false;
m_merchantslot = 0;
m_color = 0;
m_exp = 0;
m_evolveLvl = 0;
m_activated = false;
m_scaledItem = nullptr;
m_evolveInfo = nullptr;
m_scaling = false;
m_ornamenticon = 0;
m_ornamentidfile = 0;
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
m_new_id_file = 0;
m_use_type = use_type;
}
// Make a copy of an EQ::ItemInstance object
EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
{
m_use_type=copy.m_use_type;
if(copy.m_item)
m_item = new ItemData(*copy.m_item);
else
m_item = nullptr;
m_use_type = copy.m_use_type;
if (copy.m_item) {
m_item = new ItemData(*copy.m_item);
} else {
m_item = nullptr;
}
m_charges = copy.m_charges;
m_price = copy.m_price;
m_color = copy.m_color;
m_merchantslot = copy.m_merchantslot;
m_currentslot = copy.m_currentslot;
m_attuned = copy.m_attuned;
m_merchantcount = copy.m_merchantcount;
m_charges=copy.m_charges;
m_price=copy.m_price;
m_color=copy.m_color;
m_merchantslot=copy.m_merchantslot;
m_currentslot=copy.m_currentslot;
m_attuned=copy.m_attuned;
m_merchantcount=copy.m_merchantcount;
// Copy container contents
for (auto it = copy.m_contents.begin(); it != copy.m_contents.end(); ++it) {
ItemInstance* inst_old = it->second;
@@ -168,37 +123,42 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
inst_new = inst_old->Clone();
}
if (inst_new != nullptr) {
if (inst_new) {
m_contents[it->first] = inst_new;
}
}
std::map<std::string, std::string>::const_iterator iter;
for (iter = copy.m_custom_data.begin(); iter != copy.m_custom_data.end(); ++iter) {
m_custom_data[iter->first] = iter->second;
}
m_SerialNumber = copy.m_SerialNumber;
m_custom_data = copy.m_custom_data;
m_timers = copy.m_timers;
m_exp = copy.m_exp;
m_SerialNumber = copy.m_SerialNumber;
m_custom_data = copy.m_custom_data;
m_timers = copy.m_timers;
m_exp = copy.m_exp;
m_evolveLvl = copy.m_evolveLvl;
m_activated = copy.m_activated;
if (copy.m_scaledItem)
if (copy.m_scaledItem) {
m_scaledItem = new ItemData(*copy.m_scaledItem);
else
} else {
m_scaledItem = nullptr;
}
if(copy.m_evolveInfo)
if (copy.m_evolveInfo) {
m_evolveInfo = new EvolveInfo(*copy.m_evolveInfo);
else
} else {
m_evolveInfo = nullptr;
}
m_scaling = copy.m_scaling;
m_ornamenticon = copy.m_ornamenticon;
m_ornamentidfile = copy.m_ornamentidfile;
m_scaling = copy.m_scaling;
m_ornamenticon = copy.m_ornamenticon;
m_ornamentidfile = copy.m_ornamentidfile;
m_ornament_hero_model = copy.m_ornament_hero_model;
m_recast_timestamp = copy.m_recast_timestamp;
m_new_id_file = copy.m_new_id_file;
m_recast_timestamp = copy.m_recast_timestamp;
m_new_id_file = copy.m_new_id_file;
}
// Clean up container contents
@@ -216,11 +176,13 @@ bool EQ::ItemInstance::IsType(item::ItemClass item_class) const
// IsType(<ItemClassTypes>) does not protect against 'm_item = nullptr'
// Check usage type
if ((m_use_type == ItemInstWorldContainer) && (item_class == item::ItemClassBag))
if (m_use_type == ItemInstWorldContainer && item_class == item::ItemClassBag) {
return true;
}
if (!m_item)
if (!m_item) {
return false;
}
return (m_item->ItemClass == item_class);
}
@@ -243,96 +205,145 @@ bool EQ::ItemInstance::IsClassBook() const
// Is item stackable?
bool EQ::ItemInstance::IsStackable() const
{
if (!m_item)
return false;
return m_item->Stackable;
return (m_item && m_item->Stackable);
}
bool EQ::ItemInstance::IsCharged() const
{
if (!m_item)
if (!m_item) {
return false;
}
if (m_item->MaxCharges > 1)
if (m_item->MaxCharges > 1) {
return true;
else
} else {
return false;
}
}
// Can item be equipped?
bool EQ::ItemInstance::IsEquipable(uint16 race, uint16 class_) const
{
if (!m_item || (m_item->Slots == 0))
if (!m_item || !m_item->Slots) {
return false;
}
return m_item->IsEquipable(race, class_);
}
// Can item be equipped by Class?
bool EQ::ItemInstance::IsClassEquipable(uint16 class_) const
{
if (!m_item || !m_item->Slots) {
return false;
}
return m_item->IsClassEquipable(class_);
}
// Can item be equipped by Race?
bool EQ::ItemInstance::IsRaceEquipable(uint16 race) const
{
if (!m_item || !m_item->Slots) {
return false;
}
return m_item->IsRaceEquipable(race);
}
// Can equip at this slot?
bool EQ::ItemInstance::IsEquipable(int16 slot_id) const
{
if (!m_item)
if (!m_item || !m_item->Slots) {
return false;
}
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END)
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END) {
return false;
}
return ((m_item->Slots & (1 << slot_id)) != 0);
}
bool EQ::ItemInstance::IsAugmentable() const
{
if (!m_item)
if (!m_item) {
return false;
}
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
if (m_item->AugSlotType[index] != 0)
if (m_item->AugSlotType[index] != 0) {
return true;
}
}
return false;
}
bool EQ::ItemInstance::AvailableWearSlot(uint32 aug_wear_slots) const {
if (!m_item || !m_item->IsClassCommon())
if (!m_item || !m_item->IsClassCommon()) {
return false;
}
int index = invslot::EQUIPMENT_BEGIN;
for (; index <= invslot::EQUIPMENT_END; ++index) {
if (m_item->Slots & (1 << index)) {
if (aug_wear_slots & (1 << index))
if (aug_wear_slots & (1 << index)) {
break;
}
}
}
return (index <= EQ::invslot::EQUIPMENT_END);
}
int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augtype) const
int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const
{
if (!m_item || !m_item->IsClassCommon())
if (!m_item || !m_item->IsClassCommon()) {
return INVALID_INDEX;
int index = invaug::SOCKET_BEGIN;
for (; index <= invaug::SOCKET_END; ++index) {
if (GetItem(index)) { continue; }
if (augtype == -1 || (m_item->AugSlotType[index] && ((1 << (m_item->AugSlotType[index] - 1)) & augtype)))
break;
}
return (index <= invaug::SOCKET_END) ? index : INVALID_INDEX;
auto i = invaug::SOCKET_BEGIN;
for (; i <= invaug::SOCKET_END; ++i) {
if (GetItem(i)) {
continue;
}
if (
augment_type == -1 ||
(
m_item->AugSlotType[i] &&
((1 << (m_item->AugSlotType[i] - 1)) & augment_type)
)
) {
break;
}
}
return (i <= invaug::SOCKET_END) ? i : INVALID_INDEX;
}
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const
{
if (!m_item || !m_item->IsClassCommon())
return false;
if (!m_item || !m_item->IsClassCommon()) {
return false;
}
if ((!GetItem(slot) && m_item->AugSlotVisible[slot]) && augtype == -1 || (m_item->AugSlotType[slot] && ((1 << (m_item->AugSlotType[slot] - 1)) & augtype))) {
if (
(
!GetItem(slot) &&
m_item->AugSlotVisible[slot]
) &&
augment_type == -1 ||
(
m_item->AugSlotType[slot] &&
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
)
) {
return true;
}
return false;
return false;
}
// Retrieve item inside container
@@ -348,9 +359,10 @@ EQ::ItemInstance* EQ::ItemInstance::GetItem(uint8 index) const
uint32 EQ::ItemInstance::GetItemID(uint8 slot) const
{
ItemInstance *item = GetItem(slot);
if (item)
const auto item = GetItem(slot);
if (item) {
return item->GetID();
}
return 0;
}
@@ -474,14 +486,21 @@ uint8 EQ::ItemInstance::FirstOpenSlot() const
uint8 EQ::ItemInstance::GetTotalItemCount() const
{
if (!m_item)
if (!m_item) {
return 0;
}
uint8 item_count = 1;
if (m_item && !m_item->IsClassBag()) { return item_count; }
if (!m_item->IsClassBag()) {
return item_count;
}
for (int index = invbag::SLOT_BEGIN; index < m_item->BagSlots; ++index) { if (GetItem(index)) { ++item_count; } }
for (int index = invbag::SLOT_BEGIN; index < m_item->BagSlots; ++index) {
if (GetItem(index)) {
++item_count;
}
}
return item_count;
}
@@ -500,86 +519,108 @@ bool EQ::ItemInstance::IsNoneEmptyContainer()
}
// Retrieve augment inside item
EQ::ItemInstance* EQ::ItemInstance::GetAugment(uint8 slot) const
EQ::ItemInstance* EQ::ItemInstance::GetAugment(uint8 augment_index) const
{
if (m_item && m_item->IsClassCommon())
return GetItem(slot);
if (m_item && m_item->IsClassCommon()) {
return GetItem(augment_index);
}
return nullptr;
}
EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAug(int32 ornamentationAugtype) const
bool EQ::ItemInstance::IsOrnamentationAugment(EQ::ItemInstance* augment) const
{
if (!m_item || !m_item->IsClassCommon()) { return nullptr; }
if (ornamentationAugtype == 0) { return nullptr; }
if (!m_item || !m_item->IsClassCommon() || !augment) {
return false;
}
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++)
{
if (GetAugment(i) && m_item->AugSlotType[i] == ornamentationAugtype)
{
const char *item_IDFile = GetAugment(i)->GetItem()->IDFile;
if (
(strncmp(item_IDFile, "IT64", strlen(item_IDFile)) == 0
|| strncmp(item_IDFile, "IT63", strlen(item_IDFile)) == 0)
&& GetAugment(i)->GetItem()->HerosForgeModel == 0
)
{
continue;
}
return GetAugment(i);
const auto augment_item = augment->GetItem();
if (!augment_item) {
return false;
}
const std::string& idfile = augment_item->IDFile;
if (
EQ::ValueWithin(
augment->GetAugmentType(),
OrnamentationAugmentTypes::StandardOrnamentation,
OrnamentationAugmentTypes::SpecialOrnamentation
) ||
(
idfile != "IT63" &&
idfile != "IT64"
) ||
augment_item->HerosForgeModel
) {
return true;
}
return false;
}
EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAugment() const
{
if (!m_item || !m_item->IsClassCommon()) {
return nullptr;
}
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++) {
const auto augment = GetAugment(i);
if (augment && IsOrnamentationAugment(augment)) {
return augment;
}
}
return nullptr;
}
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const {
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const
{
// Not a Hero Forge item.
if (m_ornament_hero_model == 0 || material_slot < 0)
if (m_ornament_hero_model == 0 || material_slot < 0) {
return 0;
}
// Item is using an explicit Hero Forge ID
if (m_ornament_hero_model >= 1000)
if (m_ornament_hero_model >= 1000) {
return m_ornament_hero_model;
}
// Item is using a shorthand ID
return (m_ornament_hero_model * 100) + material_slot;
}
bool EQ::ItemInstance::UpdateOrnamentationInfo() {
if (!m_item || !m_item->IsClassCommon())
bool EQ::ItemInstance::UpdateOrnamentationInfo()
{
if (!m_item || !m_item->IsClassCommon()) {
return false;
}
bool ornamentSet = false;
const auto augment = GetOrnamentationAugment();
int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
if (GetOrnamentationAug(ornamentationAugtype))
{
const ItemData* ornamentItem;
ornamentItem = GetOrnamentationAug(ornamentationAugtype)->GetItem();
if (ornamentItem != nullptr)
{
SetOrnamentIcon(ornamentItem->Icon);
SetOrnamentHeroModel(ornamentItem->HerosForgeModel);
if (strlen(ornamentItem->IDFile) > 2)
{
SetOrnamentationIDFile(atoi(&ornamentItem->IDFile[2]));
}
else
{
if (augment) {
const auto augment_item = GetOrnamentationAugment()->GetItem();
if (augment_item) {
SetOrnamentIcon(augment_item->Icon);
SetOrnamentHeroModel(augment_item->HerosForgeModel);
if (strlen(augment_item->IDFile) > 2) {
SetOrnamentationIDFile(Strings::ToUnsignedInt(&augment_item->IDFile[2]));
} else {
SetOrnamentationIDFile(0);
}
ornamentSet = true;
return true;
}
}
else
{
SetOrnamentIcon(0);
SetOrnamentHeroModel(0);
SetOrnamentationIDFile(0);
}
return ornamentSet;
SetOrnamentIcon(0);
SetOrnamentHeroModel(0);
SetOrnamentationIDFile(0);
return false;
}
bool EQ::ItemInstance::CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll) {
@@ -629,12 +670,13 @@ bool EQ::ItemInstance::CanTransform(const ItemData *ItemToTry, const ItemData *C
return false;
}
uint32 EQ::ItemInstance::GetAugmentItemID(uint8 slot) const
uint32 EQ::ItemInstance::GetAugmentItemID(uint8 augment_index) const
{
if (!m_item || !m_item->IsClassCommon())
if (!m_item || !m_item->IsClassCommon()) {
return 0;
}
return GetItemID(slot);
return GetItemID(augment_index);
}
// Add an augment to the item
@@ -678,12 +720,14 @@ EQ::ItemInstance* EQ::ItemInstance::RemoveAugment(uint8 index)
bool EQ::ItemInstance::IsAugmented()
{
if (!m_item || !m_item->IsClassCommon())
if (!m_item || !m_item->IsClassCommon()) {
return false;
}
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
if (GetAugmentItemID(index))
for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; ++slot_id) {
if (GetAugmentItemID(slot_id)) {
return true;
}
}
return false;
@@ -792,7 +836,20 @@ std::string EQ::ItemInstance::GetCustomDataString() const {
return ret_val;
}
std::string EQ::ItemInstance::GetCustomData(std::string identifier) {
void EQ::ItemInstance::SetCustomDataString(const std::string& str)
{
auto components = Strings::Split(str, "^");
auto value_count = components.size() / 2;
for (auto i = 0; i < value_count; i++) {
auto identifier = components[i * 2];
auto value = components[(i * 2) + 1];
SetCustomData(identifier, value);
}
}
std::string EQ::ItemInstance::GetCustomData(const std::string& identifier) {
std::map<std::string, std::string>::const_iterator iter = m_custom_data.find(identifier);
if (iter != m_custom_data.end()) {
return iter->second;
@@ -801,33 +858,33 @@ std::string EQ::ItemInstance::GetCustomData(std::string identifier) {
return "";
}
void EQ::ItemInstance::SetCustomData(std::string identifier, std::string value) {
void EQ::ItemInstance::SetCustomData(const std::string& identifier, const std::string& value) {
DeleteCustomData(identifier);
m_custom_data[identifier] = value;
}
void EQ::ItemInstance::SetCustomData(std::string identifier, int value) {
void EQ::ItemInstance::SetCustomData(const std::string& identifier, int value) {
DeleteCustomData(identifier);
std::stringstream ss;
ss << value;
m_custom_data[identifier] = ss.str();
}
void EQ::ItemInstance::SetCustomData(std::string identifier, float value) {
void EQ::ItemInstance::SetCustomData(const std::string& identifier, float value) {
DeleteCustomData(identifier);
std::stringstream ss;
ss << value;
m_custom_data[identifier] = ss.str();
}
void EQ::ItemInstance::SetCustomData(std::string identifier, bool value) {
void EQ::ItemInstance::SetCustomData(const std::string& identifier, bool value) {
DeleteCustomData(identifier);
std::stringstream ss;
ss << value;
m_custom_data[identifier] = ss.str();
}
void EQ::ItemInstance::DeleteCustomData(std::string identifier) {
void EQ::ItemInstance::DeleteCustomData(const std::string& identifier) {
auto iter = m_custom_data.find(identifier);
if (iter != m_custom_data.end()) {
m_custom_data.erase(iter);
@@ -879,8 +936,9 @@ bool EQ::ItemInstance::IsDroppable(bool recurse) const
void EQ::ItemInstance::Initialize(SharedDatabase *db) {
// if there's no actual item, don't do anything
if (!m_item)
if (!m_item) {
return;
}
// initialize scaling items
if (m_item->CharmFileID != 0) {
@@ -889,7 +947,7 @@ void EQ::ItemInstance::Initialize(SharedDatabase *db) {
}
// initialize evolving items
else if ((db) && m_item->LoreGroup >= 1000 && m_item->LoreGroup != -1) {
else if (db && m_item->LoreGroup >= 1000) {
// not complete yet
}
}
@@ -1215,7 +1273,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bool augments) const
int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
{
int race = 0;
int race = RACE_DOUG_0;
const auto item = GetItem();
if (item) {
race = item->BaneDmgRace;
@@ -1721,6 +1779,18 @@ int EQ::ItemInstance::GetItemHaste(bool augments) const
return total;
}
int EQ::ItemInstance::RemoveTaskDeliveredItems()
{
int count = IsStackable() ? GetCharges() : 1;
count -= GetTaskDeliveredCount();
if (IsStackable())
{
SetCharges(count);
}
SetTaskDeliveredCount(0);
return count;
}
//
// class EvolveInfo
//
+57 -38
View File
@@ -51,6 +51,11 @@ typedef enum {
byFlagNotSet //apply action if the flag is NOT set
} byFlagSetting;
enum OrnamentationAugmentTypes {
StandardOrnamentation = 20,
SpecialOrnamentation = 21
};
class SharedDatabase;
// ########################################
@@ -92,6 +97,8 @@ namespace EQ
// Can item be equipped by/at?
bool IsEquipable(uint16 race, uint16 class_) const;
bool IsClassEquipable(uint16 class_) const;
bool IsRaceEquipable(uint16 race) const;
bool IsEquipable(int16 slot_id) const;
//
@@ -99,9 +106,10 @@ namespace EQ
//
bool IsAugmentable() const;
bool AvailableWearSlot(uint32 aug_wear_slots) const;
int8 AvailableAugmentSlot(int32 augtype) const;
bool IsAugmentSlotAvailable(int32 augtype, uint8 slot) const;
inline int32 GetAugmentType() const { return ((m_item) ? m_item->AugType : 0); }
int8 AvailableAugmentSlot(int32 augment_type) const;
bool IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const;
inline int GetAugmentType() const { return m_item ? m_item->AugType : 0; }
inline uint32 GetAugmentRestriction() const { return m_item ? m_item->AugRestrict : 0; }
inline bool IsExpendable() const { return ((m_item) ? ((m_item->Click.Type == item::ItemEffectExpendable) || (m_item->ItemType == item::ItemTypePotion)) : false); }
@@ -125,8 +133,8 @@ namespace EQ
//
// Augments
//
ItemInstance* GetAugment(uint8 slot) const;
uint32 GetAugmentItemID(uint8 slot) const;
ItemInstance* GetAugment(uint8 augment_index) const;
uint32 GetAugmentItemID(uint8 augment_index) const;
void PutAugment(uint8 slot, const ItemInstance& inst);
void PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id);
void DeleteAugment(uint8 slot);
@@ -134,7 +142,8 @@ namespace EQ
bool IsAugmented();
bool ContainsAugmentByID(uint32 item_id);
int CountAugmentByID(uint32 item_id);
ItemInstance* GetOrnamentationAug(int32 ornamentationAugtype) const;
bool IsOrnamentationAugment(EQ::ItemInstance* augment) const;
ItemInstance* GetOrnamentationAugment() const;
bool UpdateOrnamentationInfo();
static bool CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll = false);
@@ -148,6 +157,8 @@ namespace EQ
const ItemData* GetItem() const;
const ItemData* GetUnscaledItem() const;
const uint8 GetItemType() const { return m_item ? m_item->ItemType : 255; } // Return 255 so you know there's no valid item
int16 GetCharges() const { return m_charges; }
void SetCharges(int16 charges) { m_charges = charges; }
@@ -171,12 +182,13 @@ namespace EQ
void SetAttuned(bool flag) { m_attuned = flag; }
std::string GetCustomDataString() const;
std::string GetCustomData(std::string identifier);
void SetCustomData(std::string identifier, std::string value);
void SetCustomData(std::string identifier, int value);
void SetCustomData(std::string identifier, float value);
void SetCustomData(std::string identifier, bool value);
void DeleteCustomData(std::string identifier);
std::string GetCustomData(const std::string &identifier);
void SetCustomDataString(const std::string& str);
void SetCustomData(const std::string &identifier, const std::string& value);
void SetCustomData(const std::string &identifier, int value);
void SetCustomData(const std::string &identifier, float value);
void SetCustomData(const std::string &identifier, bool value);
void DeleteCustomData(const std::string& identifier);
// Allows treatment of this object as though it were a pointer to m_item
operator bool() const { return (m_item != nullptr); }
@@ -229,6 +241,13 @@ namespace EQ
void StopTimer(std::string name);
void ClearTimers();
int GetTaskDeliveredCount() const { return m_task_delivered_count; }
void SetTaskDeliveredCount(int count) { m_task_delivered_count = count; }
// This function should only be used by trade return apis
// Removes delivered task items from stack count and returns remaining count
// Return value should be used to determine if an item still exists (for stackable and non-stackable)
int RemoveTaskDeliveredItems();
// Get a total of a stat, including augs
// These functions should be used in place of other code manually totaling
// to centralize where it is done to make future changes easier (ex. whenever powersources come around)
@@ -292,33 +311,33 @@ namespace EQ
void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; }
ItemInstTypes m_use_type; // Usage type for item
const ItemData* m_item; // Ptr to item data
int16 m_charges; // # of charges for chargeable items
uint32 m_price; // Bazaar /trader price
uint32 m_color;
uint32 m_merchantslot;
int16 m_currentslot;
bool m_attuned;
int32 m_merchantcount; //number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber; // Unique identifier for this instance of an item. Needed for Bazaar.
uint32 m_exp;
int8 m_evolveLvl;
bool m_activated;
ItemData* m_scaledItem;
::EvolveInfo* m_evolveInfo;
bool m_scaling;
uint32 m_ornamenticon;
uint32 m_ornamentidfile;
uint32 m_new_id_file;
uint32 m_ornament_hero_model;
uint32 m_recast_timestamp;
ItemInstTypes m_use_type {ItemInstNormal}; // Usage type for item
const ItemData* m_item {nullptr}; // Ptr to item data
int16 m_charges {0}; // # of charges for chargeable items
uint32 m_price {0}; // Bazaar /trader price
uint32 m_color {0};
uint32 m_merchantslot {0};
int16 m_currentslot {0};
bool m_attuned {false};
int32 m_merchantcount {1}; //number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber {0}; // Unique identifier for this instance of an item. Needed for Bazaar.
uint32 m_exp {0};
int8 m_evolveLvl {0};
bool m_activated {false};
ItemData* m_scaledItem {nullptr};
::EvolveInfo* m_evolveInfo {nullptr};
bool m_scaling {false};
uint32 m_ornamenticon {0};
uint32 m_ornamentidfile {0};
uint32 m_new_id_file {0};
uint32 m_ornament_hero_model {0};
uint32 m_recast_timestamp {0};
int m_task_delivered_count {0};
//
// Items inside of this item (augs or contents);
std::map<uint8, ItemInstance*> m_contents; // Zero-based index: min=0, max=9
std::map<std::string, std::string> m_custom_data;
std::map<std::string, ::Timer> m_timers;
// Items inside of this item (augs or contents) {};
std::map<uint8, ItemInstance*> m_contents {}; // Zero-based index: min=0, max=9
std::map<std::string, std::string> m_custom_data {};
std::map<std::string, ::Timer> m_timers {};
};
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -48,5 +48,7 @@
#define LANG_HADAL 26
#define LANG_UNKNOWN 27
#define MAX_LANGUAGE_SKILL 100
#endif
+7 -7
View File
@@ -1,5 +1,5 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
@@ -41,7 +41,7 @@ namespace EQ
MemoryBuffer& operator+=(const MemoryBuffer &rhs);
friend MemoryBuffer operator+(MemoryBuffer lhs, const MemoryBuffer& rhs) { return lhs += rhs; }
~MemoryBuffer();
uchar& operator[](size_t pos);
const uchar& operator[](size_t pos) const;
@@ -64,20 +64,20 @@ namespace EQ
size_t Size() const;
size_t Capacity();
size_t Capacity() const;
void Resize(size_t sz);
void Clear();
void Zero();
template<typename T>
void Write(T val) {
static_assert(std::is_pod<T>::value, "MemoryBuffer::Write<T>(T val) only works on pod and string types.");
static_assert(std::is_standard_layout<T>::value, "MemoryBuffer::Write<T>(T val) only works on pod and string types.");
Write((const char*)&val, sizeof(T));
}
template<typename T>
T Read() {
static_assert(std::is_pod<T>::value, "MemoryBuffer::Read<T>() only works on pod and string types.");
static_assert(std::is_standard_layout<T>::value, "MemoryBuffer::Read<T>() only works on pod and string types.");
T temp;
Read((uchar*)&temp, sizeof(T));
return temp;
@@ -102,7 +102,7 @@ namespace EQ
read_pos_ += len + 1;
return ret;
}
void Write(const char *val, size_t len);
void Read(uchar *buf, size_t len);
void Read(char *str);
@@ -113,7 +113,7 @@ namespace EQ
inline size_t GetReadPosition() { return read_pos_; }
inline void SetReadPosition(size_t rp) { read_pos_ = rp; }
inline void ReadSkipBytes(size_t skip) { read_pos_ += skip; }
private:
uchar *buffer_;
size_t size_;
+2 -118
View File
@@ -18,6 +18,7 @@
#include "misc.h"
#include "types.h"
#include <cstring>
#include "strings.h"
std::map<int,std::string> DBFieldNames;
@@ -150,7 +151,7 @@ static char *temp=nullptr;
return false;
}
ptr++;
uint32 id = atoi(field[id_pos].c_str());
uint32 id = Strings::ToUnsignedInt(field[id_pos]);
items[id]=field;
for(i=0;i<10;i++) {
@@ -213,123 +214,6 @@ std::string x;
return i;
}
void LoadItemDBFieldNames() {
DBFieldNames[0]="N/A"; // Charges
DBFieldNames[1]="unknown002"; // ?
DBFieldNames[2]="N/A"; // Current Equip Slot
DBFieldNames[3]="unknown004";
DBFieldNames[4]="unknown005"; // ?
DBFieldNames[5]="itemclass"; // "Item Type (0=common, 1=container, 2=book)"
DBFieldNames[6]="name"; // Name
DBFieldNames[7]="lore"; // "Lore Name (*=lore, &=summoned, #=artifact)"
DBFieldNames[8]="idfile"; // IDFile
DBFieldNames[9]="id"; // ItemNumber
DBFieldNames[10]="weight"; // Weight
DBFieldNames[11]="norent"; // "NoRent (0=norent, 255=not norent)"
DBFieldNames[12]="nodrop"; // "NoDrop (0=nodrop, 255=not nodrop)"
DBFieldNames[13]="size"; // "Size (0=tiny, 1=small, 2=medium, 3=large, 4=giant)"
DBFieldNames[14]="slots"; // EquipSlots
DBFieldNames[15]="cost"; // Cost
DBFieldNames[16]="icon"; // IconNumber
DBFieldNames[17]="unknown018";
DBFieldNames[18]="unknown019";
DBFieldNames[19]="unknown020"; // ?
DBFieldNames[20]="tradeskills"; // "Tradeskill Item (1=is a tradeskill item, 0=not)"
DBFieldNames[21]="cr"; // SvCold
DBFieldNames[22]="dr"; // SvDisease
DBFieldNames[23]="pr"; // SvPoison
DBFieldNames[24]="mr"; // SvMagic
DBFieldNames[25]="fr"; // SvFire
DBFieldNames[26]="astr"; // STR
DBFieldNames[27]="asta"; // STA
DBFieldNames[28]="aagi"; // AGI
DBFieldNames[29]="adex"; // DEX
DBFieldNames[30]="acha"; // CHA
DBFieldNames[31]="aint"; // INT
DBFieldNames[32]="awis"; // WIS
DBFieldNames[33]="hp"; // HP
DBFieldNames[34]="mana"; // Mana
DBFieldNames[35]="ac"; // AC
DBFieldNames[36]="deity"; // Deity
DBFieldNames[37]="skillmodvalue"; // Skill Mod Value
DBFieldNames[38]="skillmodtype"; // Skill Mod Type
DBFieldNames[39]="banedmgrace"; // Bane Dmg Race
DBFieldNames[40]="banedmgamt"; // Band Dmg
DBFieldNames[41]="banedmgbody"; // Band Dmg Body
DBFieldNames[42]="magic"; // "Magic (0=not magic, 1=magic)"
DBFieldNames[43]="casttime2"; // Casttime appears twice
DBFieldNames[44]="hasteproclvl"; // "Level (Haste value, rather)"
DBFieldNames[45]="reqlevel"; // Required Level
DBFieldNames[46]="bardtype"; // Bard Type
DBFieldNames[47]="bardvalue"; // Bard Type Amount
DBFieldNames[48]="light"; // Light
DBFieldNames[49]="delay"; // Attack Delay
DBFieldNames[50]="reclevel"; // Recommended Level
DBFieldNames[51]="recskill"; // Recommended Skill
DBFieldNames[52]="elemdmgamt"; // "Elemental Dmg Type (1=magic, 2=fire, 3=cold, 4=poison, 5=disease)"
DBFieldNames[53]="elemdmgtype"; // Elemental Dmg
DBFieldNames[54]="effecttype"; // "Effect Type (0=combat, 1=clicky, 2=Worn, 3=Expendable charges, 4=Must Equip Clicky, 5=clicky)"
DBFieldNames[55]="range"; // Range
DBFieldNames[56]="damage"; // Damage
DBFieldNames[57]="color"; // Color
DBFieldNames[58]="classes"; // Classes
DBFieldNames[59]="races"; // Races
DBFieldNames[60]="unknown061";
DBFieldNames[61]="spellid"; // SpellId
DBFieldNames[62]="maxcharges"; // MaxCharges
DBFieldNames[63]="itemtype"; // "Skill (ItemType: 1hs, etc)"
DBFieldNames[64]="material"; // Material
DBFieldNames[65]="sellrate"; // ** Sell Rate
DBFieldNames[66]="unknown067";
DBFieldNames[67]="casttime"; // CastTime (milliseconds)
DBFieldNames[68]="unknown069";
DBFieldNames[69]="unknown070"; // ?
DBFieldNames[70]="focusid"; // Focus Effect Spell Id
DBFieldNames[71]="combateffects"; // CombatEffects
DBFieldNames[72]="shielding"; // Shielding
DBFieldNames[73]="stunresist"; // StunResist
DBFieldNames[74]="strikethrough"; // StrikeThrough
DBFieldNames[75]="unknown076";
DBFieldNames[76]="unknown077"; // ?
DBFieldNames[77]="spellshield"; // Spell Shield
DBFieldNames[78]="avoidance"; // Avoidance
DBFieldNames[79]="accuracy"; // Accuracy
DBFieldNames[80]="factionmod1"; // Faction Mod Index 1
DBFieldNames[81]="factionmod2"; // Faction Mod Index 2
DBFieldNames[82]="factionmod3"; // Faction Mod Index 3
DBFieldNames[83]="factionmod4"; // Faction Mod Index 4
DBFieldNames[84]="factionamt1"; // Faction Mod Value 1
DBFieldNames[85]="factionamt2"; // Faction Mod Value 2
DBFieldNames[86]="factionamt3"; // Faction Mod Value 3
DBFieldNames[87]="factionamt4"; // Faction Mod Value 4
DBFieldNames[88]="unknown089";
DBFieldNames[89]="charmfile"; // ** Charm File
DBFieldNames[90]="unknown091";
DBFieldNames[91]="augslot1type"; // Slot1Type
DBFieldNames[92]="augslot2type"; // Slot2Type
DBFieldNames[93]="augslot3type"; // Slot3Type
DBFieldNames[94]="augslot4type"; // Slot4Type
DBFieldNames[95]="augslot5type"; // Slot5Type
DBFieldNames[96]="ldonpointtheme";
DBFieldNames[97]="ldonpointcost"; // ?
DBFieldNames[98]="unknown099";
DBFieldNames[99]="bagtype"; // bag type
DBFieldNames[100]="bagslots"; // bag slots
DBFieldNames[101]="bagsize"; // bag size capacity
DBFieldNames[102]="bagwr"; // bag weight reduction
DBFieldNames[103]="booktype"; // "book type (0=rolled up note, 1=book)"
DBFieldNames[104]="unknown105";
DBFieldNames[105]="filename"; // Book Filename
DBFieldNames[106]="unknown107";
DBFieldNames[107]="unknown108";
DBFieldNames[108]="loreflag";
DBFieldNames[109]="unknown111";
DBFieldNames[110]="unknown112";
DBFieldNames[111]="unknown113";
DBFieldNames[112]="unknown114";
DBFieldNames[113]="unknown115"; // ? (end quote)
}
void dump_message_column(unsigned char *buffer, unsigned long length, std::string leader, FILE *to)
{
unsigned long i,j;
-2
View File
@@ -15,8 +15,6 @@ bool ItemParse(const char *data, int length, std::map<int,std::map<int,std::stri
int Tokenize(std::string s, std::map<int,std::string> & tokens, char delim='|');
void LoadItemDBFieldNames();
#ifndef WIN32
int print_stacktrace();
#endif
+2 -1
View File
@@ -21,6 +21,7 @@
#include "misc_functions.h"
#include <string.h>
#include <time.h>
#include "strings.h"
#ifndef WIN32
#include <netinet/in.h>
@@ -130,7 +131,7 @@ bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf
if (*oIP == 0)
return false;
if (oPort)
*oPort = atoi(sep.arg[1]);
*oPort = Strings::ToUnsignedInt(sep.arg[1]);
return true;
}
return false;
+21
View File
@@ -51,6 +51,7 @@ void MySQLRequestResult::ZeroOut()
m_RowCount = 0;
m_RowsAffected = 0;
m_LastInsertedID = 0;
m_error_message = "";
}
MySQLRequestResult::~MySQLRequestResult()
@@ -137,3 +138,23 @@ MySQLRequestResult& MySQLRequestResult::operator=(MySQLRequestResult&& other)
other.ZeroOut();
return *this;
}
uint32 MySQLRequestResult::GetErrorNumber() const
{
return m_ErrorNumber;
}
void MySQLRequestResult::SetErrorNumber(uint32 m_error_number)
{
m_ErrorNumber = m_error_number;
}
const std::string &MySQLRequestResult::GetErrorMessage() const
{
return m_error_message;
}
void MySQLRequestResult::SetErrorMessage(const std::string &m_error_message)
{
MySQLRequestResult::m_error_message = m_error_message;
}
+15 -3
View File
@@ -33,30 +33,42 @@ private:
uint32 m_LastInsertedID;
uint32 m_ErrorNumber;
std::string m_error_message;
public:
MySQLRequestResult(MYSQL_RES* result, uint32 rowsAffected = 0, uint32 rowCount = 0, uint32 columnCount = 0, uint32 lastInsertedID = 0, uint32 errorNumber = 0, char *errorBuffer = nullptr);
MySQLRequestResult();
MySQLRequestResult();
MySQLRequestResult(MySQLRequestResult&& moveItem);
~MySQLRequestResult();
MySQLRequestResult& operator=(MySQLRequestResult&& other);
bool Success() const { return m_Success;}
std::string ErrorMessage() const {return m_ErrorBuffer ? std::string(m_ErrorBuffer) : std::string("");}
std::string ErrorMessage() const {
if (!m_error_message.empty()) {
return m_error_message;
}
return m_ErrorBuffer ? std::string(m_ErrorBuffer) : std::string("");
}
uint32 ErrorNumber() const {return m_ErrorNumber;}
uint32 RowsAffected() const {return m_RowsAffected;}
uint32 RowCount() const {return m_RowCount;}
uint32 ColumnCount() const {return m_ColumnCount;}
uint32 LastInsertedID() const {return m_LastInsertedID;}
// default to 0 index since we mostly use it that way anyways.
uint32 LengthOfColumn(int columnIndex = 0);
uint32 LengthOfColumn(int columnIndex = 0);
const std::string FieldName(int columnIndex);
MySQLRequestRow& begin() { return m_CurrentRow; }
MySQLRequestRow& end() { return m_OneBeyondRow; }
uint32 GetErrorNumber() const;
void SetErrorNumber(uint32 m_error_number);
const std::string &GetErrorMessage() const;
void SetErrorMessage(const std::string &m_error_message);
private:
void FreeInternals();
void ZeroOut();
+1 -1
View File
@@ -7,7 +7,7 @@ EQ::Net::ConsoleServer::ConsoleServer(const std::string &addr, int port)
m_server = std::make_unique<EQ::Net::TCPServer>();
m_server->Listen(addr, port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
ConsoleServerConnection *c = new ConsoleServerConnection(this, connection);
m_connections.insert(std::make_pair(c->GetUUID(), std::unique_ptr<ConsoleServerConnection>(c)));
m_connections.emplace(std::make_pair(c->GetUUID(), std::unique_ptr<ConsoleServerConnection>(c)));
});
}
+6 -6
View File
@@ -97,7 +97,7 @@ void EQ::Net::DaybreakConnectionManager::Connect(const std::string &addr, int po
m_on_new_connection(connection);
}
m_connections.insert(std::make_pair(std::make_pair(addr, port), connection));
m_connections.emplace(std::make_pair(std::make_pair(addr, port), connection));
}
void EQ::Net::DaybreakConnectionManager::Process()
@@ -234,7 +234,7 @@ void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoi
if (m_on_new_connection) {
m_on_new_connection(connection);
}
m_connections.insert(std::make_pair(std::make_pair(endpoint, port), connection));
m_connections.emplace(std::make_pair(std::make_pair(endpoint, port), connection));
connection->ProcessPacket(p);
}
else if (data[1] != OP_OutOfSession) {
@@ -527,7 +527,7 @@ void EQ::Net::DaybreakConnection::AddToQueue(int stream, uint16_t seq, const Pac
DynamicPacket *out = new DynamicPacket();
out->PutPacket(0, p);
s->packet_queue.insert(std::make_pair(seq, out));
s->packet_queue.emplace(std::make_pair(seq, out));
}
}
@@ -1427,7 +1427,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
m_owner->m_options.resend_delay_min,
m_owner->m_options.resend_delay_max);
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
stream->sent_packets.emplace(std::make_pair(stream->sequence_out, sent));
stream->sequence_out++;
InternalBufferedSend(first_packet);
@@ -1459,7 +1459,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
m_owner->m_options.resend_delay_min,
m_owner->m_options.resend_delay_max);
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
stream->sent_packets.emplace(std::make_pair(stream->sequence_out, sent));
stream->sequence_out++;
InternalBufferedSend(packet);
@@ -1483,7 +1483,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
m_owner->m_options.resend_delay_min,
m_owner->m_options.resend_delay_max);
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
stream->sent_packets.emplace(std::make_pair(stream->sequence_out, sent));
stream->sequence_out++;
InternalBufferedSend(packet);
+1 -1
View File
@@ -22,7 +22,7 @@ void EQ::Net::EQStreamManager::SetOptions(const EQStreamManagerInterfaceOptions
void EQ::Net::EQStreamManager::DaybreakNewConnection(std::shared_ptr<DaybreakConnection> connection)
{
std::shared_ptr<EQStream> stream(new EQStream(this, connection));
m_streams.insert(std::make_pair(connection, stream));
m_streams.emplace(std::make_pair(connection, stream));
if (m_on_new_connection) {
m_on_new_connection(stream);
}
+1 -1
View File
@@ -45,7 +45,7 @@ void EQ::Net::ServertalkClient::SendPacket(ServerPacket *p)
void EQ::Net::ServertalkClient::OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb)
{
m_message_callbacks.insert(std::make_pair(opcode, cb));
m_message_callbacks.emplace(std::make_pair(opcode, cb));
}
void EQ::Net::ServertalkClient::OnMessage(std::function<void(uint16_t, EQ::Net::Packet&)> cb)
@@ -41,7 +41,7 @@ void EQ::Net::ServertalkLegacyClient::SendPacket(ServerPacket *p)
void EQ::Net::ServertalkLegacyClient::OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb)
{
m_message_callbacks.insert(std::make_pair(opcode, cb));
m_message_callbacks.emplace(std::make_pair(opcode, cb));
}
void EQ::Net::ServertalkLegacyClient::OnMessage(std::function<void(uint16_t, EQ::Net::Packet&)> cb)
+3 -3
View File
@@ -19,12 +19,12 @@ void EQ::Net::ServertalkServer::Listen(const ServertalkServerOptions& opts)
void EQ::Net::ServertalkServer::OnConnectionIdentified(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
{
m_on_ident.insert(std::make_pair(type, cb));
m_on_ident.emplace(std::make_pair(type, cb));
}
void EQ::Net::ServertalkServer::OnConnectionRemoved(const std::string &type, std::function<void(std::shared_ptr<ServertalkServerConnection>)> cb)
{
m_on_disc.insert(std::make_pair(type, cb));
m_on_disc.emplace(std::make_pair(type, cb));
}
void EQ::Net::ServertalkServer::ConnectionDisconnected(ServertalkServerConnection *conn)
@@ -75,7 +75,7 @@ void EQ::Net::ServertalkServer::ConnectionIdentified(ServertalkServerConnection
else {
std::vector<std::shared_ptr<EQ::Net::ServertalkServerConnection>> vec;
vec.push_back(*iter);
m_ident_connections.insert(std::make_pair(conn->GetIdentifier(), vec));
m_ident_connections.emplace(std::make_pair(conn->GetIdentifier(), vec));
}
m_unident_connections.erase(iter);
+1 -1
View File
@@ -100,7 +100,7 @@ void EQ::Net::ServertalkServerConnection::SendPacket(ServerPacket *p)
void EQ::Net::ServertalkServerConnection::OnMessage(uint16_t opcode, std::function<void(uint16_t, EQ::Net::Packet&)> cb)
{
m_message_callbacks.insert(std::make_pair(opcode, cb));
m_message_callbacks.emplace(std::make_pair(opcode, cb));
}
void EQ::Net::ServertalkServerConnection::OnMessage(std::function<void(uint16_t, EQ::Net::Packet&)> cb)
+1 -1
View File
@@ -142,7 +142,7 @@ void EQ::Net::TCPConnection::Write(const char *data, size_t count)
WriteBaton *baton = new WriteBaton;
baton->connection = this;
baton->buffer = new char[count];;
baton->buffer = new char[count];
uv_write_t *write_req = new uv_write_t;
memset(write_req, 0, sizeof(uv_write_t));
+16 -12
View File
@@ -33,6 +33,7 @@
#include "rof_structs.h"
#include "../rulesys.h"
#include "../path_manager.h"
#include "../races.h"
#include <iostream>
#include <sstream>
@@ -664,7 +665,7 @@ namespace RoF
ENCODE(OP_DeleteCharge)
{
Log(Logs::Moderate, Logs::Netcode, "RoF::ENCODE(OP_DeleteCharge)");
Log(Logs::Detail, Logs::Netcode, "RoF::ENCODE(OP_DeleteCharge)");
ENCODE_FORWARD(OP_MoveItem);
}
@@ -1049,7 +1050,7 @@ namespace RoF
{
if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername))
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct));
@@ -1068,7 +1069,7 @@ namespace RoF
return;
}
//if(gjs->action == groupActLeave)
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct));
@@ -1098,7 +1099,7 @@ namespace RoF
for (int i = 0; i < 5; ++i)
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->membername[i]);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->member_name[i]);
if (gu2->membername[i][0] != '\0')
{
PacketLength += (22 + strlen(gu2->membername[i]) + 1);
@@ -1168,7 +1169,7 @@ namespace RoF
return;
}
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
ENCODE_LENGTH_EXACT(GroupJoin_Struct);
SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct);
@@ -1592,7 +1593,7 @@ namespace RoF
ENCODE_LENGTH_EXACT(LootingItem_Struct);
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
Log(Logs::Moderate, Logs::Netcode, "RoF::ENCODE(OP_LootItem)");
Log(Logs::Detail, Logs::Netcode, "RoF::ENCODE(OP_LootItem)");
OUT(lootee);
OUT(looter);
@@ -1750,7 +1751,7 @@ namespace RoF
ENCODE_LENGTH_EXACT(MoveItem_Struct);
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
Log(Logs::Moderate, Logs::Netcode, "RoF::ENCODE(OP_MoveItem)");
Log(Logs::Detail, Logs::Netcode, "RoF::ENCODE(OP_MoveItem)");
eq->from_slot = ServerToRoFSlot(emu->from_slot);
eq->to_slot = ServerToRoFSlot(emu->to_slot);
@@ -3830,7 +3831,9 @@ namespace RoF
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)))
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
)
{
PacketSize += 60;
@@ -3962,7 +3965,9 @@ namespace RoF
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown18
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown19
if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
{
@@ -4817,7 +4822,7 @@ namespace RoF
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
Log(Logs::Moderate, Logs::Netcode, "RoF::DECODE(OP_LootItem)");
Log(Logs::Detail, Logs::Netcode, "RoF::DECODE(OP_LootItem)");
IN(lootee);
IN(looter);
@@ -4832,7 +4837,7 @@ namespace RoF
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
Log(Logs::Moderate, Logs::Netcode, "RoF::DECODE(OP_MoveItem)");
Log(Logs::Detail, Logs::Netcode, "RoF::DECODE(OP_MoveItem)");
emu->from_slot = RoFToServerSlot(eq->from_slot);
emu->to_slot = RoFToServerSlot(eq->to_slot);
@@ -5213,7 +5218,6 @@ namespace RoF
/**
* Ornamentation
*/
int ornamentation_augment_type = RuleI(Character, OrnamentationAugmentType);
uint32 ornamentation_icon = (inst->GetOrnamentationIcon() ? inst->GetOrnamentationIcon() : 0);
uint32 hero_model = 0;
+42 -22
View File
@@ -33,6 +33,9 @@
#include "rof2_structs.h"
#include "../rulesys.h"
#include "../path_manager.h"
#include "../classes.h"
#include "../races.h"
#include "../../zone/raids.h"
#include <iostream>
#include <sstream>
@@ -714,7 +717,7 @@ namespace RoF2
ENCODE(OP_DeleteCharge)
{
Log(Logs::Moderate, Logs::Netcode, "RoF2::ENCODE(OP_DeleteCharge)");
Log(Logs::Detail, Logs::Netcode, "RoF2::ENCODE(OP_DeleteCharge)");
ENCODE_FORWARD(OP_MoveItem);
}
@@ -1099,7 +1102,7 @@ namespace RoF2
{
if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername))
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct));
@@ -1118,7 +1121,7 @@ namespace RoF2
return;
}
//if(gjs->action == groupActLeave)
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct));
@@ -1148,7 +1151,7 @@ namespace RoF2
for (int i = 0; i < 5; ++i)
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->membername[i]);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->member_name[i]);
if (gu2->membername[i][0] != '\0')
{
PacketLength += (22 + strlen(gu2->membername[i]) + 1);
@@ -1218,7 +1221,7 @@ namespace RoF2
return;
}
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
ENCODE_LENGTH_EXACT(GroupJoin_Struct);
SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct);
@@ -1642,7 +1645,7 @@ namespace RoF2
ENCODE_LENGTH_EXACT(LootingItem_Struct);
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
Log(Logs::Moderate, Logs::Netcode, "RoF2::ENCODE(OP_LootItem)");
Log(Logs::Detail, Logs::Netcode, "RoF2::ENCODE(OP_LootItem)");
OUT(lootee);
OUT(looter);
@@ -1800,7 +1803,7 @@ namespace RoF2
ENCODE_LENGTH_EXACT(MoveItem_Struct);
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
Log(Logs::Moderate, Logs::Netcode, "RoF2::ENCODE(OP_MoveItem)");
Log(Logs::Detail, Logs::Netcode, "RoF2::ENCODE(OP_MoveItem)");
eq->from_slot = ServerToRoF2Slot(emu->from_slot);
eq->to_slot = ServerToRoF2Slot(emu->to_slot);
@@ -2735,7 +2738,7 @@ namespace RoF2
{
RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer;
auto outapp =
new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer;
outlaa->action = inlaa->action;
@@ -2744,6 +2747,18 @@ namespace RoF2
memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct));
dest->FastQueuePacket(&outapp);
}
else if (raid_gen->action == raidSetNote)
{
auto in_note = (RaidGeneral_Struct*)__emu_buffer;
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
auto note = (RaidGeneral_Struct*)outapp->pBuffer;
note->action = raidSetNote;
strn0cpy(note->leader_name, in_note->leader_name, sizeof(note->leader_name));
strn0cpy(note->player_name, in_note->player_name, sizeof(note->leader_name));
strn0cpy(note->note, in_note->note, sizeof(note->note));
dest->QueuePacket(outapp);
safe_delete(outapp);
}
else
{
RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer;
@@ -3944,7 +3959,7 @@ namespace RoF2
if (strlen(emu->suffix))
PacketSize += strlen(emu->suffix) + 1;
if (emu->DestructibleObject || emu->class_ == 62)
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE)
{
if (emu->DestructibleObject)
PacketSize = PacketSize - 4; // No bodytype
@@ -3965,7 +3980,9 @@ namespace RoF2
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)))
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
)
{
PacketSize += 60;
@@ -4032,17 +4049,19 @@ namespace RoF2
// actually part of bitfields
uint8 OtherData = 0;
if (emu->class_ == 62) //LDoN Chest
if (emu->class_ == LDON_TREASURE) //LDoN Chest
{
OtherData = OtherData | 0x04;
if (strlen(emu->title))
}
if (strlen(emu->title)) {
OtherData = OtherData | 16;
if (strlen(emu->suffix))
}
if (strlen(emu->suffix)) {
OtherData = OtherData | 32;
if (emu->DestructibleObject)
}
if (emu->DestructibleObject) {
OtherData = OtherData | 0xe1; // Live has 0xe1 for OtherData
}
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
// float EmitterScalingRadius
@@ -4058,7 +4077,7 @@ namespace RoF2
// int DefaultEmitterID
VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4
if (emu->DestructibleObject || emu->class_ == 62)
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE)
{
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleModel);
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleName2);
@@ -4166,7 +4185,9 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // These do something with OP_WeaponEquip1
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // ^
if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
{
@@ -5015,7 +5036,7 @@ namespace RoF2
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
Log(Logs::Moderate, Logs::Netcode, "RoF2::DECODE(OP_LootItem)");
Log(Logs::Detail, Logs::Netcode, "RoF2::DECODE(OP_LootItem)");
IN(lootee);
IN(looter);
@@ -5030,7 +5051,7 @@ namespace RoF2
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
Log(Logs::Moderate, Logs::Netcode, "RoF2::DECODE(OP_MoveItem)");
Log(Logs::Detail, Logs::Netcode, "RoF2::DECODE(OP_MoveItem)");
emu->from_slot = RoF2ToServerSlot(eq->from_slot);
emu->to_slot = RoF2ToServerSlot(eq->to_slot);
@@ -5469,7 +5490,6 @@ namespace RoF2
/**
* Ornamentation
*/
int ornamentation_augment_type = RuleI(Character, OrnamentationAugmentType);
uint32 ornamentation_icon = (inst->GetOrnamentationIcon() ? inst->GetOrnamentationIcon() : 0);
uint32 hero_model = 0;
+2 -2
View File
@@ -2590,7 +2590,7 @@ struct GroupUpdate_Struct_Live { // New for Live
struct GroupMembers_Struct { // New for Live
/*0000*/ uint32 membernumber; // Guess - number of member in the group (0 to 5?)
/*0000*/ //char membername[0]; // Member Name Null Terminated
/*0000*/ //char member_name[0]; // Member Name Null Terminated
/*0000*/ uint8 unknown001[3]; // Seen 0
/*0000*/ uint32 memberlevel; // Guess
/*0000*/ uint8 unknown002[11]; // Seen 0
@@ -2600,7 +2600,7 @@ struct GroupJoin_Struct_Live { // New for Live
/*0000*/ uint32 unknown0000; // Matches unknown0136 from GroupFollow_Struct
/*0004*/ uint32 action;
/*0008*/ uint8 unknown0008[5]; // Seen 0
/*0013*/ //char membername[0]; // Null Terminated?
/*0013*/ //char member_name[0]; // Null Terminated?
/*0000*/ uint8 unknown0013[3]; // Seen 0
/*0000*/ uint32 unknown0016; // Matches unknown0132 from GroupFollow_Struct
/*0000*/ uint8 unknown0020[11]; // Seen 0
+2 -2
View File
@@ -2566,7 +2566,7 @@ struct GroupUpdate_Struct_Live { // New for Live
struct GroupMembers_Struct { // New for Live
/*0000*/ uint32 membernumber; // Guess - number of member in the group (0 to 5?)
/*0000*/ //char membername[0]; // Member Name Null Terminated
/*0000*/ //char member_name[0]; // Member Name Null Terminated
/*0000*/ uint8 unknown001[3]; // Seen 0
/*0000*/ uint32 memberlevel; // Guess
/*0000*/ uint8 unknown002[11]; // Seen 0
@@ -2576,7 +2576,7 @@ struct GroupJoin_Struct_Live { // New for Live
/*0000*/ uint32 unknown0000; // Matches unknown0136 from GroupFollow_Struct
/*0004*/ uint32 action;
/*0008*/ uint8 unknown0008[5]; // Seen 0
/*0013*/ //char membername[0]; // Null Terminated?
/*0013*/ //char member_name[0]; // Null Terminated?
/*0000*/ uint8 unknown0013[3]; // Seen 0
/*0000*/ uint32 unknown0016; // Matches unknown0132 from GroupFollow_Struct
/*0000*/ uint8 unknown0020[11]; // Seen 0

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