Compare commits

...

31 Commits

Author SHA1 Message Date
Chris Miles 703862d977 [Release] 22.37.0 (#3789) 2023-12-18 15:43:09 -06:00
nytmyr 6e325c1ee3 [Bots] Fix unnecessary failed to save timer error (#3788) 2023-12-18 15:39:14 -06:00
nytmyr 933b83add6 [Bots] Fix ^defensive from checking aggressive disciplines. (#3787)
Bots were checking for aggressive disciplines with both ^aggressive and ^defensive.
2023-12-18 15:38:37 -06:00
Alex King b3cd4e63f1 [Bug Fix] Drop Invisibility when hit by traps (#3785)
# Notes
- Resolves https://github.com/EQEmu/Server/issues/663.

# Video
[Drop Invisibility Trap Test](https://github.com/EQEmu/Server/assets/89047260/d6e96704-ee6d-4b16-bd52-4122e3b37577)
2023-12-18 15:37:53 -06:00
nytmyr 3c894cb533 [Bots] Add ScanCloseMobs support to fix AEs (#3786)
Previously bots were only scanning for nearby clients so any AE spells or procs didn't have mobs to hit.

This changes that to scan for mobs instead of clients so their close entity list supports AEs with mobs to hit.
2023-12-18 15:37:07 -06:00
Alex King b19ad64800 [Bug Fix] Send Entity ID in Death Events to resolve #3721 (#3779)
* [Bug Fix] Send Entity ID in Death Events to resolve #3721

# Notes
- Due to some pointers becoming invalid you may get an invalid entity ID on the killed mob if we don't just directly send the entity ID in the export string.

* Update attack.cpp

* Remove GetID() export.
2023-12-17 19:43:41 -06:00
Alex King 2cd3d27c67 [Quest API] Add GetNPCAggro() and SetNPCAggro() to Perl/Lua (#3781)
* [Quest API] Add GetNPCAggro() and SetNPCAggro() to Perl/Lua

# Perl
- Add `$npc->GetNPCAggro()`.
- Add `$npc->SetNPCAggro(in_npc_aggro)`.

# Lua
- Add `npc:GetNPCAggro()`.
- Add `npc:SetNPCAggro(in_npc_aggro)`.

# Notes
- Allows operators to enable or disable an NPC's NPC aggro capability dynamically.

* Update api_service.cpp
2023-12-17 20:34:06 -05:00
Alex King d3b46becd0 [Bug Fix] Fix NPCs routing to 0.0, 0.0 on #summon (#3780)
# Notes
- Resolves #2474.
2023-12-17 20:24:24 -05:00
Chris Miles 286479198f [Compilation] Use pre-compiled headers for Windows (speed) (#3778)
* Experiment with PCH

* Another run

* GCC test

* Different test

* Another one

* Another one

* Lua headers

* PCH main zone primitives

* Tweaks

* Tweaks

* Tweaks

* Add EQEMU_BUILD_PCH option default to ON
2023-12-17 19:04:21 -06:00
Chris Miles 21ec832ca6 [CI] Switch to use clang for Linux builds (speed) (#3777) 2023-12-17 15:17:29 -06:00
nytmyr bdf5f8b4a3 [Bots] [Quest API] Add ^clickitem, ^timer, fix GetBestBotSpellForCure (#3755)
* [Bots][Quest API] Add ^clickitem, ^timer, revamp bot timers, fix GetBestBotSpellForCure

This adds the command **^clickitem** for bots.
Bots can click items they are wearing with the provided slot ID, players can use **^invlist** on their bots to see items and slot IDs.
This supports actionables.
**^itemclick 13 byclass 11** would command all Necromancer bots to attempt to click their Primary item.

This adds and supports charges for items to bots, when an item is used, it will lose a charge and cannot be clicked once no charges remain.

This adds the following rules:
**Bots, BotsClickItemsMinLvl** - Minimum level bots can use **^clickitem**.
**Bots, BotsCanClickItems** - Whether or not **^clickitem** is allowed for bots.
**Bots, CanClickMageEpicV1** - Whether or not players are allowed to command their bots to use the Magician Epic 1.0

This adds quest methods to Perl/Lua for:
ClearDisciplineReuseTimer, ClearItemReuseTimer, ClearSpellRecastTimer
GetDisciplineReuseTimer, GetItemReuseTimer, GetSpellRecastTimer
SetDisciplineReuseTimer, SetItemReuseTimer, SetSpellRecastTimer

Discipline and Spell methods use the spell_id to check, get and set. Item uses the item_id.
Clear and Get support wildcards (no spell/item id) to clear all timers of the type or get the first timer of the type.
Get will return the remaining time on the chosen timer, if any.
Set supports a wildcard (no recast/reuse provided) to use the default of the provided type, you can also specify a recast/reuse timer to set that timer to the chosen value.

**^timer** has been added as a bot command, defaulted for GM access.
This can be used to set, get and clear timers of different types. Use **^timer help** for info.

This revamps the way timers are set, stored, loaded for bots.

**GetBestBotSpellForCure** was previously checking only the first spell found and not properly iterating through the checks.

This requires modifications to the **bot_timers** table and is included in this commit.

* Rebase Conflicts

* Update queries to use repositories

* Minor adjustment

* Formatting

* Handle delete as well

* Cleanup.

* Adjust primary keys to prevent conflicts

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-12-17 14:53:34 -05:00
Alex King 4ca6485398 [Bug Fix] Fix issue with HOTBonusHealingSplitOverDuration Rule (#3776)
# Notes
- This rule didn't function properly since we didn't add extra heal regardless of rule setting.
2023-12-16 22:48:19 -06:00
Alex King 0c9c2e25c1 [Quest API] Add EVENT_CRYSTAL_GAIN and EVENT_CRYSTAL_LOSS to Perl/Lua (#3735)
* [Quest API] Add EVENT_CRYSTAL_GAIN and EVENT_CRYSTAL_LOSS

- Add `$client->AddEbonCrystals(amount)`.
- Add `$client->AddRadiantCrystals(amount)`.
- Add `$client->RemoveEbonCrystals(amount)`.
- Add `$client->RemoveRadiantCrystals(amount)`.
- Add `EVENT_CRYSTAL_GAIN`.
- Add `EVENT_CRYSTAL_LOSS`.
- Export `$ebon_amount`, `$radiant_amount`, and `$is_reclaim`.

- Add `client:AddEbonCrystals(amount)`.
- Add `client:AddRadiantCrystals(amount)`.
- Add `client:RemoveEbonCrystals(amount)`.
- Add `client:RemoveRadiantCrystals(amount)`.
- Add `event_crystal_gain`.
- Add `event_crystal_loss`.
- Export `e.ebon_amount`, `e.radiant_amount`, and `e.is_reclaim`.

- Allows operators to add or remove Ebon/Radiant Crystals directly.
- Allows operators to track gain/loss of Ebon/Radiant Crystals.

* Update perl_client.cpp

* Update lua_client.cpp
2023-12-16 22:47:13 -06:00
regneq 7e651877c7 [Bug Fix] Fixed the discrepacy with time using command #time and in quests. (#3767)
* [BUG] Fixed the discrepacy with time using command #time and in quests. https://github.com/EQEmu/Server/issues/3700

* removed comments and paratheses from previous commit.

* fixed typos.

* made some adjustment so #time, /time, scripting, and log all match.

* Update lua_general.cpp
2023-12-16 22:40:40 -06:00
Alex King 9739c1c8ef [Quest API] Add EVENT_ALT_CURRENCY_GAIN and EVENT_ALT_CURRENCY_LOSS to Perl/Lua (#3734)
* [Quest API] Add EVENT_ALT_CURRENCY_GAIN and EVENT_ALT_CURRENCY_LOSS

- Add `EVENT_ALT_CURRENCY_GAIN`.
- Add `EVENT_ALT_CURRENCY_LOSS`.
- Export `$currency_id`, `$amount`, and `$total.

- Add `event_alt_currency_gain`.
- Add `event_alt_currency_loss`.
- Export `e.currency_id`, `e.amount`, and `e.total.

- Convert `int8 method` to `bool is_scripted` in `Client::AddAlternateCurrencyValue`.
- Properly utilize `is_scripted` parameter in `perl_client.cpp`.
- Allows operators to perform events on alternate currency gains/losses.

* Update lua_general.cpp

* Cleanup types.

* Update lua_client.cpp
2023-12-16 22:40:24 -06:00
Alex King 8aae59eebe [Quest API] Add EVENT_LDON_POINTS_GAIN and EVENT_LDON_POINTS_LOSS to Perl/Lua (#3742)
* [Quest API] Add EVENT_LDON_POINTS_GAIN and EVENT_LDON_POINTS_LOSS to Perl/Lua

- Add `EVENT_LDON_POINTS_GAIN`.
- Add `EVENT_LDON_POINTS_LOSS`.
- Exports `$theme_id` and `$points`.

- Add `event_ldon_points_gain`.
- Add `event_ldon_points_loss`.
- Exports `e.theme_id` and `e.points`.

- Allows operators to track gain/loss of LDoN Points of any theme.

* Update client.cpp
2023-12-16 22:31:25 -06:00
Alex King c1b07afae9 [Quest API] Add EVENT_LOOT_ADDED to Perl/Lua (#3739)
* [Quest API] Add EVENT_ADDED_LOOT to Perl/Lua

# Perl
- Add `EVENT_ADDED_LOOT`.
- Exports `$item`, `$item_id`, `$item_name`, `$item_charges`, `$augment_one`, `$augment_two`, `$augment_three`, `$augment_four`, `$augment_five`, and `$augment_six`.

# Lua
- Add `event_added_loot`.
- Exports `e.item`, `e.item_id`, `e.item_name`, `e.item_charges`, `e.augment_one`, `e.augment_two`, `e.augment_three`, `e.augment_four`, `e.augment_five`, and `e.augment_six`.

# Notes
- Allows operators to perform events when loot is added to an NPC, such as removing the loot or keeping track of it.

* Update lua_parser_events.cpp

* Rename event.

* loot_added

* AddItem changese
2023-12-16 22:25:09 -06:00
Alex King 9c238cd08d [Quest API] Add EVENT_LEVEL_UP and EVENT_LEVEL_DOWN to Bots (#3750)
* [Quest API] Add EVENT_LEVEL_UP and EVENT_LEVEL_DOWN to bots

# Notes
- Bots did not have these events, this will allow operators to perform events on bot level up/down.

* Update bot.cpp
2023-12-16 22:23:38 -06:00
Akkadius 33adb9bcc1 [Hotfix] Fix bad merge 2023-12-16 21:06:36 -06:00
nytmyr 2e8bf82861 [Bots] Expand ^itemuse options (#3756)
Adds additional options to **^itemuse** to narrow down the list of accepting bots.

You can now specify by class, casters, hybrids, melee, WIS caster, INT caster or plate/chain/leather/cloth wearing.
2023-12-16 20:54:23 -05:00
nytmyr 4d118ab978 [Bots] Fix ^oo autodefend from sending bots/pets to invalid haters (#3772)
Bots and especially their pets could get in a loop where they try to attack an invalid target. This would result in their pets spamming "That is not a legal target" messages.
2023-12-16 16:08:16 -05:00
Chris Miles fcb40daaf1 [Release] 22.36.0 (#3774) 2023-12-16 01:07:19 -06:00
Alex King 553bafdbe1 [Bug Fix] Fix Starting Items SQL (#3766)
* [Bug Fix] Fix Starting Items SQL

# Notes
- `race_list` comes before `class_list`,query had them in the wrong order.

* Real fix.

* Update database_update_manifest.cpp

* Manifest change

* Repository generate

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-12-16 00:45:27 -06:00
Chris Miles d0443db199 [Database] When database version is greater than binary, we are up to date (#3771) 2023-12-16 00:44:40 -06:00
Chris Miles 9206163190 [Database] Make it clearer to users that a database backup is occurring (#3769) 2023-12-16 00:44:25 -06:00
Chris Miles e504482b94 [Corpse] Fix /corpse command regression from #3727 (#3770) 2023-12-16 00:44:11 -06:00
Alex King 77b88e3dec [Rules] Add DOT and HOT Rules (#3760)
* [Rules] Add DOT and HOT Rules

# Notes
- Add `Spells:DOTDamageBonusSplitOverDuration` rule.
- Allows operators to disable the DOT bonus damage being split over duration and instead adds the full amount every tic.
- Add `Spells:HOTBonusHealingSplitOverDuration` rule.
- Allows operators to disable the HOT bonus healing being split over duration and instead adds the full amount every tic.

* Update effects.cpp

* Update effects.cpp
2023-12-15 19:25:38 -06:00
Alex King aeeb350068 [Cleanup] Cleanup classes.cpp/classes.h (#3752)
* [Cleanup] Cleanup classes.cpp/classes.h

# Notes
- Remove unused methods and cleanup logic.

* Update classes.cpp

* Final push.
2023-12-13 18:38:45 -05:00
nytmyr df83113cea [Bots] Enable auto-saving of bots. (#3758)
Adds the rule **Bots, AutosaveIntervalSeconds** to control the frequency of the autosave of bots. Currently they only fully save on camp/zone.

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-12-12 22:22:44 -05:00
nytmyr 940abfaf7a [Logging] Change empty object loading to warning (#3759) 2023-12-11 17:06:29 -05:00
nytmyr a46443b95e [Bots] Add rule to toggle DT hitting owner (#3757)
**Bots, CazicTouchBotsOwner** is a rule that will toggle whether or not DT will hit the targeted bot or the owner. Similar to how **Spells, CazicTouchTargetsPetOwner** functions except for  bots.
2023-12-11 14:31:33 -05:00
90 changed files with 4092 additions and 2235 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ volumes:
steps: steps:
- name: Build Linux X64 - name: Build Linux X64
image: akkadius/eqemu-server:v13 image: akkadius/eqemu-server:v14
environment: environment:
GITHUB_TOKEN: GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN from_secret: GH_RELEASE_GITHUB_API_TOKEN
+69
View File
@@ -1,3 +1,72 @@
## [22.37.0] - 12/18/2023
### Bots
* Add ScanCloseMobs support to fix AEs ([#3786](https://github.com/EQEmu/Server/pull/3786)) @nytmyr 2023-12-18
* Expand ^itemuse options ([#3756](https://github.com/EQEmu/Server/pull/3756)) @nytmyr 2023-12-17
* Fix ^defensive from checking aggressive disciplines. ([#3787](https://github.com/EQEmu/Server/pull/3787)) @nytmyr 2023-12-18
* Fix ^oo autodefend from sending bots/pets to invalid haters ([#3772](https://github.com/EQEmu/Server/pull/3772)) @nytmyr 2023-12-16
* Fix unnecessary failed to save timer error ([#3788](https://github.com/EQEmu/Server/pull/3788)) @nytmyr 2023-12-18
* [Quest API] Add ^clickitem, ^timer, fix GetBestBotSpellForCure ([#3755](https://github.com/EQEmu/Server/pull/3755)) @nytmyr 2023-12-17
### CI
* Switch to use clang for Linux builds (speed) ([#3777](https://github.com/EQEmu/Server/pull/3777)) @Akkadius 2023-12-17
### Compilation
* Use pre-compiled headers for Windows (speed) ([#3778](https://github.com/EQEmu/Server/pull/3778)) @Akkadius 2023-12-18
### Fixes
* Drop Invisibility when hit by traps ([#3785](https://github.com/EQEmu/Server/pull/3785)) @Kinglykrab 2023-12-18
* Fix NPCs routing to 0.0, 0.0 on #summon ([#3780](https://github.com/EQEmu/Server/pull/3780)) @Kinglykrab 2023-12-18
* Fix bad merge @Akkadius 2023-12-17
* Fix issue with HOTBonusHealingSplitOverDuration Rule ([#3776](https://github.com/EQEmu/Server/pull/3776)) @Kinglykrab 2023-12-17
* Fixed the discrepacy with time using command #time and in quests. ([#3767](https://github.com/EQEmu/Server/pull/3767)) @regneq 2023-12-17
* Send Entity ID in Death Events to resolve #3721 ([#3779](https://github.com/EQEmu/Server/pull/3779)) @Kinglykrab 2023-12-18
### Quest API
* Add EVENT_ALT_CURRENCY_GAIN and EVENT_ALT_CURRENCY_LOSS to Perl/Lua ([#3734](https://github.com/EQEmu/Server/pull/3734)) @Kinglykrab 2023-12-17
* Add EVENT_CRYSTAL_GAIN and EVENT_CRYSTAL_LOSS to Perl/Lua ([#3735](https://github.com/EQEmu/Server/pull/3735)) @Kinglykrab 2023-12-17
* Add EVENT_LDON_POINTS_GAIN and EVENT_LDON_POINTS_LOSS to Perl/Lua ([#3742](https://github.com/EQEmu/Server/pull/3742)) @Kinglykrab 2023-12-17
* Add EVENT_LEVEL_UP and EVENT_LEVEL_DOWN to Bots ([#3750](https://github.com/EQEmu/Server/pull/3750)) @Kinglykrab 2023-12-17
* Add EVENT_LOOT_ADDED to Perl/Lua ([#3739](https://github.com/EQEmu/Server/pull/3739)) @Kinglykrab 2023-12-17
* Add GetNPCAggro() and SetNPCAggro() to Perl/Lua ([#3781](https://github.com/EQEmu/Server/pull/3781)) @Kinglykrab 2023-12-18
## [22.36.0] - 12/16/2023
### Bots
* Add rule to toggle DT hitting owner ([#3757](https://github.com/EQEmu/Server/pull/3757)) @nytmyr 2023-12-11
* Enable auto-saving of bots. ([#3758](https://github.com/EQEmu/Server/pull/3758)) @nytmyr 2023-12-13
### Code
* Cleanup classes.cpp/classes.h ([#3752](https://github.com/EQEmu/Server/pull/3752)) @Kinglykrab 2023-12-13
### Corpse
* Fix /corpse command regression from #3727 ([#3770](https://github.com/EQEmu/Server/pull/3770)) @Akkadius 2023-12-16
### Database
* Make it clearer to users that a database backup is occurring ([#3769](https://github.com/EQEmu/Server/pull/3769)) @Akkadius 2023-12-16
* When database version is greater than binary, we are up to date ([#3771](https://github.com/EQEmu/Server/pull/3771)) @Akkadius 2023-12-16
### Fixes
* Fix Starting Items SQL ([#3766](https://github.com/EQEmu/Server/pull/3766)) @Kinglykrab 2023-12-16
### Logging
* Change empty object loading to warning ([#3759](https://github.com/EQEmu/Server/pull/3759)) @nytmyr 2023-12-11
### Rules
* Add DOT and HOT Rules ([#3760](https://github.com/EQEmu/Server/pull/3760)) @Kinglykrab 2023-12-16
## [22.35.0] - 12/10/2023 ## [22.35.0] - 12/10/2023
### Bots ### Bots
+1
View File
@@ -17,6 +17,7 @@ SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF) SET(CMAKE_CXX_EXTENSIONS OFF)
OPTION(EQEMU_BUILD_STATIC "Build with static linking" OFF) OPTION(EQEMU_BUILD_STATIC "Build with static linking" OFF)
OPTION(EQEMU_BUILD_PCH "Build with precompiled headers (Windows)" ON)
IF (EQEMU_BUILD_STATIC) IF (EQEMU_BUILD_STATIC)
SET(BUILD_SHARED_LIBS OFF) SET(BUILD_SHARED_LIBS OFF)
+3
View File
@@ -792,5 +792,8 @@ IF (UNIX)
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0) SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0)
ENDIF (UNIX) ENDIF (UNIX)
IF (WIN32 AND EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/pch.h)
ENDIF()
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+289 -466
View File
File diff suppressed because it is too large Load Diff
+96 -93
View File
@@ -19,99 +19,106 @@
#define CLASSES_CH #define CLASSES_CH
#include "../common/types.h" #include "../common/types.h"
#include "../common/rulesys.h"
#include <string> #include <string>
#include <map>
#define NO_CLASS 0 namespace Class {
#define WARRIOR 1 constexpr uint8 None = 0;
#define CLERIC 2 constexpr uint8 Warrior = 1;
#define PALADIN 3 constexpr uint8 Cleric = 2;
#define RANGER 4 constexpr uint8 Paladin = 3;
#define SHADOWKNIGHT 5 constexpr uint8 Ranger = 4;
#define DRUID 6 constexpr uint8 ShadowKnight = 5;
#define MONK 7 constexpr uint8 Druid = 6;
#define BARD 8 constexpr uint8 Monk = 7;
#define ROGUE 9 constexpr uint8 Bard = 8;
#define SHAMAN 10 constexpr uint8 Rogue = 9;
#define NECROMANCER 11 constexpr uint8 Shaman = 10;
#define WIZARD 12 constexpr uint8 Necromancer = 11;
#define MAGICIAN 13 constexpr uint8 Wizard = 12;
#define ENCHANTER 14 constexpr uint8 Magician = 13;
#define BEASTLORD 15 constexpr uint8 Enchanter = 14;
#define BERSERKER 16 constexpr uint8 Beastlord = 15;
#define WARRIORGM 20 constexpr uint8 Berserker = 16;
#define CLERICGM 21 constexpr uint8 WarriorGM = 20;
#define PALADINGM 22 constexpr uint8 ClericGM = 21;
#define RANGERGM 23 constexpr uint8 PaladinGM = 22;
#define SHADOWKNIGHTGM 24 constexpr uint8 RangerGM = 23;
#define DRUIDGM 25 constexpr uint8 ShadowKnightGM = 24;
#define MONKGM 26 constexpr uint8 DruidGM = 25;
#define BARDGM 27 constexpr uint8 MonkGM = 26;
#define ROGUEGM 28 constexpr uint8 BardGM = 27;
#define SHAMANGM 29 constexpr uint8 RogueGM = 28;
#define NECROMANCERGM 30 constexpr uint8 ShamanGM = 29;
#define WIZARDGM 31 constexpr uint8 NecromancerGM = 30;
#define MAGICIANGM 32 constexpr uint8 WizardGM = 31;
#define ENCHANTERGM 33 constexpr uint8 MagicianGM = 32;
#define BEASTLORDGM 34 constexpr uint8 EnchanterGM = 33;
#define BERSERKERGM 35 constexpr uint8 BeastlordGM = 34;
#define BANKER 40 constexpr uint8 BerserkerGM = 35;
#define MERCHANT 41 constexpr uint8 Banker = 40;
#define DISCORD_MERCHANT 59 constexpr uint8 Merchant = 41;
#define ADVENTURE_RECRUITER 60 constexpr uint8 DiscordMerchant = 59;
#define ADVENTURE_MERCHANT 61 constexpr uint8 AdventureRecruiter = 60;
#define LDON_TREASURE 62 // objects you can use /open on first seen in LDONs, seen on Danvi's Corpse in Akheva constexpr uint8 AdventureMerchant = 61;
#define TRIBUTE_MASTER 63 constexpr uint8 LDoNTreasure = 62;
#define GUILD_TRIBUTE_MASTER 64 // not sure constexpr uint8 TributeMaster = 63;
#define GUILD_BANKER 66 constexpr uint8 GuildTributeMaster = 64;
#define NORRATHS_KEEPERS_MERCHANT 67 constexpr uint8 GuildBanker = 66;
#define DARK_REIGN_MERCHANT 68 constexpr uint8 NorrathsKeepersMerchant = 67;
#define FELLOWSHIP_MASTER 69 constexpr uint8 DarkReignMerchant = 68;
#define ALT_CURRENCY_MERCHANT 70 constexpr uint8 FellowshipMaster = 69;
#define MERCENARY_MASTER 71 constexpr uint8 AlternateCurrencyMerchant = 70;
constexpr uint8 MercenaryLiaison = 71;
constexpr uint8 PLAYER_CLASS_COUNT = 16;
constexpr uint16 ALL_CLASSES_BITMASK = 65535;
};
// player class values static std::map<uint8, uint16> player_class_bitmasks = {
#define PLAYER_CLASS_UNKNOWN 0 {Class::Warrior, 1},
#define PLAYER_CLASS_WARRIOR 1 {Class::Cleric, 2},
#define PLAYER_CLASS_CLERIC 2 {Class::Paladin, 4},
#define PLAYER_CLASS_PALADIN 3 {Class::Ranger, 8},
#define PLAYER_CLASS_RANGER 4 {Class::ShadowKnight, 16},
#define PLAYER_CLASS_SHADOWKNIGHT 5 {Class::Druid, 32},
#define PLAYER_CLASS_DRUID 6 {Class::Monk, 64},
#define PLAYER_CLASS_MONK 7 {Class::Bard, 128},
#define PLAYER_CLASS_BARD 8 {Class::Rogue, 256},
#define PLAYER_CLASS_ROGUE 9 {Class::Shaman, 512},
#define PLAYER_CLASS_SHAMAN 10 {Class::Necromancer, 1024},
#define PLAYER_CLASS_NECROMANCER 11 {Class::Wizard, 2048},
#define PLAYER_CLASS_WIZARD 12 {Class::Magician, 4096},
#define PLAYER_CLASS_MAGICIAN 13 {Class::Enchanter, 8192},
#define PLAYER_CLASS_ENCHANTER 14 {Class::Beastlord, 16384},
#define PLAYER_CLASS_BEASTLORD 15 {Class::Berserker, 32768},
#define PLAYER_CLASS_BERSERKER 16 };
#define PLAYER_CLASS_COUNT 16 static std::string shadow_knight_class_name = (
RuleB(World, UseOldShadowKnightClassExport) ?
"Shadowknight" :
"Shadow Knight"
);
static std::map<uint8, std::string> class_names = {
// player class bits {Class::Warrior, "Warrior"},
#define PLAYER_CLASS_UNKNOWN_BIT 0 {Class::Cleric, "Cleric"},
#define PLAYER_CLASS_WARRIOR_BIT 1 {Class::Paladin, "Paladin"},
#define PLAYER_CLASS_CLERIC_BIT 2 {Class::Ranger, "Ranger"},
#define PLAYER_CLASS_PALADIN_BIT 4 {Class::ShadowKnight, shadow_knight_class_name},
#define PLAYER_CLASS_RANGER_BIT 8 {Class::Druid, "Druid"},
#define PLAYER_CLASS_SHADOWKNIGHT_BIT 16 {Class::Monk, "Monk"},
#define PLAYER_CLASS_DRUID_BIT 32 {Class::Bard, "Bard"},
#define PLAYER_CLASS_MONK_BIT 64 {Class::Rogue, "Rogue"},
#define PLAYER_CLASS_BARD_BIT 128 {Class::Shaman, "Shaman"},
#define PLAYER_CLASS_ROGUE_BIT 256 {Class::Necromancer, "Necromancer"},
#define PLAYER_CLASS_SHAMAN_BIT 512 {Class::Wizard, "Wizard"},
#define PLAYER_CLASS_NECROMANCER_BIT 1024 {Class::Magician, "Magician"},
#define PLAYER_CLASS_WIZARD_BIT 2048 {Class::Enchanter, "Enchanter"},
#define PLAYER_CLASS_MAGICIAN_BIT 4096 {Class::Beastlord, "Beastlord"},
#define PLAYER_CLASS_ENCHANTER_BIT 8192 {Class::Berserker, "Berserker"},
#define PLAYER_CLASS_BEASTLORD_BIT 16384 };
#define PLAYER_CLASS_BERSERKER_BIT 32768
#define PLAYER_CLASS_ALL_MASK 65535 // was 65536
#define ARMOR_TYPE_UNKNOWN 0 #define ARMOR_TYPE_UNKNOWN 0
@@ -126,16 +133,12 @@
const char* GetClassIDName(uint8 class_id, uint8 level = 0); const char* GetClassIDName(uint8 class_id, uint8 level = 0);
const char* GetPlayerClassName(uint32 player_class_value, uint8 level = 0);
bool IsPlayerClass(uint8 class_id); bool IsPlayerClass(uint8 class_id);
const std::string GetPlayerClassAbbreviation(uint8 class_id); const std::string GetPlayerClassAbbreviation(uint8 class_id);
uint32 GetPlayerClassValue(uint8 class_id); uint8 GetPlayerClassValue(uint8 class_id);
uint32 GetPlayerClassBit(uint8 class_id); uint16 GetPlayerClassBit(uint8 class_id);
uint8 GetClassIDFromPlayerClassValue(uint32 player_class_value);
uint8 GetClassIDFromPlayerClassBit(uint32 player_class_bit);
bool IsFighterClass(uint8 class_id); bool IsFighterClass(uint8 class_id);
bool IsSpellFighterClass(uint8 class_id); bool IsSpellFighterClass(uint8 class_id);
@@ -322,6 +322,10 @@ void DatabaseDumpService::DatabaseDump()
pipe_file pipe_file
); );
LogInfo("Backing up database [{}]", execute_command);
LogInfo("This can take a few minutes depending on the size of your database");
LogInfo("LOADING... PLEASE WAIT...");
BuildCredentialsFile(); BuildCredentialsFile();
std::string execution_result = Process::execute(execute_command); std::string execution_result = Process::execute(execute_command);
if (!execution_result.empty() && IsDumpOutputToConsole()) { if (!execution_result.empty() && IsDumpOutputToConsole()) {
+2 -2
View File
@@ -274,9 +274,9 @@ bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH)); LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
// server database version is required // server database version is required
bool server_up_to_date = v.server_database_version == b.server_database_version; 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 // 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; 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; return server_up_to_date && bots_up_to_date;
} }
@@ -5116,6 +5116,23 @@ ALTER TABLE `object` CHANGE COLUMN `unknown20` `incline` int(11) NOT NULL DEFAUL
ALTER TABLE `keyring` ALTER TABLE `keyring`
ADD COLUMN `id` int UNSIGNED NOT NULL AUTO_INCREMENT FIRST, ADD COLUMN `id` int UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
ADD PRIMARY KEY (`id`); ADD PRIMARY KEY (`id`);
)"
},
ManifestEntry{
.version = 9247,
.description = "2023_12_14_starting_items_fix.sql",
.check = "SHOW COLUMNS FROM `starting_items` LIKE 'inventory_slot'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `starting_items`
CHANGE COLUMN `race_list` `temporary` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `id`,
CHANGE COLUMN `class_list` `race_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `temporary`,
CHANGE COLUMN `gm` `status` mediumint(3) NOT NULL DEFAULT 0 AFTER `item_charges`,
CHANGE COLUMN `slot` `inventory_slot` mediumint(9) NOT NULL DEFAULT -1 AFTER `status`;
ALTER TABLE `starting_items`
CHANGE COLUMN `temporary` `class_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `id`;
)" )"
} }
@@ -82,6 +82,28 @@ CREATE TABLE `bot_starting_items` (
`content_flags_disabled` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL, `content_flags_disabled` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci; ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci;
)",
},
ManifestEntry{
.version = 9041,
.description = "2023_12_04_bot_timers.sql",
.check = "SHOW COLUMNS FROM `bot_timers` LIKE 'recast_time'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `bot_timers`
ADD COLUMN `recast_time` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `timer_value`,
ADD COLUMN `is_spell` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `recast_time`,
ADD COLUMN `is_disc` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `is_spell`,
ADD COLUMN `spell_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `is_disc`,
ADD COLUMN `is_item` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `spell_id`,
ADD COLUMN `item_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `is_item`;
ALTER TABLE `bot_timers`
DROP FOREIGN KEY `FK_bot_timers_1`;
ALTER TABLE `bot_timers`
DROP PRIMARY KEY;
ALTER TABLE `bot_timers`
ADD PRIMARY KEY (`bot_id`, `timer_id`, `spell_id`, `item_id`);
)" )"
} }
// -- template; copy/paste this when you need to create a new entry // -- template; copy/paste this when you need to create a new entry
+6
View File
@@ -124,6 +124,12 @@ struct LDoNTrapTemplate
uint8 locked; uint8 locked;
}; };
enum CrystalReclaimTypes
{
Ebon = 5,
Radiant = 4,
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -132,7 +132,7 @@ namespace EQ
// Swap items in inventory // Swap items in inventory
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel }; 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 = RACE_DOUG_0, uint8 class_id = NO_CLASS, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0); bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = RACE_DOUG_0, uint8 class_id = Class::None, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0);
// Remove item from inventory // Remove item from inventory
bool DeleteItem(int16 slot_id, int16 quantity = 0); bool DeleteItem(int16 slot_id, int16 quantity = 0);
+3 -3
View File
@@ -3986,7 +3986,7 @@ namespace RoF2
if (strlen(emu->suffix)) if (strlen(emu->suffix))
PacketSize += strlen(emu->suffix) + 1; PacketSize += strlen(emu->suffix) + 1;
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE) if (emu->DestructibleObject || emu->class_ == Class::LDoNTreasure)
{ {
if (emu->DestructibleObject) if (emu->DestructibleObject)
PacketSize = PacketSize - 4; // No bodytype PacketSize = PacketSize - 4; // No bodytype
@@ -4076,7 +4076,7 @@ namespace RoF2
// actually part of bitfields // actually part of bitfields
uint8 OtherData = 0; uint8 OtherData = 0;
if (emu->class_ == LDON_TREASURE) //LDoN Chest if (emu->class_ == Class::LDoNTreasure) //LDoN Chest
{ {
OtherData = OtherData | 0x04; OtherData = OtherData | 0x04;
} }
@@ -4104,7 +4104,7 @@ namespace RoF2
// int DefaultEmitterID // int DefaultEmitterID
VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4 VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE) if (emu->DestructibleObject || emu->class_ == Class::LDoNTreasure)
{ {
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleModel); VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleModel);
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleName2); VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleName2);
+3 -3
View File
@@ -2758,7 +2758,7 @@ namespace UF
if (strlen(emu->suffix)) if (strlen(emu->suffix))
PacketSize += strlen(emu->suffix) + 1; PacketSize += strlen(emu->suffix) + 1;
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE) if (emu->DestructibleObject || emu->class_ == Class::LDoNTreasure)
{ {
if (emu->DestructibleObject) if (emu->DestructibleObject)
PacketSize = PacketSize - 4; // No bodytype PacketSize = PacketSize - 4; // No bodytype
@@ -2847,7 +2847,7 @@ namespace UF
uint8 OtherData = 0; uint8 OtherData = 0;
if (emu->class_ == LDON_TREASURE) //Ldon chest if (emu->class_ == Class::LDoNTreasure) //Ldon chest
{ {
OtherData = OtherData | 0x01; OtherData = OtherData | 0x01;
} }
@@ -2873,7 +2873,7 @@ namespace UF
} }
VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4 VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE) if (emu->DestructibleObject || emu->class_ == Class::LDoNTreasure)
{ {
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleModel); VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleModel);
VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleName2); VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleName2);
+34
View File
@@ -0,0 +1,34 @@
// types
#include <limits>
#include <string>
#include <cctype>
#include <sstream>
// containers
#include <iterator>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <list>
#include <vector>
// utilities
#include <iostream>
#include <cassert>
#include <cmath>
#include <memory>
#include <functional>
#include <algorithm>
#include <utility>
#include <tuple>
#include <fstream>
#include <cstdio>
// fmt
#include <fmt/format.h>
// lua
#include "lua.hpp"
#include <luabind/luabind.hpp>
#include <luabind/object.hpp>
@@ -16,12 +16,19 @@
#include "../../strings.h" #include "../../strings.h"
#include <ctime> #include <ctime>
class BaseBotTimersRepository { class BaseBotTimersRepository {
public: public:
struct BotTimers { struct BotTimers {
uint32_t bot_id; uint32_t bot_id;
uint32_t timer_id; uint32_t timer_id;
uint32_t timer_value; uint32_t timer_value;
uint32_t recast_time;
uint8_t is_spell;
uint8_t is_disc;
uint32_t spell_id;
uint8_t is_item;
uint32_t item_id;
}; };
static std::string PrimaryKey() static std::string PrimaryKey()
@@ -35,6 +42,12 @@ public:
"bot_id", "bot_id",
"timer_id", "timer_id",
"timer_value", "timer_value",
"recast_time",
"is_spell",
"is_disc",
"spell_id",
"is_item",
"item_id",
}; };
} }
@@ -44,6 +57,12 @@ public:
"bot_id", "bot_id",
"timer_id", "timer_id",
"timer_value", "timer_value",
"recast_time",
"is_spell",
"is_disc",
"spell_id",
"is_item",
"item_id",
}; };
} }
@@ -87,6 +106,12 @@ public:
e.bot_id = 0; e.bot_id = 0;
e.timer_id = 0; e.timer_id = 0;
e.timer_value = 0; e.timer_value = 0;
e.recast_time = 0;
e.is_spell = 0;
e.is_disc = 0;
e.spell_id = 0;
e.is_item = 0;
e.item_id = 0;
return e; return e;
} }
@@ -112,8 +137,9 @@ public:
{ {
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
"{} WHERE id = {} LIMIT 1", "{} WHERE {} = {} LIMIT 1",
BaseSelect(), BaseSelect(),
PrimaryKey(),
bot_timers_id bot_timers_id
) )
); );
@@ -125,6 +151,12 @@ public:
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10)); e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10)); e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10)); e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
return e; return e;
} }
@@ -161,6 +193,12 @@ public:
v.push_back(columns[0] + " = " + std::to_string(e.bot_id)); v.push_back(columns[0] + " = " + std::to_string(e.bot_id));
v.push_back(columns[1] + " = " + std::to_string(e.timer_id)); v.push_back(columns[1] + " = " + std::to_string(e.timer_id));
v.push_back(columns[2] + " = " + std::to_string(e.timer_value)); v.push_back(columns[2] + " = " + std::to_string(e.timer_value));
v.push_back(columns[3] + " = " + std::to_string(e.recast_time));
v.push_back(columns[4] + " = " + std::to_string(e.is_spell));
v.push_back(columns[5] + " = " + std::to_string(e.is_disc));
v.push_back(columns[6] + " = " + std::to_string(e.spell_id));
v.push_back(columns[7] + " = " + std::to_string(e.is_item));
v.push_back(columns[8] + " = " + std::to_string(e.item_id));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@@ -185,6 +223,12 @@ public:
v.push_back(std::to_string(e.bot_id)); v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.timer_id)); v.push_back(std::to_string(e.timer_id));
v.push_back(std::to_string(e.timer_value)); v.push_back(std::to_string(e.timer_value));
v.push_back(std::to_string(e.recast_time));
v.push_back(std::to_string(e.is_spell));
v.push_back(std::to_string(e.is_disc));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.is_item));
v.push_back(std::to_string(e.item_id));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@@ -217,6 +261,12 @@ public:
v.push_back(std::to_string(e.bot_id)); v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.timer_id)); v.push_back(std::to_string(e.timer_id));
v.push_back(std::to_string(e.timer_value)); v.push_back(std::to_string(e.timer_value));
v.push_back(std::to_string(e.recast_time));
v.push_back(std::to_string(e.is_spell));
v.push_back(std::to_string(e.is_disc));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.is_item));
v.push_back(std::to_string(e.item_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
} }
@@ -253,6 +303,12 @@ public:
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10)); e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10)); e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10)); e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
all_entries.push_back(e); all_entries.push_back(e);
} }
@@ -280,6 +336,12 @@ public:
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10)); e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10)); e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10)); e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
all_entries.push_back(e); all_entries.push_back(e);
} }
@@ -21,14 +21,14 @@ class BaseStartingItemsRepository {
public: public:
struct StartingItems { struct StartingItems {
uint32_t id; uint32_t id;
std::string race_list;
std::string class_list; std::string class_list;
std::string race_list;
std::string deity_list; std::string deity_list;
std::string zone_id_list; std::string zone_id_list;
uint32_t item_id; uint32_t item_id;
uint8_t item_charges; uint8_t item_charges;
uint8_t gm; int32_t status;
int32_t slot; int32_t inventory_slot;
int8_t min_expansion; int8_t min_expansion;
int8_t max_expansion; int8_t max_expansion;
std::string content_flags; std::string content_flags;
@@ -44,14 +44,14 @@ public:
{ {
return { return {
"id", "id",
"race_list",
"class_list", "class_list",
"race_list",
"deity_list", "deity_list",
"zone_id_list", "zone_id_list",
"item_id", "item_id",
"item_charges", "item_charges",
"gm", "status",
"slot", "inventory_slot",
"min_expansion", "min_expansion",
"max_expansion", "max_expansion",
"content_flags", "content_flags",
@@ -63,14 +63,14 @@ public:
{ {
return { return {
"id", "id",
"race_list",
"class_list", "class_list",
"race_list",
"deity_list", "deity_list",
"zone_id_list", "zone_id_list",
"item_id", "item_id",
"item_charges", "item_charges",
"gm", "status",
"slot", "inventory_slot",
"min_expansion", "min_expansion",
"max_expansion", "max_expansion",
"content_flags", "content_flags",
@@ -116,14 +116,14 @@ public:
StartingItems e{}; StartingItems e{};
e.id = 0; e.id = 0;
e.race_list = "";
e.class_list = ""; e.class_list = "";
e.race_list = "";
e.deity_list = ""; e.deity_list = "";
e.zone_id_list = ""; e.zone_id_list = "";
e.item_id = 0; e.item_id = 0;
e.item_charges = 1; e.item_charges = 1;
e.gm = 0; e.status = 0;
e.slot = -1; e.inventory_slot = -1;
e.min_expansion = -1; e.min_expansion = -1;
e.max_expansion = -1; e.max_expansion = -1;
e.content_flags = ""; e.content_flags = "";
@@ -165,14 +165,14 @@ public:
StartingItems e{}; StartingItems e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10)); e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.race_list = row[1] ? row[1] : ""; e.class_list = row[1] ? row[1] : "";
e.class_list = row[2] ? row[2] : ""; e.race_list = row[2] ? row[2] : "";
e.deity_list = row[3] ? row[3] : ""; e.deity_list = row[3] ? row[3] : "";
e.zone_id_list = row[4] ? row[4] : ""; e.zone_id_list = row[4] ? row[4] : "";
e.item_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10)); e.item_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10)); e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.gm = static_cast<uint8_t>(strtoul(row[7], nullptr, 10)); e.status = static_cast<int32_t>(atoi(row[7]));
e.slot = static_cast<int32_t>(atoi(row[8])); e.inventory_slot = static_cast<int32_t>(atoi(row[8]));
e.min_expansion = static_cast<int8_t>(atoi(row[9])); e.min_expansion = static_cast<int8_t>(atoi(row[9]));
e.max_expansion = static_cast<int8_t>(atoi(row[10])); e.max_expansion = static_cast<int8_t>(atoi(row[10]));
e.content_flags = row[11] ? row[11] : ""; e.content_flags = row[11] ? row[11] : "";
@@ -210,14 +210,14 @@ public:
auto columns = Columns(); auto columns = Columns();
v.push_back(columns[1] + " = '" + Strings::Escape(e.race_list) + "'"); v.push_back(columns[1] + " = '" + Strings::Escape(e.class_list) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.class_list) + "'"); v.push_back(columns[2] + " = '" + Strings::Escape(e.race_list) + "'");
v.push_back(columns[3] + " = '" + Strings::Escape(e.deity_list) + "'"); v.push_back(columns[3] + " = '" + Strings::Escape(e.deity_list) + "'");
v.push_back(columns[4] + " = '" + Strings::Escape(e.zone_id_list) + "'"); v.push_back(columns[4] + " = '" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(columns[5] + " = " + std::to_string(e.item_id)); v.push_back(columns[5] + " = " + std::to_string(e.item_id));
v.push_back(columns[6] + " = " + std::to_string(e.item_charges)); v.push_back(columns[6] + " = " + std::to_string(e.item_charges));
v.push_back(columns[7] + " = " + std::to_string(e.gm)); v.push_back(columns[7] + " = " + std::to_string(e.status));
v.push_back(columns[8] + " = " + std::to_string(e.slot)); v.push_back(columns[8] + " = " + std::to_string(e.inventory_slot));
v.push_back(columns[9] + " = " + std::to_string(e.min_expansion)); v.push_back(columns[9] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[10] + " = " + std::to_string(e.max_expansion)); v.push_back(columns[10] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[11] + " = '" + Strings::Escape(e.content_flags) + "'"); v.push_back(columns[11] + " = '" + Strings::Escape(e.content_flags) + "'");
@@ -244,14 +244,14 @@ public:
std::vector<std::string> v; std::vector<std::string> v;
v.push_back(std::to_string(e.id)); v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.race_list) + "'");
v.push_back("'" + Strings::Escape(e.class_list) + "'"); v.push_back("'" + Strings::Escape(e.class_list) + "'");
v.push_back("'" + Strings::Escape(e.race_list) + "'");
v.push_back("'" + Strings::Escape(e.deity_list) + "'"); v.push_back("'" + Strings::Escape(e.deity_list) + "'");
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'"); v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(std::to_string(e.item_id)); v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges)); v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.gm)); v.push_back(std::to_string(e.status));
v.push_back(std::to_string(e.slot)); v.push_back(std::to_string(e.inventory_slot));
v.push_back(std::to_string(e.min_expansion)); v.push_back(std::to_string(e.min_expansion));
v.push_back(std::to_string(e.max_expansion)); v.push_back(std::to_string(e.max_expansion));
v.push_back("'" + Strings::Escape(e.content_flags) + "'"); v.push_back("'" + Strings::Escape(e.content_flags) + "'");
@@ -286,14 +286,14 @@ public:
std::vector<std::string> v; std::vector<std::string> v;
v.push_back(std::to_string(e.id)); v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.race_list) + "'");
v.push_back("'" + Strings::Escape(e.class_list) + "'"); v.push_back("'" + Strings::Escape(e.class_list) + "'");
v.push_back("'" + Strings::Escape(e.race_list) + "'");
v.push_back("'" + Strings::Escape(e.deity_list) + "'"); v.push_back("'" + Strings::Escape(e.deity_list) + "'");
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'"); v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(std::to_string(e.item_id)); v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_charges)); v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.gm)); v.push_back(std::to_string(e.status));
v.push_back(std::to_string(e.slot)); v.push_back(std::to_string(e.inventory_slot));
v.push_back(std::to_string(e.min_expansion)); v.push_back(std::to_string(e.min_expansion));
v.push_back(std::to_string(e.max_expansion)); v.push_back(std::to_string(e.max_expansion));
v.push_back("'" + Strings::Escape(e.content_flags) + "'"); v.push_back("'" + Strings::Escape(e.content_flags) + "'");
@@ -332,14 +332,14 @@ public:
StartingItems e{}; StartingItems e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10)); e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.race_list = row[1] ? row[1] : ""; e.class_list = row[1] ? row[1] : "";
e.class_list = row[2] ? row[2] : ""; e.race_list = row[2] ? row[2] : "";
e.deity_list = row[3] ? row[3] : ""; e.deity_list = row[3] ? row[3] : "";
e.zone_id_list = row[4] ? row[4] : ""; e.zone_id_list = row[4] ? row[4] : "";
e.item_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10)); e.item_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10)); e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.gm = static_cast<uint8_t>(strtoul(row[7], nullptr, 10)); e.status = static_cast<int32_t>(atoi(row[7]));
e.slot = static_cast<int32_t>(atoi(row[8])); e.inventory_slot = static_cast<int32_t>(atoi(row[8]));
e.min_expansion = static_cast<int8_t>(atoi(row[9])); e.min_expansion = static_cast<int8_t>(atoi(row[9]));
e.max_expansion = static_cast<int8_t>(atoi(row[10])); e.max_expansion = static_cast<int8_t>(atoi(row[10]));
e.content_flags = row[11] ? row[11] : ""; e.content_flags = row[11] ? row[11] : "";
@@ -369,14 +369,14 @@ public:
StartingItems e{}; StartingItems e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10)); e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.race_list = row[1] ? row[1] : ""; e.class_list = row[1] ? row[1] : "";
e.class_list = row[2] ? row[2] : ""; e.race_list = row[2] ? row[2] : "";
e.deity_list = row[3] ? row[3] : ""; e.deity_list = row[3] ? row[3] : "";
e.zone_id_list = row[4] ? row[4] : ""; e.zone_id_list = row[4] ? row[4] : "";
e.item_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10)); e.item_id = static_cast<uint32_t>(strtoul(row[5], nullptr, 10));
e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10)); e.item_charges = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.gm = static_cast<uint8_t>(strtoul(row[7], nullptr, 10)); e.status = static_cast<int32_t>(atoi(row[7]));
e.slot = static_cast<int32_t>(atoi(row[8])); e.inventory_slot = static_cast<int32_t>(atoi(row[8]));
e.min_expansion = static_cast<int8_t>(atoi(row[9])); e.min_expansion = static_cast<int8_t>(atoi(row[9]));
e.max_expansion = static_cast<int8_t>(atoi(row[10])); e.max_expansion = static_cast<int8_t>(atoi(row[10]));
e.content_flags = row[11] ? row[11] : ""; e.content_flags = row[11] ? row[11] : "";
+8
View File
@@ -305,6 +305,7 @@ RULE_BOOL(World, EnableChecksumVerification, false, "Enable or Disable the Check
RULE_INT(World, MaximumQuestErrors, 30, "Changes the maximum number of quest errors that can be displayed in #questerrors, default is 30") RULE_INT(World, MaximumQuestErrors, 30, "Changes the maximum number of quest errors that can be displayed in #questerrors, default is 30")
RULE_INT(World, BootHour, 0, "Sets the in-game hour world will set when it first boots. 0-24 are valid options, where 0 disables this rule") RULE_INT(World, BootHour, 0, "Sets the in-game hour world will set when it first boots. 0-24 are valid options, where 0 disables this rule")
RULE_BOOL(World, UseItemLinksForKeyRing, false, "Uses item links for Key Ring Listing instead of item name") RULE_BOOL(World, UseItemLinksForKeyRing, false, "Uses item links for Key Ring Listing instead of item name")
RULE_BOOL(World, UseOldShadowKnightClassExport, true, "Disable to have Shadowknight show as Shadow Knight (live-like)")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Zone) RULE_CATEGORY(Zone)
@@ -458,6 +459,8 @@ RULE_INT(Spells, WizardCritMinimumRandomRatio, 20, "The minimum value for the ra
RULE_INT(Spells, WizardCritMaximumRandomRatio, 70, "The maximum value for the random range which Wizards and Caster DPS Mercs innately have for spell crit ratio. Set to 70 for vanilla values.") RULE_INT(Spells, WizardCritMaximumRandomRatio, 70, "The maximum value for the random range which Wizards and Caster DPS Mercs innately have for spell crit ratio. Set to 70 for vanilla values.")
RULE_INT(Spells, DefensiveProcPenaltyLevelGap, 6, "Defensive Proc Penalty Level Gap where procs start losing their proc rate at RuleR(Spells, DefensiveProcPenaltyModifier)% per level difference") RULE_INT(Spells, DefensiveProcPenaltyLevelGap, 6, "Defensive Proc Penalty Level Gap where procs start losing their proc rate at RuleR(Spells, DefensiveProcPenaltyModifier)% per level difference")
RULE_REAL(Spells, DefensiveProcPenaltyLevelGapModifier, 10.0f, "Defensive Proc Penalty Level Gap Modifier where procs start losing their proc rate at defined % after RuleI(Spells, DefensiveProcLevelGap) level difference") RULE_REAL(Spells, DefensiveProcPenaltyLevelGapModifier, 10.0f, "Defensive Proc Penalty Level Gap Modifier where procs start losing their proc rate at defined % after RuleI(Spells, DefensiveProcLevelGap) level difference")
RULE_BOOL(Spells, DOTBonusDamageSplitOverDuration, true, "Disable to have Damage Over Time total bonus damage added to each tick instead of divided across duration")
RULE_BOOL(Spells, HOTBonusHealingSplitOverDuration, true, "Disable to have Heal Over Time total bonus healing added to each tick instead of divided across duration")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Combat) RULE_CATEGORY(Combat)
@@ -651,6 +654,11 @@ RULE_INT(Bots, OldResurrectionSicknessSpell, 757, "757 is Default Old Resurrecti
RULE_INT(Bots, ResurrectionSicknessSpell, 756, "756 is Default Resurrection Sickness Spell") RULE_INT(Bots, ResurrectionSicknessSpell, 756, "756 is Default Resurrection Sickness Spell")
RULE_BOOL(Bots, AllowPickpocketCommand, true, "Allows the use of the bot command 'pickpocket'") RULE_BOOL(Bots, AllowPickpocketCommand, true, "Allows the use of the bot command 'pickpocket'")
RULE_BOOL(Bots, BotHealOnLevel, false, "Setting whether a bot should heal completely when leveling. Default FALSE.") RULE_BOOL(Bots, BotHealOnLevel, false, "Setting whether a bot should heal completely when leveling. Default FALSE.")
RULE_INT(Bots, AutosaveIntervalSeconds, 300, "Number of seconds after which a timer is triggered which stores the bot data. The value 0 means no periodic automatic saving.")
RULE_BOOL(Bots, CazicTouchBotsOwner, true, "Default True. Cazic Touch/DT will hit bot owner rather than bot.")
RULE_INT(Bots, BotsClickItemsMinLvl, 1, "Minimum level for bots to be able to use ^clickitem. Default 1.")
RULE_BOOL(Bots, BotsCanClickItems, true, "Enabled the ability for bots to click items they have equipped. Default TRUE")
RULE_BOOL(Bots, CanClickMageEpicV1, true, "Whether or not bots are allowed to click Mage Epic 1.0. Default TRUE")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Chat) RULE_CATEGORY(Chat)
+5 -5
View File
@@ -506,7 +506,7 @@ bool SharedDatabase::SetStartingItems(
for (const auto &e : v) { for (const auto &e : v) {
const uint32 item_id = e.item_id; const uint32 item_id = e.item_id;
const uint8 item_charges = e.item_charges; const uint8 item_charges = e.item_charges;
int32 slot = e.slot; int32 slot = e.inventory_slot;
item_data = GetItem(item_id); item_data = GetItem(item_id);
@@ -1808,7 +1808,7 @@ bool SharedDatabase::LoadSkillCaps(const std::string &prefix) {
} }
void SharedDatabase::LoadSkillCaps(void *data) { void SharedDatabase::LoadSkillCaps(void *data) {
const uint32 class_count = PLAYER_CLASS_COUNT; const uint32 class_count = Class::PLAYER_CLASS_COUNT;
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1; const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
const uint32 level_count = HARD_LEVEL_CAP + 1; const uint32 level_count = HARD_LEVEL_CAP + 1;
uint16 *skill_caps_table = static_cast<uint16*>(data); uint16 *skill_caps_table = static_cast<uint16*>(data);
@@ -1848,7 +1848,7 @@ uint16 SharedDatabase::GetSkillCap(uint8 Class_, EQ::skills::SkillType Skill, ui
SkillMaxLevel = RuleI(Character, MaxLevel); SkillMaxLevel = RuleI(Character, MaxLevel);
} }
const uint32 class_count = PLAYER_CLASS_COUNT; const uint32 class_count = Class::PLAYER_CLASS_COUNT;
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1; const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
const uint32 level_count = HARD_LEVEL_CAP + 1; const uint32 level_count = HARD_LEVEL_CAP + 1;
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) { if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
@@ -1878,7 +1878,7 @@ uint8 SharedDatabase::GetTrainLevel(uint8 Class_, EQ::skills::SkillType Skill, u
SkillMaxLevel = RuleI(Character, MaxLevel); SkillMaxLevel = RuleI(Character, MaxLevel);
} }
const uint32 class_count = PLAYER_CLASS_COUNT; const uint32 class_count = Class::PLAYER_CLASS_COUNT;
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1; const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
const uint32 level_count = HARD_LEVEL_CAP + 1; const uint32 level_count = HARD_LEVEL_CAP + 1;
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) { if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
@@ -2061,7 +2061,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].environment_type=Strings::ToInt(row[102]); sp[tempid].environment_type=Strings::ToInt(row[102]);
sp[tempid].time_of_day=Strings::ToInt(row[103]); sp[tempid].time_of_day=Strings::ToInt(row[103]);
for(y=0; y < PLAYER_CLASS_COUNT;y++) for(y=0; y < Class::PLAYER_CLASS_COUNT;y++)
sp[tempid].classes[y]=Strings::ToInt(row[104+y]); sp[tempid].classes[y]=Strings::ToInt(row[104+y]);
sp[tempid].casting_animation=Strings::ToInt(row[120]); sp[tempid].casting_animation=Strings::ToInt(row[120]);
+3 -3
View File
@@ -666,7 +666,7 @@ bool IsBardSong(uint16 spell_id)
const auto& spell = spells[spell_id]; const auto& spell = spells[spell_id];
if ( if (
spell.classes[BARD - 1] < UINT8_MAX && spell.classes[Class::Bard - 1] < UINT8_MAX &&
!spell.is_discipline !spell.is_discipline
) { ) {
return true; return true;
@@ -780,7 +780,7 @@ uint8 GetSpellMinimumLevel(uint16 spell_id)
const auto& spell = spells[spell_id]; const auto& spell = spells[spell_id];
for (int i = 0; i < PLAYER_CLASS_COUNT; i++) { for (int i = 0; i < Class::PLAYER_CLASS_COUNT; i++) {
if (spell.classes[i] < minimum_level) { if (spell.classes[i] < minimum_level) {
minimum_level = spell.classes[i]; minimum_level = spell.classes[i];
} }
@@ -798,7 +798,7 @@ uint8 GetSpellLevel(uint16 spell_id, uint8 class_id)
return UINT8_MAX; return UINT8_MAX;
} }
if (class_id >= PLAYER_CLASS_COUNT) { if (class_id >= Class::PLAYER_CLASS_COUNT) {
return UINT8_MAX; return UINT8_MAX;
} }
+1 -1
View File
@@ -1369,7 +1369,7 @@ struct SPDat_Spell_Struct
/* 101 */ int8 zone_type; // 01=Outdoors, 02=dungeons, ff=Any -- ZONETYPE /* 101 */ int8 zone_type; // 01=Outdoors, 02=dungeons, ff=Any -- ZONETYPE
/* 102 */ int8 environment_type; // -- ENVIRONMENTTYPE /* 102 */ int8 environment_type; // -- ENVIRONMENTTYPE
/* 103 */ int8 time_of_day; // -- TIMEOFDAY /* 103 */ int8 time_of_day; // -- TIMEOFDAY
/* 104 */ uint8 classes[PLAYER_CLASS_COUNT]; // Classes, and their min levels -- WARRIORMIN ... BERSERKERMIN /* 104 */ uint8 classes[Class::PLAYER_CLASS_COUNT]; // Classes, and their min levels -- WARRIORMIN ... BERSERKERMIN
/* 120 */ uint8 casting_animation; // -- CASTINGANIM /* 120 */ uint8 casting_animation; // -- CASTINGANIM
/* 121 */ //uint8 TargetAnim; // -- TARGETANIM /* 121 */ //uint8 TargetAnim; // -- TARGETANIM
/* 122 */ //uint32 TravelType; // -- TRAVELTYPE /* 122 */ //uint32 TravelType; // -- TRAVELTYPE
+3 -3
View File
@@ -25,7 +25,7 @@
// Build variables // Build variables
// these get injected during the build pipeline // these get injected during the build pipeline
#define CURRENT_VERSION "22.35.0-dev" // always append -dev to the current version for custom-builds #define CURRENT_VERSION "22.37.0-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0" #define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__ #define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__ #define COMPILE_TIME __TIME__
@@ -42,9 +42,9 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/ */
#define CURRENT_BINARY_DATABASE_VERSION 9246 #define CURRENT_BINARY_DATABASE_VERSION 9247
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9040 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041
#endif #endif
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "eqemu-server", "name": "eqemu-server",
"version": "22.35.0", "version": "22.37.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/EQEmu/Server.git" "url": "https://github.com/EQEmu/Server.git"
+1 -1
View File
@@ -29,7 +29,7 @@ void LoadSkillCaps(SharedDatabase *database, const std::string &prefix) {
EQ::IPCMutex mutex("skill_caps"); EQ::IPCMutex mutex("skill_caps");
mutex.Lock(); mutex.Lock();
uint32 class_count = PLAYER_CLASS_COUNT; uint32 class_count = Class::PLAYER_CLASS_COUNT;
uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1; uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
uint32 level_count = HARD_LEVEL_CAP + 1; uint32 level_count = HARD_LEVEL_CAP + 1;
uint32 size = (class_count * skill_count * level_count * sizeof(uint16)); uint32 size = (class_count * skill_count * level_count * sizeof(uint16));
+2 -2
View File
@@ -15,8 +15,8 @@ mkdir -p build && cd build && \
-DEQEMU_BUILD_LOGIN=ON \ -DEQEMU_BUILD_LOGIN=ON \
-DEQEMU_BUILD_LUA=ON \ -DEQEMU_BUILD_LUA=ON \
-DEQEMU_BUILD_PERL=ON \ -DEQEMU_BUILD_PERL=ON \
-DCMAKE_CXX_FLAGS:STRING="-O1 -g" \ -DCMAKE_CXX_FLAGS:STRING="-O1 -g -Wno-everything" \
-DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O1 -g" \ -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O1 -g -Wno-everything" \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-G 'Unix Makefiles' \ -G 'Unix Makefiles' \
.. && make -j$((`nproc`-4)) .. && make -j$((`nproc`-4))
+4
View File
@@ -78,6 +78,10 @@ ADD_EXECUTABLE(world ${world_sources} ${world_headers})
INSTALL(TARGETS world RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) INSTALL(TARGETS world RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
IF (WIN32 AND EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(world PRIVATE ../common/pch/pch.h)
ENDIF ()
ADD_DEFINITIONS(-DWORLD) ADD_DEFINITIONS(-DWORLD)
TARGET_LINK_LIBRARIES(world ${SERVER_LIBS}) TARGET_LINK_LIBRARIES(world ${SERVER_LIBS})
+5 -5
View File
@@ -1966,7 +1966,7 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc)
{ /*Drakkin*/ 70, 80, 85, 75, 80, 85, 75} { /*Drakkin*/ 70, 80, 85, 75, 80, 85, 75}
}; };
static const int BaseClass[PLAYER_CLASS_COUNT][8] = static const int BaseClass[Class::PLAYER_CLASS_COUNT][8] =
{ /* STR STA AGI DEX WIS INT CHR ADD*/ { /* STR STA AGI DEX WIS INT CHR ADD*/
{ /*Warrior*/ 10, 10, 5, 0, 0, 0, 0, 25}, { /*Warrior*/ 10, 10, 5, 0, 0, 0, 0, 25},
{ /*Cleric*/ 5, 5, 0, 0, 10, 0, 0, 30}, { /*Cleric*/ 5, 5, 0, 0, 10, 0, 0, 30},
@@ -1986,7 +1986,7 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc)
{ /*Berserker*/ 10, 5, 0, 10, 0, 0, 0, 25} { /*Berserker*/ 10, 5, 0, 10, 0, 0, 0, 25}
}; };
static const bool ClassRaceLookupTable[PLAYER_CLASS_COUNT][_TABLE_RACES]= static const bool ClassRaceLookupTable[Class::PLAYER_CLASS_COUNT][_TABLE_RACES]=
{ /*Human Barbarian Erudite Woodelf Highelf Darkelf Halfelf Dwarf Troll Ogre Halfling Gnome Iksar Vahshir Froglok Drakkin*/ { /*Human Barbarian Erudite Woodelf Highelf Darkelf Halfelf Dwarf Troll Ogre Halfling Gnome Iksar Vahshir Froglok Drakkin*/
{ /*Warrior*/ true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true}, { /*Warrior*/ true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true},
{ /*Cleric*/ true, false, true, false, true, true, true, true, false, false, true, true, false, false, true, true}, { /*Cleric*/ true, false, true, false, true, true, true, true, false, false, true, true, false, false, true, true},
@@ -2021,7 +2021,7 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc)
// if out of range looking it up in the table would crash stuff // if out of range looking it up in the table would crash stuff
// so we return from these // so we return from these
if (classtemp >= PLAYER_CLASS_COUNT) { if (classtemp >= Class::PLAYER_CLASS_COUNT) {
LogInfo(" class is out of range"); LogInfo(" class is out of range");
return false; return false;
} }
@@ -2114,7 +2114,7 @@ void Client::SetClassStartingSkills(PlayerProfile_Struct *pp)
} }
} }
if (cle->GetClientVersion() < static_cast<uint8>(EQ::versions::ClientVersion::RoF2) && pp->class_ == BERSERKER) { if (cle->GetClientVersion() < static_cast<uint8>(EQ::versions::ClientVersion::RoF2) && pp->class_ == Class::Berserker) {
pp->skills[EQ::skills::Skill1HPiercing] = pp->skills[EQ::skills::Skill2HPiercing]; pp->skills[EQ::skills::Skill1HPiercing] = pp->skills[EQ::skills::Skill2HPiercing];
pp->skills[EQ::skills::Skill2HPiercing] = 0; pp->skills[EQ::skills::Skill2HPiercing] = 0;
} }
@@ -2299,7 +2299,7 @@ void Client::SetClassLanguages(PlayerProfile_Struct *pp)
{ {
// we only need to handle one class, but custom server might want to do more // we only need to handle one class, but custom server might want to do more
switch(pp->class_) { switch(pp->class_) {
case ROGUE: case Class::Rogue:
pp->languages[LANG_THIEVES_CANT] = 100; pp->languages[LANG_THIEVES_CANT] = 100;
break; break;
default: default:
+2 -2
View File
@@ -33,7 +33,7 @@ GroupLFP::GroupLFP(uint32 inLeaderID) {
LeaderID = inLeaderID; LeaderID = inLeaderID;
for (auto &member : Members) { for (auto &member : Members) {
member.Name[0] = '\0'; member.Name[0] = '\0';
member.Class = NO_CLASS; member.Class = Class::None;
member.Level = 0; member.Level = 0;
member.Zone = 0; member.Zone = 0;
} }
@@ -77,7 +77,7 @@ void GroupLFP::SetDetails(ServerLFPUpdate_Struct *Update) {
Members[i].GuildID = CLE->GuildID(); Members[i].GuildID = CLE->GuildID();
} }
else { else {
Members[i].Class = NO_CLASS; Members[i].Class = Class::None;
Members[i].Level = 0; Members[i].Level = 0;
Members[i].Zone = 0; Members[i].Zone = 0;
Members[i].GuildID = 0xFFFF; Members[i].GuildID = 0xFFFF;
+1 -1
View File
@@ -434,7 +434,7 @@ int main(int argc, char **argv)
tod.year, tod.year,
tod.month, tod.month,
tod.day, tod.day,
tod.hour, tod.hour - 1,
tod.minute tod.minute
); );
} }
+6
View File
@@ -284,6 +284,12 @@ ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers})
INSTALL(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) INSTALL(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
IF (WIN32 AND EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/pch/pch.h)
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/types.h ../common/eqemu_logsys.h ../common/eqemu_logsys_log_aliases.h ../common/features.h ../common/global_define.h)
TARGET_PRECOMPILE_HEADERS(zone PRIVATE mob.h npc.h corpse.h doors.h bot.h entity.h client.h zone.h)
ENDIF()
ADD_DEFINITIONS(-DZONE) ADD_DEFINITIONS(-DZONE)
TARGET_LINK_LIBRARIES(zone ${ZONE_LIBS}) TARGET_LINK_LIBRARIES(zone ${ZONE_LIBS})
+17 -17
View File
@@ -373,72 +373,72 @@ void Mob::WakeTheDead(uint16 spell_id, Corpse *corpse_to_use, Mob *tar, uint32 d
//some basic combat mods here too since it's convienent //some basic combat mods here too since it's convienent
switch (corpse_to_use->class_) switch (corpse_to_use->class_)
{ {
case CLERIC: case Class::Cleric:
made_npc->npc_spells_id = 1; made_npc->npc_spells_id = 1;
break; break;
case WIZARD: case Class::Wizard:
made_npc->npc_spells_id = 2; made_npc->npc_spells_id = 2;
break; break;
case NECROMANCER: case Class::Necromancer:
made_npc->npc_spells_id = 3; made_npc->npc_spells_id = 3;
break; break;
case MAGICIAN: case Class::Magician:
made_npc->npc_spells_id = 4; made_npc->npc_spells_id = 4;
break; break;
case ENCHANTER: case Class::Enchanter:
made_npc->npc_spells_id = 5; made_npc->npc_spells_id = 5;
break; break;
case SHAMAN: case Class::Shaman:
made_npc->npc_spells_id = 6; made_npc->npc_spells_id = 6;
break; break;
case DRUID: case Class::Druid:
made_npc->npc_spells_id = 7; made_npc->npc_spells_id = 7;
break; break;
case PALADIN: case Class::Paladin:
//SPECATK_TRIPLE //SPECATK_TRIPLE
strcpy(made_npc->special_abilities, "6,1"); strcpy(made_npc->special_abilities, "6,1");
made_npc->current_hp = made_npc->current_hp * 150 / 100; made_npc->current_hp = made_npc->current_hp * 150 / 100;
made_npc->max_hp = made_npc->max_hp * 150 / 100; made_npc->max_hp = made_npc->max_hp * 150 / 100;
made_npc->npc_spells_id = 8; made_npc->npc_spells_id = 8;
break; break;
case SHADOWKNIGHT: case Class::ShadowKnight:
strcpy(made_npc->special_abilities, "6,1"); strcpy(made_npc->special_abilities, "6,1");
made_npc->current_hp = made_npc->current_hp * 150 / 100; made_npc->current_hp = made_npc->current_hp * 150 / 100;
made_npc->max_hp = made_npc->max_hp * 150 / 100; made_npc->max_hp = made_npc->max_hp * 150 / 100;
made_npc->npc_spells_id = 9; made_npc->npc_spells_id = 9;
break; break;
case RANGER: case Class::Ranger:
strcpy(made_npc->special_abilities, "7,1"); strcpy(made_npc->special_abilities, "7,1");
made_npc->current_hp = made_npc->current_hp * 135 / 100; made_npc->current_hp = made_npc->current_hp * 135 / 100;
made_npc->max_hp = made_npc->max_hp * 135 / 100; made_npc->max_hp = made_npc->max_hp * 135 / 100;
made_npc->npc_spells_id = 10; made_npc->npc_spells_id = 10;
break; break;
case BARD: case Class::Bard:
strcpy(made_npc->special_abilities, "6,1"); strcpy(made_npc->special_abilities, "6,1");
made_npc->current_hp = made_npc->current_hp * 110 / 100; made_npc->current_hp = made_npc->current_hp * 110 / 100;
made_npc->max_hp = made_npc->max_hp * 110 / 100; made_npc->max_hp = made_npc->max_hp * 110 / 100;
made_npc->npc_spells_id = 11; made_npc->npc_spells_id = 11;
break; break;
case BEASTLORD: case Class::Beastlord:
strcpy(made_npc->special_abilities, "7,1"); strcpy(made_npc->special_abilities, "7,1");
made_npc->current_hp = made_npc->current_hp * 110 / 100; made_npc->current_hp = made_npc->current_hp * 110 / 100;
made_npc->max_hp = made_npc->max_hp * 110 / 100; made_npc->max_hp = made_npc->max_hp * 110 / 100;
made_npc->npc_spells_id = 12; made_npc->npc_spells_id = 12;
break; break;
case ROGUE: case Class::Rogue:
strcpy(made_npc->special_abilities, "7,1"); strcpy(made_npc->special_abilities, "7,1");
made_npc->max_dmg = made_npc->max_dmg * 150 / 100; made_npc->max_dmg = made_npc->max_dmg * 150 / 100;
made_npc->current_hp = made_npc->current_hp * 110 / 100; made_npc->current_hp = made_npc->current_hp * 110 / 100;
made_npc->max_hp = made_npc->max_hp * 110 / 100; made_npc->max_hp = made_npc->max_hp * 110 / 100;
break; break;
case MONK: case Class::Monk:
strcpy(made_npc->special_abilities, "7,1"); strcpy(made_npc->special_abilities, "7,1");
made_npc->max_dmg = made_npc->max_dmg * 150 / 100; made_npc->max_dmg = made_npc->max_dmg * 150 / 100;
made_npc->current_hp = made_npc->current_hp * 135 / 100; made_npc->current_hp = made_npc->current_hp * 135 / 100;
made_npc->max_hp = made_npc->max_hp * 135 / 100; made_npc->max_hp = made_npc->max_hp * 135 / 100;
break; break;
case WARRIOR: case Class::Warrior:
case BERSERKER: case Class::Berserker:
strcpy(made_npc->special_abilities, "7,1"); strcpy(made_npc->special_abilities, "7,1");
made_npc->max_dmg = made_npc->max_dmg * 150 / 100; made_npc->max_dmg = made_npc->max_dmg * 150 / 100;
made_npc->current_hp = made_npc->current_hp * 175 / 100; made_npc->current_hp = made_npc->current_hp * 175 / 100;
@@ -1354,7 +1354,7 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
} }
else { else {
// Bards can cast instant cast AAs while they are casting or channeling item cast. // Bards can cast instant cast AAs while they are casting or channeling item cast.
if (GetClass() == BARD && IsCasting() && spells[rank->spell].cast_time == 0) { if (GetClass() == Class::Bard && IsCasting() && spells[rank->spell].cast_time == 0) {
if (!DoCastingChecksOnCaster(rank->spell, EQ::spells::CastingSlot::AltAbility)) { if (!DoCastingChecksOnCaster(rank->spell, EQ::spells::CastingSlot::AltAbility)) {
return; return;
} }
+2 -2
View File
@@ -46,7 +46,7 @@ void EntityList::DescribeAggro(Client *to_who, NPC *from_who, float d, bool verb
); );
bool is_engaged = from_who->IsEngaged(); bool is_engaged = from_who->IsEngaged();
bool will_aggro_npcs = from_who->WillAggroNPCs(); bool will_aggro_npcs = from_who->GetNPCAggro();
if (is_engaged) { if (is_engaged) {
Mob *top = from_who->GetHateTop(); Mob *top = from_who->GetHateTop();
to_who->Message( to_who->Message(
@@ -678,7 +678,7 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
if(!isSpellAttack) if(!isSpellAttack)
{ {
if(GetClass() == LDON_TREASURE) if(GetClass() == Class::LDoNTreasure)
{ {
return false; return false;
} }
+1 -1
View File
@@ -245,7 +245,7 @@ Json::Value ApiGetNpcListDetail(EQ::Net::WebsocketServerConnection *connection,
row["swarm_owner"] = npc->GetSwarmOwner(); row["swarm_owner"] = npc->GetSwarmOwner();
row["swarm_target"] = npc->GetSwarmTarget(); row["swarm_target"] = npc->GetSwarmTarget();
row["waypoint_max"] = npc->GetWaypointMax(); row["waypoint_max"] = npc->GetWaypointMax();
row["will_aggro_npcs"] = npc->WillAggroNPCs(); row["npc_aggro"] = npc->GetNPCAggro();
response.append(row); response.append(row);
} }
+161 -161
View File
@@ -558,7 +558,7 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
} }
// dodge // dodge
if (CanThisClassDodge() && (InFront || GetClass() == MONK)) { if (CanThisClassDodge() && (InFront || GetClass() == Class::Monk)) {
if (IsClient()) if (IsClient())
CastToClient()->CheckIncreaseSkill(EQ::skills::SkillDodge, other, -10); CastToClient()->CheckIncreaseSkill(EQ::skills::SkillDodge, other, -10);
// check auto discs ... I guess aa/items too :P // check auto discs ... I guess aa/items too :P
@@ -674,28 +674,28 @@ int Mob::GetACSoftcap()
int level = std::min(105, static_cast<int>(GetLevel())) - 1; int level = std::min(105, static_cast<int>(GetLevel())) - 1;
switch (GetClass()) { switch (GetClass()) {
case WARRIOR: case Class::Warrior:
return war_softcaps[level]; return war_softcaps[level];
case CLERIC: case Class::Cleric:
case BARD: case Class::Bard:
case MONK: case Class::Monk:
return clrbrdmnk_softcaps[level]; return clrbrdmnk_softcaps[level];
case PALADIN: case Class::Paladin:
case SHADOWKNIGHT: case Class::ShadowKnight:
return palshd_softcaps[level]; return palshd_softcaps[level];
case RANGER: case Class::Ranger:
return rng_softcaps[level]; return rng_softcaps[level];
case DRUID: case Class::Druid:
return dru_softcaps[level]; return dru_softcaps[level];
case ROGUE: case Class::Rogue:
case SHAMAN: case Class::Shaman:
case BEASTLORD: case Class::Beastlord:
case BERSERKER: case Class::Berserker:
return rogshmbstber_softcaps[level]; return rogshmbstber_softcaps[level];
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
return necwizmagenc_softcaps[level]; return necwizmagenc_softcaps[level];
default: default:
return 350; return 350;
@@ -707,28 +707,28 @@ double Mob::GetSoftcapReturns()
// These are based on the dev post, they seem to be correct for every level // These are based on the dev post, they seem to be correct for every level
// AKA no more hard caps // AKA no more hard caps
switch (GetClass()) { switch (GetClass()) {
case WARRIOR: case Class::Warrior:
return 0.35; return 0.35;
case CLERIC: case Class::Cleric:
case BARD: case Class::Bard:
case MONK: case Class::Monk:
return 0.3; return 0.3;
case PALADIN: case Class::Paladin:
case SHADOWKNIGHT: case Class::ShadowKnight:
return 0.33; return 0.33;
case RANGER: case Class::Ranger:
return 0.315; return 0.315;
case DRUID: case Class::Druid:
return 0.265; return 0.265;
case ROGUE: case Class::Rogue:
case SHAMAN: case Class::Shaman:
case BEASTLORD: case Class::Beastlord:
case BERSERKER: case Class::Berserker:
return 0.28; return 0.28;
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
return 0.25; return 0.25;
default: default:
return 0.3; return 0.3;
@@ -739,7 +739,7 @@ int Mob::GetClassRaceACBonus()
{ {
int ac_bonus = 0; int ac_bonus = 0;
auto level = GetLevel(); auto level = GetLevel();
if (GetClass() == MONK) { if (GetClass() == Class::Monk) {
int hardcap = 30; int hardcap = 30;
int softcap = 14; int softcap = 14;
if (level > 99) { if (level > 99) {
@@ -824,7 +824,7 @@ int Mob::GetClassRaceACBonus()
} }
} }
if (GetClass() == ROGUE) { if (GetClass() == Class::Rogue) {
int level_scaler = level - 26; int level_scaler = level - 26;
if (GetAGI() < 80) if (GetAGI() < 80)
ac_bonus = level_scaler / 4; ac_bonus = level_scaler / 4;
@@ -840,7 +840,7 @@ int Mob::GetClassRaceACBonus()
ac_bonus = 12; ac_bonus = 12;
} }
if (GetClass() == BEASTLORD) { if (GetClass() == Class::Beastlord) {
int level_scaler = level - 6; int level_scaler = level - 6;
if (GetAGI() < 80) if (GetAGI() < 80)
ac_bonus = level_scaler / 5; ac_bonus = level_scaler / 5;
@@ -894,14 +894,14 @@ int Mob::ACSum(bool skip_caps)
ac += GetPetACBonusFromOwner(); ac += GetPetACBonusFromOwner();
auto spell_aa_ac = aabonuses.AC + spellbonuses.AC; auto spell_aa_ac = aabonuses.AC + spellbonuses.AC;
ac += GetSkill(EQ::skills::SkillDefense) / 5; ac += GetSkill(EQ::skills::SkillDefense) / 5;
if (EQ::ValueWithin(static_cast<int>(GetClass()), NECROMANCER, ENCHANTER)) if (EQ::ValueWithin(static_cast<int>(GetClass()), Class::Necromancer, Class::Enchanter))
ac += spell_aa_ac / 3; ac += spell_aa_ac / 3;
else else
ac += spell_aa_ac / 4; ac += spell_aa_ac / 4;
} }
else { // TODO: so we can't set NPC skills ... so the skill bonus ends up being HUGE so lets nerf them a bit else { // TODO: so we can't set NPC skills ... so the skill bonus ends up being HUGE so lets nerf them a bit
auto spell_aa_ac = aabonuses.AC + spellbonuses.AC; auto spell_aa_ac = aabonuses.AC + spellbonuses.AC;
if (EQ::ValueWithin(static_cast<int>(GetClass()), NECROMANCER, ENCHANTER)) if (EQ::ValueWithin(static_cast<int>(GetClass()), Class::Necromancer, Class::Enchanter))
ac += GetSkill(EQ::skills::SkillDefense) / 2 + spell_aa_ac / 3; ac += GetSkill(EQ::skills::SkillDefense) / 2 + spell_aa_ac / 3;
else else
ac += GetSkill(EQ::skills::SkillDefense) / 3 + spell_aa_ac / 4; ac += GetSkill(EQ::skills::SkillDefense) / 3 + spell_aa_ac / 4;
@@ -1085,7 +1085,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemData *weapon_item) {
return 0; return 0;
} }
} }
else if ((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30) { else if ((GetClass() == Class::Monk || GetClass() == Class::Beastlord) && GetLevel() >= 30) {
dmg = GetHandToHandDamage(); dmg = GetHandToHandDamage();
} }
else { else {
@@ -1199,7 +1199,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in
MagicGloves = gloves->GetItemMagical(true); MagicGloves = gloves->GetItemMagical(true);
} }
if (GetClass() == MONK || GetClass() == BEASTLORD) { if (GetClass() == Class::Monk || GetClass() == Class::Beastlord) {
if (MagicGloves || GetLevel() >= 30) { if (MagicGloves || GetLevel() >= 30) {
dmg = GetHandToHandDamage(); dmg = GetHandToHandDamage();
if (hate) if (hate)
@@ -1295,15 +1295,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
} }
else if (level >= 40) { else if (level >= 40) {
switch (GetClass()) { switch (GetClass()) {
case CLERIC: case Class::Cleric:
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
cap = 80; cap = 80;
break; break;
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
cap = 40; cap = 40;
break; break;
default: default:
@@ -1313,15 +1313,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
} }
else if (level >= 30) { else if (level >= 30) {
switch (GetClass()) { switch (GetClass()) {
case CLERIC: case Class::Cleric:
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
cap = 26; cap = 26;
break; break;
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
cap = 18; cap = 18;
break; break;
default: default:
@@ -1331,15 +1331,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
} }
else if (level >= 20) { else if (level >= 20) {
switch (GetClass()) { switch (GetClass()) {
case CLERIC: case Class::Cleric:
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
cap = 20; cap = 20;
break; break;
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
cap = 12; cap = 12;
break; break;
default: default:
@@ -1349,15 +1349,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
} }
else if (level >= 10) { else if (level >= 10) {
switch (GetClass()) { switch (GetClass()) {
case CLERIC: case Class::Cleric:
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
cap = 12; cap = 12;
break; break;
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
cap = 10; cap = 10;
break; break;
default: default:
@@ -1367,15 +1367,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
} }
else { else {
switch (GetClass()) { switch (GetClass()) {
case CLERIC: case Class::Cleric:
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
cap = 9; cap = 9;
break; break;
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
cap = 6; cap = 6;
break; break;
default: default:
@@ -1476,7 +1476,7 @@ bool Mob::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
LogCombatDetail("Attacking [{}] with hand [{}] [{}]", other->GetName(), Hand, bRiposte ? "this is a riposte" : ""); LogCombatDetail("Attacking [{}] with hand [{}] [{}]", other->GetName(), Hand, bRiposte ? "this is a riposte" : "");
if ( if (
(IsCasting() && GetClass() != BARD && !IsFromSpell) (IsCasting() && GetClass() != Class::Bard && !IsFromSpell)
|| ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) || ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead))
|| (GetHP() < 0) || (GetHP() < 0)
|| (!IsAttackAllowed(other)) || (!IsAttackAllowed(other))
@@ -2019,7 +2019,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
/* /*
Reset reuse timer for classic skill based Lay on Hands (For tit I guess) Reset reuse timer for classic skill based Lay on Hands (For tit I guess)
*/ */
if (GetClass() == PALADIN) { // we could check if it's not expired I guess, but should be fine not to if (GetClass() == Class::Paladin) { // we could check if it's not expired I guess, but should be fine not to
p_timers.Clear(&database, pTimerLayHands); p_timers.Clear(&database, pTimerLayHands);
} }
@@ -2343,7 +2343,7 @@ void NPC::Damage(Mob* other, int64 damage, uint16 spell_id, EQ::skills::SkillTyp
if (!IsEngaged()) if (!IsEngaged())
zone->AddAggroMob(); zone->AddAggroMob();
if (GetClass() == LDON_TREASURE) if (GetClass() == Class::LDoNTreasure)
{ {
if (IsLDoNLocked() && GetLDoNLockedSkill() != LDoNTypeMechanical) if (IsLDoNLocked() && GetLDoNLockedSkill() != LDoNTypeMechanical)
{ {
@@ -2461,7 +2461,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
BuffFadeAll(); BuffFadeAll();
const auto killed_level = GetLevel(); const auto killed_level = GetLevel();
if (GetClass() == LDON_TREASURE) { // open chest if (GetClass() == Class::LDoNTreasure) { // open chest
auto outapp = new EQApplicationPacket(OP_Animation, sizeof(Animation_Struct)); auto outapp = new EQApplicationPacket(OP_Animation, sizeof(Animation_Struct));
Animation_Struct* anim = (Animation_Struct*)outapp->pBuffer; Animation_Struct* anim = (Animation_Struct*)outapp->pBuffer;
anim->spawnid = GetID(); anim->spawnid = GetID();
@@ -2488,7 +2488,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
respawn2->DeathReset(1); respawn2->DeathReset(1);
} }
if (killer_mob && GetClass() != LDON_TREASURE) { if (killer_mob && GetClass() != Class::LDoNTreasure) {
hate_list.AddEntToHateList(killer_mob, damage); hate_list.AddEntToHateList(killer_mob, damage);
} }
@@ -2535,7 +2535,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
hate_list.DoFactionHits(GetNPCFactionID(), GetPrimaryFaction(), GetFactionAmount()); hate_list.DoFactionHits(GetNPCFactionID(), GetPrimaryFaction(), GetFactionAmount());
} }
bool IsLdonTreasure = (GetClass() == LDON_TREASURE); bool IsLdonTreasure = (GetClass() == Class::LDoNTreasure);
if (give_exp_client && !IsCorpse()) { if (give_exp_client && !IsCorpse()) {
Group *kg = entity_list.GetGroupByClient(give_exp_client); Group *kg = entity_list.GetGroupByClient(give_exp_client);
@@ -2701,10 +2701,73 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
} }
bool allow_merchant_corpse = RuleB(Merchant, AllowCorpse); bool allow_merchant_corpse = RuleB(Merchant, AllowCorpse);
bool is_merchant = (class_ == MERCHANT || class_ == ADVENTURE_MERCHANT || MerchantType != 0); bool is_merchant = (class_ == Class::Merchant || class_ == Class::AdventureMerchant || MerchantType != 0);
Corpse* corpse = nullptr; Corpse* corpse = nullptr;
// Parse quests even if we're killed by an NPC
if (oos) {
if (IsNPC()) {
auto emote_id = GetEmoteID();
if (emote_id) {
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid);
}
}
if (oos->IsNPC()) {
if (parse->HasQuestSub(oos->GetNPCTypeID(), EVENT_NPC_SLAY)) {
parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0);
}
auto emote_id = oos->GetEmoteID();
if (emote_id) {
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id);
}
if (killer_mob) {
killer_mob->TrySpellOnKill(killed_level, spell);
}
}
}
if (killer_mob && killer_mob->IsBot()) {
if (parse->BotHasQuestSub(EVENT_NPC_SLAY)) {
parse->EventBot(EVENT_NPC_SLAY, killer_mob->CastToBot(), this, "", 0);
}
killer_mob->TrySpellOnKill(killed_level, spell);
}
m_combat_record.Stop();
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_DEATH_COMPLETE)) {
const auto& export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { corpse };
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0, &args);
}
/* Zone controller process EVENT_DEATH_ZONE (Death events) */
if (parse->HasQuestSub(ZONE_CONTROLLER_NPC_ID, EVENT_DEATH_ZONE)) {
const auto& export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { corpse, this };
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, oos, export_string, 0, &args);
}
if (!HasOwner() && !IsMerc() && !GetSwarmInfo() && (!is_merchant || allow_merchant_corpse) && if (!HasOwner() && !IsMerc() && !GetSwarmInfo() && (!is_merchant || allow_merchant_corpse) &&
((killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) || ((killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) ||
(killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient()))) (killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient())))
@@ -2814,38 +2877,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
entity_list.RemoveFromXTargets(this); entity_list.RemoveFromXTargets(this);
} }
// Parse quests even if we're killed by an NPC
if (oos) {
if (IsNPC()) {
auto emote_id = GetEmoteID();
if (emote_id) {
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid);
}
}
if (oos->IsNPC()) {
if (parse->HasQuestSub(oos->GetNPCTypeID(), EVENT_NPC_SLAY)) {
parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0);
}
auto emote_id = oos->GetEmoteID();
if (emote_id) {
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id);
}
if (killer_mob) {
killer_mob->TrySpellOnKill(killed_level, spell);
}
}
}
if (killer_mob && killer_mob->IsBot()) {
if (parse->BotHasQuestSub(EVENT_NPC_SLAY)) {
parse->EventBot(EVENT_NPC_SLAY, killer_mob->CastToBot(), this, "", 0);
}
killer_mob->TrySpellOnKill(killed_level, spell);
}
WipeHateList(); WipeHateList();
p_depop = true; p_depop = true;
@@ -2854,37 +2885,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
entity_list.UpdateFindableNPCState(this, true); entity_list.UpdateFindableNPCState(this, true);
m_combat_record.Stop();
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_DEATH_COMPLETE)) {
const auto& export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { corpse };
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0, &args);
}
/* Zone controller process EVENT_DEATH_ZONE (Death events) */
if (parse->HasQuestSub(ZONE_CONTROLLER_NPC_ID, EVENT_DEATH_ZONE)) {
const auto& export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { corpse, this };
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, oos, export_string, 0, &args);
}
return true; return true;
} }
@@ -3295,14 +3295,14 @@ int Mob::GetHandToHandDamage(void)
7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30
9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40
10, 11, 11, 11, 11, 11, 11, 12, 12 }; // 41-49 10, 11, 11, 11, 11, 11, 11, 12, 12 }; // 41-49
if (GetClass() == MONK) { if (GetClass() == Class::Monk) {
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50) if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50)
return 9; return 9;
if (level > 62) if (level > 62)
return 15; return 15;
return mnk_dmg[level]; return mnk_dmg[level];
} }
else if (GetClass() == BEASTLORD) { else if (GetClass() == Class::Beastlord) {
if (level > 49) if (level > 49)
return 13; return 13;
return bst_dmg[level]; return bst_dmg[level];
@@ -3354,7 +3354,7 @@ int Mob::GetHandToHandDelay(void)
28, 28, 28, 27, 27, 27, 27, 27, 26, 26, // 61-70 28, 28, 28, 27, 27, 27, 27, 27, 26, 26, // 61-70
26, 26, 26 }; // 71-73 26, 26, 26 }; // 71-73
if (GetClass() == MONK) { if (GetClass() == Class::Monk) {
// Have a look to see if we have epic fists on // Have a look to see if we have epic fists on
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50) if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50)
return 16; return 16;
@@ -3363,7 +3363,7 @@ int Mob::GetHandToHandDelay(void)
return GetRace() == IKSAR ? 21 : 20; return GetRace() == IKSAR ? 21 : 20;
return GetRace() == IKSAR ? mnk_iks_delay[level] : mnk_hum_delay[level]; return GetRace() == IKSAR ? mnk_iks_delay[level] : mnk_hum_delay[level];
} }
else if (GetClass() == BEASTLORD) { else if (GetClass() == Class::Beastlord) {
int level = GetLevel(); int level = GetLevel();
if (level > 73) if (level > 73)
return 25; return 25;
@@ -4067,7 +4067,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
} }
} }
else if (skill_used == EQ::skills::SkillKick && else if (skill_used == EQ::skills::SkillKick &&
(attacker->GetLevel() > 55 || attacker->IsNPC()) && GetClass() == WARRIOR) { (attacker->GetLevel() > 55 || attacker->IsNPC()) && GetClass() == Class::Warrior) {
can_stun = true; can_stun = true;
} }
@@ -5053,11 +5053,11 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
// We either require an innate crit chance or some SPA 169 to crit // We either require an innate crit chance or some SPA 169 to crit
bool innate_crit = false; bool innate_crit = false;
int crit_chance = GetCriticalChanceBonus(hit.skill); int crit_chance = GetCriticalChanceBonus(hit.skill);
if ((GetClass() == WARRIOR || GetClass() == BERSERKER) && GetLevel() >= 12) if ((GetClass() == Class::Warrior || GetClass() == Class::Berserker) && GetLevel() >= 12)
innate_crit = true; innate_crit = true;
else if (GetClass() == RANGER && GetLevel() >= 12 && hit.skill == EQ::skills::SkillArchery) else if (GetClass() == Class::Ranger && GetLevel() >= 12 && hit.skill == EQ::skills::SkillArchery)
innate_crit = true; innate_crit = true;
else if (GetClass() == ROGUE && GetLevel() >= 12 && hit.skill == EQ::skills::SkillThrowing) else if (GetClass() == Class::Rogue && GetLevel() >= 12 && hit.skill == EQ::skills::SkillThrowing)
innate_crit = true; innate_crit = true;
// we have a chance to crit! // we have a chance to crit!
@@ -5077,7 +5077,7 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
dex_bonus += 45; // chances did not match live without a small boost dex_bonus += 45; // chances did not match live without a small boost
// so if we have an innate crit we have a better chance, except for ber throwing // so if we have an innate crit we have a better chance, except for ber throwing
if (!innate_crit || (GetClass() == BERSERKER && hit.skill == EQ::skills::SkillThrowing)) if (!innate_crit || (GetClass() == Class::Berserker && hit.skill == EQ::skills::SkillThrowing))
dex_bonus = dex_bonus * 3 / 5; dex_bonus = dex_bonus * 3 / 5;
if (crit_chance) if (crit_chance)
@@ -5101,7 +5101,7 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
LogCombat("Crit success roll [{}] dex chance [{}] og dmg [{}] crit_mod [{}] new dmg [{}]", roll, dex_bonus, og_damage, crit_mod, hit.damage_done); LogCombat("Crit success roll [{}] dex chance [{}] og dmg [{}] crit_mod [{}] new dmg [{}]", roll, dex_bonus, og_damage, crit_mod, hit.damage_done);
// step 3: check deadly strike // step 3: check deadly strike
if (GetClass() == ROGUE && hit.skill == EQ::skills::SkillThrowing) { if (GetClass() == Class::Rogue && hit.skill == EQ::skills::SkillThrowing) {
if (BehindMob(defender, GetX(), GetY())) { if (BehindMob(defender, GetX(), GetY())) {
int chance = GetLevel() * 12; int chance = GetLevel() * 12;
if (zone->random.Int(1, 1000) < chance) { if (zone->random.Int(1, 1000) < chance) {
@@ -5284,7 +5284,7 @@ void Mob::DoRiposte(Mob *defender)
if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) { if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) {
LogCombat("Preforming a return SPECIAL ATTACK ([{}] percent chance)", DoubleRipChance); LogCombat("Preforming a return SPECIAL ATTACK ([{}] percent chance)", DoubleRipChance);
if (defender->GetClass() == MONK) if (defender->GetClass() == Class::Monk)
defender->MonkSpecialAttack(this, defender->aabonuses.GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_SKILL]); defender->MonkSpecialAttack(this, defender->aabonuses.GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_SKILL]);
else if (defender->IsClient()) // so yeah, even if you don't have the skill you can still do the attack :P (and we don't crash anymore) else if (defender->IsClient()) // so yeah, even if you don't have the skill you can still do the attack :P (and we don't crash anymore)
defender->CastToClient()->DoClassAttacks(this, defender->aabonuses.GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_SKILL], true); defender->CastToClient()->DoClassAttacks(this, defender->aabonuses.GiveDoubleRiposte[SBIndex::DOUBLE_RIPOSTE_SKILL], true);
@@ -5301,7 +5301,7 @@ void Mob::ApplyMeleeDamageMods(uint16 skill, int64 &damage, Mob *defender, Extra
dmgbonusmod += opts->melee_damage_bonus_flat; dmgbonusmod += opts->melee_damage_bonus_flat;
if (defender) { if (defender) {
if (defender->IsOfClientBotMerc() && defender->GetClass() == WARRIOR) { if (defender->IsOfClientBotMerc() && defender->GetClass() == Class::Warrior) {
dmgbonusmod -= 5; dmgbonusmod -= 5;
} }
// 168 defensive // 168 defensive
@@ -5445,7 +5445,7 @@ const DamageTable &Mob::GetDamageTable() const
{ 415, 15, 40 }, // 105 { 415, 15, 40 }, // 105
}; };
bool monk = GetClass() == MONK; bool monk = GetClass() == Class::Monk;
bool melee = IsWarriorClass(); bool melee = IsWarriorClass();
// tables caped at 105 for now -- future proofed for a while at least :P // tables caped at 105 for now -- future proofed for a while at least :P
int level = std::min(static_cast<int>(GetLevel()), 105); int level = std::min(static_cast<int>(GetLevel()), 105);
@@ -5893,7 +5893,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
// BER weren't parsing the halving // BER weren't parsing the halving
if (hit.skill == EQ::skills::SkillArchery || if (hit.skill == EQ::skills::SkillArchery ||
(hit.skill == EQ::skills::SkillThrowing && GetClass() != BERSERKER)) (hit.skill == EQ::skills::SkillThrowing && GetClass() != Class::Berserker))
hit.damage_done /= 2; hit.damage_done /= 2;
if (hit.damage_done < 1) if (hit.damage_done < 1)
@@ -5906,7 +5906,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
if (headshot > 0) { if (headshot > 0) {
hit.damage_done = headshot; hit.damage_done = headshot;
} }
else if (GetClass() == RANGER && GetLevel() > 50) { // no double dmg on headshot else if (GetClass() == Class::Ranger && GetLevel() > 50) { // no double dmg on headshot
if ((defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) || !RuleB(Combat, ArcheryBonusRequiresStationary)) { if ((defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) || !RuleB(Combat, ArcheryBonusRequiresStationary)) {
hit.damage_done *= 2; hit.damage_done *= 2;
MessageString(Chat::MeleeCrit, BOW_DOUBLE_DAMAGE); MessageString(Chat::MeleeCrit, BOW_DOUBLE_DAMAGE);
@@ -5931,7 +5931,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
hit.damage_done = ass; hit.damage_done = ass;
} }
} }
else if (hit.skill == EQ::skills::SkillFrenzy && GetClass() == BERSERKER && GetLevel() > 50) { else if (hit.skill == EQ::skills::SkillFrenzy && GetClass() == Class::Berserker && GetLevel() > 50) {
extra_mincap = 4 * GetLevel() / 5; extra_mincap = 4 * GetLevel() / 5;
} }
+2 -2
View File
@@ -117,7 +117,7 @@ void Client::CalcBonuses()
// hmm maybe a better way to do this // hmm maybe a better way to do this
int metabolism = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism; int metabolism = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism;
int timer = GetClass() == MONK ? CONSUMPTION_MNK_TIMER : CONSUMPTION_TIMER; int timer = GetClass() == Class::Monk ? CONSUMPTION_MNK_TIMER : CONSUMPTION_TIMER;
timer = timer * (100 + metabolism) / 100; timer = timer * (100 + metabolism) / 100;
if (timer != consume_food_timer.GetTimerTime()) if (timer != consume_food_timer.GetTimerTime())
consume_food_timer.SetTimer(timer); consume_food_timer.SetTimer(timer);
@@ -2053,7 +2053,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
} }
} }
if (GetClass() == BARD) if (GetClass() == Class::Bard)
newbon->ManaRegen = 0; // Bards do not get mana regen from spells. newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
} }
+830 -191
View File
File diff suppressed because it is too large Load Diff
+35 -17
View File
@@ -42,13 +42,12 @@ constexpr uint32 BOT_FOLLOW_DISTANCE_DEFAULT_MAX = 2500; // as DSq value (50 uni
constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds
constexpr uint32 MAG_EPIC_1_0 = 28034;
extern WorldServer worldserver; extern WorldServer worldserver;
constexpr int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this constexpr int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
constexpr int MaxSpellTimer = 15; constexpr int NegativeItemReuse = -1; // Unlinked timer for items
constexpr int MaxDisciplineTimer = 10;
constexpr int DisciplineReuseStart = MaxSpellTimer + 1;
constexpr int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
// nHSND negative Healer/Slower/Nuker/Doter // nHSND negative Healer/Slower/Nuker/Doter
// pH positive Healer // pH positive Healer
@@ -222,6 +221,8 @@ public:
void SetPullFlag(bool flag = true) { m_pull_flag = flag; } void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
bool GetPullingFlag() const { return m_pulling_flag; } bool GetPullingFlag() const { return m_pulling_flag; }
bool GetReturningFlag() const { return m_returning_flag; } bool GetReturningFlag() const { return m_returning_flag; }
bool GetIsUsingItemClick() { return is_using_item_click; }
void SetIsUsingItemClick(bool flag = true) { is_using_item_click = flag; }
bool UseDiscipline(uint32 spell_id, uint32 target); bool UseDiscipline(uint32 spell_id, uint32 target);
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid); uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid);
uint8 GetNumberNeedingHealedInRaidGroup(uint8& need_healed, uint8 hpr, bool includePets, Raid* raid); uint8 GetNumberNeedingHealedInRaidGroup(uint8& need_healed, uint8 hpr, bool includePets, Raid* raid);
@@ -286,6 +287,10 @@ public:
void SetEndurance(int32 newEnd) override; void SetEndurance(int32 newEnd) override;
void DoEnduranceUpkeep(); void DoEnduranceUpkeep();
void TryItemClick(uint16 slot_id);
EQ::ItemInstance* GetClickItem(uint16 slot_id);
void DoItemClick(const EQ::ItemData* inst, uint16 slot_id);
bool AI_AddBotSpells(uint32 bot_spell_id); bool AI_AddBotSpells(uint32 bot_spell_id);
void AddSpellToBotList( void AddSpellToBotList(
int16 iPriority, int16 iPriority,
@@ -394,25 +399,20 @@ public:
// Static Class Methods // Static Class Methods
static Bot* LoadBot(uint32 botID); static Bot* LoadBot(uint32 botID);
static uint32 SpawnedBotCount(const uint32 owner_id, uint8 class_id = NO_CLASS); static uint32 SpawnedBotCount(const uint32 owner_id, uint8 class_id = Class::None);
static void LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp); static void LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp);
static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined); static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined);
static Bot* GetBotByBotClientOwnerAndBotName(Client* c, const std::string& botName); static Bot* GetBotByBotClientOwnerAndBotName(Client* c, const std::string& botName);
static void ProcessBotGroupInvite(Client* c, std::string const& botName); static void ProcessBotGroupInvite(Client* c, std::string const& botName);
static void ProcessBotGroupDisband(Client* c, const std::string& botName); static void ProcessBotGroupDisband(Client* c, const std::string& botName);
static void BotOrderCampAll(Client* c, uint8 class_id = NO_CLASS); static void BotOrderCampAll(Client* c, uint8 class_id = Class::None);
static void ProcessBotInspectionRequest(Bot* inspectedBot, Client* client); static void ProcessBotInspectionRequest(Bot* inspectedBot, Client* client);
static void LoadAndSpawnAllZonedBots(Client* bot_owner); static void LoadAndSpawnAllZonedBots(Client* bot_owner);
static bool GroupHasBot(Group* group); static bool GroupHasBot(Group* group);
static Bot* GetFirstBotInGroup(Group* group); static Bot* GetFirstBotInGroup(Group* group);
static void ProcessClientZoneChange(Client* botOwner); static void ProcessClientZoneChange(Client* botOwner);
static void ProcessBotOwnerRefDelete(Mob* botOwner); // Removes a Client* reference when the Client object is destroyed static void ProcessBotOwnerRefDelete(Mob* botOwner); // Removes a Client* reference when the Client object is destroyed
static int32 GetSpellRecastTimer(Bot *caster, int timer_index);
static bool CheckSpellRecastTimers(Bot *caster, int SpellIndex);
static int32 GetDisciplineRecastTimer(Bot *caster, int timer_index);
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
//Raid methods //Raid methods
static void ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite = false); static void ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite = false);
@@ -604,7 +604,7 @@ public:
void SetBotCharmer(bool c) { _botCharmer = c; } void SetBotCharmer(bool c) { _botCharmer = c; }
void SetPetChooser(bool p) { _petChooser = p; } void SetPetChooser(bool p) { _petChooser = p; }
void SetBotOwner(Mob* botOwner) { this->_botOwner = botOwner; } void SetBotOwner(Mob* botOwner) { this->_botOwner = botOwner; }
void SetRangerAutoWeaponSelect(bool enable) { GetClass() == RANGER ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; } void SetRangerAutoWeaponSelect(bool enable) { GetClass() == Class::Ranger ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; }
void SetBotStance(EQ::constants::StanceType botStance) { void SetBotStance(EQ::constants::StanceType botStance) {
if (botStance >= EQ::constants::stancePassive && botStance <= EQ::constants::stanceBurnAE) if (botStance >= EQ::constants::stancePassive && botStance <= EQ::constants::stanceBurnAE)
_botStance = botStance; _botStance = botStance;
@@ -612,8 +612,23 @@ public:
_botStance = EQ::constants::stancePassive; _botStance = EQ::constants::stancePassive;
} }
void SetBotCasterRange(uint32 bot_caster_range) { m_bot_caster_range = bot_caster_range; } void SetBotCasterRange(uint32 bot_caster_range) { m_bot_caster_range = bot_caster_range; }
void SetSpellRecastTimer(int timer_index, int32 recast_delay); uint32 GetSpellRecastTimer(uint16 spell_id = 0);
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay); bool CheckSpellRecastTimer(uint16 spell_id = 0);
uint32 GetSpellRecastRemainingTime(uint16 spell_id = 0);
void SetSpellRecastTimer(uint16 spell_id, int32 recast_delay = 0);
uint32 CalcSpellRecastTimer(uint16 spell_id);
uint32 GetDisciplineReuseTimer(uint16 spell_id = 0);
bool CheckDisciplineReuseTimer(uint16 spell_id = 0);
uint32 GetDisciplineReuseRemainingTime(uint16 spell_id = 0);
void SetDisciplineReuseTimer(uint16 spell_id, int32 reuse_timer = 0);
uint32 GetItemReuseTimer(uint32 item_id = 0);
bool CheckItemReuseTimer(uint32 item_id = 0);
void SetItemReuseTimer(uint32 item_id, uint32 reuse_timer = 0);
void ClearDisciplineReuseTimer(uint16 spell_id = 0);
void ClearItemReuseTimer(uint32 item_id = 0);
void ClearSpellRecastTimer(uint16 spell_id = 0);
uint32 GetItemReuseRemainingTime(uint32 item_id = 0);
void ClearExpiredTimers();
void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;} void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;}
void SetShowHelm(bool showhelm) { _showhelm = showhelm; } void SetShowHelm(bool showhelm) { _showhelm = showhelm; }
void SetBeardColor(uint8 value) { beardcolor = value; } void SetBeardColor(uint8 value) { beardcolor = value; }
@@ -713,7 +728,8 @@ public:
// New accessors for BotDatabase access // New accessors for BotDatabase access
bool DeleteBot(); bool DeleteBot();
uint32* GetTimers() { return timers; } std::vector<BotTimer_Struct> GetBotTimers() { return bot_timers; }
void SetBotTimers(std::vector<BotTimer_Struct> timers) { bot_timers = timers; }
uint32 GetLastZoneID() const { return _lastZoneId; } uint32 GetLastZoneID() const { return _lastZoneId; }
int32 GetBaseAC() const { return _baseAC; } int32 GetBaseAC() const { return _baseAC; }
int32 GetBaseATK() const { return _baseATK; } int32 GetBaseATK() const { return _baseATK; }
@@ -738,7 +754,7 @@ public:
//Raid additions //Raid additions
Raid* p_raid_instance; Raid* p_raid_instance;
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND]; static uint8 spell_casting_chances[SPELL_TYPE_COUNT][Class::PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
bool BotCastMez(Mob* tar, uint8 botLevel, bool checked_los, BotSpell& botSpell, Raid* raid); bool BotCastMez(Mob* tar, uint8 botLevel, bool checked_los, BotSpell& botSpell, Raid* raid);
bool BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, Raid* raid); bool BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, Raid* raid);
@@ -828,6 +844,7 @@ protected:
std::vector<BotSpells_Struct> AIBot_spells; std::vector<BotSpells_Struct> AIBot_spells;
std::vector<BotSpells_Struct> AIBot_spells_enforced; std::vector<BotSpells_Struct> AIBot_spells_enforced;
std::vector<BotTimer_Struct> bot_timers;
private: private:
// Class Members // Class Members
@@ -861,11 +878,11 @@ private:
int32 cur_end; int32 cur_end;
int32 max_end; int32 max_end;
int32 end_regen; int32 end_regen;
uint32 timers[MaxTimer];
Timer m_evade_timer; // can be moved to pTimers at some point Timer m_evade_timer; // can be moved to pTimers at some point
Timer m_alt_combat_hate_timer; Timer m_alt_combat_hate_timer;
Timer m_auto_defend_timer; Timer m_auto_defend_timer;
Timer auto_save_timer;
bool m_dirtyautohaters; bool m_dirtyautohaters;
bool m_guard_flag; bool m_guard_flag;
bool m_hold_flag; bool m_hold_flag;
@@ -874,6 +891,7 @@ private:
bool m_pull_flag; bool m_pull_flag;
bool m_pulling_flag; bool m_pulling_flag;
bool m_returning_flag; bool m_returning_flag;
bool is_using_item_click;
eStandingPetOrder m_previous_pet_order; eStandingPetOrder m_previous_pet_order;
uint32 m_bot_caster_range; uint32 m_bot_caster_range;
BotCastingRoles m_CastingRoles; BotCastingRoles m_CastingRoles;
+434 -97
View File
@@ -84,8 +84,8 @@ namespace
enum { EffectIDFirst = 1, EffectIDLast = 12 }; enum { EffectIDFirst = 1, EffectIDLast = 12 };
#define VALIDATECLASSID(x) ((x >= WARRIOR && x <= BERSERKER) ? (x) : (0)) #define VALIDATECLASSID(x) ((x >= Class::Warrior && x <= Class::Berserker) ? (x) : (0))
#define CLASSIDTOINDEX(x) ((x >= WARRIOR && x <= BERSERKER) ? (x - 1) : (0)) #define CLASSIDTOINDEX(x) ((x >= Class::Warrior && x <= Class::Berserker) ? (x - 1) : (0))
#define EFFECTIDTOINDEX(x) ((x >= EffectIDFirst && x <= EffectIDLast) ? (x - 1) : (0)) #define EFFECTIDTOINDEX(x) ((x >= EffectIDFirst && x <= EffectIDLast) ? (x - 1) : (0))
#define AILMENTIDTOINDEX(x) ((x >= BCEnum::AT_Blindness && x <= BCEnum::AT_Corruption) ? (x - 1) : (0)) #define AILMENTIDTOINDEX(x) ((x >= BCEnum::AT_Blindness && x <= BCEnum::AT_Corruption) ? (x - 1) : (0))
#define RESISTANCEIDTOINDEX(x) ((x >= BCEnum::RT_Fire && x <= BCEnum::RT_Corruption) ? (x - 1) : (0)) #define RESISTANCEIDTOINDEX(x) ((x >= BCEnum::RT_Fire && x <= BCEnum::RT_Corruption) ? (x - 1) : (0))
@@ -196,7 +196,7 @@ public:
uint8 class_levels[16] = {0}; uint8 class_levels[16] = {0};
bool player_spell = false; bool player_spell = false;
for (int class_type = WARRIOR; class_type <= BERSERKER; ++class_type) { for (int class_type = Class::Warrior; class_type <= Class::Berserker; ++class_type) {
int class_index = CLASSIDTOINDEX(class_type); int class_index = CLASSIDTOINDEX(class_type);
if (spells[spell_id].classes[class_index] == 0 || if (spells[spell_id].classes[class_index] == 0 ||
spells[spell_id].classes[class_index] > HARD_LEVEL_CAP) { spells[spell_id].classes[class_index] > HARD_LEVEL_CAP) {
@@ -489,7 +489,7 @@ public:
entry_prototype->target_type = target_type; entry_prototype->target_type = target_type;
bcst_levels& bot_levels = bot_levels_map[entry_prototype->BCST()]; bcst_levels& bot_levels = bot_levels_map[entry_prototype->BCST()];
for (int class_type = WARRIOR; class_type <= BERSERKER; ++class_type) { for (int class_type = Class::Warrior; class_type <= Class::Berserker; ++class_type) {
int class_index = CLASSIDTOINDEX(class_type); int class_index = CLASSIDTOINDEX(class_type);
if (!class_levels[class_index]) if (!class_levels[class_index])
continue; continue;
@@ -1119,7 +1119,7 @@ private:
} }
static void helper_bots_string(BCEnum::SpType type_index, bcst_levels& bot_levels) { static void helper_bots_string(BCEnum::SpType type_index, bcst_levels& bot_levels) {
for (int i = WARRIOR; i <= BERSERKER; ++i) for (int i = Class::Warrior; i <= Class::Berserker; ++i)
required_bots_map_by_class[type_index][i] = "Unavailable..."; required_bots_map_by_class[type_index][i] = "Unavailable...";
if (bot_levels.empty()) { if (bot_levels.empty()) {
@@ -1375,6 +1375,7 @@ int bot_command_init(void)
bot_command_add("casterrange", "Controls the range casters will try to stay away from a mob (if too far, they will skip spells that are out-of-range)", AccountStatus::Player, bot_command_caster_range) || bot_command_add("casterrange", "Controls the range casters will try to stay away from a mob (if too far, they will skip spells that are out-of-range)", AccountStatus::Player, bot_command_caster_range) ||
bot_command_add("charm", "Attempts to have a bot charm your target", AccountStatus::Player, bot_command_charm) || bot_command_add("charm", "Attempts to have a bot charm your target", AccountStatus::Player, bot_command_charm) ||
bot_command_add("circle", "Orders a Druid bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_subcommand_circle) || bot_command_add("circle", "Orders a Druid bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_subcommand_circle) ||
bot_command_add("clickitem", "Orders your targeted bot to click the item in the provided inventory slot.", AccountStatus::Player, bot_command_click_item) ||
bot_command_add("cure", "Orders a bot to remove any ailments", AccountStatus::Player, bot_command_cure) || bot_command_add("cure", "Orders a bot to remove any ailments", AccountStatus::Player, bot_command_cure) ||
bot_command_add("defensive", "Orders a bot to use a defensive discipline", AccountStatus::Player, bot_command_defensive) || bot_command_add("defensive", "Orders a bot to use a defensive discipline", AccountStatus::Player, bot_command_defensive) ||
bot_command_add("depart", "Orders a bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_command_depart) || bot_command_add("depart", "Orders a bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_command_depart) ||
@@ -1444,6 +1445,7 @@ int bot_command_init(void)
bot_command_add("summoncorpse", "Orders a bot to summon a corpse to its feet", AccountStatus::Player, bot_command_summon_corpse) || bot_command_add("summoncorpse", "Orders a bot to summon a corpse to its feet", AccountStatus::Player, bot_command_summon_corpse) ||
bot_command_add("suspend", "Suspends a bot's AI processing until released", AccountStatus::Player, bot_command_suspend) || bot_command_add("suspend", "Suspends a bot's AI processing until released", AccountStatus::Player, bot_command_suspend) ||
bot_command_add("taunt", "Toggles taunt use by a bot", AccountStatus::Player, bot_command_taunt) || bot_command_add("taunt", "Toggles taunt use by a bot", AccountStatus::Player, bot_command_taunt) ||
bot_command_add("timer", "Checks or clears timers of the chosen type.", AccountStatus::GMMgmt, bot_command_timer) ||
bot_command_add("track", "Orders a capable bot to track enemies", AccountStatus::Player, bot_command_track) || bot_command_add("track", "Orders a capable bot to track enemies", AccountStatus::Player, bot_command_track) ||
bot_command_add("viewcombos", "Views bot race class combinations", AccountStatus::Player, bot_command_view_combos) || bot_command_add("viewcombos", "Views bot race class combinations", AccountStatus::Player, bot_command_view_combos) ||
bot_command_add("waterbreathing", "Orders a bot to cast a water breathing spell", AccountStatus::Player, bot_command_water_breathing) bot_command_add("waterbreathing", "Orders a bot to cast a water breathing spell", AccountStatus::Player, bot_command_water_breathing)
@@ -2730,9 +2732,9 @@ namespace ActionableBots
static void Filter_ByHighestPickLock(Client* bot_owner, std::list<Bot*>& sbl, float& pick_lock_value) { static void Filter_ByHighestPickLock(Client* bot_owner, std::list<Bot*>& sbl, float& pick_lock_value) {
sbl.remove_if([bot_owner](Bot* l) { return (!MyBots::IsMyBot(bot_owner, l)); }); sbl.remove_if([bot_owner](Bot* l) { return (!MyBots::IsMyBot(bot_owner, l)); });
sbl.remove_if([bot_owner](const Bot* l) { return (l->GetClass() != ROGUE && l->GetClass() != BARD); }); sbl.remove_if([bot_owner](const Bot* l) { return (l->GetClass() != Class::Rogue && l->GetClass() != Class::Bard); });
sbl.remove_if([bot_owner](const Bot* l) { return (l->GetClass() == ROGUE && l->GetLevel() < 5); }); sbl.remove_if([bot_owner](const Bot* l) { return (l->GetClass() == Class::Rogue && l->GetLevel() < 5); });
sbl.remove_if([bot_owner](const Bot* l) { return (l->GetClass() == BARD && l->GetLevel() < 40); }); sbl.remove_if([bot_owner](const Bot* l) { return (l->GetClass() == Class::Bard && l->GetLevel() < 40); });
ActionableBots::Filter_ByHighestSkill(bot_owner, sbl, EQ::skills::SkillPickLock, pick_lock_value); ActionableBots::Filter_ByHighestSkill(bot_owner, sbl, EQ::skills::SkillPickLock, pick_lock_value);
} }
@@ -2832,7 +2834,7 @@ void bot_command_aggressive(Client *c, const Seperator *sep)
} }
} }
c->Message(Chat::White, "%i of %i bots have used aggressive disciplines", success_count, candidate_count); c->Message(Chat::White, "%i of %i bots have attempted to use aggressive disciplines", success_count, candidate_count);
} }
void bot_command_apply_poison(Client *c, const Seperator *sep) void bot_command_apply_poison(Client *c, const Seperator *sep)
@@ -2856,7 +2858,7 @@ void bot_command_apply_poison(Client *c, const Seperator *sep)
t && t &&
t->IsBot() && t->IsBot() &&
t->CastToBot()->GetBotOwnerCharacterID() == c->CharacterID() && t->CastToBot()->GetBotOwnerCharacterID() == c->CharacterID() &&
t->GetClass() == ROGUE t->GetClass() == Class::Rogue
) { ) {
my_rogue_bot = t->CastToBot(); my_rogue_bot = t->CastToBot();
} }
@@ -2964,7 +2966,7 @@ void bot_command_apply_potion(Client* c, const Seperator* sep)
if (potion_data->ItemType == EQ::item::ItemTypePotion && potion_data->Click.Effect > 0) { if (potion_data->ItemType == EQ::item::ItemTypePotion && potion_data->Click.Effect > 0) {
if (RuleB(Bots, RestrictApplyPotionToRogue) && potion_data->Classes != PLAYER_CLASS_ROGUE_BIT) { if (RuleB(Bots, RestrictApplyPotionToRogue) && potion_data->Classes != player_class_bitmasks[Class::Rogue]) {
c->Message(Chat::White, "This command is restricted to rogue poison potions only!"); c->Message(Chat::White, "This command is restricted to rogue poison potions only!");
return; return;
@@ -3300,7 +3302,7 @@ void bot_command_defensive(Client *c, const Seperator *sep)
auto local_entry = list_iter->SafeCastToStance(); auto local_entry = list_iter->SafeCastToStance();
if (helper_spell_check_fail(local_entry)) if (helper_spell_check_fail(local_entry))
continue; continue;
if (local_entry->stance_type != BCEnum::StT_Aggressive) if (local_entry->stance_type != BCEnum::StT_Defensive)
continue; continue;
for (auto bot_iter = sbl.begin(); bot_iter != sbl.end(); ) { for (auto bot_iter = sbl.begin(); bot_iter != sbl.end(); ) {
@@ -3332,7 +3334,7 @@ void bot_command_defensive(Client *c, const Seperator *sep)
} }
} }
c->Message(Chat::White, "%i of %i bots have used defensive disciplines", success_count, candidate_count); c->Message(Chat::White, "%i of %i bots have attempted to use defensive disciplines", success_count, candidate_count);
} }
void bot_command_depart(Client *c, const Seperator *sep) void bot_command_depart(Client *c, const Seperator *sep)
@@ -3353,8 +3355,8 @@ void bot_command_depart(Client *c, const Seperator *sep)
std::string destination = sep->arg[1]; std::string destination = sep->arg[1];
if (!destination.compare("list")) { if (!destination.compare("list")) {
Bot* my_druid_bot = ActionableBots::AsGroupMember_ByClass(c, c, DRUID); Bot* my_druid_bot = ActionableBots::AsGroupMember_ByClass(c, c, Class::Druid);
Bot* my_wizard_bot = ActionableBots::AsGroupMember_ByClass(c, c, WIZARD); Bot* my_wizard_bot = ActionableBots::AsGroupMember_ByClass(c, c, Class::Wizard);
helper_command_depart_list(c, my_druid_bot, my_wizard_bot, local_list, single); helper_command_depart_list(c, my_druid_bot, my_wizard_bot, local_list, single);
return; return;
} }
@@ -3906,16 +3908,77 @@ void bot_command_invisibility(Client *c, const Seperator *sep)
void bot_command_item_use(Client* c, const Seperator* sep) void bot_command_item_use(Client* c, const Seperator* sep)
{ {
if (helper_is_help_or_usage(sep->arg[1])) { if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(Chat::White, "usage: %s ([empty])", sep->arg[0]); c->Message(Chat::White, "usage: [%s empty] will display only bots that can use the item in an empty slot.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s byclass classID] - Example: [%s byclass 7] will display only bots that match the class that can use the item. Example is a Monk, use [^create help] for a list of class IDs.", sep->arg[0], sep->arg[0]);
c->Message(Chat::White, "usage: [%s casteronly] will display only caster bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s hybridonly] will display only hybrid bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s meleeonly] will display only melee bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s wiscasteronly] will display only Wisdom-based Caster bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s intcasteronly] will display only Intelligence-based Caster bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s plateonly] will display only Plate-wearing bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s chainonly] will display only Chain-wearing bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s leatheronly] will display only Leather-wearing bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s clothonly] will display only Cloth-wearing bots that can use the item.", sep->arg[0]);
return; return;
} }
bool empty_only = false; bool empty_only = false;
int8 class_mask = 0;
bool caster_only = false;
bool hybrid_only = false;
bool melee_only = false;
bool wis_caster_only = false;
bool int_caster_only = false;
bool plate_only = false;
bool chain_only = false;
bool leather_only = false;
bool cloth_only = false;
std::string arg1 = sep->arg[1]; std::string arg1 = sep->arg[1];
std::string arg2 = sep->arg[2];
if (arg1.compare("empty") == 0) { if (arg1.compare("empty") == 0) {
empty_only = true; empty_only = true;
} }
else if (arg1.compare("byclass") == 0) {
if (Strings::IsNumber(sep->arg[2])) {
class_mask = Strings::ToUnsignedInt(sep->arg[2]);
if (!(class_mask >= Class::Warrior && class_mask <= Class::Berserker)) {
c->Message(Chat::White, "Invalid class range, you must choose between 1 (Warrior) and 15 (Beastlord)");
return;
}
}
}
else if (arg1.compare("casteronly") == 0) {
caster_only = true;
}
else if (arg1.compare("hybridonly") == 0) {
hybrid_only = true;
}
else if (arg1.compare("meleeonly") == 0) {
melee_only = true;
}
else if (arg1.compare("wiscasteronly") == 0) {
wis_caster_only = true;
}
else if (arg1.compare("intcasteronly") == 0) {
int_caster_only = true;
}
else if (arg1.compare("plateonly") == 0) {
plate_only = true;
}
else if (arg1.compare("chainonly") == 0) {
chain_only = true;
}
else if (arg1.compare("leatheronly") == 0) {
leather_only = true;
}
else if (arg1.compare("clothonly") == 0) {
cloth_only = true;
}
else if (!arg1.empty()) {
c->Message(Chat::White, "Please choose the correct subtype. For help use %s help.", sep->arg[0]);
return;
}
const auto item_instance = c->GetInv().GetItem(EQ::invslot::slotCursor); const auto item_instance = c->GetInv().GetItem(EQ::invslot::slotCursor);
if (!item_instance) { if (!item_instance) {
c->Message(Chat::White, "No item found on cursor!"); c->Message(Chat::White, "No item found on cursor!");
@@ -3948,11 +4011,41 @@ void bot_command_item_use(Client* c, const Seperator* sep)
std::list<Bot*> sbl; std::list<Bot*> sbl;
MyBots::PopulateSBL_BySpawnedBots(c, sbl); MyBots::PopulateSBL_BySpawnedBots(c, sbl);
if (class_mask) {
ActionableBots::Filter_ByClasses(c, sbl, GetPlayerClassBit(class_mask));
}
for (const auto& bot_iter : sbl) { for (const auto& bot_iter : sbl) {
if (!bot_iter) { if (!bot_iter) {
continue; continue;
} }
if (caster_only && !IsCasterClass(bot_iter->GetClass())) {
continue;
}
if (hybrid_only && !IsSpellFighterClass(bot_iter->GetClass())) {
continue;
}
if (melee_only && !IsNonSpellFighterClass(bot_iter->GetClass())) {
continue;
}
if (wis_caster_only && !IsWISCasterClass(bot_iter->GetClass())) {
continue;
}
if (int_caster_only && !IsINTCasterClass(bot_iter->GetClass())) {
continue;
}
if (plate_only && !IsPlateClass(bot_iter->GetClass())) {
continue;
}
if (chain_only && !IsChainClass(bot_iter->GetClass())) {
continue;
}
if (leather_only && !IsLeatherClass(bot_iter->GetClass())) {
continue;
}
if (cloth_only && !IsClothClass(bot_iter->GetClass())) {
continue;
}
if (((~item_data->Races) & GetPlayerRaceBit(bot_iter->GetRace())) || ((~item_data->Classes) & GetPlayerClassBit(bot_iter->GetClass()))) { if (((~item_data->Races) & GetPlayerRaceBit(bot_iter->GetRace())) || ((~item_data->Classes) & GetPlayerClassBit(bot_iter->GetClass()))) {
continue; continue;
} }
@@ -3997,7 +4090,8 @@ void bot_command_item_use(Client* c, const Seperator* sep)
); );
bot_iter->DoAnim(29); bot_iter->DoAnim(29);
} else if (!equipped_item) { }
else if (!equipped_item) {
c->Message( c->Message(
Chat::Say, Chat::Say,
fmt::format( fmt::format(
@@ -4647,17 +4741,17 @@ void bot_command_pull(Client *c, const Seperator *sep)
} }
switch (bot_iter->GetClass()) { switch (bot_iter->GetClass()) {
case ROGUE: case Class::Rogue:
case MONK: case Class::Monk:
case BARD: case Class::Bard:
case RANGER: case Class::Ranger:
bot_puller = bot_iter; bot_puller = bot_iter;
break; break;
case WARRIOR: case Class::Warrior:
case SHADOWKNIGHT: case Class::ShadowKnight:
case PALADIN: case Class::Paladin:
case BERSERKER: case Class::Berserker:
case BEASTLORD: case Class::Beastlord:
if (!bot_puller) { if (!bot_puller) {
bot_puller = bot_iter; bot_puller = bot_iter;
@@ -4665,22 +4759,22 @@ void bot_command_pull(Client *c, const Seperator *sep)
} }
switch (bot_puller->GetClass()) { switch (bot_puller->GetClass()) {
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
case CLERIC: case Class::Cleric:
case WIZARD: case Class::Wizard:
case NECROMANCER: case Class::Necromancer:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
bot_puller = bot_iter; bot_puller = bot_iter;
default: default:
continue; continue;
} }
continue; continue;
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
case CLERIC: case Class::Cleric:
if (!bot_puller) { if (!bot_puller) {
bot_puller = bot_iter; bot_puller = bot_iter;
@@ -4688,20 +4782,20 @@ void bot_command_pull(Client *c, const Seperator *sep)
} }
switch (bot_puller->GetClass()) { switch (bot_puller->GetClass()) {
case WIZARD: case Class::Wizard:
case NECROMANCER: case Class::Necromancer:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
bot_puller = bot_iter; bot_puller = bot_iter;
default: default:
continue; continue;
} }
continue; continue;
case WIZARD: case Class::Wizard:
case NECROMANCER: case Class::Necromancer:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
if (!bot_puller) { if (!bot_puller) {
bot_puller = bot_iter; bot_puller = bot_iter;
} }
@@ -5194,6 +5288,194 @@ void bot_command_taunt(Client *c, const Seperator *sep)
} }
} }
void bot_command_timer(Client* c, const Seperator* sep)
{
if (helper_command_alias_fail(c, "bot_command_timer", sep->arg[0], "timer"))
return;
if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(Chat::White, "usage: %s [clear | has | set] [disc | item | spell] [timer ID | item ID | spell ID | all] [optional ms for set] [actionable].", sep->arg[0]);
c->Message(Chat::White, "When setting, you can leave the value blank to use the default for the item or specify a value in ms to set the timer to.");
c->Message(Chat::White, "Returns or sets the provided timer(s) for the selected bot(s) or clears the selected timer(s) for the selected bot(s).");
return;
}
const int ab_mask = ActionableBots::ABM_Type1;
std::string arg1 = sep->arg[1];
std::string arg2 = sep->arg[2];
std::string arg3 = sep->arg[3];
int ab_arg = 4;
bool clear = false;
bool has = false;
bool set = false;
bool disc = false;
bool item = false;
bool spell = false;
uint32 timer_id = 0;
uint32 timer_value = 0;
bool all = false;
if (!arg1.compare("clear")) {
clear = true;
}
else if (!arg1.compare("has")) {
has = true;
}
else if (!arg1.compare("set")) {
set = true;
}
else {
c->Message(Chat::White, "Incorrect argument, use %s help for a list of options.", sep->arg[0]);
return;
}
if (!arg2.compare("disc")) {
disc = true;
}
else if (!arg2.compare("item")) {
item = true;
}
else if (!arg2.compare("spell")) {
spell = true;
}
else {
c->Message(Chat::White, "Incorrect timer type, use %s help for a list of options.", sep->arg[0]);
return;
}
if (sep->IsNumber(3)) {
timer_id = atoi(sep->arg[3]);
if (timer_id < 0) {
c->Message(Chat::White, "You cannot use negative numbers.");
return;
}
}
else if (!arg3.compare("all")) {
if (has || set) {
c->Message(Chat::White, "You can only use 'all' for clearing timers.");
return;
}
all = true;
}
else {
c->Message(Chat::White, "Incorrect ID option, use %s help for a list of options.", sep->arg[0]);
return;
}
if (set) {
if (sep->IsNumber(4)) {
ab_arg = 5;
timer_value = atoi(sep->arg[4]);
if (timer_value <= 0) {
c->Message(Chat::White, "You cannot use 0 or negative numbers.");
return;
}
}
}
std::string class_race_arg = sep->arg[ab_arg];
bool class_race_check = false;
if (!class_race_arg.compare("byclass") || !class_race_arg.compare("byrace")) {
class_race_check = true;
}
std::list<Bot*> sbl;
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg + 1] : nullptr, class_race_check ? atoi(sep->arg[ab_arg + 1]) : 0) == ActionableBots::ABT_None) {
return;
}
sbl.remove(nullptr);
for (auto my_bot : sbl) {
bool found = false;
if (clear) {
c->Message(
Chat::White,
fmt::format(
"{} says, 'Clearing {} timer{}'",
my_bot->GetCleanName(),
disc ? "Discipline" : item ? "Item" : "Spell",
(all ? "s." : ".")
).c_str()
);
if (disc) {
my_bot->ClearDisciplineReuseTimer(timer_id);
}
else if (item) {
my_bot->ClearItemReuseTimer(timer_id);
}
else if (spell) {
my_bot->ClearSpellRecastTimer(timer_id);
}
}
else if (has) {
uint32 remaining_time;
std::string time_string = "";
if (disc) {
if (!my_bot->CheckDisciplineReuseTimer(timer_id)) {
remaining_time = my_bot->GetDisciplineReuseRemainingTime(timer_id) / 1000;
time_string = Strings::SecondsToTime(remaining_time);
found = true;
}
}
else if (item) {
if (!my_bot->CheckItemReuseTimer(timer_id)) {
remaining_time = my_bot->GetItemReuseRemainingTime(timer_id) / 1000;
time_string = Strings::SecondsToTime(remaining_time);
found = true;
}
}
else if (spell) {
if (!my_bot->CheckSpellRecastTimer(timer_id)) {
remaining_time = my_bot->GetSpellRecastRemainingTime(timer_id) / 1000;
time_string = Strings::SecondsToTime(remaining_time);
found = true;
}
}
c->Message(
Chat::White,
fmt::format(
"{} says, 'I {}{}{}'",
my_bot->GetCleanName(),
(!found ? " do not have that timer currently" : " have "),
(!found ? "" : time_string),
(!found ? "." : " remaining.")
).c_str()
);
}
else if (set) {
c->Message(
Chat::White,
fmt::format(
"{} says, 'Setting {} timer{} for {} to {}.'",
my_bot->GetCleanName(),
disc ? "Discipline" : item ? "Item" : "Spell",
(all ? "s" : ""),
timer_id,
timer_value ? std::to_string(timer_value) : "the default value"
).c_str()
);
if (disc) {
my_bot->ClearDisciplineReuseTimer(timer_id);
my_bot->SetDisciplineReuseTimer(timer_id, timer_value);
}
else if (item) {
my_bot->ClearItemReuseTimer(timer_id);
my_bot->SetItemReuseTimer(timer_id, timer_value);
}
else if (spell) {
my_bot->ClearSpellRecastTimer(timer_id);
my_bot->SetSpellRecastTimer(timer_id, timer_value);
}
}
}
}
void bot_command_track(Client *c, const Seperator *sep) void bot_command_track(Client *c, const Seperator *sep)
{ {
if (helper_command_alias_fail(c, "bot_command_track", sep->arg[0], "track")) if (helper_command_alias_fail(c, "bot_command_track", sep->arg[0], "track"))
@@ -5210,15 +5492,15 @@ void bot_command_track(Client *c, const Seperator *sep)
std::list<Bot*> sbl; std::list<Bot*> sbl;
MyBots::PopulateSBL_BySpawnedBots(c, sbl); MyBots::PopulateSBL_BySpawnedBots(c, sbl);
uint16 class_mask = (PLAYER_CLASS_RANGER_BIT | PLAYER_CLASS_DRUID_BIT | PLAYER_CLASS_BARD_BIT); uint16 class_mask = (player_class_bitmasks[Class::Ranger] | player_class_bitmasks[Class::Druid] | player_class_bitmasks[Class::Bard]);
ActionableBots::Filter_ByClasses(c, sbl, class_mask); ActionableBots::Filter_ByClasses(c, sbl, class_mask);
Bot* my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 1, RANGER); Bot* my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 1, Class::Ranger);
if (tracking_scope.empty()) { if (tracking_scope.empty()) {
if (!my_bot) if (!my_bot)
my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 20, DRUID); my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 20, Class::Druid);
if (!my_bot) if (!my_bot)
my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 35, BARD); my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 35, Class::Bard);
} }
if (!my_bot) { if (!my_bot) {
c->Message(Chat::White, "No bots are capable of performing this action"); c->Message(Chat::White, "No bots are capable of performing this action");
@@ -5229,7 +5511,7 @@ void bot_command_track(Client *c, const Seperator *sep)
bool track_named = false; bool track_named = false;
std::string tracking_msg; std::string tracking_msg;
switch (my_bot->GetClass()) { switch (my_bot->GetClass()) {
case RANGER: case Class::Ranger:
if (!tracking_scope.compare("local")) { if (!tracking_scope.compare("local")) {
base_distance = 30; base_distance = 30;
tracking_msg = "Local tracking..."; tracking_msg = "Local tracking...";
@@ -5244,11 +5526,11 @@ void bot_command_track(Client *c, const Seperator *sep)
tracking_msg = "Advanced tracking..."; tracking_msg = "Advanced tracking...";
} }
break; break;
case DRUID: case Class::Druid:
base_distance = 30; base_distance = 30;
tracking_msg = "Local tracking..."; tracking_msg = "Local tracking...";
break; break;
case BARD: case Class::Bard:
base_distance = 20; base_distance = 20;
tracking_msg = "Near tracking..."; tracking_msg = "Near tracking...";
break; break;
@@ -6612,7 +6894,7 @@ void bot_subcommand_bot_list(Client *c, const Seperator *sep)
).c_str() ).c_str()
); );
for (uint8 class_id = WARRIOR; class_id <= BERSERKER; class_id++) { for (uint8 class_id = Class::Warrior; class_id <= Class::Berserker; class_id++) {
auto class_creation_limit = c->GetBotCreationLimit(class_id); auto class_creation_limit = c->GetBotCreationLimit(class_id);
if (class_creation_limit != overall_bot_creation_limit) { if (class_creation_limit != overall_bot_creation_limit) {
@@ -6865,7 +7147,7 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
std::string bot_name = sep->arg[1]; std::string bot_name = sep->arg[1];
uint32 bot_id = 0; uint32 bot_id = 0;
uint8 bot_class = NO_CLASS; uint8 bot_class = Class::None;
if (!database.botdb.LoadBotID(c->CharacterID(), bot_name, bot_id, bot_class)) { if (!database.botdb.LoadBotID(c->CharacterID(), bot_name, bot_id, bot_class)) {
c->Message( c->Message(
Chat::White, Chat::White,
@@ -6972,22 +7254,22 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
static std::string bot_spawn_message[17] = { static std::string bot_spawn_message[17] = {
"I am ready to fight!", // DEFAULT "I am ready to fight!", // DEFAULT
"A solid weapon is my ally!", // WARRIOR "A solid weapon is my ally!", // Class::Warrior
"The pious shall never die!", // CLERIC "The pious shall never die!", // Class::Cleric
"I am the symbol of Light!", // PALADIN "I am the symbol of Light!", // Class::Paladin
"There are enemies near!", // RANGER "There are enemies near!", // Class::Ranger
"Out of the shadows, I step!", // SHADOWKNIGHT "Out of the shadows, I step!", // Class::ShadowKnight
"Nature's fury shall be wrought!", // DRUID "Nature's fury shall be wrought!", // Class::Druid
"Your punishment will be my fist!", // MONK "Your punishment will be my fist!", // Class::Monk
"Music is the overture of battle! ", // BARD "Music is the overture of battle! ", // BARD
"Daggers into the backs of my enemies!", // ROGUE "Daggers into the backs of my enemies!", // Class::Rogue
"More bones to grind!", // SHAMAN "More bones to grind!", // Class::Shaman
"Death is only the beginning!", // NECROMANCER "Death is only the beginning!", // Class::Necromancer
"I am the harbinger of demise!", // WIZARD "I am the harbinger of demise!", // Class::Wizard
"The elements are at my command!", // MAGICIAN "The elements are at my command!", // Class::Magician
"No being can resist my charm!", // ENCHANTER "No being can resist my charm!", // Class::Enchanter
"Battles are won by hand and paw!", // BEASTLORD "Battles are won by hand and paw!", // Class::Beastlord
"My bloodthirst shall not be quenched!" // BERSERKER "My bloodthirst shall not be quenched!" // Class::Berserker
}; };
uint8 message_index = 0; uint8 message_index = 0;
@@ -7257,7 +7539,7 @@ void bot_subcommand_bot_toggle_archer(Client *c, const Seperator *sep)
} }
bot_iter->ChangeBotArcherWeapons(bot_iter->IsBotArcher()); bot_iter->ChangeBotArcherWeapons(bot_iter->IsBotArcher());
if (bot_iter->GetClass() == RANGER && bot_iter->GetLevel() >= 61) { if (bot_iter->GetClass() == Class::Ranger && bot_iter->GetLevel() >= 61) {
bot_iter->SetRangerAutoWeaponSelect(bot_iter->IsBotArcher()); bot_iter->SetRangerAutoWeaponSelect(bot_iter->IsBotArcher());
} }
} }
@@ -7467,7 +7749,7 @@ void bot_subcommand_circle(Client *c, const Seperator *sep)
return; return;
if (helper_is_help_or_usage(sep->arg[1])) { if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(Chat::White, "usage: %s [list | destination] ([option: single])", sep->arg[0]); c->Message(Chat::White, "usage: %s [list | destination] ([option: single])", sep->arg[0]);
helper_send_usage_required_bots(c, BCEnum::SpT_Depart, DRUID); helper_send_usage_required_bots(c, BCEnum::SpT_Depart, Class::Druid);
return; return;
} }
@@ -7478,7 +7760,7 @@ void bot_subcommand_circle(Client *c, const Seperator *sep)
std::string destination = sep->arg[1]; std::string destination = sep->arg[1];
if (!destination.compare("list")) { if (!destination.compare("list")) {
auto my_druid_bot = ActionableBots::AsGroupMember_ByClass(c, c, DRUID); auto my_druid_bot = ActionableBots::AsGroupMember_ByClass(c, c, Class::Druid);
helper_command_depart_list(c, my_druid_bot, nullptr, local_list, single); helper_command_depart_list(c, my_druid_bot, nullptr, local_list, single);
return; return;
} }
@@ -7497,7 +7779,7 @@ void bot_subcommand_circle(Client *c, const Seperator *sep)
auto local_entry = list_iter->SafeCastToDepart(); auto local_entry = list_iter->SafeCastToDepart();
if (helper_spell_check_fail(local_entry)) if (helper_spell_check_fail(local_entry))
continue; continue;
if (local_entry->caster_class != DRUID) if (local_entry->caster_class != Class::Druid)
continue; continue;
if (local_entry->single != single) if (local_entry->single != single)
continue; continue;
@@ -8988,7 +9270,7 @@ void bot_subcommand_pet_remove(Client *c, const Seperator *sep)
if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None)
return; return;
uint16 class_mask = (PLAYER_CLASS_DRUID_BIT | PLAYER_CLASS_NECROMANCER_BIT | PLAYER_CLASS_ENCHANTER_BIT); uint16 class_mask = (player_class_bitmasks[Class::Druid] | player_class_bitmasks[Class::Necromancer] | player_class_bitmasks[Class::Enchanter]);
ActionableBots::Filter_ByClasses(c, sbl, class_mask); ActionableBots::Filter_ByClasses(c, sbl, class_mask);
if (sbl.empty()) { if (sbl.empty()) {
c->Message(Chat::White, "You have no spawned bots capable of charming"); c->Message(Chat::White, "You have no spawned bots capable of charming");
@@ -9068,7 +9350,7 @@ void bot_subcommand_pet_set_type(Client *c, const Seperator *sep)
if (ActionableBots::PopulateSBL(c, sep->arg[2], sbl, ab_mask, sep->arg[3]) == ActionableBots::ABT_None) if (ActionableBots::PopulateSBL(c, sep->arg[2], sbl, ab_mask, sep->arg[3]) == ActionableBots::ABT_None)
return; return;
uint16 class_mask = PLAYER_CLASS_MAGICIAN_BIT; uint16 class_mask = player_class_bitmasks[Class::Magician];
ActionableBots::Filter_ByClasses(c, sbl, class_mask); ActionableBots::Filter_ByClasses(c, sbl, class_mask);
if (sbl.empty()) { if (sbl.empty()) {
c->Message(Chat::White, "You have no spawned Magician bots"); c->Message(Chat::White, "You have no spawned Magician bots");
@@ -9103,7 +9385,7 @@ void bot_subcommand_portal(Client *c, const Seperator *sep)
return; return;
if (helper_is_help_or_usage(sep->arg[1])) { if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(Chat::White, "usage: %s [list | destination] ([option: single])", sep->arg[0]); c->Message(Chat::White, "usage: %s [list | destination] ([option: single])", sep->arg[0]);
helper_send_usage_required_bots(c, BCEnum::SpT_Depart, WIZARD); helper_send_usage_required_bots(c, BCEnum::SpT_Depart, Class::Wizard);
return; return;
} }
@@ -9114,7 +9396,7 @@ void bot_subcommand_portal(Client *c, const Seperator *sep)
std::string destination = sep->arg[1]; std::string destination = sep->arg[1];
if (!destination.compare("list")) { if (!destination.compare("list")) {
auto my_wizard_bot = ActionableBots::AsGroupMember_ByClass(c, c, WIZARD); auto my_wizard_bot = ActionableBots::AsGroupMember_ByClass(c, c, Class::Wizard);
helper_command_depart_list(c, nullptr, my_wizard_bot, local_list, single); helper_command_depart_list(c, nullptr, my_wizard_bot, local_list, single);
return; return;
} }
@@ -9133,7 +9415,7 @@ void bot_subcommand_portal(Client *c, const Seperator *sep)
auto local_entry = list_iter->SafeCastToDepart(); auto local_entry = list_iter->SafeCastToDepart();
if (helper_spell_check_fail(local_entry)) if (helper_spell_check_fail(local_entry))
continue; continue;
if (local_entry->caster_class != WIZARD) if (local_entry->caster_class != Class::Wizard)
continue; continue;
if (local_entry->single != single) if (local_entry->single != single)
continue; continue;
@@ -9427,26 +9709,26 @@ void helper_bot_out_of_combat(Client *bot_owner, Bot *my_bot)
return; return;
switch (my_bot->GetClass()) { switch (my_bot->GetClass()) {
case WARRIOR: case Class::Warrior:
case CLERIC: case Class::Cleric:
case PALADIN: case Class::Paladin:
case RANGER: case Class::Ranger:
case SHADOWKNIGHT: case Class::ShadowKnight:
case DRUID: case Class::Druid:
case MONK: case Class::Monk:
bot_owner->Message(Chat::White, "%s has no out-of-combat behavior defined", my_bot->GetCleanName()); bot_owner->Message(Chat::White, "%s has no out-of-combat behavior defined", my_bot->GetCleanName());
break; break;
case BARD: case Class::Bard:
bot_owner->Message(Chat::White, "%s will %s use out-of-combat behavior for bard songs", my_bot->GetCleanName(), ((my_bot->GetAltOutOfCombatBehavior()) ? ("now") : ("no longer"))); bot_owner->Message(Chat::White, "%s will %s use out-of-combat behavior for bard songs", my_bot->GetCleanName(), ((my_bot->GetAltOutOfCombatBehavior()) ? ("now") : ("no longer")));
break; break;
case ROGUE: case Class::Rogue:
case SHAMAN: case Class::Shaman:
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
case BEASTLORD: case Class::Beastlord:
case BERSERKER: case Class::Berserker:
bot_owner->Message(Chat::White, "%s has no out-of-combat behavior defined", my_bot->GetCleanName()); bot_owner->Message(Chat::White, "%s has no out-of-combat behavior defined", my_bot->GetCleanName());
break; break;
default: default:
@@ -10438,6 +10720,61 @@ void bot_command_caster_range(Client* c, const Seperator* sep)
} }
} }
void bot_command_click_item(Client* c, const Seperator* sep)
{
if (!RuleB(Bots, BotsCanClickItems)) {
c->Message(Chat::White, "The ability for bots to click equipped items is currently disabled.");
return;
}
if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(Chat::White, "usage: <slot id> %s ([actionable: target | byname | ownergroup | ownerraid | targetgroup | namesgroup | byclass | byrace | spawned] ([actionable_name]))", sep->arg[0]);
c->Message(Chat::White, "This will cause the selected bots to click the item in the given slot ID.");
c->Message(Chat::White, "Use ^invlist to see their items along with slot IDs.");
return;
}
if (!sep->IsNumber(1)) {
c->Message(Chat::Yellow, "You must specify a slot ID. Use %s help for more information.", sep->arg[0]);
return;
}
const int ab_mask = ActionableBots::ABM_Type1;
int ab_arg = 1;
uint32 slot_id = 0;
if (sep->IsNumber(1)) {
ab_arg = 2;
slot_id = atoi(sep->arg[1]);
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END) {
c->Message(Chat::Yellow, "You must specify a valid inventory slot from 0 to 22. Use %s help for more information", sep->arg[0]);
return;
}
}
std::string class_race_arg = sep->arg[ab_arg];
bool class_race_check = false;
if (!class_race_arg.compare("byclass") || !class_race_arg.compare("byrace")) {
class_race_check = true;
}
std::list<Bot*> sbl;
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg + 1] : nullptr, class_race_check ? atoi(sep->arg[ab_arg + 1]) : 0) == ActionableBots::ABT_None) {
return;
}
sbl.remove(nullptr);
for (auto my_bot : sbl) {
if (RuleI(Bots, BotsClickItemsMinLvl) > my_bot->GetLevel()) {
c->Message(Chat::White, "%s must be level %i to use clickable items.", my_bot->GetCleanName(), RuleI(Bots, BotsClickItemsMinLvl));
continue;
}
my_bot->TryItemClick(slot_id);
}
}
void bot_command_pickpocket(Client *c, const Seperator *sep) void bot_command_pickpocket(Client *c, const Seperator *sep)
{ {
if (helper_command_disabled(c, RuleB(Bots, AllowPickpocketCommand), "pickpocket")) { if (helper_command_disabled(c, RuleB(Bots, AllowPickpocketCommand), "pickpocket")) {
@@ -10457,8 +10794,8 @@ void bot_command_pickpocket(Client *c, const Seperator *sep)
MyBots::PopulateSBL_BySpawnedBots(c, sbl); MyBots::PopulateSBL_BySpawnedBots(c, sbl);
// Check for capable rogue // Check for capable rogue
ActionableBots::Filter_ByClasses(c, sbl, PLAYER_CLASS_ROGUE_BIT); ActionableBots::Filter_ByClasses(c, sbl, player_class_bitmasks[Class::Rogue]);
Bot *my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 7, ROGUE); Bot *my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 7, Class::Rogue);
if (!my_bot) { if (!my_bot) {
c->Message(Chat::White, "No bots are capable of performing this action"); c->Message(Chat::White, "No bots are capable of performing this action");
return; return;
+3 -1
View File
@@ -554,6 +554,7 @@ void bot_command_bind_affinity(Client *c, const Seperator *sep);
void bot_command_bot(Client *c, const Seperator *sep); void bot_command_bot(Client *c, const Seperator *sep);
void bot_command_caster_range(Client* c, const Seperator* sep); void bot_command_caster_range(Client* c, const Seperator* sep);
void bot_command_charm(Client *c, const Seperator *sep); void bot_command_charm(Client *c, const Seperator *sep);
void bot_command_click_item(Client* c, const Seperator* sep);
void bot_command_cure(Client *c, const Seperator *sep); void bot_command_cure(Client *c, const Seperator *sep);
void bot_command_defensive(Client *c, const Seperator *sep); void bot_command_defensive(Client *c, const Seperator *sep);
void bot_command_depart(Client *c, const Seperator *sep); void bot_command_depart(Client *c, const Seperator *sep);
@@ -595,6 +596,7 @@ void bot_command_enforce_spell_list(Client* c, const Seperator* sep);
void bot_command_summon_corpse(Client *c, const Seperator *sep); void bot_command_summon_corpse(Client *c, const Seperator *sep);
void bot_command_suspend(Client *c, const Seperator *sep); void bot_command_suspend(Client *c, const Seperator *sep);
void bot_command_taunt(Client *c, const Seperator *sep); void bot_command_taunt(Client *c, const Seperator *sep);
void bot_command_timer(Client* c, const Seperator* sep);
void bot_command_track(Client *c, const Seperator *sep); void bot_command_track(Client *c, const Seperator *sep);
void bot_command_view_combos(Client *c, const Seperator *sep); void bot_command_view_combos(Client *c, const Seperator *sep);
void bot_command_water_breathing(Client *c, const Seperator *sep); void bot_command_water_breathing(Client *c, const Seperator *sep);
@@ -677,7 +679,7 @@ void helper_command_depart_list(Client* bot_owner, Bot* druid_bot, Bot* wizard_b
bool helper_is_help_or_usage(const char* arg); bool helper_is_help_or_usage(const char* arg);
bool helper_no_available_bots(Client *bot_owner, Bot *my_bot = nullptr); bool helper_no_available_bots(Client *bot_owner, Bot *my_bot = nullptr);
void helper_send_available_subcommands(Client *bot_owner, const char* command_simile, const std::list<const char*>& subcommand_list); void helper_send_available_subcommands(Client *bot_owner, const char* command_simile, const std::list<const char*>& subcommand_list);
void helper_send_usage_required_bots(Client *bot_owner, BCEnum::SpType spell_type, uint8 bot_class = NO_CLASS); void helper_send_usage_required_bots(Client *bot_owner, BCEnum::SpType spell_type, uint8 bot_class = Class::None);
bool helper_spell_check_fail(STBaseEntry* local_entry); bool helper_spell_check_fail(STBaseEntry* local_entry);
bool helper_spell_list_fail(Client *bot_owner, bcst_list* spell_list, BCEnum::SpType spell_type); bool helper_spell_list_fail(Client *bot_owner, bcst_list* spell_list, BCEnum::SpType spell_type);
#endif #endif
+78 -55
View File
@@ -24,6 +24,7 @@
#include "../common/repositories/bot_data_repository.h" #include "../common/repositories/bot_data_repository.h"
#include "../common/repositories/bot_inventories_repository.h" #include "../common/repositories/bot_inventories_repository.h"
#include "../common/repositories/bot_timers_repository.h"
#include "zonedb.h" #include "zonedb.h"
#include "bot.h" #include "bot.h"
@@ -141,7 +142,7 @@ bool BotDatabase::LoadBotSpellCastingChances()
if (spell_type_index >= Bot::SPELL_TYPE_COUNT) if (spell_type_index >= Bot::SPELL_TYPE_COUNT)
continue; continue;
uint8 class_index = Strings::ToInt(row[1]); uint8 class_index = Strings::ToInt(row[1]);
if (class_index < WARRIOR || class_index > BERSERKER) if (class_index < Class::Warrior || class_index > Class::Berserker)
continue; continue;
--class_index; --class_index;
uint8 stance_index = Strings::ToInt(row[2]); uint8 stance_index = Strings::ToInt(row[2]);
@@ -224,7 +225,7 @@ bool BotDatabase::QueryBotCount(const uint32 owner_id, int class_id, uint32& bot
auto row = results.begin(); auto row = results.begin();
bot_count = Strings::ToUnsignedInt(row[0]); bot_count = Strings::ToUnsignedInt(row[0]);
if (EQ::ValueWithin(class_id, WARRIOR, BERSERKER)) { if (EQ::ValueWithin(class_id, Class::Warrior, Class::Berserker)) {
query = fmt::format( query = fmt::format(
"SELECT COUNT(`bot_id`) FROM `bot_data` WHERE `owner_id` = {} AND `class` = {}", "SELECT COUNT(`bot_id`) FROM `bot_data` WHERE `owner_id` = {} AND `class` = {}",
owner_id, owner_id,
@@ -917,45 +918,39 @@ bool BotDatabase::LoadTimers(Bot* bot_inst)
if (!bot_inst) if (!bot_inst)
return false; return false;
query = StringFormat( auto timers = BotTimersRepository::GetWhere(
"SELECT" database,
" IfNull(bt.`timer_id`, '0') As timer_id," fmt::format("bot_id = {}", bot_inst->GetBotID())
" IfNull(bt.`timer_value`, '0') As timer_value,"
" IfNull(MAX(sn.`recast_time`), '0') AS MaxTimer"
" FROM `bot_timers` bt, `spells_new` sn"
" WHERE bt.`bot_id` = '%u' AND sn.`EndurTimerIndex` = ("
"SELECT case"
" WHEN timer_id > '%i' THEN timer_id - '%i'"
" ELSE timer_id END AS timer_id"
" FROM `bot_timers` WHERE `timer_id` = bt.`timer_id` AND `bot_id` = bt.`bot_id`" // double-check validity
")"
" AND sn.`classes%i` <= '%i'",
bot_inst->GetBotID(),
(DisciplineReuseStart - 1),
(DisciplineReuseStart - 1),
bot_inst->GetClass(),
bot_inst->GetLevel()
); );
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
if (!results.RowCount())
return true;
uint32* bot_timers = bot_inst->GetTimers(); std::vector<BotTimer_Struct> bot_timers;
if (!bot_timers)
return false;
int timer_id = 0; BotTimer_Struct t{};
uint32 timer_value = 0; t.timer_id = 0;
uint32 max_value = 0; t.timer_value = 0;
for (auto row = results.begin(); row != results.end(); ++row) { t.recast_time = 0;
timer_id = Strings::ToInt(row[0]) - 1; t.is_spell = false;
timer_value = Strings::ToInt(row[1]); t.is_disc = false;
max_value = Strings::ToInt(row[2]); t.spell_id = 0;
t.is_item = false;
t.item_id = 0;
if (timer_id >= 0 && timer_id < MaxTimer && timer_value < (Timer::GetCurrentTime() + max_value)) for (auto& timer : timers) {
bot_timers[timer_id] = timer_value; if (t.timer_value < (Timer::GetCurrentTime() + t.recast_time)) {
t.timer_id = timer.timer_id;
t.timer_value = timer.timer_value;
t.recast_time = timer.recast_time;
t.is_spell = timer.is_spell ? true : false;
t.is_disc = timer.is_disc ? true : false;
t.spell_id = timer.spell_id;
t.is_item = timer.is_item ? true : false;
t.item_id = timer.item_id;
bot_timers.push_back(t);
}
}
if (!bot_timers.empty()) {
bot_inst->SetBotTimers(bot_timers);
} }
return true; return true;
@@ -963,26 +958,56 @@ bool BotDatabase::LoadTimers(Bot* bot_inst)
bool BotDatabase::SaveTimers(Bot* bot_inst) bool BotDatabase::SaveTimers(Bot* bot_inst)
{ {
if (!bot_inst) if (!bot_inst) {
return false; return false;
}
if (!DeleteTimers(bot_inst->GetBotID())) if (!DeleteTimers(bot_inst->GetBotID())) {
return false; return false;
}
uint32* bot_timers = bot_inst->GetTimers(); std::vector<BotTimer_Struct> bot_timers = bot_inst->GetBotTimers();
if (!bot_timers)
return false;
for (int timer_index = 0; timer_index < MaxTimer; ++timer_index) { if (bot_timers.empty()) {
if (bot_timers[timer_index] <= Timer::GetCurrentTime()) return true;
}
std::vector<BotTimersRepository::BotTimers> timers;
if (!bot_timers.empty()) {
for (auto & bot_timer : bot_timers) {
if (bot_timer.timer_value <= Timer::GetCurrentTime()) {
continue; continue;
}
query = fmt::format( auto t = BotTimersRepository::BotTimers{
"REPLACE INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) VALUES ('{}', '{}', '{}')", .bot_id = bot_inst->GetBotID(),
bot_inst->GetBotID(), (timer_index + 1), bot_timers[timer_index] .timer_id = bot_timer.timer_id,
.timer_value = bot_timer.timer_value,
.recast_time = bot_timer.recast_time,
.is_spell = bot_timer.is_spell ? true : false,
.is_disc = bot_timer.is_disc ? true : false,
.spell_id = bot_timer.spell_id,
.is_item = bot_timer.is_item ? true : false,
.item_id = bot_timer.item_id
};
timers.push_back(t);
}
if (timers.empty()) {
return true;
}
// delete existing
BotTimersRepository::DeleteWhere(
database,
fmt::format("bot_id = {}", bot_inst->GetBotID())
); );
auto results = database.QueryDatabase(query);
if (!results.Success()) { // bulk insert current
auto success = BotTimersRepository::InsertMany(database, timers);
if (!success) {
DeleteTimers(bot_inst->GetBotID()); DeleteTimers(bot_inst->GetBotID());
return false; return false;
} }
@@ -993,13 +1018,11 @@ bool BotDatabase::SaveTimers(Bot* bot_inst)
bool BotDatabase::DeleteTimers(const uint32 bot_id) bool BotDatabase::DeleteTimers(const uint32 bot_id)
{ {
if (!bot_id) if (!bot_id) {
return false; return false;
}
query = StringFormat("DELETE FROM `bot_timers` WHERE `bot_id` = '%u'", bot_id); BotTimersRepository::DeleteWhere(database, fmt::format("bot_id = {}", bot_id));
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
return true; return true;
} }
@@ -2517,7 +2540,7 @@ uint8 BotDatabase::GetSpellCastingChance(uint8 spell_type_index, uint8 class_ind
{ {
if (spell_type_index >= Bot::SPELL_TYPE_COUNT) if (spell_type_index >= Bot::SPELL_TYPE_COUNT)
return 0; return 0;
if (class_index >= PLAYER_CLASS_COUNT) if (class_index >= Class::PLAYER_CLASS_COUNT)
return 0; return 0;
if (stance_index >= EQ::constants::STANCE_TYPE_COUNT) if (stance_index >= EQ::constants::STANCE_TYPE_COUNT)
return 0; return 0;
+11
View File
@@ -81,4 +81,15 @@ struct BotSpells_Struct {
uint8 bucket_comparison; uint8 bucket_comparison;
}; };
struct BotTimer_Struct {
uint32 timer_id;
uint32 timer_value;
uint32 recast_time;
bool is_spell;
bool is_disc;
uint16 spell_id;
bool is_item;
uint32 item_id;
};
#endif // BOT_STRUCTS #endif // BOT_STRUCTS
+112 -177
View File
@@ -101,14 +101,14 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
bool Bot::BotCastSong(Mob* tar, uint8 botLevel) { bool Bot::BotCastSong(Mob* tar, uint8 botLevel) {
bool casted_spell = false; bool casted_spell = false;
if (GetClass() != BARD || tar != this || IsEngaged()) // Out-of-Combat songs can not be cast in combat if (GetClass() != Class::Bard || tar != this || IsEngaged()) // Out-of-Combat songs can not be cast in combat
return casted_spell; return casted_spell;
for (auto botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_OutOfCombatBuffSong); for (auto botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_OutOfCombatBuffSong);
auto iter : botSongList) { auto iter : botSongList) {
if (!iter.SpellId) if (!iter.SpellId)
continue; continue;
if (!CheckSpellRecastTimers(this, iter.SpellIndex)) if (!CheckSpellRecastTimer(iter.SpellId))
continue; continue;
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType())) if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
continue; continue;
@@ -142,7 +142,7 @@ bool Bot::BotCastCombatSong(Mob* tar, uint8 botLevel) {
auto iter : botSongList) { auto iter : botSongList) {
if (!iter.SpellId) if (!iter.SpellId)
continue; continue;
if (!CheckSpellRecastTimers(this, iter.SpellIndex)) if (!CheckSpellRecastTimer(iter.SpellId))
continue; continue;
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType())) if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
continue; continue;
@@ -169,12 +169,12 @@ bool Bot::BotCastCombatSong(Mob* tar, uint8 botLevel) {
bool Bot::BotCastHateReduction(Mob* tar, uint8 botLevel, const BotSpell& botSpell) { bool Bot::BotCastHateReduction(Mob* tar, uint8 botLevel, const BotSpell& botSpell) {
bool casted_spell = false; bool casted_spell = false;
if (GetClass() == BARD) { if (GetClass() == Class::Bard) {
std::list<BotSpell_wPriority> botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_HateRedux); std::list<BotSpell_wPriority> botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_HateRedux);
for (auto iter : botSongList) { for (auto iter : botSongList) {
if (!iter.SpellId) if (!iter.SpellId)
continue; continue;
if (!CheckSpellRecastTimers(this, iter.SpellIndex)) if (!CheckSpellRecastTimer(iter.SpellId))
continue; continue;
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType())) if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
continue; continue;
@@ -220,7 +220,7 @@ bool Bot::BotCastCure(Mob* tar, uint8 botClass, BotSpell& botSpell, Raid* raid)
casted_spell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontCureMeBeforeTime); casted_spell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontCureMeBeforeTime);
if (casted_spell && botClass != BARD) { if (casted_spell && botClass != Class::Bard) {
if (IsGroupSpell(botSpell.SpellId)) { if (IsGroupSpell(botSpell.SpellId)) {
if (HasGroup()) { if (HasGroup()) {
Group const* group = GetGroup(); Group const* group = GetGroup();
@@ -301,7 +301,7 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
} }
switch (botClass) { switch (botClass) {
case BARD: { case Class::Bard: {
// probably needs attackable check // probably needs attackable check
for ( for (
auto botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_Slow); auto botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_Slow);
@@ -312,7 +312,7 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
continue; continue;
} }
if (!CheckSpellRecastTimers(this, iter.SpellIndex)) { if (!CheckSpellRecastTimer(iter.SpellId)) {
continue; continue;
} }
@@ -339,12 +339,12 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
break; break;
} }
case ENCHANTER: { case Class::Enchanter: {
botSpell = GetBestBotSpellForMagicBasedSlow(this); botSpell = GetBestBotSpellForMagicBasedSlow(this);
break; break;
} }
case SHAMAN: case Class::Shaman:
case BEASTLORD: { case Class::Beastlord: {
botSpell = GetBestBotSpellForDiseaseBasedSlow(this); botSpell = GetBestBotSpellForDiseaseBasedSlow(this);
if (botSpell.SpellId == 0 || ((tar->GetMR() - 50) < (tar->GetDR() + spells[botSpell.SpellId].resist_difficulty))) if (botSpell.SpellId == 0 || ((tar->GetMR() - 50) < (tar->GetDR() + spells[botSpell.SpellId].resist_difficulty)))
@@ -364,7 +364,7 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
casted_spell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); casted_spell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost);
} }
if (casted_spell && GetClass() != BARD) { if (casted_spell && GetClass() != Class::Bard) {
if (raid) { if (raid) {
const auto msg = fmt::format("Attempting to slow {}.", tar->GetCleanName()); const auto msg = fmt::format("Attempting to slow {}.", tar->GetCleanName());
raid->RaidSay(msg.c_str(), GetCleanName(), 0, 100); raid->RaidSay(msg.c_str(), GetCleanName(), 0, 100);
@@ -391,7 +391,7 @@ bool Bot::BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const b
return casted_spell; return casted_spell;
} }
if (GetClass() == BARD) { if (GetClass() == Class::Bard) {
std::list<BotSpell_wPriority> dotList = GetPrioritizedBotSpellsBySpellType(this, SpellType_DOT); std::list<BotSpell_wPriority> dotList = GetPrioritizedBotSpellsBySpellType(this, SpellType_DOT);
const int maxDotSelect = 5; const int maxDotSelect = 5;
@@ -403,7 +403,7 @@ bool Bot::BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const b
continue; continue;
} }
if (CheckSpellRecastTimers(this, s.SpellIndex)) if (CheckSpellRecastTimer(s.SpellId))
{ {
if (!(!tar->IsImmuneToSpell(s.SpellId, this) && tar->CanBuffStack(s.SpellId, botLevel, true) >= 0)) { if (!(!tar->IsImmuneToSpell(s.SpellId, this) && tar->CanBuffStack(s.SpellId, botLevel, true) >= 0)) {
@@ -438,7 +438,7 @@ bool Bot::BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const b
continue; continue;
} }
if (CheckSpellRecastTimers(this, s.SpellIndex)) { if (CheckSpellRecastTimer(s.SpellId)) {
if (!(!tar->IsImmuneToSpell(s.SpellId, this) && if (!(!tar->IsImmuneToSpell(s.SpellId, this) &&
tar->CanBuffStack(s.SpellId, botLevel, true) >= 0)) { tar->CanBuffStack(s.SpellId, botLevel, true) >= 0)) {
@@ -569,7 +569,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
(tar == this && spells[s.SpellId].target_type != ST_TargetsTarget) || (tar == this && spells[s.SpellId].target_type != ST_TargetsTarget) ||
spells[s.SpellId].target_type == ST_Group || spells[s.SpellId].target_type == ST_Group ||
spells[s.SpellId].target_type == ST_GroupTeleport || spells[s.SpellId].target_type == ST_GroupTeleport ||
(botClass == BARD && spells[s.SpellId].target_type == ST_AEBard) (botClass == Class::Bard && spells[s.SpellId].target_type == ST_AEBard)
) && ) &&
!tar->IsImmuneToSpell(s.SpellId, this) && !tar->IsImmuneToSpell(s.SpellId, this) &&
tar->CanBuffStack(s.SpellId, botLevel, true) >= 0 tar->CanBuffStack(s.SpellId, botLevel, true) >= 0
@@ -582,7 +582,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
if ( if (
((IsEffectInSpell(s.SpellId, SE_Levitate) && !zone->CanLevitate()) || ((IsEffectInSpell(s.SpellId, SE_Levitate) && !zone->CanLevitate()) ||
(IsEffectInSpell(s.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())) && (IsEffectInSpell(s.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())) &&
(botClass != BARD || !IsSpellUsableInThisZoneType(s.SpellId, zone->GetZoneType())) (botClass != Class::Bard || !IsSpellUsableInThisZoneType(s.SpellId, zone->GetZoneType()))
) { ) {
continue; continue;
} }
@@ -625,7 +625,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
} }
} }
// TODO: Add TriggerSpell Support for Exchanter Runes // TODO: Add TriggerSpell Support for Exchanter Runes
if (botClass == ENCHANTER && IsEffectInSpell(s.SpellId, SE_Rune)) { if (botClass == Class::Enchanter && IsEffectInSpell(s.SpellId, SE_Rune)) {
float manaRatioToCast = 75.0f; float manaRatioToCast = 75.0f;
switch(GetBotStance()) { switch(GetBotStance()) {
@@ -652,7 +652,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
} }
} }
if (CheckSpellRecastTimers(this, s.SpellIndex)) { if (CheckSpellRecastTimer(s.SpellId)) {
uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore(); uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore();
casted_spell = AIDoSpellCast(s.SpellIndex, tar, s.ManaCost, &TempDontBuffMeBefore); casted_spell = AIDoSpellCast(s.SpellIndex, tar, s.ManaCost, &TempDontBuffMeBefore);
if (TempDontBuffMeBefore != tar->DontBuffMeBefore()) { if (TempDontBuffMeBefore != tar->DontBuffMeBefore()) {
@@ -671,7 +671,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
bool Bot::BotCastPet(Mob* tar, uint8 botClass, BotSpell& botSpell) { bool Bot::BotCastPet(Mob* tar, uint8 botClass, BotSpell& botSpell) {
bool casted_spell = false; bool casted_spell = false;
if (!IsPet() && !GetPetID() && !IsBotCharmer()) { if (!IsPet() && !GetPetID() && !IsBotCharmer()) {
if (botClass == WIZARD) { if (botClass == Class::Wizard) {
auto buffs_max = GetMaxBuffSlots(); auto buffs_max = GetMaxBuffSlots();
auto my_buffs = GetBuffs(); auto my_buffs = GetBuffs();
int familiar_buff_slot = -1; int familiar_buff_slot = -1;
@@ -694,7 +694,7 @@ bool Bot::BotCastPet(Mob* tar, uint8 botClass, BotSpell& botSpell) {
botSpell = GetFirstBotSpellBySpellType(this, SpellType_Pet); botSpell = GetFirstBotSpellBySpellType(this, SpellType_Pet);
} }
else if (botClass == MAGICIAN) { else if (botClass == Class::Magician) {
botSpell = GetBestBotMagicianPetSpell(this); botSpell = GetBestBotMagicianPetSpell(this);
} }
else { else {
@@ -735,13 +735,13 @@ bool Bot::BotCastDispel(Mob* tar, BotSpell& botSpell, uint32 iSpellTypes, const
bool Bot::BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, const bool& checked_los) { bool Bot::BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, const bool& checked_los) {
bool casted_spell = false; bool casted_spell = false;
if ((tar->GetHPRatio() <= 95.0f) || ((botClass == BARD) || (botClass == SHAMAN) || (botClass == ENCHANTER) || (botClass == PALADIN) || (botClass == SHADOWKNIGHT) || (botClass == WARRIOR))) if ((tar->GetHPRatio() <= 95.0f) || ((botClass == Class::Bard) || (botClass == Class::Shaman) || (botClass == Class::Enchanter) || (botClass == Class::Paladin) || (botClass == Class::ShadowKnight) || (botClass == Class::Warrior)))
{ {
if (!checked_los && (!CheckLosFN(tar) || !CheckWaterLoS(tar))) { if (!checked_los && (!CheckLosFN(tar) || !CheckWaterLoS(tar))) {
return casted_spell; return casted_spell;
} }
if (botClass == CLERIC || botClass == ENCHANTER) if (botClass == Class::Cleric || botClass == Class::Enchanter)
{ {
float manaRatioToCast = 75.0f; float manaRatioToCast = 75.0f;
@@ -770,17 +770,17 @@ bool Bot::BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
return casted_spell; return casted_spell;
} }
if (botClass == MAGICIAN || botClass == SHADOWKNIGHT || botClass == NECROMANCER || botClass == PALADIN || botClass == RANGER || botClass == DRUID || botClass == CLERIC) { if (botClass == Class::Magician || botClass == Class::ShadowKnight || botClass == Class::Necromancer || botClass == Class::Paladin || botClass == Class::Ranger || botClass == Class::Druid || botClass == Class::Cleric) {
if (tar->GetBodyType() == BT_Undead || tar->GetBodyType() == BT_SummonedUndead || tar->GetBodyType() == BT_Vampire) if (tar->GetBodyType() == BT_Undead || tar->GetBodyType() == BT_SummonedUndead || tar->GetBodyType() == BT_Vampire)
botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Undead); botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Undead);
else if (tar->GetBodyType() == BT_Summoned || tar->GetBodyType() == BT_Summoned2 || tar->GetBodyType() == BT_Summoned3) else if (tar->GetBodyType() == BT_Summoned || tar->GetBodyType() == BT_Summoned2 || tar->GetBodyType() == BT_Summoned3)
botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Summoned); botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Summoned);
} }
if ((botClass == PALADIN || botClass == DRUID || botClass == CLERIC || botClass == ENCHANTER || botClass == WIZARD) && !IsValidSpell(botSpell.SpellId)) { if ((botClass == Class::Paladin || botClass == Class::Druid || botClass == Class::Cleric || botClass == Class::Enchanter || botClass == Class::Wizard) && !IsValidSpell(botSpell.SpellId)) {
uint8 stunChance = (tar->IsCasting() ? 30: 15); uint8 stunChance = (tar->IsCasting() ? 30: 15);
if (botClass == PALADIN) { if (botClass == Class::Paladin) {
stunChance = 50; stunChance = 50;
} }
@@ -789,7 +789,7 @@ bool Bot::BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
} }
} }
if (botClass == WIZARD && botSpell.SpellId == 0) { if (botClass == Class::Wizard && botSpell.SpellId == 0) {
botSpell = GetBestBotWizardNukeSpellByTargetResists(this, tar); botSpell = GetBestBotWizardNukeSpellByTargetResists(this, tar);
} }
@@ -819,7 +819,7 @@ bool Bot::BotCastEscape(Mob*& tar, uint8 botClass, BotSpell& botSpell, uint32 iS
auto hpr = (uint8) GetHPRatio(); auto hpr = (uint8) GetHPRatio();
bool mayGetAggro = false; bool mayGetAggro = false;
if (hpr > 15 && ((botClass == WIZARD) || (botClass == ENCHANTER) || (botClass == RANGER))) { if (hpr > 15 && ((botClass == Class::Wizard) || (botClass == Class::Enchanter) || (botClass == Class::Ranger))) {
mayGetAggro = HasOrMayGetAggro(); mayGetAggro = HasOrMayGetAggro();
} }
@@ -835,7 +835,7 @@ bool Bot::BotCastEscape(Mob*& tar, uint8 botClass, BotSpell& botSpell, uint32 iS
tar = this; //target self for invul type spells tar = this; //target self for invul type spells
} }
if (IsValidSpellRange(botSpell.SpellId, tar) || botClass == BARD) { if (IsValidSpellRange(botSpell.SpellId, tar) || botClass == Class::Bard) {
casted_spell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); casted_spell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost);
} }
} }
@@ -877,7 +877,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
(tar == this && spells[s.SpellId].target_type != ST_TargetsTarget) || (tar == this && spells[s.SpellId].target_type != ST_TargetsTarget) ||
spells[s.SpellId].target_type == ST_Group || spells[s.SpellId].target_type == ST_Group ||
spells[s.SpellId].target_type == ST_GroupTeleport || spells[s.SpellId].target_type == ST_GroupTeleport ||
(botClass == BARD && spells[s.SpellId].target_type == ST_AEBard) (botClass == Class::Bard && spells[s.SpellId].target_type == ST_AEBard)
) && ) &&
!tar->IsImmuneToSpell(s.SpellId, this) && !tar->IsImmuneToSpell(s.SpellId, this) &&
tar->CanBuffStack(s.SpellId, botLevel, true) >= 0 tar->CanBuffStack(s.SpellId, botLevel, true) >= 0
@@ -892,7 +892,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
(IsEffectInSpell(s.SpellId, SE_Levitate) && !zone->CanLevitate()) || (IsEffectInSpell(s.SpellId, SE_Levitate) && !zone->CanLevitate()) ||
(IsEffectInSpell(s.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor()) (IsEffectInSpell(s.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())
) && ) &&
(botClass != BARD || !IsSpellUsableInThisZoneType(s.SpellId, zone->GetZoneType())) (botClass != Class::Bard || !IsSpellUsableInThisZoneType(s.SpellId, zone->GetZoneType()))
) { ) {
continue; continue;
} }
@@ -919,7 +919,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
break; break;
} }
if (botClass == ENCHANTER && IsEffectInSpell(s.SpellId, SE_Rune)) if (botClass == Class::Enchanter && IsEffectInSpell(s.SpellId, SE_Rune))
{ {
float manaRatioToCast = 75.0f; float manaRatioToCast = 75.0f;
@@ -947,7 +947,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
} }
} }
if (CheckSpellRecastTimers(this, s.SpellIndex)) if (CheckSpellRecastTimer(s.SpellId))
{ {
uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore(); uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore();
@@ -1003,17 +1003,17 @@ bool Bot::BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
isPrimaryHealer = IsGroupHealer(); isPrimaryHealer = IsGroupHealer();
} }
if (hpr < 95 || tar->IsClient() || botClass == BARD) { if (hpr < 95 || tar->IsClient() || botClass == Class::Bard) {
if (tar->GetClass() == NECROMANCER && hpr >= 40) { if (tar->GetClass() == Class::Necromancer && hpr >= 40) {
return false; return false;
} }
if (tar->GetClass() == SHAMAN && hpr >= 80) { if (tar->GetClass() == Class::Shaman && hpr >= 80) {
return false; return false;
} }
// Evaluate the situation // Evaluate the situation
if ((IsEngaged()) && ((botClass == CLERIC) || (botClass == DRUID) || (botClass == SHAMAN) || (botClass == PALADIN))) { if ((IsEngaged()) && ((botClass == Class::Cleric) || (botClass == Class::Druid) || (botClass == Class::Shaman) || (botClass == Class::Paladin))) {
if (tar->GetTarget() && tar->GetTarget()->GetHateTop() && tar->GetTarget()->GetHateTop() == tar) { if (tar->GetTarget() && tar->GetTarget()->GetHateTop() && tar->GetTarget()->GetHateTop() == tar) {
hasAggro = true; hasAggro = true;
} }
@@ -1045,7 +1045,7 @@ bool Bot::BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
} }
} }
} }
else if ((botClass == CLERIC) || (botClass == DRUID) || (botClass == SHAMAN) || (botClass == PALADIN)) { else if ((botClass == Class::Cleric) || (botClass == Class::Druid) || (botClass == Class::Shaman) || (botClass == Class::Paladin)) {
if (GetNumberNeedingHealedInGroup(40, true, raid) >= 2) { if (GetNumberNeedingHealedInGroup(40, true, raid) >= 2) {
botSpell = GetBestBotSpellForGroupCompleteHeal(this); botSpell = GetBestBotSpellForGroupCompleteHeal(this);
@@ -1119,7 +1119,7 @@ bool Bot::BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
if (!IsValidSpell(botSpell.SpellId)) { if (!IsValidSpell(botSpell.SpellId)) {
botSpell = GetFirstBotSpellForSingleTargetHeal(this); botSpell = GetFirstBotSpellForSingleTargetHeal(this);
} }
if (botSpell.SpellId == 0 && botClass == BARD) { if (botSpell.SpellId == 0 && botClass == Class::Bard) {
botSpell = GetFirstBotSpellBySpellType(this, SpellType_Heal); botSpell = GetFirstBotSpellBySpellType(this, SpellType_Heal);
} }
@@ -1134,11 +1134,11 @@ bool Bot::BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
uint32 TempDontHealMeBeforeTime = tar->DontHealMeBefore(); uint32 TempDontHealMeBeforeTime = tar->DontHealMeBefore();
if (IsValidSpellRange(botSpell.SpellId, tar) || botClass == BARD) { if (IsValidSpellRange(botSpell.SpellId, tar) || botClass == Class::Bard) {
casted_spell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontHealMeBeforeTime); casted_spell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontHealMeBeforeTime);
} }
if (casted_spell && botClass != BARD) { if (casted_spell && botClass != Class::Bard) {
if (IsGroupSpell(botSpell.SpellId)) { if (IsGroupSpell(botSpell.SpellId)) {
if (HasGroup()) { if (HasGroup()) {
Group *group = GetGroup(); Group *group = GetGroup();
@@ -1306,10 +1306,8 @@ bool Bot::AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
SetMana(hasMana); SetMana(hasMana);
} }
else { else {
AIBot_spells[i].time_cancast = Timer::GetCurrentTime() + spells[AIBot_spells[i].spellid].recast_time; if (CalcSpellRecastTimer(AIBot_spells[i].spellid) > 0) {
SetSpellRecastTimer(AIBot_spells[i].spellid);
if (spells[AIBot_spells[i].spellid].timer_id > 0) {
SetSpellRecastTimer(spells[AIBot_spells[i].spellid].timer_id, spells[AIBot_spells[i].spellid].recast_time);
} }
} }
@@ -1362,9 +1360,9 @@ bool Bot::AI_IdleCastCheck() {
//Ok, IdleCastCheck depends of class. //Ok, IdleCastCheck depends of class.
switch (GetClass()) { switch (GetClass()) {
// Healers WITHOUT pets will check if a heal is needed before buffing. // Healers WITHOUT pets will check if a heal is needed before buffing.
case CLERIC: case Class::Cleric:
case PALADIN: case Class::Paladin:
case RANGER: { case Class::Ranger: {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Heal)) { if (!AICastSpell(this, 100, SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) {
@@ -1379,10 +1377,10 @@ bool Bot::AI_IdleCastCheck() {
result = true; result = true;
break; break;
} }
case MONK: case Class::Monk:
case ROGUE: case Class::Rogue:
case WARRIOR: case Class::Warrior:
case BERSERKER: { case Class::Berserker: {
if (!AICastSpell(this, 100, SpellType_Cure)) { if (!AICastSpell(this, 100, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Heal)) { if (!AICastSpell(this, 100, SpellType_Heal)) {
if (!AICastSpell(this, 100, SpellType_Buff)) { if (!AICastSpell(this, 100, SpellType_Buff)) {
@@ -1397,10 +1395,10 @@ bool Bot::AI_IdleCastCheck() {
} }
// Pets class will first cast their pet, then buffs // Pets class will first cast their pet, then buffs
case MAGICIAN: case Class::Magician:
case SHADOWKNIGHT: case Class::ShadowKnight:
case NECROMANCER: case Class::Necromancer:
case ENCHANTER: { case Class::Enchanter: {
if (!AICastSpell(this, 100, SpellType_Pet)) { if (!AICastSpell(this, 100, SpellType_Pet)) {
if (!AICastSpell(this, 100, SpellType_Cure)) { if (!AICastSpell(this, 100, SpellType_Cure)) {
if (!AICastSpell(GetPet(), 100, SpellType_Cure)) { if (!AICastSpell(GetPet(), 100, SpellType_Cure)) {
@@ -1417,9 +1415,9 @@ bool Bot::AI_IdleCastCheck() {
result = true; result = true;
break; break;
} }
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
case BEASTLORD: { case Class::Beastlord: {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Pet)) { if (!AICastSpell(this, 100, SpellType_Pet)) {
if (!AICastSpell(this, 100, SpellType_Heal)) { if (!AICastSpell(this, 100, SpellType_Heal)) {
@@ -1438,7 +1436,7 @@ bool Bot::AI_IdleCastCheck() {
result = true; result = true;
break; break;
} }
case WIZARD: { // This can eventually be move into the BEASTLORD case handler once pre-combat is fully implemented case Class::Wizard: { // This can eventually be move into the Class::Beastlord case handler once pre-combat is fully implemented
if (pre_combat) { if (pre_combat) {
if (!AICastSpell(this, 100, SpellType_Pet)) { if (!AICastSpell(this, 100, SpellType_Pet)) {
if (!AICastSpell(this, 100, SpellType_Cure)) { if (!AICastSpell(this, 100, SpellType_Cure)) {
@@ -1469,7 +1467,7 @@ bool Bot::AI_IdleCastCheck() {
result = true; result = true;
break; break;
} }
case BARD: { case Class::Bard: {
if (pre_combat) { if (pre_combat) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Buff)) { if (!AICastSpell(this, 100, SpellType_Buff)) {
@@ -1518,7 +1516,7 @@ bool Bot::AI_EngagedCastCheck() {
LogAIDetail("Engaged autocast check triggered (BOTS). Trying to cast healing spells then maybe offensive spells"); LogAIDetail("Engaged autocast check triggered (BOTS). Trying to cast healing spells then maybe offensive spells");
if (botClass == CLERIC) { if (botClass == Class::Cleric) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) {
@@ -1534,7 +1532,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == DRUID) { else if (botClass == Class::Druid) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_Heal), BotAISpellRange, SpellType_Heal)) {
@@ -1552,7 +1550,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == SHAMAN) { else if (botClass == Class::Shaman) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
@@ -1573,7 +1571,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == RANGER) { else if (botClass == Class::Ranger) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) {
@@ -1588,7 +1586,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == BEASTLORD) { else if (botClass == Class::Beastlord) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
@@ -1609,7 +1607,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == WIZARD) { else if (botClass == Class::Wizard) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) {
@@ -1620,7 +1618,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == PALADIN) { else if (botClass == Class::Paladin) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
@@ -1633,7 +1631,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == SHADOWKNIGHT) { else if (botClass == Class::ShadowKnight) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Lifetap), SpellType_Lifetap)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Lifetap), SpellType_Lifetap)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
@@ -1646,7 +1644,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == MAGICIAN) { else if (botClass == Class::Magician) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Pet), SpellType_Pet)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Pet), SpellType_Pet)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) {
@@ -1659,7 +1657,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == NECROMANCER) { else if (botClass == Class::Necromancer) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Pet), SpellType_Pet)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Pet), SpellType_Pet)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
@@ -1678,7 +1676,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == ENCHANTER) { else if (botClass == Class::Enchanter) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Mez), SpellType_Mez)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Mez), SpellType_Mez)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) {
@@ -1695,7 +1693,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == BARD) { else if (botClass == Class::Bard) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {// Bards will use their escape songs if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {// Bards will use their escape songs
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_HateRedux), BotAISpellRange, SpellType_HateRedux)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_HateRedux), BotAISpellRange, SpellType_HateRedux)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Slow), SpellType_Slow)) {
@@ -1714,7 +1712,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == BERSERKER) { else if (botClass == Class::Berserker) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
@@ -1731,7 +1729,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == MONK) { else if (botClass == Class::Monk) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
@@ -1748,7 +1746,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == ROGUE) { else if (botClass == Class::Rogue) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
@@ -1765,7 +1763,7 @@ bool Bot::AI_EngagedCastCheck() {
} }
} }
} }
else if (botClass == WARRIOR) { else if (botClass == Class::Warrior) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) { if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) { if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) { if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
@@ -2044,7 +2042,7 @@ BotSpell Bot::GetFirstBotSpellBySpellType(Bot* botCaster, uint32 spellType) {
continue; continue;
} }
if ((botSpellList[i].type & spellType) && CheckSpellRecastTimers(botCaster, i)) { if ((botSpellList[i].type & spellType) && botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
result.SpellId = botSpellList[i].spellid; result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i; result.SpellIndex = i;
result.ManaCost = botSpellList[i].manacost; result.ManaCost = botSpellList[i].manacost;
@@ -2069,7 +2067,7 @@ BotSpell Bot::GetBestBotSpellForFastHeal(Bot *botCaster) {
for (auto botSpellListItr : botSpellList) { for (auto botSpellListItr : botSpellList) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if (IsFastHealSpell(botSpellListItr.SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr.SpellIndex)) { if (IsFastHealSpell(botSpellListItr.SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr.SpellId)) {
result.SpellId = botSpellListItr.SpellId; result.SpellId = botSpellListItr.SpellId;
result.SpellIndex = botSpellListItr.SpellIndex; result.SpellIndex = botSpellListItr.SpellIndex;
result.ManaCost = botSpellListItr.ManaCost; result.ManaCost = botSpellListItr.ManaCost;
@@ -2106,7 +2104,7 @@ BotSpell Bot::GetBestBotSpellForHealOverTime(Bot* botCaster) {
if ( if (
botSpellList[i].spellid == botSpellListItr.SpellId && botSpellList[i].spellid == botSpellListItr.SpellId &&
(botSpellList[i].type & SpellType_Heal) && (botSpellList[i].type & SpellType_Heal) &&
CheckSpellRecastTimers(botCaster, botSpellListItr.SpellIndex) botCaster->CheckSpellRecastTimer(botSpellListItr.SpellId)
) { ) {
result.SpellId = botSpellListItr.SpellId; result.SpellId = botSpellListItr.SpellId;
result.SpellIndex = botSpellListItr.SpellIndex; result.SpellIndex = botSpellListItr.SpellIndex;
@@ -2139,7 +2137,7 @@ BotSpell Bot::GetBestBotSpellForPercentageHeal(Bot *botCaster) {
continue; continue;
} }
if (IsCompleteHealSpell(botSpellList[i].spellid) && CheckSpellRecastTimers(botCaster, i)) { if (IsCompleteHealSpell(botSpellList[i].spellid) && botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
result.SpellId = botSpellList[i].spellid; result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i; result.SpellIndex = i;
result.ManaCost = botSpellList[i].manacost; result.ManaCost = botSpellList[i].manacost;
@@ -2163,7 +2161,7 @@ BotSpell Bot::GetBestBotSpellForRegularSingleTargetHeal(Bot* botCaster) {
for (std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { for (std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if (IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { if (IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
result.ManaCost = botSpellListItr->ManaCost; result.ManaCost = botSpellListItr->ManaCost;
@@ -2192,7 +2190,7 @@ BotSpell Bot::GetFirstBotSpellForSingleTargetHeal(Bot* botCaster) {
IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) || IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) ||
IsFastHealSpell(botSpellListItr->SpellId) IsFastHealSpell(botSpellListItr->SpellId)
) && ) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex) botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) { ) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2219,7 +2217,7 @@ BotSpell Bot::GetBestBotSpellForGroupHeal(Bot* botCaster) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if ( if (
IsRegularGroupHealSpell(botSpellListItr->SpellId) && IsRegularGroupHealSpell(botSpellListItr->SpellId) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex) botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) { ) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2257,7 +2255,7 @@ BotSpell Bot::GetBestBotSpellForGroupHealOverTime(Bot* botCaster) {
if ( if (
botSpellList[i].spellid == botSpellListItr->SpellId && botSpellList[i].spellid == botSpellListItr->SpellId &&
(botSpellList[i].type & SpellType_Heal) && (botSpellList[i].type & SpellType_Heal) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex) botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) { ) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2287,7 +2285,7 @@ BotSpell Bot::GetBestBotSpellForGroupCompleteHeal(Bot* botCaster) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if ( if (
IsGroupCompleteHealSpell(botSpellListItr->SpellId) && IsGroupCompleteHealSpell(botSpellListItr->SpellId) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex) botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) { ) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2314,7 +2312,7 @@ BotSpell Bot::GetBestBotSpellForMez(Bot* botCaster) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if ( if (
IsMesmerizeSpell(botSpellListItr->SpellId) && IsMesmerizeSpell(botSpellListItr->SpellId) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex) botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) { ) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2343,7 +2341,7 @@ BotSpell Bot::GetBestBotSpellForMagicBasedSlow(Bot* botCaster) {
if ( if (
IsSlowSpell(botSpellListItr->SpellId) && IsSlowSpell(botSpellListItr->SpellId) &&
spells[botSpellListItr->SpellId].resist_type == RESIST_MAGIC && spells[botSpellListItr->SpellId].resist_type == RESIST_MAGIC &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex) botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) { ) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2371,7 +2369,7 @@ BotSpell Bot::GetBestBotSpellForDiseaseBasedSlow(Bot* botCaster) {
if ( if (
IsSlowSpell(botSpellListItr->SpellId) && IsSlowSpell(botSpellListItr->SpellId) &&
spells[botSpellListItr->SpellId].resist_type == RESIST_DISEASE && spells[botSpellListItr->SpellId].resist_type == RESIST_DISEASE &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex) botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) { ) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2437,7 +2435,7 @@ BotSpell Bot::GetBestBotMagicianPetSpell(Bot *botCaster) {
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if (IsSummonPetSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { if (IsSummonPetSpell(botSpellListItr->SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
if (!strncmp(spells[botSpellListItr->SpellId].teleport_zone, petType.c_str(), petType.length())) { if (!strncmp(spells[botSpellListItr->SpellId].teleport_zone, petType.c_str(), petType.length())) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2546,7 +2544,7 @@ BotSpell Bot::GetBestBotSpellForNukeByTargetType(Bot* botCaster, SpellTargetType
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) { for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if ((IsPureNukeSpell(botSpellListItr->SpellId) || IsDamageSpell(botSpellListItr->SpellId)) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { if ((IsPureNukeSpell(botSpellListItr->SpellId) || IsDamageSpell(botSpellListItr->SpellId)) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
result.ManaCost = botSpellListItr->ManaCost; result.ManaCost = botSpellListItr->ManaCost;
@@ -2574,7 +2572,7 @@ BotSpell Bot::GetBestBotSpellForStunByTargetType(Bot* botCaster, SpellTargetType
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr)
{ {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if (IsStunSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) if (IsStunSpell(botSpellListItr->SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId))
{ {
result.SpellId = botSpellListItr->SpellId; result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex; result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2614,7 +2612,7 @@ BotSpell Bot::GetBestBotWizardNukeSpellByTargetResists(Bot* botCaster, Mob* targ
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
bool spellSelected = false; bool spellSelected = false;
if (CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) { if (botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
if (selectLureNuke && (spells[botSpellListItr->SpellId].resist_difficulty < lureResisValue)) { if (selectLureNuke && (spells[botSpellListItr->SpellId].resist_difficulty < lureResisValue)) {
spellSelected = true; spellSelected = true;
} }
@@ -2682,7 +2680,7 @@ BotSpell Bot::GetDebuffBotSpell(Bot* botCaster, Mob *tar) {
if (((botSpellList[i].type & SpellType_Debuff) || IsDebuffSpell(botSpellList[i].spellid)) if (((botSpellList[i].type & SpellType_Debuff) || IsDebuffSpell(botSpellList[i].spellid))
&& (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster) && (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster)
&& tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0) && tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0)
&& CheckSpellRecastTimers(botCaster, i)) { && botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
result.SpellId = botSpellList[i].spellid; result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i; result.SpellIndex = i;
result.ManaCost = botSpellList[i].manacost; result.ManaCost = botSpellList[i].manacost;
@@ -2735,7 +2733,7 @@ BotSpell Bot::GetBestBotSpellForResistDebuff(Bot* botCaster, Mob *tar) {
|| (needsDiseaseResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistDisease)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll))) || (needsDiseaseResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistDisease)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)))
&& (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster) && (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster)
&& tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0) && tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0)
&& CheckSpellRecastTimers(botCaster, i)) { && botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
result.SpellId = botSpellList[i].spellid; result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i; result.SpellIndex = i;
result.ManaCost = botSpellList[i].manacost; result.ManaCost = botSpellList[i].manacost;
@@ -2786,31 +2784,31 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
for (std::list<BotSpell_wPriority>::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) { for (std::list<BotSpell_wPriority>::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) {
BotSpell selectedBotSpell = *itr; BotSpell selectedBotSpell = *itr;
if (IsGroupSpell(itr->SpellId) && CheckSpellRecastTimers(botCaster, itr->SpellIndex)) { if (IsGroupSpell(itr->SpellId) && botCaster->CheckSpellRecastTimer(selectedBotSpell.SpellId)) {
if (selectedBotSpell.SpellId == 0) if (selectedBotSpell.SpellId == 0)
continue; continue;
if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) { if (isPoisoned && IsEffectInSpell(selectedBotSpell.SpellId, SE_PoisonCounter)) {
spellSelected = true; spellSelected = true;
} }
else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) { else if (isDiseased && IsEffectInSpell(selectedBotSpell.SpellId, SE_DiseaseCounter)) {
spellSelected = true; spellSelected = true;
} }
else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) { else if (isCursed && IsEffectInSpell(selectedBotSpell.SpellId, SE_CurseCounter)) {
spellSelected = true; spellSelected = true;
} }
else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) { else if (isCorrupted && IsEffectInSpell(selectedBotSpell.SpellId, SE_CorruptionCounter)) {
spellSelected = true; spellSelected = true;
} }
else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) { else if (IsEffectInSpell(selectedBotSpell.SpellId, SE_DispelDetrimental)) {
spellSelected = true; spellSelected = true;
} }
if (spellSelected) if (spellSelected)
{ {
result.SpellId = itr->SpellId; result.SpellId = selectedBotSpell.SpellId;
result.SpellIndex = itr->SpellIndex; result.SpellIndex = selectedBotSpell.SpellIndex;
result.ManaCost = itr->ManaCost; result.ManaCost = selectedBotSpell.ManaCost;
break; break;
} }
@@ -2823,31 +2821,31 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
for(std::list<BotSpell_wPriority>::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) { for(std::list<BotSpell_wPriority>::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) {
BotSpell selectedBotSpell = *itr; BotSpell selectedBotSpell = *itr;
if (CheckSpellRecastTimers(botCaster, itr->SpellIndex)) { if (botCaster->CheckSpellRecastTimer(selectedBotSpell.SpellId)) {
if (selectedBotSpell.SpellId == 0) if (selectedBotSpell.SpellId == 0)
continue; continue;
if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) { if (isPoisoned && IsEffectInSpell(selectedBotSpell.SpellId, SE_PoisonCounter)) {
spellSelected = true; spellSelected = true;
} }
else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) { else if (isDiseased && IsEffectInSpell(selectedBotSpell.SpellId, SE_DiseaseCounter)) {
spellSelected = true; spellSelected = true;
} }
else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) { else if (isCursed && IsEffectInSpell(selectedBotSpell.SpellId, SE_CurseCounter)) {
spellSelected = true; spellSelected = true;
} }
else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) { else if (isCorrupted && IsEffectInSpell(selectedBotSpell.SpellId, SE_CorruptionCounter)) {
spellSelected = true; spellSelected = true;
} }
else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) { else if (IsEffectInSpell(selectedBotSpell.SpellId, SE_DispelDetrimental)) {
spellSelected = true; spellSelected = true;
} }
if (spellSelected) if (spellSelected)
{ {
result.SpellId = itr->SpellId; result.SpellId = selectedBotSpell.SpellId;
result.SpellIndex = itr->SpellIndex; result.SpellIndex = selectedBotSpell.SpellIndex;
result.ManaCost = itr->ManaCost; result.ManaCost = selectedBotSpell.ManaCost;
break; break;
} }
@@ -2859,69 +2857,6 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
return result; return result;
} }
void Bot::SetSpellRecastTimer(int timer_index, int32 recast_delay) {
if (timer_index > 0 && timer_index <= MaxSpellTimer) {
timers[timer_index - 1] = Timer::GetCurrentTime() + recast_delay;
}
}
int32 Bot::GetSpellRecastTimer(Bot *caster, int timer_index) {
int32 result = 0;
if (caster) {
if (timer_index > 0 && timer_index <= MaxSpellTimer) {
result = caster->timers[timer_index - 1];
}
}
return result;
}
bool Bot::CheckSpellRecastTimers(Bot *caster, int SpellIndex) {
if (caster) {
if (caster->AIBot_spells[SpellIndex].time_cancast < Timer::GetCurrentTime()) { //checks spell recast
if (GetSpellRecastTimer(caster, spells[caster->AIBot_spells[SpellIndex].spellid].timer_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer
return true; //can cast spell
}
}
}
return false;
}
void Bot::SetDisciplineRecastTimer(int timer_index, int32 recast_delay) {
if (timer_index > 0 && timer_index <= MaxDisciplineTimer) {
timers[DisciplineReuseStart + timer_index - 1] = Timer::GetCurrentTime() + recast_delay;
}
}
int32 Bot::GetDisciplineRecastTimer(Bot *caster, int timer_index) {
int32 result = 0;
if (caster) {
if (timer_index > 0 && timer_index <= MaxDisciplineTimer) {
result = caster->timers[DisciplineReuseStart + timer_index - 1];
}
}
return result;
}
uint32 Bot::GetDisciplineRemainingTime(Bot *caster, int timer_index) {
int32 result = 0;
if (caster) {
if (timer_index > 0 && timer_index <= MaxDisciplineTimer) {
if (GetDisciplineRecastTimer(caster, timer_index) > Timer::GetCurrentTime())
result = GetDisciplineRecastTimer(caster, timer_index) - Timer::GetCurrentTime();
}
}
return result;
}
bool Bot::CheckDisciplineRecastTimers(Bot *caster, int timer_index) {
if (caster) {
if (GetDisciplineRecastTimer(caster, timer_index) < Timer::GetCurrentTime()) { //checks for spells on the same timer
return true; //can cast spell
}
}
return false;
}
uint8 Bot::GetChanceToCastBySpellType(uint32 spellType) uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
{ {
uint8 spell_type_index = SPELL_TYPE_COUNT; uint8 spell_type_index = SPELL_TYPE_COUNT;
@@ -3000,7 +2935,7 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
return 0; return 0;
uint8 class_index = GetClass(); uint8 class_index = GetClass();
if (class_index > BERSERKER || class_index < WARRIOR) if (class_index > Class::Berserker || class_index < Class::Warrior)
return 0; return 0;
--class_index; --class_index;
+200 -86
View File
@@ -1411,126 +1411,163 @@ void Client::SetMaxHP() {
Save(); Save();
} }
bool Client::UpdateLDoNPoints(uint32 theme_id, int points) { bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
{
/* make sure total stays in sync with individual buckets if (points < 0) {
m_pp.ldon_points_available = m_pp.ldon_points_guk if (m_pp.ldon_points_available < (0 - points)) {
+m_pp.ldon_points_mir
+m_pp.ldon_points_mmc
+m_pp.ldon_points_ruj
+m_pp.ldon_points_tak; */
if(points < 0) {
if(m_pp.ldon_points_available < (0 - points))
return false; return false;
} }
}
bool is_loss = false;
switch (theme_id) { switch (theme_id) {
case LDoNThemes::Unused: { // No theme, so distribute evenly across all case LDoNThemes::Unused: { // No theme, so distribute evenly across all
int split_points = (points / 5); int split_points = (points / 5);
int guk_points = (split_points + (points % 5)); int guk_points = (split_points + (points % 5));
int mir_points = split_points; int mir_points = split_points;
int mmc_points = split_points; int mmc_points = split_points;
int ruj_points = split_points; int ruj_points = split_points;
int tak_points = split_points; int tak_points = split_points;
split_points = 0; split_points = 0;
if(points < 0) {
if(m_pp.ldon_points_available < (0 - points)) { if (points < 0) {
if (m_pp.ldon_points_available < (0 - points)) {
return false; return false;
} }
if(m_pp.ldon_points_guk < (0 - guk_points)) { is_loss = true;
if (m_pp.ldon_points_guk < (0 - guk_points)) {
mir_points += (guk_points + m_pp.ldon_points_guk); mir_points += (guk_points + m_pp.ldon_points_guk);
guk_points = (0 - m_pp.ldon_points_guk); guk_points = (0 - m_pp.ldon_points_guk);
} }
if(m_pp.ldon_points_mir < (0 - mir_points)) { if (m_pp.ldon_points_mir < (0 - mir_points)) {
mmc_points += (mir_points + m_pp.ldon_points_mir); mmc_points += (mir_points + m_pp.ldon_points_mir);
mir_points = (0 - m_pp.ldon_points_mir); mir_points = (0 - m_pp.ldon_points_mir);
} }
if(m_pp.ldon_points_mmc < (0 - mmc_points)) { if (m_pp.ldon_points_mmc < (0 - mmc_points)) {
ruj_points += (mmc_points + m_pp.ldon_points_mmc); ruj_points += (mmc_points + m_pp.ldon_points_mmc);
mmc_points = (0 - m_pp.ldon_points_mmc); mmc_points = (0 - m_pp.ldon_points_mmc);
} }
if(m_pp.ldon_points_ruj < (0 - ruj_points)) { if (m_pp.ldon_points_ruj < (0 - ruj_points)) {
tak_points += (ruj_points + m_pp.ldon_points_ruj); tak_points += (ruj_points + m_pp.ldon_points_ruj);
ruj_points = (0 - m_pp.ldon_points_ruj); ruj_points = (0 - m_pp.ldon_points_ruj);
} }
if(m_pp.ldon_points_tak < (0 - tak_points)) { if (m_pp.ldon_points_tak < (0 - tak_points)) {
split_points = (tak_points + m_pp.ldon_points_tak); split_points = (tak_points + m_pp.ldon_points_tak);
tak_points = (0 - m_pp.ldon_points_tak); tak_points = (0 - m_pp.ldon_points_tak);
} }
} }
m_pp.ldon_points_guk += guk_points; m_pp.ldon_points_guk += guk_points;
m_pp.ldon_points_mir += mir_points; m_pp.ldon_points_mir += mir_points;
m_pp.ldon_points_mmc += mmc_points; m_pp.ldon_points_mmc += mmc_points;
m_pp.ldon_points_ruj += ruj_points; m_pp.ldon_points_ruj += ruj_points;
m_pp.ldon_points_tak += tak_points; m_pp.ldon_points_tak += tak_points;
points -= split_points; points -= split_points;
if (split_points != 0) { // if anything left, recursively loop thru again if (split_points != 0) { // if anything left, recursively loop thru again
UpdateLDoNPoints(0, split_points); UpdateLDoNPoints(LDoNThemes::Unused, split_points);
} }
break; break;
} }
case LDoNThemes::GUK: { case LDoNThemes::GUK: {
if(points < 0) { if (points < 0) {
if(m_pp.ldon_points_guk < (0 - points)) { if (m_pp.ldon_points_guk < (0 - points)) {
return false; return false;
} }
is_loss = true;
} }
m_pp.ldon_points_guk += points; m_pp.ldon_points_guk += points;
break; break;
} }
case LDoNThemes::MIR: { case LDoNThemes::MIR: {
if(points < 0) { if (points < 0) {
if(m_pp.ldon_points_mir < (0 - points)) { if (m_pp.ldon_points_mir < (0 - points)) {
return false; return false;
} }
is_loss = true;
} }
m_pp.ldon_points_mir += points; m_pp.ldon_points_mir += points;
break; break;
} }
case LDoNThemes::MMC: { case LDoNThemes::MMC: {
if(points < 0) { if (points < 0) {
if(m_pp.ldon_points_mmc < (0 - points)) { if (m_pp.ldon_points_mmc < (0 - points)) {
return false; return false;
} }
is_loss = true;
} }
m_pp.ldon_points_mmc += points; m_pp.ldon_points_mmc += points;
break; break;
} }
case LDoNThemes::RUJ: { case LDoNThemes::RUJ: {
if(points < 0) { if (points < 0) {
if(m_pp.ldon_points_ruj < (0 - points)) { if (m_pp.ldon_points_ruj < (0 - points)) {
return false; return false;
} }
is_loss = true;
} }
m_pp.ldon_points_ruj += points; m_pp.ldon_points_ruj += points;
break; break;
} }
case LDoNThemes::TAK: { case LDoNThemes::TAK: {
if(points < 0) { if (points < 0) {
if(m_pp.ldon_points_tak < (0 - points)) { if (m_pp.ldon_points_tak < (0 - points)) {
return false; return false;
} }
is_loss = true;
} }
m_pp.ldon_points_tak += points; m_pp.ldon_points_tak += points;
break; break;
} }
} }
m_pp.ldon_points_available += points; m_pp.ldon_points_available += points;
QuestEventID event_id = is_loss ? EVENT_LDON_POINTS_LOSS : EVENT_LDON_POINTS_GAIN;
if (parse->PlayerHasQuestSub(event_id)) {
const std::string &export_string = fmt::format(
"{} {}",
theme_id,
std::abs(points)
);
parse->EventPlayer(event_id, this, export_string, 0);
}
auto outapp = new EQApplicationPacket(OP_AdventurePointsUpdate, sizeof(AdventurePoints_Update_Struct)); auto outapp = new EQApplicationPacket(OP_AdventurePointsUpdate, sizeof(AdventurePoints_Update_Struct));
AdventurePoints_Update_Struct* apus = (AdventurePoints_Update_Struct*)outapp->pBuffer; auto *apus = (AdventurePoints_Update_Struct *) outapp->pBuffer;
apus->ldon_available_points = m_pp.ldon_points_available; apus->ldon_available_points = m_pp.ldon_points_available;
apus->ldon_guk_points = m_pp.ldon_points_guk; apus->ldon_guk_points = m_pp.ldon_points_guk;
apus->ldon_mirugal_points = m_pp.ldon_points_mir; apus->ldon_mirugal_points = m_pp.ldon_points_mir;
apus->ldon_mistmoore_points = m_pp.ldon_points_mmc; apus->ldon_mistmoore_points = m_pp.ldon_points_mmc;
apus->ldon_rujarkian_points = m_pp.ldon_points_ruj; apus->ldon_rujarkian_points = m_pp.ldon_points_ruj;
apus->ldon_takish_points = m_pp.ldon_points_tak; apus->ldon_takish_points = m_pp.ldon_points_tak;
outapp->priority = 6; outapp->priority = 6;
QueuePacket(outapp); QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
return true; return true;
@@ -2676,7 +2713,7 @@ bool Client::HasSkill(EQ::skills::SkillType skill_id) const {
} }
bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) const { bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) const {
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == BERSERKER && skill_id == EQ::skills::Skill1HPiercing) if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skill_id == EQ::skills::Skill1HPiercing)
skill_id = EQ::skills::Skill2HPiercing; skill_id = EQ::skills::Skill2HPiercing;
return(content_db.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)) > 0); return(content_db.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)) > 0);
@@ -2684,7 +2721,7 @@ bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) const {
} }
uint16 Client::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const { uint16 Client::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const {
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == BERSERKER && skillid == EQ::skills::Skill1HPiercing) if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skillid == EQ::skills::Skill1HPiercing)
skillid = EQ::skills::Skill2HPiercing; skillid = EQ::skills::Skill2HPiercing;
return(content_db.GetSkillCap(class_, skillid, level)); return(content_db.GetSkillCap(class_, skillid, level));
@@ -2692,7 +2729,7 @@ uint16 Client::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 lev
uint8 Client::SkillTrainLevel(EQ::skills::SkillType skillid, uint16 class_) uint8 Client::SkillTrainLevel(EQ::skills::SkillType skillid, uint16 class_)
{ {
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == BERSERKER && skillid == EQ::skills::Skill1HPiercing) if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skillid == EQ::skills::Skill1HPiercing)
skillid = EQ::skills::Skill2HPiercing; skillid = EQ::skills::Skill2HPiercing;
return(content_db.GetTrainLevel(class_, skillid, RuleI(Character, MaxLevel))); return(content_db.GetTrainLevel(class_, skillid, RuleI(Character, MaxLevel)));
@@ -3028,7 +3065,7 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
int max_percent = 50 + maxHPBonus; int max_percent = 50 + maxHPBonus;
if (GetClass() == MONK && GetSkill(EQ::skills::SkillBindWound) > 200) { if (GetClass() == Class::Monk && GetSkill(EQ::skills::SkillBindWound) > 200) {
max_percent = 70 + maxHPBonus; max_percent = 70 + maxHPBonus;
} }
@@ -3077,9 +3114,9 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
else { else {
int percent_base = 50; int percent_base = 50;
if (GetRawSkill(EQ::skills::SkillBindWound) > 200) { if (GetRawSkill(EQ::skills::SkillBindWound) > 200) {
if ((GetClass() == MONK) || (GetClass() == BEASTLORD)) if ((GetClass() == Class::Monk) || (GetClass() == Class::Beastlord))
percent_base = 70; percent_base = 70;
else if ((GetLevel() > 50) && ((GetClass() == WARRIOR) || (GetClass() == ROGUE) || (GetClass() == CLERIC))) else if ((GetLevel() > 50) && ((GetClass() == Class::Warrior) || (GetClass() == Class::Rogue) || (GetClass() == Class::Cleric)))
percent_base = 70; percent_base = 70;
} }
@@ -4232,7 +4269,7 @@ void Client::UpdateLFP() {
for(unsigned int i=0; i<MAX_GROUP_MEMBERS; i++) { for(unsigned int i=0; i<MAX_GROUP_MEMBERS; i++) {
LFPMembers[i].Name[0] = '\0'; LFPMembers[i].Name[0] = '\0';
LFPMembers[i].Class = NO_CLASS; LFPMembers[i].Class = Class::None;
LFPMembers[i].Level = 0; LFPMembers[i].Level = 0;
LFPMembers[i].Zone = 0; LFPMembers[i].Zone = 0;
} }
@@ -4849,7 +4886,7 @@ void Client::HandleLDoNOpen(NPC *target)
{ {
if(target) if(target)
{ {
if(target->GetClass() != LDON_TREASURE) if(target->GetClass() != Class::LDoNTreasure)
{ {
LogDebug("[{}] tried to open [{}] but [{}] was not a treasure chest", LogDebug("[{}] tried to open [{}] but [{}] was not a treasure chest",
GetName(), target->GetName(), target->GetName()); GetName(), target->GetName(), target->GetName());
@@ -4918,7 +4955,7 @@ void Client::HandleLDoNOpen(NPC *target)
void Client::HandleLDoNSenseTraps(NPC *target, uint16 skill, uint8 type) void Client::HandleLDoNSenseTraps(NPC *target, uint16 skill, uint8 type)
{ {
if(target && target->GetClass() == LDON_TREASURE) if(target && target->GetClass() == Class::LDoNTreasure)
{ {
if(target->IsLDoNTrapped()) if(target->IsLDoNTrapped())
{ {
@@ -4961,7 +4998,7 @@ void Client::HandleLDoNDisarm(NPC *target, uint16 skill, uint8 type)
{ {
if(target) if(target)
{ {
if(target->GetClass() == LDON_TREASURE) if(target->GetClass() == Class::LDoNTreasure)
{ {
if(!target->IsLDoNTrapped()) if(!target->IsLDoNTrapped())
{ {
@@ -5011,7 +5048,7 @@ void Client::HandleLDoNPickLock(NPC *target, uint16 skill, uint8 type)
{ {
if(target) if(target)
{ {
if(target->GetClass() == LDON_TREASURE) if(target->GetClass() == Class::LDoNTreasure)
{ {
if(target->IsLDoNTrapped()) if(target->IsLDoNTrapped())
{ {
@@ -5690,26 +5727,89 @@ void Client::AddPVPPoints(uint32 Points)
SendPVPStats(); SendPVPStats();
} }
void Client::AddCrystals(uint32 radiant, uint32 ebon) void Client::AddEbonCrystals(uint32 amount, bool is_reclaim) {
{ m_pp.currentEbonCrystals += amount;
m_pp.currentRadCrystals += radiant; m_pp.careerEbonCrystals += amount;
m_pp.careerRadCrystals += radiant;
m_pp.currentEbonCrystals += ebon;
m_pp.careerEbonCrystals += ebon;
SaveCurrency(); SaveCurrency();
SendCrystalCounts(); SendCrystalCounts();
// newer clients handle message client side (older clients likely used eqstr 5967 and 5968, this matches live) MessageString(
if (radiant > 0) Chat::Yellow,
{ YOU_RECEIVE,
MessageString(Chat::Yellow, YOU_RECEIVE, fmt::format("{} Radiant Crystals", radiant).c_str()); fmt::format(
} "{} {}",
amount,
database.CreateItemLink(RuleI(Zone, EbonCrystalItemID))
).c_str()
);
if (ebon > 0) if (parse->PlayerHasQuestSub(EVENT_CRYSTAL_GAIN)) {
{ const std::string &export_string = fmt::format(
MessageString(Chat::Yellow, YOU_RECEIVE, fmt::format("{} Ebon Crystals", ebon).c_str()); "{} 0 {}",
amount,
is_reclaim ? 1 : 0
);
parse->EventPlayer(EVENT_CRYSTAL_GAIN, this, export_string, 0);
}
}
void Client::AddRadiantCrystals(uint32 amount, bool is_reclaim) {
m_pp.currentRadCrystals += amount;
m_pp.careerRadCrystals += amount;
SaveCurrency();
SendCrystalCounts();
MessageString(
Chat::Yellow,
YOU_RECEIVE,
fmt::format(
"{} {}",
amount,
database.CreateItemLink(RuleI(Zone, RadiantCrystalItemID))
).c_str()
);
if (parse->PlayerHasQuestSub(EVENT_CRYSTAL_GAIN)) {
const std::string &export_string = fmt::format(
"0 {} {}",
amount,
is_reclaim ? 1 : 0
);
parse->EventPlayer(EVENT_CRYSTAL_GAIN, this, export_string, 0);
}
}
void Client::RemoveEbonCrystals(uint32 amount, bool is_reclaim) {
m_pp.currentEbonCrystals -= amount;
SaveCurrency();
SendCrystalCounts();
if (parse->PlayerHasQuestSub(EVENT_CRYSTAL_LOSS)) {
const std::string &export_string = fmt::format(
"{} 0 {}",
amount,
is_reclaim ? 1 : 0
);
parse->EventPlayer(EVENT_CRYSTAL_LOSS, this, export_string, 0);
}
}
void Client::RemoveRadiantCrystals(uint32 amount, bool is_reclaim) {
m_pp.currentRadCrystals -= amount;
SaveCurrency();
SendCrystalCounts();
if (parse->PlayerHasQuestSub(EVENT_CRYSTAL_LOSS)) {
const std::string &export_string = fmt::format(
"0 {} {}",
amount,
is_reclaim ? 1 : 0
);
parse->EventPlayer(EVENT_CRYSTAL_LOSS, this, export_string, 0);
} }
} }
@@ -6454,11 +6554,10 @@ void Client::SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount)
SendAlternateCurrencyValue(currency_id); SendAlternateCurrencyValue(currency_id);
} }
int Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method) int Client::AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_scripted)
{ {
/* Added via Quest, rest of the logging methods may be done inline due to information available in that area of the code */ /* Added via Quest, rest of the logging methods may be done inline due to information available in that area of the code */
if (method == 1){ if (is_scripted) {
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */ /* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){ if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){
std::string event_desc = StringFormat("Added via Quest :: Cursor to Item :: alt_currency_id:%i amount:%i in zoneid:%i instid:%i", currency_id, GetZoneID(), GetInstanceID()); std::string event_desc = StringFormat("Added via Quest :: Cursor to Item :: alt_currency_id:%i amount:%i in zoneid:%i instid:%i", currency_id, GetZoneID(), GetInstanceID());
@@ -6466,32 +6565,47 @@ int Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 met
} }
} }
if(amount == 0) { if (!amount) {
return 0; return 0;
} }
if(!alternate_currency_loaded) { if (!alternate_currency_loaded) {
alternate_currency_queued_operations.push(std::make_pair(currency_id, amount)); alternate_currency_queued_operations.push(std::make_pair(currency_id, amount));
return 0; return 0;
} }
int new_value = 0; int new_value = 0;
auto iter = alternate_currency.find(currency_id); auto iter = alternate_currency.find(currency_id);
if(iter == alternate_currency.end()) { if (iter == alternate_currency.end()) {
new_value = amount; new_value = amount;
} else { } else {
new_value = (*iter).second + amount; new_value = (*iter).second + amount;
} }
if(new_value < 0) { if (new_value < 0) {
new_value = 0;
alternate_currency[currency_id] = 0; alternate_currency[currency_id] = 0;
database.UpdateAltCurrencyValue(CharacterID(), currency_id, 0); database.UpdateAltCurrencyValue(CharacterID(), currency_id, 0);
} else { } else {
alternate_currency[currency_id] = new_value; alternate_currency[currency_id] = new_value;
database.UpdateAltCurrencyValue(CharacterID(), currency_id, new_value); database.UpdateAltCurrencyValue(CharacterID(), currency_id, new_value);
} }
SendAlternateCurrencyValue(currency_id); SendAlternateCurrencyValue(currency_id);
QuestEventID event_id = amount > 0 ? EVENT_ALT_CURRENCY_GAIN : EVENT_ALT_CURRENCY_LOSS;
if (parse->PlayerHasQuestSub(event_id)) {
const std::string &export_string = fmt::format(
"{} {} {}",
currency_id,
std::abs(amount),
new_value
);
parse->EventPlayer(event_id, this, export_string, 0);
}
return new_value; return new_value;
} }
@@ -8603,20 +8717,20 @@ void Client::InitInnates()
} }
switch (class_) { switch (class_) {
case DRUID: case Class::Druid:
m_pp.InnateSkills[InnateHarmony] = InnateEnabled; m_pp.InnateSkills[InnateHarmony] = InnateEnabled;
break; break;
case BARD: case Class::Bard:
m_pp.InnateSkills[InnateReveal] = InnateEnabled; m_pp.InnateSkills[InnateReveal] = InnateEnabled;
break; break;
case ROGUE: case Class::Rogue:
m_pp.InnateSkills[InnateSurprise] = InnateEnabled; m_pp.InnateSkills[InnateSurprise] = InnateEnabled;
m_pp.InnateSkills[InnateReveal] = InnateEnabled; m_pp.InnateSkills[InnateReveal] = InnateEnabled;
break; break;
case RANGER: case Class::Ranger:
m_pp.InnateSkills[InnateAwareness] = InnateEnabled; m_pp.InnateSkills[InnateAwareness] = InnateEnabled;
break; break;
case MONK: case Class::Monk:
m_pp.InnateSkills[InnateSurprise] = InnateEnabled; m_pp.InnateSkills[InnateSurprise] = InnateEnabled;
m_pp.InnateSkills[InnateAwareness] = InnateEnabled; m_pp.InnateSkills[InnateAwareness] = InnateEnabled;
default: default:
@@ -9754,7 +9868,7 @@ std::vector<int> Client::GetLearnableDisciplines(uint8 min_level, uint8 max_leve
continue; continue;
} }
if (spells[spell_id].classes[WARRIOR] == 0) { if (spells[spell_id].classes[Class::Warrior] == 0) {
continue; continue;
} }
@@ -9825,7 +9939,7 @@ std::vector<int> Client::GetScribeableSpells(uint8 min_level, uint8 max_level) {
continue; continue;
} }
if (spells[spell_id].classes[WARRIOR] == 0) { if (spells[spell_id].classes[Class::Warrior] == 0) {
continue; continue;
} }
@@ -10694,37 +10808,37 @@ uint16 Client::LearnDisciplines(uint8 min_level, uint8 max_level)
uint16 Client::GetClassTrackingDistanceMultiplier(uint16 class_) { uint16 Client::GetClassTrackingDistanceMultiplier(uint16 class_) {
switch (class_) { switch (class_) {
case WARRIOR: case Class::Warrior:
return RuleI(Character, WarriorTrackingDistanceMultiplier); return RuleI(Character, WarriorTrackingDistanceMultiplier);
case CLERIC: case Class::Cleric:
return RuleI(Character, ClericTrackingDistanceMultiplier); return RuleI(Character, ClericTrackingDistanceMultiplier);
case PALADIN: case Class::Paladin:
return RuleI(Character, PaladinTrackingDistanceMultiplier); return RuleI(Character, PaladinTrackingDistanceMultiplier);
case RANGER: case Class::Ranger:
return RuleI(Character, RangerTrackingDistanceMultiplier); return RuleI(Character, RangerTrackingDistanceMultiplier);
case SHADOWKNIGHT: case Class::ShadowKnight:
return RuleI(Character, ShadowKnightTrackingDistanceMultiplier); return RuleI(Character, ShadowKnightTrackingDistanceMultiplier);
case DRUID: case Class::Druid:
return RuleI(Character, DruidTrackingDistanceMultiplier); return RuleI(Character, DruidTrackingDistanceMultiplier);
case MONK: case Class::Monk:
return RuleI(Character, MonkTrackingDistanceMultiplier); return RuleI(Character, MonkTrackingDistanceMultiplier);
case BARD: case Class::Bard:
return RuleI(Character, BardTrackingDistanceMultiplier); return RuleI(Character, BardTrackingDistanceMultiplier);
case ROGUE: case Class::Rogue:
return RuleI(Character, RogueTrackingDistanceMultiplier); return RuleI(Character, RogueTrackingDistanceMultiplier);
case SHAMAN: case Class::Shaman:
return RuleI(Character, ShamanTrackingDistanceMultiplier); return RuleI(Character, ShamanTrackingDistanceMultiplier);
case NECROMANCER: case Class::Necromancer:
return RuleI(Character, NecromancerTrackingDistanceMultiplier); return RuleI(Character, NecromancerTrackingDistanceMultiplier);
case WIZARD: case Class::Wizard:
return RuleI(Character, WizardTrackingDistanceMultiplier); return RuleI(Character, WizardTrackingDistanceMultiplier);
case MAGICIAN: case Class::Magician:
return RuleI(Character, MagicianTrackingDistanceMultiplier); return RuleI(Character, MagicianTrackingDistanceMultiplier);
case ENCHANTER: case Class::Enchanter:
return RuleI(Character, EnchanterTrackingDistanceMultiplier); return RuleI(Character, EnchanterTrackingDistanceMultiplier);
case BEASTLORD: case Class::Beastlord:
return RuleI(Character, BeastlordTrackingDistanceMultiplier); return RuleI(Character, BeastlordTrackingDistanceMultiplier);
case BERSERKER: case Class::Berserker:
return RuleI(Character, BerserkerTrackingDistanceMultiplier); return RuleI(Character, BerserkerTrackingDistanceMultiplier);
default: default:
return 0; return 0;
+12 -9
View File
@@ -611,11 +611,14 @@ public:
void SetPVPPoints(uint32 Points) { m_pp.PVPCurrentPoints = Points; } void SetPVPPoints(uint32 Points) { m_pp.PVPCurrentPoints = Points; }
uint32 GetPVPPoints() { return m_pp.PVPCurrentPoints; } uint32 GetPVPPoints() { return m_pp.PVPCurrentPoints; }
void AddPVPPoints(uint32 Points); void AddPVPPoints(uint32 Points);
void AddEbonCrystals(uint32 amount, bool is_reclaim = false);
void AddRadiantCrystals(uint32 amount, bool is_reclaim = false);
void RemoveEbonCrystals(uint32 amount, bool is_reclaim = false);
void RemoveRadiantCrystals(uint32 amount, bool is_reclaim = false);
uint32 GetRadiantCrystals() { return m_pp.currentRadCrystals; } uint32 GetRadiantCrystals() { return m_pp.currentRadCrystals; }
void SetRadiantCrystals(uint32 value); void SetRadiantCrystals(uint32 value);
uint32 GetEbonCrystals() { return m_pp.currentEbonCrystals; } uint32 GetEbonCrystals() { return m_pp.currentEbonCrystals; }
void SetEbonCrystals(uint32 value); void SetEbonCrystals(uint32 value);
void AddCrystals(uint32 Radiant, uint32 Ebon);
void SendCrystalCounts(); void SendCrystalCounts();
uint64 GetExperienceForKill(Mob *against); uint64 GetExperienceForKill(Mob *against);
@@ -1493,7 +1496,7 @@ public:
void ConsentCorpses(std::string consent_name, bool deny = false); void ConsentCorpses(std::string consent_name, bool deny = false);
void SendAltCurrencies(); void SendAltCurrencies();
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount); void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
int AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0); int AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_scripted = false);
void SendAlternateCurrencyValues(); void SendAlternateCurrencyValues();
void SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null = true); void SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null = true);
uint32 GetAlternateCurrencyValue(uint32 currency_id) const; uint32 GetAlternateCurrencyValue(uint32 currency_id) const;
@@ -2045,14 +2048,14 @@ public:
bool GetBotPrecombat() { return m_bot_precombat; } bool GetBotPrecombat() { return m_bot_precombat; }
void SetBotPrecombat(bool flag = true) { m_bot_precombat = flag; } void SetBotPrecombat(bool flag = true) { m_bot_precombat = flag; }
int GetBotRequiredLevel(uint8 class_id = NO_CLASS); int GetBotRequiredLevel(uint8 class_id = Class::None);
uint32 GetBotCreationLimit(uint8 class_id = NO_CLASS); uint32 GetBotCreationLimit(uint8 class_id = Class::None);
int GetBotSpawnLimit(uint8 class_id = NO_CLASS); int GetBotSpawnLimit(uint8 class_id = Class::None);
void SetBotCreationLimit(uint32 new_creation_limit, uint8 class_id = NO_CLASS); void SetBotCreationLimit(uint32 new_creation_limit, uint8 class_id = Class::None);
void SetBotRequiredLevel(int new_required_level, uint8 class_id = NO_CLASS); void SetBotRequiredLevel(int new_required_level, uint8 class_id = Class::None);
void SetBotSpawnLimit(int new_spawn_limit, uint8 class_id = NO_CLASS); void SetBotSpawnLimit(int new_spawn_limit, uint8 class_id = Class::None);
void CampAllBots(uint8 class_id = NO_CLASS); void CampAllBots(uint8 class_id = Class::None);
void SpawnRaidBotsOnConnect(Raid* raid); void SpawnRaidBotsOnConnect(Raid* raid);
private: private:
+29 -29
View File
@@ -345,7 +345,7 @@ uint32 Mob::GetClassLevelFactor()
uint32 multiplier = 0; uint32 multiplier = 0;
uint8 mlevel = GetLevel(); uint8 mlevel = GetLevel();
switch (GetClass()) { switch (GetClass()) {
case WARRIOR: { case Class::Warrior: {
if (mlevel < 20) { if (mlevel < 20) {
multiplier = 220; multiplier = 220;
} }
@@ -372,9 +372,9 @@ uint32 Mob::GetClassLevelFactor()
} }
break; break;
} }
case DRUID: case Class::Druid:
case CLERIC: case Class::Cleric:
case SHAMAN: { case Class::Shaman: {
if (mlevel < 70) { if (mlevel < 70) {
multiplier = 150; multiplier = 150;
} }
@@ -383,9 +383,9 @@ uint32 Mob::GetClassLevelFactor()
} }
break; break;
} }
case BERSERKER: case Class::Berserker:
case PALADIN: case Class::Paladin:
case SHADOWKNIGHT: { case Class::ShadowKnight: {
if (mlevel < 35) { if (mlevel < 35) {
multiplier = 210; multiplier = 210;
} }
@@ -409,10 +409,10 @@ uint32 Mob::GetClassLevelFactor()
} }
break; break;
} }
case MONK: case Class::Monk:
case BARD: case Class::Bard:
case ROGUE: case Class::Rogue:
case BEASTLORD: { case Class::Beastlord: {
if (mlevel < 51) { if (mlevel < 51) {
multiplier = 180; multiplier = 180;
} }
@@ -427,7 +427,7 @@ uint32 Mob::GetClassLevelFactor()
} }
break; break;
} }
case RANGER: { case Class::Ranger: {
if (mlevel < 58) { if (mlevel < 58) {
multiplier = 200; multiplier = 200;
} }
@@ -439,10 +439,10 @@ uint32 Mob::GetClassLevelFactor()
} }
break; break;
} }
case MAGICIAN: case Class::Magician:
case WIZARD: case Class::Wizard:
case NECROMANCER: case Class::Necromancer:
case ENCHANTER: { case Class::Enchanter: {
if (mlevel < 70) { if (mlevel < 70) {
multiplier = 120; multiplier = 120;
} }
@@ -677,7 +677,7 @@ int64 Client::CalcManaRegen(bool bCombat)
if (IsSitting() || CanMedOnHorse()) { if (IsSitting() || CanMedOnHorse()) {
// kind of weird to do it here w/e // kind of weird to do it here w/e
// client does some base medding regen for shrouds here // client does some base medding regen for shrouds here
if (GetClass() != BARD) { if (GetClass() != Class::Bard) {
auto skill = GetSkill(EQ::skills::SkillMeditate); auto skill = GetSkill(EQ::skills::SkillMeditate);
if (skill > 0) { if (skill > 0) {
regen++; regen++;
@@ -1077,7 +1077,7 @@ int32 Client::CalcMR()
MR = 20; MR = 20;
} }
MR += itembonuses.MR + spellbonuses.MR + aabonuses.MR; MR += itembonuses.MR + spellbonuses.MR + aabonuses.MR;
if (GetClass() == WARRIOR || GetClass() == BERSERKER) { if (GetClass() == Class::Warrior || GetClass() == Class::Berserker) {
MR += GetLevel() / 2; MR += GetLevel() / 2;
} }
if (MR < 1) { if (MR < 1) {
@@ -1151,14 +1151,14 @@ int32 Client::CalcFR()
FR = 20; FR = 20;
} }
int c = GetClass(); int c = GetClass();
if (c == RANGER) { if (c == Class::Ranger) {
FR += 4; FR += 4;
int l = GetLevel(); int l = GetLevel();
if (l > 49) { if (l > 49) {
FR += l - 49; FR += l - 49;
} }
} }
if (c == MONK) { if (c == Class::Monk) {
FR += 8; FR += 8;
int l = GetLevel(); int l = GetLevel();
if (l > 49) { if (l > 49) {
@@ -1238,19 +1238,19 @@ int32 Client::CalcDR()
} }
int c = GetClass(); int c = GetClass();
// the monk one is part of base resist // the monk one is part of base resist
if (c == MONK) { if (c == Class::Monk) {
int l = GetLevel(); int l = GetLevel();
if (l > 50) if (l > 50)
DR += l - 50; DR += l - 50;
} }
if (c == PALADIN) { if (c == Class::Paladin) {
DR += 8; DR += 8;
int l = GetLevel(); int l = GetLevel();
if (l > 49) { if (l > 49) {
DR += l - 49; DR += l - 49;
} }
} }
else if (c == SHADOWKNIGHT || c == BEASTLORD) { else if (c == Class::ShadowKnight || c == Class::Beastlord) {
DR += 4; DR += 4;
int l = GetLevel(); int l = GetLevel();
if (l > 49) { if (l > 49) {
@@ -1330,19 +1330,19 @@ int32 Client::CalcPR()
} }
int c = GetClass(); int c = GetClass();
// this monk bonus is part of the base // this monk bonus is part of the base
if (c == MONK) { if (c == Class::Monk) {
int l = GetLevel(); int l = GetLevel();
if (l > 50) if (l > 50)
PR += l - 50; PR += l - 50;
} }
if (c == ROGUE) { if (c == Class::Rogue) {
PR += 8; PR += 8;
int l = GetLevel(); int l = GetLevel();
if (l > 49) { if (l > 49) {
PR += l - 49; PR += l - 49;
} }
} }
else if (c == SHADOWKNIGHT) { else if (c == Class::ShadowKnight) {
PR += 4; PR += 4;
int l = GetLevel(); int l = GetLevel();
if (l > 49) { if (l > 49) {
@@ -1421,7 +1421,7 @@ int32 Client::CalcCR()
CR = 25; CR = 25;
} }
int c = GetClass(); int c = GetClass();
if (c == RANGER || c == BEASTLORD) { if (c == Class::Ranger || c == Class::Beastlord) {
CR += 4; CR += 4;
int l = GetLevel(); int l = GetLevel();
if (l > 49) { if (l > 49) {
@@ -1455,7 +1455,7 @@ int32 Client::CalcATK()
uint32 Mob::GetInstrumentMod(uint16 spell_id) uint32 Mob::GetInstrumentMod(uint16 spell_id)
{ {
if (GetClass() != BARD) { if (GetClass() != Class::Bard) {
//Other classes can get a base effects mod using SPA 413 //Other classes can get a base effects mod using SPA 413
if (HasBaseEffectFocus()) { if (HasBaseEffectFocus()) {
return (10 + (GetFocusEffect(focusFcBaseEffects, spell_id) / 10));//TODO: change action->instrument mod to float to support < 10% focus values return (10 + (GetFocusEffect(focusFcBaseEffects, spell_id) / 10));//TODO: change action->instrument mod to float to support < 10% focus values
@@ -1689,7 +1689,7 @@ int64 Client::CalcEnduranceRegen(bool bCombat)
int weight_limit = GetSTR(); int weight_limit = GetSTR();
auto level = GetLevel(); auto level = GetLevel();
if (GetClass() == MONK) { if (GetClass() == Class::Monk) {
if (level > 99) if (level > 99)
weight_limit = 58; weight_limit = 58;
else if (level > 94) else if (level > 94)
+63 -74
View File
@@ -1381,7 +1381,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
SetClientMaxLevel(client_max_level); SetClientMaxLevel(client_max_level);
// we know our class now, so we might have to fix our consume timer! // we know our class now, so we might have to fix our consume timer!
if (class_ == MONK) if (class_ == Class::Monk)
consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER); consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER);
InitInnates(); InitInnates();
@@ -1592,9 +1592,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
m_pp.spellSlotRefresh[i] = p_timers.GetRemainingTime(pTimerSpellStart + m_pp.mem_spells[i]) * 1000; m_pp.spellSlotRefresh[i] = p_timers.GetRemainingTime(pTimerSpellStart + m_pp.mem_spells[i]) * 1000;
/* Ability slot refresh send SK/PAL */ /* Ability slot refresh send SK/PAL */
if (m_pp.class_ == SHADOWKNIGHT || m_pp.class_ == PALADIN) { if (m_pp.class_ == Class::ShadowKnight || m_pp.class_ == Class::Paladin) {
uint32 abilitynum = 0; uint32 abilitynum = 0;
if (m_pp.class_ == SHADOWKNIGHT) { abilitynum = pTimerHarmTouch; } if (m_pp.class_ == Class::ShadowKnight) { abilitynum = pTimerHarmTouch; }
else { abilitynum = pTimerLayHands; } else { abilitynum = pTimerLayHands; }
uint32 remaining = p_timers.GetRemainingTime(abilitynum); uint32 remaining = p_timers.GetRemainingTime(abilitynum);
@@ -1935,8 +1935,8 @@ void Client::Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app)
Adventure_Purchase_Struct* aps = (Adventure_Purchase_Struct*)app->pBuffer; Adventure_Purchase_Struct* aps = (Adventure_Purchase_Struct*)app->pBuffer;
uint32 merchantid = 0; uint32 merchantid = 0;
Mob* tmp = entity_list.GetMob(aps->npcid); Mob* tmp = entity_list.GetMob(aps->npcid);
if (tmp == 0 || !tmp->IsNPC() || ((tmp->GetClass() != ADVENTURE_MERCHANT) && if (tmp == 0 || !tmp->IsNPC() || ((tmp->GetClass() != Class::AdventureMerchant) &&
(tmp->GetClass() != DISCORD_MERCHANT) && (tmp->GetClass() != NORRATHS_KEEPERS_MERCHANT) && (tmp->GetClass() != DARK_REIGN_MERCHANT))) (tmp->GetClass() != Class::DiscordMerchant) && (tmp->GetClass() != Class::NorrathsKeepersMerchant) && (tmp->GetClass() != Class::DarkReignMerchant)))
return; return;
//you have to be somewhat close to them to be properly using them //you have to be somewhat close to them to be properly using them
@@ -2121,8 +2121,8 @@ void Client::Handle_OP_AdventureMerchantRequest(const EQApplicationPacket *app)
uint32 merchantid = 0; uint32 merchantid = 0;
Mob* tmp = entity_list.GetMob(eid->entity_id); Mob* tmp = entity_list.GetMob(eid->entity_id);
if (tmp == 0 || !tmp->IsNPC() || ((tmp->GetClass() != ADVENTURE_MERCHANT) && if (tmp == 0 || !tmp->IsNPC() || ((tmp->GetClass() != Class::AdventureMerchant) &&
(tmp->GetClass() != DISCORD_MERCHANT) && (tmp->GetClass() != NORRATHS_KEEPERS_MERCHANT) && (tmp->GetClass() != DARK_REIGN_MERCHANT))) (tmp->GetClass() != Class::DiscordMerchant) && (tmp->GetClass() != Class::NorrathsKeepersMerchant) && (tmp->GetClass() != Class::DarkReignMerchant)))
return; return;
if (!tmp->CastToNPC()->IsMerchantOpen()) { if (!tmp->CastToNPC()->IsMerchantOpen()) {
@@ -2197,8 +2197,8 @@ void Client::Handle_OP_AdventureMerchantSell(const EQApplicationPacket *app)
Adventure_Sell_Struct *ams_in = (Adventure_Sell_Struct*)app->pBuffer; Adventure_Sell_Struct *ams_in = (Adventure_Sell_Struct*)app->pBuffer;
Mob* vendor = entity_list.GetMob(ams_in->npcid); Mob* vendor = entity_list.GetMob(ams_in->npcid);
if (vendor == 0 || !vendor->IsNPC() || ((vendor->GetClass() != ADVENTURE_MERCHANT) && if (vendor == 0 || !vendor->IsNPC() || ((vendor->GetClass() != Class::AdventureMerchant) &&
(vendor->GetClass() != NORRATHS_KEEPERS_MERCHANT) && (vendor->GetClass() != DARK_REIGN_MERCHANT))) (vendor->GetClass() != Class::NorrathsKeepersMerchant) && (vendor->GetClass() != Class::DarkReignMerchant)))
{ {
Message(Chat::Red, "Vendor was not found."); Message(Chat::Red, "Vendor was not found.");
return; return;
@@ -2298,17 +2298,17 @@ void Client::Handle_OP_AdventureMerchantSell(const EQApplicationPacket *app)
switch (vendor->GetClass()) switch (vendor->GetClass())
{ {
case ADVENTURE_MERCHANT: case Class::AdventureMerchant:
{ {
UpdateLDoNPoints(6, price); UpdateLDoNPoints(6, price);
break; break;
} }
case NORRATHS_KEEPERS_MERCHANT: case Class::NorrathsKeepersMerchant:
{ {
SetRadiantCrystals(GetRadiantCrystals() + price); SetRadiantCrystals(GetRadiantCrystals() + price);
break; break;
} }
case DARK_REIGN_MERCHANT: case Class::DarkReignMerchant:
{ {
SetEbonCrystals(GetEbonCrystals() + price); SetEbonCrystals(GetEbonCrystals() + price);
break; break;
@@ -2482,7 +2482,7 @@ void Client::Handle_OP_AltCurrencyMerchantRequest(const EQApplicationPacket *app
return; return;
} }
if (target->GetClass() != ALT_CURRENCY_MERCHANT) { if (target->GetClass() != Class::AlternateCurrencyMerchant) {
return; return;
} }
@@ -2553,7 +2553,7 @@ void Client::Handle_OP_AltCurrencyPurchase(const EQApplicationPacket *app)
if (DistanceSquared(m_Position, tar->GetPosition())> USE_NPC_RANGE2) if (DistanceSquared(m_Position, tar->GetPosition())> USE_NPC_RANGE2)
return; return;
if (tar->GetClass() != ALT_CURRENCY_MERCHANT) { if (tar->GetClass() != Class::AlternateCurrencyMerchant) {
return; return;
} }
@@ -2626,7 +2626,7 @@ void Client::Handle_OP_AltCurrencyPurchase(const EQApplicationPacket *app)
parse->EventPlayer(EVENT_ALT_CURRENCY_MERCHANT_BUY, this, export_string, 0); parse->EventPlayer(EVENT_ALT_CURRENCY_MERCHANT_BUY, this, export_string, 0);
} }
uint64 current_balance = AddAlternateCurrencyValue(alt_cur_id, -((int32) cost)); uint64 current_balance = AddAlternateCurrencyValue(alt_cur_id, -((int) cost));
int16 charges = 1; int16 charges = 1;
if (item->MaxCharges != 0) { if (item->MaxCharges != 0) {
charges = item->MaxCharges; charges = item->MaxCharges;
@@ -2701,7 +2701,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app)
} }
else { else {
SummonItem(item_id, reclaim->count, 0, 0, 0, 0, 0, 0, false, EQ::invslot::slotCursor); SummonItem(item_id, reclaim->count, 0, 0, 0, 0, 0, 0, false, EQ::invslot::slotCursor);
AddAlternateCurrencyValue(reclaim->currency_id, -((int32)reclaim->count)); AddAlternateCurrencyValue(reclaim->currency_id, -((int)reclaim->count));
} }
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */ /* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)) { if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)) {
@@ -2722,7 +2722,7 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app)
if (DistanceSquared(m_Position, tar->GetPosition()) > USE_NPC_RANGE2) if (DistanceSquared(m_Position, tar->GetPosition()) > USE_NPC_RANGE2)
return; return;
if (tar->GetClass() != ALT_CURRENCY_MERCHANT) { if (tar->GetClass() != Class::AlternateCurrencyMerchant) {
return; return;
} }
@@ -2858,7 +2858,7 @@ void Client::Handle_OP_AltCurrencySellSelection(const EQApplicationPacket *app)
if (DistanceSquared(m_Position, tar->GetPosition()) > USE_NPC_RANGE2) if (DistanceSquared(m_Position, tar->GetPosition()) > USE_NPC_RANGE2)
return; return;
if (tar->GetClass() != ALT_CURRENCY_MERCHANT) { if (tar->GetClass() != Class::AlternateCurrencyMerchant) {
return; return;
} }
@@ -2966,7 +2966,7 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app)
bool IsPoison = (poison && poison->ItemType == EQ::item::ItemTypePoison); bool IsPoison = (poison && poison->ItemType == EQ::item::ItemTypePoison);
if (IsPoison && GetClass() == ROGUE) { if (IsPoison && GetClass() == Class::Rogue) {
// Live always checks for skillup, even when poison is too high // Live always checks for skillup, even when poison is too high
CheckIncreaseSkill(EQ::skills::SkillApplyPoison, nullptr, 10); CheckIncreaseSkill(EQ::skills::SkillApplyPoison, nullptr, 10);
@@ -3926,7 +3926,7 @@ void Client::Handle_OP_Begging(const EQApplicationPacket *app)
if (!HasSkill(EQ::skills::SkillBegging) || !GetTarget()) if (!HasSkill(EQ::skills::SkillBegging) || !GetTarget())
return; return;
if (GetTarget()->GetClass() == LDON_TREASURE) if (GetTarget()->GetClass() == Class::LDoNTreasure)
return; return;
p_timers.Start(pTimerBeggingPickPocket, 8); p_timers.Start(pTimerBeggingPickPocket, 8);
@@ -4471,7 +4471,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
else if (slot == CastingSlot::Ability) { else if (slot == CastingSlot::Ability) {
uint16 spell_to_cast = 0; uint16 spell_to_cast = 0;
if (castspell->spell_id == SPELL_LAY_ON_HANDS && GetClass() == PALADIN) { if (castspell->spell_id == SPELL_LAY_ON_HANDS && GetClass() == Class::Paladin) {
if (!p_timers.Expired(&database, pTimerLayHands)) { if (!p_timers.Expired(&database, pTimerLayHands)) {
Message(Chat::Red, "Ability recovery time not yet met."); Message(Chat::Red, "Ability recovery time not yet met.");
InterruptSpell(castspell->spell_id); InterruptSpell(castspell->spell_id);
@@ -4481,7 +4481,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
p_timers.Start(pTimerLayHands, LayOnHandsReuseTime); p_timers.Start(pTimerLayHands, LayOnHandsReuseTime);
} }
else if ((castspell->spell_id == SPELL_HARM_TOUCH else if ((castspell->spell_id == SPELL_HARM_TOUCH
|| castspell->spell_id == SPELL_HARM_TOUCH2) && GetClass() == SHADOWKNIGHT) { || castspell->spell_id == SPELL_HARM_TOUCH2) && GetClass() == Class::ShadowKnight) {
if (!p_timers.Expired(&database, pTimerHarmTouch)) { if (!p_timers.Expired(&database, pTimerHarmTouch)) {
Message(Chat::Red, "Ability recovery time not yet met."); Message(Chat::Red, "Ability recovery time not yet met.");
InterruptSpell(castspell->spell_id); InterruptSpell(castspell->spell_id);
@@ -5122,7 +5122,7 @@ void Client::Handle_OP_Consider(const EQApplicationPacket *app)
} }
} }
if (t->GetClass() == LDON_TREASURE) { if (t->GetClass() == Class::LDoNTreasure) {
Message(Chat::Yellow, fmt::format("{}", t->GetCleanName()).c_str()); Message(Chat::Yellow, fmt::format("{}", t->GetCleanName()).c_str());
return; return;
} }
@@ -5475,59 +5475,50 @@ void Client::Handle_OP_CreateObject(const EQApplicationPacket *app)
void Client::Handle_OP_CrystalCreate(const EQApplicationPacket *app) void Client::Handle_OP_CrystalCreate(const EQApplicationPacket *app)
{ {
VERIFY_PACKET_LENGTH(OP_CrystalCreate, app, CrystalReclaim_Struct); VERIFY_PACKET_LENGTH(OP_CrystalCreate, app, CrystalReclaim_Struct);
CrystalReclaim_Struct *cr = (CrystalReclaim_Struct*)app->pBuffer; auto *cr = (CrystalReclaim_Struct *) app->pBuffer;
const uint32 requestQty = cr->amount; const uint32 quantity = cr->amount;
const bool isRadiant = cr->type == 4; const bool is_radiant = cr->type == CrystalReclaimTypes::Radiant;
const bool isEbon = cr->type == 5; const bool is_ebon = cr->type == CrystalReclaimTypes::Ebon;
// Check: Valid type requested. if (!is_radiant && !is_ebon) {
if (!isRadiant && !isEbon) {
return; return;
} }
// Check: Valid quantity requested.
if (requestQty < 1) { if (quantity < 1) {
return; return;
} }
// Check: Valid client state to make request. // Check: Valid client state to make request.
// In this situation the client is either desynced or attempting an exploit. // In this situation the client is either desynced or attempting an exploit.
const uint32 currentQty = isRadiant ? GetRadiantCrystals() : GetEbonCrystals(); const uint32 current_quantity = is_radiant ? GetRadiantCrystals() : GetEbonCrystals();
if (currentQty == 0) { if (!current_quantity) {
return; return;
} }
// Prevent the client from creating more than they have. // Prevent the client from creating more than they have.
const uint32 amount = EQ::ClampUpper(requestQty, currentQty); const uint32 amount = EQ::ClampUpper(quantity, current_quantity);
const uint32 itemID = isRadiant ? RuleI(Zone, RadiantCrystalItemID) : RuleI(Zone, EbonCrystalItemID); const uint32 item_id = is_radiant ? RuleI(Zone, RadiantCrystalItemID) : RuleI(Zone, EbonCrystalItemID);
// Summon crystals for player.
const bool success = SummonItem(itemID, amount);
const bool success = SummonItem(item_id, amount);
if (!success) { if (!success) {
return; return;
} }
// Deduct crystals from client and update them. if (is_ebon) {
if (isRadiant) { RemoveEbonCrystals(amount, true);
m_pp.currentRadCrystals -= amount; } else if (is_radiant) {
m_pp.careerRadCrystals -= amount; RemoveRadiantCrystals(amount, true);
} }
else if (isEbon) {
m_pp.currentEbonCrystals -= amount;
m_pp.careerEbonCrystals -= amount;
}
SaveCurrency();
SendCrystalCounts();
} }
void Client::Handle_OP_CrystalReclaim(const EQApplicationPacket *app) void Client::Handle_OP_CrystalReclaim(const EQApplicationPacket *app)
{ {
uint32 ebon = NukeItem(RuleI(Zone, EbonCrystalItemID), invWhereWorn | invWherePersonal | invWhereCursor); const uint32 ebon = NukeItem(RuleI(Zone, EbonCrystalItemID), invWhereWorn | invWherePersonal | invWhereCursor);
uint32 radiant = NukeItem(RuleI(Zone, RadiantCrystalItemID), invWhereWorn | invWherePersonal | invWhereCursor); const uint32 radiant = NukeItem(RuleI(Zone, RadiantCrystalItemID), invWhereWorn | invWherePersonal | invWhereCursor);
if ((ebon + radiant) > 0) { if ((ebon + radiant) > 0) {
AddCrystals(radiant, ebon); AddEbonCrystals(ebon, true);
AddRadiantCrystals(radiant, true);
} }
} }
@@ -6293,6 +6284,10 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
); );
parse->EventPlayer(EVENT_ENVIRONMENTAL_DAMAGE, this, export_string, 0); parse->EventPlayer(EVENT_ENVIRONMENTAL_DAMAGE, this, export_string, 0);
} }
if (ed->dmgtype == EQ::constants::EnvironmentalDamage::Trap) {
BreakInvisibleSpells();
}
} }
if (GetHP() <= 0) { if (GetHP() <= 0) {
@@ -6879,12 +6874,6 @@ void Client::Handle_OP_GMSummon(const EQApplicationPacket *app)
return; return;
} }
if (!GetGM()) {
Message(Chat::Red, "Your account has been reported for hacking.");
RecordPlayerEventLog(PlayerEvent::POSSIBLE_HACK, PlayerEvent::PossibleHackEvent{.message = "Used /summon"});
return;
}
OPGMSummon(app); OPGMSummon(app);
return; return;
} }
@@ -8626,7 +8615,7 @@ void Client::Handle_OP_Hide(const EQApplicationPacket *app)
hidden = true; hidden = true;
tmHidden = Timer::GetCurrentTime(); tmHidden = Timer::GetCurrentTime();
} }
if (GetClass() == ROGUE) { if (GetClass() == Class::Rogue) {
auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct)); auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct));
SimpleMessage_Struct *msg = (SimpleMessage_Struct *)outapp->pBuffer; SimpleMessage_Struct *msg = (SimpleMessage_Struct *)outapp->pBuffer;
msg->color = 0x010E; msg->color = 0x010E;
@@ -9175,7 +9164,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
Bards on live can click items while casting spell gems, it stops that song cast and replaces it with item click cast. Bards on live can click items while casting spell gems, it stops that song cast and replaces it with item click cast.
Can not click while casting other items. Can not click while casting other items.
*/ */
if (GetClass() == BARD && IsCasting() && casting_spell_slot < CastingSlot::MaxGems) if (GetClass() == Class::Bard && IsCasting() && casting_spell_slot < CastingSlot::MaxGems)
{ {
is_casting_bard_song = true; is_casting_bard_song = true;
} }
@@ -9341,7 +9330,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
if (!IsCastWhileInvisibleSpell(item->Click.Effect)) { if (!IsCastWhileInvisibleSpell(item->Click.Effect)) {
CommonBreakInvisible(); // client can't do this for us :( CommonBreakInvisible(); // client can't do this for us :(
} }
if (GetClass() == BARD){ if (GetClass() == Class::Bard){
DoBardCastingFromItemClick(is_casting_bard_song, item->CastTime, item->Click.Effect, target_id, CastingSlot::Item, slot_id, item->RecastType, item->RecastDelay); DoBardCastingFromItemClick(is_casting_bard_song, item->CastTime, item->Click.Effect, target_id, CastingSlot::Item, slot_id, item->RecastType, item->RecastDelay);
} }
else { else {
@@ -9413,7 +9402,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
if (!IsCastWhileInvisibleSpell(augitem->Click.Effect)) { if (!IsCastWhileInvisibleSpell(augitem->Click.Effect)) {
CommonBreakInvisible(); // client can't do this for us :( CommonBreakInvisible(); // client can't do this for us :(
} }
if (GetClass() == BARD) { if (GetClass() == Class::Bard) {
DoBardCastingFromItemClick(is_casting_bard_song, augitem->CastTime, augitem->Click.Effect, target_id, CastingSlot::Item, slot_id, augitem->RecastType, augitem->RecastDelay); DoBardCastingFromItemClick(is_casting_bard_song, augitem->CastTime, augitem->Click.Effect, target_id, CastingSlot::Item, slot_id, augitem->RecastType, augitem->RecastDelay);
} }
else { else {
@@ -9549,7 +9538,7 @@ void Client::Handle_OP_LDoNDisarmTraps(const EQApplicationPacket *app)
void Client::Handle_OP_LDoNInspect(const EQApplicationPacket *app) void Client::Handle_OP_LDoNInspect(const EQApplicationPacket *app)
{ {
auto* t = GetTarget(); auto* t = GetTarget();
if (t && t->GetClass() == LDON_TREASURE && !t->IsAura()) { if (t && t->GetClass() == Class::LDoNTreasure && !t->IsAura()) {
if (parse->PlayerHasQuestSub(EVENT_INSPECT)) { if (parse->PlayerHasQuestSub(EVENT_INSPECT)) {
std::vector<std::any> args = { t }; std::vector<std::any> args = { t };
if (parse->EventPlayer(EVENT_INSPECT, this, "", t->GetID(), &args) == 0) { if (parse->EventPlayer(EVENT_INSPECT, this, "", t->GetID(), &args) == 0) {
@@ -9878,7 +9867,7 @@ void Client::Handle_OP_LFPCommand(const EQApplicationPacket *app)
for (unsigned int i = 0; i<MAX_GROUP_MEMBERS; i++) { for (unsigned int i = 0; i<MAX_GROUP_MEMBERS; i++) {
LFPMembers[i].Name[0] = '\0'; LFPMembers[i].Name[0] = '\0';
LFPMembers[i].Class = NO_CLASS; LFPMembers[i].Class = Class::None;
LFPMembers[i].Level = 0; LFPMembers[i].Level = 0;
LFPMembers[i].Zone = 0; LFPMembers[i].Zone = 0;
LFPMembers[i].GuildID = 0xFFFF; LFPMembers[i].GuildID = 0xFFFF;
@@ -10219,7 +10208,7 @@ void Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app)
if (DistanceSquared(m_Position, tar->GetPosition()) > USE_NPC_RANGE2) if (DistanceSquared(m_Position, tar->GetPosition()) > USE_NPC_RANGE2)
return; return;
if (tar->GetClass() != MERCENARY_MASTER) { if (tar->GetClass() != Class::MercenaryLiaison) {
return; return;
} }
@@ -10594,7 +10583,7 @@ void Client::Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app)
//Opens the guild tribute master window //Opens the guild tribute master window
StartTribute_Struct* st = (StartTribute_Struct*)app->pBuffer; StartTribute_Struct* st = (StartTribute_Struct*)app->pBuffer;
Mob* tribmast = entity_list.GetMob(st->tribute_master_id); Mob* tribmast = entity_list.GetMob(st->tribute_master_id);
if (tribmast && tribmast->IsNPC() && tribmast->GetClass() == GUILD_TRIBUTE_MASTER if (tribmast && tribmast->IsNPC() && tribmast->GetClass() == Class::GuildTributeMaster
&& DistanceSquared(m_Position, tribmast->GetPosition()) <= USE_NPC_RANGE2) { && DistanceSquared(m_Position, tribmast->GetPosition()) <= USE_NPC_RANGE2) {
st->response = 1; st->response = 1;
QueuePacket(app); QueuePacket(app);
@@ -10625,7 +10614,7 @@ void Client::Handle_OP_OpenTributeMaster(const EQApplicationPacket *app)
//Opens the tribute master window //Opens the tribute master window
StartTribute_Struct* st = (StartTribute_Struct*)app->pBuffer; StartTribute_Struct* st = (StartTribute_Struct*)app->pBuffer;
Mob* tribmast = entity_list.GetMob(st->tribute_master_id); Mob* tribmast = entity_list.GetMob(st->tribute_master_id);
if (tribmast && tribmast->IsNPC() && tribmast->GetClass() == TRIBUTE_MASTER if (tribmast && tribmast->IsNPC() && tribmast->GetClass() == Class::TributeMaster
&& DistanceSquared(m_Position, tribmast->GetPosition()) <= USE_NPC_RANGE2) { && DistanceSquared(m_Position, tribmast->GetPosition()) <= USE_NPC_RANGE2) {
st->response = 1; st->response = 1;
QueuePacket(app); QueuePacket(app);
@@ -13531,7 +13520,7 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
return; return;
} }
if (GetClass() != WARRIOR){ if (GetClass() != Class::Warrior){
return; return;
} }
@@ -13587,7 +13576,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
bool tmpmer_used = false; bool tmpmer_used = false;
Mob* tmp = entity_list.GetMob(mp->npcid); Mob* tmp = entity_list.GetMob(mp->npcid);
if (tmp == 0 || !tmp->IsNPC() || tmp->GetClass() != MERCHANT) if (tmp == 0 || !tmp->IsNPC() || tmp->GetClass() != Class::Merchant)
return; return;
if (mp->quantity < 1) return; if (mp->quantity < 1) return;
@@ -13896,7 +13885,7 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
Mob* vendor = entity_list.GetMob(mp->npcid); Mob* vendor = entity_list.GetMob(mp->npcid);
if (vendor == 0 || !vendor->IsNPC() || vendor->GetClass() != MERCHANT) if (vendor == 0 || !vendor->IsNPC() || vendor->GetClass() != Class::Merchant)
return; return;
//you have to be somewhat close to them to be properly using them //you have to be somewhat close to them to be properly using them
@@ -14122,7 +14111,7 @@ void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app)
int merchantid = 0; int merchantid = 0;
Mob* tmp = entity_list.GetMob(mc->npcid); Mob* tmp = entity_list.GetMob(mc->npcid);
if (tmp == 0 || !tmp->IsNPC() || tmp->GetClass() != MERCHANT) if (tmp == 0 || !tmp->IsNPC() || tmp->GetClass() != Class::Merchant)
return; return;
//you have to be somewhat close to them to be properly using them //you have to be somewhat close to them to be properly using them
@@ -14229,7 +14218,7 @@ void Client::Handle_OP_Sneak(const EQApplicationPacket *app)
sa_out->parameter = sneaking; sa_out->parameter = sneaking;
QueuePacket(outapp); QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
if (GetClass() == ROGUE) { if (GetClass() == Class::Rogue) {
outapp = new EQApplicationPacket(OP_SimpleMessage, 12); outapp = new EQApplicationPacket(OP_SimpleMessage, 12);
SimpleMessage_Struct *msg = (SimpleMessage_Struct *)outapp->pBuffer; SimpleMessage_Struct *msg = (SimpleMessage_Struct *)outapp->pBuffer;
msg->color = 0x010E; msg->color = 0x010E;
@@ -15545,7 +15534,7 @@ void Client::Handle_OP_TributeItem(const EQApplicationPacket *app)
tribute_master_id = t->tribute_master_id; tribute_master_id = t->tribute_master_id;
//make sure they are dealing with a valid tribute master //make sure they are dealing with a valid tribute master
Mob* tribmast = entity_list.GetMob(t->tribute_master_id); Mob* tribmast = entity_list.GetMob(t->tribute_master_id);
if (!tribmast || !tribmast->IsNPC() || tribmast->GetClass() != TRIBUTE_MASTER) if (!tribmast || !tribmast->IsNPC() || tribmast->GetClass() != Class::TributeMaster)
return; return;
if (DistanceSquared(m_Position, tribmast->GetPosition()) > USE_NPC_RANGE2) if (DistanceSquared(m_Position, tribmast->GetPosition()) > USE_NPC_RANGE2)
return; return;
@@ -15572,7 +15561,7 @@ void Client::Handle_OP_TributeMoney(const EQApplicationPacket *app)
tribute_master_id = t->tribute_master_id; tribute_master_id = t->tribute_master_id;
//make sure they are dealing with a valid tribute master //make sure they are dealing with a valid tribute master
Mob* tribmast = entity_list.GetMob(t->tribute_master_id); Mob* tribmast = entity_list.GetMob(t->tribute_master_id);
if (!tribmast || !tribmast->IsNPC() || tribmast->GetClass() != TRIBUTE_MASTER) if (!tribmast || !tribmast->IsNPC() || tribmast->GetClass() != Class::TributeMaster)
return; return;
if (DistanceSquared(m_Position, tribmast->GetPosition()) > USE_NPC_RANGE2) if (DistanceSquared(m_Position, tribmast->GetPosition()) > USE_NPC_RANGE2)
return; return;
+9 -9
View File
@@ -434,7 +434,7 @@ bool Client::Process() {
} }
} }
if (GetClass() == WARRIOR || GetClass() == BERSERKER) { if (GetClass() == Class::Warrior || GetClass() == Class::Berserker) {
if (!dead && !IsBerserk() && GetHPRatio() < RuleI(Combat, BerserkerFrenzyStart)) { if (!dead && !IsBerserk() && GetHPRatio() < RuleI(Combat, BerserkerFrenzyStart)) {
entity_list.MessageCloseString(this, false, 200, 0, BERSERK_START, GetName()); entity_list.MessageCloseString(this, false, 200, 0, BERSERK_START, GetName());
berserk = true; berserk = true;
@@ -1121,7 +1121,7 @@ void Client::OPMemorizeSpell(const EQApplicationPacket* app)
if ( if (
m->scribing != memSpellForget && m->scribing != memSpellForget &&
( (
!EQ::ValueWithin(GetClass(), PLAYER_CLASS_WARRIOR, PLAYER_CLASS_BERSERKER) || !IsPlayerClass(GetClass()) ||
GetLevel() < spells[m->spell_id].classes[GetClass() - 1] GetLevel() < spells[m->spell_id].classes[GetClass() - 1]
) )
) { ) {
@@ -1552,12 +1552,12 @@ void Client::OPGMTraining(const EQApplicationPacket *app)
Mob* pTrainer = entity_list.GetMob(gmtrain->npcid); Mob* pTrainer = entity_list.GetMob(gmtrain->npcid);
if(!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < WARRIORGM || pTrainer->GetClass() > BERSERKERGM) if(!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < Class::WarriorGM || pTrainer->GetClass() > Class::BerserkerGM)
return; return;
//you can only use your own trainer, client enforces this, but why trust it //you can only use your own trainer, client enforces this, but why trust it
if (!RuleB(Character, AllowCrossClassTrainers)) { if (!RuleB(Character, AllowCrossClassTrainers)) {
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR); int trains_class = pTrainer->GetClass() - (Class::WarriorGM - Class::Warrior);
if (GetClass() != trains_class) if (GetClass() != trains_class)
return; return;
} }
@@ -1579,7 +1579,7 @@ void Client::OPGMTraining(const EQApplicationPacket *app)
} }
} }
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && GetClass() == BERSERKER) { if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && GetClass() == Class::Berserker) {
gmtrain->skills[EQ::skills::Skill1HPiercing] = gmtrain->skills[EQ::skills::Skill2HPiercing]; gmtrain->skills[EQ::skills::Skill1HPiercing] = gmtrain->skills[EQ::skills::Skill2HPiercing];
gmtrain->skills[EQ::skills::Skill2HPiercing] = 0; gmtrain->skills[EQ::skills::Skill2HPiercing] = 0;
} }
@@ -1607,12 +1607,12 @@ void Client::OPGMEndTraining(const EQApplicationPacket *app)
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
Mob* pTrainer = entity_list.GetMob(p->npcid); Mob* pTrainer = entity_list.GetMob(p->npcid);
if(!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < WARRIORGM || pTrainer->GetClass() > BERSERKERGM) if(!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < Class::WarriorGM || pTrainer->GetClass() > Class::BerserkerGM)
return; return;
//you can only use your own trainer, client enforces this, but why trust it //you can only use your own trainer, client enforces this, but why trust it
if (!RuleB(Character, AllowCrossClassTrainers)) { if (!RuleB(Character, AllowCrossClassTrainers)) {
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR); int trains_class = pTrainer->GetClass() - (Class::WarriorGM - Class::Warrior);
if (GetClass() != trains_class) if (GetClass() != trains_class)
return; return;
} }
@@ -1638,12 +1638,12 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
GMSkillChange_Struct* gmskill = (GMSkillChange_Struct*) app->pBuffer; GMSkillChange_Struct* gmskill = (GMSkillChange_Struct*) app->pBuffer;
Mob* pTrainer = entity_list.GetMob(gmskill->npcid); Mob* pTrainer = entity_list.GetMob(gmskill->npcid);
if(!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < WARRIORGM || pTrainer->GetClass() > BERSERKERGM) if(!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < Class::WarriorGM || pTrainer->GetClass() > Class::BerserkerGM)
return; return;
//you can only use your own trainer, client enforces this, but why trust it //you can only use your own trainer, client enforces this, but why trust it
if (!RuleB(Character, AllowCrossClassTrainers)) { if (!RuleB(Character, AllowCrossClassTrainers)) {
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR); int trains_class = pTrainer->GetClass() - (Class::WarriorGM - Class::Warrior);
if (GetClass() != trains_class) if (GetClass() != trains_class)
return; return;
} }
+23 -14
View File
@@ -75,7 +75,7 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation; chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation;
//Crtical Hit Calculation pathway //Crtical Hit Calculation pathway
if (chance > 0 || (IsOfClientBot() && GetClass() == WIZARD && GetLevel() >= RuleI(Spells, WizCritLevel))) { if (chance > 0 || (IsOfClientBot() && GetClass() == Class::Wizard && GetLevel() >= RuleI(Spells, WizCritLevel))) {
int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals. int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.
@@ -92,7 +92,7 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack; ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack;
} }
else if ((IsOfClientBot() && GetClass() == WIZARD) || (IsMerc() && GetClass() == CASTERDPS)) { else if ((IsOfClientBot() && GetClass() == Class::Wizard) || (IsMerc() && GetClass() == CASTERDPS)) {
if ((GetLevel() >= RuleI(Spells, WizCritLevel)) && zone->random.Roll(RuleI(Spells, WizCritChance))){ if ((GetLevel() >= RuleI(Spells, WizCritLevel)) && zone->random.Roll(RuleI(Spells, WizCritChance))){
//Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed) //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed)
ratio += zone->random.Int(RuleI(Spells, WizardCritMinimumRandomRatio), RuleI(Spells, WizardCritMaximumRandomRatio)); ratio += zone->random.Int(RuleI(Spells, WizardCritMinimumRandomRatio), RuleI(Spells, WizardCritMaximumRandomRatio));
@@ -100,7 +100,7 @@ int64 Mob::GetActSpellDamage(uint16 spell_id, int64 value, Mob* target) {
} }
} }
if (IsOfClientBot() && GetClass() == WIZARD) { if (IsOfClientBot() && GetClass() == Class::Wizard) {
ratio += RuleI(Spells, WizCritRatio); //Default is zero ratio += RuleI(Spells, WizCritRatio); //Default is zero
} }
@@ -285,11 +285,14 @@ int64 Mob::GetActDoTDamage(uint16 spell_id, int64 value, Mob* target, bool from_
extra_dmg += GetSkillDmgAmt(spells[spell_id].skill) * ratio / 100; extra_dmg += GetSkillDmgAmt(spells[spell_id].skill) * ratio / 100;
} }
if (RuleB(Spells, DOTBonusDamageSplitOverDuration)) {
if (extra_dmg) { if (extra_dmg) {
int duration = CalcBuffDuration(this, target, spell_id); const int duration = CalcBuffDuration(this, target, spell_id);
if (duration > 0) if (duration > 0) {
extra_dmg /= duration; extra_dmg /= duration;
} }
}
}
value -= extra_dmg; value -= extra_dmg;
} }
@@ -328,11 +331,14 @@ int64 Mob::GetActDoTDamage(uint16 spell_id, int64 value, Mob* target, bool from_
extra_dmg += GetSkillDmgAmt(spells[spell_id].skill); extra_dmg += GetSkillDmgAmt(spells[spell_id].skill);
} }
if (RuleB(Spells, DOTBonusDamageSplitOverDuration)) {
if (extra_dmg) { if (extra_dmg) {
int duration = CalcBuffDuration(this, target, spell_id); const int duration = CalcBuffDuration(this, target, spell_id);
if (duration > 0) if (duration > 0) {
extra_dmg /= duration; extra_dmg /= duration;
} }
}
}
value -= extra_dmg; value -= extra_dmg;
} }
@@ -426,7 +432,7 @@ int64 Mob::GetActSpellHealing(uint16 spell_id, int64 value, Mob* target, bool fr
} }
} }
if (GetClass() == CLERIC) { if (GetClass() == Class::Cleric) {
value += int64(base_value*RuleI(Spells, ClericInnateHealFocus) / 100); //confirmed on live parsing clerics get an innate 5 pct heal focus value += int64(base_value*RuleI(Spells, ClericInnateHealFocus) / 100); //confirmed on live parsing clerics get an innate 5 pct heal focus
} }
value += int64(base_value*GetFocusEffect(focusImprovedHeal, spell_id, nullptr, from_buff_tic) / 100); value += int64(base_value*GetFocusEffect(focusImprovedHeal, spell_id, nullptr, from_buff_tic) / 100);
@@ -518,13 +524,16 @@ int64 Mob::GetActSpellHealing(uint16 spell_id, int64 value, Mob* target, bool fr
} }
if (extra_heal) { if (extra_heal) {
int duration = CalcBuffDuration(this, target, spell_id); if (RuleB(Spells, HOTBonusHealingSplitOverDuration)) {
const int duration = CalcBuffDuration(this, target, spell_id);
if (duration > 0) { if (duration > 0) {
extra_heal /= duration; extra_heal /= duration;
value += extra_heal;
} }
} }
value += extra_heal;
}
value *= critical_modifier; value *= critical_modifier;
} }
@@ -632,7 +641,7 @@ bool Client::TrainDiscipline(uint32 itemid) {
} }
const auto player_class = GetClass(); const auto player_class = GetClass();
if (player_class == WIZARD || player_class == ENCHANTER || player_class == MAGICIAN || player_class == NECROMANCER) { if (player_class == Class::Wizard || player_class == Class::Enchanter || player_class == Class::Magician || player_class == Class::Necromancer) {
Message(Chat::Red, "Your class cannot learn from this tome."); Message(Chat::Red, "Your class cannot learn from this tome.");
//summon them the item back... //summon them the item back...
SummonItem(itemid); SummonItem(itemid);
@@ -906,7 +915,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
if (reduced_recast > 0) { if (reduced_recast > 0) {
instant_recast = false; instant_recast = false;
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) { if (GetClass() == Class::Bard && IsCasting() && spells[spell_id].cast_time == 0) {
if (DoCastingChecksOnCaster(spell_id, EQ::spells::CastingSlot::Discipline)) { if (DoCastingChecksOnCaster(spell_id, EQ::spells::CastingSlot::Discipline)) {
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, (uint32)DiscTimer, reduced_recast, false); SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, (uint32)DiscTimer, reduced_recast, false);
} }
@@ -921,7 +930,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
} }
if (instant_recast) { if (instant_recast) {
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) { if (GetClass() == Class::Bard && IsCasting() && spells[spell_id].cast_time == 0) {
if (DoCastingChecksOnCaster(spell_id, EQ::spells::CastingSlot::Discipline)) { if (DoCastingChecksOnCaster(spell_id, EQ::spells::CastingSlot::Discipline)) {
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, 0xFFFFFFFF, 0, false); SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, 0xFFFFFFFF, 0, false);
} }
@@ -1320,7 +1329,7 @@ void EntityList::AEAttack(
) { ) {
for (int i = 0; i < attack_rounds; i++) { for (int i = 0; i < attack_rounds; i++) {
if (!attacker->IsClient() || attacker->GetClass() == MONK || attacker->GetClass() == RANGER) { if (!attacker->IsClient() || attacker->GetClass() == Class::Monk || attacker->GetClass() == Class::Ranger) {
attacker->Attack(current_mob, Hand, false, false, is_from_spell); attacker->Attack(current_mob, Hand, false, false, is_from_spell);
} else { } else {
attacker->CastToClient()->DoAttackRounds(current_mob, Hand, is_from_spell); attacker->CastToClient()->DoAttackRounds(current_mob, Hand, is_from_spell);
+60 -10
View File
@@ -186,6 +186,14 @@ const char *QuestEventSubroutines[_LargestEventID] = {
"EVENT_UNMEMORIZE_SPELL", "EVENT_UNMEMORIZE_SPELL",
"EVENT_SCRIBE_SPELL", "EVENT_SCRIBE_SPELL",
"EVENT_UNSCRIBE_SPELL", "EVENT_UNSCRIBE_SPELL",
"EVENT_LOOT_ADDED",
"EVENT_LDON_POINTS_GAIN",
"EVENT_LDON_POINTS_LOSS",
"EVENT_ALT_CURRENCY_GAIN",
"EVENT_ALT_CURRENCY_LOSS",
"EVENT_CRYSTAL_GAIN",
"EVENT_CRYSTAL_LOSS",
// Add new events before these or Lua crashes // Add new events before these or Lua crashes
"EVENT_SPELL_EFFECT_BOT", "EVENT_SPELL_EFFECT_BOT",
"EVENT_SPELL_EFFECT_BUFF_TIC_BOT" "EVENT_SPELL_EFFECT_BUFF_TIC_BOT"
@@ -1883,19 +1891,17 @@ void PerlembParser::ExportEventVariables(
ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]); ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]); ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]); ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
if (extra_pointers && extra_pointers->size() >= 1)
{ if (extra_pointers && extra_pointers->size() >= 1) {
Corpse* corpse = std::any_cast<Corpse*>(extra_pointers->at(0)); Corpse *corpse = std::any_cast<Corpse *>(extra_pointers->at(0));
if (corpse) if (corpse) {
{
ExportVar(package_name.c_str(), "killed_corpse_id", corpse->GetID()); ExportVar(package_name.c_str(), "killed_corpse_id", corpse->GetID());
} }
} }
if (extra_pointers && extra_pointers->size() >= 2)
{ if (extra_pointers && extra_pointers->size() >= 2) {
NPC* killed = std::any_cast<NPC*>(extra_pointers->at(1)); NPC *killed = std::any_cast<NPC *>(extra_pointers->at(1));
if (killed) if (killed) {
{
ExportVar(package_name.c_str(), "killed_entity_id", killed->GetID()); ExportVar(package_name.c_str(), "killed_entity_id", killed->GetID());
ExportVar(package_name.c_str(), "killed_bot_id", killed->IsBot() ? killed->CastToBot()->GetBotID() : 0); ExportVar(package_name.c_str(), "killed_bot_id", killed->IsBot() ? killed->CastToBot()->GetBotID() : 0);
ExportVar(package_name.c_str(), "killed_npc_id", killed->IsNPC() ? killed->GetNPCTypeID() : 0); ExportVar(package_name.c_str(), "killed_npc_id", killed->IsNPC() ? killed->GetNPCTypeID() : 0);
@@ -2241,6 +2247,50 @@ void PerlembParser::ExportEventVariables(
break; break;
} }
case EVENT_LOOT_ADDED: {
if (extra_pointers && extra_pointers->size() == 1) {
auto *inst = std::any_cast<EQ::ItemInstance *>(extra_pointers->at(0));
if (inst) {
ExportVar(package_name.c_str(), "item", "QuestItem", inst);
ExportVar(package_name.c_str(), "item_id", inst->GetID());
ExportVar(package_name.c_str(), "item_name", inst->GetItem()->Name);
ExportVar(package_name.c_str(), "item_charges", inst->GetCharges());
ExportVar(package_name.c_str(), "augment_one", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN));
ExportVar(package_name.c_str(), "augment_two", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 1));
ExportVar(package_name.c_str(), "augment_three", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 2));
ExportVar(package_name.c_str(), "augment_four", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 3));
ExportVar(package_name.c_str(), "augment_five", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 4));
ExportVar(package_name.c_str(), "augment_six", inst->GetAugmentItemID(EQ::invaug::SOCKET_END));
}
}
}
case EVENT_LDON_POINTS_GAIN:
case EVENT_LDON_POINTS_LOSS: {
Seperator sep(data);
ExportVar(package_name.c_str(), "theme_id", sep.arg[0]);
ExportVar(package_name.c_str(), "points", sep.arg[1]);
break;
}
case EVENT_ALT_CURRENCY_GAIN:
case EVENT_ALT_CURRENCY_LOSS: {
Seperator sep(data);
ExportVar(package_name.c_str(), "currency_id", sep.arg[0]);
ExportVar(package_name.c_str(), "amount", sep.arg[1]);
ExportVar(package_name.c_str(), "total", sep.arg[2]);
break;
}
case EVENT_CRYSTAL_GAIN:
case EVENT_CRYSTAL_LOSS: {
Seperator sep(data);
ExportVar(package_name.c_str(), "ebon_amount", sep.arg[0]);
ExportVar(package_name.c_str(), "radiant_amount", sep.arg[1]);
ExportVar(package_name.c_str(), "is_reclaim", sep.arg[2]);
break;
}
default: { default: {
break; break;
} }
+5 -5
View File
@@ -4918,7 +4918,7 @@ void EntityList::ZoneWho(Client *c, Who_All_Struct *Who)
FormatMSGID = 5024; // 5024 %T1[ANONYMOUS] %2 %3 FormatMSGID = 5024; // 5024 %T1[ANONYMOUS] %2 %3
else if (ClientEntry->GetAnon() == 2) else if (ClientEntry->GetAnon() == 2)
FormatMSGID = 5023; // 5023 %T1[ANONYMOUS] %2 %3 %4 FormatMSGID = 5023; // 5023 %T1[ANONYMOUS] %2 %3 %4
uint32 PlayerClass = NO_CLASS; uint32 PlayerClass = Class::None;
uint32 PlayerLevel = 0; uint32 PlayerLevel = 0;
uint32 PlayerRace = RACE_DOUG_0; uint32 PlayerRace = RACE_DOUG_0;
uint32 ZoneMSGID = 0xFFFFFFFF; uint32 ZoneMSGID = 0xFFFFFFFF;
@@ -4995,7 +4995,7 @@ uint32 EntityList::CheckNPCsClose(Mob *center)
auto it = npc_list.begin(); auto it = npc_list.begin();
while (it != npc_list.end()) { while (it != npc_list.end()) {
NPC *cur = it->second; NPC *cur = it->second;
if (!cur || cur == center || cur->IsPet() || cur->GetClass() == LDON_TREASURE || if (!cur || cur == center || cur->IsPet() || cur->GetClass() == Class::LDoNTreasure ||
cur->GetBodyType() == BT_NoTarget || cur->GetBodyType() == BT_Special) { cur->GetBodyType() == BT_NoTarget || cur->GetBodyType() == BT_Special) {
++it; ++it;
continue; continue;
@@ -5355,7 +5355,7 @@ void EntityList::AddLootToNPCS(uint32 item_id, uint32 count)
auto it = npc_list.begin(); auto it = npc_list.begin();
while (it != npc_list.end()) { while (it != npc_list.end()) {
if (!it->second->IsPet() if (!it->second->IsPet()
&& it->second->GetClass() != LDON_TREASURE && it->second->GetClass() != Class::LDoNTreasure
&& it->second->GetBodyType() != BT_NoTarget && it->second->GetBodyType() != BT_NoTarget
&& it->second->GetBodyType() != BT_NoTarget2 && it->second->GetBodyType() != BT_NoTarget2
&& it->second->GetBodyType() != BT_Special) && it->second->GetBodyType() != BT_Special)
@@ -5376,7 +5376,7 @@ void EntityList::AddLootToNPCS(uint32 item_id, uint32 count)
it = npc_list.begin(); it = npc_list.begin();
while (it != npc_list.end()) { while (it != npc_list.end()) {
if (!it->second->IsPet() if (!it->second->IsPet()
&& it->second->GetClass() != LDON_TREASURE && it->second->GetClass() != Class::LDoNTreasure
&& it->second->GetBodyType() != BT_NoTarget && it->second->GetBodyType() != BT_NoTarget
&& it->second->GetBodyType() != BT_NoTarget2 && it->second->GetBodyType() != BT_NoTarget2
&& it->second->GetBodyType() != BT_Special) && it->second->GetBodyType() != BT_Special)
@@ -5429,7 +5429,7 @@ NPC *EntityList::GetClosestBanker(Mob *sender, uint32 &distance)
auto it = npc_list.begin(); auto it = npc_list.begin();
while (it != npc_list.end()) { while (it != npc_list.end()) {
if (it->second->GetClass() == BANKER) { if (it->second->GetClass() == Class::Banker) {
uint32 nd = ((it->second->GetY() - sender->GetY()) * (it->second->GetY() - sender->GetY())) + uint32 nd = ((it->second->GetY() - sender->GetY()) * (it->second->GetY() - sender->GetY())) +
((it->second->GetX() - sender->GetX()) * (it->second->GetX() - sender->GetX())); ((it->second->GetX() - sender->GetX()) * (it->second->GetX() - sender->GetX()));
if (nd < distance){ if (nd < distance){
+2 -2
View File
@@ -529,8 +529,8 @@ public:
inline const std::unordered_map<uint16, Merc *> &GetMercList() { return merc_list; } inline const std::unordered_map<uint16, Merc *> &GetMercList() { return merc_list; }
inline const std::unordered_map<uint16, Client *> &GetClientList() { return client_list; } inline const std::unordered_map<uint16, Client *> &GetClientList() { return client_list; }
inline const std::list<Bot *> &GetBotList() { return bot_list; } inline const std::list<Bot *> &GetBotList() { return bot_list; }
std::vector<Bot *> GetBotListByCharacterID(uint32 character_id, uint8 class_id = NO_CLASS); std::vector<Bot *> GetBotListByCharacterID(uint32 character_id, uint8 class_id = Class::None);
std::vector<Bot *> GetBotListByClientName(std::string client_name, uint8 class_id = NO_CLASS); std::vector<Bot *> GetBotListByClientName(std::string client_name, uint8 class_id = Class::None);
void SignalAllBotsByOwnerCharacterID(uint32 character_id, int signal_id); void SignalAllBotsByOwnerCharacterID(uint32 character_id, int signal_id);
void SignalAllBotsByOwnerName(std::string owner_name, int signal_id); void SignalAllBotsByOwnerName(std::string owner_name, int signal_id);
void SignalBotByBotID(uint32 bot_id, int signal_id); void SignalBotByBotID(uint32 bot_id, int signal_id);
+8
View File
@@ -128,6 +128,14 @@ typedef enum {
EVENT_UNMEMORIZE_SPELL, EVENT_UNMEMORIZE_SPELL,
EVENT_SCRIBE_SPELL, EVENT_SCRIBE_SPELL,
EVENT_UNSCRIBE_SPELL, EVENT_UNSCRIBE_SPELL,
EVENT_LOOT_ADDED,
EVENT_LDON_POINTS_GAIN,
EVENT_LDON_POINTS_LOSS,
EVENT_ALT_CURRENCY_GAIN,
EVENT_ALT_CURRENCY_LOSS,
EVENT_CRYSTAL_GAIN,
EVENT_CRYSTAL_LOSS,
// Add new events before these or Lua crashes // Add new events before these or Lua crashes
EVENT_SPELL_EFFECT_BOT, EVENT_SPELL_EFFECT_BOT,
EVENT_SPELL_EFFECT_BUFF_TIC_BOT, EVENT_SPELL_EFFECT_BUFF_TIC_BOT,
+9 -9
View File
@@ -128,8 +128,8 @@ uint64 Client::CalcEXP(uint8 consider_level, bool ignore_modifiers) {
if (RuleB(Character, UseRaceClassExpBonuses)) { if (RuleB(Character, UseRaceClassExpBonuses)) {
if ( if (
GetClass() == WARRIOR || GetClass() == Class::Warrior ||
GetClass() == ROGUE || GetClass() == Class::Rogue ||
GetBaseRace() == HALFLING GetBaseRace() == HALFLING
) { ) {
total_modifier *= 1.05; total_modifier *= 1.05;
@@ -295,7 +295,7 @@ void Client::CalculateStandardAAExp(uint64 &add_aaxp, uint8 conlevel, bool resex
aatotalmod *= 1.05; aatotalmod *= 1.05;
} }
if (GetClass() == ROGUE || GetClass() == WARRIOR) { if (GetClass() == Class::Rogue || GetClass() == Class::Warrior) {
aatotalmod *= 1.05; aatotalmod *= 1.05;
} }
} }
@@ -443,7 +443,7 @@ void Client::CalculateExp(uint64 in_add_exp, uint64 &add_exp, uint64 &add_aaxp,
totalmod *= 1.05; totalmod *= 1.05;
} }
if (GetClass() == ROGUE || GetClass() == WARRIOR) { if (GetClass() == Class::Rogue || GetClass() == Class::Warrior) {
totalmod *= 1.05; totalmod *= 1.05;
} }
} }
@@ -1051,15 +1051,15 @@ uint32 Client::GetEXPForLevel(uint16 check_level)
if(RuleB(Character,UseOldClassExpPenalties)) if(RuleB(Character,UseOldClassExpPenalties))
{ {
float classmod = 1.0; float classmod = 1.0;
if(GetClass() == PALADIN || GetClass() == SHADOWKNIGHT || GetClass() == RANGER || GetClass() == BARD) { if(GetClass() == Class::Paladin || GetClass() == Class::ShadowKnight || GetClass() == Class::Ranger || GetClass() == Class::Bard) {
classmod = 1.4; classmod = 1.4;
} else if(GetClass() == MONK) { } else if(GetClass() == Class::Monk) {
classmod = 1.2; classmod = 1.2;
} else if(GetClass() == WIZARD || GetClass() == ENCHANTER || GetClass() == MAGICIAN || GetClass() == NECROMANCER) { } else if(GetClass() == Class::Wizard || GetClass() == Class::Enchanter || GetClass() == Class::Magician || GetClass() == Class::Necromancer) {
classmod = 1.1; classmod = 1.1;
} else if(GetClass() == ROGUE) { } else if(GetClass() == Class::Rogue) {
classmod = 0.91; classmod = 0.91;
} else if(GetClass() == WARRIOR) { } else if(GetClass() == Class::Warrior) {
classmod = 0.9; classmod = 0.9;
} }
+2 -2
View File
@@ -4,7 +4,7 @@ void FindClass(Client *c, const Seperator *sep)
{ {
if (sep->IsNumber(2)) { if (sep->IsNumber(2)) {
const auto class_id = Strings::ToInt(sep->arg[2]); const auto class_id = Strings::ToInt(sep->arg[2]);
if (EQ::ValueWithin(class_id, WARRIOR, BERSERKER)) { if (EQ::ValueWithin(class_id, Class::Warrior, Class::Berserker)) {
const std::string& class_name = GetClassIDName(class_id); const std::string& class_name = GetClassIDName(class_id);
c->Message( c->Message(
Chat::White, Chat::White,
@@ -41,7 +41,7 @@ void FindClass(Client *c, const Seperator *sep)
auto found_count = 0; auto found_count = 0;
for (uint16 class_id = WARRIOR; class_id <= MERCENARY_MASTER; class_id++) { for (uint16 class_id = Class::Warrior; class_id <= Class::MercenaryLiaison; class_id++) {
const std::string& class_name = GetClassIDName(class_id); const std::string& class_name = GetClassIDName(class_id);
const auto& class_name_lower = Strings::ToLower(class_name); const auto& class_name_lower = Strings::ToLower(class_name);
if (!Strings::Contains(class_name_lower, search_criteria)) { if (!Strings::Contains(class_name_lower, search_criteria)) {
+6 -6
View File
@@ -7,12 +7,12 @@ void command_merchantshop(Client *c, const Seperator *sep)
!m || !m ||
!m->IsNPC() || !m->IsNPC() ||
( (
m->GetClass() != MERCHANT && m->GetClass() != Class::Merchant &&
m->GetClass() != DISCORD_MERCHANT && m->GetClass() != Class::DiscordMerchant &&
m->GetClass() != ADVENTURE_MERCHANT && m->GetClass() != Class::AdventureMerchant &&
m->GetClass() != NORRATHS_KEEPERS_MERCHANT && m->GetClass() != Class::NorrathsKeepersMerchant &&
m->GetClass() != DARK_REIGN_MERCHANT && m->GetClass() != Class::DarkReignMerchant &&
m->GetClass() != ALT_CURRENCY_MERCHANT m->GetClass() != Class::AlternateCurrencyMerchant
) )
) { ) {
c->Message(Chat::White, "You must target a merchant."); c->Message(Chat::White, "You must target a merchant.");
+1 -1
View File
@@ -46,7 +46,7 @@ void command_scribespell(Client *c, const Seperator *sep)
); );
if ( if (
spells[spell_id].classes[WARRIOR] != 0 && spells[spell_id].classes[Class::Warrior] != 0 &&
spells[spell_id].skill != EQ::skills::SkillTigerClaw && spells[spell_id].skill != EQ::skills::SkillTigerClaw &&
spells[spell_id].classes[t->GetPP().class_ - 1] > 0 && spells[spell_id].classes[t->GetPP().class_ - 1] > 0 &&
!IsDiscipline(spell_id) !IsDiscipline(spell_id)
+9 -16
View File
@@ -9,17 +9,11 @@ void SetTime(Client *c, const Seperator *sep)
TimeOfDay_Struct world_time{}; TimeOfDay_Struct world_time{};
zone->zone_time.GetCurrentEQTimeOfDay(time(0), &world_time); zone->zone_time.GetCurrentEQTimeOfDay(time(0), &world_time);
auto time_string = fmt::format(
"{} (Timezone: {})",
Strings::ZoneTime(world_time.hour, world_time.minute),
Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr())
);
c->Message( c->Message(
Chat::White, Chat::White,
fmt::format( fmt::format(
"It is currently {}.", "It is currently {}.",
time_string Strings::ZoneTime(world_time.hour - 1, world_time.minute)
).c_str() ).c_str()
); );
@@ -27,15 +21,15 @@ void SetTime(Client *c, const Seperator *sep)
} }
uint8 minutes = 0; uint8 minutes = 0;
uint8 hours = Strings::ToUnsignedInt(sep->arg[2]) + 1; uint8 hours = Strings::ToUnsignedInt(sep->arg[2]);
if (hours > 24) { if (hours > 24) {
hours = 24; hours = 24;
} }
uint8 real_hours = ( uint8 real_hours = (
(hours - 1) > 0 ? hours > 0 ?
(hours - 1) : hours :
0 0
); );
@@ -47,21 +41,20 @@ void SetTime(Client *c, const Seperator *sep)
} }
} }
c->Message( c->Message(
Chat::White, Chat::White,
fmt::format( fmt::format(
"Setting world time to {} (Timezone: {}).", "Setting world time to {}.",
Strings::ZoneTime(hours, minutes), Strings::ZoneTime(hours, minutes)
Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr())
).c_str() ).c_str()
); );
zone->SetTime(real_hours, minutes); zone->SetTime(real_hours, minutes);
LogInfo( LogInfo(
"{} :: Setting world time to {} (Timezone: {})", "{} :: Setting world time to {}.",
c->GetCleanName(), c->GetCleanName(),
Strings::ZoneTime(hours, minutes), Strings::ZoneTime(hours, minutes)
Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr())
); );
} }
+11 -16
View File
@@ -3,19 +3,16 @@
extern WorldServer worldserver; extern WorldServer worldserver;
#include "../corpse.h"
void command_summon(Client *c, const Seperator *sep) void command_summon(Client *c, const Seperator *sep)
{ {
int arguments = sep->argnum; const int arguments = sep->argnum;
if (!arguments && !c->GetTarget()) { if (!arguments && !c->GetTarget()) {
c->Message(Chat::White, "Usage: #summon - Summon your target, if you have one, to your position"); c->Message(Chat::White, "Usage: #summon - Summon your target, if you have one, to your position");
c->Message(Chat::White, "Usage: #summon [Character Name] - Summon a character by name to your position"); c->Message(Chat::White, "Usage: #summon [Character Name] - Summon a character by name to your position");
c->Message(Chat::White, "Note: You may also summon your target if you have one.");
return; return;
} }
Mob* t = c; Mob *t = c;
if (arguments == 1) { if (arguments == 1) {
std::string character_name = sep->arg[1]; std::string character_name = sep->arg[1];
@@ -31,9 +28,9 @@ void command_summon(Client *c, const Seperator *sep)
return; return;
} }
auto search_client = entity_list.GetClientByName(character_name.c_str()); Client *s = entity_list.GetClientByName(character_name.c_str());
if (search_client) { if (s) {
t = search_client->CastToMob(); t = s->CastToMob();
} else { } else {
if (!worldserver.Connected()) { if (!worldserver.Connected()) {
c->Message(Chat::White, "World server is currently disconnected."); c->Message(Chat::White, "World server is currently disconnected.");
@@ -42,15 +39,18 @@ void command_summon(Client *c, const Seperator *sep)
auto pack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct)); auto pack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct));
auto szp = (ServerZonePlayer_Struct *) pack->pBuffer; auto szp = (ServerZonePlayer_Struct *) pack->pBuffer;
strn0cpy(szp->adminname, c->GetName(), sizeof(szp->adminname)); strn0cpy(szp->adminname, c->GetName(), sizeof(szp->adminname));
szp->adminrank = c->Admin();
szp->ignorerestrictions = 2;
strn0cpy(szp->name, character_name.c_str(), sizeof(szp->name)); strn0cpy(szp->name, character_name.c_str(), sizeof(szp->name));
strn0cpy(szp->zone, zone->GetShortName(), sizeof(szp->zone)); strn0cpy(szp->zone, zone->GetShortName(), sizeof(szp->zone));
szp->adminrank = c->Admin();
szp->ignorerestrictions = 2;
szp->instance_id = zone->GetInstanceID();
szp->x_pos = c->GetX(); szp->x_pos = c->GetX();
szp->y_pos = c->GetY(); szp->y_pos = c->GetY();
szp->z_pos = c->GetZ(); szp->z_pos = c->GetZ();
szp->instance_id = zone->GetInstanceID();
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
return; return;
@@ -97,9 +97,4 @@ void command_summon(Client *c, const Seperator *sep)
} }
t->GMMove(c->GetPosition()); t->GMMove(c->GetPosition());
if (t->IsNPC()) {
t->CastToNPC()->SaveGuardSpot(glm::vec4(0.0f));
}
} }
+5 -5
View File
@@ -600,7 +600,7 @@ bool HealRotation::healable_target(bool use_class_at, bool critical_only)
return false; return false;
if (healable_target->GetHPRatio() > m_safe_hp_ratio[ClassArmorType(healable_target->GetClass())]) if (healable_target->GetHPRatio() > m_safe_hp_ratio[ClassArmorType(healable_target->GetClass())])
return false; return false;
if (healable_target->IsBerserk() && (healable_target->GetClass() == WARRIOR || healable_target->GetClass() == BERSERKER)) { if (healable_target->IsBerserk() && (healable_target->GetClass() == Class::Warrior || healable_target->GetClass() == Class::Berserker)) {
if (healable_target->GetHPRatio() <= RuleI(Combat, BerserkerFrenzyEnd) && healable_target->GetHPRatio() > m_critical_hp_ratio[ClassArmorType(healable_target->GetClass())]) if (healable_target->GetHPRatio() <= RuleI(Combat, BerserkerFrenzyEnd) && healable_target->GetHPRatio() > m_critical_hp_ratio[ClassArmorType(healable_target->GetClass())])
return false; return false;
} }
@@ -610,7 +610,7 @@ bool HealRotation::healable_target(bool use_class_at, bool critical_only)
return false; return false;
if (healable_target->GetHPRatio() > SAFE_HP_RATIO_BASE) if (healable_target->GetHPRatio() > SAFE_HP_RATIO_BASE)
return false; return false;
if (healable_target->IsBerserk() && (healable_target->GetClass() == WARRIOR || healable_target->GetClass() == BERSERKER)) { if (healable_target->IsBerserk() && (healable_target->GetClass() == Class::Warrior || healable_target->GetClass() == Class::Berserker)) {
if (healable_target->GetHPRatio() <= RuleI(Combat, BerserkerFrenzyEnd) && healable_target->GetHPRatio() > CRITICAL_HP_RATIO_BASE) if (healable_target->GetHPRatio() <= RuleI(Combat, BerserkerFrenzyEnd) && healable_target->GetHPRatio() > CRITICAL_HP_RATIO_BASE)
return false; return false;
} }
@@ -938,9 +938,9 @@ void HealRotation::validate_hot()
bool IsHealRotationMemberClass(uint8 class_id) bool IsHealRotationMemberClass(uint8 class_id)
{ {
switch (class_id) { switch (class_id) {
case CLERIC: case Class::Cleric:
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
return true; return true;
default: default:
return false; return false;
+219 -200
View File
@@ -27,24 +27,37 @@
#include "zonedb.h" #include "zonedb.h"
#include "global_loot_manager.h" #include "global_loot_manager.h"
#include "../common/repositories/criteria/content_filter_criteria.h" #include "../common/repositories/criteria/content_filter_criteria.h"
#include "quest_parser_collection.h"
#ifdef _WINDOWS #ifdef _WINDOWS
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
// Queries the loottable: adds item & coin to the npc // Queries the loottable: adds item & coin to the npc
void ZoneDatabase::AddLootTableToNPC(NPC* npc, uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) { void ZoneDatabase::AddLootTableToNPC(
const LootTable_Struct* lts = nullptr; NPC *npc,
// global loot passes nullptr for these uint32 loottable_id,
bool bGlobal = copper == nullptr && silver == nullptr && gold == nullptr && plat == nullptr; ItemList *itemlist,
if (!bGlobal) { uint32 *copper,
uint32 *silver,
uint32 *gold,
uint32 *plat
)
{
const bool is_global = (
copper == nullptr &&
silver == nullptr &&
gold == nullptr &&
plat == nullptr
);
if (!is_global) {
*copper = 0; *copper = 0;
*silver = 0; *silver = 0;
*gold = 0; *gold = 0;
*plat = 0; *plat = 0;
} }
lts = database.GetLootTable(loottable_id); const auto *lts = database.GetLootTable(loottable_id);
if (!lts) { if (!lts) {
return; return;
} }
@@ -55,19 +68,23 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc, uint32 loottable_id, ItemList* it
uint32 min_cash = lts->mincash; uint32 min_cash = lts->mincash;
uint32 max_cash = lts->maxcash; uint32 max_cash = lts->maxcash;
if(min_cash > max_cash) { if (min_cash > max_cash) {
uint32 t = min_cash; const uint32 t = min_cash;
min_cash = max_cash; min_cash = max_cash;
max_cash = t; max_cash = t;
} }
uint32 cash = 0; uint32 cash = 0;
if (!bGlobal) { if (!is_global) {
if(max_cash > 0 && lts->avgcoin > 0 && EQ::ValueWithin(lts->avgcoin, min_cash, max_cash)) { if (
float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash); max_cash > 0 &&
float avg_cash_roll = (float)zone->random.Real(0.0, 1.0); lts->avgcoin > 0 &&
EQ::ValueWithin(lts->avgcoin, min_cash, max_cash)
) {
const float upper_chance = static_cast<float>(lts->avgcoin - min_cash) / static_cast<float>(max_cash - min_cash);
const float avg_cash_roll = static_cast<float>(zone->random.Real(0.0, 1.0));
if(avg_cash_roll < upper_chance) { if (avg_cash_roll < upper_chance) {
cash = zone->random.Int(lts->avgcoin, max_cash); cash = zone->random.Int(lts->avgcoin, max_cash);
} else { } else {
cash = zone->random.Int(min_cash, lts->avgcoin); cash = zone->random.Int(min_cash, lts->avgcoin);
@@ -77,7 +94,7 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc, uint32 loottable_id, ItemList* it
} }
} }
if(cash != 0) { if (cash != 0) {
*plat = cash / 1000; *plat = cash / 1000;
cash -= *plat * 1000; cash -= *plat * 1000;
@@ -90,25 +107,23 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc, uint32 loottable_id, ItemList* it
*copper = cash; *copper = cash;
} }
uint32 global_loot_multiplier = RuleI(Zone, GlobalLootMultiplier); const uint32 global_loot_multiplier = RuleI(Zone, GlobalLootMultiplier);
// Do items for (uint32 i = 0; i < lts->NumEntries; i++) {
for (uint32 i=0; i<lts->NumEntries; i++) {
for (uint32 k = 1; k <= (lts->Entries[i].multiplier * global_loot_multiplier); k++) { for (uint32 k = 1; k <= (lts->Entries[i].multiplier * global_loot_multiplier); k++) {
uint8 droplimit = lts->Entries[i].droplimit; const uint8 drop_limit = lts->Entries[i].droplimit;
uint8 mindrop = lts->Entries[i].mindrop; const uint8 minimum_drop = lts->Entries[i].mindrop;
//LootTable Entry probability //LootTable Entry probability
float ltchance = 0.0f; const float probability = lts->Entries[i].probability;
ltchance = lts->Entries[i].probability;
float drop_chance = 0.0f; float drop_chance = 0.0f;
if(ltchance > 0.0 && ltchance < 100.0) { if (EQ::ValueWithin(probability, 0.0f, 100.0f)) {
drop_chance = (float)zone->random.Real(0.0, 100.0); drop_chance = static_cast<float>(zone->random.Real(0.0, 100.0));
} }
if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance <= ltchance)) { if (probability != 0.0 && (probability == 100.0 || drop_chance <= probability)) {
AddLootDropToNPC(npc, lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop); AddLootDropToNPC(npc, lts->Entries[i].lootdrop_id, itemlist, drop_limit, minimum_drop);
} }
} }
} }
@@ -118,31 +133,29 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc, uint32 loottable_id, ItemList* it
// maxdrops = size of the array npcd // maxdrops = size of the array npcd
void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item_list, uint8 droplimit, uint8 mindrop) void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item_list, uint8 droplimit, uint8 mindrop)
{ {
const LootDrop_Struct *loot_drop = GetLootDrop(lootdrop_id); const auto *lds = GetLootDrop(lootdrop_id);
if (!loot_drop) { if (
return; !lds ||
} lds->NumEntries == 0 ||
!content_service.DoesPassContentFiltering(lds->content_flags)
if (loot_drop->NumEntries == 0) { ) {
return;
}
if (!content_service.DoesPassContentFiltering(loot_drop->content_flags)) {
return; return;
} }
// if this lootdrop is droplimit=0 and mindrop 0, scan list once and return // if this lootdrop is droplimit=0 and mindrop 0, scan list once and return
if (droplimit == 0 && mindrop == 0) { if (droplimit == 0 && mindrop == 0) {
for (uint32 i = 0; i < loot_drop->NumEntries; ++i) { for (uint32 i = 0; i < lds->NumEntries; ++i) {
int charges = loot_drop->Entries[i].multiplier; const uint8 charges = lds->Entries[i].multiplier;
for (int j = 0; j < charges; ++j) { for (int j = 0; j < charges; ++j) {
if (zone->random.Real(0.0, 100.0) <= loot_drop->Entries[i].chance && if (
npc->MeetsLootDropLevelRequirements(loot_drop->Entries[i], true)) { zone->random.Real(0.0, 100.0) <= lds->Entries[i].chance &&
const EQ::ItemData *database_item = GetItem(loot_drop->Entries[i].item_id); npc->MeetsLootDropLevelRequirements(lds->Entries[i], true)
) {
const EQ::ItemData *database_item = GetItem(lds->Entries[i].item_id);
npc->AddLootDrop( npc->AddLootDrop(
database_item, database_item,
item_list, item_list,
loot_drop->Entries[i] lds->Entries[i]
); );
} }
} }
@@ -150,7 +163,7 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
return; return;
} }
if (loot_drop->NumEntries > 100 && droplimit == 0) { if (lds->NumEntries > 100 && droplimit == 0) {
droplimit = 10; droplimit = 10;
} }
@@ -163,16 +176,17 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
bool roll_table_chance_bypass = false; bool roll_table_chance_bypass = false;
bool active_item_list = false; bool active_item_list = false;
for (uint32 i = 0; i < loot_drop->NumEntries; ++i) { for (uint32 i = 0; i < lds->NumEntries; ++i) {
const EQ::ItemData *db_item = GetItem(loot_drop->Entries[i].item_id); const EQ::ItemData *db_item = GetItem(lds->Entries[i].item_id);
if (db_item && npc->MeetsLootDropLevelRequirements(loot_drop->Entries[i])) { if (db_item && npc->MeetsLootDropLevelRequirements(lds->Entries[i])) {
roll_t += loot_drop->Entries[i].chance; roll_t += lds->Entries[i].chance;
if (loot_drop->Entries[i].chance >= 100) {
if (lds->Entries[i].chance >= 100) {
roll_table_chance_bypass = true; roll_table_chance_bypass = true;
} else {
no_loot_prob *= (100 - lds->Entries[i].chance) / 100.0f;
} }
else {
no_loot_prob *= (100 - loot_drop->Entries[i].chance) / 100.0f;
}
active_item_list = true; active_item_list = true;
} }
} }
@@ -191,41 +205,40 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
for (int i = 0; i < droplimit; ++i) { for (int i = 0; i < droplimit; ++i) {
if (drops < mindrop || roll_table_chance_bypass || (float) zone->random.Real(0.0, 1.0) >= no_loot_prob) { if (drops < mindrop || roll_table_chance_bypass || (float) zone->random.Real(0.0, 1.0) >= no_loot_prob) {
float roll = (float) zone->random.Real(0.0, roll_t); float roll = (float) zone->random.Real(0.0, roll_t);
for (uint32 j = 0; j < loot_drop->NumEntries; ++j) { for (uint32 j = 0; j < lds->NumEntries; ++j) {
const EQ::ItemData *db_item = GetItem(loot_drop->Entries[j].item_id); const auto *db_item = GetItem(lds->Entries[j].item_id);
if (db_item) { if (db_item) {
// if it doesn't meet the requirements do nothing // if it doesn't meet the requirements do nothing
if (!npc->MeetsLootDropLevelRequirements(loot_drop->Entries[j])) { if (!npc->MeetsLootDropLevelRequirements(lds->Entries[j])) {
continue; continue;
} }
if (roll < loot_drop->Entries[j].chance) { if (roll < lds->Entries[j].chance) {
npc->AddLootDrop( npc->AddLootDrop(
db_item, db_item,
item_list, item_list,
loot_drop->Entries[j] lds->Entries[j]
); );
drops++; drops++;
int charges = (int) loot_drop->Entries[i].multiplier; uint8 charges = lds->Entries[i].multiplier;
charges = EQ::ClampLower(charges, 1); charges = EQ::ClampLower(charges, static_cast<uint8>(1));
for (int k = 1; k < charges; ++k) { for (int k = 1; k < charges; ++k) {
float c_roll = (float) zone->random.Real(0.0, 100.0); float c_roll = static_cast<float>(zone->random.Real(0.0, 100.0));
if (c_roll <= loot_drop->Entries[i].chance) { if (c_roll <= lds->Entries[i].chance) {
npc->AddLootDrop( npc->AddLootDrop(
db_item, db_item,
item_list, item_list,
loot_drop->Entries[i] lds->Entries[i]
); );
} }
} }
j = loot_drop->NumEntries; j = lds->NumEntries;
break; break;
} } else {
else { roll -= lds->Entries[j].chance;
roll -= loot_drop->Entries[j].chance;
} }
} }
} }
@@ -291,19 +304,18 @@ void NPC::AddLootDrop(
ItemList *itemlist, ItemList *itemlist,
LootDropEntries_Struct loot_drop, LootDropEntries_Struct loot_drop,
bool wear_change, bool wear_change,
uint32 aug1, uint32 augment_one,
uint32 aug2, uint32 augment_two,
uint32 aug3, uint32 augment_three,
uint32 aug4, uint32 augment_four,
uint32 aug5, uint32 augment_five,
uint32 aug6 uint32 augment_six
) )
{ {
if (!item2) { if (!item2) {
return; return;
} }
//make sure we are doing something...
if (!itemlist && !wear_change) { if (!itemlist && !wear_change) {
return; return;
} }
@@ -340,18 +352,17 @@ void NPC::AddLootDrop(
item->item_id = item2->ID; item->item_id = item2->ID;
item->charges = loot_drop.item_charges; item->charges = loot_drop.item_charges;
item->aug_1 = aug1; item->aug_1 = augment_one;
item->aug_2 = aug2; item->aug_2 = augment_two;
item->aug_3 = aug3; item->aug_3 = augment_three;
item->aug_4 = aug4; item->aug_4 = augment_four;
item->aug_5 = aug5; item->aug_5 = augment_five;
item->aug_6 = aug6; item->aug_6 = augment_six;
item->attuned = 0; item->attuned = false;
item->trivial_min_level = loot_drop.trivial_min_level; item->trivial_min_level = loot_drop.trivial_min_level;
item->trivial_max_level = loot_drop.trivial_max_level; item->trivial_max_level = loot_drop.trivial_max_level;
item->equip_slot = EQ::invslot::SLOT_INVALID; item->equip_slot = EQ::invslot::SLOT_INVALID;
// unsure if required to equip, YOLO for now // unsure if required to equip, YOLO for now
if (item2->ItemType == EQ::item::ItemTypeBow) { if (item2->ItemType == EQ::item::ItemTypeBow) {
SetBowEquipped(true); SetBowEquipped(true);
@@ -363,17 +374,17 @@ void NPC::AddLootDrop(
bool found = false; // track if we found an empty slot we fit into bool found = false; // track if we found an empty slot we fit into
int foundslot = INVALID_INDEX; // for multi-slot items int found_slot = INVALID_INDEX; // for multi-slot items
const auto* inst = database.CreateItem( auto *inst = database.CreateItem(
item2->ID, item2->ID,
loot_drop.item_charges, loot_drop.item_charges,
aug1, augment_one,
aug2, augment_two,
aug3, augment_three,
aug4, augment_four,
aug5, augment_five,
aug6 augment_six
); );
if (!inst) { if (!inst) {
@@ -381,9 +392,8 @@ void NPC::AddLootDrop(
} }
if (loot_drop.equip_item > 0) { if (loot_drop.equip_item > 0) {
uint8 eslot = 0xFF; uint8 equipment_slot = UINT8_MAX;
char newid[20]; const EQ::ItemData *compitem = nullptr;
const EQ::ItemData* compitem = nullptr;
// Equip rules are as follows: // Equip rules are as follows:
// If the item has the NoPet flag set it will not be equipped. // If the item has the NoPet flag set it will not be equipped.
@@ -395,141 +405,136 @@ void NPC::AddLootDrop(
// it is an improvement. // it is an improvement.
if (!item2->NoPet) { if (!item2->NoPet) {
for (int i = EQ::invslot::EQUIPMENT_BEGIN; !found && i <= EQ::invslot::EQUIPMENT_END; i++) { for (
uint32 slots = (1 << i); int i = EQ::invslot::EQUIPMENT_BEGIN;
!found && i <= EQ::invslot::EQUIPMENT_END;
i++
) {
const uint32 slots = (1 << i);
if (item2->Slots & slots) { if (item2->Slots & slots) {
if(equipment[i]) if (equipment[i]) {
{
compitem = database.GetItem(equipment[i]); compitem = database.GetItem(equipment[i]);
if (item2->AC > compitem->AC || if (
(item2->AC == compitem->AC && item2->HP > compitem->HP)) item2->AC > compitem->AC ||
{ (item2->AC == compitem->AC && item2->HP > compitem->HP)
) {
// item would be an upgrade // item would be an upgrade
// check if we're multi-slot, if yes then we have to keep // check if we're multi-slot, if yes then we have to keep
// looking in case any of the other slots we can fit into are empty. // looking in case any of the other slots we can fit into are empty.
if (item2->Slots != slots) { if (item2->Slots != slots) {
foundslot = i; found_slot = i;
} } else {
else {
// Unequip old item // Unequip old item
auto* olditem = GetItem(i); auto *old_item = GetItem(i);
olditem->equip_slot = EQ::invslot::SLOT_INVALID; old_item->equip_slot = EQ::invslot::SLOT_INVALID;
equipment[i] = item2->ID; equipment[i] = item2->ID;
foundslot = i; found_slot = i;
found = true; found = true;
} }
} // end if ac
} }
else } else {
{
equipment[i] = item2->ID; equipment[i] = item2->ID;
foundslot = i;
found_slot = i;
found = true; found = true;
} }
} // end if (slots) }
} // end for }
} // end if NoPet }
// Possible slot was found but not selected. Pick it now. // Possible slot was found but not selected. Pick it now.
if (!found && foundslot >= 0) { if (!found && found_slot >= 0) {
equipment[foundslot] = item2->ID; equipment[found_slot] = item2->ID;
found = true; found = true;
} }
// @merth: IDFile size has been increased, this needs to change uint32 equipment_material;
uint16 emat; if (
if(item2->Material <= 0 item2->Material <= 0 ||
|| (item2->Slots & ((1 << EQ::invslot::slotPrimary) | (1 << EQ::invslot::slotSecondary)))) { (
memset(newid, 0, sizeof(newid)); item2->Slots & (
for(int i=0;i<7;i++){ (1 << EQ::invslot::slotPrimary) |
if (!isalpha(item2->IDFile[i])){ (1 << EQ::invslot::slotSecondary)
strn0cpy(newid, &item2->IDFile[i],6); )
i=8; )
} ) {
} equipment_material = Strings::ToUnsignedInt(&item2->IDFile[2]);
emat = Strings::ToInt(newid);
} else { } else {
emat = item2->Material; equipment_material = item2->Material;
} }
if (foundslot == EQ::invslot::slotPrimary) { if (found_slot == EQ::invslot::slotPrimary) {
equipment_slot = EQ::textures::weaponPrimary;
eslot = EQ::textures::weaponPrimary;
if (item2->Damage > 0) { if (item2->Damage > 0) {
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped); SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
if (!RuleB(Combat, ClassicNPCBackstab))
if (!RuleB(Combat, ClassicNPCBackstab)) {
SetFacestab(true); SetFacestab(true);
} }
if (item2->IsType2HWeapon()) }
if (item2->IsType2HWeapon()) {
SetTwoHanderEquipped(true); SetTwoHanderEquipped(true);
} }
else if (foundslot == EQ::invslot::slotSecondary } else if (
&& (GetOwner() != nullptr || (CanThisClassDualWield() && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) && found_slot == EQ::invslot::slotSecondary &&
(item2->IsType1HWeapon() || item2->ItemType == EQ::item::ItemTypeShield || item2->ItemType == EQ::item::ItemTypeLight)) (
{ GetOwner() ||
(CanThisClassDualWield() && zone->random.Roll(NPC_DW_CHANCE)) ||
item2->Damage == 0
) &&
(
item2->IsType1HWeapon() ||
item2->ItemType == EQ::item::ItemTypeShield ||
item2->ItemType == EQ::item::ItemTypeLight
)
) {
equipment_slot = EQ::textures::weaponSecondary;
eslot = EQ::textures::weaponSecondary; if (item2->Damage > 0) {
if (item2->Damage > 0)
SendAddPlayerState(PlayerState::SecondaryWeaponEquipped); SendAddPlayerState(PlayerState::SecondaryWeaponEquipped);
} }
else if (foundslot == EQ::invslot::slotHead) { } else if (found_slot == EQ::invslot::slotHead) {
eslot = EQ::textures::armorHead; equipment_slot = EQ::textures::armorHead;
} } else if (found_slot == EQ::invslot::slotChest) {
else if (foundslot == EQ::invslot::slotChest) { equipment_slot = EQ::textures::armorChest;
eslot = EQ::textures::armorChest; } else if (found_slot == EQ::invslot::slotArms) {
} equipment_slot = EQ::textures::armorArms;
else if (foundslot == EQ::invslot::slotArms) { } else if (EQ::ValueWithin(found_slot, EQ::invslot::slotWrist1, EQ::invslot::slotWrist2)) {
eslot = EQ::textures::armorArms; equipment_slot = EQ::textures::armorWrist;
} } else if (found_slot == EQ::invslot::slotHands) {
else if (foundslot == EQ::invslot::slotWrist1 || foundslot == EQ::invslot::slotWrist2) { equipment_slot = EQ::textures::armorHands;
eslot = EQ::textures::armorWrist; } else if (found_slot == EQ::invslot::slotLegs) {
} equipment_slot = EQ::textures::armorLegs;
else if (foundslot == EQ::invslot::slotHands) { } else if (found_slot == EQ::invslot::slotFeet) {
eslot = EQ::textures::armorHands; equipment_slot = EQ::textures::armorFeet;
}
else if (foundslot == EQ::invslot::slotLegs) {
eslot = EQ::textures::armorLegs;
}
else if (foundslot == EQ::invslot::slotFeet) {
eslot = EQ::textures::armorFeet;
} }
/* if (equipment_slot != UINT8_MAX) {
what was this about??? if (wear_change) {
p_wear_change_struct->wear_slot_id = equipment_slot;
if (((npc->GetRace()==127) && (npc->CastToMob()->GetOwnerID()!=0)) && (item2->Slots==24576) || (item2->Slots==8192) || (item2->Slots==16384)){ p_wear_change_struct->material = equipment_material;
npc->d_melee_texture2=Strings::ToInt(newid);
wc->wear_slot_id=8;
if (item2->Material >0)
wc->material=item2->Material;
else
wc->material=Strings::ToInt(newid);
npc->AC+=item2->AC;
npc->STR+=item2->STR;
npc->INT+=item2->INT;
} }
*/
//if we found an open slot it goes in...
if(eslot != 0xFF) {
if(wear_change) {
p_wear_change_struct->wear_slot_id = eslot;
p_wear_change_struct->material = emat;
} }
}
if (found) { if (found) {
item->equip_slot = foundslot; item->equip_slot = found_slot;
} }
} }
if (itemlist) { if (itemlist) {
if (foundslot != INVALID_INDEX) { if (found_slot != INVALID_INDEX) {
GetInv().PutItem(foundslot, *inst); GetInv().PutItem(found_slot, *inst);
}
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_LOOT_ADDED)) {
std::vector<std::any> args = { inst };
parse->EventNPC(EVENT_LOOT_ADDED, this, nullptr, "", 0, &args);
} }
itemlist->push_back(item); itemlist->push_back(item);
@@ -551,55 +556,69 @@ void NPC::AddLootDrop(
} }
UpdateEquipmentLight(); UpdateEquipmentLight();
if (UpdateActiveLight()) { if (UpdateActiveLight()) {
SendAppearancePacket(AT_Light, GetActiveLightType()); SendAppearancePacket(AT_Light, GetActiveLightType());
} }
} }
void NPC::AddItem(const EQ::ItemData *item, uint16 charges, bool equipitem) void NPC::AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item)
{ {
//slot isnt needed, its determined from the item.
auto loot_drop_entry = NPC::NewLootDropEntry(); auto loot_drop_entry = NPC::NewLootDropEntry();
loot_drop_entry.equip_item = static_cast<uint8>(equipitem ? 1 : 0);
loot_drop_entry.equip_item = static_cast<uint8>(equip_item ? 1 : 0);
loot_drop_entry.item_charges = charges; loot_drop_entry.item_charges = charges;
AddLootDrop(item, &itemlist, loot_drop_entry, true); AddLootDrop(item, &itemlist, loot_drop_entry, true);
} }
void NPC::AddItem( void NPC::AddItem(
uint32 itemid, uint32 item_id,
uint16 charges, uint16 charges,
bool equipitem, bool equip_item,
uint32 aug1, uint32 augment_one,
uint32 aug2, uint32 augment_two,
uint32 aug3, uint32 augment_three,
uint32 aug4, uint32 augment_four,
uint32 aug5, uint32 augment_five,
uint32 aug6 uint32 augment_six
) )
{ {
//slot isnt needed, its determined from the item. const auto *item = database.GetItem(item_id);
const EQ::ItemData *i = database.GetItem(itemid); if (!item) {
if (i == nullptr) {
return; return;
} }
auto loot_drop_entry = NPC::NewLootDropEntry(); auto loot_drop_entry = NPC::NewLootDropEntry();
loot_drop_entry.equip_item = static_cast<uint8>(equipitem ? 1 : 0);
loot_drop_entry.equip_item = static_cast<uint8>(equip_item ? 1 : 0);
loot_drop_entry.item_charges = charges; loot_drop_entry.item_charges = charges;
AddLootDrop(i, &itemlist, loot_drop_entry, true, aug1, aug2, aug3, aug4, aug5, aug6); AddLootDrop(
item,
&itemlist,
loot_drop_entry,
true,
augment_one,
augment_two,
augment_three,
augment_four,
augment_five,
augment_six
);
} }
void NPC::AddLootTable() { void NPC::AddLootTable()
{
if (npctype_id != 0) { // check if it's a GM spawn if (npctype_id != 0) { // check if it's a GM spawn
database.AddLootTableToNPC(this,loottable_id, &itemlist, &copper, &silver, &gold, &platinum); database.AddLootTableToNPC(this, loottable_id, &itemlist, &copper, &silver, &gold, &platinum);
} }
} }
void NPC::AddLootTable(uint32 ldid) { void NPC::AddLootTable(uint32 loottable_id)
{
if (npctype_id != 0) { // check if it's a GM spawn if (npctype_id != 0) { // check if it's a GM spawn
database.AddLootTableToNPC(this,ldid, &itemlist, &copper, &silver, &gold, &platinum); database.AddLootTableToNPC(this, loottable_id, &itemlist, &copper, &silver, &gold, &platinum);
} }
} }
+109 -1
View File
@@ -389,6 +389,96 @@ int Lua_Bot::GetRawItemAC() {
return self->GetRawItemAC(); return self->GetRawItemAC();
} }
void Lua_Bot::ClearDisciplineReuseTimer() {
Lua_Safe_Call_Void();
return self->ClearDisciplineReuseTimer();
}
void Lua_Bot::ClearDisciplineReuseTimer(uint16 spell_id) {
Lua_Safe_Call_Void();
return self->ClearDisciplineReuseTimer(spell_id);
}
void Lua_Bot::ClearItemReuseTimer() {
Lua_Safe_Call_Void();
return self->ClearItemReuseTimer();
}
void Lua_Bot::ClearItemReuseTimer(uint32 item_id) {
Lua_Safe_Call_Void();
return self->ClearItemReuseTimer(item_id);
}
void Lua_Bot::ClearSpellRecastTimer() {
Lua_Safe_Call_Void();
return self->ClearSpellRecastTimer();
}
void Lua_Bot::ClearSpellRecastTimer(uint16 spell_id) {
Lua_Safe_Call_Void();
return self->ClearSpellRecastTimer(spell_id);
}
uint32 Lua_Bot::GetDisciplineReuseTimer() {
Lua_Safe_Call_Int();
return self->GetDisciplineReuseRemainingTime();
}
uint32 Lua_Bot::GetDisciplineReuseTimer(uint16 spell_id) {
Lua_Safe_Call_Int();
return self->GetDisciplineReuseRemainingTime(spell_id);
}
uint32 Lua_Bot::GetItemReuseTimer() {
Lua_Safe_Call_Int();
return self->GetItemReuseRemainingTime();
}
uint32 Lua_Bot::GetItemReuseTimer(uint32 item_id) {
Lua_Safe_Call_Int();
return self->GetItemReuseRemainingTime(item_id);
}
uint32 Lua_Bot::GetSpellRecastTimer() {
Lua_Safe_Call_Int();
return self->GetSpellRecastRemainingTime();
}
uint32 Lua_Bot::GetSpellRecastTimer(uint16 spell_id) {
Lua_Safe_Call_Int();
return self->GetSpellRecastRemainingTime(spell_id);
}
void Lua_Bot::SetDisciplineReuseTimer(uint16 spell_id) {
Lua_Safe_Call_Void();
return self->SetDisciplineReuseTimer(spell_id);
}
void Lua_Bot::SetDisciplineReuseTimer(uint16 spell_id, uint32 reuse_timer) {
Lua_Safe_Call_Void();
return self->SetDisciplineReuseTimer(spell_id, reuse_timer);
}
void Lua_Bot::SetItemReuseTimer(uint32 item_id) {
Lua_Safe_Call_Void();
return self->SetItemReuseTimer(item_id);
}
void Lua_Bot::SetItemReuseTimer(uint32 item_id, uint32 reuse_timer) {
Lua_Safe_Call_Void();
return self->SetItemReuseTimer(item_id, reuse_timer);
}
void Lua_Bot::SetSpellRecastTimer(uint16 spell_id) {
Lua_Safe_Call_Void();
return self->SetSpellRecastTimer(spell_id);
}
void Lua_Bot::SetSpellRecastTimer(uint16 spell_id, uint32 recast_delay) {
Lua_Safe_Call_Void();
return self->SetSpellRecastTimer(spell_id, recast_delay);
}
bool Lua_Bot::IsGrouped() { bool Lua_Bot::IsGrouped() {
Lua_Safe_Call_Bool(); Lua_Safe_Call_Bool();
return self->IsGrouped(); return self->IsGrouped();
@@ -600,6 +690,12 @@ luabind::scope lua_register_bot() {
.def("ApplySpellRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::ApplySpellRaid) .def("ApplySpellRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::ApplySpellRaid)
.def("Camp", (void(Lua_Bot::*)(void))&Lua_Bot::Camp) .def("Camp", (void(Lua_Bot::*)(void))&Lua_Bot::Camp)
.def("Camp", (void(Lua_Bot::*)(bool))&Lua_Bot::Camp) .def("Camp", (void(Lua_Bot::*)(bool))&Lua_Bot::Camp)
.def("ClearDisciplineReuseTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearDisciplineReuseTimer)
.def("ClearDisciplineReuseTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::ClearDisciplineReuseTimer)
.def("ClearItemReuseTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearItemReuseTimer)
.def("ClearItemReuseTimer", (void(Lua_Bot::*)(uint32))&Lua_Bot::ClearItemReuseTimer)
.def("ClearSpellRecastTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearSpellRecastTimer)
.def("ClearSpellRecastTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::ClearSpellRecastTimer)
.def("CountBotItem", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::CountBotItem) .def("CountBotItem", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::CountBotItem)
.def("CountItemEquippedByID", (int(Lua_Bot::*)(uint32))&Lua_Bot::CountItemEquippedByID) .def("CountItemEquippedByID", (int(Lua_Bot::*)(uint32))&Lua_Bot::CountItemEquippedByID)
.def("DeleteBucket", (void(Lua_Bot::*)(std::string))&Lua_Bot::DeleteBucket) .def("DeleteBucket", (void(Lua_Bot::*)(std::string))&Lua_Bot::DeleteBucket)
@@ -623,6 +719,8 @@ luabind::scope lua_register_bot() {
.def("GetBotID", (uint32(Lua_Bot::*)(void))&Lua_Bot::GetBotID) .def("GetBotID", (uint32(Lua_Bot::*)(void))&Lua_Bot::GetBotID)
.def("GetBotItem", (Lua_ItemInst(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItem) .def("GetBotItem", (Lua_ItemInst(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItem)
.def("GetBotItemIDBySlot", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItemIDBySlot) .def("GetBotItemIDBySlot", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItemIDBySlot)
.def("GetDisciplineReuseTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetDisciplineReuseTimer)
.def("GetDisciplineReuseTimer", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetDisciplineReuseTimer)
.def("GetBucket", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucket) .def("GetBucket", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucket)
.def("GetBucketExpires", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketExpires) .def("GetBucketExpires", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketExpires)
.def("GetBucketRemaining", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketRemaining) .def("GetBucketRemaining", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketRemaining)
@@ -633,13 +731,17 @@ luabind::scope lua_register_bot() {
.def("GetInstrumentMod", (int(Lua_Bot::*)(int))&Lua_Bot::GetInstrumentMod) .def("GetInstrumentMod", (int(Lua_Bot::*)(int))&Lua_Bot::GetInstrumentMod)
.def("GetItemAt", (Lua_ItemInst(Lua_Bot::*)(int16))&Lua_Bot::GetItemAt) .def("GetItemAt", (Lua_ItemInst(Lua_Bot::*)(int16))&Lua_Bot::GetItemAt)
.def("GetItemIDAt", (int(Lua_Bot::*)(int16))&Lua_Bot::GetItemIDAt) .def("GetItemIDAt", (int(Lua_Bot::*)(int16))&Lua_Bot::GetItemIDAt)
.def("GetItemReuseTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetItemReuseTimer)
.def("GetItemReuseTimer", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::GetItemReuseTimer)
.def("GetOwner", (Lua_Mob(Lua_Bot::*)(void))&Lua_Bot::GetOwner) .def("GetOwner", (Lua_Mob(Lua_Bot::*)(void))&Lua_Bot::GetOwner)
.def("GetRaceAbbreviation", (std::string(Lua_Bot::*)(void))&Lua_Bot::GetRaceAbbreviation) .def("GetRaceAbbreviation", (std::string(Lua_Bot::*)(void))&Lua_Bot::GetRaceAbbreviation)
.def("GetRawItemAC", (int(Lua_Bot::*)(void))&Lua_Bot::GetRawItemAC) .def("GetRawItemAC", (int(Lua_Bot::*)(void))&Lua_Bot::GetRawItemAC)
.def("GetSpellDamage", (int(Lua_Bot::*)(void))&Lua_Bot::GetSpellDamage) .def("GetSpellDamage", (int(Lua_Bot::*)(void))&Lua_Bot::GetSpellDamage)
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetSpellRecastTimer)
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetSpellRecastTimer)
.def("HasAugmentEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasAugmentEquippedByID) .def("HasAugmentEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasAugmentEquippedByID)
.def("HasBotItem", (int16(Lua_Bot::*)(uint32))&Lua_Bot::HasBotItem) .def("HasBotItem", (int16(Lua_Bot::*)(uint32))&Lua_Bot::HasBotItem)
.def("HasBotSpellEntry", (bool(Lua_Bot::*)(uint16)) & Lua_Bot::HasBotSpellEntry) .def("HasBotSpellEntry", (bool(Lua_Bot::*)(uint16))&Lua_Bot::HasBotSpellEntry)
.def("HasItemEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasItemEquippedByID) .def("HasItemEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasItemEquippedByID)
.def("IsGrouped", (bool(Lua_Bot::*)(void))&Lua_Bot::IsGrouped) .def("IsGrouped", (bool(Lua_Bot::*)(void))&Lua_Bot::IsGrouped)
.def("IsSitting", (bool(Lua_Bot::*)(void))&Lua_Bot::IsSitting) .def("IsSitting", (bool(Lua_Bot::*)(void))&Lua_Bot::IsSitting)
@@ -655,6 +757,10 @@ luabind::scope lua_register_bot() {
.def("SetBucket", (void(Lua_Bot::*)(std::string,std::string,std::string))&Lua_Bot::SetBucket) .def("SetBucket", (void(Lua_Bot::*)(std::string,std::string,std::string))&Lua_Bot::SetBucket)
.def("SetExpansionBitmask", (void(Lua_Bot::*)(int))&Lua_Bot::SetExpansionBitmask) .def("SetExpansionBitmask", (void(Lua_Bot::*)(int))&Lua_Bot::SetExpansionBitmask)
.def("SetExpansionBitmask", (void(Lua_Bot::*)(int,bool))&Lua_Bot::SetExpansionBitmask) .def("SetExpansionBitmask", (void(Lua_Bot::*)(int,bool))&Lua_Bot::SetExpansionBitmask)
.def("SetDisciplineReuseTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::SetDisciplineReuseTimer)
.def("SetDisciplineReuseTimer", (void(Lua_Bot::*)(uint16, uint32))&Lua_Bot::SetDisciplineReuseTimer)
.def("SetItemReuseTimer", (void(Lua_Bot::*)(uint32))&Lua_Bot::SetItemReuseTimer)
.def("SetItemReuseTimer", (void(Lua_Bot::*)(uint32, uint32))&Lua_Bot::SetItemReuseTimer)
.def("SetSpellDuration", (void(Lua_Bot::*)(int))&Lua_Bot::SetSpellDuration) .def("SetSpellDuration", (void(Lua_Bot::*)(int))&Lua_Bot::SetSpellDuration)
.def("SetSpellDuration", (void(Lua_Bot::*)(int,int))&Lua_Bot::SetSpellDuration) .def("SetSpellDuration", (void(Lua_Bot::*)(int,int))&Lua_Bot::SetSpellDuration)
.def("SetSpellDuration", (void(Lua_Bot::*)(int,int,int))&Lua_Bot::SetSpellDuration) .def("SetSpellDuration", (void(Lua_Bot::*)(int,int,int))&Lua_Bot::SetSpellDuration)
@@ -668,6 +774,8 @@ luabind::scope lua_register_bot() {
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int))&Lua_Bot::SetSpellDurationRaid) .def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int))&Lua_Bot::SetSpellDurationRaid)
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool))&Lua_Bot::SetSpellDurationRaid) .def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool))&Lua_Bot::SetSpellDurationRaid)
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::SetSpellDurationRaid) .def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::SetSpellDurationRaid)
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::SetSpellRecastTimer)
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16, uint32))&Lua_Bot::SetSpellRecastTimer)
.def("SendPayload", (void(Lua_Bot::*)(int))&Lua_Bot::SendPayload) .def("SendPayload", (void(Lua_Bot::*)(int))&Lua_Bot::SendPayload)
.def("SendPayload", (void(Lua_Bot::*)(int,std::string))&Lua_Bot::SendPayload) .def("SendPayload", (void(Lua_Bot::*)(int,std::string))&Lua_Bot::SendPayload)
.def("Signal", (void(Lua_Bot::*)(int))&Lua_Bot::Signal) .def("Signal", (void(Lua_Bot::*)(int))&Lua_Bot::Signal)
+19
View File
@@ -107,6 +107,25 @@ public:
void SetSpellDurationRaid(int spell_id, int duration, int level, bool allow_pets); void SetSpellDurationRaid(int spell_id, int duration, int level, bool allow_pets);
void SetSpellDurationRaid(int spell_id, int duration, int level, bool allow_pets, bool is_raid_group_only); void SetSpellDurationRaid(int spell_id, int duration, int level, bool allow_pets, bool is_raid_group_only);
void ClearDisciplineReuseTimer();
void ClearDisciplineReuseTimer(uint16 spell_id);
void ClearItemReuseTimer();
void ClearItemReuseTimer(uint32 item_id);
void ClearSpellRecastTimer();
void ClearSpellRecastTimer(uint16 spell_id);
uint32 GetDisciplineReuseTimer();
uint32 GetDisciplineReuseTimer(uint16 spell_id);
uint32 GetItemReuseTimer();
uint32 GetItemReuseTimer(uint32 item_id);
uint32 GetSpellRecastTimer();
uint32 GetSpellRecastTimer(uint16 spell_id);
void SetDisciplineReuseTimer(uint16 spell_id);
void SetDisciplineReuseTimer(uint16 spell_id, uint32 reuse_timer);
void SetItemReuseTimer(uint32 item_id);
void SetItemReuseTimer(uint32 item_id, uint32 reuse_timer);
void SetSpellRecastTimer(uint16 spell_id);
void SetSpellRecastTimer(uint16 spell_id, uint32 reuse_timer);
int CountAugmentEquippedByID(uint32 item_id); int CountAugmentEquippedByID(uint32 item_id);
int CountItemEquippedByID(uint32 item_id); int CountItemEquippedByID(uint32 item_id);
bool HasAugmentEquippedByID(uint32 item_id); bool HasAugmentEquippedByID(uint32 item_id);
+51 -6
View File
@@ -1211,7 +1211,24 @@ void Lua_Client::AddPVPPoints(uint32 points) {
void Lua_Client::AddCrystals(uint32 radiant, uint32 ebon) { void Lua_Client::AddCrystals(uint32 radiant, uint32 ebon) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->AddCrystals(radiant, ebon);
if (ebon != 0) {
if (ebon > 0) {
self->AddEbonCrystals(ebon);
return;
}
self->RemoveEbonCrystals(ebon);
}
if (radiant != 0) {
if (radiant > 0) {
self->AddRadiantCrystals(radiant);
return;
}
self->RemoveRadiantCrystals(radiant);
}
} }
void Lua_Client::SetEbonCrystals(uint32 value) { void Lua_Client::SetEbonCrystals(uint32 value) {
@@ -1486,15 +1503,15 @@ void Lua_Client::Signal(int signal_id) {
void Lua_Client::AddAlternateCurrencyValue(uint32 currency, int amount) { void Lua_Client::AddAlternateCurrencyValue(uint32 currency, int amount) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->AddAlternateCurrencyValue(currency, amount, 1); self->AddAlternateCurrencyValue(currency, amount, true);
} }
void Lua_Client::SetAlternateCurrencyValue(uint32 currency, int amount) { void Lua_Client::SetAlternateCurrencyValue(uint32 currency, uint32 amount) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->SetAlternateCurrencyValue(currency, amount); self->SetAlternateCurrencyValue(currency, amount);
} }
int Lua_Client::GetAlternateCurrencyValue(uint32 currency) { uint32 Lua_Client::GetAlternateCurrencyValue(uint32 currency) {
Lua_Safe_Call_Int(); Lua_Safe_Call_Int();
return self->GetAlternateCurrencyValue(currency); return self->GetAlternateCurrencyValue(currency);
} }
@@ -3176,6 +3193,30 @@ void Lua_Client::GrantAllAAPoints(uint8 unlock_level)
self->GrantAllAAPoints(unlock_level); self->GrantAllAAPoints(unlock_level);
} }
void Lua_Client::AddEbonCrystals(uint32 amount)
{
Lua_Safe_Call_Void();
self->AddEbonCrystals(amount);
}
void Lua_Client::AddRadiantCrystals(uint32 amount)
{
Lua_Safe_Call_Void();
self->AddRadiantCrystals(amount);
}
void Lua_Client::RemoveEbonCrystals(uint32 amount)
{
Lua_Safe_Call_Void();
self->RemoveEbonCrystals(amount);
}
void Lua_Client::RemoveRadiantCrystals(uint32 amount)
{
Lua_Safe_Call_Void();
self->RemoveRadiantCrystals(amount);
}
luabind::scope lua_register_client() { luabind::scope lua_register_client() {
return luabind::class_<Lua_Client, Lua_Mob>("Client") return luabind::class_<Lua_Client, Lua_Mob>("Client")
.def(luabind::constructor<>()) .def(luabind::constructor<>())
@@ -3187,6 +3228,7 @@ luabind::scope lua_register_client() {
.def("AddEXP", (void(Lua_Client::*)(uint32))&Lua_Client::AddEXP) .def("AddEXP", (void(Lua_Client::*)(uint32))&Lua_Client::AddEXP)
.def("AddEXP", (void(Lua_Client::*)(uint32,int))&Lua_Client::AddEXP) .def("AddEXP", (void(Lua_Client::*)(uint32,int))&Lua_Client::AddEXP)
.def("AddEXP", (void(Lua_Client::*)(uint32,int,bool))&Lua_Client::AddEXP) .def("AddEXP", (void(Lua_Client::*)(uint32,int,bool))&Lua_Client::AddEXP)
.def("AddEbonCrystals", (void(Lua_Client::*)(uint32))&Lua_Client::AddEbonCrystals)
.def("AddExpeditionLockout", (void(Lua_Client::*)(std::string, std::string, uint32))&Lua_Client::AddExpeditionLockout) .def("AddExpeditionLockout", (void(Lua_Client::*)(std::string, std::string, uint32))&Lua_Client::AddExpeditionLockout)
.def("AddExpeditionLockout", (void(Lua_Client::*)(std::string, std::string, uint32, std::string))&Lua_Client::AddExpeditionLockout) .def("AddExpeditionLockout", (void(Lua_Client::*)(std::string, std::string, uint32, std::string))&Lua_Client::AddExpeditionLockout)
.def("AddExpeditionLockoutDuration", (void(Lua_Client::*)(std::string, std::string, int))&Lua_Client::AddExpeditionLockoutDuration) .def("AddExpeditionLockoutDuration", (void(Lua_Client::*)(std::string, std::string, int))&Lua_Client::AddExpeditionLockoutDuration)
@@ -3202,6 +3244,7 @@ luabind::scope lua_register_client() {
.def("AddPlatinum", (void(Lua_Client::*)(uint32))&Lua_Client::AddPlatinum) .def("AddPlatinum", (void(Lua_Client::*)(uint32))&Lua_Client::AddPlatinum)
.def("AddPlatinum", (void(Lua_Client::*)(uint32,bool))&Lua_Client::AddPlatinum) .def("AddPlatinum", (void(Lua_Client::*)(uint32,bool))&Lua_Client::AddPlatinum)
.def("AddPVPPoints", (void(Lua_Client::*)(uint32))&Lua_Client::AddPVPPoints) .def("AddPVPPoints", (void(Lua_Client::*)(uint32))&Lua_Client::AddPVPPoints)
.def("AddRadiantCrystals", (void(Lua_Client::*)(uint32))&Lua_Client::AddRadiantCrystals)
.def("AddSkill", (void(Lua_Client::*)(int,int))&Lua_Client::AddSkill) .def("AddSkill", (void(Lua_Client::*)(int,int))&Lua_Client::AddSkill)
.def("Admin", (int16(Lua_Client::*)(void))&Lua_Client::Admin) .def("Admin", (int16(Lua_Client::*)(void))&Lua_Client::Admin)
.def("ApplySpell", (void(Lua_Client::*)(int))&Lua_Client::ApplySpell) .def("ApplySpell", (void(Lua_Client::*)(int))&Lua_Client::ApplySpell)
@@ -3303,7 +3346,7 @@ luabind::scope lua_register_client() {
.def("GetAccountFlags", (luabind::object(Lua_Client::*)(lua_State*))&Lua_Client::GetAccountFlags) .def("GetAccountFlags", (luabind::object(Lua_Client::*)(lua_State*))&Lua_Client::GetAccountFlags)
.def("GetAggroCount", (uint32(Lua_Client::*)(void))&Lua_Client::GetAggroCount) .def("GetAggroCount", (uint32(Lua_Client::*)(void))&Lua_Client::GetAggroCount)
.def("GetAllMoney", (uint64(Lua_Client::*)(void))&Lua_Client::GetAllMoney) .def("GetAllMoney", (uint64(Lua_Client::*)(void))&Lua_Client::GetAllMoney)
.def("GetAlternateCurrencyValue", (int(Lua_Client::*)(uint32))&Lua_Client::GetAlternateCurrencyValue) .def("GetAlternateCurrencyValue", (uint32(Lua_Client::*)(uint32))&Lua_Client::GetAlternateCurrencyValue)
.def("GetAnon", (int(Lua_Client::*)(void))&Lua_Client::GetAnon) .def("GetAnon", (int(Lua_Client::*)(void))&Lua_Client::GetAnon)
.def("GetAugmentIDAt", (int(Lua_Client::*)(int,int))&Lua_Client::GetAugmentIDAt) .def("GetAugmentIDAt", (int(Lua_Client::*)(int,int))&Lua_Client::GetAugmentIDAt)
.def("GetAugmentIDsBySlotID", (luabind::object(Lua_Client::*)(lua_State* L,int16))&Lua_Client::GetAugmentIDsBySlotID) .def("GetAugmentIDsBySlotID", (luabind::object(Lua_Client::*)(lua_State* L,int16))&Lua_Client::GetAugmentIDsBySlotID)
@@ -3554,7 +3597,9 @@ luabind::scope lua_register_client() {
.def("ResetCastbarCooldownBySlot", (void(Lua_Client::*)(int))&Lua_Client::ResetCastbarCooldownBySlot) .def("ResetCastbarCooldownBySlot", (void(Lua_Client::*)(int))&Lua_Client::ResetCastbarCooldownBySlot)
.def("ResetCastbarCooldownBySpellID", (void(Lua_Client::*)(uint32))&Lua_Client::ResetCastbarCooldownBySpellID) .def("ResetCastbarCooldownBySpellID", (void(Lua_Client::*)(uint32))&Lua_Client::ResetCastbarCooldownBySpellID)
.def("ResetDisciplineTimer", (void(Lua_Client::*)(uint32))&Lua_Client::ResetDisciplineTimer) .def("ResetDisciplineTimer", (void(Lua_Client::*)(uint32))&Lua_Client::ResetDisciplineTimer)
.def("RemoveEbonCrystals", (void(Lua_Client::*)(uint32))&Lua_Client::RemoveEbonCrystals)
.def("ResetItemCooldown", (void(Lua_Client::*)(uint32))&Lua_Client::ResetItemCooldown) .def("ResetItemCooldown", (void(Lua_Client::*)(uint32))&Lua_Client::ResetItemCooldown)
.def("RemoveRadiantCrystals", (void(Lua_Client::*)(uint32))&Lua_Client::RemoveRadiantCrystals)
.def("ResetTrade", (void(Lua_Client::*)(void))&Lua_Client::ResetTrade) .def("ResetTrade", (void(Lua_Client::*)(void))&Lua_Client::ResetTrade)
.def("RewardFaction", (void(Lua_Client::*)(int,int))&Lua_Client::RewardFaction) .def("RewardFaction", (void(Lua_Client::*)(int,int))&Lua_Client::RewardFaction)
.def("Save", (void(Lua_Client::*)(int))&Lua_Client::Save) .def("Save", (void(Lua_Client::*)(int))&Lua_Client::Save)
@@ -3586,7 +3631,7 @@ luabind::scope lua_register_client() {
.def("SetAATitle", (void(Lua_Client::*)(std::string,bool))&Lua_Client::SetAATitle) .def("SetAATitle", (void(Lua_Client::*)(std::string,bool))&Lua_Client::SetAATitle)
.def("SetAFK", (void(Lua_Client::*)(uint8))&Lua_Client::SetAFK) .def("SetAFK", (void(Lua_Client::*)(uint8))&Lua_Client::SetAFK)
.def("SetAccountFlag", (void(Lua_Client::*)(const std::string&,const std::string&))&Lua_Client::SetAccountFlag) .def("SetAccountFlag", (void(Lua_Client::*)(const std::string&,const std::string&))&Lua_Client::SetAccountFlag)
.def("SetAlternateCurrencyValue", (void(Lua_Client::*)(uint32,int))&Lua_Client::SetAlternateCurrencyValue) .def("SetAlternateCurrencyValue", (void(Lua_Client::*)(uint32,uint32))&Lua_Client::SetAlternateCurrencyValue)
.def("SetAnon", (void(Lua_Client::*)(uint8))&Lua_Client::SetAnon) .def("SetAnon", (void(Lua_Client::*)(uint8))&Lua_Client::SetAnon)
.def("SetBaseClass", (void(Lua_Client::*)(int))&Lua_Client::SetBaseClass) .def("SetBaseClass", (void(Lua_Client::*)(int))&Lua_Client::SetBaseClass)
.def("SetBaseGender", (void(Lua_Client::*)(int))&Lua_Client::SetBaseGender) .def("SetBaseGender", (void(Lua_Client::*)(int))&Lua_Client::SetBaseGender)
+6 -2
View File
@@ -376,8 +376,8 @@ public:
void NotifyNewTitlesAvailable(); void NotifyNewTitlesAvailable();
void Signal(int signal_id); void Signal(int signal_id);
void AddAlternateCurrencyValue(uint32 currency, int amount); void AddAlternateCurrencyValue(uint32 currency, int amount);
void SetAlternateCurrencyValue(uint32 currency, int amount); void SetAlternateCurrencyValue(uint32 currency, uint32 amount);
int GetAlternateCurrencyValue(uint32 currency); uint32 GetAlternateCurrencyValue(uint32 currency);
void SendWebLink(const char *site); void SendWebLink(const char *site);
bool HasSpellScribed(int spell_id); bool HasSpellScribed(int spell_id);
void ClearAccountFlag(const std::string& flag); void ClearAccountFlag(const std::string& flag);
@@ -482,6 +482,10 @@ public:
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration); void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration);
void GrantAllAAPoints(); void GrantAllAAPoints();
void GrantAllAAPoints(uint8 unlock_level); void GrantAllAAPoints(uint8 unlock_level);
void AddEbonCrystals(uint32 amount);
void AddRadiantCrystals(uint32 amount);
void RemoveEbonCrystals(uint32 amount);
void RemoveRadiantCrystals(uint32 amount);
void ApplySpell(int spell_id); void ApplySpell(int spell_id);
void ApplySpell(int spell_id, int duration); void ApplySpell(int spell_id, int duration);
+55 -47
View File
@@ -5431,7 +5431,7 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
LuaCreateNPCParse(runspeed, float, 1.25f); LuaCreateNPCParse(runspeed, float, 1.25f);
LuaCreateNPCParse(gender, uint8, 0); LuaCreateNPCParse(gender, uint8, 0);
LuaCreateNPCParse(race, uint16, 1); LuaCreateNPCParse(race, uint16, 1);
LuaCreateNPCParse(class_, uint8, WARRIOR); LuaCreateNPCParse(class_, uint8, Class::Warrior);
LuaCreateNPCParse(bodytype, uint8, 0); LuaCreateNPCParse(bodytype, uint8, 0);
LuaCreateNPCParse(deity, uint8, 0); LuaCreateNPCParse(deity, uint8, 0);
LuaCreateNPCParse(level, uint8, 1); LuaCreateNPCParse(level, uint8, 1);
@@ -6609,7 +6609,14 @@ luabind::scope lua_register_events() {
luabind::value("memorize_spell", static_cast<int>(EVENT_MEMORIZE_SPELL)), luabind::value("memorize_spell", static_cast<int>(EVENT_MEMORIZE_SPELL)),
luabind::value("unmemorize_spell", static_cast<int>(EVENT_UNMEMORIZE_SPELL)), luabind::value("unmemorize_spell", static_cast<int>(EVENT_UNMEMORIZE_SPELL)),
luabind::value("scribe_spell", static_cast<int>(EVENT_SCRIBE_SPELL)), luabind::value("scribe_spell", static_cast<int>(EVENT_SCRIBE_SPELL)),
luabind::value("unscribe_spell", static_cast<int>(EVENT_UNSCRIBE_SPELL)) luabind::value("unscribe_spell", static_cast<int>(EVENT_UNSCRIBE_SPELL)),
luabind::value("loot_added", static_cast<int>(EVENT_LOOT_ADDED)),
luabind::value("ldon_points_gain", static_cast<int>(EVENT_LDON_POINTS_GAIN)),
luabind::value("ldon_points_loss", static_cast<int>(EVENT_LDON_POINTS_LOSS)),
luabind::value("alt_currency_gain", static_cast<int>(EVENT_ALT_CURRENCY_GAIN)),
luabind::value("alt_currency_loss", static_cast<int>(EVENT_ALT_CURRENCY_LOSS)),
luabind::value("crystal_gain", static_cast<int>(EVENT_CRYSTAL_GAIN)),
luabind::value("crystal_loss", static_cast<int>(EVENT_CRYSTAL_LOSS))
)]; )];
} }
@@ -6778,51 +6785,52 @@ luabind::scope lua_register_classes() {
return luabind::class_<Classes>("Class") return luabind::class_<Classes>("Class")
.enum_("constants") .enum_("constants")
[( [(
luabind::value("WARRIOR", WARRIOR), luabind::value("WARRIOR", Class::Warrior),
luabind::value("CLERIC", CLERIC), luabind::value("CLERIC", Class::Cleric),
luabind::value("PALADIN", PALADIN), luabind::value("PALADIN", Class::Paladin),
luabind::value("RANGER", RANGER), luabind::value("RANGER", Class::Ranger),
luabind::value("SHADOWKNIGHT", SHADOWKNIGHT), luabind::value("SHADOWKNIGHT", Class::ShadowKnight),
luabind::value("DRUID", DRUID), luabind::value("DRUID", Class::Druid),
luabind::value("MONK", MONK), luabind::value("MONK", Class::Monk),
luabind::value("BARD", BARD), luabind::value("BARD", Class::Bard),
luabind::value("ROGUE", ROGUE), luabind::value("ROGUE", Class::Rogue),
luabind::value("SHAMAN", SHAMAN), luabind::value("SHAMAN", Class::Shaman),
luabind::value("NECROMANCER", NECROMANCER), luabind::value("NECROMANCER", Class::Necromancer),
luabind::value("WIZARD", WIZARD), luabind::value("WIZARD", Class::Wizard),
luabind::value("MAGICIAN", MAGICIAN), luabind::value("MAGICIAN", Class::Magician),
luabind::value("ENCHANTER", ENCHANTER), luabind::value("ENCHANTER", Class::Enchanter),
luabind::value("BEASTLORD", BEASTLORD), luabind::value("BEASTLORD", Class::Beastlord),
luabind::value("BERSERKER", BERSERKER), luabind::value("BERSERKER", Class::Berserker),
luabind::value("WARRIORGM", WARRIORGM), luabind::value("WARRIORGM", Class::WarriorGM),
luabind::value("CLERICGM", CLERICGM), luabind::value("CLERICGM", Class::ClericGM),
luabind::value("PALADINGM", PALADINGM), luabind::value("PALADINGM", Class::PaladinGM),
luabind::value("RANGERGM", RANGERGM), luabind::value("RANGERGM", Class::RangerGM),
luabind::value("SHADOWKNIGHTGM", SHADOWKNIGHTGM), luabind::value("SHADOWKNIGHTGM", Class::ShadowKnightGM),
luabind::value("DRUIDGM", DRUIDGM), luabind::value("DRUIDGM", Class::DruidGM),
luabind::value("MONKGM", MONKGM), luabind::value("MONKGM", Class::MonkGM),
luabind::value("BARDGM", BARDGM), luabind::value("BARDGM", Class::BardGM),
luabind::value("ROGUEGM", ROGUEGM), luabind::value("ROGUEGM", Class::RogueGM),
luabind::value("SHAMANGM", SHAMANGM), luabind::value("SHAMANGM", Class::ShamanGM),
luabind::value("NECROMANCERGM", NECROMANCERGM), luabind::value("NECROMANCERGM", Class::NecromancerGM),
luabind::value("WIZARDGM", WIZARDGM), luabind::value("WIZARDGM", Class::WizardGM),
luabind::value("MAGICIANGM", MAGICIANGM), luabind::value("MAGICIANGM", Class::MagicianGM),
luabind::value("ENCHANTERGM", ENCHANTERGM), luabind::value("ENCHANTERGM", Class::EnchanterGM),
luabind::value("BEASTLORDGM", BEASTLORDGM), luabind::value("BEASTLORDGM", Class::BeastlordGM),
luabind::value("BERSERKERGM", BERSERKERGM), luabind::value("BERSERKERGM", Class::BerserkerGM),
luabind::value("BANKER", BANKER), luabind::value("BANKER", Class::Banker),
luabind::value("MERCHANT", MERCHANT), luabind::value("MERCHANT", Class::Merchant),
luabind::value("DISCORD_MERCHANT", DISCORD_MERCHANT), luabind::value("DISCORD_MERCHANT", Class::DiscordMerchant),
luabind::value("ADVENTURE_RECRUITER", ADVENTURE_RECRUITER), luabind::value("ADVENTURE_RECRUITER", Class::AdventureRecruiter),
luabind::value("ADVENTURE_MERCHANT", ADVENTURE_MERCHANT), luabind::value("ADVENTURE_MERCHANT", Class::AdventureMerchant),
luabind::value("LDON_TREASURE", LDON_TREASURE), luabind::value("LDON_TREASURE", Class::LDoNTreasure),
luabind::value("TRIBUTE_MASTER", TRIBUTE_MASTER), luabind::value("TRIBUTE_MASTER", Class::TributeMaster),
luabind::value("GUILD_TRIBUTE_MASTER", GUILD_TRIBUTE_MASTER), luabind::value("GUILD_TRIBUTE_MASTER", Class::GuildTributeMaster),
luabind::value("NORRATHS_KEEPERS_MERCHANT", NORRATHS_KEEPERS_MERCHANT), luabind::value("GUILD_BANKER", Class::GuildBanker),
luabind::value("DARK_REIGN_MERCHANT", DARK_REIGN_MERCHANT), luabind::value("NORRATHS_KEEPERS_MERCHANT", Class::NorrathsKeepersMerchant),
luabind::value("FELLOWSHIP_MASTER", FELLOWSHIP_MASTER), luabind::value("DARK_REIGN_MERCHANT", Class::DarkReignMerchant),
luabind::value("ALT_CURRENCY_MERCHANT", ALT_CURRENCY_MERCHANT), luabind::value("FELLOWSHIP_MASTER", Class::FellowshipMaster),
luabind::value("MERCENARY_MASTER", MERCENARY_MASTER) luabind::value("ALT_CURRENCY_MERCHANT", Class::AlternateCurrencyMerchant),
luabind::value("MERCENARY_MASTER", Class::MercenaryLiaison)
)]; )];
} }
+14
View File
@@ -813,6 +813,18 @@ void Lua_NPC::SetBucket(std::string bucket_name, std::string bucket_value, std::
self->SetBucket(bucket_name, bucket_value, expiration); self->SetBucket(bucket_name, bucket_value, expiration);
} }
bool Lua_NPC::GetNPCAggro()
{
Lua_Safe_Call_Bool();
return self->GetNPCAggro();
}
void Lua_NPC::SetNPCAggro(bool in_npc_aggro)
{
Lua_Safe_Call_Void();
self->SetNPCAggro(in_npc_aggro);
}
luabind::scope lua_register_npc() { luabind::scope lua_register_npc() {
return luabind::class_<Lua_NPC, Lua_Mob>("NPC") return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
.def(luabind::constructor<>()) .def(luabind::constructor<>())
@@ -872,6 +884,7 @@ luabind::scope lua_register_npc() {
.def("GetLDoNLockedSkill", (uint16(Lua_NPC::*)(void))&Lua_NPC::GetLDoNLockedSkill) .def("GetLDoNLockedSkill", (uint16(Lua_NPC::*)(void))&Lua_NPC::GetLDoNLockedSkill)
.def("GetLDoNTrapType", (uint8(Lua_NPC::*)(void))&Lua_NPC::GetLDoNTrapType) .def("GetLDoNTrapType", (uint8(Lua_NPC::*)(void))&Lua_NPC::GetLDoNTrapType)
.def("GetLDoNTrapSpellID", (uint16(Lua_NPC::*)(void))&Lua_NPC::GetLDoNTrapSpellID) .def("GetLDoNTrapSpellID", (uint16(Lua_NPC::*)(void))&Lua_NPC::GetLDoNTrapSpellID)
.def("GetNPCAggro", (bool(Lua_NPC::*)(void))&Lua_NPC::GetNPCAggro)
.def("GetNPCFactionID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCFactionID) .def("GetNPCFactionID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCFactionID)
.def("GetNPCHate", (int64(Lua_NPC::*)(Lua_Mob))&Lua_NPC::GetNPCHate) .def("GetNPCHate", (int64(Lua_NPC::*)(Lua_Mob))&Lua_NPC::GetNPCHate)
.def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID) .def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID)
@@ -949,6 +962,7 @@ luabind::scope lua_register_npc() {
.def("SetLDoNTrapDetected", (void(Lua_NPC::*)(bool))&Lua_NPC::SetLDoNTrapDetected) .def("SetLDoNTrapDetected", (void(Lua_NPC::*)(bool))&Lua_NPC::SetLDoNTrapDetected)
.def("SetLDoNTrapSpellID", (void(Lua_NPC::*)(uint16))&Lua_NPC::SetLDoNTrapSpellID) .def("SetLDoNTrapSpellID", (void(Lua_NPC::*)(uint16))&Lua_NPC::SetLDoNTrapSpellID)
.def("SetLDoNTrapType", (void(Lua_NPC::*)(uint8))&Lua_NPC::SetLDoNTrapType) .def("SetLDoNTrapType", (void(Lua_NPC::*)(uint8))&Lua_NPC::SetLDoNTrapType)
.def("SetNPCAggro", (void(Lua_NPC::*)(bool))&Lua_NPC::SetNPCAggro)
.def("SetNPCFactionID", (void(Lua_NPC::*)(int))&Lua_NPC::SetNPCFactionID) .def("SetNPCFactionID", (void(Lua_NPC::*)(int))&Lua_NPC::SetNPCFactionID)
.def("SetPetSpellID", (void(Lua_NPC::*)(int))&Lua_NPC::SetPetSpellID) .def("SetPetSpellID", (void(Lua_NPC::*)(int))&Lua_NPC::SetPetSpellID)
.def("SetPlatinum", (void(Lua_NPC::*)(uint32))&Lua_NPC::SetPlatinum) .def("SetPlatinum", (void(Lua_NPC::*)(uint32))&Lua_NPC::SetPlatinum)
+2
View File
@@ -182,6 +182,8 @@ public:
std::string GetBucketRemaining(std::string bucket_name); std::string GetBucketRemaining(std::string bucket_name);
void SetBucket(std::string bucket_name, std::string bucket_value); void SetBucket(std::string bucket_name, std::string bucket_value);
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration); void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration);
bool GetNPCAggro();
void SetNPCAggro(bool in_npc_aggro);
}; };
#endif #endif
+17 -1
View File
@@ -168,7 +168,14 @@ const char *LuaEvents[_LargestEventID] = {
"event_memorize_spell", "event_memorize_spell",
"event_unmemorize_spell", "event_unmemorize_spell",
"event_scribe_spell", "event_scribe_spell",
"event_unscribe_spell" "event_unscribe_spell",
"event_loot_added",
"event_ldon_points_gain",
"event_ldon_points_loss",
"event_alt_currency_gain",
"event_alt_currency_loss",
"event_crystal_gain",
"event_crystal_loss"
}; };
extern Zone *zone; extern Zone *zone;
@@ -226,6 +233,7 @@ LuaParser::LuaParser() {
NPCArgumentDispatch[EVENT_DESPAWN_ZONE] = handle_npc_despawn_zone; NPCArgumentDispatch[EVENT_DESPAWN_ZONE] = handle_npc_despawn_zone;
NPCArgumentDispatch[EVENT_DAMAGE_GIVEN] = handle_npc_damage; NPCArgumentDispatch[EVENT_DAMAGE_GIVEN] = handle_npc_damage;
NPCArgumentDispatch[EVENT_DAMAGE_TAKEN] = handle_npc_damage; NPCArgumentDispatch[EVENT_DAMAGE_TAKEN] = handle_npc_damage;
NPCArgumentDispatch[EVENT_LOOT_ADDED] = handle_npc_loot_added;
PlayerArgumentDispatch[EVENT_SAY] = handle_player_say; PlayerArgumentDispatch[EVENT_SAY] = handle_player_say;
PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage; PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage;
@@ -300,6 +308,12 @@ LuaParser::LuaParser() {
PlayerArgumentDispatch[EVENT_UNMEMORIZE_SPELL] = handle_player_memorize_scribe_spell; PlayerArgumentDispatch[EVENT_UNMEMORIZE_SPELL] = handle_player_memorize_scribe_spell;
PlayerArgumentDispatch[EVENT_SCRIBE_SPELL] = handle_player_memorize_scribe_spell; PlayerArgumentDispatch[EVENT_SCRIBE_SPELL] = handle_player_memorize_scribe_spell;
PlayerArgumentDispatch[EVENT_UNSCRIBE_SPELL] = handle_player_memorize_scribe_spell; PlayerArgumentDispatch[EVENT_UNSCRIBE_SPELL] = handle_player_memorize_scribe_spell;
PlayerArgumentDispatch[EVENT_LDON_POINTS_GAIN] = handle_player_ldon_points_gain_loss;
PlayerArgumentDispatch[EVENT_LDON_POINTS_LOSS] = handle_player_ldon_points_gain_loss;
PlayerArgumentDispatch[EVENT_ALT_CURRENCY_GAIN] = handle_player_alt_currency_gain_loss;
PlayerArgumentDispatch[EVENT_ALT_CURRENCY_LOSS] = handle_player_alt_currency_gain_loss;
PlayerArgumentDispatch[EVENT_CRYSTAL_GAIN] = handle_player_crystal_gain_loss;
PlayerArgumentDispatch[EVENT_CRYSTAL_LOSS] = handle_player_crystal_gain_loss;
ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click; ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click;
ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click; ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click;
@@ -341,6 +355,8 @@ LuaParser::LuaParser() {
BotArgumentDispatch[EVENT_UNEQUIP_ITEM_BOT] = handle_bot_equip_item; BotArgumentDispatch[EVENT_UNEQUIP_ITEM_BOT] = handle_bot_equip_item;
BotArgumentDispatch[EVENT_DAMAGE_GIVEN] = handle_bot_damage; BotArgumentDispatch[EVENT_DAMAGE_GIVEN] = handle_bot_damage;
BotArgumentDispatch[EVENT_DAMAGE_TAKEN] = handle_bot_damage; BotArgumentDispatch[EVENT_DAMAGE_TAKEN] = handle_bot_damage;
BotArgumentDispatch[EVENT_LEVEL_UP] = handle_bot_level_up;
BotArgumentDispatch[EVENT_LEVEL_DOWN] = handle_bot_level_down;
#endif #endif
L = nullptr; L = nullptr;
+140
View File
@@ -492,6 +492,63 @@ void handle_npc_damage(
lua_setfield(L, -2, "other"); lua_setfield(L, -2, "other");
} }
void handle_npc_loot_added(
QuestInterface *parse,
lua_State* L,
NPC* npc,
Mob* init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
if (extra_pointers && extra_pointers->size() == 1) {
auto *inst = std::any_cast<EQ::ItemInstance *>(extra_pointers->at(0));
auto *item = database.GetItem(inst->GetID());
if (item) {
Lua_Item l_item(item);
luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L);
lua_setfield(L, -2, "item");
} else {
Lua_Item l_item(nullptr);
luabind::adl::object l_item_o = luabind::adl::object(L, l_item);
l_item_o.push(L);
lua_setfield(L, -2, "item");
}
if (inst) {
lua_pushinteger(L, inst->GetID());
lua_setfield(L, -2, "item_id");
lua_pushstring(L, inst->GetItem()->Name);
lua_setfield(L, -2, "item_name");
lua_pushinteger(L, inst->GetCharges());
lua_setfield(L, -2, "item_charges");
lua_pushinteger(L, inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN));
lua_setfield(L, -2, "augment_one");
lua_pushinteger(L, inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 1));
lua_setfield(L, -2, "augment_two");
lua_pushinteger(L, inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 2));
lua_setfield(L, -2, "augment_three");
lua_pushinteger(L, inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 3));
lua_setfield(L, -2, "augment_four");
lua_pushinteger(L, inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 4));
lua_setfield(L, -2, "augment_five");
lua_pushinteger(L, inst->GetAugmentItemID(EQ::invaug::SOCKET_END));
lua_setfield(L, -2, "augment_six");
}
}
}
// Player // Player
void handle_player_say( void handle_player_say(
QuestInterface *parse, QuestInterface *parse,
@@ -1444,6 +1501,63 @@ void handle_player_memorize_scribe_spell(
} }
} }
void handle_player_ldon_points_gain_loss(
QuestInterface *parse,
lua_State* L,
Client* client,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Seperator sep(data.c_str());
lua_pushnumber(L, Strings::ToUnsignedInt(sep.arg[0]));
lua_setfield(L, -2, "theme_id");
lua_pushnumber(L, Strings::ToUnsignedInt(sep.arg[1]));
lua_setfield(L, -2, "points");
}
void handle_player_crystal_gain_loss(
QuestInterface *parse,
lua_State* L,
Client* client,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Seperator sep(data.c_str());
lua_pushnumber(L, Strings::ToUnsignedInt(sep.arg[0]));
lua_setfield(L, -2, "ebon_amount");
lua_pushnumber(L, Strings::ToUnsignedInt(sep.arg[1]));
lua_setfield(L, -2, "radiant_amount");
lua_pushboolean(L, Strings::ToBool(sep.arg[2]));
lua_setfield(L, -2, "is_reclaim");
}
void handle_player_alt_currency_gain_loss(
QuestInterface *parse,
lua_State* L,
Client* client,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
Seperator sep(data.c_str());
lua_pushnumber(L, Strings::ToUnsignedInt(sep.arg[0]));
lua_setfield(L, -2, "currency_id");
lua_pushnumber(L, Strings::ToInt(sep.arg[1]));
lua_setfield(L, -2, "amount");
lua_pushnumber(L, Strings::ToUnsignedInt(sep.arg[2]));
lua_setfield(L, -2, "total");
}
// Item // Item
void handle_item_click( void handle_item_click(
QuestInterface *parse, QuestInterface *parse,
@@ -2300,4 +2414,30 @@ void handle_bot_damage(
lua_setfield(L, -2, "other"); lua_setfield(L, -2, "other");
} }
void handle_bot_level_up(
QuestInterface *parse,
lua_State* L,
Bot* bot,
Mob *init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
lua_pushinteger(L, Strings::ToInt(data));
lua_setfield(L, -2, "levels_gained");
}
void handle_bot_level_down(
QuestInterface *parse,
lua_State* L,
Bot* bot,
Mob *init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
lua_pushinteger(L, Strings::ToInt(data));
lua_setfield(L, -2, "levels_lost");
}
#endif #endif
+57
View File
@@ -210,6 +210,16 @@ void handle_npc_damage(
std::vector<std::any> *extra_pointers std::vector<std::any> *extra_pointers
); );
void handle_npc_loot_added(
QuestInterface *parse,
lua_State* L,
NPC* npc,
Mob *init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
// Player // Player
void handle_player_say( void handle_player_say(
QuestInterface *parse, QuestInterface *parse,
@@ -733,6 +743,33 @@ void handle_player_memorize_scribe_spell(
std::vector<std::any> *extra_pointers std::vector<std::any> *extra_pointers
); );
void handle_player_ldon_points_gain_loss(
QuestInterface *parse,
lua_State* L,
Client* client,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_player_alt_currency_gain_loss(
QuestInterface *parse,
lua_State* L,
Client* client,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_player_crystal_gain_loss(
QuestInterface *parse,
lua_State* L,
Client* client,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
// Item // Item
void handle_item_click( void handle_item_click(
QuestInterface *parse, QuestInterface *parse,
@@ -1055,5 +1092,25 @@ void handle_bot_damage(
std::vector<std::any> *extra_pointers std::vector<std::any> *extra_pointers
); );
void handle_bot_level_up(
QuestInterface *parse,
lua_State* L,
Bot* bot,
Mob* init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
void handle_bot_level_down(
QuestInterface *parse,
lua_State* L,
Bot* bot,
Mob* init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
#endif #endif
#endif #endif
+7 -7
View File
@@ -60,7 +60,7 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
SetStance(EQ::constants::stanceBalanced); SetStance(EQ::constants::stanceBalanced);
rest_timer.Disable(); rest_timer.Disable();
if (GetClass() == ROGUE) if (GetClass() == Class::Rogue)
evade_timer.Start(); evade_timer.Start();
int r; int r;
@@ -1090,7 +1090,7 @@ void Merc::AI_Process() {
float meleeDistance = GetMaxMeleeRangeToTarget(GetTarget()); float meleeDistance = GetMaxMeleeRangeToTarget(GetTarget());
if(GetClass() == SHADOWKNIGHT || GetClass() == PALADIN || GetClass() == WARRIOR) { if(GetClass() == Class::ShadowKnight || GetClass() == Class::Paladin || GetClass() == Class::Warrior) {
meleeDistance = meleeDistance * .30; meleeDistance = meleeDistance * .30;
} }
else { else {
@@ -1118,7 +1118,7 @@ void Merc::AI_Process() {
if(AI_movement_timer->Check()) { if(AI_movement_timer->Check()) {
if (!IsMoving()) { if (!IsMoving()) {
if (GetClass() == ROGUE) { if (GetClass() == Class::Rogue) {
if (HasTargetReflection() && !GetTarget()->IsFeared() && !GetTarget()->IsStunned()) { if (HasTargetReflection() && !GetTarget()->IsFeared() && !GetTarget()->IsStunned()) {
// Hate redux actions // Hate redux actions
if (evade_timer.Check(false)) { if (evade_timer.Check(false)) {
@@ -1161,7 +1161,7 @@ void Merc::AI_Process() {
} }
} }
} }
else if (GetClass() != ROGUE && (DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) < GetTarget()->GetSize())) { else if (GetClass() != Class::Rogue && (DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) < GetTarget()->GetSize())) {
// If we are not a rogue trying to backstab, let's try to adjust our melee range so we don't appear to be bunched up // If we are not a rogue trying to backstab, let's try to adjust our melee range so we don't appear to be bunched up
float newX = 0; float newX = 0;
float newY = 0; float newY = 0;
@@ -1240,7 +1240,7 @@ void Merc::AI_Process() {
} }
// TODO: Do mercs berserk? Find this out on live... // TODO: Do mercs berserk? Find this out on live...
//if (GetClass() == WARRIOR || GetClass() == BERSERKER) { //if (GetClass() == Class::Warrior || GetClass() == Class::Berserker) {
// if(GetHP() > 0 && !berserk && GetHPRatio() < 30) { // if(GetHP() > 0 && !berserk && GetHPRatio() < 30) {
// entity_list.MessageCloseString(this, false, 200, 0, BERSERK_START, GetName()); // entity_list.MessageCloseString(this, false, 200, 0, BERSERK_START, GetName());
// berserk = true; // berserk = true;
@@ -1685,8 +1685,8 @@ bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) {
continue; continue;
} }
if(IsEngaged() && (g->members[i]->GetClass() == NECROMANCER && hpr >= 50) if(IsEngaged() && (g->members[i]->GetClass() == Class::Necromancer && hpr >= 50)
|| (g->members[i]->GetClass() == SHAMAN && hpr >= 80)) { || (g->members[i]->GetClass() == Class::Shaman && hpr >= 80)) {
//allow necros to lifetap & shaman to canni without wasting mana //allow necros to lifetap & shaman to canni without wasting mana
continue; continue;
} }
+131 -137
View File
@@ -983,33 +983,33 @@ int64 Mob::GetSpellHPBonuses() {
char Mob::GetCasterClass() const { char Mob::GetCasterClass() const {
switch(class_) switch(class_)
{ {
case CLERIC: case Class::Cleric:
case PALADIN: case Class::Paladin:
case RANGER: case Class::Ranger:
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
case BEASTLORD: case Class::Beastlord:
case CLERICGM: case Class::ClericGM:
case PALADINGM: case Class::PaladinGM:
case RANGERGM: case Class::RangerGM:
case DRUIDGM: case Class::DruidGM:
case SHAMANGM: case Class::ShamanGM:
case BEASTLORDGM: case Class::BeastlordGM:
return 'W'; return 'W';
break; break;
case SHADOWKNIGHT: case Class::ShadowKnight:
case BARD: case Class::Bard:
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
case SHADOWKNIGHTGM: case Class::ShadowKnightGM:
case BARDGM: case Class::BardGM:
case NECROMANCERGM: case Class::NecromancerGM:
case WIZARDGM: case Class::WizardGM:
case MAGICIANGM: case Class::MagicianGM:
case ENCHANTERGM: case Class::EnchanterGM:
return 'I'; return 'I';
break; break;
@@ -1022,42 +1022,42 @@ char Mob::GetCasterClass() const {
uint8 Mob::GetArchetype() const { uint8 Mob::GetArchetype() const {
switch(class_) switch(class_)
{ {
case PALADIN: case Class::Paladin:
case RANGER: case Class::Ranger:
case SHADOWKNIGHT: case Class::ShadowKnight:
case BARD: case Class::Bard:
case BEASTLORD: case Class::Beastlord:
case PALADINGM: case Class::PaladinGM:
case RANGERGM: case Class::RangerGM:
case SHADOWKNIGHTGM: case Class::ShadowKnightGM:
case BARDGM: case Class::BardGM:
case BEASTLORDGM: case Class::BeastlordGM:
return ARCHETYPE_HYBRID; return ARCHETYPE_HYBRID;
break; break;
case CLERIC: case Class::Cleric:
case DRUID: case Class::Druid:
case SHAMAN: case Class::Shaman:
case NECROMANCER: case Class::Necromancer:
case WIZARD: case Class::Wizard:
case MAGICIAN: case Class::Magician:
case ENCHANTER: case Class::Enchanter:
case CLERICGM: case Class::ClericGM:
case DRUIDGM: case Class::DruidGM:
case SHAMANGM: case Class::ShamanGM:
case NECROMANCERGM: case Class::NecromancerGM:
case WIZARDGM: case Class::WizardGM:
case MAGICIANGM: case Class::MagicianGM:
case ENCHANTERGM: case Class::EnchanterGM:
return ARCHETYPE_CASTER; return ARCHETYPE_CASTER;
break; break;
case WARRIOR: case Class::Warrior:
case MONK: case Class::Monk:
case ROGUE: case Class::Rogue:
case BERSERKER: case Class::Berserker:
case WARRIORGM: case Class::WarriorGM:
case MONKGM: case Class::MonkGM:
case ROGUEGM: case Class::RogueGM:
case BERSERKERGM: case Class::BerserkerGM:
return ARCHETYPE_MELEE; return ARCHETYPE_MELEE;
break; break;
default: default:
@@ -1069,73 +1069,73 @@ uint8 Mob::GetArchetype() const {
void Mob::SetSpawnLastNameByClass(NewSpawn_Struct* ns) void Mob::SetSpawnLastNameByClass(NewSpawn_Struct* ns)
{ {
switch (ns->spawn.class_) { switch (ns->spawn.class_) {
case TRIBUTE_MASTER: case Class::TributeMaster:
strcpy(ns->spawn.lastName, "Tribute Master"); strcpy(ns->spawn.lastName, "Tribute Master");
break; break;
case GUILD_TRIBUTE_MASTER: case Class::GuildTributeMaster:
strcpy(ns->spawn.lastName, "Guild Tribute Master"); strcpy(ns->spawn.lastName, "Guild Tribute Master");
break; break;
case GUILD_BANKER: case Class::GuildBanker:
strcpy(ns->spawn.lastName, "Guild Banker"); strcpy(ns->spawn.lastName, "Guild Banker");
break; break;
case ADVENTURE_RECRUITER: case Class::AdventureRecruiter:
strcpy(ns->spawn.lastName, "Adventure Recruiter"); strcpy(ns->spawn.lastName, "Adventure Recruiter");
break; break;
case ADVENTURE_MERCHANT: case Class::AdventureMerchant:
strcpy(ns->spawn.lastName, "Adventure Merchant"); strcpy(ns->spawn.lastName, "Adventure Merchant");
break; break;
case BANKER: case Class::Banker:
strcpy(ns->spawn.lastName, "Banker"); strcpy(ns->spawn.lastName, "Banker");
break; break;
case WARRIORGM: case Class::WarriorGM:
strcpy(ns->spawn.lastName, "Warrior Guildmaster"); strcpy(ns->spawn.lastName, "Warrior Guildmaster");
break; break;
case CLERICGM: case Class::ClericGM:
strcpy(ns->spawn.lastName, "Cleric Guildmaster"); strcpy(ns->spawn.lastName, "Cleric Guildmaster");
break; break;
case PALADINGM: case Class::PaladinGM:
strcpy(ns->spawn.lastName, "Paladin Guildmaster"); strcpy(ns->spawn.lastName, "Paladin Guildmaster");
break; break;
case RANGERGM: case Class::RangerGM:
strcpy(ns->spawn.lastName, "Ranger Guildmaster"); strcpy(ns->spawn.lastName, "Ranger Guildmaster");
break; break;
case SHADOWKNIGHTGM: case Class::ShadowKnightGM:
strcpy(ns->spawn.lastName, "Shadow Knight Guildmaster"); strcpy(ns->spawn.lastName, "Shadow Knight Guildmaster");
break; break;
case DRUIDGM: case Class::DruidGM:
strcpy(ns->spawn.lastName, "Druid Guildmaster"); strcpy(ns->spawn.lastName, "Druid Guildmaster");
break; break;
case MONKGM: case Class::MonkGM:
strcpy(ns->spawn.lastName, "Monk Guildmaster"); strcpy(ns->spawn.lastName, "Monk Guildmaster");
break; break;
case BARDGM: case Class::BardGM:
strcpy(ns->spawn.lastName, "Bard Guildmaster"); strcpy(ns->spawn.lastName, "Bard Guildmaster");
break; break;
case ROGUEGM: case Class::RogueGM:
strcpy(ns->spawn.lastName, "Rogue Guildmaster"); strcpy(ns->spawn.lastName, "Rogue Guildmaster");
break; break;
case SHAMANGM: case Class::ShamanGM:
strcpy(ns->spawn.lastName, "Shaman Guildmaster"); strcpy(ns->spawn.lastName, "Shaman Guildmaster");
break; break;
case NECROMANCERGM: case Class::NecromancerGM:
strcpy(ns->spawn.lastName, "Necromancer Guildmaster"); strcpy(ns->spawn.lastName, "Necromancer Guildmaster");
break; break;
case WIZARDGM: case Class::WizardGM:
strcpy(ns->spawn.lastName, "Wizard Guildmaster"); strcpy(ns->spawn.lastName, "Wizard Guildmaster");
break; break;
case MAGICIANGM: case Class::MagicianGM:
strcpy(ns->spawn.lastName, "Magician Guildmaster"); strcpy(ns->spawn.lastName, "Magician Guildmaster");
break; break;
case ENCHANTERGM: case Class::EnchanterGM:
strcpy(ns->spawn.lastName, "Enchanter Guildmaster"); strcpy(ns->spawn.lastName, "Enchanter Guildmaster");
break; break;
case BEASTLORDGM: case Class::BeastlordGM:
strcpy(ns->spawn.lastName, "Beastlord Guildmaster"); strcpy(ns->spawn.lastName, "Beastlord Guildmaster");
break; break;
case BERSERKERGM: case Class::BerserkerGM:
strcpy(ns->spawn.lastName, "Berserker Guildmaster"); strcpy(ns->spawn.lastName, "Berserker Guildmaster");
break; break;
case MERCENARY_MASTER: case Class::MercenaryLiaison:
strcpy(ns->spawn.lastName, "Mercenary Liaison"); strcpy(ns->spawn.lastName, "Mercenary Liaison");
break; break;
default: default:
@@ -1346,8 +1346,8 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
} }
if (RuleB(Character, AllowCrossClassTrainers) && ForWho) { if (RuleB(Character, AllowCrossClassTrainers) && ForWho) {
if (ns->spawn.class_ >= WARRIORGM && ns->spawn.class_ <= BERSERKERGM) { if (ns->spawn.class_ >= Class::WarriorGM && ns->spawn.class_ <= Class::BerserkerGM) {
int trainer_class = WARRIORGM + (ForWho->GetClass() - 1); int trainer_class = Class::WarriorGM + (ForWho->GetClass() - 1);
ns->spawn.class_ = trainer_class; ns->spawn.class_ = trainer_class;
} }
} }
@@ -2118,7 +2118,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
std::string bard_info; std::string bard_info;
if (GetClass() == BARD) { if (GetClass() == Class::Bard) {
const auto brass_mod = IsBot() ? CastToBot()->GetBrassMod() : CastToClient()->GetBrassMod(); const auto brass_mod = IsBot() ? CastToBot()->GetBrassMod() : CastToClient()->GetBrassMod();
const auto perc_mod = IsBot() ? CastToBot()->GetPercMod() : CastToClient()->GetPercMod(); const auto perc_mod = IsBot() ? CastToBot()->GetPercMod() : CastToClient()->GetPercMod();
const auto sing_mod = IsBot() ? CastToBot()->GetSingMod() : CastToClient()->GetSingMod(); const auto sing_mod = IsBot() ? CastToBot()->GetSingMod() : CastToClient()->GetSingMod();
@@ -2419,7 +2419,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
} }
// Bard Modifiers // Bard Modifiers
if (GetClass() == BARD) { if (GetClass() == Class::Bard) {
final_string += bard_info + DialogueWindow::Break(1); final_string += bard_info + DialogueWindow::Break(1);
} }
@@ -2688,7 +2688,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
); );
} }
if (GetClass() == BARD) { if (GetClass() == Class::Bard) {
const auto brass_mod = IsBot() ? CastToBot()->GetBrassMod() : CastToClient()->GetBrassMod(); const auto brass_mod = IsBot() ? CastToBot()->GetBrassMod() : CastToClient()->GetBrassMod();
const auto perc_mod = IsBot() ? CastToBot()->GetPercMod() : CastToClient()->GetPercMod(); const auto perc_mod = IsBot() ? CastToBot()->GetPercMod() : CastToClient()->GetPercMod();
const auto sing_mod = IsBot() ? CastToBot()->GetSingMod() : CastToClient()->GetSingMod(); const auto sing_mod = IsBot() ? CastToBot()->GetSingMod() : CastToClient()->GetSingMod();
@@ -3511,14 +3511,14 @@ void Mob::GMMove(float x, float y, float z, float heading, bool save_guard_spot)
} }
} }
void Mob::GMMove(const glm::vec4 &position) { void Mob::GMMove(const glm::vec4 &position, bool save_guard_spot) {
m_Position.x = position.x; m_Position.x = position.x;
m_Position.y = position.y; m_Position.y = position.y;
m_Position.z = position.z; m_Position.z = position.z;
SetHeading(position.w); SetHeading(position.w);
mMovementManager->SendCommandToClients(this, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny); mMovementManager->SendCommandToClients(this, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
if (IsNPC()) { if (IsNPC() && save_guard_spot) {
CastToNPC()->SaveGuardSpot(position); CastToNPC()->SaveGuardSpot(position);
} }
} }
@@ -4531,7 +4531,7 @@ bool Mob::CanThisClassDualWield(void) const {
// Dual-Wielding Empty Fists // Dual-Wielding Empty Fists
if(!pinst && !sinst) if(!pinst && !sinst)
if(class_ != MONK && class_ != MONKGM && class_ != BEASTLORD && class_ != BEASTLORDGM) if(class_ != Class::Monk && class_ != Class::MonkGM && class_ != Class::Beastlord && class_ != Class::BeastlordGM)
return false; return false;
return true; return true;
@@ -4564,24 +4564,24 @@ bool Mob::IsWarriorClass(void) const
{ {
switch(GetClass()) switch(GetClass())
{ {
case WARRIOR: case Class::Warrior:
case WARRIORGM: case Class::WarriorGM:
case ROGUE: case Class::Rogue:
case ROGUEGM: case Class::RogueGM:
case MONK: case Class::Monk:
case MONKGM: case Class::MonkGM:
case PALADIN: case Class::Paladin:
case PALADINGM: case Class::PaladinGM:
case SHADOWKNIGHT: case Class::ShadowKnight:
case SHADOWKNIGHTGM: case Class::ShadowKnightGM:
case RANGER: case Class::Ranger:
case RANGERGM: case Class::RangerGM:
case BEASTLORD: case Class::Beastlord:
case BEASTLORDGM: case Class::BeastlordGM:
case BERSERKER: case Class::Berserker:
case BERSERKERGM: case Class::BerserkerGM:
case BARD: case Class::Bard:
case BARDGM: case Class::BardGM:
{ {
return true; return true;
} }
@@ -5185,7 +5185,7 @@ int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime)
int32 cast_reducer_no_limit = GetFocusEffect(focusFcCastTimeMod2, spell_id); int32 cast_reducer_no_limit = GetFocusEffect(focusFcCastTimeMod2, spell_id);
if (level > 50 && casttime >= 3000 && !spells[spell_id].good_effect && if (level > 50 && casttime >= 3000 && !spells[spell_id].good_effect &&
(GetClass() == RANGER || GetClass() == SHADOWKNIGHT || GetClass() == PALADIN || GetClass() == BEASTLORD)) { (GetClass() == Class::Ranger || GetClass() == Class::ShadowKnight || GetClass() == Class::Paladin || GetClass() == Class::Beastlord)) {
int level_mod = std::min(15, GetLevel() - 50); int level_mod = std::min(15, GetLevel() - 50);
cast_reducer += level_mod * 3; cast_reducer += level_mod * 3;
} }
@@ -7520,29 +7520,23 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
bool Mob::CanClassEquipItem(uint32 item_id) bool Mob::CanClassEquipItem(uint32 item_id)
{ {
const EQ::ItemData* itm = nullptr; const auto *item = database.GetItem(item_id);
itm = database.GetItem(item_id); if (!item) {
if (!itm) {
return false; return false;
} }
auto item_classes = itm->Classes; const uint16 item_classes = item->Classes;
if(item_classes == PLAYER_CLASS_ALL_MASK) { if (item_classes == Class::ALL_CLASSES_BITMASK) {
return true; return true;
} }
auto class_id = GetClass(); const uint8 class_id = GetClass();
if (class_id > BERSERKER) { if (!IsPlayerClass(class_id)) {
return false; return false;
} }
int class_bitmask = GetPlayerClassBit(class_id); const uint16 class_bitmask = GetPlayerClassBit(class_id);
if(!(item_classes & class_bitmask)) { return (item_classes & class_bitmask);
return false;
} else {
return true;
}
} }
bool Mob::CanRaceEquipItem(uint32 item_id) bool Mob::CanRaceEquipItem(uint32 item_id)
@@ -8264,37 +8258,37 @@ std::string Mob::GetRacePlural()
std::string Mob::GetClassPlural() std::string Mob::GetClassPlural()
{ {
switch (GetClass()) { switch (GetClass()) {
case WARRIOR: case Class::Warrior:
return "Warriors"; return "Warriors";
case CLERIC: case Class::Cleric:
return "Clerics"; return "Clerics";
case PALADIN: case Class::Paladin:
return "Paladins"; return "Paladins";
case RANGER: case Class::Ranger:
return "Rangers"; return "Rangers";
case SHADOWKNIGHT: case Class::ShadowKnight:
return "Shadowknights"; return fmt::format("{}s", shadow_knight_class_name);
case DRUID: case Class::Druid:
return "Druids"; return "Druids";
case MONK: case Class::Monk:
return "Monks"; return "Monks";
case BARD: case Class::Bard:
return "Bards"; return "Bards";
case ROGUE: case Class::Rogue:
return "Rogues"; return "Rogues";
case SHAMAN: case Class::Shaman:
return "Shamans"; return "Shamans";
case NECROMANCER: case Class::Necromancer:
return "Necromancers"; return "Necromancers";
case WIZARD: case Class::Wizard:
return "Wizards"; return "Wizards";
case MAGICIAN: case Class::Magician:
return "Magicians"; return "Magicians";
case ENCHANTER: case Class::Enchanter:
return "Enchanters"; return "Enchanters";
case BEASTLORD: case Class::Beastlord:
return "Beastlords"; return "Beastlords";
case BERSERKER: case Class::Berserker:
return "Berserkers"; return "Berserkers";
default: default:
return "Classes"; return "Classes";
+1 -1
View File
@@ -714,7 +714,7 @@ public:
bool IsRunning() const { return m_is_running; } bool IsRunning() const { return m_is_running; }
void SetRunning(bool val) { m_is_running = val; } void SetRunning(bool val) { m_is_running = val; }
virtual void GMMove(float x, float y, float z, float heading = 0.01, bool save_guard_spot = true); virtual void GMMove(float x, float y, float z, float heading = 0.01, bool save_guard_spot = true);
virtual void GMMove(const glm::vec4 &position); virtual void GMMove(const glm::vec4 &position, bool save_guard_spot = true);
void SetDelta(const glm::vec4& delta); void SetDelta(const glm::vec4& delta);
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu); void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu); void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
+5 -5
View File
@@ -448,7 +448,7 @@ void Mob::AI_Start(uint32 iMoveDelay) {
hate_list_cleanup_timer.Disable(); hate_list_cleanup_timer.Disable();
} }
if (CastToNPC()->WillAggroNPCs()) if (CastToNPC()->GetNPCAggro())
AI_scan_area_timer = std::make_unique<Timer>(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax))); AI_scan_area_timer = std::make_unique<Timer>(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)));
AI_check_signal_timer = std::make_unique<Timer>(AI_check_signal_timer_delay); AI_check_signal_timer = std::make_unique<Timer>(AI_check_signal_timer_delay);
@@ -1066,7 +1066,7 @@ void Mob::AI_Process() {
IsNPC() && IsNPC() &&
!CastToNPC()->GetSwarmInfo() && !CastToNPC()->GetSwarmInfo() &&
(!IsPet() || (HasOwner() && GetOwner()->IsNPC())) && (!IsPet() || (HasOwner() && GetOwner()->IsNPC())) &&
!CastToNPC()->WillAggroNPCs() !CastToNPC()->GetNPCAggro()
) { ) {
WipeHateList(true); // wipe NPCs from hate list to prevent faction war WipeHateList(true); // wipe NPCs from hate list to prevent faction war
} }
@@ -1330,7 +1330,7 @@ void Mob::AI_Process() {
// Now pursue // Now pursue
// TODO: Check here for another person on hate list with close hate value // TODO: Check here for another person on hate list with close hate value
if (AI_PursueCastCheck()) { if (AI_PursueCastCheck()) {
if (IsCasting() && GetClass() != BARD) { if (IsCasting() && GetClass() != Class::Bard) {
StopNavigation(); StopNavigation();
FaceTarget(); FaceTarget();
} }
@@ -1382,11 +1382,11 @@ void Mob::AI_Process() {
} }
} }
if (AI_IdleCastCheck()) { if (AI_IdleCastCheck()) {
if (IsCasting() && GetClass() != BARD) { if (IsCasting() && GetClass() != Class::Bard) {
StopNavigation(); StopNavigation();
} }
} }
else if (zone->CanDoCombat() && CastToNPC()->WillAggroNPCs() && AI_scan_area_timer->Check()) { else if (zone->CanDoCombat() && CastToNPC()->GetNPCAggro() && AI_scan_area_timer->Check()) {
/** /**
* NPC to NPC aggro (npc_aggro flag set) * NPC to NPC aggro (npc_aggro flag set)
+9 -9
View File
@@ -245,12 +245,12 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
MerchantType = npc_type_data->merchanttype; MerchantType = npc_type_data->merchanttype;
merchant_open = ( merchant_open = (
GetClass() == MERCHANT || GetClass() == Class::Merchant ||
GetClass() == DISCORD_MERCHANT || GetClass() == Class::DiscordMerchant ||
GetClass() == ADVENTURE_MERCHANT || GetClass() == Class::AdventureMerchant ||
GetClass() == NORRATHS_KEEPERS_MERCHANT || GetClass() == Class::NorrathsKeepersMerchant ||
GetClass() == DARK_REIGN_MERCHANT || GetClass() == Class::DarkReignMerchant ||
GetClass() == ALT_CURRENCY_MERCHANT GetClass() == Class::AlternateCurrencyMerchant
); );
adventure_template_id = npc_type_data->adventure_template; adventure_template_id = npc_type_data->adventure_template;
flymode = iflymode; flymode = iflymode;
@@ -294,7 +294,7 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
innate_proc_spell_id = 0; innate_proc_spell_id = 0;
m_record_loot_stats = false; m_record_loot_stats = false;
if (GetClass() == MERCENARY_MASTER && RuleB(Mercs, AllowMercs)) { if (GetClass() == Class::MercenaryLiaison && RuleB(Mercs, AllowMercs)) {
LoadMercTypes(); LoadMercTypes();
LoadMercs(); LoadMercs();
} }
@@ -364,10 +364,10 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
// There are some known low level SHM/BST pets that do not follow this, which supports // There are some known low level SHM/BST pets that do not follow this, which supports
// the theory of needing to be able to set skills for each mob separately // the theory of needing to be able to set skills for each mob separately
if (IsBot()) { if (IsBot()) {
if (GetClass() != PALADIN && GetClass() != SHADOWKNIGHT) { if (GetClass() != Class::Paladin && GetClass() != Class::ShadowKnight) {
knightattack_timer.Disable(); knightattack_timer.Disable();
} }
else if (GetClass() != MONK || GetLevel() < 10) { else if (GetClass() != Class::Monk || GetLevel() < 10) {
monkattack_timer.Disable(); monkattack_timer.Disable();
} }
} }
+21 -10
View File
@@ -192,10 +192,20 @@ public:
virtual void SpellProcess(); virtual void SpellProcess();
virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
void AddItem(const EQ::ItemData* item, uint16 charges, bool equipitem = true); void AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item = true);
void AddItem(uint32 itemid, uint16 charges, bool equipitem = true, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0); void AddItem(
uint32 item_id,
uint16 charges,
bool equip_item = true,
uint32 augment_one = 0,
uint32 augment_two = 0,
uint32 augment_three = 0,
uint32 augment_four = 0,
uint32 augment_five = 0,
uint32 augment_six = 0
);
void AddLootTable(); void AddLootTable();
void AddLootTable(uint32 ldid); void AddLootTable(uint32 loottable_id);
void CheckGlobalLootTables(); void CheckGlobalLootTables();
void DescribeAggro(Client *to_who, Mob *mob, bool verbose); void DescribeAggro(Client *to_who, Mob *mob, bool verbose);
void RemoveItem(uint32 item_id, uint16 quantity = 0, uint16 slot = 0); void RemoveItem(uint32 item_id, uint16 quantity = 0, uint16 slot = 0);
@@ -314,12 +324,12 @@ public:
ItemList *itemlist, ItemList *itemlist,
LootDropEntries_Struct loot_drop, LootDropEntries_Struct loot_drop,
bool wear_change = false, bool wear_change = false,
uint32 aug1 = 0, uint32 augment_one = 0,
uint32 aug2 = 0, uint32 augment_two = 0,
uint32 aug3 = 0, uint32 augment_three = 0,
uint32 aug4 = 0, uint32 augment_four = 0,
uint32 aug5 = 0, uint32 augment_five = 0,
uint32 aug6 = 0 uint32 augment_six = 0
); );
bool MeetsLootDropLevelRequirements(LootDropEntries_Struct loot_drop, bool verbose=false); bool MeetsLootDropLevelRequirements(LootDropEntries_Struct loot_drop, bool verbose=false);
@@ -384,7 +394,8 @@ public:
int GetNumMercs() { return static_cast<int>(mercDataList.size()); }; int GetNumMercs() { return static_cast<int>(mercDataList.size()); };
int GetNumMercs( uint32 expansion ); int GetNumMercs( uint32 expansion );
inline bool WillAggroNPCs() const { return(npc_aggro); } inline bool GetNPCAggro() const { return npc_aggro; }
inline void SetNPCAggro(bool in_npc_aggro) { npc_aggro = in_npc_aggro; }
inline void GiveNPCTypeData(NPCType *ours) { NPCTypedata_ours = ours; } inline void GiveNPCTypeData(NPCType *ours) { NPCTypedata_ours = ours; }
inline const uint32 GetNPCSpellsID() const { return npc_spells_id; } inline const uint32 GetNPCSpellsID() const { return npc_spells_id; }
+16 -16
View File
@@ -417,7 +417,7 @@ uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
uint32 multiplier; uint32 multiplier;
switch (npc_class) { switch (npc_class) {
case WARRIOR: { case Class::Warrior: {
if (level < 20) { if (level < 20) {
multiplier = 220; multiplier = 220;
} }
@@ -444,9 +444,9 @@ uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
} }
break; break;
} }
case DRUID: case Class::Druid:
case CLERIC: case Class::Cleric:
case SHAMAN: { case Class::Shaman: {
if (level < 70) { if (level < 70) {
multiplier = 150; multiplier = 150;
} }
@@ -455,9 +455,9 @@ uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
} }
break; break;
} }
case BERSERKER: case Class::Berserker:
case PALADIN: case Class::Paladin:
case SHADOWKNIGHT: { case Class::ShadowKnight: {
if (level < 35) { if (level < 35) {
multiplier = 210; multiplier = 210;
} }
@@ -481,10 +481,10 @@ uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
} }
break; break;
} }
case MONK: case Class::Monk:
case BARD: case Class::Bard:
case ROGUE: case Class::Rogue:
case BEASTLORD: { case Class::Beastlord: {
if (level < 51) { if (level < 51) {
multiplier = 180; multiplier = 180;
} }
@@ -499,7 +499,7 @@ uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
} }
break; break;
} }
case RANGER: { case Class::Ranger: {
if (level < 58) { if (level < 58) {
multiplier = 200; multiplier = 200;
} }
@@ -511,10 +511,10 @@ uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
} }
break; break;
} }
case MAGICIAN: case Class::Magician:
case WIZARD: case Class::Wizard:
case NECROMANCER: case Class::Necromancer:
case ENCHANTER: { case Class::Enchanter: {
if (level < 70) { if (level < 70) {
multiplier = 120; multiplier = 120;
} }
+109
View File
@@ -255,11 +255,101 @@ void Perl_Bot_Stand(Bot* self) // @categories Script Utility
self->Stand(); self->Stand();
} }
uint32 Perl_Bot_GetSpellRecastTimer(Bot* self)
{
return self->GetSpellRecastRemainingTime();
}
uint32 Perl_Bot_GetSpellRecastTimer(Bot* self, uint16 spell_id)
{
return self->GetSpellRecastRemainingTime(spell_id);
}
void Perl_Bot_ClearSpellRecastTimer(Bot* self)
{
return self->ClearSpellRecastTimer();
}
void Perl_Bot_ClearSpellRecastTimer(Bot* self, uint16 spell_id)
{
return self->ClearSpellRecastTimer(spell_id);
}
uint32 Perl_Bot_GetDisciplineReuseTimer(Bot* self)
{
return self->GetDisciplineReuseRemainingTime();
}
uint32 Perl_Bot_GetDisciplineReuseTimer(Bot* self, uint16 spell_id)
{
return self->GetDisciplineReuseRemainingTime(spell_id);
}
void Perl_Bot_ClearDisciplineReuseTimer(Bot* self)
{
return self->ClearDisciplineReuseTimer();
}
void Perl_Bot_ClearDisciplineReuseTimer(Bot* self, uint16 spell_id)
{
return self->ClearDisciplineReuseTimer(spell_id);
}
void Perl_Bot_SetDisciplineReuseTimer(Bot* self, uint16 spell_id)
{
return self->SetDisciplineReuseTimer(spell_id);
}
void Perl_Bot_SetDisciplineReuseTimer(Bot* self, uint16 spell_id, uint32 recast_delay)
{
return self->SetDisciplineReuseTimer(spell_id);
}
void Perl_Bot_SetItemReuseTimer(Bot* self, uint32 item_id)
{
return self->SetItemReuseTimer(item_id);
}
void Perl_Bot_SetItemReuseTimer(Bot* self, uint32 item_id, uint32 reuse_timer)
{
return self->SetItemReuseTimer(item_id, reuse_timer);
}
void Perl_Bot_SetSpellRecastTimer(Bot* self, uint16 spell_id)
{
return self->SetSpellRecastTimer(spell_id);
}
void Perl_Bot_SetSpellRecastTimer(Bot* self, uint16 spell_id, uint32 recast_delay)
{
return self->SetSpellRecastTimer(spell_id, recast_delay);
}
int Perl_Bot_GetItemIDAt(Bot* self, int16 slot_id) // @categories Inventory and Items int Perl_Bot_GetItemIDAt(Bot* self, int16 slot_id) // @categories Inventory and Items
{ {
return self->GetItemIDAt(slot_id); return self->GetItemIDAt(slot_id);
} }
uint32 Perl_Bot_GetItemReuseTimer(Bot* self)
{
return self->GetItemReuseRemainingTime();
}
uint32 Perl_Bot_GetItemReuseTimer(Bot* self, uint32 item_id)
{
return self->GetItemReuseRemainingTime(item_id);
}
void Perl_Bot_ClearItemReuseTimer(Bot* self)
{
return self->ClearItemReuseTimer();
}
void Perl_Bot_ClearItemReuseTimer(Bot* self, uint32 item_id)
{
return self->ClearItemReuseTimer(item_id);
}
int Perl_Bot_GetAugmentIDAt(Bot* self, int16 slot_id, uint8 aug_slot) // @categories Inventory and Items int Perl_Bot_GetAugmentIDAt(Bot* self, int16 slot_id, uint8 aug_slot) // @categories Inventory and Items
{ {
return self->GetAugmentIDAt(slot_id, aug_slot); return self->GetAugmentIDAt(slot_id, aug_slot);
@@ -556,6 +646,12 @@ void perl_register_bot()
package.add("ApplySpellRaid", (void(*)(Bot*, int, int, int, bool, bool))&Perl_Bot_ApplySpellRaid); package.add("ApplySpellRaid", (void(*)(Bot*, int, int, int, bool, bool))&Perl_Bot_ApplySpellRaid);
package.add("Camp", (void(*)(Bot*))&Perl_Bot_Camp); package.add("Camp", (void(*)(Bot*))&Perl_Bot_Camp);
package.add("Camp", (void(*)(Bot*, bool))&Perl_Bot_Camp); package.add("Camp", (void(*)(Bot*, bool))&Perl_Bot_Camp);
package.add("ClearDisciplineReuseTimer", (void(*)(Bot*))&Perl_Bot_ClearDisciplineReuseTimer);
package.add("ClearDisciplineReuseTimer", (void(*)(Bot*, uint16))&Perl_Bot_ClearDisciplineReuseTimer);
package.add("ClearItemReuseTimer", (void(*)(Bot*))&Perl_Bot_ClearItemReuseTimer);
package.add("ClearItemReuseTimer", (void(*)(Bot*, uint32))&Perl_Bot_ClearItemReuseTimer);
package.add("ClearSpellRecastTimer", (void(*)(Bot*))&Perl_Bot_ClearSpellRecastTimer);
package.add("ClearSpellRecastTimer", (void(*)(Bot*, uint16))&Perl_Bot_ClearSpellRecastTimer);
package.add("CountAugmentEquippedByID", &Perl_Bot_CountAugmentEquippedByID); package.add("CountAugmentEquippedByID", &Perl_Bot_CountAugmentEquippedByID);
package.add("CountBotItem", &Perl_Bot_CountBotItem); package.add("CountBotItem", &Perl_Bot_CountBotItem);
package.add("CountItemEquippedByID", &Perl_Bot_CountItemEquippedByID); package.add("CountItemEquippedByID", &Perl_Bot_CountItemEquippedByID);
@@ -594,6 +690,13 @@ void perl_register_bot()
package.add("HasBotItem", &Perl_Bot_HasBotItem); package.add("HasBotItem", &Perl_Bot_HasBotItem);
package.add("HasBotSpellEntry", &Perl_Bot_HasBotSpellEntry); package.add("HasBotSpellEntry", &Perl_Bot_HasBotSpellEntry);
package.add("HasItemEquippedByID", &Perl_Bot_HasItemEquippedByID); package.add("HasItemEquippedByID", &Perl_Bot_HasItemEquippedByID);
package.add("GetDisciplineReuseTimer", (uint32(*)(Bot*))&Perl_Bot_GetDisciplineReuseTimer);
package.add("GetDisciplineReuseTimer", (uint32(*)(Bot*, uint16))&Perl_Bot_GetDisciplineReuseTimer);
package.add("GetItemEquippedByID", &Perl_Bot_HasItemEquippedByID);
package.add("GetItemReuseTimer", (uint32(*)(Bot*))&Perl_Bot_GetItemReuseTimer);
package.add("GetItemReuseTimer", (uint32(*)(Bot*, uint32))&Perl_Bot_GetItemReuseTimer);
package.add("GetSpellRecastTimer", (uint32(*)(Bot*))&Perl_Bot_GetSpellRecastTimer);
package.add("GetSpellRecastTimer", (uint32(*)(Bot*, uint16))&Perl_Bot_GetSpellRecastTimer);
package.add("IsGrouped", &Perl_Bot_IsGrouped); package.add("IsGrouped", &Perl_Bot_IsGrouped);
package.add("IsSitting", &Perl_Bot_IsSitting); package.add("IsSitting", &Perl_Bot_IsSitting);
package.add("IsStanding", &Perl_Bot_IsStanding); package.add("IsStanding", &Perl_Bot_IsStanding);
@@ -608,6 +711,10 @@ void perl_register_bot()
package.add("SendSpellAnim", &Perl_Bot_SendSpellAnim); package.add("SendSpellAnim", &Perl_Bot_SendSpellAnim);
package.add("SetExpansionBitmask", (void(*)(Bot*, int))&Perl_Bot_SetExpansionBitmask); package.add("SetExpansionBitmask", (void(*)(Bot*, int))&Perl_Bot_SetExpansionBitmask);
package.add("SetExpansionBitmask", (void(*)(Bot*, int, bool))&Perl_Bot_SetExpansionBitmask); package.add("SetExpansionBitmask", (void(*)(Bot*, int, bool))&Perl_Bot_SetExpansionBitmask);
package.add("SetDisciplineReuseTimer", (void(*)(Bot*, uint16))&Perl_Bot_SetDisciplineReuseTimer);
package.add("SetDisciplineReuseTimer", (void(*)(Bot*, uint16, uint32))&Perl_Bot_SetDisciplineReuseTimer);
package.add("SetItemReuseTimer", (void(*)(Bot*, uint32))&Perl_Bot_SetItemReuseTimer);
package.add("SetItemReuseTimer", (void(*)(Bot*, uint32, uint32))&Perl_Bot_SetItemReuseTimer);
package.add("SetSpellDuration", (void(*)(Bot*, int))&Perl_Bot_SetSpellDuration); package.add("SetSpellDuration", (void(*)(Bot*, int))&Perl_Bot_SetSpellDuration);
package.add("SetSpellDuration", (void(*)(Bot*, int, int))&Perl_Bot_SetSpellDuration); package.add("SetSpellDuration", (void(*)(Bot*, int, int))&Perl_Bot_SetSpellDuration);
package.add("SetSpellDuration", (void(*)(Bot*, int, int, int))&Perl_Bot_SetSpellDuration); package.add("SetSpellDuration", (void(*)(Bot*, int, int, int))&Perl_Bot_SetSpellDuration);
@@ -621,6 +728,8 @@ void perl_register_bot()
package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int))&Perl_Bot_SetSpellDurationRaid); package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int))&Perl_Bot_SetSpellDurationRaid);
package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int, bool))&Perl_Bot_SetSpellDurationRaid); package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int, bool))&Perl_Bot_SetSpellDurationRaid);
package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int, bool, bool))&Perl_Bot_SetSpellDurationRaid); package.add("SetSpellDurationRaid", (void(*)(Bot*, int, int, int, bool, bool))&Perl_Bot_SetSpellDurationRaid);
package.add("SetSpellRecastTimer", (void(*)(Bot*, uint16))&Perl_Bot_SetSpellRecastTimer);
package.add("SetSpellRecastTimer", (void(*)(Bot*, uint16, uint32))&Perl_Bot_SetSpellRecastTimer);
package.add("Signal", &Perl_Bot_Signal); package.add("Signal", &Perl_Bot_Signal);
package.add("Sit", &Perl_Bot_Sit); package.add("Sit", &Perl_Bot_Sit);
package.add("Stand", &Perl_Bot_Stand); package.add("Stand", &Perl_Bot_Stand);
+44 -4
View File
@@ -1159,7 +1159,23 @@ void Perl_Client_AddPVPPoints(Client* self, uint32 points) // @categories Curren
void Perl_Client_AddCrystals(Client* self, uint32 radiant_count, uint32 ebon_count) // @categories Currency and Points void Perl_Client_AddCrystals(Client* self, uint32 radiant_count, uint32 ebon_count) // @categories Currency and Points
{ {
self->AddCrystals(radiant_count, ebon_count); if (ebon_count != 0) {
if (ebon_count > 0) {
self->AddEbonCrystals(ebon_count);
return;
}
self->RemoveEbonCrystals(ebon_count);
}
if (radiant_count != 0) {
if (radiant_count > 0) {
self->AddRadiantCrystals(radiant_count);
return;
}
self->RemoveRadiantCrystals(radiant_count);
}
} }
void Perl_Client_SetEbonCrystals(Client* self, uint32 value) void Perl_Client_SetEbonCrystals(Client* self, uint32 value)
@@ -1472,12 +1488,12 @@ void Perl_Client_NotifyNewTitlesAvailable(Client* self) // @categories Account a
self->NotifyNewTitlesAvailable(); self->NotifyNewTitlesAvailable();
} }
void Perl_Client_AddAlternateCurrencyValue(Client* self, uint32 currency_id, int32 amount) // @categories Currency and Points void Perl_Client_AddAlternateCurrencyValue(Client* self, uint32 currency_id, int amount) // @categories Currency and Points
{ {
self->AddAlternateCurrencyValue(currency_id, amount); self->AddAlternateCurrencyValue(currency_id, amount, true);
} }
void Perl_Client_SetAlternateCurrencyValue(Client* self, uint32 currency_id, int32 amount) // @categories Currency and Points void Perl_Client_SetAlternateCurrencyValue(Client* self, uint32 currency_id, uint32 amount) // @categories Currency and Points
{ {
self->SetAlternateCurrencyValue(currency_id, amount); self->SetAlternateCurrencyValue(currency_id, amount);
} }
@@ -2992,6 +3008,26 @@ void Perl_Client_GrantAllAAPoints(Client* self, uint8 unlock_level)
self->GrantAllAAPoints(unlock_level); self->GrantAllAAPoints(unlock_level);
} }
void Perl_Client_AddEbonCrystals(Client* self, uint32 amount)
{
self->AddEbonCrystals(amount);
}
void Perl_Client_AddRadiantCrystals(Client* self, uint32 amount)
{
self->AddRadiantCrystals(amount);
}
void Perl_Client_RemoveEbonCrystals(Client* self, uint32 amount)
{
self->RemoveEbonCrystals(amount);
}
void Perl_Client_RemoveRadiantCrystals(Client* self, uint32 amount)
{
self->RemoveRadiantCrystals(amount);
}
void perl_register_client() void perl_register_client()
{ {
perl::interpreter perl(PERL_GET_THX); perl::interpreter perl(PERL_GET_THX);
@@ -3006,6 +3042,7 @@ void perl_register_client()
package.add("AddEXP", (void(*)(Client*, uint32))&Perl_Client_AddEXP); package.add("AddEXP", (void(*)(Client*, uint32))&Perl_Client_AddEXP);
package.add("AddEXP", (void(*)(Client*, uint32, uint8))&Perl_Client_AddEXP); package.add("AddEXP", (void(*)(Client*, uint32, uint8))&Perl_Client_AddEXP);
package.add("AddEXP", (void(*)(Client*, uint32, uint8, bool))&Perl_Client_AddEXP); package.add("AddEXP", (void(*)(Client*, uint32, uint8, bool))&Perl_Client_AddEXP);
package.add("AddEbonCrystals", &Perl_Client_AddEbonCrystals);
package.add("AddExpeditionLockout", (void(*)(Client*, std::string, std::string, uint32))&Perl_Client_AddExpeditionLockout); package.add("AddExpeditionLockout", (void(*)(Client*, std::string, std::string, uint32))&Perl_Client_AddExpeditionLockout);
package.add("AddExpeditionLockout", (void(*)(Client*, std::string, std::string, uint32, std::string))&Perl_Client_AddExpeditionLockout); package.add("AddExpeditionLockout", (void(*)(Client*, std::string, std::string, uint32, std::string))&Perl_Client_AddExpeditionLockout);
package.add("AddExpeditionLockoutDuration", (void(*)(Client*, std::string, std::string, int))&Perl_Client_AddExpeditionLockoutDuration); package.add("AddExpeditionLockoutDuration", (void(*)(Client*, std::string, std::string, int))&Perl_Client_AddExpeditionLockoutDuration);
@@ -3021,6 +3058,7 @@ void perl_register_client()
package.add("AddPlatinum", (void(*)(Client*, uint32))&Perl_Client_AddPlatinum); package.add("AddPlatinum", (void(*)(Client*, uint32))&Perl_Client_AddPlatinum);
package.add("AddPlatinum", (void(*)(Client*, uint32, bool))&Perl_Client_AddPlatinum); package.add("AddPlatinum", (void(*)(Client*, uint32, bool))&Perl_Client_AddPlatinum);
package.add("AddPVPPoints", &Perl_Client_AddPVPPoints); package.add("AddPVPPoints", &Perl_Client_AddPVPPoints);
package.add("AddRadiantCrystals", &Perl_Client_AddRadiantCrystals);
package.add("AddSkill", &Perl_Client_AddSkill); package.add("AddSkill", &Perl_Client_AddSkill);
package.add("Admin", &Perl_Client_Admin); package.add("Admin", &Perl_Client_Admin);
package.add("ApplySpell", (void(*)(Client*, int))&Perl_Client_ApplySpell); package.add("ApplySpell", (void(*)(Client*, int))&Perl_Client_ApplySpell);
@@ -3352,6 +3390,7 @@ void perl_register_client()
package.add("ReloadDataBuckets", &Perl_Client_ReloadDataBuckets); package.add("ReloadDataBuckets", &Perl_Client_ReloadDataBuckets);
package.add("RemoveAllExpeditionLockouts", (void(*)(Client*))&Perl_Client_RemoveAllExpeditionLockouts); package.add("RemoveAllExpeditionLockouts", (void(*)(Client*))&Perl_Client_RemoveAllExpeditionLockouts);
package.add("RemoveAllExpeditionLockouts", (void(*)(Client*, std::string))&Perl_Client_RemoveAllExpeditionLockouts); package.add("RemoveAllExpeditionLockouts", (void(*)(Client*, std::string))&Perl_Client_RemoveAllExpeditionLockouts);
package.add("RemoveEbonCrystals", &Perl_Client_RemoveEbonCrystals);
package.add("RemoveExpeditionLockout", &Perl_Client_RemoveExpeditionLockout); package.add("RemoveExpeditionLockout", &Perl_Client_RemoveExpeditionLockout);
package.add("RemoveFromInstance", &Perl_Client_RemoveFromInstance); package.add("RemoveFromInstance", &Perl_Client_RemoveFromInstance);
package.add("RemoveItem", (void(*)(Client*, uint32))&Perl_Client_RemoveItem); package.add("RemoveItem", (void(*)(Client*, uint32))&Perl_Client_RemoveItem);
@@ -3359,6 +3398,7 @@ void perl_register_client()
package.add("RemoveLDoNLoss", &Perl_Client_RemoveLDoNLoss); package.add("RemoveLDoNLoss", &Perl_Client_RemoveLDoNLoss);
package.add("RemoveLDoNWin", &Perl_Client_RemoveLDoNWin); package.add("RemoveLDoNWin", &Perl_Client_RemoveLDoNWin);
package.add("RemoveNoRent", &Perl_Client_RemoveNoRent); package.add("RemoveNoRent", &Perl_Client_RemoveNoRent);
package.add("RemoveRadiantCrystals", &Perl_Client_RemoveRadiantCrystals);
package.add("ResetAA", &Perl_Client_ResetAA); package.add("ResetAA", &Perl_Client_ResetAA);
package.add("ResetAllDisciplineTimers", &Perl_Client_ResetAllDisciplineTimers); package.add("ResetAllDisciplineTimers", &Perl_Client_ResetAllDisciplineTimers);
package.add("ResetAllCastbarCooldowns", &Perl_Client_ResetAllCastbarCooldowns); package.add("ResetAllCastbarCooldowns", &Perl_Client_ResetAllCastbarCooldowns);
+13
View File
@@ -775,6 +775,17 @@ bool Perl_NPC_HasSpecialAbilities(NPC* self) // @categories Script Utility
return self->HasSpecialAbilities(); return self->HasSpecialAbilities();
} }
bool Perl_NPC_GetNPCAggro(NPC* self) // @categories Script Utility
{
return self->GetNPCAggro();
}
void Perl_NPC_SetNPCAggro(NPC* self, bool in_npc_aggro) // @categories Script Utility
{
self->SetNPCAggro(in_npc_aggro);
}
void perl_register_npc() void perl_register_npc()
{ {
perl::interpreter perl(PERL_GET_THX); perl::interpreter perl(PERL_GET_THX);
@@ -836,6 +847,7 @@ void perl_register_npc()
package.add("GetMaxDamage", &Perl_NPC_GetMaxDamage); package.add("GetMaxDamage", &Perl_NPC_GetMaxDamage);
package.add("GetMaxWp", &Perl_NPC_GetMaxWp); package.add("GetMaxWp", &Perl_NPC_GetMaxWp);
package.add("GetMinDMG", &Perl_NPC_GetMinDMG); package.add("GetMinDMG", &Perl_NPC_GetMinDMG);
package.add("GetNPCAggro", &Perl_NPC_GetNPCAggro);
package.add("GetNPCFactionID", &Perl_NPC_GetNPCFactionID); package.add("GetNPCFactionID", &Perl_NPC_GetNPCFactionID);
package.add("GetNPCHate", &Perl_NPC_GetNPCHate); package.add("GetNPCHate", &Perl_NPC_GetNPCHate);
package.add("GetNPCSpellsID", &Perl_NPC_GetNPCSpellsID); package.add("GetNPCSpellsID", &Perl_NPC_GetNPCSpellsID);
@@ -911,6 +923,7 @@ void perl_register_npc()
package.add("SetLDoNTrapDetected", &Perl_NPC_SetLDoNTrapDetected); package.add("SetLDoNTrapDetected", &Perl_NPC_SetLDoNTrapDetected);
package.add("SetLDoNTrapSpellID", &Perl_NPC_SetLDoNTrapSpellID); package.add("SetLDoNTrapSpellID", &Perl_NPC_SetLDoNTrapSpellID);
package.add("SetLDoNTrapType", &Perl_NPC_SetLDoNTrapType); package.add("SetLDoNTrapType", &Perl_NPC_SetLDoNTrapType);
package.add("SetNPCAggro", &Perl_NPC_SetNPCAggro);
package.add("SetGold", &Perl_NPC_SetGold); package.add("SetGold", &Perl_NPC_SetGold);
package.add("SetGrid", &Perl_NPC_SetGrid); package.add("SetGrid", &Perl_NPC_SetGrid);
package.add("SetNPCFactionID", &Perl_NPC_SetNPCFactionID); package.add("SetNPCFactionID", &Perl_NPC_SetNPCFactionID);
+1 -1
View File
@@ -70,7 +70,7 @@ void Petition::SendPetitionToPlayer(Client* clientto) {
Petition::Petition(uint32 id) Petition::Petition(uint32 id)
{ {
petid = id; petid = id;
charclass = NO_CLASS; charclass = Class::None;
charrace = RACE_DOUG_0; charrace = RACE_DOUG_0;
charlevel = 0; charlevel = 0;
checkouts = 0; checkouts = 0;
+11 -11
View File
@@ -1029,10 +1029,10 @@ bool QuestManager::isdisctome(uint32 item_id) {
//we know for sure none of the int casters get disciplines //we know for sure none of the int casters get disciplines
uint32 class_bit = 0; uint32 class_bit = 0;
class_bit |= 1 << (WIZARD - 1); class_bit |= 1 << (Class::Wizard - 1);
class_bit |= 1 << (ENCHANTER - 1); class_bit |= 1 << (Class::Enchanter - 1);
class_bit |= 1 << (MAGICIAN - 1); class_bit |= 1 << (Class::Magician - 1);
class_bit |= 1 << (NECROMANCER - 1); class_bit |= 1 << (Class::Necromancer - 1);
if (item->Classes & class_bit) { if (item->Classes & class_bit) {
return false; return false;
} }
@@ -1045,10 +1045,10 @@ bool QuestManager::isdisctome(uint32 item_id) {
//we know for sure none of the int casters get disciplines //we know for sure none of the int casters get disciplines
const auto& spell = spells[spell_id]; const auto& spell = spells[spell_id];
if( if(
spell.classes[WIZARD - 1] != 255 && spell.classes[Class::Wizard - 1] != 255 &&
spell.classes[ENCHANTER - 1] != 255 && spell.classes[Class::Enchanter - 1] != 255 &&
spell.classes[MAGICIAN - 1] != 255 && spell.classes[Class::Magician - 1] != 255 &&
spell.classes[NECROMANCER - 1] != 255 spell.classes[Class::Necromancer - 1] != 255
) { ) {
return false; return false;
} }
@@ -1526,7 +1526,7 @@ void QuestManager::CreateGuild(const char *guild_name, const char *leader) {
void QuestManager::settime(uint8 new_hour, uint8 new_min, bool update_world /*= true*/) void QuestManager::settime(uint8 new_hour, uint8 new_min, bool update_world /*= true*/)
{ {
if (zone) if (zone)
zone->SetTime(new_hour + 1, new_min, update_world); zone->SetTime(new_hour, new_min, update_world);
} }
void QuestManager::itemlink(int item_id) { void QuestManager::itemlink(int item_id) {
@@ -3128,7 +3128,7 @@ void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime)
void QuestManager::MerchantSetItem(uint32 NPCid, uint32 itemid, uint32 quantity) { void QuestManager::MerchantSetItem(uint32 NPCid, uint32 itemid, uint32 quantity) {
Mob* merchant = entity_list.GetMobByNpcTypeID(NPCid); Mob* merchant = entity_list.GetMobByNpcTypeID(NPCid);
if (merchant == 0 || !merchant->IsNPC() || (merchant->GetClass() != MERCHANT)) if (merchant == 0 || !merchant->IsNPC() || (merchant->GetClass() != Class::Merchant))
return; // don't do anything if NPCid isn't a merchant return; // don't do anything if NPCid isn't a merchant
const EQ::ItemData* item = nullptr; const EQ::ItemData* item = nullptr;
@@ -3141,7 +3141,7 @@ void QuestManager::MerchantSetItem(uint32 NPCid, uint32 itemid, uint32 quantity)
uint32 QuestManager::MerchantCountItem(uint32 NPCid, uint32 itemid) { uint32 QuestManager::MerchantCountItem(uint32 NPCid, uint32 itemid) {
Mob* merchant = entity_list.GetMobByNpcTypeID(NPCid); Mob* merchant = entity_list.GetMobByNpcTypeID(NPCid);
if (merchant == 0 || !merchant->IsNPC() || (merchant->GetClass() != MERCHANT)) if (merchant == 0 || !merchant->IsNPC() || (merchant->GetClass() != Class::Merchant))
return 0; // if it isn't a merchant, it doesn't have any items return 0; // if it isn't a merchant, it doesn't have any items
const EQ::ItemData* item = nullptr; const EQ::ItemData* item = nullptr;
+2 -2
View File
@@ -365,8 +365,8 @@ public:
std::string GetEncounter() const; std::string GetEncounter() const;
inline bool ProximitySayInUse() { return HaveProximitySays; } inline bool ProximitySayInUse() { return HaveProximitySays; }
int createbotcount(uint8 class_id = NO_CLASS); int createbotcount(uint8 class_id = Class::None);
int spawnbotcount(uint8 class_id = NO_CLASS); int spawnbotcount(uint8 class_id = Class::None);
bool botquest(); bool botquest();
bool createBot(const char *name, const char *lastname, uint8 level, uint16 race, uint8 botclass, uint8 gender); bool createBot(const char *name, const char *lastname, uint8 level, uint16 race, uint8 botclass, uint8 gender);
+31 -31
View File
@@ -287,7 +287,7 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
// make sure were actually able to use such an attack. (Bards can throw while casting. ~Kayen confirmed on live 1/22) // make sure were actually able to use such an attack. (Bards can throw while casting. ~Kayen confirmed on live 1/22)
if ( if (
(spellend_timer.Enabled() && GetClass() != BARD) || (spellend_timer.Enabled() && GetClass() != Class::Bard) ||
IsFeared() || IsFeared() ||
IsStunned() || IsStunned() ||
IsMezzed() || IsMezzed() ||
@@ -420,7 +420,7 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
CheckIncreaseSkill(EQ::skills::SkillFrenzy, GetTarget(), 10); CheckIncreaseSkill(EQ::skills::SkillFrenzy, GetTarget(), 10);
DoAnim(anim1HWeapon, 0, false); DoAnim(anim1HWeapon, 0, false);
if (GetClass() == BERSERKER) { if (GetClass() == Class::Berserker) {
int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy); int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy);
if (zone->random.Roll0(450) < chance) { if (zone->random.Roll0(450) < chance) {
@@ -461,11 +461,11 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
const uint32 allowed_kick_classes = RuleI(Combat, ExtraAllowedKickClassesBitmask); const uint32 allowed_kick_classes = RuleI(Combat, ExtraAllowedKickClassesBitmask);
const bool can_use_kick = ( const bool can_use_kick = (
class_id == WARRIOR || class_id == Class::Warrior ||
class_id == RANGER || class_id == Class::Ranger ||
class_id == MONK || class_id == Class::Monk ||
class_id == BEASTLORD || class_id == Class::Beastlord ||
class_id == BERSERKER || class_id == Class::Berserker ||
allowed_kick_classes & GetPlayerClassBit(class_id) allowed_kick_classes & GetPlayerClassBit(class_id)
); );
@@ -494,7 +494,7 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
} }
} }
if (class_id == MONK) { if (class_id == Class::Monk) {
reuse_time = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction; reuse_time = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
// Live AA - Technique of Master Wu // Live AA - Technique of Master Wu
@@ -559,7 +559,7 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
if ( if (
ca_atk->m_atk == 100 && ca_atk->m_atk == 100 &&
ca_atk->m_skill == EQ::skills::SkillBackstab && ca_atk->m_skill == EQ::skills::SkillBackstab &&
class_id == ROGUE class_id == Class::Rogue
) { ) {
reuse_time = BackstabReuseTime - 1 - skill_reduction; reuse_time = BackstabReuseTime - 1 - skill_reduction;
TryBackstab(GetTarget(), reuse_time); TryBackstab(GetTarget(), reuse_time);
@@ -1495,7 +1495,7 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
} }
if(!IsAttackAllowed(other) || if(!IsAttackAllowed(other) ||
(IsCasting() && GetClass() != BARD) || (IsCasting() && GetClass() != Class::Bard) ||
IsSitting() || IsSitting() ||
(DivineAura() && !GetGM()) || (DivineAura() && !GetGM()) ||
IsStunned() || IsStunned() ||
@@ -1779,13 +1779,13 @@ void NPC::DoClassAttacks(Mob *target) {
int knightreuse = 1000; //lets give it a small cooldown actually. int knightreuse = 1000; //lets give it a small cooldown actually.
switch(GetClass()){ switch(GetClass()){
case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ case Class::ShadowKnight: case Class::ShadowKnightGM:{
if (CastSpell(SPELL_NPC_HARM_TOUCH, target->GetID())) { if (CastSpell(SPELL_NPC_HARM_TOUCH, target->GetID())) {
knightreuse = HarmTouchReuseTime * 1000; knightreuse = HarmTouchReuseTime * 1000;
} }
break; break;
} }
case PALADIN: case PALADINGM:{ case Class::Paladin: case Class::PaladinGM:{
if(GetHPRatio() < 20) { if(GetHPRatio() < 20) {
if (CastSpell(SPELL_LAY_ON_HANDS, GetID())) { if (CastSpell(SPELL_LAY_ON_HANDS, GetID())) {
knightreuse = LayOnHandsReuseTime * 1000; knightreuse = LayOnHandsReuseTime * 1000;
@@ -1822,14 +1822,14 @@ void NPC::DoClassAttacks(Mob *target) {
bool did_attack = false; bool did_attack = false;
//class specific stuff... //class specific stuff...
switch(GetClass()) { switch(GetClass()) {
case ROGUE: case ROGUEGM: case Class::Rogue: case Class::RogueGM:
if(level >= 10) { if(level >= 10) {
reuse = BackstabReuseTime * 1000; reuse = BackstabReuseTime * 1000;
TryBackstab(target, reuse); TryBackstab(target, reuse);
did_attack = true; did_attack = true;
} }
break; break;
case MONK: case MONKGM: { case Class::Monk: case Class::MonkGM: {
uint8 satype = EQ::skills::SkillKick; uint8 satype = EQ::skills::SkillKick;
if (level > 29) { satype = EQ::skills::SkillFlyingKick; } if (level > 29) { satype = EQ::skills::SkillFlyingKick; }
else if (level > 24) { satype = EQ::skills::SkillDragonPunch; } else if (level > 24) { satype = EQ::skills::SkillDragonPunch; }
@@ -1842,7 +1842,7 @@ void NPC::DoClassAttacks(Mob *target) {
did_attack = true; did_attack = true;
break; break;
} }
case WARRIOR: case WARRIORGM:{ case Class::Warrior: case Class::WarriorGM:{
if(level >= RuleI(Combat, NPCBashKickLevel)){ if(level >= RuleI(Combat, NPCBashKickLevel)){
if(zone->random.Roll(75)) { //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. if(zone->random.Roll(75)) { //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference.
DoAnim(animKick, 0, false); DoAnim(animKick, 0, false);
@@ -1870,12 +1870,12 @@ void NPC::DoClassAttacks(Mob *target) {
} }
break; break;
} }
case BERSERKER: case BERSERKERGM:{ case Class::Berserker: case Class::BerserkerGM:{
int AtkRounds = 1; int AtkRounds = 1;
int32 max_dmg = GetBaseSkillDamage(EQ::skills::SkillFrenzy); int32 max_dmg = GetBaseSkillDamage(EQ::skills::SkillFrenzy);
DoAnim(anim2HSlashing, 0, false); DoAnim(anim2HSlashing, 0, false);
if (GetClass() == BERSERKER) { if (GetClass() == Class::Berserker) {
int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy); int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy);
if (zone->random.Roll0(450) < chance) if (zone->random.Roll0(450) < chance)
AtkRounds++; AtkRounds++;
@@ -1892,8 +1892,8 @@ void NPC::DoClassAttacks(Mob *target) {
did_attack = true; did_attack = true;
break; break;
} }
case RANGER: case RANGERGM: case Class::Ranger: case Class::RangerGM:
case BEASTLORD: case BEASTLORDGM: { case Class::Beastlord: case Class::BeastlordGM: {
//kick //kick
if(level >= RuleI(Combat, NPCBashKickLevel)){ if(level >= RuleI(Combat, NPCBashKickLevel)){
DoAnim(animKick, 0, false); DoAnim(animKick, 0, false);
@@ -1908,9 +1908,9 @@ void NPC::DoClassAttacks(Mob *target) {
} }
break; break;
} }
case CLERIC: case CLERICGM: //clerics can bash too. case Class::Cleric: case Class::ClericGM: //clerics can bash too.
case SHADOWKNIGHT: case SHADOWKNIGHTGM: case Class::ShadowKnight: case Class::ShadowKnightGM:
case PALADIN: case PALADINGM:{ case Class::Paladin: case Class::PaladinGM:{
if(level >= RuleI(Combat, NPCBashKickLevel)){ if(level >= RuleI(Combat, NPCBashKickLevel)){
DoAnim(animTailRake, 0, false); DoAnim(animTailRake, 0, false);
int64 dmg = GetBaseSkillDamage(EQ::skills::SkillBash); int64 dmg = GetBaseSkillDamage(EQ::skills::SkillBash);
@@ -1957,19 +1957,19 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
if (skill == -1){ if (skill == -1){
switch(GetClass()){ switch(GetClass()){
case WARRIOR: case Class::Warrior:
case RANGER: case Class::Ranger:
case BEASTLORD: case Class::Beastlord:
skill_to_use = EQ::skills::SkillKick; skill_to_use = EQ::skills::SkillKick;
break; break;
case BERSERKER: case Class::Berserker:
skill_to_use = EQ::skills::SkillFrenzy; skill_to_use = EQ::skills::SkillFrenzy;
break; break;
case SHADOWKNIGHT: case Class::ShadowKnight:
case PALADIN: case Class::Paladin:
skill_to_use = EQ::skills::SkillBash; skill_to_use = EQ::skills::SkillBash;
break; break;
case MONK: case Class::Monk:
if(GetLevel() >= 30) if(GetLevel() >= 30)
{ {
skill_to_use = EQ::skills::SkillFlyingKick; skill_to_use = EQ::skills::SkillFlyingKick;
@@ -1995,7 +1995,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
skill_to_use = EQ::skills::SkillKick; skill_to_use = EQ::skills::SkillKick;
} }
break; break;
case ROGUE: case Class::Rogue:
skill_to_use = EQ::skills::SkillBackstab; skill_to_use = EQ::skills::SkillBackstab;
break; break;
} }
@@ -2035,7 +2035,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
ReuseTime = (FrenzyReuseTime - 1) / HasteMod; ReuseTime = (FrenzyReuseTime - 1) / HasteMod;
// bards can do riposte frenzy for some reason // bards can do riposte frenzy for some reason
if (!IsRiposte && GetClass() == BERSERKER) { if (!IsRiposte && GetClass() == Class::Berserker) {
int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy); int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy);
if (zone->random.Roll0(450) < chance) if (zone->random.Roll0(450) < chance)
AtkRounds++; AtkRounds++;
+32 -32
View File
@@ -441,7 +441,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
case SE_CurrentMana: case SE_CurrentMana:
{ {
// Bards don't get mana from effects, good or bad. // Bards don't get mana from effects, good or bad.
if(GetClass() == BARD) if(GetClass() == Class::Bard)
break; break;
if(IsManaTapSpell(spell_id)) { if(IsManaTapSpell(spell_id)) {
if(GetCasterClass() != 'N') { if(GetCasterClass() != 'N') {
@@ -478,7 +478,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
case SE_CurrentManaOnce: case SE_CurrentManaOnce:
{ {
// Bards don't get mana from effects, good or bad. // Bards don't get mana from effects, good or bad.
if(GetClass() == BARD) if(GetClass() == Class::Bard)
break; break;
#ifdef SPELL_EFFECT_SPAM #ifdef SPELL_EFFECT_SPAM
snprintf(effect_desc, _EDLEN, "Current Mana Once: %+i", effect_value); snprintf(effect_desc, _EDLEN, "Current Mana Once: %+i", effect_value);
@@ -3432,7 +3432,7 @@ int64 Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level
*/ */
//This is checked from Mob::SpellEffects and applied to instant spells and runes. //This is checked from Mob::SpellEffects and applied to instant spells and runes.
if (caster && caster->GetClass() != BARD && caster->HasBaseEffectFocus()) { if (caster && caster->GetClass() != Class::Bard && caster->HasBaseEffectFocus()) {
oval = effect_value; oval = effect_value;
int mod = caster->GetFocusEffect(focusFcBaseEffects, spell_id); int mod = caster->GetFocusEffect(focusFcBaseEffects, spell_id);
@@ -3445,7 +3445,7 @@ int64 Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level
else if (caster_id && instrument_mod > 10) { else if (caster_id && instrument_mod > 10) {
Mob* buff_caster = entity_list.GetMob(caster_id);//If targeted bard song needed to confirm caster is not bard. Mob* buff_caster = entity_list.GetMob(caster_id);//If targeted bard song needed to confirm caster is not bard.
if (buff_caster && buff_caster->GetClass() != BARD) { if (buff_caster && buff_caster->GetClass() != Class::Bard) {
oval = effect_value; oval = effect_value;
effect_value = effect_value * static_cast<int>(instrument_mod) / 10; effect_value = effect_value * static_cast<int>(instrument_mod) / 10;
@@ -7248,7 +7248,7 @@ bool Mob::PassLimitClass(uint32 Classes_, uint16 Class_)
return false; return false;
Class_ += 1; Class_ += 1;
for (int CurrentClass = 1; CurrentClass <= PLAYER_CLASS_COUNT; ++CurrentClass){ for (int CurrentClass = 1; CurrentClass <= Class::PLAYER_CLASS_COUNT; ++CurrentClass){
if (Classes_ % 2 == 1){ if (Classes_ % 2 == 1){
if (CurrentClass == Class_) if (CurrentClass == Class_)
return true; return true;
@@ -7481,7 +7481,7 @@ bool Mob::PassCastRestriction(int value)
case IS_CLASS_WIZARD: case IS_CLASS_WIZARD:
case IS_WIZARD_USED_ON_MAGE_FIRE_PET: case IS_WIZARD_USED_ON_MAGE_FIRE_PET:
if (GetClass() == WIZARD) if (GetClass() == Class::Wizard)
return true; return true;
break; break;
@@ -7521,12 +7521,12 @@ bool Mob::PassCastRestriction(int value)
break; break;
case IS_CLASS_MELEE_THAT_CAN_BASH_OR_KICK_EXCEPT_BARD: case IS_CLASS_MELEE_THAT_CAN_BASH_OR_KICK_EXCEPT_BARD:
if ((GetClass() != BARD) && (GetClass() != ROGUE) && IsFighterClass(GetClass())) if ((GetClass() != Class::Bard) && (GetClass() != Class::Rogue) && IsFighterClass(GetClass()))
return true; return true;
break; break;
case IS_CLASS_PURE_MELEE: case IS_CLASS_PURE_MELEE:
if (GetClass() == ROGUE || GetClass() == WARRIOR || GetClass() == BERSERKER || GetClass() == MONK) if (GetClass() == Class::Rogue || GetClass() == Class::Warrior || GetClass() == Class::Berserker || GetClass() == Class::Monk)
return true; return true;
break; break;
@@ -7541,78 +7541,78 @@ bool Mob::PassCastRestriction(int value)
break; break;
case IS_CLASS_WARRIOR: case IS_CLASS_WARRIOR:
if (GetClass() == WARRIOR) if (GetClass() == Class::Warrior)
return true; return true;
break; break;
case IS_CLASS_CLERIC: case IS_CLASS_CLERIC:
if (GetClass() == CLERIC) if (GetClass() == Class::Cleric)
return true; return true;
break; break;
case IS_CLASS_PALADIN: case IS_CLASS_PALADIN:
if (GetClass() == PALADIN) if (GetClass() == Class::Paladin)
return true; return true;
break; break;
case IS_CLASS_RANGER: case IS_CLASS_RANGER:
if (GetClass() == RANGER) if (GetClass() == Class::Ranger)
return true; return true;
break; break;
case IS_CLASS_SHADOWKNIGHT: case IS_CLASS_SHADOWKNIGHT:
if (GetClass() == SHADOWKNIGHT) if (GetClass() == Class::ShadowKnight)
return true; return true;
break; break;
case IS_CLASS_DRUID: case IS_CLASS_DRUID:
if (GetClass() == DRUID) if (GetClass() == Class::Druid)
return true; return true;
break; break;
case IS_CLASS_MONK: case IS_CLASS_MONK:
if (GetClass() == MONK) if (GetClass() == Class::Monk)
return true; return true;
break; break;
case IS_CLASS_BARD2: case IS_CLASS_BARD2:
case IS_CLASS_BARD: case IS_CLASS_BARD:
if (GetClass() == BARD) if (GetClass() == Class::Bard)
return true; return true;
break; break;
case IS_CLASS_ROGUE: case IS_CLASS_ROGUE:
if (GetClass() == ROGUE) if (GetClass() == Class::Rogue)
return true; return true;
break; break;
case IS_CLASS_SHAMAN: case IS_CLASS_SHAMAN:
if (GetClass() == SHAMAN) if (GetClass() == Class::Shaman)
return true; return true;
break; break;
case IS_CLASS_NECRO: case IS_CLASS_NECRO:
if (GetClass() == NECROMANCER) if (GetClass() == Class::Necromancer)
return true; return true;
break; break;
case IS_CLASS_MAGE: case IS_CLASS_MAGE:
if (GetClass() == MAGICIAN) if (GetClass() == Class::Magician)
return true; return true;
break; break;
case IS_CLASS_ENCHANTER: case IS_CLASS_ENCHANTER:
if (GetClass() == ENCHANTER) if (GetClass() == Class::Enchanter)
return true; return true;
break; break;
case IS_CLASS_BEASTLORD: case IS_CLASS_BEASTLORD:
if (GetClass() == BEASTLORD) if (GetClass() == Class::Beastlord)
return true; return true;
break; break;
case IS_CLASS_BERSERKER: case IS_CLASS_BERSERKER:
if (GetClass() == BERSERKER) if (GetClass() == Class::Berserker)
return true; return true;
break; break;
@@ -7622,7 +7622,7 @@ bool Mob::PassCastRestriction(int value)
break; break;
case IS_CLASS_NOT_WAR_PAL_SK: case IS_CLASS_NOT_WAR_PAL_SK:
if ((GetClass() != WARRIOR) && (GetClass() != PALADIN) && (GetClass() != SHADOWKNIGHT)) if ((GetClass() != Class::Warrior) && (GetClass() != Class::Paladin) && (GetClass() != Class::ShadowKnight))
return true; return true;
break; break;
@@ -7722,8 +7722,8 @@ bool Mob::PassCastRestriction(int value)
} }
case IS_CLASS_CHAIN_OR_PLATE: case IS_CLASS_CHAIN_OR_PLATE:
if ((GetClass() == WARRIOR) || (GetClass() == BARD) || (GetClass() == SHADOWKNIGHT) || (GetClass() == PALADIN) || (GetClass() == CLERIC) if ((GetClass() == Class::Warrior) || (GetClass() == Class::Bard) || (GetClass() == Class::ShadowKnight) || (GetClass() == Class::Paladin) || (GetClass() == Class::Cleric)
|| (GetClass() == RANGER) || (GetClass() == SHAMAN) || (GetClass() == ROGUE) || (GetClass() == BERSERKER)) { || (GetClass() == Class::Ranger) || (GetClass() == Class::Shaman) || (GetClass() == Class::Rogue) || (GetClass() == Class::Berserker)) {
return true; return true;
} }
break; break;
@@ -7914,7 +7914,7 @@ bool Mob::PassCastRestriction(int value)
break; break;
case IS_CLASS_WARRIOR_CASTER_PRIEST: case IS_CLASS_WARRIOR_CASTER_PRIEST:
if (IsCasterClass(GetClass()) || GetClass() == WARRIOR) if (IsCasterClass(GetClass()) || GetClass() == Class::Warrior)
return true; return true;
break; break;
@@ -8082,13 +8082,13 @@ bool Mob::PassCastRestriction(int value)
break; break;
case IS_CLEINT_AND_MALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD: case IS_CLEINT_AND_MALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD:
if (IsClient() && GetGender() == MALE && (IsCasterClass(GetClass()) && GetClass() != CLERIC)) if (IsClient() && GetGender() == MALE && (IsCasterClass(GetClass()) && GetClass() != Class::Cleric))
return true; return true;
break; break;
case IS_CLIENT_AND_MALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE: case IS_CLIENT_AND_MALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE:
if (IsClient() && GetGender() == MALE && if (IsClient() && GetGender() == MALE &&
(GetClass() == BEASTLORD || GetClass() == BERSERKER || GetClass() == MONK || GetClass() == RANGER || GetClass() == ROGUE)) (GetClass() == Class::Beastlord || GetClass() == Class::Berserker || GetClass() == Class::Monk || GetClass() == Class::Ranger || GetClass() == Class::Rogue))
return true; return true;
break; break;
@@ -8098,13 +8098,13 @@ bool Mob::PassCastRestriction(int value)
break; break;
case IS_CLIENT_AND_FEMALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD: case IS_CLIENT_AND_FEMALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD:
if (IsClient() && GetGender() == FEMALE && (IsCasterClass(GetClass()) && GetClass() != CLERIC)) if (IsClient() && GetGender() == FEMALE && (IsCasterClass(GetClass()) && GetClass() != Class::Cleric))
return true; return true;
break; break;
case IS_CLIENT_AND_FEMALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE: case IS_CLIENT_AND_FEMALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE:
if (IsClient() && GetGender() == FEMALE && if (IsClient() && GetGender() == FEMALE &&
(GetClass() == BEASTLORD || GetClass() == BERSERKER || GetClass() == MONK || GetClass() == RANGER || GetClass() == ROGUE)) (GetClass() == Class::Beastlord || GetClass() == Class::Berserker || GetClass() == Class::Monk || GetClass() == Class::Ranger || GetClass() == Class::Rogue))
return true; return true;
break; break;
@@ -8177,7 +8177,7 @@ bool Mob::PassCastRestriction(int value)
} }
case IS_NOT_CLASS_BARD: case IS_NOT_CLASS_BARD:
if (GetClass() != BARD) if (GetClass() != Class::Bard)
return true; return true;
break; break;
+82 -12
View File
@@ -402,7 +402,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
} }
} }
//must use SPA 415 with focus (SPA 127/500/501) to reduce item recast //must use SPA 415 with focus (SPA 127/500/501) to reduce item recast
else if (cast_time && IsClient() && slot == CastingSlot::Item && item_slot != 0xFFFFFFFF) { else if (cast_time && IsOfClientBot() && slot == CastingSlot::Item && item_slot != 0xFFFFFFFF) {
orgcasttime = cast_time; orgcasttime = cast_time;
if (cast_time) { if (cast_time) {
cast_time = GetActSpellCasttime(spell_id, cast_time); cast_time = GetActSpellCasttime(spell_id, cast_time);
@@ -1094,7 +1094,7 @@ bool Client::CheckFizzle(uint16 spell_id)
float diff = par_skill + static_cast<float>(spells[spell_id].base_difficulty) - act_skill; float diff = par_skill + static_cast<float>(spells[spell_id].base_difficulty) - act_skill;
// if you have high int/wis you fizzle less, you fizzle more if you are stupid // if you have high int/wis you fizzle less, you fizzle more if you are stupid
if(GetClass() == BARD) if(GetClass() == Class::Bard)
{ {
diff -= (GetCHA() - 110) / 20.0; diff -= (GetCHA() - 110) / 20.0;
} }
@@ -1381,7 +1381,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
Mob *spell_target = entity_list.GetMob(target_id); Mob *spell_target = entity_list.GetMob(target_id);
// here we do different things if this is a bard casting a bard song from // here we do different things if this is a bard casting a bard song from
// a spell bar slot // a spell bar slot
if(GetClass() == BARD) // bard's can move when casting any spell... if(GetClass() == Class::Bard) // bard's can move when casting any spell...
{ {
if (IsBardSong(spell_id) && slot < CastingSlot::MaxGems) { if (IsBardSong(spell_id) && slot < CastingSlot::MaxGems) {
if (spells[spell_id].buff_duration == 0xFFFF) { if (spells[spell_id].buff_duration == 0xFFFF) {
@@ -1643,6 +1643,10 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
{ {
DeleteChargeFromSlot = GetItemSlotToConsumeCharge(spell_id, inventory_slot); DeleteChargeFromSlot = GetItemSlotToConsumeCharge(spell_id, inventory_slot);
} }
if (IsBot() && slot == CastingSlot::Item && inventory_slot != 0xFFFFFFFF) // 10 is an item
{
DeleteChargeFromSlot = GetItemSlotToConsumeCharge(spell_id, inventory_slot);
}
// we're done casting, now try to apply the spell // we're done casting, now try to apply the spell
if(!SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust, false,-1, 0xFFFFFFFF, 0, true)) if(!SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust, false,-1, 0xFFFFFFFF, 0, true))
{ {
@@ -1661,9 +1665,23 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
TryTriggerOnCastFocusEffect(focusTriggerOnCast, spell_id); TryTriggerOnCastFocusEffect(focusTriggerOnCast, spell_id);
if (DeleteChargeFromSlot >= 0) { if (IsClient() && DeleteChargeFromSlot >= 0) {
CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true); CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true);
} }
else if (IsBot() && DeleteChargeFromSlot >= 0) {
EQ::ItemInstance* inst = CastToBot()->GetBotItem(DeleteChargeFromSlot);
if (inst) {
inst->SetCharges((inst->GetCharges() - 1));
if (!database.botdb.SaveItemBySlot(CastToBot(), DeleteChargeFromSlot, inst)) {
GetOwner()->Message(Chat::Red, "%s says, 'Failed to save item [%i] slot [%i] for [%s].", inst->GetID(), DeleteChargeFromSlot, GetCleanName());
return;
}
}
else {
GetOwner()->Message(Chat::Red, "%s says, 'Failed to update item charges.", GetCleanName());
LogError("Failed to update item charges for {}.", GetCleanName());
}
}
// //
// at this point the spell has successfully been cast // at this point the spell has successfully been cast
@@ -1938,7 +1956,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
return false; return false;
} }
if(spell_target->GetClass() != LDON_TREASURE) if(spell_target->GetClass() != Class::LDoNTreasure)
{ {
LogSpells("Spell [{}] canceled: invalid target (normal)", spell_id); LogSpells("Spell [{}] canceled: invalid target (normal)", spell_id);
MessageString(Chat::Red,SPELL_NEED_TAR); MessageString(Chat::Red,SPELL_NEED_TAR);
@@ -2301,7 +2319,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
return false; return false;
//Death Touch targets the pet owner instead of the pet when said pet is tanking. //Death Touch targets the pet owner instead of the pet when said pet is tanking.
if ((RuleB(Spells, CazicTouchTargetsPetOwner) && spell_target && spell_target->HasOwner()) && (spell_id == SPELL_CAZIC_TOUCH || spell_id == SPELL_TOUCH_OF_VINITRAS)) { if ((RuleB(Spells, CazicTouchTargetsPetOwner) && spell_target && spell_target->HasOwner()) && !spell_target->IsBot() && (spell_id == SPELL_CAZIC_TOUCH || spell_id == SPELL_TOUCH_OF_VINITRAS)) {
Mob* owner = spell_target->GetOwner(); Mob* owner = spell_target->GetOwner();
if (owner) { if (owner) {
@@ -2309,6 +2327,13 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
} }
} }
if ((RuleB(Bots, CazicTouchBotsOwner) && spell_target && spell_target->IsBot()) && spell_id == (SPELL_CAZIC_TOUCH || spell_id == SPELL_TOUCH_OF_VINITRAS)) {
auto bot_owner = spell_target->GetOwner();
if (bot_owner) {
spell_target = bot_owner;
}
}
//Guard Assist Code //Guard Assist Code
if (RuleB(Character, PVPEnableGuardFactionAssist) && spell_target && IsDetrimentalSpell(spell_id) && spell_target != this) { if (RuleB(Character, PVPEnableGuardFactionAssist) && spell_target && IsDetrimentalSpell(spell_id) && spell_target != this) {
if (IsClient() && spell_target->IsClient()|| (HasOwner() && GetOwner()->IsClient() && spell_target->IsClient())) { if (IsClient() && spell_target->IsClient()|| (HasOwner() && GetOwner()->IsClient() && spell_target->IsClient())) {
@@ -2687,7 +2712,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
} }
} }
//handle bard AA and Discipline recast timers when singing //handle bard AA and Discipline recast timers when singing
if (GetClass() == BARD && spell_id != casting_spell_id && timer != 0xFFFFFFFF) { if (GetClass() == Class::Bard && spell_id != casting_spell_id && timer != 0xFFFFFFFF) {
CastToClient()->GetPTimers().Start(timer, timer_duration); CastToClient()->GetPTimers().Start(timer, timer_duration);
LogSpells("Spell [{}]: Setting BARD custom reuse timer [{}] to [{}]", spell_id, casting_spell_timer, casting_spell_timer_duration); LogSpells("Spell [{}]: Setting BARD custom reuse timer [{}] to [{}]", spell_id, casting_spell_timer, casting_spell_timer_duration);
} }
@@ -2732,6 +2757,18 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt)){ if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt)){
CastToClient()->SetItemRecastTimer(spell_id, inventory_slot); CastToClient()->SetItemRecastTimer(spell_id, inventory_slot);
} }
else if (IsBot() && CastToBot()->GetIsUsingItemClick() && slot == CastingSlot::Item) {
EQ::ItemInstance* inst = CastToBot()->GetBotItem(inventory_slot);
const EQ::ItemData* item = nullptr;
if (inst && inst->GetItem()) {
item = inst->GetItem();
CastToBot()->SetItemReuseTimer(item->ID);
CastToBot()->SetIsUsingItemClick(false);
}
else {
GetOwner()->Message(Chat::Red, "%s says, 'Failed to set item reuse timer for %s.", GetCleanName());
}
}
if (IsNPC()) { if (IsNPC()) {
CastToNPC()->AI_Event_SpellCastFinished(true, static_cast<uint16>(slot)); CastToNPC()->AI_Event_SpellCastFinished(true, static_cast<uint16>(slot));
@@ -3143,8 +3180,8 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
if(effect1 != effect2) if(effect1 != effect2)
continue; continue;
if (IsBardOnlyStackEffect(effect1) && GetSpellLevel(spellid1, BARD) != 255 && if (IsBardOnlyStackEffect(effect1) && GetSpellLevel(spellid1, Class::Bard) != 255 &&
GetSpellLevel(spellid2, BARD) != 255) GetSpellLevel(spellid2, Class::Bard) != 255)
continue; continue;
// big ol' list according to the client, wasn't that nice! // big ol' list according to the client, wasn't that nice!
@@ -6199,7 +6236,7 @@ bool Mob::UseBardSpellLogic(uint16 spell_id, int slot)
( (
IsValidSpell(spell_id) && IsValidSpell(spell_id) &&
slot != -1 && slot != -1 &&
GetClass() == BARD && GetClass() == Class::Bard &&
slot <= EQ::spells::SPELL_GEM_COUNT && slot <= EQ::spells::SPELL_GEM_COUNT &&
IsBardSong(spell_id) IsBardSong(spell_id)
); );
@@ -6964,7 +7001,11 @@ void Mob::DoBardCastingFromItemClick(bool is_casting_bard_song, uint32 cast_time
} }
if (cast_time != 0) { if (cast_time != 0) {
CastSpell(spell_id, target_id, CastingSlot::Item, cast_time, 0, 0, item_slot); if (!CastSpell(spell_id, target_id, CastingSlot::Item, cast_time, 0, 0, item_slot)) {
if (IsBot()) {
GetOwner()->Message(Chat::Red, "%s says, 'Casting failed for %s. This could be due to zone restrictions, target restrictions or other limiting factors.", GetCleanName(), CastToBot()->GetBotItem(item_slot)->GetItem()->Name);
}
}
} }
//Instant cast items do not stop bard songs or interrupt casting. //Instant cast items do not stop bard songs or interrupt casting.
else if (CheckItemRaceClassDietyRestrictionsOnCast(item_slot) && DoCastingChecksOnCaster(spell_id, CastingSlot::Item)) { else if (CheckItemRaceClassDietyRestrictionsOnCast(item_slot) && DoCastingChecksOnCaster(spell_id, CastingSlot::Item)) {
@@ -6973,6 +7014,25 @@ void Mob::DoBardCastingFromItemClick(bool is_casting_bard_song, uint32 cast_time
if (IsClient() && DeleteChargeFromSlot >= 0) { if (IsClient() && DeleteChargeFromSlot >= 0) {
CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true); CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true);
} }
else if (IsBot() && DeleteChargeFromSlot >= 0) {
EQ::ItemInstance* inst = CastToBot()->GetBotItem(DeleteChargeFromSlot);
if (inst) {
inst->SetCharges((inst->GetCharges() - 1));
if (!database.botdb.SaveItemBySlot(CastToBot(), DeleteChargeFromSlot, inst)) {
GetOwner()->Message(Chat::Red, "%s says, 'Failed to save item [%i] slot [%i] for [%s].", inst->GetID(), DeleteChargeFromSlot, GetCleanName());
return;
}
}
else {
GetOwner()->Message(Chat::Red, "%s says, 'Failed to update item charges.", GetCleanName());
LogError("Failed to update item charges for {}.", GetCleanName());
}
}
}
else {
if (IsBot()) {
GetOwner()->Message(Chat::Red, "%s says, 'Casting failed for %s. This could be due to zone restrictions, target restrictions or other limiting factors.", GetCleanName(), CastToBot()->GetBotItem(item_slot)->GetItem()->Name);
}
} }
} }
} }
@@ -6981,12 +7041,17 @@ int16 Mob::GetItemSlotToConsumeCharge(int32 spell_id, uint32 inventory_slot)
{ {
int16 DeleteChargeFromSlot = -1; int16 DeleteChargeFromSlot = -1;
if (!IsClient() || inventory_slot == 0xFFFFFFFF) { if (!IsOfClientBot() || inventory_slot == 0xFFFFFFFF) {
return DeleteChargeFromSlot; return DeleteChargeFromSlot;
} }
EQ::ItemInstance *item = nullptr; EQ::ItemInstance *item = nullptr;
if (IsClient()) {
item = CastToClient()->GetInv().GetItem(inventory_slot); item = CastToClient()->GetInv().GetItem(inventory_slot);
}
else if (IsBot()) {
item = CastToBot()->GetBotItem(inventory_slot);
}
bool fromaug = false; bool fromaug = false;
EQ::ItemData* augitem = nullptr; EQ::ItemData* augitem = nullptr;
@@ -7029,7 +7094,12 @@ int16 Mob::GetItemSlotToConsumeCharge(int32 spell_id, uint32 inventory_slot)
} }
else{ else{
LogSpells("Item used to cast spell [{}] was missing from inventory slot [{}] after casting!", spell_id, inventory_slot); LogSpells("Item used to cast spell [{}] was missing from inventory slot [{}] after casting!", spell_id, inventory_slot);
if (IsClient()) {
Message(Chat::Red, "Casting Error: Active casting item not found in inventory slot %i", inventory_slot); Message(Chat::Red, "Casting Error: Active casting item not found in inventory slot %i", inventory_slot);
}
else if (IsBot()) {
CastToBot()->GetOwner()->Message(Chat::Red, "Casting Error: Active casting item not found in inventory slot %i for %s", inventory_slot, GetCleanName());
}
InterruptSpell(); InterruptSpell();
return DeleteChargeFromSlot; return DeleteChargeFromSlot;
} }
+2 -2
View File
@@ -1101,9 +1101,9 @@ void ClientTaskState::RewardTask(Client *c, const TaskInformation *ti, ClientTas
if (ti->reward_points > 0) { if (ti->reward_points > 0) {
if (ti->reward_point_type == static_cast<int32_t>(zone->GetCurrencyID(RADIANT_CRYSTAL))) { if (ti->reward_point_type == static_cast<int32_t>(zone->GetCurrencyID(RADIANT_CRYSTAL))) {
c->AddCrystals(ti->reward_points, 0); c->AddRadiantCrystals(ti->reward_points);
} else if (ti->reward_point_type == static_cast<int32_t>(zone->GetCurrencyID(EBON_CRYSTAL))) { } else if (ti->reward_point_type == static_cast<int32_t>(zone->GetCurrencyID(EBON_CRYSTAL))) {
c->AddCrystals(0, ti->reward_points); c->AddEbonCrystals(ti->reward_points);
} else { } else {
for (const auto& ac : zone->AlternateCurrencies) { for (const auto& ac : zone->AlternateCurrencies) {
if (ti->reward_point_type == ac.id) { if (ti->reward_point_type == ac.id) {
+2 -2
View File
@@ -448,7 +448,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob
//changing from a switch to string of if's since we don't need to iterate through all of the skills in the SkillType enum //changing from a switch to string of if's since we don't need to iterate through all of the skills in the SkillType enum
if (spec.tradeskill == EQ::skills::SkillAlchemy) { if (spec.tradeskill == EQ::skills::SkillAlchemy) {
if (user_pp.class_ != SHAMAN) { if (user_pp.class_ != Class::Shaman) {
user->Message(Chat::Red, "This tradeskill can only be performed by a shaman."); user->Message(Chat::Red, "This tradeskill can only be performed by a shaman.");
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
user->QueuePacket(outapp); user->QueuePacket(outapp);
@@ -473,7 +473,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob
} }
} }
else if (spec.tradeskill == EQ::skills::SkillMakePoison) { else if (spec.tradeskill == EQ::skills::SkillMakePoison) {
if (user_pp.class_ != ROGUE) { if (user_pp.class_ != Class::Rogue) {
user->Message(Chat::Red, "Only rogues can mix poisons."); user->Message(Chat::Red, "Only rogues can mix poisons.");
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
user->QueuePacket(outapp); user->QueuePacket(outapp);
+5 -5
View File
@@ -1068,14 +1068,14 @@ int64 Mob::TuneACSum(bool skip_caps, int ac_override, int add_ac)
ac += GetPetACBonusFromOwner(); ac += GetPetACBonusFromOwner();
auto spell_aa_ac = aabonuses.AC + spellbonuses.AC; auto spell_aa_ac = aabonuses.AC + spellbonuses.AC;
ac += GetSkill(EQ::skills::SkillDefense) / 5; ac += GetSkill(EQ::skills::SkillDefense) / 5;
if (EQ::ValueWithin(static_cast<int>(GetClass()), NECROMANCER, ENCHANTER)) if (EQ::ValueWithin(static_cast<int>(GetClass()), Class::Necromancer, Class::Enchanter))
ac += spell_aa_ac / 3; ac += spell_aa_ac / 3;
else else
ac += spell_aa_ac / 4; ac += spell_aa_ac / 4;
} }
else { // TODO: so we can't set NPC skills ... so the skill bonus ends up being HUGE so lets nerf them a bit else { // TODO: so we can't set NPC skills ... so the skill bonus ends up being HUGE so lets nerf them a bit
auto spell_aa_ac = aabonuses.AC + spellbonuses.AC; auto spell_aa_ac = aabonuses.AC + spellbonuses.AC;
if (EQ::ValueWithin(static_cast<int>(GetClass()), NECROMANCER, ENCHANTER)) if (EQ::ValueWithin(static_cast<int>(GetClass()), Class::Necromancer, Class::Enchanter))
ac += GetSkill(EQ::skills::SkillDefense) / 2 + spell_aa_ac / 3; ac += GetSkill(EQ::skills::SkillDefense) / 2 + spell_aa_ac / 3;
else else
ac += GetSkill(EQ::skills::SkillDefense) / 3 + spell_aa_ac / 4; ac += GetSkill(EQ::skills::SkillDefense) / 3 + spell_aa_ac / 4;
@@ -1423,7 +1423,7 @@ void Mob::TuneCommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraA
// BER weren't parsing the halving // BER weren't parsing the halving
if (hit.skill == EQ::skills::SkillArchery || if (hit.skill == EQ::skills::SkillArchery ||
(hit.skill == EQ::skills::SkillThrowing && GetClass() != BERSERKER)) (hit.skill == EQ::skills::SkillThrowing && GetClass() != Class::Berserker))
hit.damage_done /= 2; hit.damage_done /= 2;
if (hit.damage_done < 1) if (hit.damage_done < 1)
@@ -1436,7 +1436,7 @@ void Mob::TuneCommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraA
if (headshot > 0) { if (headshot > 0) {
hit.damage_done = headshot; hit.damage_done = headshot;
} }
else if (GetClass() == RANGER && GetLevel() > 50) { // no double dmg on headshot else if (GetClass() == Class::Ranger && GetLevel() > 50) { // no double dmg on headshot
if ((defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) || !RuleB(Combat, ArcheryBonusRequiresStationary)) { if ((defender->IsNPC() && !defender->IsMoving() && !defender->IsRooted()) || !RuleB(Combat, ArcheryBonusRequiresStationary)) {
hit.damage_done *= 2; hit.damage_done *= 2;
MessageString(Chat::MeleeCrit, BOW_DOUBLE_DAMAGE); MessageString(Chat::MeleeCrit, BOW_DOUBLE_DAMAGE);
@@ -1461,7 +1461,7 @@ void Mob::TuneCommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraA
hit.damage_done = ass; hit.damage_done = ass;
} }
} }
else if (hit.skill == EQ::skills::SkillFrenzy && GetClass() == BERSERKER && GetLevel() > 50) { else if (hit.skill == EQ::skills::SkillFrenzy && GetClass() == Class::Berserker && GetLevel() > 50) {
extra_mincap = 4 * GetLevel() / 5; extra_mincap = 4 * GetLevel() / 5;
} }
+2 -2
View File
@@ -183,7 +183,7 @@ bool Zone::LoadZoneObjects()
) )
); );
if (l.empty()) { if (l.empty()) {
LogError("Error Loading Objects for Zone [{}] Version [{}]", zoneid, instanceversion); LogWarning("No Objects to load for Zone [{}] Version [{}]", zoneid, instanceversion);
return false; return false;
} }
@@ -1941,7 +1941,7 @@ void Zone::SetTime(uint8 hour, uint8 minute, bool update_world /*= true*/)
zone_time.GetCurrentEQTimeOfDay(time(0), &eq_time_of_day->start_eqtime); zone_time.GetCurrentEQTimeOfDay(time(0), &eq_time_of_day->start_eqtime);
eq_time_of_day->start_eqtime.minute = minute; eq_time_of_day->start_eqtime.minute = minute;
eq_time_of_day->start_eqtime.hour = hour; eq_time_of_day->start_eqtime.hour = hour + 1;
eq_time_of_day->start_realtime = time(0); eq_time_of_day->start_realtime = time(0);
/* By Default we update worlds time, but we can optionally no update world which updates the rest of the zone servers */ /* By Default we update worlds time, but we can optionally no update world which updates the rest of the zone servers */