Compare commits

..

136 Commits

Author SHA1 Message Date
Chris Miles fd31915fae [Release] 22.39.0 (#3812) 2023-12-27 20:09:21 -06:00
Chris Miles 52763b6dd2 [Character] Fix character copier due to schema change (#3805)
* [Character] Fix character copier due to schema change

* Tweak
2023-12-27 20:04:46 -06:00
Chris Miles 51cd43b4ea [Player Events] Bulk replace settings on boot (#3806) 2023-12-27 20:04:29 -06:00
Chris Miles 2db84f5a4f [MySQL] Fix MySQL Query error formatting (#3808) 2023-12-27 20:04:18 -06:00
Chris Miles 79cc2d5351 [Logs] Reclassify unhelpful Info message (#3809) 2023-12-27 20:04:11 -06:00
Chris Miles d31cb09214 [Logs] Bulk insert new log settings (#3810) 2023-12-27 20:04:01 -06:00
Chris Miles 8bedcd8751 [Tasks] Add enabled column (#3804)
* [Tasks] Add enabled column

* Update task_manager.cpp

* Update task_manager.cpp

* Update base_tasks_repository.h
2023-12-27 20:03:53 -06:00
Chris Miles 473c5096f6 [Objects] Remove "No objects to load for zone" error message (#3807) 2023-12-27 21:03:08 -05:00
Paul Coene 0b181d5048 [Combat] Disarm was not dropping item to ground due to bug (#3811) 2023-12-27 10:19:09 -05:00
Chris Miles a7e9af2d27 [Release] 22.38.0 (#3803) 2023-12-26 16:30:09 -05:00
Chris Miles 7a72d5d67e [Repositories] Add ReplaceOne and ReplaceMany (#3802) 2023-12-25 20:53:44 -05:00
regneq 25872203ff [NPC] Support for multiple emotes per type, emote variables (#3801)
* [forage rule feature] add a rule to disabled using common_food_ids from the list in forage.cpp.  currently set to enabled.

* NPC database emotes now supports basic variables. More than one variable can be used at a time.

* Format manifest

* Formatting

* Formatting

* Formatting

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-12-24 23:28:57 -06:00
Alex King 6396a6fbef [Cleanup] Consolidate GetHateRandom(), GetHateRandomBot(), GetHateRandomClient(), and GetHateRandomNPC() (#3794)
* [Cleanup] Consolidate GetHateRandomBot(), GetHateRandomClient(), and GetHateRandomNPC()

# Notes
- These were separate methods and duplicated a lot of code, consolidated into the singular method using the `EntityFilterType`.

* Simplify random logic. Use filtered hate list.

* D

* D
2023-12-24 23:28:47 -06:00
Chris Miles 6db0a5c3f0 [Database] Fix issue with saylinks query in MySQL 8.0+ (#3800) 2023-12-24 09:43:31 -06:00
Chris Miles 4fa9e1d66f [Code Cleanup] Race constants refactor (#3782)
* [Code Cleanup] Race constants refactor

* Update races.h
2023-12-22 21:34:55 -06:00
JJ 556af8c5e9 [Database] Update faction mods with Live data (#3799)
Optional update to bring database up-to-date with Live data which includes Froglok and Drakkin data which was previously missing.
Raw data can be found in the Live client at Resources\Faction\FactionAssociations.txt
See discussion at #3678
2023-12-22 21:34:35 -06:00
Alex King f3ef8a0993 [Quest API] Add SummonItemIntoInventory() to Perl/Lua (#3797)
* [Quest API] Add SummonItemIntoInventory() to Perl/Lua

# Perl
- Add `$client->SummonItemIntoInventory(item_data)`.

## Example
```pl
sub EVENT_SAY {
	if ($text=~/#a/i) {
		my %item_data = (
			"item_id" => 32557,
			"charges" => 1
		);
		$client->SummonItemIntoInventory(\%item_data);
	}
}
```

# Lua
- Add `client:SummonItemIntoInventory(item_data)`.

## Example
```lua
function event_say(e)
	if e.message:find("#a") then
		local item_data = {
			"item_id" = 32557,
			"charges" = 1
		}
		e.self:SummonItemIntoInventory(item_data)
	end
end
```

* Update effects.cpp
2023-12-22 02:45:40 -06:00
regneq 267c280db8 [forage rule feature] add a rule to disabled using common_food_ids from the list in forage.cpp. currently set to enabled. (#3796) 2023-12-22 02:43:17 -06:00
Alex King e06c7d7735 [Quest API] Add GetHateTopBot(), GetHateTopClient(), and GetHateTopNPC() to Perl/Lua (#3793)
# Perl
- Add `$mob->GetHateTopBot()`.
- Add `$mob->GetHateTopClient()`.
- Add `$mob->GetHateTopNPC()`.

# Lua
- Add `mob:GetHateTopBot()`.
- Add `mob:GetHateTopClient()`.
- Add `mob:GetHateTopNPC()`.
2023-12-22 02:41:32 -06:00
nytmyr 028ebc3a0c [Bots] Remove unnecessary error on SetItemReuse (#3795)
This error is not necessary as it can be triggered when clicked spells have secondary effects that run through the same spell checks for clicked items but aren't actually clicked by the item. Spells that trigger other spell effects and some Bard scaling songs could trigger this after the initial click.
2023-12-20 10:01:54 -05:00
Alex King b3bd44cd76 [Bug Fix] Fix can_riposte parameter in DoMeleeSkillAttackDmg (#3792)
# Note
- `can_riposte` logic was reverse, setting to `true` caused the attack to not be able to be riposted, the opposite of the intended functionality.
2023-12-18 22:27:58 -05:00
Alex King 75a627a3a2 [Bug Fix] Disable Hide/Improved Hide on Trap damage (#3791)
# Notes
- Further fixes an issue where traps don't drop hide/invisible.
2023-12-18 22:24:03 -05:00
dependabot[bot] 0194aedc92 Bump golang.org/x/crypto in /utils/scripts/build/should-release (#3790)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-18 18:10:48 -06:00
Alex King 5cc87cbda7 [Bug Fix] Fix Bard Invisibility Songs breaking every 4 ticks (#3783)
# Notes
- Fixes #2361.
2023-12-18 18:10:28 -06:00
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
JJ 871f320311 [Release] 22.35.0 (#3754)
### Bots

* Add BotHealOnLevel to fully heal/mana on level. ([#3745](https://github.com/EQEmu/Server/pull/3745)) @nytmyr 2023-12-08
* Fix bots learning spells on level ([#3744](https://github.com/EQEmu/Server/pull/3744)) @nytmyr 2023-12-08

### Bug

* Fix blocked spells regression from #3638 ([#3753](https://github.com/EQEmu/Server/pull/3753)) @joligario 2023-12-11
* PR 3638 Missed the blocked spells repository updates ([#3748](https://github.com/EQEmu/Server/pull/3748)) @fryguy503 2023-12-08

### CMake

* Update minimum version of CMake ([#3743](https://github.com/EQEmu/Server/pull/3743)) @joligario 2023-12-08

### Code

* Remove hard-coded Status Checks ([#3727](https://github.com/EQEmu/Server/pull/3727)) @Kinglykrab 2023-12-03

### Commands

* #guild set CharName 0 did not remove char from guild. ([#3717](https://github.com/EQEmu/Server/pull/3717)) @noudess 2023-11-25
* #petname changes PC to Nobody if selected. ([#3720](https://github.com/EQEmu/Server/pull/3720)) @noudess 2023-11-26
* Add #show aas Command ([#3710](https://github.com/EQEmu/Server/pull/3710)) @Kinglykrab 2023-11-26
* Add #task complete Command ([#3711](https://github.com/EQEmu/Server/pull/3711)) @Kinglykrab 2023-11-26
* Cleanup #acceptrules Command ([#3716](https://github.com/EQEmu/Server/pull/3716)) @Kinglykrab 2023-11-26
* Cleanup #disarmtrap Command ([#3713](https://github.com/EQEmu/Server/pull/3713)) @Kinglykrab 2023-11-26
* Cleanup #list Command ([#3714](https://github.com/EQEmu/Server/pull/3714)) @Kinglykrab 2023-11-26
* Cleanup #movement Command ([#3715](https://github.com/EQEmu/Server/pull/3715)) @Kinglykrab 2023-11-26
* Cleanup #object Command ([#3722](https://github.com/EQEmu/Server/pull/3722)) @Kinglykrab 2023-12-03
* Cleanup #zonebootup and #zoneshutdown Commands ([#3729](https://github.com/EQEmu/Server/pull/3729)) @Kinglykrab 2023-12-03
* Fix formatting of #wpinfo output. ([#3728](https://github.com/EQEmu/Server/pull/3728)) @noudess 2023-12-01

### Database

* Add primary key to keyring table ([#3746](https://github.com/EQEmu/Server/pull/3746)) @Kinglykrab 2023-12-08
* Consolidate Starting Items Table ([#3723](https://github.com/EQEmu/Server/pull/3723)) @Kinglykrab 2023-11-30
* Extra whitespace in #3723 ([#3730](https://github.com/EQEmu/Server/pull/3730)) @joligario 2023-12-02
* Minor adjustment to #3726 ([#3732](https://github.com/EQEmu/Server/pull/3732)) @joligario 2023-12-03
* Modify `updated` column in `items` table with proper default. ([#3726](https://github.com/EQEmu/Server/pull/3726)) @joligario 2023-12-02
* Pull Spell Group Cache from Content DB ([#3749](https://github.com/EQEmu/Server/pull/3749)) @fryguy503 2023-12-08

### Faction

* Alliance line is only allowed 1 faction change at a time. ([#3718](https://github.com/EQEmu/Server/pull/3718)) @noudess 2023-11-26

### Fixes

* Changing Group Leader Invalidated GetLeaderName() ([#3712](https://github.com/EQEmu/Server/pull/3712)) @Kinglykrab 2023-11-26
* Fix 9245 SQL ([#3740](https://github.com/EQEmu/Server/pull/3740)) @Kinglykrab 2023-12-05
* Fix Swarm Pets Requiring NPC Aggros Flag ([#3738](https://github.com/EQEmu/Server/pull/3738)) @Kinglykrab 2023-12-05
* Guild Message Limits ([#3724](https://github.com/EQEmu/Server/pull/3724)) @neckkola 2023-11-29

### Quest API

* Add EVENT_AA_GAIN to AddAAPoints() ([#3733](https://github.com/EQEmu/Server/pull/3733)) @Kinglykrab 2023-12-03
* Add GMMove Overloads to Perl/Lua ([#3719](https://github.com/EQEmu/Server/pull/3719)) @Kinglykrab 2023-11-25

### Scripts

* Import items into `items_new` table instead of writing directly to the existing `items` table. ([#3725](https://github.com/EQEmu/Server/pull/3725)) @joligario 2023-11-30
* Revert database engine change from #3702. ([#3736](https://github.com/EQEmu/Server/pull/3736)) @joligario 2023-12-03
* Update 13th Floor Import Tool ([#3702](https://github.com/EQEmu/Server/pull/3702)) @joligario 2023-11-26
2023-12-10 22:07:09 -05:00
JJ a222128599 [Bug] Fix blocked spells regression from #3638 (#3753)
Fixes #3747
2023-12-10 21:40:06 -05:00
JJ 45b249e33d [CMake] Update minimum version of CMake (#3743)
```
CMake Deprecation Warning at client_files/CMakeLists.txt:1 (CMAKE_MINIMUM_REQUIRED):
  Compatibility with CMake < 3.5 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value or use a ...<max> suffix to tell
  CMake that the project does not need compatibility with older versions.
```
2023-12-08 12:48:59 -08:00
Fryguy c24834de5d [Database] Pull Spell Group Cache from Content DB (#3749) 2023-12-08 15:41:09 -05:00
Fryguy 841d7f2700 [Bug] PR 3638 Missed the blocked spells repository updates (#3748)
Ran generator to update blocked_spells Repo
2023-12-08 15:19:54 -05:00
Alex King 56c29154f0 [Database] Add primary key to keyring table (#3746)
* [Database] Add primary key to keyring table

# Notes
- Adds a primary key of `id` to `keyring` table so we can use it with repositories.

* Update version.h

* Update client.cpp

* Update client.cpp
2023-12-07 23:12:01 -05:00
nytmyr 6466c2ff21 [Bots] Add BotHealOnLevel to fully heal/mana on level. (#3745)
Adds the rule ***Bots, BotHealOnLevel***, default false, to control whether or not bots will gain full health and mana when their owner levels.
2023-12-07 22:25:17 -05:00
nytmyr 16dc210cd8 [Bots] Fix bots learning spells on level (#3744)
Previously bots would need to be zoned or camped/spawned to begin using new spells for their level.
2023-12-07 21:19:21 -05:00
Alex King 77045f558e [Bug Fix] Fix 9245 SQL (#3740)
* [Bug Fix] Fix 9245 SQL

# Notes
- Should be a `;` not `,`.

* Update database_update_manifest.cpp
2023-12-04 22:21:31 -05:00
Alex King e1fa2d5bc5 [Bug Fix] Fix Swarm Pets Requiring NPC Aggros Flag (#3738)
# Notes
- https://github.com/EQEmu/Server/pull/3595 made swarm pets require the `npc_aggro` flag to be set to attack.
2023-12-04 19:05:16 -05:00
Alex King b03f52de18 [Commands] Cleanup #object Command (#3722)
* [Commands] Cleanup #object Command

# Notes
- Cleanup messages and logic.
- Introduce enum for object types.
- Set ground work for object manipulation similar to door manipulation.

* Update object_manipulation.cpp

* Final push

* Update client_packet.cpp

* Update object_manipulation.cpp

* Update object_manipulation.cpp

* Update object.h

* Update client_packet.cpp

* Update client_packet.cpp

* Push.

* Update version.h

* Update database_update_manifest.cpp

* Update zone.cpp
2023-12-03 17:42:27 -05:00
JJ 226cc3d6cb [Scripts] Revert database engine change from #3702. (#3736)
InnoDB doesn't like the lengths. Will need to address that in the future.
2023-12-03 14:17:58 -05:00
Alex King 7f54e26dec [Quest API] Add EVENT_AA_GAIN to AddAAPoints() (#3733)
# Notes
- Using this method did not call `EVENT_AA_GAIN`.
2023-12-03 12:41:06 -05:00
Alex King 11a81d8e8a [Commands] Cleanup #zonebootup and #zoneshutdown Commands (#3729)
# Notes
- Cleanup messages and logic.
2023-12-03 12:40:54 -05:00
Alex King e719aa43cf [Cleanup] Remove hard-coded Status Checks (#3727)
* [Cleanup] Remove hard-coded Status Checks

# Notes
- Removed the hard-coded GM status checks since if you have access to the command we can now limit access to subcommands if necessary.

* Update client_packet.cpp
2023-12-03 11:44:30 -05:00
JJ 22994e3264 [Database] Minor adjustment to #3726 (#3732) 2023-12-03 10:18:27 -05:00
JJ cfbdecad19 [Database] Extra whitespace in #3723 (#3730) 2023-12-01 21:13:08 -05:00
JJ 2427f7e034 [Database] Modify updated column in items table with proper default. (#3726)
* [Database] Modify `updated` column in `items` table with proper default.
From https://mariadb.com/kb/en/datetime/, `datetime` can be ZERO_DATE (`0000-00-00` with no time component) or between `1000-01-01 00:00:00.000000` and `9999-12-31 23:59:59.999999`. Currently, `updated` is the only datetime field that is `NOT NULL` and improperly defaulted to `0000-00-00 00:00:00`. This change matches existing structures of the other `datetime` columns.

* Update items_repository.h

* Update base_items_repository.h

* Revert "Update items_repository.h"

This reverts commit 3599f26818.
2023-12-01 21:10:52 -05:00
Paul Coene 9a6403b196 [Commands] Fix formatting of #wpinfo output. (#3728) 2023-12-01 15:28:24 -05:00
JJ d8953c5156 [Scripts] Import items into items_new table instead of writing directly to the existing items table. (#3725) 2023-11-30 17:21:00 -05:00
Alex King 33b40e83b7 [Database] Consolidate Starting Items Table (#3723)
* [Database] Consolidate Starting Items Table

# Notes
- Convert `class`, `deityId`, `race`, and `zoneid` columns to `|` separated columns.
- Consolidates up to 15 rows per item down to a singular row.
- Allows ease of use for operators.
- Entire process is automated and creates a backup of pre-existing table.

* Update shareddb.cpp

* Unnecessary.
2023-11-30 14:37:08 -05:00
Mitch Freeman e75c31d524 [Bug Fix] Guild Message Limits (#3724)
Mail to 'Guild' was failing after after 50ish members.
The buffer was set at 512, which cut truncated the message and caused the issue.
Refactored to adjust the size of the buffer based on the inbound message size.
2023-11-28 19:03:32 -05:00
Paul Coene cf1f8d5460 [Commands] #petname changes PC to Nobody if selected. (#3720) 2023-11-26 14:50:44 -05:00
Paul Coene 690cacdaab [Faction] Alliance line is only allowed 1 faction change at a time. (#3718) 2023-11-26 01:13:16 -05:00
Alex King f9f45eedcd [Commands] Cleanup #acceptrules Command (#3716)
# Note
- Cleanup messages and logic.
- Utilize repositories in database methods.
2023-11-26 01:13:08 -05:00
Alex King 93ddffa57f [Commands] Cleanup #movement Command (#3715)
# Notes
- Cleanup messages and logic.
2023-11-26 01:13:03 -05:00
Alex King c9993fb698 [Commands] Cleanup #list Command (#3714)
* [Commands] Cleanup #list Command

# Notes
- Cleanup messages and logic.
- Introduce a struct so we don't have to duplicate so much code.

* Update list.cpp
2023-11-26 01:12:58 -05:00
Alex King aa0fbb8b45 [Commands] Cleanup #disarmtrap Command (#3713)
# Notes
- Cleanup messages and logic.
2023-11-26 00:27:22 -05:00
Alex King 62532c6bdd [Bug Fix] Changing Group Leader Invalidated GetLeaderName() (#3712)
# Notes
- Utilizes fixes posted in https://github.com/EQEmu/Server/issues/3706 to resolve https://github.com/EQEmu/Server/issues/368.
- Changing group leader caused issues because we assumed `member[0]` was always leader.
2023-11-26 00:27:15 -05:00
Alex King f8c3c03185 [Commands] Add #task complete Command (#3711)
# Notes
- `#task complete [Task ID]` allows operators to complete an entire task without updating individual activities.
2023-11-26 00:27:08 -05:00
Alex King 692a90f3f0 [Commands] Add #show aas Command (#3710)
# Notes
- Allows operators to view AAs a player has purchased from ingame and their ranks.
2023-11-26 00:27:02 -05:00
JJ 3a49d851ca [Scripts] Update 13th Floor Import Tool (#3702) 2023-11-26 00:20:10 -05:00
Alex King fdc5c27061 [Quest API] Add GMMove Overloads to Perl/Lua (#3719)
# Perl
- Add `$mob->GMMove(x, y, z, heading, save_guard_spot)`.

# Lua
- Add `mob:GMMove(x, y, z, heading, save_guard_spot)`.

# Notes
- Operators weren't able to disable saving guard spots, so moving with `GMMove` meant NPCs stayed where they were moved.
2023-11-25 18:15:37 -05:00
Paul Coene 56be69ddb1 [Commands] #guild set CharName 0 did not remove char from guild. (#3717)
* [Commands] #guild set CharName 0 did not remove char from guild.

* Fix cut-n-paste error on this branch
2023-11-25 11:27:43 -05:00
Alex King 9477ff72ac [Release] 22.34.2 (#3709)
### Admin

* Update date in changelog ([#3698](https://github.com/EQEmu/Server/pull/3698)) @joligario 2023-11-19

### Code

* Fix typo in #giveitem ([#3704](https://github.com/EQEmu/Server/pull/3704)) @Kinglykrab 2023-11-22

### Fixes

* Add "IgnoreLevelBasedHasteCaps" rule to GetHaste() ([#3705](https://github.com/EQEmu/Server/pull/3705)) @jcr4990 2023-11-23
* Fix bots/Mercenaries being removed from hatelist ([#3708](https://github.com/EQEmu/Server/pull/3708)) @Kinglykrab 2023-11-23
* Fix some spell types failing IsValidSpellRange check ([#3707](https://github.com/EQEmu/Server/pull/3707)) @nytmyr 2023-11-23

### Loginserver

* Update ticket login table structure ([#3703](https://github.com/EQEmu/Server/pull/3703)) @KimLS 2023-11-22
2023-11-24 13:23:10 -05:00
Alex King 6d8e80b1e5 [Bug Fix] Fix bots/Mercenaries being removed from hatelist (#3708)
# Notes
- https://github.com/EQEmu/Server/pull/3595 caused bots, bot pets, and mercenaries to be removed from hate list because we were only checking for `IsClient()` not `IsOfClientBotMerc()`.
- Resolves an issue mentioned [here](https://discord.com/channels/212663220849213441/1177288302383079534) where NPCs would run past bots/mercenaries to attack the owner.
2023-11-23 12:36:54 -05:00
Joel ebeaef598b [Bug Fix] Add "IgnoreLevelBasedHasteCaps" rule to GetHaste() (#3705) 2023-11-22 22:45:53 -05:00
nytmyr 60b65da7f2 [Bug Fix] Fix some spell types failing IsValidSpellRange check (#3707)
Hate Reduction, Slow and DoT spells were failing IsValidSpellRange checks due to improper spell IDs being checked.

They were using the first spell in a bot's spell list by checking botSpell.id vs the proper spells in the loop.
2023-11-22 22:44:59 -05:00
Alex King 100e6698ea [Cleanup] Fix typo in #giveitem (#3704) 2023-11-22 08:26:54 -05:00
Alex 2bd94ab7a2 [Loginserver] Update ticket login table structure (#3703)
* Updates login table to support tickets in a way that makes more sense.

* Change to snake_case as requested by Akka

---------

Co-authored-by: KimLS <KimLS@peqtgc.com>
2023-11-22 02:56:47 -06:00
Akkadius 4c8d68c24b [Release] 22.34.1 2023-11-20 09:12:11 -06:00
Akkadius 1755678b1f [Release] 22.34.1 2023-11-20 09:10:22 -06:00
JJ 39e2763968 [Admin] Update date in changelog (#3698) 2023-11-19 13:22:56 -05:00
Fryguy f7780b0247 [Bug Fix] NPC Faction War prevention. (#3595)
* [Bug] NPC Faction War prevention.

This should assist with prevention of NPC Faction waring. I have been using this code on my server for over 5 years with no coredumps or any noted bugs. This was brought up as users have reported a few events where they can trigger NPC's to fight each other.

* Correct a few entries to line up with updated code.

* Re-add missing RestTimer functionality
2023-11-19 11:40:15 -05:00
JJ c0fe0f11f7 [Release] 22.34.0 (#3697)
* Update CHANGELOG.md

* Update package.json

* Update version.h

* Update CHANGELOG.md
2023-11-19 11:21:39 -05:00
nytmyr a1f1f11940 [Bots] Add ownerraid, byclass and byrace actionables and fix group-based arguments for raids. (#3680)
This adds raid support to actionables for bot commands.

This also addresses Issue #3567

If in a group, group based commands will function as normal, however if in a raid they will support raids and use the group of the bot that fits  the criteria.

This adds new actionables as well; namely, **ownerraid**, **byclass** and **byrace**.

**byclass** and **byrace** use the int of the chosen class/race. IE Shadowknight is 5, Barbarian is 2. **^create help** is an easy way for players to identify numbers associated with classes and races.

**targetgroup** will now select all bots that meet the criteria within a raid group in addition to the current functionality of groups.
**namesgroup** will now select all bots that meet the criteria within a raid group in addition to the current functionality of groups.
**ownerraid** will select all bots in the raid owned by the player.
**byclass** will selects all bots in the group or raid owned by the player that match the class.
**byrace** will selects all bots in the group or raid owned by the player that match the race

This adds actionables to **^casterrange** and **^camp** as well.
2023-11-18 23:24:49 -05:00
Alex King 4c5013e09e [Cleanup] Cleanup #giveitem and #summonitem (#3692)
# Notes
- Adds summoned messages for `#giveitem` and `#summonitem`.
- `#summonitem` did not stop you from summoning items beyond your status level.
2023-11-18 21:22:12 -05:00
Alex King 838ffbd8c7 [Commands] Add #show aa_points Command (#3695)
# Notes
- Adds a command to view a player's current, spent, and total AA Points.
2023-11-18 19:23:35 -05:00
JJ 42b41d973c [GM Commands] Remove duplicate comment (#3691) 2023-11-18 19:08:56 -05:00
JJ e7761133a9 [GM Commands] Add #takeplatinum (#3690)
* [GM Commands] Add `#takeplatinum`

* Revert database manifest change

* Revert database version change

* Remove duplicated messages

* Remove hint as to why `#takeplatinum` might fail.
2023-11-18 19:08:48 -05:00
Alex King 93f2bea96e [Cleanup] Cleanup #show currencies Command (#3693)
* [Cleanup] Cleanup #show currencies Command

# Notes
- Cleans up messages.
- Adds `AA Points` as a viewable currency.
- Adds an enum for `MoneyTypes` and `MoneySubtypes` so we're not using magic numbers for `GetMoney` anymore.
- Converts money amounts to `uint64`.

* Update currencies.cpp

* Update currencies.cpp
2023-11-18 19:05:04 -05:00
regneq ded82ac6d6 [Spawn] (imported from takp) Added min_time and max_time to spawnentry. This will prevent a NPC from… (#3685)
* Added mintime and maxtime to spawnentry. This will prevent a NPC from spawning outside of the times specified. NPCs spawned in this way will then behave like normal NPCs. They will not despawn on their own, unlike spawn_events/spawn_conditions. NPCs using this that are alone in their spawngroup will attempt to spawn after their respawn timer has expired if the time of day is outside their range. Otherwise, another NPC in the spawngroup will be chosen to spawn. The normal rules (chance, spawn_limit) still apply to these NPCs, this is just another rule added to the system.

mintime and maxtime both represent the in-game EQ Hour. Valid values are 1-24. If either or both of the values are 0, then the NPC will not have any time restriction.

Added a new rule World:BootHour. This allows server admins to specify the EQ hour the server will boot to. Valid options are 1-24. Setting this rule to 0 (default) disables it and world will use whatever time is specified in the DB.

* generated base_spawnentry_repository.h from script

* removed the rule insert from database_update_manifest.cpp.

* Add logging, initializers, minor cleanup

* Remove if/else branch

* Update eqtime.cpp

* Initializers, logging

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-11-18 14:23:04 -06:00
JJ 6ef182edfd [Database] Pull pet power from content database (#3689) 2023-11-18 14:19:33 -06:00
Paul Coene e466ca1c6d [Illusions] RandomizeFeastures erased texture. (#3686) 2023-11-12 16:02:54 -05:00
Akkadius fa5a3155fe [Release] 22.33.0 2023-11-11 21:09:06 -06:00
Chris Miles a20d333f9d [Spawn2] Fix edge case with instances not copying disabled spawn state (#3688)
* [Spawn2] Fix edge case with instances not copying disabled spawn state

* Update spawn2.cpp
2023-11-11 21:00:50 -06:00
Alex King 853739b538 [Feature] Add Comment to Item Data/Quest API (#3669)
* [Feature] Add Comment to Item Data/Quest API

# Perl
- Add `quest::getitemcomment(item_id)`.
- Add `quest::getitemlore(item_id)`.
- Add `$questitemdata->GetComment()`.

# Lua
- Add `eq.get_item_comment(item_id)`.
- Add `eq.get_item_lore(item_id)`.
- Add `item:Comment()`.
# Notes
- Added the ability for operators to pull these fields from item data without a database hit.
- Fixed a bug in `embparser_api.cpp` where `GetZoneGravity` was connected to the wrong methods.

* Update embparser_api.cpp
2023-11-07 18:12:39 -05:00
Alex King 6094ec9c7b [Bug Fix] Fix GetZoneGravity package.add (#3684)
# Notes
- This was incorrect and would cause `GetZoneGravity()` to function improperly in Perl.
2023-11-07 18:12:25 -05:00
Akkadius 9da1d6b397 [Release] 22.32.1 2023-11-06 18:38:21 -06:00
Chris Miles 8ea7299a57 [Release] 22.32.0 (#3683) 2023-11-06 17:56:51 -06:00
Chris Miles 0811a899d1 [Spawn] Split spawn2 enabled into its own state table (#3664)
* [Spawn] Split spawn2 enabled into its own state table

* Update spawn2.cpp

* Update repo

* Make spawn2 enabled/disabled instance aware

* Update questmgr.cpp

* Make sure packet stuff is aware of instance_id

* Update questmgr.cpp

* Update database_update_manifest.cpp

* Cleanup

* Revert "Cleanup"

This reverts commit 64b58bfc52.

* Update database_instances.cpp
2023-11-06 17:34:42 -06:00
hg fad9599642 [Quest API] Add details to Lua event dispatch errors (#3679) 2023-11-06 17:31:34 -06:00
Fryguy 62711b13d8 Revert "[Bug Fix] Fix Killed XYZH support in EVENT_DEATH in Perl. (#3591)" (#3682)
This reverts commit 9b992167f0.
2023-11-06 17:30:55 -06:00
nytmyr 2702485206 [Bots] Fix invalid races from being created (#3681)
Previously this check allowed bots of invalid races to be created. If a race was neither a valid combination or a valid player race, it would pass the check and allow bots of any race to be created.

**^create 1 123 0** could create a Male Innoruuk Warrior
2023-11-06 17:03:34 -05:00
Mitch Freeman 0aadb891a1 [CRASH] Fix crash on CentOS when forming a raid with PCs or BOTs (#3676)
* [CRASH] Fix crash on CentOS

Update raid crash in CentOS.  raid constructors and learnmembers used a memset that was overwriting std::string structure.
Added default initializers to RaidMember struct

* Update based on feedback
2023-11-06 13:36:59 -05:00
JJ d812310c5b [GCC] Compatibility fix for GCC 13 (#3677)
Fixes ` ‘uint64_t’ does not name a type ` error under GCC 13
2023-11-05 14:05:15 -05:00
regneq 1420983700 [Spells] Added IsNightTime() for Dance of the Fireflies (#3667)
* Added IsNightOnly for Dance of the Fireflies spell which should only be cast at night from 7pm to 4pm.

* Update to include IsDayTime and replace magic numbers.
2023-11-04 13:58:08 -04:00
Alex King d25cc35f1b [Bug Fix] Add IsTGBCompatibleSpell() to package.add (#3675)
# Notes
- `IsTGBCompatibleSpell` was not exported properly.
2023-11-04 13:55:47 -04:00
Alex King ed7f395612 [Parser] Cleanup Spire Parsing for crosszonemoveplayerbycharid (#3674)
# Notes
- This formatting was causing Spire not to pick up the parameters.
2023-11-04 13:13:17 -04:00
Alex King 8dceb20dd8 [Parser] Cleanup Spire Parsing for crosszonemoveplayerbygroupid (#3673)
# Notes
- This formatting was causing Spire not to pick up the parameters.
2023-11-04 12:59:25 -04:00
Alex King 6929d180ca [Parser] Cleanup Spire Parsing for crosszonemoveplayerbyguildid (#3672)
# Notes
- This formatting was causing Spire not to pick up the parameters.
2023-11-04 12:45:21 -04:00
Alex King 011a66a75e [Parser] Cleanup Spire Parsing for crosszonemoveplayerbyexpeditionid (#3671)
# Notes
- This formatting was causing Spire not to pick up the parameters.
2023-11-04 12:31:47 -04:00
Alex King 07120563a2 [Bug Fix] Fix Perl__worldwideremovetask package (#3670)
# Notes
- Two lines were using the same parameters.
2023-11-04 12:18:25 -04:00
JJ cc985cbcd5 [Quest API] Add GetBaseRaceName() to Perl and Lua (#3668) 2023-10-31 21:43:04 -04:00
JJ 97caa79472 [Release] 22.31.3 (#3666)
* Update package.json

* Update version.h

* Update CHANGELOG.md
2023-10-31 20:26:30 -05:00
Alex King cfa575c756 [Logs] Convert Loot Messages to Error Logs (#3663)
* [Logs] Convert Loot Messages to Error Logs

# Notes
- These messages were sending to users and not being logged.
- `Message(Chat::Red, "Error: OP_EndLootRequest: Corpse not found (ent = 0)");` sends often when corpse expires right as you try to loot, so it makes the user think there's a true error.

* Update zoning.cpp
2023-10-31 18:58:06 -04:00
JJ 85063249b4 [Bug] Force raids off content database (#3665) 2023-10-31 18:46:03 -04:00
Akkadius 04d6f8feea [Release] 22.31.2 2023-10-31 09:47:18 -05:00
Akkadius dfc1bf0381 Revert "[Crash] Fix spell in AESpell related to beacons (#3659)"
This reverts commit 0b452f4ec1.
2023-10-31 09:46:08 -05:00
Akkadius 2237c3a056 [Release] 22.31.1 2023-10-31 08:08:29 -05:00
Akkadius 4af191c593 [Hotfix] Fix issue with blocked spells not loading properly 2023-10-31 08:06:51 -05:00
211 changed files with 22932 additions and 8814 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ volumes:
steps:
- name: Build Linux X64
image: akkadius/eqemu-server:v13
image: akkadius/eqemu-server:v14
environment:
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
+349
View File
@@ -1,3 +1,352 @@
## [22.39.0] - 12/27/2023
### Character
* Fix character copier due to schema change ([#3805](https://github.com/EQEmu/Server/pull/3805)) @Akkadius 2023-12-28
### Combat
* Disarm was not dropping item to ground due to bug ([#3811](https://github.com/EQEmu/Server/pull/3811)) @noudess 2023-12-27
### Logs
* Bulk insert new log settings ([#3810](https://github.com/EQEmu/Server/pull/3810)) @Akkadius 2023-12-28
* Reclassify unhelpful Info message ([#3809](https://github.com/EQEmu/Server/pull/3809)) @Akkadius 2023-12-28
### MySQL
* Fix MySQL Query error formatting ([#3808](https://github.com/EQEmu/Server/pull/3808)) @Akkadius 2023-12-28
### Objects
* Remove "No objects to load for zone" error message ([#3807](https://github.com/EQEmu/Server/pull/3807)) @Akkadius 2023-12-28
### Player Events
* Bulk replace settings on boot ([#3806](https://github.com/EQEmu/Server/pull/3806)) @Akkadius 2023-12-28
### Tasks
* Add enabled column ([#3804](https://github.com/EQEmu/Server/pull/3804)) @Akkadius 2023-12-28
## [22.38.0] - 12/26/2023
### Bots
* Remove unnecessary error on SetItemReuse ([#3795](https://github.com/EQEmu/Server/pull/3795)) @nytmyr 2023-12-20
### Code
* Consolidate GetHateRandom(), GetHateRandomBot(), GetHateRandomClient(), and GetHateRandomNPC() ([#3794](https://github.com/EQEmu/Server/pull/3794)) @Kinglykrab 2023-12-25
* Race constants refactor ([#3782](https://github.com/EQEmu/Server/pull/3782)) @Akkadius 2023-12-23
### Database
* Fix issue with saylinks query in MySQL 8.0+ ([#3800](https://github.com/EQEmu/Server/pull/3800)) @Akkadius 2023-12-24
* Update faction mods with Live data ([#3799](https://github.com/EQEmu/Server/pull/3799)) @joligario 2023-12-23
### Fixes
* Disable Hide/Improved Hide on Trap damage ([#3791](https://github.com/EQEmu/Server/pull/3791)) @Kinglykrab 2023-12-19
* Fix Bard Invisibility Songs breaking every 4 ticks ([#3783](https://github.com/EQEmu/Server/pull/3783)) @Kinglykrab 2023-12-19
* Fix can_riposte parameter in DoMeleeSkillAttackDmg ([#3792](https://github.com/EQEmu/Server/pull/3792)) @Kinglykrab 2023-12-19
### Forage
* Add a rule to disabled using common_food_ids from the list in forage.cpp. currently set to enabled. ([#3796](https://github.com/EQEmu/Server/pull/3796)) @regneq 2023-12-22
### NPC
* Support for multiple emotes per type, emote variables ([#3801](https://github.com/EQEmu/Server/pull/3801)) @regneq 2023-12-25
### Quest API
* Add GetHateTopBot(), GetHateTopClient(), and GetHateTopNPC() to Perl/Lua ([#3793](https://github.com/EQEmu/Server/pull/3793)) @Kinglykrab 2023-12-22
* Add SummonItemIntoInventory() to Perl/Lua ([#3797](https://github.com/EQEmu/Server/pull/3797)) @Kinglykrab 2023-12-22
### Repositories
* Add ReplaceOne and ReplaceMany ([#3802](https://github.com/EQEmu/Server/pull/3802)) @Akkadius 2023-12-26
## [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
### Bots
* Add BotHealOnLevel to fully heal/mana on level. ([#3745](https://github.com/EQEmu/Server/pull/3745)) @nytmyr 2023-12-08
* Fix bots learning spells on level ([#3744](https://github.com/EQEmu/Server/pull/3744)) @nytmyr 2023-12-08
### Bug
* Fix blocked spells regression from #3638 ([#3753](https://github.com/EQEmu/Server/pull/3753)) @joligario 2023-12-11
* PR 3638 Missed the blocked spells repository updates ([#3748](https://github.com/EQEmu/Server/pull/3748)) @fryguy503 2023-12-08
### CMake
* Update minimum version of CMake ([#3743](https://github.com/EQEmu/Server/pull/3743)) @joligario 2023-12-08
### Code
* Remove hard-coded Status Checks ([#3727](https://github.com/EQEmu/Server/pull/3727)) @Kinglykrab 2023-12-03
### Commands
* #guild set CharName 0 did not remove char from guild. ([#3717](https://github.com/EQEmu/Server/pull/3717)) @noudess 2023-11-25
* #petname changes PC to Nobody if selected. ([#3720](https://github.com/EQEmu/Server/pull/3720)) @noudess 2023-11-26
* Add #show aas Command ([#3710](https://github.com/EQEmu/Server/pull/3710)) @Kinglykrab 2023-11-26
* Add #task complete Command ([#3711](https://github.com/EQEmu/Server/pull/3711)) @Kinglykrab 2023-11-26
* Cleanup #acceptrules Command ([#3716](https://github.com/EQEmu/Server/pull/3716)) @Kinglykrab 2023-11-26
* Cleanup #disarmtrap Command ([#3713](https://github.com/EQEmu/Server/pull/3713)) @Kinglykrab 2023-11-26
* Cleanup #list Command ([#3714](https://github.com/EQEmu/Server/pull/3714)) @Kinglykrab 2023-11-26
* Cleanup #movement Command ([#3715](https://github.com/EQEmu/Server/pull/3715)) @Kinglykrab 2023-11-26
* Cleanup #object Command ([#3722](https://github.com/EQEmu/Server/pull/3722)) @Kinglykrab 2023-12-03
* Cleanup #zonebootup and #zoneshutdown Commands ([#3729](https://github.com/EQEmu/Server/pull/3729)) @Kinglykrab 2023-12-03
* Fix formatting of #wpinfo output. ([#3728](https://github.com/EQEmu/Server/pull/3728)) @noudess 2023-12-01
### Database
* Add primary key to keyring table ([#3746](https://github.com/EQEmu/Server/pull/3746)) @Kinglykrab 2023-12-08
* Consolidate Starting Items Table ([#3723](https://github.com/EQEmu/Server/pull/3723)) @Kinglykrab 2023-11-30
* Extra whitespace in #3723 ([#3730](https://github.com/EQEmu/Server/pull/3730)) @joligario 2023-12-02
* Minor adjustment to #3726 ([#3732](https://github.com/EQEmu/Server/pull/3732)) @joligario 2023-12-03
* Modify `updated` column in `items` table with proper default. ([#3726](https://github.com/EQEmu/Server/pull/3726)) @joligario 2023-12-02
* Pull Spell Group Cache from Content DB ([#3749](https://github.com/EQEmu/Server/pull/3749)) @fryguy503 2023-12-08
### Faction
* Alliance line is only allowed 1 faction change at a time. ([#3718](https://github.com/EQEmu/Server/pull/3718)) @noudess 2023-11-26
### Fixes
* Changing Group Leader Invalidated GetLeaderName() ([#3712](https://github.com/EQEmu/Server/pull/3712)) @Kinglykrab 2023-11-26
* Fix 9245 SQL ([#3740](https://github.com/EQEmu/Server/pull/3740)) @Kinglykrab 2023-12-05
* Fix Swarm Pets Requiring NPC Aggros Flag ([#3738](https://github.com/EQEmu/Server/pull/3738)) @Kinglykrab 2023-12-05
* Guild Message Limits ([#3724](https://github.com/EQEmu/Server/pull/3724)) @neckkola 2023-11-29
### Quest API
* Add EVENT_AA_GAIN to AddAAPoints() ([#3733](https://github.com/EQEmu/Server/pull/3733)) @Kinglykrab 2023-12-03
* Add GMMove Overloads to Perl/Lua ([#3719](https://github.com/EQEmu/Server/pull/3719)) @Kinglykrab 2023-11-25
### Scripts
* Import items into `items_new` table instead of writing directly to the existing `items` table. ([#3725](https://github.com/EQEmu/Server/pull/3725)) @joligario 2023-11-30
* Revert database engine change from #3702. ([#3736](https://github.com/EQEmu/Server/pull/3736)) @joligario 2023-12-03
* Update 13th Floor Import Tool ([#3702](https://github.com/EQEmu/Server/pull/3702)) @joligario 2023-11-26
## [22.34.2] - 11/23/2023
### Admin
* Update date in changelog ([#3698](https://github.com/EQEmu/Server/pull/3698)) @joligario 2023-11-19
### Code
* Fix typo in #giveitem ([#3704](https://github.com/EQEmu/Server/pull/3704)) @Kinglykrab 2023-11-22
### Fixes
* Add "IgnoreLevelBasedHasteCaps" rule to GetHaste() ([#3705](https://github.com/EQEmu/Server/pull/3705)) @jcr4990 2023-11-23
* Fix bots/Mercenaries being removed from hatelist ([#3708](https://github.com/EQEmu/Server/pull/3708)) @Kinglykrab 2023-11-23
* Fix some spell types failing IsValidSpellRange check ([#3707](https://github.com/EQEmu/Server/pull/3707)) @nytmyr 2023-11-23
### Loginserver
* Update ticket login table structure ([#3703](https://github.com/EQEmu/Server/pull/3703)) @KimLS 2023-11-22
## [22.34.1] - 11/20/2023
### EQTime
Hotfix for world not spamming save messages by setting to detail level logging @Akkadius 2023-11-20
## [22.34.0] - 11/19/2023
### Bots
* Add ownerraid, byclass and byrace actionables and fix group-based arguments for raids. ([#3680](https://github.com/EQEmu/Server/pull/3680)) @nytmyr 2023-11-19
### Code
* Cleanup #giveitem and #summonitem ([#3692](https://github.com/EQEmu/Server/pull/3692)) @Kinglykrab 2023-11-19
* Cleanup #show currencies Command ([#3693](https://github.com/EQEmu/Server/pull/3693)) @Kinglykrab 2023-11-19
### Commands
* Add #show aa_points Command ([#3695](https://github.com/EQEmu/Server/pull/3695)) @Kinglykrab 2023-11-19
### Database
* Pull pet power from content database ([#3689](https://github.com/EQEmu/Server/pull/3689)) @joligario 2023-11-18
### GM Commands
* Add `#takeplatinum` ([#3690](https://github.com/EQEmu/Server/pull/3690)) @joligario 2023-11-19
* Remove duplicate comment ([#3691](https://github.com/EQEmu/Server/pull/3691)) @joligario 2023-11-19
### Illusions
* RandomizeFeastures erased texture. ([#3686](https://github.com/EQEmu/Server/pull/3686)) @noudess 2023-11-12
### Spawn
* (imported from takp) Added min_time and max_time to spawnentry. This will prevent a NPC from… ([#3685](https://github.com/EQEmu/Server/pull/3685)) @regneq 2023-11-18
## [22.33.0] - 11/11/2023
### Feature
* Add Comment to Item Data/Quest API ([#3669](https://github.com/EQEmu/Server/pull/3669)) @Kinglykrab 2023-11-07
### Spawn2
* Fix edge case with instances not copying disabled spawn state ([#3688](https://github.com/EQEmu/Server/pull/3688)) @Akkadius 2023-11-12
## [22.32.1] - 11/6/2023
### Hotfix
* Adjust spawn2_disabled migration to copy data over
## [22.32.0] - 11/6/2023
### Bots
* Fix invalid races from being created ([#3681](https://github.com/EQEmu/Server/pull/3681)) @nytmyr 2023-11-06
### Crash
* Fix crash on CentOS when forming a raid with PCs or BOTs ([#3676](https://github.com/EQEmu/Server/pull/3676)) @neckkola 2023-11-06
### Fixes
* Add IsTGBCompatibleSpell() to package.add ([#3675](https://github.com/EQEmu/Server/pull/3675)) @Kinglykrab 2023-11-04
* Fix Perl__worldwideremovetask package ([#3670](https://github.com/EQEmu/Server/pull/3670)) @Kinglykrab 2023-11-04
* Revert " Fix Killed XYZH support in EVENT_DEATH in Perl. " (#3682) ([#3591](https://github.com/EQEmu/Server/pull/3591)) @fryguy503 2023-11-06
CRASH
### GCC
* Compatibility fix for GCC 13 ([#3677](https://github.com/EQEmu/Server/pull/3677)) @joligario 2023-11-05
### Parser
* Cleanup Spire Parsing for crosszonemoveplayerbycharid ([#3674](https://github.com/EQEmu/Server/pull/3674)) @Kinglykrab 2023-11-04
* Cleanup Spire Parsing for crosszonemoveplayerbyexpeditionid ([#3671](https://github.com/EQEmu/Server/pull/3671)) @Kinglykrab 2023-11-04
* Cleanup Spire Parsing for crosszonemoveplayerbygroupid ([#3673](https://github.com/EQEmu/Server/pull/3673)) @Kinglykrab 2023-11-04
* Cleanup Spire Parsing for crosszonemoveplayerbyguildid ([#3672](https://github.com/EQEmu/Server/pull/3672)) @Kinglykrab 2023-11-04
### Quest API
* Add GetBaseRaceName() to Perl and Lua ([#3668](https://github.com/EQEmu/Server/pull/3668)) @joligario 2023-11-01
* Add details to Lua event dispatch errors ([#3679](https://github.com/EQEmu/Server/pull/3679)) @hgtw 2023-11-06
### Spawn
* Split spawn2 enabled into its own state table ([#3664](https://github.com/EQEmu/Server/pull/3664)) @Akkadius 2023-11-06
### Spells
* Added IsNightTime() for Dance of the Fireflies ([#3667](https://github.com/EQEmu/Server/pull/3667)) @regneq 2023-11-04
## [22.31.3] - 10/31/2023
### Bug
* Force raids off content database ([#3665](https://github.com/EQEmu/Server/pull/3665)) @joligario 2023-10-31
### Crash
* Revert " Fix spell in AESpell related to beacons " ([#3659](https://github.com/EQEmu/Server/pull/3659)) @Akkadius 2023-10-31
### Fixes
* Fix issue with blocked spells not loading properly @Akkadius 2023-10-31
### Logs
* Convert Loot Messages to Error Logs ([#3663](https://github.com/EQEmu/Server/pull/3663)) @Kinglykrab 2023-10-31
## [22.31.2] - 10/31/2023
### Fixes
* Hotfix issue with beacon spells crashing @Akkadius 2023-10-31
## [22.31.1] - 10/31/2023
### Fixes
* Hotfix issue with blocked spells not loading properly @Akkadius 2023-10-31
## [22.31.0] - 10/29/2023
### Crash
+1
View File
@@ -17,6 +17,7 @@ SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF)
OPTION(EQEMU_BUILD_STATIC "Build with static linking" OFF)
OPTION(EQEMU_BUILD_PCH "Build with precompiled headers (Windows)" ON)
IF (EQEMU_BUILD_STATIC)
SET(BUILD_SHARED_LIBS OFF)
+1 -1
View File
@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
CMAKE_MINIMUM_REQUIRED(VERSION 3.5)
add_subdirectory(import)
add_subdirectory(export)
+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)
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)
+296 -473
View File
File diff suppressed because it is too large Load Diff
+96 -93
View File
@@ -19,99 +19,106 @@
#define CLASSES_CH
#include "../common/types.h"
#include "../common/rulesys.h"
#include <string>
#include <map>
#define NO_CLASS 0
#define WARRIOR 1
#define CLERIC 2
#define PALADIN 3
#define RANGER 4
#define SHADOWKNIGHT 5
#define DRUID 6
#define MONK 7
#define BARD 8
#define ROGUE 9
#define SHAMAN 10
#define NECROMANCER 11
#define WIZARD 12
#define MAGICIAN 13
#define ENCHANTER 14
#define BEASTLORD 15
#define BERSERKER 16
#define WARRIORGM 20
#define CLERICGM 21
#define PALADINGM 22
#define RANGERGM 23
#define SHADOWKNIGHTGM 24
#define DRUIDGM 25
#define MONKGM 26
#define BARDGM 27
#define ROGUEGM 28
#define SHAMANGM 29
#define NECROMANCERGM 30
#define WIZARDGM 31
#define MAGICIANGM 32
#define ENCHANTERGM 33
#define BEASTLORDGM 34
#define BERSERKERGM 35
#define BANKER 40
#define MERCHANT 41
#define DISCORD_MERCHANT 59
#define ADVENTURE_RECRUITER 60
#define ADVENTURE_MERCHANT 61
#define LDON_TREASURE 62 // objects you can use /open on first seen in LDONs, seen on Danvi's Corpse in Akheva
#define TRIBUTE_MASTER 63
#define GUILD_TRIBUTE_MASTER 64 // not sure
#define GUILD_BANKER 66
#define NORRATHS_KEEPERS_MERCHANT 67
#define DARK_REIGN_MERCHANT 68
#define FELLOWSHIP_MASTER 69
#define ALT_CURRENCY_MERCHANT 70
#define MERCENARY_MASTER 71
namespace Class {
constexpr uint8 None = 0;
constexpr uint8 Warrior = 1;
constexpr uint8 Cleric = 2;
constexpr uint8 Paladin = 3;
constexpr uint8 Ranger = 4;
constexpr uint8 ShadowKnight = 5;
constexpr uint8 Druid = 6;
constexpr uint8 Monk = 7;
constexpr uint8 Bard = 8;
constexpr uint8 Rogue = 9;
constexpr uint8 Shaman = 10;
constexpr uint8 Necromancer = 11;
constexpr uint8 Wizard = 12;
constexpr uint8 Magician = 13;
constexpr uint8 Enchanter = 14;
constexpr uint8 Beastlord = 15;
constexpr uint8 Berserker = 16;
constexpr uint8 WarriorGM = 20;
constexpr uint8 ClericGM = 21;
constexpr uint8 PaladinGM = 22;
constexpr uint8 RangerGM = 23;
constexpr uint8 ShadowKnightGM = 24;
constexpr uint8 DruidGM = 25;
constexpr uint8 MonkGM = 26;
constexpr uint8 BardGM = 27;
constexpr uint8 RogueGM = 28;
constexpr uint8 ShamanGM = 29;
constexpr uint8 NecromancerGM = 30;
constexpr uint8 WizardGM = 31;
constexpr uint8 MagicianGM = 32;
constexpr uint8 EnchanterGM = 33;
constexpr uint8 BeastlordGM = 34;
constexpr uint8 BerserkerGM = 35;
constexpr uint8 Banker = 40;
constexpr uint8 Merchant = 41;
constexpr uint8 DiscordMerchant = 59;
constexpr uint8 AdventureRecruiter = 60;
constexpr uint8 AdventureMerchant = 61;
constexpr uint8 LDoNTreasure = 62;
constexpr uint8 TributeMaster = 63;
constexpr uint8 GuildTributeMaster = 64;
constexpr uint8 GuildBanker = 66;
constexpr uint8 NorrathsKeepersMerchant = 67;
constexpr uint8 DarkReignMerchant = 68;
constexpr uint8 FellowshipMaster = 69;
constexpr uint8 AlternateCurrencyMerchant = 70;
constexpr uint8 MercenaryLiaison = 71;
constexpr uint8 PLAYER_CLASS_COUNT = 16;
constexpr uint16 ALL_CLASSES_BITMASK = 65535;
};
// player class values
#define PLAYER_CLASS_UNKNOWN 0
#define PLAYER_CLASS_WARRIOR 1
#define PLAYER_CLASS_CLERIC 2
#define PLAYER_CLASS_PALADIN 3
#define PLAYER_CLASS_RANGER 4
#define PLAYER_CLASS_SHADOWKNIGHT 5
#define PLAYER_CLASS_DRUID 6
#define PLAYER_CLASS_MONK 7
#define PLAYER_CLASS_BARD 8
#define PLAYER_CLASS_ROGUE 9
#define PLAYER_CLASS_SHAMAN 10
#define PLAYER_CLASS_NECROMANCER 11
#define PLAYER_CLASS_WIZARD 12
#define PLAYER_CLASS_MAGICIAN 13
#define PLAYER_CLASS_ENCHANTER 14
#define PLAYER_CLASS_BEASTLORD 15
#define PLAYER_CLASS_BERSERKER 16
static std::map<uint8, uint16> player_class_bitmasks = {
{Class::Warrior, 1},
{Class::Cleric, 2},
{Class::Paladin, 4},
{Class::Ranger, 8},
{Class::ShadowKnight, 16},
{Class::Druid, 32},
{Class::Monk, 64},
{Class::Bard, 128},
{Class::Rogue, 256},
{Class::Shaman, 512},
{Class::Necromancer, 1024},
{Class::Wizard, 2048},
{Class::Magician, 4096},
{Class::Enchanter, 8192},
{Class::Beastlord, 16384},
{Class::Berserker, 32768},
};
#define PLAYER_CLASS_COUNT 16
static std::string shadow_knight_class_name = (
RuleB(World, UseOldShadowKnightClassExport) ?
"Shadowknight" :
"Shadow Knight"
);
// player class bits
#define PLAYER_CLASS_UNKNOWN_BIT 0
#define PLAYER_CLASS_WARRIOR_BIT 1
#define PLAYER_CLASS_CLERIC_BIT 2
#define PLAYER_CLASS_PALADIN_BIT 4
#define PLAYER_CLASS_RANGER_BIT 8
#define PLAYER_CLASS_SHADOWKNIGHT_BIT 16
#define PLAYER_CLASS_DRUID_BIT 32
#define PLAYER_CLASS_MONK_BIT 64
#define PLAYER_CLASS_BARD_BIT 128
#define PLAYER_CLASS_ROGUE_BIT 256
#define PLAYER_CLASS_SHAMAN_BIT 512
#define PLAYER_CLASS_NECROMANCER_BIT 1024
#define PLAYER_CLASS_WIZARD_BIT 2048
#define PLAYER_CLASS_MAGICIAN_BIT 4096
#define PLAYER_CLASS_ENCHANTER_BIT 8192
#define PLAYER_CLASS_BEASTLORD_BIT 16384
#define PLAYER_CLASS_BERSERKER_BIT 32768
#define PLAYER_CLASS_ALL_MASK 65535 // was 65536
static std::map<uint8, std::string> class_names = {
{Class::Warrior, "Warrior"},
{Class::Cleric, "Cleric"},
{Class::Paladin, "Paladin"},
{Class::Ranger, "Ranger"},
{Class::ShadowKnight, shadow_knight_class_name},
{Class::Druid, "Druid"},
{Class::Monk, "Monk"},
{Class::Bard, "Bard"},
{Class::Rogue, "Rogue"},
{Class::Shaman, "Shaman"},
{Class::Necromancer, "Necromancer"},
{Class::Wizard, "Wizard"},
{Class::Magician, "Magician"},
{Class::Enchanter, "Enchanter"},
{Class::Beastlord, "Beastlord"},
{Class::Berserker, "Berserker"},
};
#define ARMOR_TYPE_UNKNOWN 0
@@ -126,16 +133,12 @@
const char* GetClassIDName(uint8 class_id, uint8 level = 0);
const char* GetPlayerClassName(uint32 player_class_value, uint8 level = 0);
bool IsPlayerClass(uint8 class_id);
const std::string GetPlayerClassAbbreviation(uint8 class_id);
uint32 GetPlayerClassValue(uint8 class_id);
uint32 GetPlayerClassBit(uint8 class_id);
uint8 GetClassIDFromPlayerClassValue(uint32 player_class_value);
uint8 GetClassIDFromPlayerClassBit(uint32 player_class_bit);
uint8 GetPlayerClassValue(uint8 class_id);
uint16 GetPlayerClassBit(uint8 class_id);
bool IsFighterClass(uint8 class_id);
bool IsSpellFighterClass(uint8 class_id);
+50 -37
View File
@@ -29,6 +29,8 @@
#include <stdlib.h>
#include <string.h>
#include "../common/repositories/account_repository.h"
// Disgrace: for windows compile
#ifdef _WINDOWS
#include <windows.h>
@@ -1643,25 +1645,20 @@ void Database::ClearGroupLeader(uint32 gid) {
std::cout << "Unable to clear group leader: " << results.ErrorMessage() << std::endl;
}
uint8 Database::GetAgreementFlag(uint32 acctid) {
std::string query = StringFormat("SELECT rulesflag FROM account WHERE id=%i",acctid);
auto results = QueryDatabase(query);
if (!results.Success())
uint8 Database::GetAgreementFlag(uint32 account_id)
{
const auto& e = AccountRepository::FindOne(*this, account_id);
if (!e.id) {
return 0;
}
if (results.RowCount() != 1)
return 0;
auto row = results.begin();
return Strings::ToUnsignedInt(row[0]);
return e.rulesflag;
}
void Database::SetAgreementFlag(uint32 acctid) {
std::string query = StringFormat("UPDATE account SET rulesflag=1 where id=%i", acctid);
QueryDatabase(query);
void Database::SetAgreementFlag(uint32 account_id) {
auto e = AccountRepository::FindOne(*this, account_id);
e.rulesflag = 1;
AccountRepository::UpdateOne(*this, e);
}
void Database::ClearRaid(uint32 rid) {
@@ -2097,37 +2094,45 @@ void Database::ClearInvSnapshots(bool from_now) {
struct TimeOfDay_Struct Database::LoadTime(time_t &realtime)
{
TimeOfDay_Struct eqTime;
std::string query = StringFormat("SELECT minute,hour,day,month,year,realtime FROM eqtime limit 1");
TimeOfDay_Struct t{};
std::string query = StringFormat("SELECT minute,hour,day,month,year,realtime FROM eqtime limit 1");
auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() == 0){
if (!results.Success() || results.RowCount() == 0) {
LogInfo("Loading EQ time of day failed. Using defaults");
eqTime.minute = 0;
eqTime.hour = 9;
eqTime.day = 1;
eqTime.month = 1;
eqTime.year = 3100;
t.minute = 0;
t.hour = 9;
t.day = 1;
t.month = 1;
t.year = 3100;
realtime = time(nullptr);
}
else{
auto row = results.begin();
eqTime.minute = Strings::ToUnsignedInt(row[0]);
eqTime.hour = Strings::ToUnsignedInt(row[1]);
eqTime.day = Strings::ToUnsignedInt(row[2]);
eqTime.month = Strings::ToUnsignedInt(row[3]);
eqTime.year = Strings::ToUnsignedInt(row[4]);
realtime = Strings::ToBigInt(row[5]);
return t;
}
return eqTime;
auto row = results.begin();
uint8 hour = Strings::ToUnsignedInt(row[1]);
time_t realtime_ = Strings::ToBigInt(row[5]);
if (RuleI(World, BootHour) > 0 && RuleI(World, BootHour) <= 24) {
hour = RuleI(World, BootHour);
realtime_ = time(nullptr);
}
t.minute = Strings::ToUnsignedInt(row[0]);
t.hour = hour;
t.day = Strings::ToUnsignedInt(row[2]);
t.month = Strings::ToUnsignedInt(row[3]);
t.year = Strings::ToUnsignedInt(row[4]);
realtime = realtime_;
LogEqTime("Setting hour to [{}]", hour);
return t;
}
bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year)
{
std::string query = StringFormat("UPDATE eqtime set minute = %d, hour = %d, day = %d, month = %d, year = %d, realtime = %d limit 1", minute, hour, day, month, year, time(0));
std::string query = StringFormat("UPDATE eqtime set minute = %d, hour = %d, day = %d, month = %d, year = %d, realtime = %d limit 1", minute, hour, day, month, year, time(nullptr));
auto results = QueryDatabase(query);
return results.Success();
@@ -2241,6 +2246,11 @@ bool Database::CopyCharacter(
row = results.begin();
std::string new_character_id = row[0];
std::vector<std::string> tables_to_zero_id = {
"keyring",
"data_buckets",
};
TransactionBegin();
for (const auto &iter : DatabaseSchema::GetCharacterTables()) {
std::string table_name = iter.first;
@@ -2274,6 +2284,10 @@ bool Database::CopyCharacter(
std::string column = columns[column_index];
std::string value = row[column_index] ? row[column_index] : "null";
if (column == "id" && Strings::Contains(tables_to_zero_id, table_name)) {
value = "0";
}
if (column == character_id_column_name) {
value = new_character_id;
}
@@ -2321,7 +2335,6 @@ bool Database::CopyCharacter(
if (!insert.ErrorMessage().empty()) {
TransactionRollback();
return false;
break;
}
}
}
+2 -2
View File
@@ -188,10 +188,10 @@ public:
uint32 CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus = 0);
uint32 CreateAccount(const char* name, const char* password, int16 status, const char* loginserver, uint32 lsaccount_id);
uint32 GetAccountIDFromLSID(const std::string& in_loginserver_id, uint32 in_loginserver_account_id, char* in_account_name = 0, int16* in_status = 0);
uint8 GetAgreementFlag(uint32 acctid);
uint8 GetAgreementFlag(uint32 account_id);
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
void SetAgreementFlag(uint32 acctid);
void SetAgreementFlag(uint32 account_id);
int GetIPExemption(std::string account_ip);
void SetIPExemption(std::string account_ip, int exemption_amount);
@@ -322,6 +322,10 @@ void DatabaseDumpService::DatabaseDump()
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();
std::string execution_result = Process::execute(execute_command);
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));
// 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
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;
}
@@ -4997,6 +4997,165 @@ ADD PRIMARY KEY (`id`) USING BTREE,
ADD UNIQUE INDEX(`varname`);
)"
},
ManifestEntry{
.version = 9241,
.description = "2023_10_29_split_spawn2_enabled.sql",
.check = "SHOW TABLES LIKE 'spawn2_disabled'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE `spawn2_backup_2023_10_29` LIKE `spawn2`;
INSERT INTO `spawn2_backup_2023_10_29` SELECT * FROM `spawn2`;
CREATE TABLE `spawn2_disabled` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`spawn2_id` int(11) DEFAULT NULL,
`instance_id` int(11) DEFAULT 0,
`disabled` smallint(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `spawn2_id` (`spawn2_id`,`instance_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
INSERT INTO spawn2_disabled (spawn2_id, disabled) SELECT id, 1 FROM spawn2 WHERE enabled = 0;
ALTER TABLE `spawn2` DROP COLUMN `enabled`;
)"
},
ManifestEntry{
.version = 9242,
.description = "2023_11_7_mintime_maxtime_spawnentry.sql",
.check = "SHOW COLUMNS FROM `spawnentry` LIKE 'min_time'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `spawnentry`
ADD COLUMN `min_time` smallint(4) NOT NULL DEFAULT 0 AFTER `condition_value_filter`,
ADD COLUMN `max_time` smallint(4) NOT NULL DEFAULT 0 AFTER `min_time`;
)"
},
ManifestEntry{
.version = 9243,
.description = "2023_11_27_starting_items_revamp.sql",
.check = "SHOW COLUMNS FROM `starting_items` LIKE 'race_list'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE `starting_items_backup_9243` LIKE `starting_items`;
INSERT INTO `starting_items_backup_9243` SELECT * FROM `starting_items`;
CREATE TABLE `starting_items_new` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`race_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`class_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`deity_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`zone_id_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
`item_id` int(11) UNSIGNED NOT NULL DEFAULT 0,
`item_charges` tinyint(3) UNSIGNED NOT NULL DEFAULT 1,
`gm` mediumint(3) UNSIGNED NOT NULL DEFAULT 0,
`slot` mediumint(9) NOT NULL DEFAULT -1,
`min_expansion` tinyint(4) NOT NULL DEFAULT -1,
`max_expansion` tinyint(4) NOT NULL DEFAULT -1,
`content_flags` varchar(100) NULL,
`content_flags_disabled` varchar(100) NULL,
PRIMARY KEY (`id`)
);
INSERT INTO
`starting_items_new`
(
SELECT
0 AS `id`,
GROUP_CONCAT(DISTINCT `class` ORDER BY class ASC SEPARATOR '|') AS `class_list`,
GROUP_CONCAT(DISTINCT `race` ORDER BY race ASC SEPARATOR '|') AS `race_list`,
GROUP_CONCAT(DISTINCT `deityid` ORDER BY deityid ASC SEPARATOR '|') AS `deity_list`,
GROUP_CONCAT(DISTINCT `zoneid` ORDER BY zoneid ASC SEPARATOR '|') AS `zone_list`,
`itemid`,
`item_charges`,
`gm`,
`slot`,
`min_expansion`,
`max_expansion`,
`content_flags`,
`content_flags_disabled`
FROM
`starting_items`
GROUP BY
`itemid`
);
DROP TABLE `starting_items`;
RENAME TABLE `starting_items_new` TO `starting_items`;
)"
},
ManifestEntry{
.version = 9244,
.description = "2023_11_30_items_table_schema.sql",
.check = "SHOW COLUMNS FROM `items` LIKE 'updated'",
.condition = "contains",
.match = "0000-00-00 00:00:00",
.sql = R"(
ALTER TABLE `items` MODIFY COLUMN `updated` datetime NULL DEFAULT NULL;
)"
},
ManifestEntry{
.version = 9245,
.description = "2023_12_03_object_incline.sql",
.check = "SHOW COLUMNS FROM `object` LIKE 'incline'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `object` CHANGE COLUMN `unknown08` `size_percentage` float NOT NULL DEFAULT 0 AFTER `icon`;
ALTER TABLE `object` CHANGE COLUMN `unknown10` `solid_type` mediumint(5) NOT NULL DEFAULT 0 AFTER `size`;
ALTER TABLE `object` CHANGE COLUMN `unknown20` `incline` int(11) NOT NULL DEFAULT 0 AFTER `solid_type`;
)"
},
ManifestEntry{
.version = 9246,
.description = "2023_12_07_keyring_id.sql",
.check = "SHOW COLUMNS FROM `keyring` LIKE 'id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `keyring`
ADD COLUMN `id` int UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
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`;
)"
},
ManifestEntry{
.version = 9248,
.description = "2023_12_22_drop_npc_emotes_index.sql",
.check = "show index from npc_emotes where key_name = 'emoteid'",
.condition = "not_empty",
.match = "",
.sql = R"(
ALTER TABLE `npc_emotes` DROP INDEX `emoteid`;
)"
},
ManifestEntry{
.version = 9249,
.description = "2023_12_26_add_tasks_enabled_column.sql",
.check = "SHOW COLUMNS FROM `tasks` LIKE 'enabled'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `tasks`
ADD COLUMN `enabled` smallint NULL DEFAULT 1 AFTER `faction_amount`
)"
}
// -- template; copy/paste this when you need to create a new entry
// ManifestEntry{
@@ -82,6 +82,28 @@ CREATE TABLE `bot_starting_items` (
`content_flags_disabled` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) 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
+3
View File
@@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/repositories/raid_members_repository.h"
#include "../common/repositories/respawn_times_repository.h"
#include "../common/repositories/spawn_condition_values_repository.h"
#include "repositories/spawn2_disabled_repository.h"
#include "database.h"
@@ -49,6 +50,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <sys/time.h>
#endif
bool Database::AddClientToInstance(uint16 instance_id, uint32 character_id)
{
auto e = InstanceListPlayerRepository::NewEntity();
@@ -553,6 +555,7 @@ void Database::PurgeExpiredInstances()
CharacterCorpsesRepository::BuryInstances(*this, imploded_instance_ids);
DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids);
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
Spawn2DisabledRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
}
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
+2 -1
View File
@@ -71,7 +71,7 @@ namespace DatabaseSchema {
{"character_tasks", "charid"},
{"character_tribute", "character_id"},
{"completed_tasks", "charid"},
{"data_buckets", "id"},
{"data_buckets", "character_id"},
{"faction_values", "char_id"},
{"friends", "charid"},
{"guild_members", "char_id"},
@@ -345,6 +345,7 @@ namespace DatabaseSchema {
"respawn_times",
"saylink",
"server_scheduled_events",
"spawn2_disabled",
"player_event_log_settings",
"player_event_logs",
"shared_task_activity_state",
+1 -1
View File
@@ -138,7 +138,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
* Error logging
*/
if (mysql_errno(mysql) > 0 && query[0] != '\0') {
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(mysql), mysql_error(mysql), query);
LogMySQLError("MySQL Error ({}) [{}] Query [{}]", mysql_errno(mysql), mysql_error(mysql), query);
}
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(mysql), errorBuffer);
+23
View File
@@ -1052,4 +1052,27 @@ enum ScribeSpellActions
Unmemorize
};
enum SpellTimeRestrictions
{
NoRestriction,
Day,
Night
};
enum MoneyTypes
{
Copper,
Silver,
Gold,
Platinum
};
enum MoneySubtypes
{
Personal,
Bank,
Cursor,
SharedBank // Platinum Only
};
#endif /*COMMON_EQ_CONSTANTS_H*/
+8 -2
View File
@@ -124,6 +124,12 @@ struct LDoNTrapTemplate
uint8 locked;
};
enum CrystalReclaimTypes
{
Ebon = 5,
Radiant = 4,
};
///////////////////////////////////////////////////////////////////////////////
@@ -2594,11 +2600,11 @@ struct BookButton_Struct
struct Object_Struct {
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
/*08*/ float size; //
/*10*/ uint16 solidtype; //
/*10*/ uint16 solid_type; //
/*12*/ uint32 drop_id; // Unique object id for zone
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
/*18*/ uint16 zone_instance; //
/*20*/ uint32 unknown020; //
/*20*/ uint32 incline; //
/*24*/ uint32 unknown024; //
/*28*/ float tilt_x;
/*32*/ float tilt_y;
+13 -7
View File
@@ -100,6 +100,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::Discord].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::QuestErrors].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::QuestErrors].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::EqTime].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::EqTime].log_to_gmsay = static_cast<uint8>(Logs::General);
/**
* RFC 5424
@@ -649,6 +651,9 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
}
// Auto inject categories that don't exist in the database...
std::vector<LogsysCategoriesRepository::LogsysCategories> db_categories_to_add{};
for (int i = Logs::AA; i != Logs::MaxCategoryID; i++) {
bool is_missing_in_database = std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end();
@@ -663,11 +668,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
}
if (is_missing_in_database && !is_deprecated_category) {
LogInfo(
"Automatically adding new log category [{}] ({})",
Logs::LogCategoryName[i],
i
);
LogInfo("Automatically adding new log category [{}] ({})", Logs::LogCategoryName[i], i);
auto new_category = LogsysCategoriesRepository::NewEntity();
new_category.log_category_id = i;
@@ -676,11 +677,16 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
new_category.log_to_gmsay = log_settings[i].log_to_gmsay;
new_category.log_to_file = log_settings[i].log_to_file;
new_category.log_to_discord = log_settings[i].log_to_discord;
LogsysCategoriesRepository::InsertOne(*m_database, new_category);
db_categories_to_add.emplace_back(new_category);
}
}
if (!db_categories_to_add.empty()) {
LogsysCategoriesRepository::ReplaceMany(*m_database, db_categories_to_add);
LoadLogDatabaseSettings();
return this;
}
LogInfo("Loaded [{}] log categories", categories.size());
auto webhooks = DiscordWebhooksRepository::GetWhere(*m_database, fmt::format("id < {}", MAX_DISCORD_WEBHOOK_ID));
+2
View File
@@ -139,6 +139,7 @@ namespace Logs {
PlayerEvents,
DataBuckets,
Zoning,
EqTime,
MaxCategoryID /* Don't Remove this */
};
@@ -237,6 +238,7 @@ namespace Logs {
"PlayerEvents",
"DataBuckets",
"Zoning",
"EqTime",
};
}
+10
View File
@@ -814,6 +814,16 @@
OutF(LogSys, Logs::Detail, Logs::Zoning, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogEqTime(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::EqTime))\
OutF(LogSys, Logs::General, Logs::EqTime, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogEqTimeDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::EqTime))\
OutF(LogSys, Logs::Detail, Logs::EqTime, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
+51 -7
View File
@@ -46,16 +46,16 @@ EQTime::EQTime()
timezone = 0;
memset(&eqTime, 0, sizeof(eqTime));
//Defaults for time
TimeOfDay_Struct start;
start.day = 1;
start.hour = 9;
start.minute = 0;
start.month = 1;
start.year = 3100;
TimeOfDay_Struct t{};
t.day = 1;
t.hour = 9;
t.minute = 0;
t.month = 1;
t.year = 3100;
//Set default time zone
timezone = 0;
//Start EQTimer
SetCurrentEQTimeOfDay(start, time(0));
SetCurrentEQTimeOfDay(t, time(nullptr));
}
//getEQTimeOfDay - Reads timeConvert and writes the result to eqTimeOfDay
@@ -200,3 +200,47 @@ void EQTime::ToString(TimeOfDay_Struct *t, std::string &str) {
buf[127] = '\0';
str = buf;
}
bool EQTime::IsDayTime() {
TimeOfDay_Struct tod{}; //Day time is 5am to 6:59pm (14 hours in-game)
GetCurrentEQTimeOfDay(&tod); //TODO: what if it fails and returns zero?
if (tod.hour >= 5 || tod.hour < 19) {
return true;
}
return false;
}
bool EQTime::IsNightTime() {
TimeOfDay_Struct tod{}; //Night time is 7pm to 4:59am (10 hours in-game)
GetCurrentEQTimeOfDay(&tod); //TODO: what if it fails and returns zero?
if (tod.hour >= 19 || tod.hour < 5) {
return true;
}
return false;
}
bool EQTime::IsInbetweenTime(uint8 min_time, uint8 max_time) {
TimeOfDay_Struct tod{};
GetCurrentEQTimeOfDay(&tod);
if (min_time == 0 || max_time == 0 || min_time > 24 || max_time > 24) {
return true;
}
if (max_time < min_time) {
if ((tod.hour >= min_time && tod.hour > max_time) || (tod.hour < min_time && tod.hour <= max_time)) {
return true;
}
}
else {
if (tod.hour >= min_time && tod.hour <= max_time) {
return true;
}
}
return false;
}
+3
View File
@@ -28,6 +28,9 @@ public:
uint32 getEQTimeZone() { return timezone; }
uint32 getEQTimeZoneHr() { return timezone/60; }
uint32 getEQTimeZoneMin() { return timezone%60; }
bool IsDayTime();
bool IsNightTime();
bool IsInbetweenTime(uint8 min_time, uint8 max_time);
//Set functions
int SetCurrentEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real);
+9 -7
View File
@@ -37,6 +37,8 @@ void PlayerEventLogs::Init()
db.emplace_back(e.id);
}
std::vector<PlayerEventLogSettingsRepository::PlayerEventLogSettings> settings_to_insert{};
// insert entries that don't exist in database
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
bool is_in_database = std::find(db.begin(), db.end(), i) != db.end();
@@ -56,21 +58,21 @@ void PlayerEventLogs::Init()
bool is_missing_in_database = std::find(db.begin(), db.end(), i) == db.end();
if (is_missing_in_database && is_implemented && !is_deprecated) {
LogInfo(
"[New] PlayerEvent [{}] ({})",
PlayerEvent::EventName[i],
i
);
LogInfo("[New] PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
auto c = PlayerEventLogSettingsRepository::NewEntity();
c.id = i;
c.event_name = PlayerEvent::EventName[i];
c.event_enabled = m_settings[i].event_enabled;
c.retention_days = m_settings[i].retention_days;
PlayerEventLogSettingsRepository::InsertOne(*m_database, c);
settings_to_insert.emplace_back(c);
}
}
if (!settings_to_insert.empty()) {
PlayerEventLogSettingsRepository::ReplaceMany(*m_database, settings_to_insert);
}
bool processing_in_world = !RuleB(Logging, PlayerEventsQSProcess) && IsWorld();
bool processing_in_qs = RuleB(Logging, PlayerEventsQSProcess) && IsQueryServ();
@@ -611,7 +613,7 @@ void PlayerEventLogs::Process()
void PlayerEventLogs::ProcessRetentionTruncation()
{
LogInfo("Running truncation");
LogPlayerEvents("Running truncation");
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
if (m_settings[i].retention_days > 0) {
+2 -2
View File
@@ -96,12 +96,12 @@ bool IsOfEqualRace(int r1, int r2)
// TODO: add more values
switch (r1) {
case DARK_ELF:
if (r2 == RACE_NERIAK_CITIZEN_77) {
if (r2 == Race::NeriakCitizen) {
return true;
}
break;
case BARBARIAN:
if (r2 == RACE_HALAS_CITIZEN_90) {
if (r2 == Race::HalasCitizen) {
return true;
}
}
-19
View File
@@ -238,25 +238,6 @@ enum { //some random constants
// Timer to update aggrometer
#define AGGRO_METER_UPDATE_MS 1000
//Some hard coded statuses from commands and other places:
enum {
minStatusToBeGM = 40,
minStatusToUseGMCommands = 80,
minStatusToKick = 150,
minStatusToAvoidFalling = 100,
minStatusToIgnoreZoneFlags = 80,
minStatusToSeeOthersZoneFlags = 80,
minStatusToEditOtherGuilds = 80,
commandMovecharSelfOnly = 80, //below this == only self move allowed
commandMovecharToSpecials = 200, //ability to send people to cshom/load zones
commandCastSpecials = 100, //can cast special spells
commandDoAnimOthers = 100, //can #doanim on others
commandEditPlayerCorpses = 150, //can Edit Player Corpses
commandInterrogateInv = 100, //below this == only log on error state and self-only target dump
commandInvSnapshot = 150 //ability to clear/restore snapshots
};
// This is the item ID we use for say links, we use the max that fits in 5 ASCII chars
#define SAYLINK_ITEM_ID 0xFFFFF
+19 -18
View File
@@ -801,34 +801,35 @@ int16 EQ::InventoryProfile::HasItemByLoreGroup(uint32 loregroup, uint8 where)
// Returns slot_id when there's one available, else SLOT_INVALID
int16 EQ::InventoryProfile::FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size, bool is_arrow)
{
// Check basic inventory
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
continue;
const int16 last_bag_slot = RuleI(World, ExpansionSettings) & EQ::expansions::bitHoT ? EQ::invslot::slotGeneral10 : EQ::invslot::slotGeneral8;
if (!GetItem(i))
// Found available slot in personal inventory
return i;
for (int16 i = invslot::GENERAL_BEGIN; i <= last_bag_slot; i++) { // Check basic inventory
if ((((uint64) 1 << i) & m_lookup->PossessionsBitmask) == 0) {
continue;
}
if (!GetItem(i)) {
return i; // Found available slot in personal inventory
}
}
if (!for_bag) {
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
for (int16 i = invslot::GENERAL_BEGIN; i <= last_bag_slot; i++) {
if ((((uint64) 1 << i) & m_lookup->PossessionsBitmask) == 0) {
continue;
}
const ItemInstance* inst = GetItem(i);
if (inst && inst->IsClassBag() && inst->GetItem()->BagSize >= min_size)
{
if (inst->GetItem()->BagType == item::BagTypeQuiver && inst->GetItem()->ItemType != item::ItemTypeArrow)
{
const auto *inst = GetItem(i);
if (inst && inst->IsClassBag() && inst->GetItem()->BagSize >= min_size) {
if (inst->GetItem()->BagType == item::BagTypeQuiver &&
inst->GetItem()->ItemType != item::ItemTypeArrow) {
continue;
}
int16 base_slot_id = InventoryProfile::CalcSlotId(i, invbag::SLOT_BEGIN);
const int16 base_slot_id = InventoryProfile::CalcSlotId(i, invbag::SLOT_BEGIN);
uint8 slots = inst->GetItem()->BagSlots;
uint8 j;
for (j = invbag::SLOT_BEGIN; j<slots; j++) {
const uint8 slots = inst->GetItem()->BagSlots;
for (uint8 j = invbag::SLOT_BEGIN; j < slots; j++) {
if (!GetItem(base_slot_id + j)) {
// Found available slot within bag
return (base_slot_id + j);
+1 -1
View File
@@ -132,7 +132,7 @@ namespace EQ
// Swap items in inventory
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel };
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = 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, uint8 class_id = Class::None, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0);
// Remove item from inventory
bool DeleteItem(int16 slot_id, int16 quantity = 0);
+1
View File
@@ -356,6 +356,7 @@ namespace EQ
struct ItemData {
// Non packet based fields
uint8 MinStatus {};
char Comment[255] {};
// Packet based fields
uint8 ItemClass {}; // Item Type: 0=common, 1=container, 2=book
+1 -1
View File
@@ -1273,7 +1273,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bool augments) const
int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
{
int race = RACE_DOUG_0;
int race = Race::Doug;
const auto item = GetItem();
if (item) {
race = item->BaneDmgRace;
+4 -4
View File
@@ -3868,8 +3868,8 @@ namespace RoF
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
)
{
PacketSize += 60;
@@ -4002,8 +4002,8 @@ namespace RoF
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown18
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown19
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
+8 -8
View File
@@ -2706,7 +2706,7 @@ namespace RoF2
switch (raid_gen->action)
{
case raidAdd:
case raidAdd:
{
RaidAddMember_Struct* emu = (RaidAddMember_Struct*)__emu_buffer;
@@ -3986,7 +3986,7 @@ namespace RoF2
if (strlen(emu->suffix))
PacketSize += strlen(emu->suffix) + 1;
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE)
if (emu->DestructibleObject || emu->class_ == Class::LDoNTreasure)
{
if (emu->DestructibleObject)
PacketSize = PacketSize - 4; // No bodytype
@@ -4007,8 +4007,8 @@ namespace RoF2
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
)
{
PacketSize += 60;
@@ -4076,7 +4076,7 @@ namespace RoF2
// actually part of bitfields
uint8 OtherData = 0;
if (emu->class_ == LDON_TREASURE) //LDoN Chest
if (emu->class_ == Class::LDoNTreasure) //LDoN Chest
{
OtherData = OtherData | 0x04;
}
@@ -4104,7 +4104,7 @@ namespace RoF2
// int DefaultEmitterID
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->DestructibleName2);
@@ -4212,8 +4212,8 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // These do something with OP_WeaponEquip1
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // ^
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
+6 -6
View File
@@ -2507,8 +2507,8 @@ namespace SoD
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
)
{
PacketSize -= (sizeof(structs::Texture_Struct) * EQ::textures::materialCount);
@@ -2706,8 +2706,8 @@ namespace SoD
Buffer += sizeof(structs::Spawn_Struct_Position);
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
@@ -2733,8 +2733,8 @@ namespace SoD
}
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer;
+9 -9
View File
@@ -2758,7 +2758,7 @@ namespace UF
if (strlen(emu->suffix))
PacketSize += strlen(emu->suffix) + 1;
if (emu->DestructibleObject || emu->class_ == LDON_TREASURE)
if (emu->DestructibleObject || emu->class_ == Class::LDoNTreasure)
{
if (emu->DestructibleObject)
PacketSize = PacketSize - 4; // No bodytype
@@ -2779,8 +2779,8 @@ namespace UF
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
)
{
PacketSize -= (sizeof(structs::Texture_Struct) * EQ::textures::materialCount);
@@ -2847,7 +2847,7 @@ namespace UF
uint8 OtherData = 0;
if (emu->class_ == LDON_TREASURE) //Ldon chest
if (emu->class_ == Class::LDoNTreasure) //Ldon chest
{
OtherData = OtherData | 0x01;
}
@@ -2873,7 +2873,7 @@ namespace UF
}
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->DestructibleName2);
@@ -2982,8 +2982,8 @@ namespace UF
Buffer += sizeof(structs::Spawn_Struct_Position);
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
@@ -3018,8 +3018,8 @@ namespace UF
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
}
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer;
+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>
+755 -755
View File
File diff suppressed because it is too large Load Diff
+739 -1471
View File
File diff suppressed because it is too large Load Diff
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseBlockedSpellsRepository {
public:
struct BlockedSpells {
@@ -31,6 +32,10 @@ public:
float z_diff;
std::string message;
std::string description;
int8_t min_expansion;
int8_t max_expansion;
std::string content_flags;
std::string content_flags_disabled;
};
static std::string PrimaryKey()
@@ -53,6 +58,10 @@ public:
"z_diff",
"message",
"description",
"min_expansion",
"max_expansion",
"content_flags",
"content_flags_disabled",
};
}
@@ -71,6 +80,10 @@ public:
"z_diff",
"message",
"description",
"min_expansion",
"max_expansion",
"content_flags",
"content_flags_disabled",
};
}
@@ -111,18 +124,22 @@ public:
{
BlockedSpells e{};
e.id = 0;
e.spellid = 0;
e.type = 0;
e.zoneid = 0;
e.x = 0;
e.y = 0;
e.z = 0;
e.x_diff = 0;
e.y_diff = 0;
e.z_diff = 0;
e.message = "";
e.description = "";
e.id = 0;
e.spellid = 0;
e.type = 0;
e.zoneid = 0;
e.x = 0;
e.y = 0;
e.z = 0;
e.x_diff = 0;
e.y_diff = 0;
e.z_diff = 0;
e.message = "";
e.description = "";
e.min_expansion = -1;
e.max_expansion = -1;
e.content_flags = "";
e.content_flags_disabled = "";
return e;
}
@@ -148,8 +165,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
blocked_spells_id
)
);
@@ -158,18 +176,22 @@ public:
if (results.RowCount() == 1) {
BlockedSpells e{};
e.id = static_cast<int32_t>(atoi(row[0]));
e.spellid = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.type = static_cast<int8_t>(atoi(row[2]));
e.zoneid = static_cast<int32_t>(atoi(row[3]));
e.x = strtof(row[4], nullptr);
e.y = strtof(row[5], nullptr);
e.z = strtof(row[6], nullptr);
e.x_diff = strtof(row[7], nullptr);
e.y_diff = strtof(row[8], nullptr);
e.z_diff = strtof(row[9], nullptr);
e.message = row[10] ? row[10] : "";
e.description = row[11] ? row[11] : "";
e.id = static_cast<int32_t>(atoi(row[0]));
e.spellid = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.type = static_cast<int8_t>(atoi(row[2]));
e.zoneid = static_cast<int32_t>(atoi(row[3]));
e.x = strtof(row[4], nullptr);
e.y = strtof(row[5], nullptr);
e.z = strtof(row[6], nullptr);
e.x_diff = strtof(row[7], nullptr);
e.y_diff = strtof(row[8], nullptr);
e.z_diff = strtof(row[9], nullptr);
e.message = row[10] ? row[10] : "";
e.description = row[11] ? row[11] : "";
e.min_expansion = static_cast<int8_t>(atoi(row[12]));
e.max_expansion = static_cast<int8_t>(atoi(row[13]));
e.content_flags = row[14] ? row[14] : "";
e.content_flags_disabled = row[15] ? row[15] : "";
return e;
}
@@ -214,6 +236,10 @@ public:
v.push_back(columns[9] + " = " + std::to_string(e.z_diff));
v.push_back(columns[10] + " = '" + Strings::Escape(e.message) + "'");
v.push_back(columns[11] + " = '" + Strings::Escape(e.description) + "'");
v.push_back(columns[12] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[13] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[14] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[15] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -247,6 +273,10 @@ public:
v.push_back(std::to_string(e.z_diff));
v.push_back("'" + Strings::Escape(e.message) + "'");
v.push_back("'" + Strings::Escape(e.description) + "'");
v.push_back(std::to_string(e.min_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_disabled) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -288,6 +318,10 @@ public:
v.push_back(std::to_string(e.z_diff));
v.push_back("'" + Strings::Escape(e.message) + "'");
v.push_back("'" + Strings::Escape(e.description) + "'");
v.push_back(std::to_string(e.min_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_disabled) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -321,18 +355,22 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
BlockedSpells e{};
e.id = static_cast<int32_t>(atoi(row[0]));
e.spellid = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.type = static_cast<int8_t>(atoi(row[2]));
e.zoneid = static_cast<int32_t>(atoi(row[3]));
e.x = strtof(row[4], nullptr);
e.y = strtof(row[5], nullptr);
e.z = strtof(row[6], nullptr);
e.x_diff = strtof(row[7], nullptr);
e.y_diff = strtof(row[8], nullptr);
e.z_diff = strtof(row[9], nullptr);
e.message = row[10] ? row[10] : "";
e.description = row[11] ? row[11] : "";
e.id = static_cast<int32_t>(atoi(row[0]));
e.spellid = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.type = static_cast<int8_t>(atoi(row[2]));
e.zoneid = static_cast<int32_t>(atoi(row[3]));
e.x = strtof(row[4], nullptr);
e.y = strtof(row[5], nullptr);
e.z = strtof(row[6], nullptr);
e.x_diff = strtof(row[7], nullptr);
e.y_diff = strtof(row[8], nullptr);
e.z_diff = strtof(row[9], nullptr);
e.message = row[10] ? row[10] : "";
e.description = row[11] ? row[11] : "";
e.min_expansion = static_cast<int8_t>(atoi(row[12]));
e.max_expansion = static_cast<int8_t>(atoi(row[13]));
e.content_flags = row[14] ? row[14] : "";
e.content_flags_disabled = row[15] ? row[15] : "";
all_entries.push_back(e);
}
@@ -357,18 +395,22 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
BlockedSpells e{};
e.id = static_cast<int32_t>(atoi(row[0]));
e.spellid = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.type = static_cast<int8_t>(atoi(row[2]));
e.zoneid = static_cast<int32_t>(atoi(row[3]));
e.x = strtof(row[4], nullptr);
e.y = strtof(row[5], nullptr);
e.z = strtof(row[6], nullptr);
e.x_diff = strtof(row[7], nullptr);
e.y_diff = strtof(row[8], nullptr);
e.z_diff = strtof(row[9], nullptr);
e.message = row[10] ? row[10] : "";
e.description = row[11] ? row[11] : "";
e.id = static_cast<int32_t>(atoi(row[0]));
e.spellid = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.type = static_cast<int8_t>(atoi(row[2]));
e.zoneid = static_cast<int32_t>(atoi(row[3]));
e.x = strtof(row[4], nullptr);
e.y = strtof(row[5], nullptr);
e.z = strtof(row[6], nullptr);
e.x_diff = strtof(row[7], nullptr);
e.y_diff = strtof(row[8], nullptr);
e.z_diff = strtof(row[9], nullptr);
e.message = row[10] ? row[10] : "";
e.description = row[11] ? row[11] : "";
e.min_expansion = static_cast<int8_t>(atoi(row[12]));
e.max_expansion = static_cast<int8_t>(atoi(row[13]));
e.content_flags = row[14] ? row[14] : "";
e.content_flags_disabled = row[15] ? row[15] : "";
all_entries.push_back(e);
}
@@ -16,12 +16,19 @@
#include "../../strings.h"
#include <ctime>
class BaseBotTimersRepository {
public:
struct BotTimers {
uint32_t bot_id;
uint32_t timer_id;
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()
@@ -35,6 +42,12 @@ public:
"bot_id",
"timer_id",
"timer_value",
"recast_time",
"is_spell",
"is_disc",
"spell_id",
"is_item",
"item_id",
};
}
@@ -44,6 +57,12 @@ public:
"bot_id",
"timer_id",
"timer_value",
"recast_time",
"is_spell",
"is_disc",
"spell_id",
"is_item",
"item_id",
};
}
@@ -87,6 +106,12 @@ public:
e.bot_id = 0;
e.timer_id = 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;
}
@@ -112,8 +137,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
bot_timers_id
)
);
@@ -125,6 +151,12 @@ public:
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_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;
}
@@ -161,6 +193,12 @@ public:
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[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(
fmt::format(
@@ -185,6 +223,12 @@ public:
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_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(
fmt::format(
@@ -217,6 +261,12 @@ public:
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_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) + ")");
}
@@ -253,6 +303,12 @@ public:
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_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);
}
@@ -280,6 +336,12 @@ public:
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_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);
}
@@ -75,7 +75,7 @@ public:
int32_t damageshield;
int32_t deity;
int32_t delay;
int32_t augdistiller;
uint32_t augdistiller;
int32_t dotshielding;
int32_t dr;
int32_t clicktype;
@@ -227,7 +227,7 @@ public:
int32_t focusunk5;
std::string focusunk6;
int32_t focusunk7;
int32_t scrollunk1;
uint32_t scrollunk1;
int32_t scrollunk2;
int32_t scrollunk3;
int32_t scrollunk4;
@@ -266,10 +266,10 @@ public:
std::string created;
int16_t elitematerial;
int16_t ldonsellbackrate;
int16_t scriptfileid;
int32_t scriptfileid;
int16_t expendablearrow;
int16_t powersourcecapacity;
int16_t bardeffect;
int32_t powersourcecapacity;
int32_t bardeffect;
int16_t bardeffecttype;
int16_t bardlevel2;
int16_t bardlevel;
@@ -1307,7 +1307,7 @@ public:
e.damageshield = static_cast<int32_t>(atoi(row[52]));
e.deity = static_cast<int32_t>(atoi(row[53]));
e.delay = static_cast<int32_t>(atoi(row[54]));
e.augdistiller = static_cast<int32_t>(atoi(row[55]));
e.augdistiller = static_cast<uint32_t>(strtoul(row[55], nullptr, 10));
e.dotshielding = static_cast<int32_t>(atoi(row[56]));
e.dr = static_cast<int32_t>(atoi(row[57]));
e.clicktype = static_cast<int32_t>(atoi(row[58]));
@@ -1459,7 +1459,7 @@ public:
e.focusunk5 = static_cast<int32_t>(atoi(row[204]));
e.focusunk6 = row[205] ? row[205] : "";
e.focusunk7 = static_cast<int32_t>(atoi(row[206]));
e.scrollunk1 = static_cast<int32_t>(atoi(row[207]));
e.scrollunk1 = static_cast<uint32_t>(strtoul(row[207], nullptr, 10));
e.scrollunk2 = static_cast<int32_t>(atoi(row[208]));
e.scrollunk3 = static_cast<int32_t>(atoi(row[209]));
e.scrollunk4 = static_cast<int32_t>(atoi(row[210]));
@@ -1498,10 +1498,10 @@ public:
e.created = row[243] ? row[243] : "";
e.elitematerial = static_cast<int16_t>(atoi(row[244]));
e.ldonsellbackrate = static_cast<int16_t>(atoi(row[245]));
e.scriptfileid = static_cast<int16_t>(atoi(row[246]));
e.scriptfileid = static_cast<int32_t>(atoi(row[246]));
e.expendablearrow = static_cast<int16_t>(atoi(row[247]));
e.powersourcecapacity = static_cast<int16_t>(atoi(row[248]));
e.bardeffect = static_cast<int16_t>(atoi(row[249]));
e.powersourcecapacity = static_cast<int32_t>(atoi(row[248]));
e.bardeffect = static_cast<int32_t>(atoi(row[249]));
e.bardeffecttype = static_cast<int16_t>(atoi(row[250]));
e.bardlevel2 = static_cast<int16_t>(atoi(row[251]));
e.bardlevel = static_cast<int16_t>(atoi(row[252]));
@@ -2563,7 +2563,7 @@ public:
e.damageshield = static_cast<int32_t>(atoi(row[52]));
e.deity = static_cast<int32_t>(atoi(row[53]));
e.delay = static_cast<int32_t>(atoi(row[54]));
e.augdistiller = static_cast<int32_t>(atoi(row[55]));
e.augdistiller = static_cast<uint32_t>(strtoul(row[55], nullptr, 10));
e.dotshielding = static_cast<int32_t>(atoi(row[56]));
e.dr = static_cast<int32_t>(atoi(row[57]));
e.clicktype = static_cast<int32_t>(atoi(row[58]));
@@ -2715,7 +2715,7 @@ public:
e.focusunk5 = static_cast<int32_t>(atoi(row[204]));
e.focusunk6 = row[205] ? row[205] : "";
e.focusunk7 = static_cast<int32_t>(atoi(row[206]));
e.scrollunk1 = static_cast<int32_t>(atoi(row[207]));
e.scrollunk1 = static_cast<uint32_t>(strtoul(row[207], nullptr, 10));
e.scrollunk2 = static_cast<int32_t>(atoi(row[208]));
e.scrollunk3 = static_cast<int32_t>(atoi(row[209]));
e.scrollunk4 = static_cast<int32_t>(atoi(row[210]));
@@ -2754,10 +2754,10 @@ public:
e.created = row[243] ? row[243] : "";
e.elitematerial = static_cast<int16_t>(atoi(row[244]));
e.ldonsellbackrate = static_cast<int16_t>(atoi(row[245]));
e.scriptfileid = static_cast<int16_t>(atoi(row[246]));
e.scriptfileid = static_cast<int32_t>(atoi(row[246]));
e.expendablearrow = static_cast<int16_t>(atoi(row[247]));
e.powersourcecapacity = static_cast<int16_t>(atoi(row[248]));
e.bardeffect = static_cast<int16_t>(atoi(row[249]));
e.powersourcecapacity = static_cast<int32_t>(atoi(row[248]));
e.bardeffect = static_cast<int32_t>(atoi(row[249]));
e.bardeffecttype = static_cast<int16_t>(atoi(row[250]));
e.bardlevel2 = static_cast<int16_t>(atoi(row[251]));
e.bardlevel = static_cast<int16_t>(atoi(row[252]));
@@ -2872,7 +2872,7 @@ public:
e.damageshield = static_cast<int32_t>(atoi(row[52]));
e.deity = static_cast<int32_t>(atoi(row[53]));
e.delay = static_cast<int32_t>(atoi(row[54]));
e.augdistiller = static_cast<int32_t>(atoi(row[55]));
e.augdistiller = static_cast<uint32_t>(strtoul(row[55], nullptr, 10));
e.dotshielding = static_cast<int32_t>(atoi(row[56]));
e.dr = static_cast<int32_t>(atoi(row[57]));
e.clicktype = static_cast<int32_t>(atoi(row[58]));
@@ -3024,7 +3024,7 @@ public:
e.focusunk5 = static_cast<int32_t>(atoi(row[204]));
e.focusunk6 = row[205] ? row[205] : "";
e.focusunk7 = static_cast<int32_t>(atoi(row[206]));
e.scrollunk1 = static_cast<int32_t>(atoi(row[207]));
e.scrollunk1 = static_cast<uint32_t>(strtoul(row[207], nullptr, 10));
e.scrollunk2 = static_cast<int32_t>(atoi(row[208]));
e.scrollunk3 = static_cast<int32_t>(atoi(row[209]));
e.scrollunk4 = static_cast<int32_t>(atoi(row[210]));
@@ -3063,10 +3063,10 @@ public:
e.created = row[243] ? row[243] : "";
e.elitematerial = static_cast<int16_t>(atoi(row[244]));
e.ldonsellbackrate = static_cast<int16_t>(atoi(row[245]));
e.scriptfileid = static_cast<int16_t>(atoi(row[246]));
e.scriptfileid = static_cast<int32_t>(atoi(row[246]));
e.expendablearrow = static_cast<int16_t>(atoi(row[247]));
e.powersourcecapacity = static_cast<int16_t>(atoi(row[248]));
e.bardeffect = static_cast<int16_t>(atoi(row[249]));
e.powersourcecapacity = static_cast<int32_t>(atoi(row[248]));
e.bardeffect = static_cast<int32_t>(atoi(row[249]));
e.bardeffecttype = static_cast<int16_t>(atoi(row[250]));
e.bardlevel2 = static_cast<int16_t>(atoi(row[251]));
e.bardlevel = static_cast<int16_t>(atoi(row[252]));
@@ -0,0 +1,344 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_KEYRING_REPOSITORY_H
#define EQEMU_BASE_KEYRING_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseKeyringRepository {
public:
struct Keyring {
uint32_t id;
int32_t char_id;
int32_t item_id;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"char_id",
"item_id",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"char_id",
"item_id",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("keyring");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static Keyring NewEntity()
{
Keyring e{};
e.id = 0;
e.char_id = 0;
e.item_id = 0;
return e;
}
static Keyring GetKeyring(
const std::vector<Keyring> &keyrings,
int keyring_id
)
{
for (auto &keyring : keyrings) {
if (keyring.id == keyring_id) {
return keyring;
}
}
return NewEntity();
}
static Keyring FindOne(
Database& db,
int keyring_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
keyring_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
Keyring e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.char_id = static_cast<int32_t>(atoi(row[1]));
e.item_id = static_cast<int32_t>(atoi(row[2]));
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int keyring_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
keyring_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const Keyring &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.char_id));
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static Keyring InsertOne(
Database& db,
Keyring e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.item_id));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<Keyring> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.item_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<Keyring> All(Database& db)
{
std::vector<Keyring> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Keyring e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.char_id = static_cast<int32_t>(atoi(row[1]));
e.item_id = static_cast<int32_t>(atoi(row[2]));
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<Keyring> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<Keyring> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Keyring e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.char_id = static_cast<int32_t>(atoi(row[1]));
e.item_id = static_cast<int32_t>(atoi(row[2]));
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
};
#endif //EQEMU_BASE_KEYRING_REPOSITORY_H
@@ -6,7 +6,7 @@
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_LOGSYS_CATEGORIES_REPOSITORY_H
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseLogsysCategoriesRepository {
public:
struct LogsysCategories {
@@ -128,8 +129,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
logsys_categories_id
)
);
@@ -378,6 +380,74 @@ public:
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const LogsysCategories &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.log_category_id));
v.push_back("'" + Strings::Escape(e.log_category_description) + "'");
v.push_back(std::to_string(e.log_to_console));
v.push_back(std::to_string(e.log_to_file));
v.push_back(std::to_string(e.log_to_gmsay));
v.push_back(std::to_string(e.log_to_discord));
v.push_back(std::to_string(e.discord_webhook_id));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<LogsysCategories> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.log_category_id));
v.push_back("'" + Strings::Escape(e.log_category_description) + "'");
v.push_back(std::to_string(e.log_to_console));
v.push_back(std::to_string(e.log_to_file));
v.push_back(std::to_string(e.log_to_gmsay));
v.push_back(std::to_string(e.log_to_discord));
v.push_back(std::to_string(e.discord_webhook_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_LOGSYS_CATEGORIES_REPOSITORY_H
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseNpcEmotesRepository {
public:
struct NpcEmotes {
@@ -120,8 +121,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
npc_emotes_id
)
);
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseObjectRepository {
public:
struct Object {
@@ -31,9 +32,9 @@ public:
std::string objectname;
int32_t type;
int32_t icon;
int32_t unknown08;
int32_t unknown10;
int32_t unknown20;
float size_percentage;
int32_t solid_type;
int32_t incline;
int32_t unknown24;
int32_t unknown60;
int32_t unknown64;
@@ -71,9 +72,9 @@ public:
"objectname",
"type",
"icon",
"unknown08",
"unknown10",
"unknown20",
"size_percentage",
"solid_type",
"incline",
"unknown24",
"unknown60",
"unknown64",
@@ -107,9 +108,9 @@ public:
"objectname",
"type",
"icon",
"unknown08",
"unknown10",
"unknown20",
"size_percentage",
"solid_type",
"incline",
"unknown24",
"unknown60",
"unknown64",
@@ -177,9 +178,9 @@ public:
e.objectname = "";
e.type = 0;
e.icon = 0;
e.unknown08 = 0;
e.unknown10 = 0;
e.unknown20 = 0;
e.size_percentage = 0;
e.solid_type = 0;
e.incline = 0;
e.unknown24 = 0;
e.unknown60 = 0;
e.unknown64 = 0;
@@ -220,8 +221,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
object_id
)
);
@@ -242,9 +244,9 @@ public:
e.objectname = row[9] ? row[9] : "";
e.type = static_cast<int32_t>(atoi(row[10]));
e.icon = static_cast<int32_t>(atoi(row[11]));
e.unknown08 = static_cast<int32_t>(atoi(row[12]));
e.unknown10 = static_cast<int32_t>(atoi(row[13]));
e.unknown20 = static_cast<int32_t>(atoi(row[14]));
e.size_percentage = strtof(row[12], nullptr);
e.solid_type = static_cast<int32_t>(atoi(row[13]));
e.incline = static_cast<int32_t>(atoi(row[14]));
e.unknown24 = static_cast<int32_t>(atoi(row[15]));
e.unknown60 = static_cast<int32_t>(atoi(row[16]));
e.unknown64 = static_cast<int32_t>(atoi(row[17]));
@@ -304,9 +306,9 @@ public:
v.push_back(columns[9] + " = '" + Strings::Escape(e.objectname) + "'");
v.push_back(columns[10] + " = " + std::to_string(e.type));
v.push_back(columns[11] + " = " + std::to_string(e.icon));
v.push_back(columns[12] + " = " + std::to_string(e.unknown08));
v.push_back(columns[13] + " = " + std::to_string(e.unknown10));
v.push_back(columns[14] + " = " + std::to_string(e.unknown20));
v.push_back(columns[12] + " = " + std::to_string(e.size_percentage));
v.push_back(columns[13] + " = " + std::to_string(e.solid_type));
v.push_back(columns[14] + " = " + std::to_string(e.incline));
v.push_back(columns[15] + " = " + std::to_string(e.unknown24));
v.push_back(columns[16] + " = " + std::to_string(e.unknown60));
v.push_back(columns[17] + " = " + std::to_string(e.unknown64));
@@ -355,9 +357,9 @@ public:
v.push_back("'" + Strings::Escape(e.objectname) + "'");
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.icon));
v.push_back(std::to_string(e.unknown08));
v.push_back(std::to_string(e.unknown10));
v.push_back(std::to_string(e.unknown20));
v.push_back(std::to_string(e.size_percentage));
v.push_back(std::to_string(e.solid_type));
v.push_back(std::to_string(e.incline));
v.push_back(std::to_string(e.unknown24));
v.push_back(std::to_string(e.unknown60));
v.push_back(std::to_string(e.unknown64));
@@ -414,9 +416,9 @@ public:
v.push_back("'" + Strings::Escape(e.objectname) + "'");
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.icon));
v.push_back(std::to_string(e.unknown08));
v.push_back(std::to_string(e.unknown10));
v.push_back(std::to_string(e.unknown20));
v.push_back(std::to_string(e.size_percentage));
v.push_back(std::to_string(e.solid_type));
v.push_back(std::to_string(e.incline));
v.push_back(std::to_string(e.unknown24));
v.push_back(std::to_string(e.unknown60));
v.push_back(std::to_string(e.unknown64));
@@ -477,9 +479,9 @@ public:
e.objectname = row[9] ? row[9] : "";
e.type = static_cast<int32_t>(atoi(row[10]));
e.icon = static_cast<int32_t>(atoi(row[11]));
e.unknown08 = static_cast<int32_t>(atoi(row[12]));
e.unknown10 = static_cast<int32_t>(atoi(row[13]));
e.unknown20 = static_cast<int32_t>(atoi(row[14]));
e.size_percentage = strtof(row[12], nullptr);
e.solid_type = static_cast<int32_t>(atoi(row[13]));
e.incline = static_cast<int32_t>(atoi(row[14]));
e.unknown24 = static_cast<int32_t>(atoi(row[15]));
e.unknown60 = static_cast<int32_t>(atoi(row[16]));
e.unknown64 = static_cast<int32_t>(atoi(row[17]));
@@ -531,9 +533,9 @@ public:
e.objectname = row[9] ? row[9] : "";
e.type = static_cast<int32_t>(atoi(row[10]));
e.icon = static_cast<int32_t>(atoi(row[11]));
e.unknown08 = static_cast<int32_t>(atoi(row[12]));
e.unknown10 = static_cast<int32_t>(atoi(row[13]));
e.unknown20 = static_cast<int32_t>(atoi(row[14]));
e.size_percentage = strtof(row[12], nullptr);
e.solid_type = static_cast<int32_t>(atoi(row[13]));
e.incline = static_cast<int32_t>(atoi(row[14]));
e.unknown24 = static_cast<int32_t>(atoi(row[15]));
e.unknown60 = static_cast<int32_t>(atoi(row[16]));
e.unknown64 = static_cast<int32_t>(atoi(row[17]));
@@ -6,7 +6,7 @@
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BasePlayerEventLogSettingsRepository {
public:
struct PlayerEventLogSettings {
@@ -359,6 +360,70 @@ public:
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventLogSettings &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back(std::to_string(e.event_enabled));
v.push_back(std::to_string(e.retention_days));
v.push_back(std::to_string(e.discord_webhook_id));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventLogSettings> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back(std::to_string(e.event_enabled));
v.push_back(std::to_string(e.retention_days));
v.push_back(std::to_string(e.discord_webhook_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
@@ -6,7 +6,7 @@
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
@@ -240,8 +240,8 @@ public:
v.push_back(columns[7] + " = " + std::to_string(e.z));
v.push_back(columns[8] + " = " + std::to_string(e.heading));
v.push_back(columns[9] + " = " + std::to_string(e.event_type_id));
v.push_back(columns[10] + " = '" + db.Escape(e.event_type_name) + "'");
v.push_back(columns[11] + " = '" + db.Escape(e.event_data) + "'");
v.push_back(columns[10] + " = '" + Strings::Escape(e.event_type_name) + "'");
v.push_back(columns[11] + " = '" + Strings::Escape(e.event_data) + "'");
v.push_back(columns[12] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
@@ -274,8 +274,8 @@ public:
v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + db.Escape(e.event_type_name) + "'");
v.push_back("'" + db.Escape(e.event_data) + "'");
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
@@ -316,8 +316,8 @@ public:
v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + db.Escape(e.event_type_name) + "'");
v.push_back("'" + db.Escape(e.event_data) + "'");
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
@@ -460,6 +460,86 @@ public:
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventLogs &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.zone_id));
v.push_back(std::to_string(e.instance_id));
v.push_back(std::to_string(e.x));
v.push_back(std::to_string(e.y));
v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventLogs> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.zone_id));
v.push_back(std::to_string(e.instance_id));
v.push_back(std::to_string(e.x));
v.push_back(std::to_string(e.y));
v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
@@ -0,0 +1,354 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_SPAWN2_DISABLED_REPOSITORY_H
#define EQEMU_BASE_SPAWN2_DISABLED_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseSpawn2DisabledRepository {
public:
struct Spawn2Disabled {
int64_t id;
int32_t spawn2_id;
int32_t instance_id;
int16_t disabled;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"spawn2_id",
"instance_id",
"disabled",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"spawn2_id",
"instance_id",
"disabled",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("spawn2_disabled");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static Spawn2Disabled NewEntity()
{
Spawn2Disabled e{};
e.id = 0;
e.spawn2_id = 0;
e.instance_id = 0;
e.disabled = 0;
return e;
}
static Spawn2Disabled GetSpawn2Disabled(
const std::vector<Spawn2Disabled> &spawn2_disableds,
int spawn2_disabled_id
)
{
for (auto &spawn2_disabled : spawn2_disableds) {
if (spawn2_disabled.id == spawn2_disabled_id) {
return spawn2_disabled;
}
}
return NewEntity();
}
static Spawn2Disabled FindOne(
Database& db,
int spawn2_disabled_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
spawn2_disabled_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
Spawn2Disabled e{};
e.id = strtoll(row[0], nullptr, 10);
e.spawn2_id = static_cast<int32_t>(atoi(row[1]));
e.instance_id = static_cast<int32_t>(atoi(row[2]));
e.disabled = static_cast<int16_t>(atoi(row[3]));
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int spawn2_disabled_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
spawn2_disabled_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const Spawn2Disabled &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.spawn2_id));
v.push_back(columns[2] + " = " + std::to_string(e.instance_id));
v.push_back(columns[3] + " = " + std::to_string(e.disabled));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static Spawn2Disabled InsertOne(
Database& db,
Spawn2Disabled e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.spawn2_id));
v.push_back(std::to_string(e.instance_id));
v.push_back(std::to_string(e.disabled));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<Spawn2Disabled> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.spawn2_id));
v.push_back(std::to_string(e.instance_id));
v.push_back(std::to_string(e.disabled));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<Spawn2Disabled> All(Database& db)
{
std::vector<Spawn2Disabled> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Spawn2Disabled e{};
e.id = strtoll(row[0], nullptr, 10);
e.spawn2_id = static_cast<int32_t>(atoi(row[1]));
e.instance_id = static_cast<int32_t>(atoi(row[2]));
e.disabled = static_cast<int16_t>(atoi(row[3]));
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<Spawn2Disabled> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<Spawn2Disabled> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Spawn2Disabled e{};
e.id = strtoll(row[0], nullptr, 10);
e.spawn2_id = static_cast<int32_t>(atoi(row[1]));
e.instance_id = static_cast<int32_t>(atoi(row[2]));
e.disabled = static_cast<int16_t>(atoi(row[3]));
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
};
#endif //EQEMU_BASE_SPAWN2_DISABLED_REPOSITORY_H
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseSpawn2Repository {
public:
struct Spawn2 {
@@ -33,7 +34,6 @@ public:
int8_t path_when_zone_idle;
uint32_t _condition;
int32_t cond_value;
uint8_t enabled;
uint8_t animation;
int8_t min_expansion;
int8_t max_expansion;
@@ -63,7 +63,6 @@ public:
"path_when_zone_idle",
"_condition",
"cond_value",
"enabled",
"animation",
"min_expansion",
"max_expansion",
@@ -89,7 +88,6 @@ public:
"path_when_zone_idle",
"_condition",
"cond_value",
"enabled",
"animation",
"min_expansion",
"max_expansion",
@@ -149,7 +147,6 @@ public:
e.path_when_zone_idle = 0;
e._condition = 0;
e.cond_value = 1;
e.enabled = 1;
e.animation = 0;
e.min_expansion = -1;
e.max_expansion = -1;
@@ -180,8 +177,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
spawn2_id
)
);
@@ -204,12 +202,11 @@ public:
e.path_when_zone_idle = static_cast<int8_t>(atoi(row[11]));
e._condition = static_cast<uint32_t>(strtoul(row[12], nullptr, 10));
e.cond_value = static_cast<int32_t>(atoi(row[13]));
e.enabled = static_cast<uint8_t>(strtoul(row[14], nullptr, 10));
e.animation = static_cast<uint8_t>(strtoul(row[15], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[16]));
e.max_expansion = static_cast<int8_t>(atoi(row[17]));
e.content_flags = row[18] ? row[18] : "";
e.content_flags_disabled = row[19] ? row[19] : "";
e.animation = static_cast<uint8_t>(strtoul(row[14], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[15]));
e.max_expansion = static_cast<int8_t>(atoi(row[16]));
e.content_flags = row[17] ? row[17] : "";
e.content_flags_disabled = row[18] ? row[18] : "";
return e;
}
@@ -256,12 +253,11 @@ public:
v.push_back(columns[11] + " = " + std::to_string(e.path_when_zone_idle));
v.push_back(columns[12] + " = " + std::to_string(e._condition));
v.push_back(columns[13] + " = " + std::to_string(e.cond_value));
v.push_back(columns[14] + " = " + std::to_string(e.enabled));
v.push_back(columns[15] + " = " + std::to_string(e.animation));
v.push_back(columns[16] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[17] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[18] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[19] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
v.push_back(columns[14] + " = " + std::to_string(e.animation));
v.push_back(columns[15] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[16] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[17] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[18] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -297,7 +293,6 @@ public:
v.push_back(std::to_string(e.path_when_zone_idle));
v.push_back(std::to_string(e._condition));
v.push_back(std::to_string(e.cond_value));
v.push_back(std::to_string(e.enabled));
v.push_back(std::to_string(e.animation));
v.push_back(std::to_string(e.min_expansion));
v.push_back(std::to_string(e.max_expansion));
@@ -346,7 +341,6 @@ public:
v.push_back(std::to_string(e.path_when_zone_idle));
v.push_back(std::to_string(e._condition));
v.push_back(std::to_string(e.cond_value));
v.push_back(std::to_string(e.enabled));
v.push_back(std::to_string(e.animation));
v.push_back(std::to_string(e.min_expansion));
v.push_back(std::to_string(e.max_expansion));
@@ -399,12 +393,11 @@ public:
e.path_when_zone_idle = static_cast<int8_t>(atoi(row[11]));
e._condition = static_cast<uint32_t>(strtoul(row[12], nullptr, 10));
e.cond_value = static_cast<int32_t>(atoi(row[13]));
e.enabled = static_cast<uint8_t>(strtoul(row[14], nullptr, 10));
e.animation = static_cast<uint8_t>(strtoul(row[15], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[16]));
e.max_expansion = static_cast<int8_t>(atoi(row[17]));
e.content_flags = row[18] ? row[18] : "";
e.content_flags_disabled = row[19] ? row[19] : "";
e.animation = static_cast<uint8_t>(strtoul(row[14], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[15]));
e.max_expansion = static_cast<int8_t>(atoi(row[16]));
e.content_flags = row[17] ? row[17] : "";
e.content_flags_disabled = row[18] ? row[18] : "";
all_entries.push_back(e);
}
@@ -443,12 +436,11 @@ public:
e.path_when_zone_idle = static_cast<int8_t>(atoi(row[11]));
e._condition = static_cast<uint32_t>(strtoul(row[12], nullptr, 10));
e.cond_value = static_cast<int32_t>(atoi(row[13]));
e.enabled = static_cast<uint8_t>(strtoul(row[14], nullptr, 10));
e.animation = static_cast<uint8_t>(strtoul(row[15], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[16]));
e.max_expansion = static_cast<int8_t>(atoi(row[17]));
e.content_flags = row[18] ? row[18] : "";
e.content_flags_disabled = row[19] ? row[19] : "";
e.animation = static_cast<uint8_t>(strtoul(row[14], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[15]));
e.max_expansion = static_cast<int8_t>(atoi(row[16]));
e.content_flags = row[17] ? row[17] : "";
e.content_flags_disabled = row[18] ? row[18] : "";
all_entries.push_back(e);
}
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseSpawnentryRepository {
public:
struct Spawnentry {
@@ -23,6 +24,8 @@ public:
int32_t npcID;
int16_t chance;
int32_t condition_value_filter;
int16_t min_time;
int16_t max_time;
int8_t min_expansion;
int8_t max_expansion;
std::string content_flags;
@@ -41,6 +44,8 @@ public:
"npcID",
"chance",
"condition_value_filter",
"min_time",
"max_time",
"min_expansion",
"max_expansion",
"content_flags",
@@ -55,6 +60,8 @@ public:
"npcID",
"chance",
"condition_value_filter",
"min_time",
"max_time",
"min_expansion",
"max_expansion",
"content_flags",
@@ -103,6 +110,8 @@ public:
e.npcID = 0;
e.chance = 0;
e.condition_value_filter = 1;
e.min_time = 0;
e.max_time = 0;
e.min_expansion = -1;
e.max_expansion = -1;
e.content_flags = "";
@@ -132,8 +141,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
spawnentry_id
)
);
@@ -146,10 +156,12 @@ public:
e.npcID = static_cast<int32_t>(atoi(row[1]));
e.chance = static_cast<int16_t>(atoi(row[2]));
e.condition_value_filter = static_cast<int32_t>(atoi(row[3]));
e.min_expansion = static_cast<int8_t>(atoi(row[4]));
e.max_expansion = static_cast<int8_t>(atoi(row[5]));
e.content_flags = row[6] ? row[6] : "";
e.content_flags_disabled = row[7] ? row[7] : "";
e.min_time = static_cast<int16_t>(atoi(row[4]));
e.max_time = static_cast<int16_t>(atoi(row[5]));
e.min_expansion = static_cast<int8_t>(atoi(row[6]));
e.max_expansion = static_cast<int8_t>(atoi(row[7]));
e.content_flags = row[8] ? row[8] : "";
e.content_flags_disabled = row[9] ? row[9] : "";
return e;
}
@@ -187,10 +199,12 @@ public:
v.push_back(columns[1] + " = " + std::to_string(e.npcID));
v.push_back(columns[2] + " = " + std::to_string(e.chance));
v.push_back(columns[3] + " = " + std::to_string(e.condition_value_filter));
v.push_back(columns[4] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[5] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[6] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[7] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
v.push_back(columns[4] + " = " + std::to_string(e.min_time));
v.push_back(columns[5] + " = " + std::to_string(e.max_time));
v.push_back(columns[6] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[7] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[8] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[9] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -216,6 +230,8 @@ public:
v.push_back(std::to_string(e.npcID));
v.push_back(std::to_string(e.chance));
v.push_back(std::to_string(e.condition_value_filter));
v.push_back(std::to_string(e.min_time));
v.push_back(std::to_string(e.max_time));
v.push_back(std::to_string(e.min_expansion));
v.push_back(std::to_string(e.max_expansion));
v.push_back("'" + Strings::Escape(e.content_flags) + "'");
@@ -253,6 +269,8 @@ public:
v.push_back(std::to_string(e.npcID));
v.push_back(std::to_string(e.chance));
v.push_back(std::to_string(e.condition_value_filter));
v.push_back(std::to_string(e.min_time));
v.push_back(std::to_string(e.max_time));
v.push_back(std::to_string(e.min_expansion));
v.push_back(std::to_string(e.max_expansion));
v.push_back("'" + Strings::Escape(e.content_flags) + "'");
@@ -294,10 +312,12 @@ public:
e.npcID = static_cast<int32_t>(atoi(row[1]));
e.chance = static_cast<int16_t>(atoi(row[2]));
e.condition_value_filter = static_cast<int32_t>(atoi(row[3]));
e.min_expansion = static_cast<int8_t>(atoi(row[4]));
e.max_expansion = static_cast<int8_t>(atoi(row[5]));
e.content_flags = row[6] ? row[6] : "";
e.content_flags_disabled = row[7] ? row[7] : "";
e.min_time = static_cast<int16_t>(atoi(row[4]));
e.max_time = static_cast<int16_t>(atoi(row[5]));
e.min_expansion = static_cast<int8_t>(atoi(row[6]));
e.max_expansion = static_cast<int8_t>(atoi(row[7]));
e.content_flags = row[8] ? row[8] : "";
e.content_flags_disabled = row[9] ? row[9] : "";
all_entries.push_back(e);
}
@@ -326,10 +346,12 @@ public:
e.npcID = static_cast<int32_t>(atoi(row[1]));
e.chance = static_cast<int16_t>(atoi(row[2]));
e.condition_value_filter = static_cast<int32_t>(atoi(row[3]));
e.min_expansion = static_cast<int8_t>(atoi(row[4]));
e.max_expansion = static_cast<int8_t>(atoi(row[5]));
e.content_flags = row[6] ? row[6] : "";
e.content_flags_disabled = row[7] ? row[7] : "";
e.min_time = static_cast<int16_t>(atoi(row[4]));
e.max_time = static_cast<int16_t>(atoi(row[5]));
e.min_expansion = static_cast<int8_t>(atoi(row[6]));
e.max_expansion = static_cast<int8_t>(atoi(row[7]));
e.content_flags = row[8] ? row[8] : "";
e.content_flags_disabled = row[9] ? row[9] : "";
all_entries.push_back(e);
}
@@ -16,18 +16,19 @@
#include "../../strings.h"
#include <ctime>
class BaseStartingItemsRepository {
public:
struct StartingItems {
uint32_t id;
int32_t race;
int32_t class_;
int32_t deityid;
int32_t zoneid;
int32_t itemid;
std::string class_list;
std::string race_list;
std::string deity_list;
std::string zone_id_list;
uint32_t item_id;
uint8_t item_charges;
int8_t gm;
int32_t slot;
int32_t status;
int32_t inventory_slot;
int8_t min_expansion;
int8_t max_expansion;
std::string content_flags;
@@ -43,14 +44,14 @@ public:
{
return {
"id",
"race",
"`class`",
"deityid",
"zoneid",
"itemid",
"class_list",
"race_list",
"deity_list",
"zone_id_list",
"item_id",
"item_charges",
"gm",
"slot",
"status",
"inventory_slot",
"min_expansion",
"max_expansion",
"content_flags",
@@ -62,14 +63,14 @@ public:
{
return {
"id",
"race",
"`class`",
"deityid",
"zoneid",
"itemid",
"class_list",
"race_list",
"deity_list",
"zone_id_list",
"item_id",
"item_charges",
"gm",
"slot",
"status",
"inventory_slot",
"min_expansion",
"max_expansion",
"content_flags",
@@ -115,14 +116,14 @@ public:
StartingItems e{};
e.id = 0;
e.race = 0;
e.class_ = 0;
e.deityid = 0;
e.zoneid = 0;
e.itemid = 0;
e.class_list = "";
e.race_list = "";
e.deity_list = "";
e.zone_id_list = "";
e.item_id = 0;
e.item_charges = 1;
e.gm = 0;
e.slot = -1;
e.status = 0;
e.inventory_slot = -1;
e.min_expansion = -1;
e.max_expansion = -1;
e.content_flags = "";
@@ -152,8 +153,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
starting_items_id
)
);
@@ -163,14 +165,14 @@ public:
StartingItems e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.race = static_cast<int32_t>(atoi(row[1]));
e.class_ = static_cast<int32_t>(atoi(row[2]));
e.deityid = static_cast<int32_t>(atoi(row[3]));
e.zoneid = static_cast<int32_t>(atoi(row[4]));
e.itemid = static_cast<int32_t>(atoi(row[5]));
e.class_list = row[1] ? row[1] : "";
e.race_list = row[2] ? row[2] : "";
e.deity_list = row[3] ? row[3] : "";
e.zone_id_list = row[4] ? row[4] : "";
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.gm = static_cast<int8_t>(atoi(row[7]));
e.slot = static_cast<int32_t>(atoi(row[8]));
e.status = static_cast<int32_t>(atoi(row[7]));
e.inventory_slot = static_cast<int32_t>(atoi(row[8]));
e.min_expansion = static_cast<int8_t>(atoi(row[9]));
e.max_expansion = static_cast<int8_t>(atoi(row[10]));
e.content_flags = row[11] ? row[11] : "";
@@ -208,14 +210,14 @@ public:
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.race));
v.push_back(columns[2] + " = " + std::to_string(e.class_));
v.push_back(columns[3] + " = " + std::to_string(e.deityid));
v.push_back(columns[4] + " = " + std::to_string(e.zoneid));
v.push_back(columns[5] + " = " + std::to_string(e.itemid));
v.push_back(columns[1] + " = '" + 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[4] + " = '" + Strings::Escape(e.zone_id_list) + "'");
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[7] + " = " + std::to_string(e.gm));
v.push_back(columns[8] + " = " + std::to_string(e.slot));
v.push_back(columns[7] + " = " + std::to_string(e.status));
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[10] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[11] + " = '" + Strings::Escape(e.content_flags) + "'");
@@ -242,14 +244,14 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.race));
v.push_back(std::to_string(e.class_));
v.push_back(std::to_string(e.deityid));
v.push_back(std::to_string(e.zoneid));
v.push_back(std::to_string(e.itemid));
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.zone_id_list) + "'");
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.gm));
v.push_back(std::to_string(e.slot));
v.push_back(std::to_string(e.status));
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.max_expansion));
v.push_back("'" + Strings::Escape(e.content_flags) + "'");
@@ -284,14 +286,14 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.race));
v.push_back(std::to_string(e.class_));
v.push_back(std::to_string(e.deityid));
v.push_back(std::to_string(e.zoneid));
v.push_back(std::to_string(e.itemid));
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.zone_id_list) + "'");
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.gm));
v.push_back(std::to_string(e.slot));
v.push_back(std::to_string(e.status));
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.max_expansion));
v.push_back("'" + Strings::Escape(e.content_flags) + "'");
@@ -330,14 +332,14 @@ public:
StartingItems e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.race = static_cast<int32_t>(atoi(row[1]));
e.class_ = static_cast<int32_t>(atoi(row[2]));
e.deityid = static_cast<int32_t>(atoi(row[3]));
e.zoneid = static_cast<int32_t>(atoi(row[4]));
e.itemid = static_cast<int32_t>(atoi(row[5]));
e.class_list = row[1] ? row[1] : "";
e.race_list = row[2] ? row[2] : "";
e.deity_list = row[3] ? row[3] : "";
e.zone_id_list = row[4] ? row[4] : "";
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.gm = static_cast<int8_t>(atoi(row[7]));
e.slot = static_cast<int32_t>(atoi(row[8]));
e.status = static_cast<int32_t>(atoi(row[7]));
e.inventory_slot = static_cast<int32_t>(atoi(row[8]));
e.min_expansion = static_cast<int8_t>(atoi(row[9]));
e.max_expansion = static_cast<int8_t>(atoi(row[10]));
e.content_flags = row[11] ? row[11] : "";
@@ -367,14 +369,14 @@ public:
StartingItems e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.race = static_cast<int32_t>(atoi(row[1]));
e.class_ = static_cast<int32_t>(atoi(row[2]));
e.deityid = static_cast<int32_t>(atoi(row[3]));
e.zoneid = static_cast<int32_t>(atoi(row[4]));
e.itemid = static_cast<int32_t>(atoi(row[5]));
e.class_list = row[1] ? row[1] : "";
e.race_list = row[2] ? row[2] : "";
e.deity_list = row[3] ? row[3] : "";
e.zone_id_list = row[4] ? row[4] : "";
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.gm = static_cast<int8_t>(atoi(row[7]));
e.slot = static_cast<int32_t>(atoi(row[8]));
e.status = static_cast<int32_t>(atoi(row[7]));
e.inventory_slot = static_cast<int32_t>(atoi(row[8]));
e.min_expansion = static_cast<int8_t>(atoi(row[9]));
e.max_expansion = static_cast<int8_t>(atoi(row[10]));
e.content_flags = row[11] ? row[11] : "";
@@ -6,7 +6,7 @@
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_TASKS_REPOSITORY_H
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseTasksRepository {
public:
struct Tasks {
@@ -47,6 +48,7 @@ public:
uint32_t dz_template_id;
int32_t lock_activity_id;
int32_t faction_amount;
int16_t enabled;
};
static std::string PrimaryKey()
@@ -85,6 +87,7 @@ public:
"dz_template_id",
"lock_activity_id",
"faction_amount",
"enabled",
};
}
@@ -119,6 +122,7 @@ public:
"dz_template_id",
"lock_activity_id",
"faction_amount",
"enabled",
};
}
@@ -187,6 +191,7 @@ public:
e.dz_template_id = 0;
e.lock_activity_id = -1;
e.faction_amount = 0;
e.enabled = 1;
return e;
}
@@ -212,8 +217,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
tasks_id
)
);
@@ -250,6 +256,7 @@ public:
e.dz_template_id = static_cast<uint32_t>(strtoul(row[25], nullptr, 10));
e.lock_activity_id = static_cast<int32_t>(atoi(row[26]));
e.faction_amount = static_cast<int32_t>(atoi(row[27]));
e.enabled = static_cast<int16_t>(atoi(row[28]));
return e;
}
@@ -311,6 +318,7 @@ public:
v.push_back(columns[25] + " = " + std::to_string(e.dz_template_id));
v.push_back(columns[26] + " = " + std::to_string(e.lock_activity_id));
v.push_back(columns[27] + " = " + std::to_string(e.faction_amount));
v.push_back(columns[28] + " = " + std::to_string(e.enabled));
auto results = db.QueryDatabase(
fmt::format(
@@ -360,6 +368,7 @@ public:
v.push_back(std::to_string(e.dz_template_id));
v.push_back(std::to_string(e.lock_activity_id));
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.enabled));
auto results = db.QueryDatabase(
fmt::format(
@@ -417,6 +426,7 @@ public:
v.push_back(std::to_string(e.dz_template_id));
v.push_back(std::to_string(e.lock_activity_id));
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.enabled));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -478,6 +488,7 @@ public:
e.dz_template_id = static_cast<uint32_t>(strtoul(row[25], nullptr, 10));
e.lock_activity_id = static_cast<int32_t>(atoi(row[26]));
e.faction_amount = static_cast<int32_t>(atoi(row[27]));
e.enabled = static_cast<int16_t>(atoi(row[28]));
all_entries.push_back(e);
}
@@ -530,6 +541,7 @@ public:
e.dz_template_id = static_cast<uint32_t>(strtoul(row[25], nullptr, 10));
e.lock_activity_id = static_cast<int32_t>(atoi(row[26]));
e.faction_amount = static_cast<int32_t>(atoi(row[27]));
e.enabled = static_cast<int16_t>(atoi(row[28]));
all_entries.push_back(e);
}
@@ -588,6 +600,118 @@ public:
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const Tasks &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.duration));
v.push_back(std::to_string(e.duration_code));
v.push_back("'" + Strings::Escape(e.title) + "'");
v.push_back("'" + Strings::Escape(e.description) + "'");
v.push_back("'" + Strings::Escape(e.reward_text) + "'");
v.push_back("'" + Strings::Escape(e.reward_id_list) + "'");
v.push_back(std::to_string(e.cash_reward));
v.push_back(std::to_string(e.exp_reward));
v.push_back(std::to_string(e.reward_method));
v.push_back(std::to_string(e.reward_points));
v.push_back(std::to_string(e.reward_point_type));
v.push_back(std::to_string(e.min_level));
v.push_back(std::to_string(e.max_level));
v.push_back(std::to_string(e.level_spread));
v.push_back(std::to_string(e.min_players));
v.push_back(std::to_string(e.max_players));
v.push_back(std::to_string(e.repeatable));
v.push_back(std::to_string(e.faction_reward));
v.push_back("'" + Strings::Escape(e.completion_emote) + "'");
v.push_back(std::to_string(e.replay_timer_group));
v.push_back(std::to_string(e.replay_timer_seconds));
v.push_back(std::to_string(e.request_timer_group));
v.push_back(std::to_string(e.request_timer_seconds));
v.push_back(std::to_string(e.dz_template_id));
v.push_back(std::to_string(e.lock_activity_id));
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.enabled));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<Tasks> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.duration));
v.push_back(std::to_string(e.duration_code));
v.push_back("'" + Strings::Escape(e.title) + "'");
v.push_back("'" + Strings::Escape(e.description) + "'");
v.push_back("'" + Strings::Escape(e.reward_text) + "'");
v.push_back("'" + Strings::Escape(e.reward_id_list) + "'");
v.push_back(std::to_string(e.cash_reward));
v.push_back(std::to_string(e.exp_reward));
v.push_back(std::to_string(e.reward_method));
v.push_back(std::to_string(e.reward_points));
v.push_back(std::to_string(e.reward_point_type));
v.push_back(std::to_string(e.min_level));
v.push_back(std::to_string(e.max_level));
v.push_back(std::to_string(e.level_spread));
v.push_back(std::to_string(e.min_players));
v.push_back(std::to_string(e.max_players));
v.push_back(std::to_string(e.repeatable));
v.push_back(std::to_string(e.faction_reward));
v.push_back("'" + Strings::Escape(e.completion_emote) + "'");
v.push_back(std::to_string(e.replay_timer_group));
v.push_back(std::to_string(e.replay_timer_seconds));
v.push_back(std::to_string(e.request_timer_group));
v.push_back(std::to_string(e.request_timer_seconds));
v.push_back(std::to_string(e.dz_template_id));
v.push_back(std::to_string(e.lock_activity_id));
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.enabled));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_TASKS_REPOSITORY_H
@@ -120,6 +120,8 @@ public:
{.parent_command = "set", .sub_command = "title_suffix", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "titlesuffix"},
{.parent_command = "set", .sub_command = "weather", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "weather"},
{.parent_command = "set", .sub_command = "zone", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "zclip|zcolor|zheader|zonelock|zsafecoords|zsky|zunderworld"},
{.parent_command = "show", .sub_command = "aas", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showaas"},
{.parent_command = "show", .sub_command = "aa_points", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showaapoints|showaapts"},
{.parent_command = "show", .sub_command = "aggro", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "aggro"},
{.parent_command = "show", .sub_command = "buffs", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showbuffs"},
{.parent_command = "show", .sub_command = "buried_corpse_count", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "getplayerburiedcorpsecount"},
+50
View File
@@ -0,0 +1,50 @@
#ifndef EQEMU_KEYRING_REPOSITORY_H
#define EQEMU_KEYRING_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_keyring_repository.h"
class KeyringRepository: public BaseKeyringRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* KeyringRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* KeyringRepository::GetWhereNeverExpires()
* KeyringRepository::GetWhereXAndY()
* KeyringRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
};
#endif //EQEMU_KEYRING_REPOSITORY_H
@@ -0,0 +1,50 @@
#ifndef EQEMU_SPAWN2_DISABLED_REPOSITORY_H
#define EQEMU_SPAWN2_DISABLED_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_spawn2_disabled_repository.h"
class Spawn2DisabledRepository: public BaseSpawn2DisabledRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* Spawn2DisabledRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* Spawn2DisabledRepository::GetWhereNeverExpires()
* Spawn2DisabledRepository::GetWhereXAndY()
* Spawn2DisabledRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
};
#endif //EQEMU_SPAWN2_DISABLED_REPOSITORY_H
@@ -6,7 +6,7 @@
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_{{TABLE_NAME_UPPER}}_REPOSITORY_H
@@ -319,6 +319,62 @@ public:
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const {{TABLE_NAME_STRUCT}} &e
)
{
std::vector<std::string> v;
{{INSERT_ONE_ENTRIES}}
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<{{TABLE_NAME_STRUCT}}> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
{{INSERT_MANY_ENTRIES}}
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_{{TABLE_NAME_UPPER}}_REPOSITORY_H
+12
View File
@@ -215,6 +215,7 @@ RULE_BOOL(Character, EnableRaidEXPModifier, true, "Enable or disable the raid ex
RULE_BOOL(Character, EnableRaidMemberEXPModifier, true, "Enable or disable the raid experience modifier based on members in raid, default is true")
RULE_BOOL(Character, LeaveCursorMoneyOnCorpse, false, "Enable or disable leaving cursor money on player corpses")
RULE_BOOL(Character, ItemExtraSkillDamageCalcAsPercent, false, "If enabled, apply Item Extra Skill Damage as Percentage-based modifiers")
RULE_BOOL(Character, UseForageCommonFood, true, "If enabled, use the common foods specified in the code.")
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
@@ -303,6 +304,9 @@ RULE_BOOL(World, EnforceCharacterLimitAtLogin, false, "Enforce the limit for cha
RULE_BOOL(World, EnableDevTools, true, "Enable or Disable the Developer Tools globally (Most of the time you want this enabled)")
RULE_BOOL(World, EnableChecksumVerification, false, "Enable or Disable the Checksum Verification for eqgame.exe and spells_us.txt")
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_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(Zone)
@@ -456,6 +460,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, 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_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(Combat)
@@ -648,6 +654,12 @@ RULE_BOOL(Bots, ResurrectionSickness, true, "Use Resurrection Sickness based on
RULE_INT(Bots, OldResurrectionSicknessSpell, 757, "757 is Default Old 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, 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(Chat)
+1 -1
View File
@@ -376,7 +376,7 @@ std::string EQ::SayLinkEngine::InjectSaylinksIfNotExist(const char *message)
void EQ::SayLinkEngine::LoadCachedSaylinks()
{
auto saylinks = SaylinkRepository::GetWhere(database, "phrase not REGEXP BINARY '[A-Z]' and phrase not REGEXP '[0-9]'");
auto saylinks = SaylinkRepository::GetWhere(database, "phrase not REGEXP '[A-Z]' and phrase not REGEXP '[0-9]'");
LogSaylink("Loaded [{}] saylinks into cache", saylinks.size());
g_cached_saylinks = saylinks;
}
+1
View File
@@ -19,6 +19,7 @@
#include <string>
#include <vector>
#include <stdint.h>
typedef struct eq_cpu_info_s {
std::string model;
+9 -9
View File
@@ -461,12 +461,12 @@ struct SPackSendQueue {
uchar buffer[0];
};
struct ServerZoneStateChange_struct {
uint32 ZoneServerID;
char adminname[64];
uint32 zoneid;
uint16 instanceid;
bool makestatic;
struct ServerZoneStateChange_Struct {
uint32 zone_server_id;
uint32 zone_id;
uint16 instance_id;
bool is_static;
char admin_name[64];
};
struct ServerZoneIncomingClient_Struct {
@@ -1142,10 +1142,10 @@ struct ServerInstanceUpdateTime_Struct
uint32 new_duration;
};
struct ServerSpawnStatusChange_Struct
{
struct ServerSpawnStatusChange_Struct {
uint32 id;
bool new_status;
bool new_status;
uint32 instance_id;
};
struct ServerQGlobalUpdate_Struct
+78 -35
View File
@@ -41,6 +41,7 @@
#include "repositories/criteria/content_filter_criteria.h"
#include "repositories/account_repository.h"
#include "repositories/faction_association_repository.h"
#include "repositories/starting_items_repository.h"
#include "path_manager.h"
#include "repositories/loottable_repository.h"
@@ -51,7 +52,9 @@ namespace ItemField
#define F(x) x,
#include "item_fieldlist.h"
#undef F
updated
updated,
minstatus,
comment,
};
}
@@ -444,45 +447,81 @@ bool SharedDatabase::SetSharedPlatinum(uint32 account_id, int32 amount_to_add) {
return true;
}
bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, EQ::InventoryProfile* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin_level) {
bool SharedDatabase::SetStartingItems(
PlayerProfile_Struct *pp,
EQ::InventoryProfile *inv,
uint32 si_race,
uint32 si_class,
uint32 si_deity,
uint32 si_current_zone,
char *si_name,
int admin_level
)
{
const EQ::ItemData *item_data;
const EQ::ItemData *myitem;
const auto &l = StartingItemsRepository::All(*this);
const std::string query = StringFormat(
"SELECT itemid, item_charges, slot FROM starting_items "
"WHERE (race = %i or race = 0) AND (class = %i or class = 0) AND "
"(deityid = %i or deityid = 0) AND (zoneid = %i or zoneid = 0) AND "
"gm <= %i %s ORDER BY id",
si_race,
si_class,
si_deity,
si_current_zone,
admin_level,
ContentFilterCriteria::apply().c_str()
);
auto results = QueryDatabase(query);
if (!results.Success()) {
if (l.empty()) {
return false;
}
std::vector<StartingItemsRepository::StartingItems> v;
for (auto& row = results.begin(); row != results.end(); ++row) {
const int32 itemid = Strings::ToInt(row[0]);
const int32 charges = Strings::ToInt(row[1]);
int32 slot = Strings::ToInt(row[2]);
myitem = GetItem(itemid);
for (const auto &e : l) {
const auto &classes = Strings::Split(e.class_list, "|");
const auto &deities = Strings::Split(e.deity_list, "|");
const auto &races = Strings::Split(e.race_list, "|");
const auto &zones = Strings::Split(e.zone_id_list, "|");
if(!myitem)
const std::string &all = std::to_string(0);
if (classes[0] != all) {
if (!Strings::Contains(classes, std::to_string(si_class))) {
continue;
}
}
if (deities[0] != all) {
if (!Strings::Contains(deities, std::to_string(si_deity))) {
continue;
}
}
if (races[0] != all) {
if (!Strings::Contains(races, std::to_string(si_race))) {
continue;
}
}
if (zones[0] != all) {
if (!Strings::Contains(zones, std::to_string(si_current_zone))) {
continue;
}
}
v.emplace_back(e);
}
for (const auto &e : v) {
const uint32 item_id = e.item_id;
const uint8 item_charges = e.item_charges;
int32 slot = e.inventory_slot;
item_data = GetItem(item_id);
if (!item_data) {
continue;
}
const EQ::ItemInstance* myinst = CreateBaseItem(myitem, charges);
const auto *inst = CreateBaseItem(item_data, item_charges);
if(slot < 0)
slot = inv->FindFreeSlot(0, 0);
if (slot < EQ::invslot::slotCharm) {
slot = inv->FindFreeSlot(false, false);
}
inv->PutItem(slot, *myinst);
safe_delete(myinst);
inv->PutItem(slot, *inst);
safe_delete(inst);
}
return true;
@@ -965,7 +1004,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
#define F(x) "`"#x"`,"
#include "item_fieldlist.h"
#undef F
"updated FROM items ORDER BY id";
"updated, minstatus, comment FROM items ORDER BY id";
auto results = QueryDatabase(query);
if (!results.Success()) {
return;
@@ -977,9 +1016,13 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
// Unique Identifier
item.ID = Strings::ToUnsignedInt(row[ItemField::id]);
// Name and Lore
// Minimum Status
item.MinStatus = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::minstatus]));
// Name, Lore, and Comment
strn0cpy(item.Name, row[ItemField::name], sizeof(item.Name));
strn0cpy(item.Lore, row[ItemField::lore], sizeof(item.Lore));
strn0cpy(item.Comment, row[ItemField::comment], sizeof(item.Comment));
// Flags
item.ArtifactFlag = Strings::ToBool(row[ItemField::artifactflag]);
@@ -1765,7 +1808,7 @@ bool SharedDatabase::LoadSkillCaps(const std::string &prefix) {
}
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 level_count = HARD_LEVEL_CAP + 1;
uint16 *skill_caps_table = static_cast<uint16*>(data);
@@ -1805,7 +1848,7 @@ uint16 SharedDatabase::GetSkillCap(uint8 Class_, EQ::skills::SkillType Skill, ui
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 level_count = HARD_LEVEL_CAP + 1;
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
@@ -1835,7 +1878,7 @@ uint8 SharedDatabase::GetTrainLevel(uint8 Class_, EQ::skills::SkillType Skill, u
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 level_count = HARD_LEVEL_CAP + 1;
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
@@ -2018,7 +2061,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].environment_type=Strings::ToInt(row[102]);
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].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];
if (
spell.classes[BARD - 1] < UINT8_MAX &&
spell.classes[Class::Bard - 1] < UINT8_MAX &&
!spell.is_discipline
) {
return true;
@@ -780,7 +780,7 @@ uint8 GetSpellMinimumLevel(uint16 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) {
minimum_level = spell.classes[i];
}
@@ -798,7 +798,7 @@ uint8 GetSpellLevel(uint16 spell_id, uint8 class_id)
return UINT8_MAX;
}
if (class_id >= PLAYER_CLASS_COUNT) {
if (class_id >= Class::PLAYER_CLASS_COUNT) {
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
/* 102 */ int8 environment_type; // -- ENVIRONMENTTYPE
/* 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
/* 121 */ //uint8 TargetAnim; // -- TARGETANIM
/* 122 */ //uint32 TravelType; // -- TRAVELTYPE
+3 -3
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.31.0-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.39.0-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
@@ -42,9 +42,9 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9240
#define CURRENT_BINARY_DATABASE_VERSION 9249
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9040
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041
#endif
+10 -28
View File
@@ -121,43 +121,25 @@ bool Database::GetLoginTokenDataFromToken(
std::string &user
)
{
auto query = fmt::format(
"SELECT tbllogintokens.Id, tbllogintokens.IpAddress, tbllogintokenclaims.Name, tbllogintokenclaims.Value FROM tbllogintokens "
"JOIN tbllogintokenclaims ON tbllogintokens.Id = tbllogintokenclaims.TokenId WHERE tbllogintokens.Expires > NOW() "
"AND tbllogintokens.Id='{0}' AND tbllogintokens.IpAddress='{1}'",
auto query = fmt::format("SELECT login_server, username, account_id FROM login_tickets WHERE expires > NOW()"
" AND id='{0}' AND ip_address='{1}' LIMIT 1",
Strings::Escape(token),
Strings::Escape(ip)
);
Strings::Escape(ip));
auto results = QueryDatabase(query);
if (results.RowCount() == 0 || !results.Success()) {
return false;
}
bool found_username = false;
bool found_login_id = false;
bool found_login_server_name = false;
for (auto row = results.begin(); row != results.end(); ++row) {
if (strcmp(row[2], "username") == 0) {
user = row[3];
found_username = true;
continue;
}
if (strcmp(row[2], "login_server_id") == 0) {
db_account_id = Strings::ToUnsignedInt(row[3]);
found_login_id = true;
continue;
}
if (strcmp(row[2], "login_server_name") == 0) {
db_loginserver = row[3];
found_login_server_name = true;
continue;
}
for (auto row = results.begin(); row != results.end(); ++row) {
db_loginserver = row[0];
user = row[1];
db_account_id = Strings::ToUnsignedInt(row[2]);
return true;
}
return found_username && found_login_id && found_login_server_name;
return false;
}
/**
+11
View File
@@ -0,0 +1,11 @@
DROP TABLE IF EXISTS `login_tickets`;
CREATE TABLE `login_tickets` (
`id` VARCHAR(128) NOT NULL,
`login_server` TEXT NOT NULL,
`username` TEXT NOT NULL,
`account_id` INT(10) UNSIGNED NOT NULL,
`ip_address` VARCHAR(45) NOT NULL,
`expires` DATETIME NOT NULL,
PRIMARY KEY (`id`) USING BTREE
)
ENGINE=InnoDB;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.31.0",
"version": "22.39.0",
"repository": {
"type": "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");
mutex.Lock();
uint32 class_count = PLAYER_CLASS_COUNT;
uint32 class_count = Class::PLAYER_CLASS_COUNT;
uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
uint32 level_count = HARD_LEVEL_CAP + 1;
uint32 size = (class_count * skill_count * level_count * sizeof(uint16));
+8
View File
@@ -0,0 +1,8 @@
module constantconvert
go 1.18
require (
github.com/gammazero/deque v0.2.0 // indirect
github.com/gammazero/workerpool v1.1.3 // indirect
)
+4
View File
@@ -0,0 +1,4 @@
github.com/gammazero/deque v0.2.0 h1:SkieyNB4bg2/uZZLxvya0Pq6diUlwx7m2TeT7GAIWaA=
github.com/gammazero/deque v0.2.0/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU=
github.com/gammazero/workerpool v1.1.3 h1:WixN4xzukFoN0XSeXF6puqEqFTl2mECI9S6W44HWy9Q=
github.com/gammazero/workerpool v1.1.3/go.mod h1:wPjyBLDbyKnUn2XwwyD3EEwo9dHutia9/fwNmSHWACc=
+313
View File
@@ -0,0 +1,313 @@
package main
import (
"fmt"
"github.com/gammazero/workerpool"
"io/fs"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
)
func main() {
loadDefinitions()
// get processor count
wp := workerpool.New(runtime.NumCPU())
// loop through all files in current dir that are cpp files or h files
err := filepath.WalkDir("../../", func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
return nil
}
if !strings.Contains(path, ".cpp") && !strings.Contains(path, ".h") {
return nil
}
// if file ends with ".o" skip it
if strings.HasSuffix(path, ".o") {
return nil
}
var ignoreFiles = []string{
"submodules", "/libs", "utils/", "races.h", "backward", "database_update_manifest.cpp", "zonedb.h",
}
ignore := false
for _, ignoreString := range ignoreFiles {
if strings.Contains(path, ignoreString) {
ignore = true
break
}
}
if ignore {
return nil
}
wp.Submit(func() {
// open file for reading
// get file contents
contents, err := os.ReadFile(path)
if err != nil {
log.Fatalf("impossible to read file: %s", err)
}
content := string(contents)
wroteChanges := false
var newLines []string
for _, line := range strings.Split(content, "\n") {
newLine := line
// loop through oldDefs and see if any of them are in contents
for key, value := range oldDefs {
// combine all of the above contains into a slice
// loop through slice and if any of them are in line, continue
var ignoreMatches = []string{
"#define ", "MALE", "FEMALE", "_BIT", "LANG_",
}
ignore := false
for _, ignoreString := range ignoreMatches {
if strings.Contains(newLine, ignoreString) && !strings.Contains(newLine, "NPC_") {
ignore = true
break
}
}
if ignore {
continue
}
// below we hackishly use a series of specific string contains to avoid
// making blind and wrong replacements
// but hey - at least its 100% accurate :)
if strings.Contains(line, "case "+key+":") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, " "+key+":", " "+key2+":")
wroteChanges = true
break
}
}
}
if strings.Contains(line, "\t"+key) {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "\t"+key, "\t"+key2)
wroteChanges = true
break
}
}
}
if strings.Contains(line, key+",") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, key+",", key2+",")
wroteChanges = true
break
}
}
}
if strings.Contains(line, ", "+key) {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, ", "+key, ", "+key2)
wroteChanges = true
break
}
}
}
if strings.Contains(line, "= "+key+" ") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "= "+key+" ", "= "+key2+" ")
wroteChanges = true
break
}
}
}
if strings.Contains(line, "= "+key+")") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "= "+key+")", "= "+key2+")")
wroteChanges = true
break
}
}
}
if strings.Contains(line, "= "+key+";") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "= "+key+";", "= "+key2+";")
wroteChanges = true
break
}
}
}
if strings.Contains(line, "= "+key+" ||") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "= "+key+" ||", "= "+key2+" ||")
wroteChanges = true
break
}
}
}
// match cases where our match is on the last line and last column
// we need to be exact in the last column and not do a partial because we can
// accidentally rename say OGRE to OGRE2 mistakenly
if strings.Contains(line, key) {
columns := strings.Split(line, " ")
// get the last column
lastColumn := strings.TrimSpace(columns[len(columns)-1])
if lastColumn == key {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, lastColumn, key2)
wroteChanges = true
break
}
}
}
}
//if strings.Contains(line, "race == "+key) {
// for key2, value2 := range newDefs {
// if value == value2 {
// newLine = strings.ReplaceAll(newLine, "race == "+key, "race == "+key2)
// wroteChanges = true
// break
// }
// }
//}
}
newLines = append(newLines, newLine)
}
// write contents back to file
if wroteChanges {
fmt.Printf("wrote changes to file [%v]\n", path)
err = os.WriteFile(path, []byte(strings.Join(newLines, "\n")), 0644)
if err != nil {
log.Fatalf("impossible to write file: %s", err)
}
}
return
})
return nil
})
if err != nil {
log.Fatalf("impossible to walk directories: %s", err)
}
wp.StopWait()
}
var newDefs = make(map[string]int)
var oldDefs = make(map[string]int)
func loadDefinitions() {
// git show master:common/races.h
cmd := exec.Command("git", "show", "master:common/races.h")
out, err := cmd.Output()
if err != nil {
println(err.Error())
return
}
// load into a string -> int map
for _, line := range strings.Split(string(out), "\n") {
if strings.Contains(line, "#define ") {
if len(strings.Split(line, " ")) <= 2 {
continue
}
// ignore
// #define MALE 0
// #define FEMALE 1
// #define NEUTER 2
if strings.Contains(line, "#define MALE") {
continue
}
if strings.Contains(line, "#define FEMALE") {
continue
}
if strings.Contains(line, "#define NEUTER") {
continue
}
// load "#define RACE_FLYING_CARPET_720 720" into map
key := strings.Split(line, " ")[1]
value := strings.Split(line, " ")[2]
value = strings.ReplaceAll(value, "//", "")
value = strings.TrimSpace(value)
//fmt.Printf("key [%v] value [%v]\n", key, value)
if !strings.HasPrefix(key, "RACE_") && !strings.HasPrefix(key, "RT_") {
continue
}
// convert value to int
intValue, err := strconv.Atoi(value)
if err != nil {
println(err.Error())
return
}
oldDefs[key] = intValue
fmt.Printf("oldDefs key [%v] value [%v]\n", key, intValue)
}
}
// cleanup/races_cpp_h
cmd = exec.Command("git", "show", "cleanup/races_cpp_h:common/races.h")
out, err = cmd.Output()
if err != nil {
println(err.Error())
return
}
// load into a string -> int map
for _, line := range strings.Split(string(out), "\n") {
if strings.Contains(line, "constexpr uint16") {
if len(strings.Split(line, " ")) <= 2 {
continue
}
// remove all extra spaces in between characters in line
line = strings.Join(strings.Fields(line), " ")
// load " constexpr uint16 Doug = 0;" into map
key := strings.Split(line, " ")[2]
value := strings.Split(line, " ")[4]
value = strings.ReplaceAll(value, "//", "")
value = strings.ReplaceAll(value, ";", "")
value = strings.TrimSpace(value)
// convert value to int
intValue, err := strconv.Atoi(value)
if err != nil {
println(err.Error())
return
}
mapKey := "Race::" + key
newDefs[mapKey] = intValue
fmt.Printf("newDefs key [%v] value [%v]\n", mapKey, value)
}
}
}
+2 -2
View File
@@ -15,8 +15,8 @@ mkdir -p build && cd build && \
-DEQEMU_BUILD_LOGIN=ON \
-DEQEMU_BUILD_LUA=ON \
-DEQEMU_BUILD_PERL=ON \
-DCMAKE_CXX_FLAGS:STRING="-O1 -g" \
-DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O1 -g" \
-DCMAKE_CXX_FLAGS:STRING="-O1 -g -Wno-everything" \
-DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O1 -g -Wno-everything" \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-G 'Unix Makefiles' \
.. && make -j$((`nproc`-4))
+1 -1
View File
@@ -10,7 +10,7 @@ require (
require (
github.com/golang/protobuf v1.3.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/net v0.17.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
)
+2 -2
View File
@@ -10,8 +10,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+28 -11
View File
@@ -2,8 +2,13 @@
########################################################################
#::: 13th floor import script
#::: Current Source: http://items.sodeq.org/download.php
#::: Authors: (Natedog, Akkadius)
#::: Items Source: http://items.sodeq.org/download.php
#::: How To:
#::: 1. Place this script with your server eqemu_config.json
#::: 2. Download the items.txt file and place with this script
#::: 3. Run this script with Perl
#::: 4. Review new and updated items in the items_new table
#::: 5. Make any desired changes and replace the items table contents
########################################################################
use DBI;
@@ -16,6 +21,7 @@ my $db_user = "";
my $db_pass = "";
my $total_items = 0;
my $read_items_file = "items.txt"; #default
my $keep_temp_items_table = 0; #keeps the imported items table
read_eqemu_config_json();
@@ -24,7 +30,7 @@ my $dbh = DBI->connect("DBI:mysql:database=$db_name;host=$db_host;port=$db_port"
read_items_file_from_13th_floor_text();
update_items_table();
print "\n\nImport complete!\n\n";
print "\n\nImport complete! Review items_new table before replacing into items table.\n\n";
sub read_eqemu_config_json {
use JSON;
@@ -139,7 +145,12 @@ sub read_items_file_from_13th_floor_text {
sub update_items_table {
print "Updating items table...\n";
#::: Establish items_new table
print "Setting up new items table...\n";
$dbh->do("DROP TABLE IF EXISTS items_new");
$dbh->do("CREATE TABLE items_new AS SELECT * FROM items");
print "Updating new items table...\n";
my @matching_table;
my @missing_items_table;
@@ -147,7 +158,7 @@ sub update_items_table {
print "Comparing table structure...\n";
#::: Get columns from `items`
my $sth = $dbh->prepare("SHOW COLUMNS FROM `items`;");
my $sth = $dbh->prepare("SHOW COLUMNS FROM `items_new`;");
$sth->execute();
my @items_table;
while (my @row = $sth->fetchrow_array()) {
@@ -230,7 +241,7 @@ sub update_items_table {
}
my $update_query = "
INSERT INTO items (" . $items_field_list . ")
INSERT INTO items_new (" . $items_field_list . ")
SELECT " . $items_floor_field_list . "
FROM items_floor fi
ON DUPLICATE KEY UPDATE " . $update_fields;
@@ -257,14 +268,20 @@ sub update_items_table {
#::: Update stackables
print "Updating stackable field...\n";
$dbh->do("UPDATE items i SET i.stackable = 1 WHERE i.stacksize > 1");
$dbh->do("UPDATE items_new i SET i.stackable = 1 WHERE i.stacksize > 1");
#::: Update legacy research tome bagtypes
print "Updating legacy research tomes...\n";
$dbh->do("UPDATE items i SET i.bagtype = 24 WHERE i.id IN (17655, 17903)"); #RESEARCHWIZ
$dbh->do("UPDATE items i SET i.bagtype = 25 WHERE i.id IN (17502, 17653)"); #RESEARCHMAG
$dbh->do("UPDATE items i SET i.bagtype = 26 WHERE i.id IN (17501, 17654)"); #RESEARCHNEC
$dbh->do("UPDATE items i SET i.bagtype = 27 WHERE i.id IN (17500, 17652)"); #RESEARCHENC
$dbh->do("UPDATE items_new i SET i.bagtype = 24 WHERE i.id IN (17655, 17903)"); #RESEARCHWIZ
$dbh->do("UPDATE items_new i SET i.bagtype = 25 WHERE i.id IN (17502, 17653)"); #RESEARCHMAG
$dbh->do("UPDATE items_new i SET i.bagtype = 26 WHERE i.id IN (17501, 17654)"); #RESEARCHNEC
$dbh->do("UPDATE items_new i SET i.bagtype = 27 WHERE i.id IN (17500, 17652)"); #RESEARCHENC
#::: Remove temp table
if (!$keep_temp_items_table) {
print "Cleaning up temp items table...\n";
$dbh->do("DROP TABLE items_floor");
}
}
sub trim($) {
File diff suppressed because it is too large Load Diff
+4
View File
@@ -78,6 +78,10 @@ ADD_EXECUTABLE(world ${world_sources} ${world_headers})
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)
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}
};
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*/
{ /*Warrior*/ 10, 10, 5, 0, 0, 0, 0, 25},
{ /*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}
};
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*/
{ /*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},
@@ -2021,7 +2021,7 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc)
// if out of range looking it up in the table would crash stuff
// so we return from these
if (classtemp >= PLAYER_CLASS_COUNT) {
if (classtemp >= Class::PLAYER_CLASS_COUNT) {
LogInfo(" class is out of range");
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::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
switch(pp->class_) {
case ROGUE:
case Class::Rogue:
pp->languages[LANG_THIEVES_CANT] = 100;
break;
default:
+10 -10
View File
@@ -578,25 +578,25 @@ void ConsoleZoneShutdown(
strcpy(&tmpname[1], connection->UserName().c_str());
auto pack = new ServerPacket;
pack->size = sizeof(ServerZoneStateChange_struct);
pack->size = sizeof(ServerZoneStateChange_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, sizeof(ServerZoneStateChange_struct));
ServerZoneStateChange_struct *s = (ServerZoneStateChange_struct *) pack->pBuffer;
memset(pack->pBuffer, 0, sizeof(ServerZoneStateChange_Struct));
auto *s = (ServerZoneStateChange_Struct *) pack->pBuffer;
pack->opcode = ServerOP_ZoneShutdown;
strcpy(s->adminname, tmpname);
strcpy(s->admin_name, tmpname);
if (Strings::IsNumber(args[0])) {
s->ZoneServerID = Strings::ToInt(args[0]);
s->zone_server_id = Strings::ToInt(args[0]);
}
else {
s->zoneid = ZoneID(args[0].c_str());
s->zone_id = ZoneID(args[0].c_str());
}
ZoneServer *zs = 0;
if (s->ZoneServerID != 0) {
zs = zoneserver_list.FindByID(s->ZoneServerID);
if (s->zone_server_id != 0) {
zs = zoneserver_list.FindByID(s->zone_server_id);
}
else if (s->zoneid != 0) {
zs = zoneserver_list.FindByName(ZoneName(s->zoneid));
else if (s->zone_id != 0) {
zs = zoneserver_list.FindByName(ZoneName(s->zone_id));
}
else {
connection->SendLine("Error: ZoneShutdown: neither ID nor name specified");
+2 -2
View File
@@ -33,7 +33,7 @@ GroupLFP::GroupLFP(uint32 inLeaderID) {
LeaderID = inLeaderID;
for (auto &member : Members) {
member.Name[0] = '\0';
member.Class = NO_CLASS;
member.Class = Class::None;
member.Level = 0;
member.Zone = 0;
}
@@ -77,7 +77,7 @@ void GroupLFP::SetDetails(ServerLFPUpdate_Struct *Update) {
Members[i].GuildID = CLE->GuildID();
}
else {
Members[i].Class = NO_CLASS;
Members[i].Class = Class::None;
Members[i].Level = 0;
Members[i].Zone = 0;
Members[i].GuildID = 0xFFFF;
+14 -6
View File
@@ -424,12 +424,20 @@ int main(int argc, char **argv)
}
if (EQTimeTimer.Check()) {
TimeOfDay_Struct tod;
zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(0), &tod);
if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year))
LogError("Failed to save eqtime");
else
LogDebug("EQTime successfully saved");
TimeOfDay_Struct tod{};
zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(nullptr), &tod);
if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year)) {
LogEqTime("Failed to save eqtime");
}
else {
LogEqTimeDetail("EQTime successfully saved - time is now year [{}] month [{}] day [{}] hour [{}] minute [{}]",
tod.year,
tod.month,
tod.day,
tod.hour - 1,
tod.minute
);
}
}
zoneserver_list.Process();
+1 -1
View File
@@ -460,7 +460,7 @@ void SharedTaskManager::LoadSharedTaskState()
SharedTaskManager *SharedTaskManager::LoadTaskData()
{
m_task_data = TasksRepository::All(*m_content_database);
m_task_data = TasksRepository::GetWhere(*m_content_database, "enabled = 1");
m_task_activity_data = TaskActivitiesRepository::All(*m_content_database);
LogTasks("Loaded tasks [{}] activities [{}]", m_task_data.size(), m_task_activity_data.size());
+21 -18
View File
@@ -720,15 +720,15 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
break;
}
case ServerOP_ZoneShutdown: {
auto s = (ServerZoneStateChange_struct*) pack->pBuffer;
auto *s = (ServerZoneStateChange_Struct*) pack->pBuffer;
ZoneServer* zs = 0;
if (s->ZoneServerID) {
zs = zoneserver_list.FindByID(s->ZoneServerID);
} else if (s->zoneid) {
zs = zoneserver_list.FindByName(ZoneName(s->zoneid));
if (s->zone_server_id) {
zs = zoneserver_list.FindByID(s->zone_server_id);
} else if (s->zone_id) {
zs = zoneserver_list.FindByName(ZoneName(s->zone_id));
} else {
zoneserver_list.SendEmoteMessage(
s->adminname,
s->admin_name,
0,
AccountStatus::Player,
Chat::White,
@@ -738,7 +738,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
if (!zs) {
zoneserver_list.SendEmoteMessage(
s->adminname,
s->admin_name,
0,
AccountStatus::Player,
Chat::White,
@@ -751,8 +751,8 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
break;
}
case ServerOP_ZoneBootup: {
auto s = (ServerZoneStateChange_struct*) pack->pBuffer;
zoneserver_list.SOPZoneBootup(s->adminname, s->ZoneServerID, ZoneName(s->zoneid), s->makestatic);
auto *s = (ServerZoneStateChange_Struct*) pack->pBuffer;
zoneserver_list.SOPZoneBootup(s->admin_name, s->zone_server_id, ZoneName(s->zone_id), s->is_static);
break;
}
case ServerOP_ZoneStatus: {
@@ -1606,20 +1606,23 @@ void ZoneServer::ChangeWID(uint32 iCharID, uint32 iWID) {
void ZoneServer::TriggerBootup(uint32 in_zone_id, uint32 in_instance_id, const char* admin_name, bool is_static_zone) {
is_booting_up = true;
is_booting_up = true;
zone_server_zone_id = in_zone_id;
instance_id = in_instance_id;
instance_id = in_instance_id;
auto pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_Struct));
auto *s = (ServerZoneStateChange_Struct*) pack->pBuffer;
s->zone_server_id = zone_server_id;
s->zone_id = in_zone_id ? in_zone_id : GetZoneID();
s->instance_id = in_instance_id;
s->is_static = is_static_zone;
auto pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_struct));
auto s = (ServerZoneStateChange_struct*) pack->pBuffer;
s->ZoneServerID = zone_server_id;
if (admin_name) {
strn0cpy(s->adminname, admin_name, sizeof(s->adminname));
strn0cpy(s->admin_name, admin_name, sizeof(s->admin_name));
}
s->zoneid = in_zone_id ? in_zone_id : GetZoneID();
s->instanceid = in_instance_id;
s->makestatic = is_static_zone;
SendPacket(pack);
delete pack;
LSBootUpdate(in_zone_id, in_instance_id);
+6
View File
@@ -284,6 +284,12 @@ ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers})
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)
TARGET_LINK_LIBRARIES(zone ${ZONE_LIBS})
+111 -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
switch (corpse_to_use->class_)
{
case CLERIC:
case Class::Cleric:
made_npc->npc_spells_id = 1;
break;
case WIZARD:
case Class::Wizard:
made_npc->npc_spells_id = 2;
break;
case NECROMANCER:
case Class::Necromancer:
made_npc->npc_spells_id = 3;
break;
case MAGICIAN:
case Class::Magician:
made_npc->npc_spells_id = 4;
break;
case ENCHANTER:
case Class::Enchanter:
made_npc->npc_spells_id = 5;
break;
case SHAMAN:
case Class::Shaman:
made_npc->npc_spells_id = 6;
break;
case DRUID:
case Class::Druid:
made_npc->npc_spells_id = 7;
break;
case PALADIN:
case Class::Paladin:
//SPECATK_TRIPLE
strcpy(made_npc->special_abilities, "6,1");
made_npc->current_hp = made_npc->current_hp * 150 / 100;
made_npc->max_hp = made_npc->max_hp * 150 / 100;
made_npc->npc_spells_id = 8;
break;
case SHADOWKNIGHT:
case Class::ShadowKnight:
strcpy(made_npc->special_abilities, "6,1");
made_npc->current_hp = made_npc->current_hp * 150 / 100;
made_npc->max_hp = made_npc->max_hp * 150 / 100;
made_npc->npc_spells_id = 9;
break;
case RANGER:
case Class::Ranger:
strcpy(made_npc->special_abilities, "7,1");
made_npc->current_hp = made_npc->current_hp * 135 / 100;
made_npc->max_hp = made_npc->max_hp * 135 / 100;
made_npc->npc_spells_id = 10;
break;
case BARD:
case Class::Bard:
strcpy(made_npc->special_abilities, "6,1");
made_npc->current_hp = made_npc->current_hp * 110 / 100;
made_npc->max_hp = made_npc->max_hp * 110 / 100;
made_npc->npc_spells_id = 11;
break;
case BEASTLORD:
case Class::Beastlord:
strcpy(made_npc->special_abilities, "7,1");
made_npc->current_hp = made_npc->current_hp * 110 / 100;
made_npc->max_hp = made_npc->max_hp * 110 / 100;
made_npc->npc_spells_id = 12;
break;
case ROGUE:
case Class::Rogue:
strcpy(made_npc->special_abilities, "7,1");
made_npc->max_dmg = made_npc->max_dmg * 150 / 100;
made_npc->current_hp = made_npc->current_hp * 110 / 100;
made_npc->max_hp = made_npc->max_hp * 110 / 100;
break;
case MONK:
case Class::Monk:
strcpy(made_npc->special_abilities, "7,1");
made_npc->max_dmg = made_npc->max_dmg * 150 / 100;
made_npc->current_hp = made_npc->current_hp * 135 / 100;
made_npc->max_hp = made_npc->max_hp * 135 / 100;
break;
case WARRIOR:
case BERSERKER:
case Class::Warrior:
case Class::Berserker:
strcpy(made_npc->special_abilities, "7,1");
made_npc->max_dmg = made_npc->max_dmg * 150 / 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 {
// 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)) {
return;
}
@@ -2207,3 +2207,97 @@ bool Client::HasAlreadyPurchasedRank(AA::Rank* rank) {
return false;
}
void Client::ListPurchasedAAs(Client *to, std::string search_criteria)
{
if (!to) {
return;
}
std::map<std::string, uint8> client_aa_ranks;
for (auto &aa : zone->aa_abilities) {
AA::Ability *ability = aa.second.get();
AA::Rank *rank = ability->first;
while (rank) {
if (!CanUseAlternateAdvancementRank(rank)) {
break;
}
if (HasAlreadyPurchasedRank(rank)) {
const std::string aa_name = zone->GetAAName(rank->id);
if (
search_criteria.empty() ||
Strings::Contains(
Strings::ToLower(aa_name),
Strings::ToLower(search_criteria)
)
) {
if (client_aa_ranks.find(aa_name) == client_aa_ranks.end()) {
client_aa_ranks[aa_name] = 1;
} else {
client_aa_ranks[aa_name]++;
}
}
}
rank = rank->next;
}
}
if (client_aa_ranks.empty()) {
to->Message(
Chat::White,
fmt::format(
"{} {} no purchased AAs{}.",
to->GetTargetDescription(this, TargetDescriptionType::UCYou),
this == to ? "have" : "has",
(
!search_criteria.empty() ?
fmt::format(
" matching '{}'",
search_criteria
) :
""
)
).c_str()
);
return;
}
int aa_number = 1;
for (const auto &aa : client_aa_ranks) {
to->Message(
Chat::White,
fmt::format(
"{}. {} (Rank {})",
aa_number,
aa.first,
aa.second
).c_str()
);
aa_number++;
}
to->Message(
Chat::White,
fmt::format(
"{} {} {} purchased AA{}{}.",
to->GetTargetDescription(this, TargetDescriptionType::UCYou),
this == to ? "have" : "has",
client_aa_ranks.size(),
client_aa_ranks.size() > 1 ? "s" : "",
(
!search_criteria.empty() ?
fmt::format(
" matching '{}'",
search_criteria
) :
""
)
).c_str()
);
}
+9 -9
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 will_aggro_npcs = from_who->WillAggroNPCs();
bool will_aggro_npcs = from_who->GetNPCAggro();
if (is_engaged) {
Mob *top = from_who->GetHateTop();
to_who->Message(
@@ -678,7 +678,7 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
if(!isSpellAttack)
{
if(GetClass() == LDON_TREASURE)
if(GetClass() == Class::LDoNTreasure)
{
return false;
}
@@ -983,14 +983,14 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage, ExtraAtt
float size_mod = GetSize();
float other_size_mod = other->GetSize();
if (GetRace() == RACE_LAVA_DRAGON_49 || GetRace() == RACE_WURM_158 || GetRace() == RACE_GHOST_DRAGON_196) { //For races with a fixed size
if (GetRace() == Race::LavaDragon || GetRace() == Race::Wurm || GetRace() == Race::GhostDragon) { //For races with a fixed size
size_mod = 60.0f;
}
else if (size_mod < 6.0) {
size_mod = 8.0f;
}
if (other->GetRace() == RACE_LAVA_DRAGON_49 || other->GetRace() == RACE_WURM_158 || other->GetRace() == RACE_GHOST_DRAGON_196) { //For races with a fixed size
if (other->GetRace() == Race::LavaDragon || other->GetRace() == Race::Wurm || other->GetRace() == Race::GhostDragon) { //For races with a fixed size
other_size_mod = 60.0f;
}
else if (other_size_mod < 6.0) {
@@ -1011,11 +1011,11 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage, ExtraAtt
size_mod *= size_mod * 4;
}
if (other->GetRace() == RACE_VELIOUS_DRAGON_184) // Lord Vyemm and other velious dragons
if (other->GetRace() == Race::VeliousDragon) // Lord Vyemm and other velious dragons
{
size_mod *= 1.75;
}
if (other->GetRace() == RACE_DRAGON_SKELETON_122) // Dracoliche in Fear. Skeletal Dragon
if (other->GetRace() == Race::DragonSkeleton) // Dracoliche in Fear. Skeletal Dragon
{
size_mod *= 2.25;
}
@@ -1070,10 +1070,10 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage, ExtraAtt
SetPseudoRoot(false);
}
}
if (aeRampage) {
float aeramp_size = RuleR(Combat, AERampageMaxDistance);
LogCombatDetail("AERampage: Default - aeramp_size = [{}] ", aeramp_size);
if (opts) {
@@ -1093,7 +1093,7 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage, ExtraAtt
LogCombatDetail("AE Rampage: ramp_range = [{}] -- (size_mod [{}] * aeramp_size [{}])", ramp_range, size_mod, aeramp_size);
LogCombatDetail("AE Rampage: _DistNoRoot [{}] <= ramp_range [{}]", _DistNoRoot, ramp_range);
if (_DistNoRoot <= ramp_range) {
LogCombatDetail("AE Rampage: Combat Distance returned [true]");
return true;
+1 -1
View File
@@ -245,7 +245,7 @@ Json::Value ApiGetNpcListDetail(EQ::Net::WebsocketServerConnection *connection,
row["swarm_owner"] = npc->GetSwarmOwner();
row["swarm_target"] = npc->GetSwarmTarget();
row["waypoint_max"] = npc->GetWaypointMax();
row["will_aggro_npcs"] = npc->WillAggroNPCs();
row["npc_aggro"] = npc->GetNPCAggro();
response.append(row);
}
+168 -172
View File
@@ -558,7 +558,7 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
}
// dodge
if (CanThisClassDodge() && (InFront || GetClass() == MONK)) {
if (CanThisClassDodge() && (InFront || GetClass() == Class::Monk)) {
if (IsClient())
CastToClient()->CheckIncreaseSkill(EQ::skills::SkillDodge, other, -10);
// 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;
switch (GetClass()) {
case WARRIOR:
case Class::Warrior:
return war_softcaps[level];
case CLERIC:
case BARD:
case MONK:
case Class::Cleric:
case Class::Bard:
case Class::Monk:
return clrbrdmnk_softcaps[level];
case PALADIN:
case SHADOWKNIGHT:
case Class::Paladin:
case Class::ShadowKnight:
return palshd_softcaps[level];
case RANGER:
case Class::Ranger:
return rng_softcaps[level];
case DRUID:
case Class::Druid:
return dru_softcaps[level];
case ROGUE:
case SHAMAN:
case BEASTLORD:
case BERSERKER:
case Class::Rogue:
case Class::Shaman:
case Class::Beastlord:
case Class::Berserker:
return rogshmbstber_softcaps[level];
case NECROMANCER:
case WIZARD:
case MAGICIAN:
case ENCHANTER:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
return necwizmagenc_softcaps[level];
default:
return 350;
@@ -707,28 +707,28 @@ double Mob::GetSoftcapReturns()
// These are based on the dev post, they seem to be correct for every level
// AKA no more hard caps
switch (GetClass()) {
case WARRIOR:
case Class::Warrior:
return 0.35;
case CLERIC:
case BARD:
case MONK:
case Class::Cleric:
case Class::Bard:
case Class::Monk:
return 0.3;
case PALADIN:
case SHADOWKNIGHT:
case Class::Paladin:
case Class::ShadowKnight:
return 0.33;
case RANGER:
case Class::Ranger:
return 0.315;
case DRUID:
case Class::Druid:
return 0.265;
case ROGUE:
case SHAMAN:
case BEASTLORD:
case BERSERKER:
case Class::Rogue:
case Class::Shaman:
case Class::Beastlord:
case Class::Berserker:
return 0.28;
case NECROMANCER:
case WIZARD:
case MAGICIAN:
case ENCHANTER:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
return 0.25;
default:
return 0.3;
@@ -739,7 +739,7 @@ int Mob::GetClassRaceACBonus()
{
int ac_bonus = 0;
auto level = GetLevel();
if (GetClass() == MONK) {
if (GetClass() == Class::Monk) {
int hardcap = 30;
int softcap = 14;
if (level > 99) {
@@ -824,7 +824,7 @@ int Mob::GetClassRaceACBonus()
}
}
if (GetClass() == ROGUE) {
if (GetClass() == Class::Rogue) {
int level_scaler = level - 26;
if (GetAGI() < 80)
ac_bonus = level_scaler / 4;
@@ -840,7 +840,7 @@ int Mob::GetClassRaceACBonus()
ac_bonus = 12;
}
if (GetClass() == BEASTLORD) {
if (GetClass() == Class::Beastlord) {
int level_scaler = level - 6;
if (GetAGI() < 80)
ac_bonus = level_scaler / 5;
@@ -894,14 +894,14 @@ int Mob::ACSum(bool skip_caps)
ac += GetPetACBonusFromOwner();
auto spell_aa_ac = aabonuses.AC + spellbonuses.AC;
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;
else
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
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;
else
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;
}
}
else if ((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30) {
else if ((GetClass() == Class::Monk || GetClass() == Class::Beastlord) && GetLevel() >= 30) {
dmg = GetHandToHandDamage();
}
else {
@@ -1199,7 +1199,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in
MagicGloves = gloves->GetItemMagical(true);
}
if (GetClass() == MONK || GetClass() == BEASTLORD) {
if (GetClass() == Class::Monk || GetClass() == Class::Beastlord) {
if (MagicGloves || GetLevel() >= 30) {
dmg = GetHandToHandDamage();
if (hate)
@@ -1295,15 +1295,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
}
else if (level >= 40) {
switch (GetClass()) {
case CLERIC:
case DRUID:
case SHAMAN:
case Class::Cleric:
case Class::Druid:
case Class::Shaman:
cap = 80;
break;
case NECROMANCER:
case WIZARD:
case MAGICIAN:
case ENCHANTER:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
cap = 40;
break;
default:
@@ -1313,15 +1313,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
}
else if (level >= 30) {
switch (GetClass()) {
case CLERIC:
case DRUID:
case SHAMAN:
case Class::Cleric:
case Class::Druid:
case Class::Shaman:
cap = 26;
break;
case NECROMANCER:
case WIZARD:
case MAGICIAN:
case ENCHANTER:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
cap = 18;
break;
default:
@@ -1331,15 +1331,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
}
else if (level >= 20) {
switch (GetClass()) {
case CLERIC:
case DRUID:
case SHAMAN:
case Class::Cleric:
case Class::Druid:
case Class::Shaman:
cap = 20;
break;
case NECROMANCER:
case WIZARD:
case MAGICIAN:
case ENCHANTER:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
cap = 12;
break;
default:
@@ -1349,15 +1349,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
}
else if (level >= 10) {
switch (GetClass()) {
case CLERIC:
case DRUID:
case SHAMAN:
case Class::Cleric:
case Class::Druid:
case Class::Shaman:
cap = 12;
break;
case NECROMANCER:
case WIZARD:
case MAGICIAN:
case ENCHANTER:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
cap = 10;
break;
default:
@@ -1367,15 +1367,15 @@ int64 Mob::DoDamageCaps(int64 base_damage)
}
else {
switch (GetClass()) {
case CLERIC:
case DRUID:
case SHAMAN:
case Class::Cleric:
case Class::Druid:
case Class::Shaman:
cap = 9;
break;
case NECROMANCER:
case WIZARD:
case MAGICIAN:
case ENCHANTER:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
cap = 6;
break;
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" : "");
if (
(IsCasting() && GetClass() != BARD && !IsFromSpell)
(IsCasting() && GetClass() != Class::Bard && !IsFromSpell)
|| ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead))
|| (GetHP() < 0)
|| (!IsAttackAllowed(other))
@@ -1741,8 +1741,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { CastToMob() };
if (parse->EventPlayer(EVENT_DEATH, this, export_string, 0, &args) != 0) {
if (parse->EventPlayer(EVENT_DEATH, this, export_string, 0) != 0) {
if (GetHP() < 0) {
SetHP(0);
}
@@ -1821,7 +1820,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
auto emote_id = killerMob->GetEmoteID();
if (emote_id) {
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid);
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid, this);
}
killerMob->TrySpellOnKill(killed_level, spell);
@@ -2020,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)
*/
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);
}
@@ -2344,7 +2343,7 @@ void NPC::Damage(Mob* other, int64 damage, uint16 spell_id, EQ::skills::SkillTyp
if (!IsEngaged())
zone->AddAggroMob();
if (GetClass() == LDON_TREASURE)
if (GetClass() == Class::LDoNTreasure)
{
if (IsLDoNLocked() && GetLDoNLockedSkill() != LDoNTypeMechanical)
{
@@ -2389,8 +2388,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { CastToMob() };
if (parse->EventNPC(EVENT_DEATH, this, oos, export_string, 0, &args) != 0) {
if (parse->EventNPC(EVENT_DEATH, this, oos, export_string, 0) != 0) {
if (GetHP() < 0) {
SetHP(0);
}
@@ -2407,9 +2405,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
spell,
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { CastToMob() };
if (parse->EventBot(EVENT_DEATH, CastToBot(), oos, export_string, 0, &args) != 0) {
if (parse->EventBot(EVENT_DEATH, CastToBot(), oos, export_string, 0) != 0) {
if (GetHP() < 0) {
SetHP(0);
}
@@ -2465,7 +2461,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
BuffFadeAll();
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));
Animation_Struct* anim = (Animation_Struct*)outapp->pBuffer;
anim->spawnid = GetID();
@@ -2492,7 +2488,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
respawn2->DeathReset(1);
}
if (killer_mob && GetClass() != LDON_TREASURE) {
if (killer_mob && GetClass() != Class::LDoNTreasure) {
hate_list.AddEntToHateList(killer_mob, damage);
}
@@ -2539,7 +2535,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
hate_list.DoFactionHits(GetNPCFactionID(), GetPrimaryFaction(), GetFactionAmount());
}
bool IsLdonTreasure = (GetClass() == LDON_TREASURE);
bool IsLdonTreasure = (GetClass() == Class::LDoNTreasure);
if (give_exp_client && !IsCorpse()) {
Group *kg = entity_list.GetGroupByClient(give_exp_client);
@@ -2705,10 +2701,73 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
}
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;
// 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, killer_mob);
}
}
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, this);
}
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) &&
((killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) ||
(killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient())))
@@ -2740,7 +2799,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
ApplyIllusionToCorpse(illusion_spell_id, corpse);
if (killer != 0 && emoteid != 0)
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid);
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid, killer);
if (killer != 0 && killer->IsClient()) {
corpse->AllowPlayerLoot(killer, 0);
if (killer->IsGrouped()) {
@@ -2818,38 +2877,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
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();
p_depop = true;
@@ -2858,37 +2885,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
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;
}
@@ -3299,14 +3295,14 @@ int Mob::GetHandToHandDamage(void)
7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30
9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40
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)
return 9;
if (level > 62)
return 15;
return mnk_dmg[level];
}
else if (GetClass() == BEASTLORD) {
else if (GetClass() == Class::Beastlord) {
if (level > 49)
return 13;
return bst_dmg[level];
@@ -3358,7 +3354,7 @@ int Mob::GetHandToHandDelay(void)
28, 28, 28, 27, 27, 27, 27, 27, 26, 26, // 61-70
26, 26, 26 }; // 71-73
if (GetClass() == MONK) {
if (GetClass() == Class::Monk) {
// Have a look to see if we have epic fists on
if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50)
return 16;
@@ -3367,7 +3363,7 @@ int Mob::GetHandToHandDelay(void)
return GetRace() == IKSAR ? 21 : 20;
return GetRace() == IKSAR ? mnk_iks_delay[level] : mnk_hum_delay[level];
}
else if (GetClass() == BEASTLORD) {
else if (GetClass() == Class::Beastlord) {
int level = GetLevel();
if (level > 73)
return 25;
@@ -4071,7 +4067,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
}
}
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;
}
@@ -4091,7 +4087,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
IsPlayerRace(GetBaseRace()) &&
RuleI(Combat, FrontalStunImmunityRaces) & GetPlayerRaceBit(GetBaseRace())
) ||
GetBaseRace() == RACE_OGGOK_CITIZEN_93
GetBaseRace() == Race::OggokCitizen
) {
is_immune_to_frontal_stun = true;
}
@@ -4111,7 +4107,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
IsPlayerRace(GetBaseRace()) &&
RuleI(Combat, FrontalStunImmunityRaces) & GetPlayerRaceBit(GetBaseRace())
) ||
GetBaseRace() == RACE_OGGOK_CITIZEN_93
GetBaseRace() == Race::OggokCitizen
)
) {
is_immune_to_frontal_stun = true;
@@ -5057,11 +5053,11 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
// We either require an innate crit chance or some SPA 169 to crit
bool innate_crit = false;
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;
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;
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;
// we have a chance to crit!
@@ -5081,7 +5077,7 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
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
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;
if (crit_chance)
@@ -5105,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);
// 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())) {
int chance = GetLevel() * 12;
if (zone->random.Int(1, 1000) < chance) {
@@ -5288,7 +5284,7 @@ void Mob::DoRiposte(Mob *defender)
if (DoubleRipChance && zone->random.Roll(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]);
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);
@@ -5305,7 +5301,7 @@ void Mob::ApplyMeleeDamageMods(uint16 skill, int64 &damage, Mob *defender, Extra
dmgbonusmod += opts->melee_damage_bonus_flat;
if (defender) {
if (defender->IsOfClientBotMerc() && defender->GetClass() == WARRIOR) {
if (defender->IsOfClientBotMerc() && defender->GetClass() == Class::Warrior) {
dmgbonusmod -= 5;
}
// 168 defensive
@@ -5449,7 +5445,7 @@ const DamageTable &Mob::GetDamageTable() const
{ 415, 15, 40 }, // 105
};
bool monk = GetClass() == MONK;
bool monk = GetClass() == Class::Monk;
bool melee = IsWarriorClass();
// tables caped at 105 for now -- future proofed for a while at least :P
int level = std::min(static_cast<int>(GetLevel()), 105);
@@ -5897,7 +5893,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
// BER weren't parsing the halving
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;
if (hit.damage_done < 1)
@@ -5910,7 +5906,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
if (headshot > 0) {
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)) {
hit.damage_done *= 2;
MessageString(Chat::MeleeCrit, BOW_DOUBLE_DAMAGE);
@@ -5935,7 +5931,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
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;
}
+2 -2
View File
@@ -117,7 +117,7 @@ void Client::CalcBonuses()
// hmm maybe a better way to do this
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;
if (timer != consume_food_timer.GetTimerTime())
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.
}
+841 -186
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 MAG_EPIC_1_0 = 28034;
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 MaxSpellTimer = 15;
constexpr int MaxDisciplineTimer = 10;
constexpr int DisciplineReuseStart = MaxSpellTimer + 1;
constexpr int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
constexpr int NegativeItemReuse = -1; // Unlinked timer for items
// nHSND negative Healer/Slower/Nuker/Doter
// pH positive Healer
@@ -222,6 +221,8 @@ public:
void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
bool GetPullingFlag() const { return m_pulling_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);
uint8 GetNumberNeedingHealedInGroup(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 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);
void AddSpellToBotList(
int16 iPriority,
@@ -394,25 +399,20 @@ public:
// Static Class Methods
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 bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined);
static Bot* GetBotByBotClientOwnerAndBotName(Client* c, const std::string& botName);
static void ProcessBotGroupInvite(Client* c, std::string const& 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 LoadAndSpawnAllZonedBots(Client* bot_owner);
static bool GroupHasBot(Group* group);
static Bot* GetFirstBotInGroup(Group* group);
static void ProcessClientZoneChange(Client* botOwner);
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
static void ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite = false);
@@ -604,7 +604,7 @@ public:
void SetBotCharmer(bool c) { _botCharmer = c; }
void SetPetChooser(bool p) { _petChooser = p; }
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) {
if (botStance >= EQ::constants::stancePassive && botStance <= EQ::constants::stanceBurnAE)
_botStance = botStance;
@@ -612,8 +612,23 @@ public:
_botStance = EQ::constants::stancePassive;
}
void SetBotCasterRange(uint32 bot_caster_range) { m_bot_caster_range = bot_caster_range; }
void SetSpellRecastTimer(int timer_index, int32 recast_delay);
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
uint32 GetSpellRecastTimer(uint16 spell_id = 0);
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 SetShowHelm(bool showhelm) { _showhelm = showhelm; }
void SetBeardColor(uint8 value) { beardcolor = value; }
@@ -713,7 +728,8 @@ public:
// New accessors for BotDatabase access
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; }
int32 GetBaseAC() const { return _baseAC; }
int32 GetBaseATK() const { return _baseATK; }
@@ -738,7 +754,7 @@ public:
//Raid additions
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 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_enforced;
std::vector<BotTimer_Struct> bot_timers;
private:
// Class Members
@@ -861,11 +878,11 @@ private:
int32 cur_end;
int32 max_end;
int32 end_regen;
uint32 timers[MaxTimer];
Timer m_evade_timer; // can be moved to pTimers at some point
Timer m_alt_combat_hate_timer;
Timer m_auto_defend_timer;
Timer auto_save_timer;
bool m_dirtyautohaters;
bool m_guard_flag;
bool m_hold_flag;
@@ -874,6 +891,7 @@ private:
bool m_pull_flag;
bool m_pulling_flag;
bool m_returning_flag;
bool is_using_item_click;
eStandingPetOrder m_previous_pet_order;
uint32 m_bot_caster_range;
BotCastingRoles m_CastingRoles;
+1084 -309
View File
File diff suppressed because it is too large Load Diff
+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_caster_range(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_defensive(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_suspend(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_view_combos(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_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_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_list_fail(Client *bot_owner, bcst_list* spell_list, BCEnum::SpType spell_type);
#endif
+79 -56
View File
@@ -24,6 +24,7 @@
#include "../common/repositories/bot_data_repository.h"
#include "../common/repositories/bot_inventories_repository.h"
#include "../common/repositories/bot_timers_repository.h"
#include "zonedb.h"
#include "bot.h"
@@ -141,7 +142,7 @@ bool BotDatabase::LoadBotSpellCastingChances()
if (spell_type_index >= Bot::SPELL_TYPE_COUNT)
continue;
uint8 class_index = Strings::ToInt(row[1]);
if (class_index < WARRIOR || class_index > BERSERKER)
if (class_index < Class::Warrior || class_index > Class::Berserker)
continue;
--class_index;
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();
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(
"SELECT COUNT(`bot_id`) FROM `bot_data` WHERE `owner_id` = {} AND `class` = {}",
owner_id,
@@ -917,45 +918,39 @@ bool BotDatabase::LoadTimers(Bot* bot_inst)
if (!bot_inst)
return false;
query = StringFormat(
"SELECT"
" IfNull(bt.`timer_id`, '0') As timer_id,"
" 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 timers = BotTimersRepository::GetWhere(
database,
fmt::format("bot_id = {}", bot_inst->GetBotID())
);
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
if (!results.RowCount())
return true;
uint32* bot_timers = bot_inst->GetTimers();
if (!bot_timers)
return false;
std::vector<BotTimer_Struct> bot_timers;
int timer_id = 0;
uint32 timer_value = 0;
uint32 max_value = 0;
for (auto row = results.begin(); row != results.end(); ++row) {
timer_id = Strings::ToInt(row[0]) - 1;
timer_value = Strings::ToInt(row[1]);
max_value = Strings::ToInt(row[2]);
BotTimer_Struct t{};
t.timer_id = 0;
t.timer_value = 0;
t.recast_time = 0;
t.is_spell = false;
t.is_disc = false;
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))
bot_timers[timer_id] = timer_value;
for (auto& timer : timers) {
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;
@@ -963,26 +958,56 @@ bool BotDatabase::LoadTimers(Bot* bot_inst)
bool BotDatabase::SaveTimers(Bot* bot_inst)
{
if (!bot_inst)
if (!bot_inst) {
return false;
}
if (!DeleteTimers(bot_inst->GetBotID()))
if (!DeleteTimers(bot_inst->GetBotID())) {
return false;
}
uint32* bot_timers = bot_inst->GetTimers();
if (!bot_timers)
return false;
std::vector<BotTimer_Struct> bot_timers = bot_inst->GetBotTimers();
for (int timer_index = 0; timer_index < MaxTimer; ++timer_index) {
if (bot_timers[timer_index] <= Timer::GetCurrentTime())
continue;
if (bot_timers.empty()) {
return true;
}
query = fmt::format(
"REPLACE INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) VALUES ('{}', '{}', '{}')",
bot_inst->GetBotID(), (timer_index + 1), bot_timers[timer_index]
std::vector<BotTimersRepository::BotTimers> timers;
if (!bot_timers.empty()) {
for (auto & bot_timer : bot_timers) {
if (bot_timer.timer_value <= Timer::GetCurrentTime()) {
continue;
}
auto t = BotTimersRepository::BotTimers{
.bot_id = bot_inst->GetBotID(),
.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());
return false;
}
@@ -993,13 +1018,11 @@ bool BotDatabase::SaveTimers(Bot* bot_inst)
bool BotDatabase::DeleteTimers(const uint32 bot_id)
{
if (!bot_id)
if (!bot_id) {
return false;
}
query = StringFormat("DELETE FROM `bot_timers` WHERE `bot_id` = '%u'", bot_id);
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
BotTimersRepository::DeleteWhere(database, fmt::format("bot_id = {}", bot_id));
return true;
}
@@ -2517,7 +2540,7 @@ uint8 BotDatabase::GetSpellCastingChance(uint8 spell_type_index, uint8 class_ind
{
if (spell_type_index >= Bot::SPELL_TYPE_COUNT)
return 0;
if (class_index >= PLAYER_CLASS_COUNT)
if (class_index >= Class::PLAYER_CLASS_COUNT)
return 0;
if (stance_index >= EQ::constants::STANCE_TYPE_COUNT)
return 0;
+11
View File
@@ -81,4 +81,15 @@ struct BotSpells_Struct {
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
+115 -180
View File
@@ -101,14 +101,14 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
bool Bot::BotCastSong(Mob* tar, uint8 botLevel) {
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;
for (auto botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_OutOfCombatBuffSong);
auto iter : botSongList) {
if (!iter.SpellId)
continue;
if (!CheckSpellRecastTimers(this, iter.SpellIndex))
if (!CheckSpellRecastTimer(iter.SpellId))
continue;
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
continue;
@@ -142,7 +142,7 @@ bool Bot::BotCastCombatSong(Mob* tar, uint8 botLevel) {
auto iter : botSongList) {
if (!iter.SpellId)
continue;
if (!CheckSpellRecastTimers(this, iter.SpellIndex))
if (!CheckSpellRecastTimer(iter.SpellId))
continue;
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
continue;
@@ -169,12 +169,12 @@ bool Bot::BotCastCombatSong(Mob* tar, uint8 botLevel) {
bool Bot::BotCastHateReduction(Mob* tar, uint8 botLevel, const BotSpell& botSpell) {
bool casted_spell = false;
if (GetClass() == BARD) {
if (GetClass() == Class::Bard) {
std::list<BotSpell_wPriority> botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_HateRedux);
for (auto iter : botSongList) {
if (!iter.SpellId)
continue;
if (!CheckSpellRecastTimers(this, iter.SpellIndex))
if (!CheckSpellRecastTimer(iter.SpellId))
continue;
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
continue;
@@ -183,7 +183,7 @@ bool Bot::BotCastHateReduction(Mob* tar, uint8 botLevel, const BotSpell& botSpel
if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0)
continue;
if (IsValidSpellRange(botSpell.SpellId, tar)) {
if (IsValidSpellRange(iter.SpellId, tar)) {
casted_spell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost);
}
if (casted_spell) {
@@ -220,7 +220,7 @@ bool Bot::BotCastCure(Mob* tar, uint8 botClass, BotSpell& botSpell, Raid* raid)
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 (HasGroup()) {
Group const* group = GetGroup();
@@ -301,7 +301,7 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
}
switch (botClass) {
case BARD: {
case Class::Bard: {
// probably needs attackable check
for (
auto botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_Slow);
@@ -312,7 +312,7 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
continue;
}
if (!CheckSpellRecastTimers(this, iter.SpellIndex)) {
if (!CheckSpellRecastTimer(iter.SpellId)) {
continue;
}
@@ -328,7 +328,7 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
continue;
}
if (IsValidSpellRange(botSpell.SpellId, tar)) {
if (IsValidSpellRange(iter.SpellId, tar)) {
casted_spell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost);
}
@@ -339,12 +339,12 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
break;
}
case ENCHANTER: {
case Class::Enchanter: {
botSpell = GetBestBotSpellForMagicBasedSlow(this);
break;
}
case SHAMAN:
case BEASTLORD: {
case Class::Shaman:
case Class::Beastlord: {
botSpell = GetBestBotSpellForDiseaseBasedSlow(this);
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);
}
if (casted_spell && GetClass() != BARD) {
if (casted_spell && GetClass() != Class::Bard) {
if (raid) {
const auto msg = fmt::format("Attempting to slow {}.", tar->GetCleanName());
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;
}
if (GetClass() == BARD) {
if (GetClass() == Class::Bard) {
std::list<BotSpell_wPriority> dotList = GetPrioritizedBotSpellsBySpellType(this, SpellType_DOT);
const int maxDotSelect = 5;
@@ -403,7 +403,7 @@ bool Bot::BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const b
continue;
}
if (CheckSpellRecastTimers(this, s.SpellIndex))
if (CheckSpellRecastTimer(s.SpellId))
{
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;
}
if (CheckSpellRecastTimers(this, s.SpellIndex)) {
if (CheckSpellRecastTimer(s.SpellId)) {
if (!(!tar->IsImmuneToSpell(s.SpellId, this) &&
tar->CanBuffStack(s.SpellId, botLevel, true) >= 0)) {
@@ -447,7 +447,7 @@ bool Bot::BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const b
uint32 TempDontDotMeBefore = tar->DontDotMeBefore();
if (IsValidSpellRange(botSpell.SpellId, tar)) {
if (IsValidSpellRange(s.SpellId, tar)) {
casted_spell = AIDoSpellCast(s.SpellIndex, tar, s.ManaCost, &TempDontDotMeBefore);
}
@@ -569,7 +569,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
(tar == this && spells[s.SpellId].target_type != ST_TargetsTarget) ||
spells[s.SpellId].target_type == ST_Group ||
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->CanBuffStack(s.SpellId, botLevel, true) >= 0
@@ -582,7 +582,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
if (
((IsEffectInSpell(s.SpellId, SE_Levitate) && !zone->CanLevitate()) ||
(IsEffectInSpell(s.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())) &&
(botClass != BARD || !IsSpellUsableInThisZoneType(s.SpellId, zone->GetZoneType()))
(botClass != Class::Bard || !IsSpellUsableInThisZoneType(s.SpellId, zone->GetZoneType()))
) {
continue;
}
@@ -625,7 +625,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
}
}
// 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;
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();
casted_spell = AIDoSpellCast(s.SpellIndex, tar, s.ManaCost, &TempDontBuffMeBefore);
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 casted_spell = false;
if (!IsPet() && !GetPetID() && !IsBotCharmer()) {
if (botClass == WIZARD) {
if (botClass == Class::Wizard) {
auto buffs_max = GetMaxBuffSlots();
auto my_buffs = GetBuffs();
int familiar_buff_slot = -1;
@@ -694,7 +694,7 @@ bool Bot::BotCastPet(Mob* tar, uint8 botClass, BotSpell& botSpell) {
botSpell = GetFirstBotSpellBySpellType(this, SpellType_Pet);
}
else if (botClass == MAGICIAN) {
else if (botClass == Class::Magician) {
botSpell = GetBestBotMagicianPetSpell(this);
}
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 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))) {
return casted_spell;
}
if (botClass == CLERIC || botClass == ENCHANTER)
if (botClass == Class::Cleric || botClass == Class::Enchanter)
{
float manaRatioToCast = 75.0f;
@@ -770,17 +770,17 @@ bool Bot::BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
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)
botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Undead);
else if (tar->GetBodyType() == BT_Summoned || tar->GetBodyType() == BT_Summoned2 || tar->GetBodyType() == BT_Summoned3)
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);
if (botClass == PALADIN) {
if (botClass == Class::Paladin) {
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);
}
@@ -819,7 +819,7 @@ bool Bot::BotCastEscape(Mob*& tar, uint8 botClass, BotSpell& botSpell, uint32 iS
auto hpr = (uint8) GetHPRatio();
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();
}
@@ -835,7 +835,7 @@ bool Bot::BotCastEscape(Mob*& tar, uint8 botClass, BotSpell& botSpell, uint32 iS
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);
}
}
@@ -877,7 +877,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
(tar == this && spells[s.SpellId].target_type != ST_TargetsTarget) ||
spells[s.SpellId].target_type == ST_Group ||
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->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_MovementSpeed) && !zone->CanCastOutdoor())
) &&
(botClass != BARD || !IsSpellUsableInThisZoneType(s.SpellId, zone->GetZoneType()))
(botClass != Class::Bard || !IsSpellUsableInThisZoneType(s.SpellId, zone->GetZoneType()))
) {
continue;
}
@@ -919,7 +919,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
break;
}
if (botClass == ENCHANTER && IsEffectInSpell(s.SpellId, SE_Rune))
if (botClass == Class::Enchanter && IsEffectInSpell(s.SpellId, SE_Rune))
{
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();
@@ -1003,17 +1003,17 @@ bool Bot::BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
isPrimaryHealer = IsGroupHealer();
}
if (hpr < 95 || tar->IsClient() || botClass == BARD) {
if (tar->GetClass() == NECROMANCER && hpr >= 40) {
if (hpr < 95 || tar->IsClient() || botClass == Class::Bard) {
if (tar->GetClass() == Class::Necromancer && hpr >= 40) {
return false;
}
if (tar->GetClass() == SHAMAN && hpr >= 80) {
if (tar->GetClass() == Class::Shaman && hpr >= 80) {
return false;
}
// 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) {
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) {
botSpell = GetBestBotSpellForGroupCompleteHeal(this);
@@ -1119,7 +1119,7 @@ bool Bot::BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
if (!IsValidSpell(botSpell.SpellId)) {
botSpell = GetFirstBotSpellForSingleTargetHeal(this);
}
if (botSpell.SpellId == 0 && botClass == BARD) {
if (botSpell.SpellId == 0 && botClass == Class::Bard) {
botSpell = GetFirstBotSpellBySpellType(this, SpellType_Heal);
}
@@ -1134,11 +1134,11 @@ bool Bot::BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
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);
}
if (casted_spell && botClass != BARD) {
if (casted_spell && botClass != Class::Bard) {
if (IsGroupSpell(botSpell.SpellId)) {
if (HasGroup()) {
Group *group = GetGroup();
@@ -1306,10 +1306,8 @@ bool Bot::AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
SetMana(hasMana);
}
else {
AIBot_spells[i].time_cancast = Timer::GetCurrentTime() + spells[AIBot_spells[i].spellid].recast_time;
if (spells[AIBot_spells[i].spellid].timer_id > 0) {
SetSpellRecastTimer(spells[AIBot_spells[i].spellid].timer_id, spells[AIBot_spells[i].spellid].recast_time);
if (CalcSpellRecastTimer(AIBot_spells[i].spellid) > 0) {
SetSpellRecastTimer(AIBot_spells[i].spellid);
}
}
@@ -1362,9 +1360,9 @@ bool Bot::AI_IdleCastCheck() {
//Ok, IdleCastCheck depends of class.
switch (GetClass()) {
// Healers WITHOUT pets will check if a heal is needed before buffing.
case CLERIC:
case PALADIN:
case RANGER: {
case Class::Cleric:
case Class::Paladin:
case Class::Ranger: {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Heal)) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) {
@@ -1379,10 +1377,10 @@ bool Bot::AI_IdleCastCheck() {
result = true;
break;
}
case MONK:
case ROGUE:
case WARRIOR:
case BERSERKER: {
case Class::Monk:
case Class::Rogue:
case Class::Warrior:
case Class::Berserker: {
if (!AICastSpell(this, 100, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Heal)) {
if (!AICastSpell(this, 100, SpellType_Buff)) {
@@ -1397,10 +1395,10 @@ bool Bot::AI_IdleCastCheck() {
}
// Pets class will first cast their pet, then buffs
case MAGICIAN:
case SHADOWKNIGHT:
case NECROMANCER:
case ENCHANTER: {
case Class::Magician:
case Class::ShadowKnight:
case Class::Necromancer:
case Class::Enchanter: {
if (!AICastSpell(this, 100, SpellType_Pet)) {
if (!AICastSpell(this, 100, SpellType_Cure)) {
if (!AICastSpell(GetPet(), 100, SpellType_Cure)) {
@@ -1417,9 +1415,9 @@ bool Bot::AI_IdleCastCheck() {
result = true;
break;
}
case DRUID:
case SHAMAN:
case BEASTLORD: {
case Class::Druid:
case Class::Shaman:
case Class::Beastlord: {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
if (!AICastSpell(this, 100, SpellType_Pet)) {
if (!AICastSpell(this, 100, SpellType_Heal)) {
@@ -1438,7 +1436,7 @@ bool Bot::AI_IdleCastCheck() {
result = true;
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 (!AICastSpell(this, 100, SpellType_Pet)) {
if (!AICastSpell(this, 100, SpellType_Cure)) {
@@ -1469,7 +1467,7 @@ bool Bot::AI_IdleCastCheck() {
result = true;
break;
}
case BARD: {
case Class::Bard: {
if (pre_combat) {
if (!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Cure)) {
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");
if (botClass == CLERIC) {
if (botClass == Class::Cleric) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Escape), SpellType_Escape)) {
if (!AICastSpell(this, GetChanceToCastBySpellType(SpellType_Heal), 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(this, GetChanceToCastBySpellType(SpellType_Heal), 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_Slow), SpellType_Slow)) {
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(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
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(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
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_Debuff), SpellType_Debuff)) {
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 (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) {
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 (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) {
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(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
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(this, GetChanceToCastBySpellType(SpellType_Pet), SpellType_Pet)) {
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_Escape), SpellType_Escape)) {
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 (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_HateRedux), BotAISpellRange, SpellType_HateRedux)) {
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(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
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(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
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(this, GetChanceToCastBySpellType(SpellType_Heal), SpellType_Heal)) {
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 (!entity_list.Bot_AICheckCloseBeneficialSpells(this, GetChanceToCastBySpellType(SpellType_InCombatBuff), BotAISpellRange, SpellType_InCombatBuff)) {
if (!AICastSpell(GetTarget(), GetChanceToCastBySpellType(SpellType_Debuff), SpellType_Debuff)) {
@@ -2044,7 +2042,7 @@ BotSpell Bot::GetFirstBotSpellBySpellType(Bot* botCaster, uint32 spellType) {
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.SpellIndex = i;
result.ManaCost = botSpellList[i].manacost;
@@ -2069,7 +2067,7 @@ BotSpell Bot::GetBestBotSpellForFastHeal(Bot *botCaster) {
for (auto botSpellListItr : botSpellList) {
// 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.SpellIndex = botSpellListItr.SpellIndex;
result.ManaCost = botSpellListItr.ManaCost;
@@ -2106,7 +2104,7 @@ BotSpell Bot::GetBestBotSpellForHealOverTime(Bot* botCaster) {
if (
botSpellList[i].spellid == botSpellListItr.SpellId &&
(botSpellList[i].type & SpellType_Heal) &&
CheckSpellRecastTimers(botCaster, botSpellListItr.SpellIndex)
botCaster->CheckSpellRecastTimer(botSpellListItr.SpellId)
) {
result.SpellId = botSpellListItr.SpellId;
result.SpellIndex = botSpellListItr.SpellIndex;
@@ -2139,7 +2137,7 @@ BotSpell Bot::GetBestBotSpellForPercentageHeal(Bot *botCaster) {
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.SpellIndex = i;
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) {
// 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.SpellIndex = botSpellListItr->SpellIndex;
result.ManaCost = botSpellListItr->ManaCost;
@@ -2192,7 +2190,7 @@ BotSpell Bot::GetFirstBotSpellForSingleTargetHeal(Bot* botCaster) {
IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) ||
IsFastHealSpell(botSpellListItr->SpellId)
) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) {
result.SpellId = botSpellListItr->SpellId;
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
if (
IsRegularGroupHealSpell(botSpellListItr->SpellId) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2257,7 +2255,7 @@ BotSpell Bot::GetBestBotSpellForGroupHealOverTime(Bot* botCaster) {
if (
botSpellList[i].spellid == botSpellListItr->SpellId &&
(botSpellList[i].type & SpellType_Heal) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) {
result.SpellId = botSpellListItr->SpellId;
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
if (
IsGroupCompleteHealSpell(botSpellListItr->SpellId) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) {
result.SpellId = botSpellListItr->SpellId;
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
if (
IsMesmerizeSpell(botSpellListItr->SpellId) &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2343,7 +2341,7 @@ BotSpell Bot::GetBestBotSpellForMagicBasedSlow(Bot* botCaster) {
if (
IsSlowSpell(botSpellListItr->SpellId) &&
spells[botSpellListItr->SpellId].resist_type == RESIST_MAGIC &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2371,7 +2369,7 @@ BotSpell Bot::GetBestBotSpellForDiseaseBasedSlow(Bot* botCaster) {
if (
IsSlowSpell(botSpellListItr->SpellId) &&
spells[botSpellListItr->SpellId].resist_type == RESIST_DISEASE &&
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
) {
result.SpellId = botSpellListItr->SpellId;
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) {
// 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())) {
result.SpellId = botSpellListItr->SpellId;
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) {
// 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.SpellIndex = botSpellListItr->SpellIndex;
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)
{
// 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.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
bool spellSelected = false;
if (CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) {
if (botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
if (selectLureNuke && (spells[botSpellListItr->SpellId].resist_difficulty < lureResisValue)) {
spellSelected = true;
}
@@ -2682,7 +2680,7 @@ BotSpell Bot::GetDebuffBotSpell(Bot* botCaster, Mob *tar) {
if (((botSpellList[i].type & SpellType_Debuff) || IsDebuffSpell(botSpellList[i].spellid))
&& (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster)
&& tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0)
&& CheckSpellRecastTimers(botCaster, i)) {
&& botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i;
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)))
&& (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster)
&& tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0)
&& CheckSpellRecastTimers(botCaster, i)) {
&& botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i;
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) {
BotSpell selectedBotSpell = *itr;
if (IsGroupSpell(itr->SpellId) && CheckSpellRecastTimers(botCaster, itr->SpellIndex)) {
if (IsGroupSpell(itr->SpellId) && botCaster->CheckSpellRecastTimer(selectedBotSpell.SpellId)) {
if (selectedBotSpell.SpellId == 0)
continue;
if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) {
if (isPoisoned && IsEffectInSpell(selectedBotSpell.SpellId, SE_PoisonCounter)) {
spellSelected = true;
}
else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) {
else if (isDiseased && IsEffectInSpell(selectedBotSpell.SpellId, SE_DiseaseCounter)) {
spellSelected = true;
}
else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) {
else if (isCursed && IsEffectInSpell(selectedBotSpell.SpellId, SE_CurseCounter)) {
spellSelected = true;
}
else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) {
else if (isCorrupted && IsEffectInSpell(selectedBotSpell.SpellId, SE_CorruptionCounter)) {
spellSelected = true;
}
else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) {
else if (IsEffectInSpell(selectedBotSpell.SpellId, SE_DispelDetrimental)) {
spellSelected = true;
}
if (spellSelected)
{
result.SpellId = itr->SpellId;
result.SpellIndex = itr->SpellIndex;
result.ManaCost = itr->ManaCost;
result.SpellId = selectedBotSpell.SpellId;
result.SpellIndex = selectedBotSpell.SpellIndex;
result.ManaCost = selectedBotSpell.ManaCost;
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) {
BotSpell selectedBotSpell = *itr;
if (CheckSpellRecastTimers(botCaster, itr->SpellIndex)) {
if (botCaster->CheckSpellRecastTimer(selectedBotSpell.SpellId)) {
if (selectedBotSpell.SpellId == 0)
continue;
if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) {
if (isPoisoned && IsEffectInSpell(selectedBotSpell.SpellId, SE_PoisonCounter)) {
spellSelected = true;
}
else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) {
else if (isDiseased && IsEffectInSpell(selectedBotSpell.SpellId, SE_DiseaseCounter)) {
spellSelected = true;
}
else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) {
else if (isCursed && IsEffectInSpell(selectedBotSpell.SpellId, SE_CurseCounter)) {
spellSelected = true;
}
else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) {
else if (isCorrupted && IsEffectInSpell(selectedBotSpell.SpellId, SE_CorruptionCounter)) {
spellSelected = true;
}
else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) {
else if (IsEffectInSpell(selectedBotSpell.SpellId, SE_DispelDetrimental)) {
spellSelected = true;
}
if (spellSelected)
{
result.SpellId = itr->SpellId;
result.SpellIndex = itr->SpellIndex;
result.ManaCost = itr->ManaCost;
result.SpellId = selectedBotSpell.SpellId;
result.SpellIndex = selectedBotSpell.SpellIndex;
result.ManaCost = selectedBotSpell.ManaCost;
break;
}
@@ -2859,69 +2857,6 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
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 spell_type_index = SPELL_TYPE_COUNT;
@@ -3000,7 +2935,7 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
return 0;
uint8 class_index = GetClass();
if (class_index > BERSERKER || class_index < WARRIOR)
if (class_index > Class::Berserker || class_index < Class::Warrior)
return 0;
--class_index;
+346 -187
View File
@@ -65,6 +65,7 @@ extern volatile bool RunLoops;
#include "../common/repositories/character_disciplines_repository.h"
#include "../common/repositories/character_data_repository.h"
#include "../common/repositories/discovered_items_repository.h"
#include "../common/repositories/keyring_repository.h"
#include "../common/events/player_events.h"
#include "../common/events/player_event_logs.h"
#include "dialogue_window.h"
@@ -1410,126 +1411,163 @@ void Client::SetMaxHP() {
Save();
}
bool Client::UpdateLDoNPoints(uint32 theme_id, int points) {
/* make sure total stays in sync with individual buckets
m_pp.ldon_points_available = m_pp.ldon_points_guk
+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))
bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
{
if (points < 0) {
if (m_pp.ldon_points_available < (0 - points)) {
return false;
}
}
bool is_loss = false;
switch (theme_id) {
case LDoNThemes::Unused: { // No theme, so distribute evenly across all
int split_points = (points / 5);
int guk_points = (split_points + (points % 5));
int mir_points = split_points;
int mmc_points = split_points;
int ruj_points = split_points;
int tak_points = split_points;
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;
}
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);
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);
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);
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);
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);
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_mir += mir_points;
m_pp.ldon_points_mmc += mmc_points;
m_pp.ldon_points_ruj += ruj_points;
m_pp.ldon_points_tak += tak_points;
points -= split_points;
if (split_points != 0) { // if anything left, recursively loop thru again
UpdateLDoNPoints(0, split_points);
UpdateLDoNPoints(LDoNThemes::Unused, split_points);
}
break;
}
case LDoNThemes::GUK: {
if(points < 0) {
if(m_pp.ldon_points_guk < (0 - points)) {
case LDoNThemes::GUK: {
if (points < 0) {
if (m_pp.ldon_points_guk < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_guk += points;
break;
}
case LDoNThemes::MIR: {
if(points < 0) {
if(m_pp.ldon_points_mir < (0 - points)) {
if (points < 0) {
if (m_pp.ldon_points_mir < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_mir += points;
break;
}
case LDoNThemes::MMC: {
if(points < 0) {
if(m_pp.ldon_points_mmc < (0 - points)) {
if (points < 0) {
if (m_pp.ldon_points_mmc < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_mmc += points;
break;
}
case LDoNThemes::RUJ: {
if(points < 0) {
if(m_pp.ldon_points_ruj < (0 - points)) {
if (points < 0) {
if (m_pp.ldon_points_ruj < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_ruj += points;
break;
}
case LDoNThemes::TAK: {
if(points < 0) {
if(m_pp.ldon_points_tak < (0 - points)) {
if (points < 0) {
if (m_pp.ldon_points_tak < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_tak += points;
break;
}
}
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));
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_guk_points = m_pp.ldon_points_guk;
apus->ldon_mirugal_points = m_pp.ldon_points_mir;
apus->ldon_guk_points = m_pp.ldon_points_guk;
apus->ldon_mirugal_points = m_pp.ldon_points_mir;
apus->ldon_mistmoore_points = m_pp.ldon_points_mmc;
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;
QueuePacket(outapp);
safe_delete(outapp);
return true;
@@ -2262,10 +2300,10 @@ void Client::QuestReadBook(const char* text, uint8 type) {
uint32 Client::GetCarriedPlatinum() {
return (
GetMoney(3, 0) +
(GetMoney(2, 0) / 10) +
(GetMoney(1, 0) / 100) +
(GetMoney(0, 0) / 1000)
GetMoney(MoneyTypes::Platinum, MoneySubtypes::Personal) +
(GetMoney(MoneyTypes::Gold, MoneySubtypes::Personal) / 10) +
(GetMoney(MoneyTypes::Silver, MoneySubtypes::Personal) / 100) +
(GetMoney(MoneyTypes::Copper, MoneySubtypes::Personal) / 1000)
);
}
@@ -2675,7 +2713,7 @@ bool Client::HasSkill(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;
return(content_db.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)) > 0);
@@ -2683,7 +2721,7 @@ bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) 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;
return(content_db.GetSkillCap(class_, skillid, level));
@@ -2691,7 +2729,7 @@ uint16 Client::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 lev
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;
return(content_db.GetTrainLevel(class_, skillid, RuleI(Character, MaxLevel)));
@@ -3027,7 +3065,7 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
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;
}
@@ -3076,9 +3114,9 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
else {
int percent_base = 50;
if (GetRawSkill(EQ::skills::SkillBindWound) > 200) {
if ((GetClass() == MONK) || (GetClass() == BEASTLORD))
if ((GetClass() == Class::Monk) || (GetClass() == Class::Beastlord))
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;
}
@@ -4087,54 +4125,87 @@ void Client::SendWindow(
void Client::KeyRingLoad()
{
std::string query = StringFormat("SELECT item_id FROM keyring "
"WHERE char_id = '%i' ORDER BY item_id", character_id);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
const auto &l = KeyringRepository::GetWhere(
database,
fmt::format(
"`char_id` = {} ORDER BY `item_id`",
character_id
)
);
if (l.empty()) {
return;
}
for (auto row = results.begin(); row != results.end(); ++row)
keyring.push_back(Strings::ToInt(row[0]));
for (const auto &e : l) {
keyring.emplace_back(e.item_id);
}
}
void Client::KeyRingAdd(uint32 item_id)
{
if(0==item_id)
return;
bool found = KeyRingCheck(item_id);
if (found)
return;
std::string query = StringFormat("INSERT INTO keyring(char_id, item_id) VALUES(%i, %i)", character_id, item_id);
auto results = database.QueryDatabase(query);
if (!results.Success()) {
if (!item_id) {
return;
}
Message(Chat::LightBlue,"Added to keyring.");
const bool found = KeyRingCheck(item_id);
if (found) {
return;
}
keyring.push_back(item_id);
auto e = KeyringRepository::NewEntity();
e.char_id = CharacterID();
e.item_id = item_id;
e = KeyringRepository::InsertOne(database, e);
if (!e.id) {
return;
}
keyring.emplace_back(item_id);
if (!RuleB(World, UseItemLinksForKeyRing)) {
Message(Chat::LightBlue, "Added to keyring.");
return;
}
const std::string &item_link = database.CreateItemLink(item_id);
Message(
Chat::LightBlue,
fmt::format(
"Added {} to keyring.",
item_link
).c_str()
);
}
bool Client::KeyRingCheck(uint32 item_id)
{
for (auto iter = keyring.begin(); iter != keyring.end(); ++iter) {
if(*iter == item_id)
for (const auto &e : keyring) {
if (e == item_id) {
return true;
}
}
return false;
}
void Client::KeyRingList()
{
Message(Chat::LightBlue,"Keys on Keyring:");
Message(Chat::LightBlue, "Keys on Keyring:");
const EQ::ItemData *item = nullptr;
for (auto iter = keyring.begin(); iter != keyring.end(); ++iter) {
if ((item = database.GetItem(*iter))!=nullptr) {
Message(Chat::LightBlue,item->Name);
for (const auto &e : keyring) {
item = database.GetItem(e);
if (item) {
const std::string &item_string = RuleB(World, UseItemLinksForKeyRing) ? database.CreateItemLink(e) : item->Name;
Message(Chat::LightBlue, item_string.c_str());
}
}
}
@@ -4198,7 +4269,7 @@ void Client::UpdateLFP() {
for(unsigned int i=0; i<MAX_GROUP_MEMBERS; i++) {
LFPMembers[i].Name[0] = '\0';
LFPMembers[i].Class = NO_CLASS;
LFPMembers[i].Class = Class::None;
LFPMembers[i].Level = 0;
LFPMembers[i].Zone = 0;
}
@@ -4815,7 +4886,7 @@ void Client::HandleLDoNOpen(NPC *target)
{
if(target)
{
if(target->GetClass() != LDON_TREASURE)
if(target->GetClass() != Class::LDoNTreasure)
{
LogDebug("[{}] tried to open [{}] but [{}] was not a treasure chest",
GetName(), target->GetName(), target->GetName());
@@ -4884,7 +4955,7 @@ void Client::HandleLDoNOpen(NPC *target)
void Client::HandleLDoNSenseTraps(NPC *target, uint16 skill, uint8 type)
{
if(target && target->GetClass() == LDON_TREASURE)
if(target && target->GetClass() == Class::LDoNTreasure)
{
if(target->IsLDoNTrapped())
{
@@ -4927,7 +4998,7 @@ void Client::HandleLDoNDisarm(NPC *target, uint16 skill, uint8 type)
{
if(target)
{
if(target->GetClass() == LDON_TREASURE)
if(target->GetClass() == Class::LDoNTreasure)
{
if(!target->IsLDoNTrapped())
{
@@ -4977,7 +5048,7 @@ void Client::HandleLDoNPickLock(NPC *target, uint16 skill, uint8 type)
{
if(target)
{
if(target->GetClass() == LDON_TREASURE)
if(target->GetClass() == Class::LDoNTreasure)
{
if(target->IsLDoNTrapped())
{
@@ -5656,26 +5727,89 @@ void Client::AddPVPPoints(uint32 Points)
SendPVPStats();
}
void Client::AddCrystals(uint32 radiant, uint32 ebon)
{
m_pp.currentRadCrystals += radiant;
m_pp.careerRadCrystals += radiant;
m_pp.currentEbonCrystals += ebon;
m_pp.careerEbonCrystals += ebon;
void Client::AddEbonCrystals(uint32 amount, bool is_reclaim) {
m_pp.currentEbonCrystals += amount;
m_pp.careerEbonCrystals += amount;
SaveCurrency();
SendCrystalCounts();
// newer clients handle message client side (older clients likely used eqstr 5967 and 5968, this matches live)
if (radiant > 0)
{
MessageString(Chat::Yellow, YOU_RECEIVE, fmt::format("{} Radiant Crystals", radiant).c_str());
}
MessageString(
Chat::Yellow,
YOU_RECEIVE,
fmt::format(
"{} {}",
amount,
database.CreateItemLink(RuleI(Zone, EbonCrystalItemID))
).c_str()
);
if (ebon > 0)
{
MessageString(Chat::Yellow, YOU_RECEIVE, fmt::format("{} Ebon Crystals", ebon).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::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);
}
}
@@ -6038,7 +6172,7 @@ void Client::CheckEmoteHail(NPC* n, const char* message)
const auto emote_id = n->GetEmoteID();
if (emote_id) {
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id);
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id, this);
}
}
@@ -6420,11 +6554,10 @@ void Client::SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount)
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 */
if (method == 1){
if (is_scripted) {
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
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());
@@ -6432,32 +6565,47 @@ int Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 met
}
}
if(amount == 0) {
if (!amount) {
return 0;
}
if(!alternate_currency_loaded) {
if (!alternate_currency_loaded) {
alternate_currency_queued_operations.push(std::make_pair(currency_id, amount));
return 0;
}
int new_value = 0;
auto iter = alternate_currency.find(currency_id);
if(iter == alternate_currency.end()) {
if (iter == alternate_currency.end()) {
new_value = amount;
} else {
new_value = (*iter).second + amount;
}
if(new_value < 0) {
if (new_value < 0) {
new_value = 0;
alternate_currency[currency_id] = 0;
database.UpdateAltCurrencyValue(CharacterID(), currency_id, 0);
} else {
alternate_currency[currency_id] = new_value;
database.UpdateAltCurrencyValue(CharacterID(), currency_id, new_value);
}
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;
}
@@ -8119,16 +8267,17 @@ void Client::SendHPUpdateMarquee(){
uint32 Client::GetMoney(uint8 type, uint8 subtype) {
uint32 value = 0;
switch (type) {
case 0: {
case MoneyTypes::Copper: {
switch (subtype) {
case 0:
case MoneySubtypes::Personal:
value = static_cast<uint32>(m_pp.copper);
break;
case 1:
case MoneySubtypes::Bank:
value = static_cast<uint32>(m_pp.copper_bank);
break;
case 2:
case MoneySubtypes::Cursor:
value = static_cast<uint32>(m_pp.copper_cursor);
break;
default:
@@ -8136,15 +8285,15 @@ uint32 Client::GetMoney(uint8 type, uint8 subtype) {
}
break;
}
case 1: {
case MoneyTypes::Silver: {
switch (subtype) {
case 0:
case MoneySubtypes::Personal:
value = static_cast<uint32>(m_pp.silver);
break;
case 1:
case MoneySubtypes::Bank:
value = static_cast<uint32>(m_pp.silver_bank);
break;
case 2:
case MoneySubtypes::Cursor:
value = static_cast<uint32>(m_pp.silver_cursor);
break;
default:
@@ -8152,15 +8301,15 @@ uint32 Client::GetMoney(uint8 type, uint8 subtype) {
}
break;
}
case 2: {
case MoneyTypes::Gold: {
switch (subtype) {
case 0:
case MoneySubtypes::Personal:
value = static_cast<uint32>(m_pp.gold);
break;
case 1:
case MoneySubtypes::Bank:
value = static_cast<uint32>(m_pp.gold_bank);
break;
case 2:
case MoneySubtypes::Cursor:
value = static_cast<uint32>(m_pp.gold_cursor);
break;
default:
@@ -8168,18 +8317,18 @@ uint32 Client::GetMoney(uint8 type, uint8 subtype) {
}
break;
}
case 3: {
case MoneyTypes::Platinum: {
switch (subtype) {
case 0:
case MoneySubtypes::Personal:
value = static_cast<uint32>(m_pp.platinum);
break;
case 1:
case MoneySubtypes::Bank:
value = static_cast<uint32>(m_pp.platinum_bank);
break;
case 2:
case MoneySubtypes::Cursor:
value = static_cast<uint32>(m_pp.platinum_cursor);
break;
case 3:
case MoneySubtypes::SharedBank:
value = static_cast<uint32>(m_pp.platinum_shared);
break;
default:
@@ -8190,6 +8339,7 @@ uint32 Client::GetMoney(uint8 type, uint8 subtype) {
default:
break;
}
return value;
}
@@ -8482,8 +8632,8 @@ void Client::InitInnates()
m_pp.InnateSkills[InnateInspect] = InnateEnabled;
m_pp.InnateSkills[InnateOpen] = InnateEnabled;
if (race >= RT_FROGLOK_3) {
if (race == RT_SKELETON_2 || race == RT_FROGLOK_3) {
if (race >= Race::Froglok2) {
if (race == Race::Skeleton2 || race == Race::Froglok2) {
m_pp.InnateSkills[InnateUltraVision] = InnateEnabled;
} else {
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
@@ -8491,75 +8641,75 @@ void Client::InitInnates()
}
switch (race) {
case RT_BARBARIAN:
case RT_BARBARIAN_2:
case Race::Barbarian:
case Race::HalasCitizen:
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
break;
case RT_ERUDITE:
case RT_ERUDITE_2:
case Race::Erudite:
case Race::EruditeCitizen:
m_pp.InnateSkills[InnateLore] = InnateEnabled;
break;
case RT_WOOD_ELF:
case RT_GUARD_3:
case Race::WoodElf:
case Race::Fayguard:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_GNOME:
case RT_HIGH_ELF:
case RT_GUARD_2:
case Race::Gnome:
case Race::HighElf:
case Race::Felguard:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
m_pp.InnateSkills[InnateLore] = InnateEnabled;
break;
case RT_TROLL:
case RT_TROLL_2:
case Race::Troll:
case Race::GrobbCitizen:
m_pp.InnateSkills[InnateRegen] = InnateEnabled;
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_DWARF:
case RT_DWARF_2:
case Race::Dwarf:
case Race::KaladimCitizen:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_OGRE:
case RT_OGRE_2:
case Race::Ogre:
case Race::OggokCitizen:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
m_pp.InnateSkills[InnateNoBash] = InnateEnabled;
m_pp.InnateSkills[InnateBashDoor] = InnateEnabled;
break;
case RT_HALFLING:
case RT_HALFLING_2:
case Race::Halfling:
case Race::RivervaleCitizen:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_IKSAR:
case Race::Iksar:
m_pp.InnateSkills[InnateRegen] = InnateEnabled;
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_VAH_SHIR:
case Race::VahShir:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_DARK_ELF:
case RT_DARK_ELF_2:
case RT_VAMPIRE_2:
case RT_FROGLOK_2:
case RT_GHOST:
case RT_GHOUL:
case RT_SKELETON:
case RT_VAMPIRE:
case RT_WILL_O_WISP:
case RT_ZOMBIE:
case RT_SPECTRE:
case RT_GHOST_2:
case RT_GHOST_3:
case RT_DRAGON_2:
case RT_INNORUUK:
case Race::DarkElf:
case Race::NeriakCitizen:
case Race::ElfVampire:
case Race::FroglokGhoul:
case Race::Ghost:
case Race::Ghoul:
case Race::Skeleton:
case Race::Vampire:
case Race::Wisp:
case Race::Zombie:
case Race::Spectre:
case Race::DwarfGhost:
case Race::EruditeGhost:
case Race::DragonSkeleton:
case Race::Innoruuk:
m_pp.InnateSkills[InnateUltraVision] = InnateEnabled;
break;
case RT_HUMAN:
case RT_GUARD:
case RT_BEGGAR:
case RT_HUMAN_2:
case RT_HUMAN_3:
case RT_FROGLOK_3: // client does froglok weird, but this should work out fine
case Race::Human:
case Race::FreeportGuard:
case Race::HumanBeggar:
case Race::HighpassCitizen:
case Race::QeynosCitizen:
case Race::Froglok2: // client does froglok weird, but this should work out fine
break;
default:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
@@ -8567,20 +8717,20 @@ void Client::InitInnates()
}
switch (class_) {
case DRUID:
case Class::Druid:
m_pp.InnateSkills[InnateHarmony] = InnateEnabled;
break;
case BARD:
case Class::Bard:
m_pp.InnateSkills[InnateReveal] = InnateEnabled;
break;
case ROGUE:
case Class::Rogue:
m_pp.InnateSkills[InnateSurprise] = InnateEnabled;
m_pp.InnateSkills[InnateReveal] = InnateEnabled;
break;
case RANGER:
case Class::Ranger:
m_pp.InnateSkills[InnateAwareness] = InnateEnabled;
break;
case MONK:
case Class::Monk:
m_pp.InnateSkills[InnateSurprise] = InnateEnabled;
m_pp.InnateSkills[InnateAwareness] = InnateEnabled;
default:
@@ -9718,7 +9868,7 @@ std::vector<int> Client::GetLearnableDisciplines(uint8 min_level, uint8 max_leve
continue;
}
if (spells[spell_id].classes[WARRIOR] == 0) {
if (spells[spell_id].classes[Class::Warrior] == 0) {
continue;
}
@@ -9789,7 +9939,7 @@ std::vector<int> Client::GetScribeableSpells(uint8 min_level, uint8 max_level) {
continue;
}
if (spells[spell_id].classes[WARRIOR] == 0) {
if (spells[spell_id].classes[Class::Warrior] == 0) {
continue;
}
@@ -10353,6 +10503,16 @@ void Client::SetDoorToolEntityId(uint16 door_tool_entity_id)
Client::m_door_tool_entity_id = door_tool_entity_id;
}
uint16 Client::GetObjectToolEntityId() const
{
return m_object_tool_entity_id;
}
void Client::SetObjectToolEntityId(uint16 object_tool_entity_id)
{
Client::m_object_tool_entity_id = object_tool_entity_id;
}
int Client::GetIPExemption()
{
return database.GetIPExemption(GetIPString());
@@ -10648,37 +10808,37 @@ uint16 Client::LearnDisciplines(uint8 min_level, uint8 max_level)
uint16 Client::GetClassTrackingDistanceMultiplier(uint16 class_) {
switch (class_) {
case WARRIOR:
case Class::Warrior:
return RuleI(Character, WarriorTrackingDistanceMultiplier);
case CLERIC:
case Class::Cleric:
return RuleI(Character, ClericTrackingDistanceMultiplier);
case PALADIN:
case Class::Paladin:
return RuleI(Character, PaladinTrackingDistanceMultiplier);
case RANGER:
case Class::Ranger:
return RuleI(Character, RangerTrackingDistanceMultiplier);
case SHADOWKNIGHT:
case Class::ShadowKnight:
return RuleI(Character, ShadowKnightTrackingDistanceMultiplier);
case DRUID:
case Class::Druid:
return RuleI(Character, DruidTrackingDistanceMultiplier);
case MONK:
case Class::Monk:
return RuleI(Character, MonkTrackingDistanceMultiplier);
case BARD:
case Class::Bard:
return RuleI(Character, BardTrackingDistanceMultiplier);
case ROGUE:
case Class::Rogue:
return RuleI(Character, RogueTrackingDistanceMultiplier);
case SHAMAN:
case Class::Shaman:
return RuleI(Character, ShamanTrackingDistanceMultiplier);
case NECROMANCER:
case Class::Necromancer:
return RuleI(Character, NecromancerTrackingDistanceMultiplier);
case WIZARD:
case Class::Wizard:
return RuleI(Character, WizardTrackingDistanceMultiplier);
case MAGICIAN:
case Class::Magician:
return RuleI(Character, MagicianTrackingDistanceMultiplier);
case ENCHANTER:
case Class::Enchanter:
return RuleI(Character, EnchanterTrackingDistanceMultiplier);
case BEASTLORD:
case Class::Beastlord:
return RuleI(Character, BeastlordTrackingDistanceMultiplier);
case BERSERKER:
case Class::Berserker:
return RuleI(Character, BerserkerTrackingDistanceMultiplier);
default:
return 0;
@@ -11125,16 +11285,15 @@ void Client::AddAAPoints(uint32 points)
{
m_pp.aapoints += points;
if (points == 1 && m_pp.aapoints == 1)
{
if (parse->PlayerHasQuestSub(EVENT_AA_GAIN)) {
parse->EventPlayer(EVENT_AA_GAIN, this, std::to_string(points), 0);
}
if (points == 1 && m_pp.aapoints == 1) {
MessageString(Chat::Yellow, GAIN_SINGLE_AA_SINGLE_AA, fmt::format_int(m_pp.aapoints).c_str());
}
else if (points == 1 && m_pp.aapoints > 1)
{
} else if (points == 1 && m_pp.aapoints > 1) {
MessageString(Chat::Yellow, GAIN_SINGLE_AA_MULTI_AA, fmt::format_int(m_pp.aapoints).c_str());
}
else
{
} else {
MessageString(Chat::Yellow, GAIN_MULTI_AA_MULTI_AA, fmt::format_int(points).c_str(), fmt::format_int(m_pp.aapoints).c_str());
}
+21 -9
View File
@@ -611,11 +611,14 @@ public:
void SetPVPPoints(uint32 Points) { m_pp.PVPCurrentPoints = Points; }
uint32 GetPVPPoints() { return m_pp.PVPCurrentPoints; }
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; }
void SetRadiantCrystals(uint32 value);
uint32 GetEbonCrystals() { return m_pp.currentEbonCrystals; }
void SetEbonCrystals(uint32 value);
void AddCrystals(uint32 Radiant, uint32 Ebon);
void SendCrystalCounts();
uint64 GetExperienceForKill(Mob *against);
@@ -908,6 +911,7 @@ public:
void AutoGrantAAPoints();
void GrantAllAAPoints(uint8 unlock_level = 0);
bool HasAlreadyPurchasedRank(AA::Rank* rank);
void ListPurchasedAAs(Client *to, std::string search_criteria = std::string());
bool SendGMCommand(std::string message, bool ignore_status = false);
@@ -978,6 +982,7 @@ public:
void PutLootInInventory(int16 slot_id, const EQ::ItemInstance &inst, ServerLootItem_Struct** bag_item_data = 0);
bool AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0);
bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = EQ::invslot::slotCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);
void SummonItemIntoInventory(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool is_attuned = false);
void SummonBaggedItems(uint32 bag_item_id, const std::vector<ServerLootItem_Struct>& bag_items);
void SetStats(uint8 type,int16 set_val);
void IncStats(uint8 type,int16 increase_val);
@@ -1274,6 +1279,10 @@ public:
}
else { return 0; }
}
inline bool CompleteTask(uint32 task_id)
{
return task_state ? task_state->CompleteTask(this, task_id) : false;
}
inline void FailTask(int task_id) { if (task_state) { task_state->FailTask(this, task_id); }}
inline int TaskTimeLeft(int task_id) { return (task_state ? task_state->TaskTimeLeft(task_id) : 0); }
inline int EnabledTaskCount(int task_set_id)
@@ -1488,7 +1497,7 @@ public:
void ConsentCorpses(std::string consent_name, bool deny = false);
void SendAltCurrencies();
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 SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null = true);
uint32 GetAlternateCurrencyValue(uint32 currency_id) const;
@@ -1809,9 +1818,12 @@ private:
bool dev_tools_enabled;
uint16 m_door_tool_entity_id;
uint16 m_object_tool_entity_id;
public:
uint16 GetDoorToolEntityId() const;
void SetDoorToolEntityId(uint16 door_tool_entity_id);
uint16 GetObjectToolEntityId() const;
void SetObjectToolEntityId(uint16 object_tool_entity_id);
private:
int32 max_end;
@@ -2037,14 +2049,14 @@ public:
bool GetBotPrecombat() { return m_bot_precombat; }
void SetBotPrecombat(bool flag = true) { m_bot_precombat = flag; }
int GetBotRequiredLevel(uint8 class_id = NO_CLASS);
uint32 GetBotCreationLimit(uint8 class_id = NO_CLASS);
int GetBotSpawnLimit(uint8 class_id = NO_CLASS);
void SetBotCreationLimit(uint32 new_creation_limit, uint8 class_id = NO_CLASS);
void SetBotRequiredLevel(int new_required_level, uint8 class_id = NO_CLASS);
void SetBotSpawnLimit(int new_spawn_limit, uint8 class_id = NO_CLASS);
int GetBotRequiredLevel(uint8 class_id = Class::None);
uint32 GetBotCreationLimit(uint8 class_id = Class::None);
int GetBotSpawnLimit(uint8 class_id = Class::None);
void SetBotCreationLimit(uint32 new_creation_limit, uint8 class_id = Class::None);
void SetBotRequiredLevel(int new_required_level, uint8 class_id = Class::None);
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);
private:
+29 -29
View File
@@ -345,7 +345,7 @@ uint32 Mob::GetClassLevelFactor()
uint32 multiplier = 0;
uint8 mlevel = GetLevel();
switch (GetClass()) {
case WARRIOR: {
case Class::Warrior: {
if (mlevel < 20) {
multiplier = 220;
}
@@ -372,9 +372,9 @@ uint32 Mob::GetClassLevelFactor()
}
break;
}
case DRUID:
case CLERIC:
case SHAMAN: {
case Class::Druid:
case Class::Cleric:
case Class::Shaman: {
if (mlevel < 70) {
multiplier = 150;
}
@@ -383,9 +383,9 @@ uint32 Mob::GetClassLevelFactor()
}
break;
}
case BERSERKER:
case PALADIN:
case SHADOWKNIGHT: {
case Class::Berserker:
case Class::Paladin:
case Class::ShadowKnight: {
if (mlevel < 35) {
multiplier = 210;
}
@@ -409,10 +409,10 @@ uint32 Mob::GetClassLevelFactor()
}
break;
}
case MONK:
case BARD:
case ROGUE:
case BEASTLORD: {
case Class::Monk:
case Class::Bard:
case Class::Rogue:
case Class::Beastlord: {
if (mlevel < 51) {
multiplier = 180;
}
@@ -427,7 +427,7 @@ uint32 Mob::GetClassLevelFactor()
}
break;
}
case RANGER: {
case Class::Ranger: {
if (mlevel < 58) {
multiplier = 200;
}
@@ -439,10 +439,10 @@ uint32 Mob::GetClassLevelFactor()
}
break;
}
case MAGICIAN:
case WIZARD:
case NECROMANCER:
case ENCHANTER: {
case Class::Magician:
case Class::Wizard:
case Class::Necromancer:
case Class::Enchanter: {
if (mlevel < 70) {
multiplier = 120;
}
@@ -677,7 +677,7 @@ int64 Client::CalcManaRegen(bool bCombat)
if (IsSitting() || CanMedOnHorse()) {
// kind of weird to do it here w/e
// client does some base medding regen for shrouds here
if (GetClass() != BARD) {
if (GetClass() != Class::Bard) {
auto skill = GetSkill(EQ::skills::SkillMeditate);
if (skill > 0) {
regen++;
@@ -1077,7 +1077,7 @@ int32 Client::CalcMR()
MR = 20;
}
MR += itembonuses.MR + spellbonuses.MR + aabonuses.MR;
if (GetClass() == WARRIOR || GetClass() == BERSERKER) {
if (GetClass() == Class::Warrior || GetClass() == Class::Berserker) {
MR += GetLevel() / 2;
}
if (MR < 1) {
@@ -1151,14 +1151,14 @@ int32 Client::CalcFR()
FR = 20;
}
int c = GetClass();
if (c == RANGER) {
if (c == Class::Ranger) {
FR += 4;
int l = GetLevel();
if (l > 49) {
FR += l - 49;
}
}
if (c == MONK) {
if (c == Class::Monk) {
FR += 8;
int l = GetLevel();
if (l > 49) {
@@ -1238,19 +1238,19 @@ int32 Client::CalcDR()
}
int c = GetClass();
// the monk one is part of base resist
if (c == MONK) {
if (c == Class::Monk) {
int l = GetLevel();
if (l > 50)
DR += l - 50;
}
if (c == PALADIN) {
if (c == Class::Paladin) {
DR += 8;
int l = GetLevel();
if (l > 49) {
DR += l - 49;
}
}
else if (c == SHADOWKNIGHT || c == BEASTLORD) {
else if (c == Class::ShadowKnight || c == Class::Beastlord) {
DR += 4;
int l = GetLevel();
if (l > 49) {
@@ -1330,19 +1330,19 @@ int32 Client::CalcPR()
}
int c = GetClass();
// this monk bonus is part of the base
if (c == MONK) {
if (c == Class::Monk) {
int l = GetLevel();
if (l > 50)
PR += l - 50;
}
if (c == ROGUE) {
if (c == Class::Rogue) {
PR += 8;
int l = GetLevel();
if (l > 49) {
PR += l - 49;
}
}
else if (c == SHADOWKNIGHT) {
else if (c == Class::ShadowKnight) {
PR += 4;
int l = GetLevel();
if (l > 49) {
@@ -1421,7 +1421,7 @@ int32 Client::CalcCR()
CR = 25;
}
int c = GetClass();
if (c == RANGER || c == BEASTLORD) {
if (c == Class::Ranger || c == Class::Beastlord) {
CR += 4;
int l = GetLevel();
if (l > 49) {
@@ -1455,7 +1455,7 @@ int32 Client::CalcATK()
uint32 Mob::GetInstrumentMod(uint16 spell_id)
{
if (GetClass() != BARD) {
if (GetClass() != Class::Bard) {
//Other classes can get a base effects mod using SPA 413
if (HasBaseEffectFocus()) {
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();
auto level = GetLevel();
if (GetClass() == MONK) {
if (GetClass() == Class::Monk) {
if (level > 99)
weight_limit = 58;
else if (level > 94)
+274 -256
View File
File diff suppressed because it is too large Load Diff
+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)) {
entity_list.MessageCloseString(this, false, 200, 0, BERSERK_START, GetName());
berserk = true;
@@ -1121,7 +1121,7 @@ void Client::OPMemorizeSpell(const EQApplicationPacket* app)
if (
m->scribing != memSpellForget &&
(
!EQ::ValueWithin(GetClass(), PLAYER_CLASS_WARRIOR, PLAYER_CLASS_BERSERKER) ||
!IsPlayerClass(GetClass()) ||
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);
if(!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < WARRIORGM || pTrainer->GetClass() > BERSERKERGM)
if(!pTrainer || !pTrainer->IsNPC() || pTrainer->GetClass() < Class::WarriorGM || pTrainer->GetClass() > Class::BerserkerGM)
return;
//you can only use your own trainer, client enforces this, but why trust it
if (!RuleB(Character, AllowCrossClassTrainers)) {
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR);
int trains_class = pTrainer->GetClass() - (Class::WarriorGM - Class::Warrior);
if (GetClass() != trains_class)
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::Skill2HPiercing] = 0;
}
@@ -1607,12 +1607,12 @@ void Client::OPGMEndTraining(const EQApplicationPacket *app)
FastQueuePacket(&outapp);
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;
//you can only use your own trainer, client enforces this, but why trust it
if (!RuleB(Character, AllowCrossClassTrainers)) {
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR);
int trains_class = pTrainer->GetClass() - (Class::WarriorGM - Class::Warrior);
if (GetClass() != trains_class)
return;
}
@@ -1638,12 +1638,12 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
GMSkillChange_Struct* gmskill = (GMSkillChange_Struct*) app->pBuffer;
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;
//you can only use your own trainer, client enforces this, but why trust it
if (!RuleB(Character, AllowCrossClassTrainers)) {
int trains_class = pTrainer->GetClass() - (WARRIORGM - WARRIOR);
int trains_class = pTrainer->GetClass() - (Class::WarriorGM - Class::Warrior);
if (GetClass() != trains_class)
return;
}

Some files were not shown because too many files have changed in this diff Show More