Compare commits

...

220 Commits

Author SHA1 Message Date
Kinglykrab df746dd07d Add slot ID conversions 2024-11-21 23:29:10 -05:00
Kinglykrab cd158aabca Cleanup 2024-11-21 23:29:10 -05:00
Kinglykrab 95687b57e9 Cleanup 2024-11-21 23:29:10 -05:00
Kinglykrab 77de74a089 Update shareddb.cpp 2024-11-21 23:29:10 -05:00
Kinglykrab 1da7901029 Update worlddb.cpp 2024-11-21 23:29:10 -05:00
Kinglykrab 738a31df51 [Feature] Implement "Big Bags" 2024-11-21 23:29:02 -05:00
Mitch Freeman 62ac015fff [Bug Fix] Fix an edge case with augmented items inside parceled containers (#4546) 2024-11-20 21:17:04 -05:00
Mitch Freeman 4977a7c2e0 [Bazaar] Further refinements for instanced bazaar (#4544)
Resolves
- Parcels being delivered with incorrect item
- Inspecting an item from the bazaar window showing the incorrect item
2024-11-16 15:14:17 -06:00
Mitch Freeman 9967384ab8 [Fix] Fix for mult-instanced bazaar zones (#4541)
* Enable bazaar for multiple instances.

* Enable buyer for multiple instances.

* Update to buyer/barter for multiple instances and attuned items.
2024-11-14 19:44:03 -06:00
Mitch Freeman d3da2e5501 [Fix] Fix for bazaar search of containers. (#4540) 2024-11-14 19:32:19 -06:00
Chris Miles 33f5c4c6a7 [Bug Fix] Fix issue where NPC's are being hidden as traders (#4539)
* [Fix] Fix issue where NPC's are being hidden as traders

* Fix

* Update mob.cpp
2024-11-14 19:15:03 -05:00
Akkadius e4aa6a6957 [Release] 22.59.1 2024-11-13 20:52:46 -06:00
Chris Miles e4d812f4b4 [Release] 22.59.0 (#4538) 2024-11-13 20:08:03 -06:00
hg bcedfe7032 [Quest API] Add Native Database Querying Interface (#4531)
* Add database quest API

API functions are named to be similar to LuaSQL and perl DBI

New connections are made for Database objects. These can either use
credentials from the server eqemu_config or manual connections.

* Add option to use zone db connections
2024-11-12 20:01:18 -06:00
Paul Johnson c1df3fbcb0 [Rules] Add Rule for restricting client versions to world server (#4527)
* add rule for supported clients, unsupported client packet

* whitespace

* PR feedback - Update client.cpp

* PR Feedback - Update client.cpp

* Update client.cpp

* Update client.cpp

---------

Co-authored-by: Paul Johnson <Paul@PJOHNSOMAC-6366.digi.box>
2024-11-12 11:00:22 -05:00
Akkadius 011e1d05e7 [Hotfix] Check if the mob is already in the close mobs list before inserting 2024-11-10 23:19:40 -06:00
Akkadius 3f0f95976c [Hotfix] ScanCloseMobs - Ensure scanning mob has an entity ID 2024-11-10 06:47:42 -06:00
Chris Miles 77de9619b5 [Databuckets] Add database index to data_buckets (#4535)
* [Databuckets] Add database index to data_buckets

* Update database_update_manifest.cpp
2024-11-08 22:26:00 -05:00
Mitch Freeman 20d3ab2ac5 [Bug Fix] Bazaar two edge case issues resolved (#4533)
This update resolves two bazaar issues that have been reported.
- If parcel delivery is used to purchase an item, and the seller has several of the same items, that have various charges, the item would not be removed from the db.  This allowed for incorrect purchases.
- If a player 'reclaims' an alt currency item that they also have for sale with an active trader,  the item would remain for sale, and be reclaimed.  This impacted custom alt currency items that were no trade.
2024-11-08 22:15:12 -05:00
Chris Miles 0ea47fadee [Performance] Improvements to ScanCloseMobs logic (#4534)
* [Performance] Minor improvements to ScanCloseMobs

* Remove timer checks one level up to reduce branching

* Reserve memory in m_close_mobs to avoid frequent re-allocations if not already reserved.
2024-11-08 17:48:39 -06:00
Chris Miles 1ce51ca3b0 [Release] 22.58.0 (#4532) 2024-11-05 22:02:32 -06:00
hg 25ef3d2cdb [Code] Update perlbind to 1.1.0 (#4529)
- Adds a perl::ref alias for perl::reference

- Optimizes array return pushes by accessing SV* values directly instead
  of using operator[] scalar_proxy

- Allows functions with a perl::hash parameter to accept hashes with any
  scalar key type instead of requiring explicit string keys

  e.g., foo(123 => 1) will now work on functions accepting a perl::hash
2024-11-05 20:14:29 -06:00
hg 95249889a6 [Code] Add mysql prepared statement support (#4530)
This adds support for using prepared statements for MySQL queries. It is
intended for use in a database quest API but it can be used in source
with some caveats:

 - It uses exceptions for error handling instead of returning a fake
   result that needs checked. Usage must be wrapped in try/catch.

 - DBcore has a connection mutex which indicates the connection might be
   shared with other threads. This mutex is locked for certain stmt
   operations in an attempt to make it safe to use with multi threaded
   connections.

 - Prepared statements should only be used on the main thread since the
   internal logging is not synchronized.

 - Unlike the current query API which retrieves all results as strings,
   results are stored in buffers that represent the db field type.
   Getter functions are available to retrieve values as desired types.
2024-11-05 20:12:17 -06:00
mmcgarvey 428cccfa50 [Feature] Focus Skill Attack Spells (#4528)
* Add Rule Spells:AllowFocusOnSkillDamageSpells

* Currently, focus mods defaults to 0 when processing spell effect 193.
* The default value for this rule is false.
* When false, the rule will retain the current default behavior.
* When true, the aforementioned focus effects will allow focus effects (185, 459, and 482) to modify spell effect 193.

* Removed undesirable whitespace

* Update spell_effects.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2024-10-31 08:13:16 -04:00
Alex King 41dd8a5754 [Quest API] Add Spawn Circle/Grid Methods to Perl/Lua (#4524)
* [Quest API] Add Spawn Circle/Grid Methods to Perl/Lua

* Update lua_general.cpp

* Update questmgr.cpp

* Update questmgr.cpp
2024-10-23 23:40:25 -04:00
Alex King d02d766563 [Bug Fix] Fix cross_zone_set_entity_variable_by_char_id in Lua (#4526) 2024-10-23 22:47:02 -04:00
Alex King dfd2729b28 [Bug Fix] Add Missing Lua Registers (#4525) 2024-10-23 22:37:21 -04:00
Chris Miles b92eafd21b [Release] 22.57.1 (#4523) 2024-10-22 00:02:14 -05:00
nytmyr d6d5d992cb [Bots] Fix pet buffs from saving duplicates every save (#4520)
* [Bots] Fix pet buffs from saving duplicates every save

Previously we were not checking the pet index properly when clearing buffs in the database before saving which resulted in no prior data being deleted.

This corrects the logic for the save and also will clean up any buffs for pets that don't exist in the table.

* Changes

* Update world_boot.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-10-21 23:57:42 -05:00
Alex King d524cb6a5a [Bots] Enable Bot Commands Only if Rule Enabled (#4519) 2024-10-21 23:49:36 -05:00
Alex e6469878ce [Loginserver] Automatifc Opcode File Creation (#4521)
* Loginserver will auto create the opcodes file if it doesn't exist on load.

* Use path manager in login opcodes.

---------

Co-authored-by: KimLS <KimLS@peqtgc.com>
2024-10-21 23:48:43 -05:00
Chris Miles 9583099ace [Release] 22.57.0 (#4517) 2024-10-20 16:17:15 -05:00
nytmyr cf3483b402 [Bots] Fix timers loading on spawn and zone (#4516)
Timers were not properly checking their expiration time on spawn and load and could cause invalid timers to load if the server was restarted resulting in improper lockouts.
2024-10-20 10:44:30 -04:00
carolus21rex 311af7bbe9 [Cleanup] Fixed a typo in Zoning.cpp (#4515)
* Fixed a typo in Zoning.cpp changed reguest to request.

* Update zoning.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2024-10-19 21:59:10 -04:00
Alex King be42b73f5c [Rules] Add Rule to disable PVP Regions (#4513) 2024-10-17 01:48:19 -05:00
Mitch Freeman f76c798910 [BugFix] Fix a display error regarding a few trader/buyer query errors (#4514) 2024-10-17 01:43:24 -05:00
Alex ae198ae043 [Crash] Fixes a crash when the faction_list db table is empty. (#4511)
Co-authored-by: KimLS <KimLS@peqtgc.com>
2024-10-13 20:50:28 -05:00
Alex King 520943ebf1 [Logs] Add NPC Trades to Player Events (#4505)
* [Logs] Add NPC Trades to Player Events

* Update player_event_discord_formatter.cpp

* Push

* Fix money and add NPC info

* [Logs] Add NPC Trades to Player Events

* Update player_event_discord_formatter.cpp

* Push

* Minor logic fix

* Push

* Update perl_client.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-10-13 17:26:10 -05:00
Fryguy 9ac306fe67 [Bug] FindBestZ selecting false zone floor as bestz - Results in roambox failures (#4504)
Added underworld checks per the EQMac project
2024-10-13 15:53:09 -05:00
Alex King 7a1d69d0d4 [Bug Fix] Fix Spells:DefaultAOEMaxTargets Default Value (#4508) 2024-10-12 14:32:40 -04:00
Alex King c873fe5a22 [Bug Fix] Fix Mercenary Encounter Crash (#4509) 2024-10-11 23:00:09 -04:00
Fryguy e06b0c4b0c [Bug Fix] Master of Disguise should apply to illusions casted by others. (#4506)
Many era comments outline how Master of Disguise would apply to Project Illusion spells on you:

https://thesafehouse.org/forums/forum/everquest-wing/main-lounge/14249-new-aa-master-of-disguise/page4

https://thesafehouse.org/forums/forum/everquest-wing/training-studios/18143-master-of-disguise-broken

```
Im not a big fan of wolf form, but having a 1200 min NDT is pretty nice  I also agree its great to shrink on a raid once and not have to worry about it. 7 aa is a little steep imho, but with a name change and some frog potions, I may reapply to my guild as the servers only froggy rogue /cackle.
```

```
share form of the great wolf gave a 1500min timer.
```
2024-10-11 13:39:36 -04:00
catapultam-habeo ed2130f649 [Bug Fix] Correctly limit max targets of PBAOE (#4507)
* fix pbaoe max targets incorrectly set

* fix scratch copy
2024-10-11 13:15:19 -04:00
Alex King 448a33a60c [Quest API] Add Scripting Support to Mercenaries (#4500)
* [Quest API] Add Scripting Support to Mercenaries

* Cleanup

* Cleanup

* Update lua_merc.h

* Update mob.cpp

* XYZH

* Final

* Update attack.cpp

* Update attack.cpp

* Simplify event invocation

* Inline example

* Nullptr init example

* EVENT_TIMER simplify add EventPlayerNpcBotMerc

* EVENT_TIMER_START

* Remove has_start_event

* EVENT_TIMER_START with settimerMS

* EVENT_POPUP_RESPONSE

* Consolidation

* Update attack.cpp

* Push

* Update quest_parser_collection.h

* Comments

* Cleanup per comments

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-10-10 21:29:29 -04:00
Fryguy 8f86cb353e [Bug Fix] Spells - Self Only (Yellow) cast when non group member is targeted (#4503)
* [Bug Fix] Spells - Self Only (Yellow) cast when non group member is targeted

When using a Yellow gem invis spell, it should cast on yourself regardless of the targetted entity.

* Update spells.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2024-10-10 21:27:49 -04:00
Alex 178129443f [Loginserver] Login Fatal Error Spamming (#4476)
Co-authored-by: KimLS <KimLS@peqtgc.com>
2024-10-09 02:15:49 -05:00
Alex King a7c3b41afc [Quest API] Add Buff Fade Methods to Perl/Lua (#4501)
* [Quest API] Add Buff Fade Methods to Perl/Lua

* BuffFadeSongs()
2024-10-09 02:12:33 -05:00
Alex King a5a568d548 [Bug Fix] Fix character_exp_modifiers Default Values (#4502) 2024-10-09 02:11:57 -05:00
Alex King e3198edb86 [Quest API] Add EVENT_READ_ITEM to Perl/Lua (#4497)
* [Quest API] Add EVENT_READ_ITEM to Perl/Lua

* Add item_id export

* Add item export.

* Update client.cpp
2024-10-08 18:25:14 -04:00
Alex King 8568cf7d49 [Bug Fix] Fix NPC::CanTalk() Crash (#4499)
* [Bug FIx] Fix NPC::CanTalk() Crash

* Update npc.cpp

* Update mob.cpp

* Update npc.cpp
2024-10-07 00:17:49 -05:00
Alex King 1fb7a860a1 [Bug Fix] Fix #set motd Crash (#4495) 2024-10-05 07:58:22 -05:00
nytmyr 7eaee2649e [Bots] Add "silent" option to ^spawn and mute raid spawn (#4494)
When zoning or forming a raid, bots would spam their spawn message. They will now be muted.

Adds an optional argument "silent" to the ^spawn command. This will bypass ^oo spawnmessage settings and not send a spawn message. Example: ^spawn Warbot silent
2024-10-04 20:20:52 -04:00
Alex King a17f467b98 [Quest API] Add NPC List Filter Methods to Perl/Lua (#4493)
* [Quest API] Add GetNPCsByNPCIDs to Perl/Lua

* Push

* Update entity.cpp

* Separate methods.
2024-10-03 20:28:57 -04:00
Alex King 3359839a9b [Bug Fix] Fix Targeted AOE Max Targets Rule (#4488) 2024-10-02 20:25:35 -05:00
Alex 7e51e629f9 [Loginserver] Larion loginserver support (#4492)
* Add larion version and opcode path

* WIP: getting server to work

* Identify server_id

* Add missing opcode, add opcodes file

---------

Co-authored-by: KimLS <KimLS@peqtgc.com>
2024-10-02 20:20:13 -05:00
Alex King dc6c28a52d [Cleanup] Remove Extra Skill in EQ::skills::GetExtraDamageSkills() (#4486) 2024-10-02 20:07:19 -05:00
Alex King 78aee0780a [Bug Fix] Fix Group ID 0 in Group::SaveGroupLeaderAA() (#4487) 2024-10-02 20:06:56 -05:00
Chris Miles bcd943a964 [Code Cleanup] Optimization Code Cleanup (#4489)
* Initial push

* More

* More

* Further simplify

* More cleanup

* More consolidation

* Fix

* Update

* Update npc.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-09-30 18:34:42 -04:00
nytmyr 56608e84bd [Bots] Add attack flag when told to attack (#4490)
This adds a flag to mobs that are told to attack by their owner to prevent unintended attacks.

Previously, if you were to send your bots to attack a target and then switch targets: before casters land their spell or if melee (especially anyone with pets)  hasn't engaged before the target switch, they could switch to your new target and attack.

This adds a flag upon attack and bots will only attack flagged targets.
2024-09-29 17:59:26 -04:00
regneq 8d23e710ce [Bug Fix] fixed a bug where it would use npc value instead of faction value in the database. (#4491) 2024-09-29 17:42:43 -04:00
Morzain 4d11077b21 [Bug Fix] Add character_instance_safereturns to tables_to_zero_id (#4485)
Co-authored-by: morzain <morzain@users.noreply.github.com>
2024-09-26 18:14:32 -04:00
Alex King 5c0bdfdc4c [Bug Fix] Fix issue with Client::SaveDisciplines() not specifying character ID (#4481) 2024-09-23 23:00:52 -05:00
Alex King 6130e10831 [Release] 22.56.2 (#4480) 2024-09-19 21:59:53 -05:00
Alex King c3e1c531d2 [Bug Fix] Fix Issue with Database::ReserveName (#4477) 2024-09-19 21:15:14 -05:00
Alex King b52719a535 [Quest API] Add GrantAllAAPoints() Overload To Perl/Lua (#4474) 2024-09-19 21:09:24 -05:00
Alex King 1af252466f [Bug Fix] Fix Untrained Disciplines in Client::SaveDisciplines() (#4472)
* [Bug Fix] Fix Untrained Disciplines in Client::SaveDisciplines()

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

Fix infinite loop condition when bot encountered

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

* Change to release

---------

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

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

### Code

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

### Feature

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

### Fixes

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

### Performance

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

### Rules

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

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

* [Feature] Teach npcs how to cast sacrifice

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

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

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

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

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

Custom code looks like this:

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

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

		if (bonus < min_bon) bonus = min_bon;

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

After the fix, the log becomes:

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

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

* Push

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

* Push

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

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

* Update task_client_state.cpp

* Update task_client_state.cpp

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

* more

* track complete connect

* it sucks to suck

* Few optimizations

* Move sent_inventory init

* Move var

* Adjustments

---------

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

* Update mob.cpp
2024-08-26 22:59:06 -05:00
Chris Miles 453106439f [Release] 22.55.0 (#4464) 2024-08-26 22:03:37 -05:00
Mitch Freeman 3da24fffa4 [Bug Fix] Fix client hotbar exchanging items when zoning (#4460)
* Add an exception process to assigning item serial numbers to correct a bug in the client hot bar clicky system.

* fixed missing guid in replace statement

* added snapshot support

* upate #show inventory command to protect against crash conditions
2024-08-26 21:58:07 -05:00
Kurt Gilpin 8d8ef6d480 [Bug Fix] Correct missed maxlevel reference in exp.cpp (#4463)
This was causing characters to de-level when gaining experience and was missed as part of https://github.com/EQEmu/Server/pull/4455
2024-08-26 22:34:22 -04:00
Chris Miles 1f9c4b3a22 [World] Fix slow world bootup bug (#4461)
* [World] Fix slow world bootup bug

* Update ip_util.cpp

* Add timeout

* Update ip_util.cpp

* Cross platform timeout
2024-08-26 20:59:43 -05:00
Alex King 7dfda95d86 [Bug Fix] Fix Bot Spell Entries IDs Capping at 32,767 (#4444)
* [Bug Fix] Fix Bot Spell Entries IDs Capping at 32,767

* Fix manifest
2024-08-26 20:29:50 -05:00
Alex King 40738b29e3 [Quest API] Add Area-Based Quest Methods to Perl/Lua (#4447)
* [Quest API] Add Area-Based Quest Methods to Perl/Lua

* Convert some to mob

* Fix
2024-08-26 20:29:07 -05:00
Alex King 080865faa2 [Feature] Add Optional Return to EVENT_DAMAGE_TAKEN (#4454)
* [Feature] Add Optional Return to EVENT_DAMAGE_TAKEN

# Description
- Allows operators to return a value from `EVENT_DAMAGE_TAKEN` to override the amount of damage taken based on any arbitrary criteria they'd like to apply.

* Update attack.cpp
2024-08-26 20:27:29 -05:00
Alex King e2b545991a [Quest API] Add AreTasksCompleted() to Perl/Lua. (#4456)
* [Quest API] Add AreTasksCompleted() to Perl/Lua.

* Bool
2024-08-22 20:21:14 -04:00
Alex King b7f8d0f179 [Feature] Extend Spell Buckets Functionality (#4441) 2024-08-22 18:49:52 -04:00
Alex King e3588781aa [Cleanup] Remove unused methods (#4449) 2024-08-22 11:48:02 -04:00
Alex King e9b84f4d11 [Bug Fix] Fix issue with killed mob coordinates (#4457) 2024-08-22 11:45:31 -04:00
Alex King 4f03970fd1 [Bug Fix] Fix Character ID of 0 being inserted into character_stats_record (#4458) 2024-08-22 11:45:19 -04:00
catapultam-habeo 4979da6932 [Bug Fix] Apply Race & Class restrictions to Auto-Combines (#4452) 2024-08-19 21:57:34 -04:00
Fryguy 9987029791 [Bug Fix] client_max_level allow leveling to end of level (#4455)
When using a method that leverages client_max_level (e.g. Max Level by bucket / qglobal / quest API) it would stop xp at 0% into the level rather than maximum xp for the level.

This could pose an issue where: If you had a max level of 65 via a databucket and a raid zone required level 65, one death would de-level them and potentially prevent them from entering the zone.

I reorganized the code to leverage the existing max_level logic which allows max xp in the max level.

I also cleaned up the overall functions formating (Mostly brackets and implied if statements).
2024-08-19 21:56:14 -04:00
Alex King eece0a92e3 [Quest API] Add Several Door Methods to Perl/Lua (#4451) 2024-08-16 15:52:49 -04:00
Alex King 057f96796a [Bug Fix] Fix Issue with Removed #setfaction Command (#4448) 2024-08-10 21:21:46 -04:00
Alex King f475cecdb1 [Bug Fix] Fix AddCrystals() in Perl/Lua (#4445) 2024-08-09 22:48:32 -04:00
Fryguy 6296ed6d41 [Bug Fix] Attune Augments when Equipped (#4446) 2024-08-09 22:27:04 -04:00
Alex King ac0f729aa2 [Feature] Add Character:DefaultGuildRank Rule (#4438)
* [Feature] Add Character:DefaultGuildRank Rule

* Update ruletypes.h

* Update ruletypes.h

* Update database.cpp
2024-08-03 22:48:30 -04:00
JJ 2937852cf9 [Bug Fix] Ensure close of Tribute Item search (#4439) 2024-08-03 20:25:07 -04:00
Alex King 2cf5bae571 [Bug Fix] Fix Lua Client FilteredMessage (#4437) 2024-07-31 19:39:57 -04:00
Fryguy 2feb05be18 [Improvement] Filtered Messages Extension (#4435)
* [Improvment] Filtered Messages Extension

Added:
ItemSpeech 25
Strikethrough 26
Stuns 27
BardSongsOnPets 28

I wired up Strikethrough and Stuns as they already had message entries.

ItemSpeech and BardSongsOnPets do not appear to be currently used in the source.

Note: There are still 5 unknown Filters in RoF2 that need to be investigated:

Achievments
Fellowships
Mercenary Messages
PVP Messages
Spam

* Spelling Error

* Missed some stun calls
2024-07-31 18:28:45 -04:00
Fryguy 421767e1e5 [Bug Fix] Imitate Death should also clear zone feign aggro (#4436) 2024-07-31 18:28:36 -04:00
JJ 6e9ff52dce [Release] 22.54.0 (#4434)
* Update CHANGELOG.md

* Update version.h

* Update package.json

* Update CHANGELOG.md
2024-07-30 20:30:38 -04:00
Alex King aa700f8960 [Cleanup] Cleanup Client File Exporting (#4348)
* [Cleanup] Cleanup Client File Exporting

* Update base_data_repository.h

* Update db_str_repository.h

* Update base_data_repository.h

* Update skill_caps_repository.h

* Update skill_caps_repository.h

* Update skill_caps_repository.h

* Update main.cpp

* Push
2024-07-30 20:10:00 -04:00
Fryguy 2ef959c5ed [Improvement] Flee Overhaul (#4407)
* Lots of flee updates primarily based on TAKPs source

* Update Values to EQEmu values.

* Add rule

* Adjustments to fear pathing

* Flee/Pathing adjustments (More TAKP code adjusted)

* updates

* Updates (Massaged functions from TAKP source)

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-07-30 18:27:47 -04:00
Mitch Freeman e49ab924cc [Feature] Add Barter/Buyer Features (#4405)
* Add Barter/Buyer Features

Adds barter and buyer features, for ROF2 only at this time including item compensation

* Remove FKs from buyer tables

Remove FKs from buyer tables

* Bug fix for Find Buyer and mutli item selling

Update for quantity purchases not correctly providing multi items.
Update for Find Buyer functionality based on zone instancing.
Update buyer messaging
Update buyer LORE duplicate check

* Revert zone instance comment

* Revert zone_id packet size field

* Add zone instancing to barter/buyer

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-07-30 16:23:37 -04:00
catapultam-habeo fc3c691588 [Feature] Implement Move Multiple Items (#4259)
* Implement Move Multiple Items

* Send LinkDead on invalid packet

* structure this more like MoveItem

* implement all modes

* remove un-needed debug message

* handle mode 3 swaps in bank\shared bank correctly.

* Revert "handle mode 3 swaps in bank\shared bank correctly."

This reverts commit ce01fbfde70d52e88381772a6c7a77b4b650c7c5.

* Revert "remove un-needed debug message"

This reverts commit f4b662459e11a60c3a46a97e5320757c4b2b9a84.

* handle mode 3 swaps without extra unintended code

* correct variable type

* remove magic numbers

* forgot a semicolon in emu_constants.h

* fix bad rebase artifact

* Remove unused struct

* apply changes discussed in PR

* last rebase conflict

* last rebase conflict

fix more inventory type enum refs

* fix windows build error

* fix other windows build error.

* fix duplication bug
2024-07-30 13:40:48 -04:00
catapultam-habeo d465a3deba [Bug Fix] Stop DOSing ourselves with OP_WearChange (#4432)
* initial commit to start convo

* additional potential problem

* Revert "additional potential problem"

This reverts commit 689e94ea95.
2024-07-30 13:00:26 -04:00
Alex King 40c9c8044b [Bug Fix] Fix issue with quest::echo and quest::me (#4433) 2024-07-30 09:25:05 -04:00
Chris Miles 70a96ea098 [Zoning] Improve zone routing (#4428)
* [Zoning] Improvements to zone routing

* Update world_content_service.h

* Update world_content_service.h
2024-07-30 09:12:31 -04:00
Chris Miles d5cbec714e Revert "[Zone Instances] Handle routing to instances when using evac/succor (#4297)" (#4429)
This reverts commit dfd1bfbd49.
2024-07-30 09:12:19 -04:00
Mitch Freeman 6903205484 [Bug Fix] Fix #parcels add subcommand (#4431)
The parcel object was not be initialized correctly resulting in the possibility of incorrect data being written for the uninitialized members.
2024-07-28 21:56:21 -04:00
Chris Miles 4c81321847 [Databuckets] Remove memory reserve from bulk load (#4427) 2024-07-23 00:37:34 -05:00
Alex King e5cea73e0c [Bug Fix] Fix Client::RemoveTitle (#4421)
* [Bug Fix] Fix Client::RemoveTitle

* Remove title/suffix if in use.

* Update titles.cpp

* Non static
2024-07-23 00:33:09 -05:00
Alex King 23308192b5 [Bug Fix] Fix #setlevel Allowing Skills Above Max (#4423) 2024-07-22 20:46:38 -05:00
Alex King 29fdf7e2ae [Bug Fix] Fix EVENT_USE_SKILL with Sense Heading (#4424) 2024-07-22 20:45:32 -05:00
Alex King 098498dedd [Commands] Extend #devtools Functionality (#4425) 2024-07-22 20:44:34 -05:00
Alex King b6fb8daae8 [Bug Fix] Fix Bot::SetBotStance (#4426) 2024-07-22 20:43:18 -05:00
nytmyr 563f7d5564 [Cleanup] Mask GM Show Buff message behind EntityVariable (#4419)
* [Cleanup] Mask GM Show Buff message behind EntityVariable

Removes the spam of "Your GM flag allows you to always see your targets' buffs." for GMs every time a buff lands on a target.

It will now lock to an Entity Variable and only show once per zone.

* Convert string to constexpr

* Switch from string to char
2024-07-22 12:51:41 -04:00
Fryguy 1e5abc456b [Bug Fix] Proximity Aggro for Frustrated and Undead (#4411)
* [Bug Fix] Prox aggro for frustrated and undead.

If mob is frustrated (Rooted and has no one to kill or is undead will add prox aggro to hate list.

* Update aggro.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-07-22 07:01:12 -04:00
Fryguy 3b0fa015a7 [Bug Fix] Corpse Call removing Resurrection Effects (#4410)
* [Bug Fix] Corpse Call removing Rez Effects

When calling a corpse, it should not remove rez effects.

* Update client_process.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-07-22 06:26:40 -04:00
nytmyr c73a1e8bea [Rules] Add HasteCap and Hastev3Cap rules for NPCs, Bots and Mercs (#4406)
* [Rules] Add HasteCap and Hastev3Cap rules for NPCs, Bots and Mercs

Previously NPCs, bots and mercs all had a flat haste cap of 150 whereas clients were capped at 100.

NPCs, bots and mercs used the character rule for v3 cap, they now each have their own.

Rules for v3 cap are the default of 25 as they were using.
Rules for haste caps are the default of 150 for NPCs they were using but lowered to 100 for bots and mercs, the same as clients.

This also adds haste output to the GM target stat window

* Fix for stat windows to account for client haste
2024-07-22 06:06:49 -04:00
Fryguy 3bfdc0cf71 [Bug Fix] Potential fix for some undesired ranged explotative behavior. (#4413)
Original Commit: 33fecd68d4eab36885eb7f8067102ba6bce95bac

Conditional ranged double attack
2024-07-22 06:05:46 -04:00
Mitch Freeman a23ac4628f [Feature] Add Parcel notification for online players when using the Quest API (#4418)
* Add parcel notification for online players when using the quest api for send_parcel

* Compile fix

fix for compile issues
2024-07-22 05:57:42 -04:00
nytmyr 5ef4612249 [Bug Fix] [Quest API] Fix getraididbycharid and getgroupidbycharid (#4417) 2024-07-16 15:53:22 -04:00
Mitch Freeman 17f66c5d60 [Bug Fix] Personal tributes for bard items were not applying correctly (#4416)
* Fixes Personal Tributes for bard items not being applied.

* Fix for bots
2024-07-16 11:18:42 -04:00
Mitch Freeman 51eb95ed31 Revert "Fixes Personal Tributes for bard items not being applied. (#4414)" (#4415)
This reverts commit 080abaede1.
2024-07-16 10:49:08 -04:00
Mitch Freeman 080abaede1 Fixes Personal Tributes for bard items not being applied. (#4414) 2024-07-15 23:02:35 -04:00
Mitch Freeman 97e332819d When searching in the bazaar, the minimum cost was not be honoured. (#4412) 2024-07-15 08:41:04 -04:00
Mitch Freeman 1e41c5517e [Bug Fix] Fix for random disconnects when a large number of guild members zone or disconnect (#4402) 2024-07-10 00:10:33 -05:00
Fryguy c7a88af11a [Bug Fix] AutoSplit unknown bug and cleanup. (#4401)
Code Credit TAKP:

Bug Post: https://discord.com/channels/212663220849213441/1258430167764832319

Resolved issue with split message being sent to group members when no split is present which creates an "Unknown Split".

Also added the random remainder split portion unless using a manual /split

Converted manual messages to Strings
2024-07-07 00:53:57 -04:00
KayenEQ d8ddd0aab9 [Bug Fix] Aegolism Spell line stacking (#4399)
* fix stacking issues with Aegolism spell line

Issue: When casting buffing a player with aegolism spell line, who already has cleric AC, symbol and heroism spell, it would overwrite heorism buff and leave other two.

Aegolism spell line when applied when a client has Heroism spell line, AC spell line, and symbol spell line. Should overwrite the Heroism spell and fade the AC and Symbol buffs.

* Update spdat.cpp
2024-07-07 00:53:46 -04:00
Fryguy 95cbadade5 [Bug Fix] Slay Adjustments (#4389)
Previous change did not account for the modern slay undead and holyforge spells.

Reverted some of the changes and cleaned up others.

Rule Renamed (Default value was incorrect, this was a clean way to fix that) - SlayDamageAdjustment -> SlayDamageMultiplier

Also added a rate multiplier

RULE_REAL(Combat, SlayRateMultiplier, 1.0, "Slay Rate Adjustments - Multiply final slay rate check by this value. Default: 1.0")

Fixed the ordering of the constants for the slay undead SPA that were backwards and causing major headaches with tuning and setting up slay undead correctly.

Base = Damage Mod (100 is base, so 240 = 140% more)
Limit = Proc Rate - Value is divided by 10000 for a Float %. e.g. 1700 becomes 0.17 (Or 17% proc rate).

Damage bonus should be additive not std::max as AA, Spells and Item bonuses should stack.

e.g. Slay Undead RK3 240 + Holy Forge 140 should = 380 (280% damage)
2024-07-07 00:53:29 -04:00
Alex King a85f4fb703 [Cleanup] Cleanup Stance Code (#4368)
* [Cleanup] Cleanup Stance-based Code

* Command

* Update emu_constants.h

* Update stance.cpp

* Cleanup
2024-07-02 21:50:34 -04:00
Fryguy e63f34638b [Bug Fix] AllowRaidTargetBlind logic backwards (#4400) 2024-07-01 08:15:36 -04:00
JJ 7918fed81c [Release] 22.53.1 (#4398) 2024-06-16 21:17:16 -04:00
JJ ac24c9bf5a [Bug Fix] Fix trader mode (#4397)
* Fix bazaar trading

* Update `constexpr`

* Added world trader table truncate on boot to ensure that the trader table is always empty when world starts.

---------

Co-authored-by: Mitch Freeman <65987027+neckkola@users.noreply.github.com>
2024-06-16 20:55:14 -04:00
Chris Miles 7b914c731b [Release] 22.53.0 (#4395) 2024-06-14 12:44:57 -05:00
Fryguy 7362c0ebb5 [Bug] Anon players should not show in /who all (#4392)
Updated to properly filter anon players from /who all.

The code formatting was very inconsistant and needed cleanup.
2024-06-14 12:39:41 -05:00
Fryguy ae213a4e4b [Rule] Classic Harm Touch Formula (#4394)
* [Rule] Classic Harm Touch Formula

Pre 2007 Harm Touch was handled differently with base harm Touch ( Ability or 2 ranks aa) and Improved Harm Touch AA. It was converted into 10 ranks of Harm Touch -

http://www.tski.co.jp/baldio/patch/20071113.html

It was further refined in 2008 to have a DoT component.

http://www.tski.co.jp/baldio/patch/20080709.html

This rule focuses on the pre 2007 version and allows the damage to properly scale

* Updated logic

* Update per feedback.
2024-06-14 12:28:43 -05:00
Alex King 187288f3aa [Rules] Add Invisible Augment Rules (#4385)
* [Rules] Add Invisible Augment Slot Rule

* Update item_instance.cpp

* Second rule

* Update ruletypes.h
2024-06-14 12:02:21 -05:00
Alex King abc8c3d886 [Cleanup] Remove unused code in emu_constants.h (#4384)
# Description
- Remove unused code that was missed as a result of resolving merge conflicts and this being left behind.
2024-06-14 11:59:13 -05:00
Alex King 0b2493beb8 [Cleanup] Cleanup Object Type Code (#4375)
* [Cleanup] Cleanup Object Type Code

* Move to object.cpp/object.h
2024-06-14 11:58:59 -05:00
JJ 9cebba5911 [Bug Fix] Fix potential trader crash when serialized item not found (#4386) 2024-06-14 11:58:00 -05:00
Fryguy 4478328b2a [Rules] Mend/Sneak allow success tuning (#4390)
MendAlwaysSucceedValue allows you to adjust skill at which mend will always succeed its check.

SneakAlwaysSucceedOver100 allows sneak to always succeed when over skill 100 (Higher skill increases the movement speed).
2024-06-14 11:57:31 -05:00
JJ 55a7e1646d Check that an event actually exists (#4387) 2024-06-14 11:56:33 -05:00
Mitch Freeman b6b8491060 [Bug Fix] Fix for players having empty bazaar window dropdown list, even though trader is tagged as a trader. (#4391)
* Potential fix for players having empty bazaar window dropdown list, even though trader is tagged as a trader.

* Update the truncate of the trader table to avoid inappropriate deletions if an instance of bazaar was started.
2024-06-14 11:53:34 -05:00
Fryguy 850053a136 [Bug] Prevent Resurrection Spells from being resisted (#4393)
* [Bug] Prevent Ressurection Spells from being resisted

Added IsRessurectionSpell(uint16 spell_id) to assist with checking on a spell is a ressurection spell.

This was noticed when Dragons of Norrath launched and the Tier 5 Progression AA provided SPA 180 2% SE_ResistSpellChance

* Helps if I spell it correctly

* Update per feedback
2024-06-14 11:51:33 -05:00
Fryguy 1aa8758b0a [Bug] Escape should put player into SOS if owned. (#4388)
When you escape if you have the Shroud of Stealth bonus (AA, Spell, item) you will go straight into SOS mode.
2024-06-07 13:57:54 -04:00
Alex King b1aa087b9f [Bug Fix] Fix Swarm Pet Damage Messages (#4383) 2024-06-04 18:50:08 -04:00
Alex King 1e57a0372f [Bug Fix] Fix #goto Target (#4382) 2024-06-03 03:02:27 -04:00
Fryguy 9614ea59ec [Rule] Snare Override Movement Bonus (#4381)
* [Rule] Snare Override Movement Bonus

This rule allows snare to override any movement bonuses.

RULE_BOOL(Spells, AllowSnareEffectsOverrideBonus, false, "Enabling will allow snares to override any speed bonuses the entity may have. Default: False")

Default: False

* Rule name

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-06-02 17:50:41 -04:00
Alex King 7a648cce16 [Cleanup] Cleanup Account Status Code (#4376)
* [Cleanup] Cleanup Account Status Code

* Update emu_constants.cpp

* Update emu_constants.h
2024-06-02 16:40:52 -04:00
Alex King 8640776a21 [Cleanup] Cleanup Body Type Code (#4366)
* [Cleanup] Cleanup Body Type-based Code

* Update bodytypes.cpp

* Final

* Update body_type.cpp

* Cleanup

* Cleanup

* Formatting

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-06-02 04:25:06 -04:00
Chris Miles 0c45d3b09e [Release] 22.52.0 (#4380) 2024-06-01 20:37:21 -05:00
Mitch Freeman 59e4adb117 [Fix] Bazaar Search not working correctly for Iksar, Vashir, Drakkin and Froglok races (#4379) 2024-06-01 19:17:18 -05:00
Alex King d5a06bfe2e [Cleanup] Cleanup Bucket Comparison Code (#4374)
* [Cleanup] Cleanup Bucket Comparison-based Code

* Final
2024-06-01 19:11:56 -05:00
Alex King 0f0676824c [Cleanup] Cleanup Bug Category Code (#4367)
* [Cleanup] Cleanup Bug Category-based Code

* Command

* Cleanup

* Cleanup

* Cleanup
2024-06-01 18:25:02 -05:00
Alex King caa647dc6b [Cleanup] Cleanup Deity Code (#4363)
* [Cleanup] Cleanup Deity-based Code

* Final push.

* Update deity.cpp

* Update deity.cpp

* Update deity.cpp

* Cleanup

* Cleanup

* [Cleanup] Cleanup Skill-based Code

* Update deity.cpp

* Update lua_client.cpp
2024-06-01 18:21:26 -05:00
Alex King 76b9ce0ac1 [Cleanup] Cleanup Special Ability Code (#4365)
* [Cleanup] Cleanup Special Ability-based Code

* Update emu_constants.cpp

* Update emu_constants.cpp

* Update emu_constants.cpp

* Update special_ability.cpp

* Cleanup

* Update emu_constants.cpp
2024-06-01 18:20:43 -05:00
Chris Miles d01d091b47 [Quests] Fix issue with Lua encounters loading in certain circumstances (#4378)
* [Quests] Fix issue with Lua encounters loading in certain circumstances

* Update quest_parser_collection.cpp

* Constant

* Move constant

* Fix

* Update quest_parser_collection.cpp
2024-06-01 18:07:38 -05:00
Alex King 47ddcb54f1 [Cleanup] Remove unused code in common/eq_constants.h (#4364) 2024-06-01 16:10:37 -05:00
Alex King dda0e410ff [Quest API] Add Item Link Methods to Perl/Lua (#4359) 2024-06-01 16:10:05 -05:00
Chris Miles eae05167f8 [Skills] Fix caps out of bounds issue (#4377)
* wip

* More adjustments
2024-06-01 16:09:34 -05:00
Alex King 16f21893a3 [Rules] Add Skill Base Damage Rules (#4360)
* [Rules] Add Skill Base Damage Rules

* Final

* Update ruletypes.h

* Update ruletypes.h
2024-06-01 16:09:21 -05:00
Alex King 4ca724956b [Bug Fix] Fix Unescaped String in Client::GotoPlayer (#4373)
* [Bug Fix] Fix Unescaped String in Client::GotoPlayer

* Final

* Update client.cpp
2024-06-01 16:09:00 -05:00
regneq 217a80ee76 [NPC Spells] Fixed an issue where the repository spell adj value was overriding the spell difficulty default value (#4370)
* [NPC Spells} fixed an issue where the repository spell adj value was overriding the spell difficulty default value.
[Command] Add resist adj to #show spells_list command to see the resist value.

* True fix, do IsValidSpell on actual spell

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-06-01 16:08:14 -05:00
JJ 8b166bf5b9 [Bug Fix] Add protection to ensure adventure points award are only attempted on players (#4371) 2024-05-31 17:47:23 -04:00
Chris Miles 4c614661e7 [Quests] Fix Lua encounter double register (#4369) 2024-05-30 20:27:21 -04:00
Fryguy 9392f86333 [Bug Fix] Adjust Kick/RoundKick Damage Lower levels (#4355)
Code for Kick and Bash were causing Warriors/Rangers to deal almost as much damage with low level abilities as a Monk using Flying Kick
2024-05-28 10:01:11 -04:00
Fryguy 0d888268a8 [Combat] Adjustments to Crippling Blows/Slay Undead and Confirmed Critical Code (#4354)
* Adjustments to Crippling Blows/Slay Undead and Confirmed Critical Code

* Adjustments per comments
2024-05-27 19:53:24 -04:00
Fryguy b044d8533e [Release] 22.51.1 (#4353)
### Fixes

* Adjust return for perl release check  @Akkadius 2024-05-26
* Corrected issue with bazaar purchase via parcels where an incorrect quantity would be calculated. ([#4352](https://github.com/EQEmu/Server/pull/4352)) @neckkola 2024-05-27

### Performance

* Improve SkillCaps::GetTrainLevel() Efficiency ([#4350](https://github.com/EQEmu/Server/pull/4350)) @Kinglykrab 2024-05-26

### Rules

* Legacy Compute Defense against modern agi based defense. ([#4349](https://github.com/EQEmu/Server/pull/4349)) @fryguy503 2024-05-27
2024-05-27 16:21:55 -05:00
Mitch Freeman d810cb02c3 [Fix] Corrected issue with bazaar purchase via parcels where an incorrect quantity would be calculated. (#4352) 2024-05-27 17:06:30 -04:00
Fryguy 992a5cc132 [Rule] Legacy Compute Defense against modern agi based defense. (#4349)
* [Rule] Legacy Compute Defense against modern agi based defense.

In new code, AGI becomes a large contributor to avoidance at low levels, since AGI isn't capped by Level but Defense is A scale factor is implemented for PCs to reduce the effect of AGI at low levels.  This isn't applied to NPCs since they can be easily controlled via the Database.

* `snake_case`

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-05-26 20:27:18 -04:00
Alex King c50fda0f73 [Performance] Improve SkillCaps::GetTrainLevel() Efficiency (#4350)
* [Performance] Improve SkillCaps::GetTrainLevel() Efficiency

* Finalize
2024-05-26 18:55:00 -05:00
Akkadius 1b15f16e3e [Hotfix] Adjust return for perl release check 2024-05-26 16:01:44 -05:00
Chris Miles 983cc1e82a [Release] 22.51.0 (#4347) 2024-05-26 15:44:28 -05:00
Mitch Freeman fc79614fac [Feature] Add RoF2 Bazaar Support (#4315)
* Add RoF2 Bazaar Support

Enable RoF2 bazaar features

* Add augments to Trader Items

* Cleanup

Cleanup of formatting and unused functions

* Update PlayerProfile for correct char_id in trader transactions.  Further cleanup.

* Add parcel delivery price functionality

Add parcel delivery price functionality via rules and new delivery cost struct.

* Add RoF support for bazaar window outside of bazaar with parcel delivery

* Further Testing and ActiveTransaction added

Further testing and a few fixes and messages added.  Add active transaction check to ensure two clients cannot purchase from the bazaar window at the same time

* Cleanup and Formatting updates

Cleanup and Formatting updates

* Update database manifest for the trader table against default peq trader table

* Logs and formatting

* Update bazaarsearch to be content_db aware

* Fix crash

* Simplify search

* Search fixes

* Push up more search logging

* More search fixes

* Formatting

* Update trader_repository.h

* Add Rule for Bazaar Parcel Delivery

Add a rule Bazaar:EnableParcelDelivery to enable/disable bazaar parcel delivery.  Default is True.

* Fix crash

* Update Bazaar Search

Adds/Tested bazaar search with move to content_db
- race, class, money, number of returned items, stats, name, slot, level, traders, local traders, specific trader.
Outstanding
- type, more stats to add (heroic, etc)

* Formatting

* Push

* Update bazaarsearch to include all stats that are available in RoF2

* Update BazaarSearch

Updates the bazaar search for item types.  They should be working as per RoF2+ types.

* Formatting

* Final updates to BazaarSearch

Add search by augmentation slots available on the item.
This enables all but Prestige, which I believe are not implemented yet.

* Add Titanium functionality correct ItemType Search

Add Titanium /trader /bazaar functionality.
Added itemtype=armor bazaar search.  It was missed in the search work

* Close off for loops

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-05-26 15:38:25 -05:00
Chris Miles d767217461 [Perl] Linux /opt/eqemu-perl checks when using release binaries (#4346) 2024-05-26 15:14:06 -05:00
Chris Miles 1310c5d528 [Scripts] Fix zone data load ordering issue (#4343)
* [Scripts] Fix zone data load ordering issue

* Move more around

* More
2024-05-26 14:26:06 -05:00
Chris Miles b253fce0d5 [Lua Mod] Fix issue with SetAAEXP and SetEXP firing when uninitialized (#4345) 2024-05-26 14:20:07 -05:00
Chris Miles 421857026d [NPC Spells] Fix an issue where procs wouldn't fire if no spell entries in list (#4344) 2024-05-26 14:53:30 -04:00
Fryguy 68f40c9255 [Rule] Backstab Haste Correction (#4337)
- Haste should only provide a max of a 2 s reduction to Backstab cooldown, but it seems that while BackstabReuseTimer can be reduced, there is another timer (repop on the button) that is controlling the actual cooldown.  I'm not sure how this is implemented, but it is impacted by spell haste (including bard v2 and v3), but not worn haste. This code applies an adjustment to backstab accuracy to compensate for this so that Rogue DPS doesn't significantly outclass other classes.
2024-05-26 11:34:36 -04:00
Fryguy 0bceee5622 [Bug Fix] Fix mistaken removed RULE_CATEGORY_END() (#4341) 2024-05-26 10:10:22 -04:00
Alex King cd03152550 [Quest API] Add Zone Uptime Exports to Perl/Lua (#4339) 2024-05-26 10:06:38 -04:00
Alex King 316fa54bd8 [Bug Fix] Fix Using Bind Wound Above 70% Health (#4340)
* [Bug Fix] Fix Using Bind Wound Above 70% Health

* Update client.cpp

* Update client.cpp
2024-05-26 10:06:26 -04:00
Fryguy 49957e3269 [Bug Fix] Raid Targets should not be Blindable as this will break all spell casting AI. (#4334)
* [Bug] Raid Targets should not be Blindable as this will break all spell casting AI.

* Add rule.

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-05-26 09:40:18 -04:00
Fryguy 9638d9af3a [Rule] Added MeleeMitigation Level Difference Roll Adjusted for level diffs (#4332)
* Added MeleeMitigation LevelDifferent Roll Adjusted for level diffs

* Adjustments per comments

* Tune method and const.

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-05-26 08:57:32 -04:00
Fryguy 87c207e862 [Feature] Add SE_IncreaseArchery and rules to tune archery (#4335)
* [Feature] Add SE_IncreaseArchery and rules to tune archery

* Adjustments per comments, also added to the tune system.

* Update bonuses.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-05-26 08:37:23 -04:00
Fryguy 2df5f3f55a [Bug Fix] When refreshing buffs, attempt to use the same buffslot if the buff still exists. (#4338) 2024-05-26 06:59:22 -04:00
Fryguy e803d3e1e1 [Bug Fix] Accuracy, Avoidance and Atk adjustments (#4336)
* [Bug Fix] Accuracy, Avoidance and Atk adjustments

- Applied Fix to Attack Power contributing too much to damage.
   Rule of thumb for era was 100 attack = 10% damage increase, but I was seeing closer to 15-25%.  Found that in the GetATK() function it seemed to be double counting attack power from items and spells, so I applied a /2 to remedy this.

* Update Tune
2024-05-26 06:57:30 -04:00
Fryguy fccb205a1d [Rule] Remove hard coded initial aggro in favor or an adjustable Rule (#4333)
* [Rule] Remove hard coded initial aggro in favor or an adjustable Rule

* Adjustments per comments
2024-05-26 06:56:36 -04:00
Fryguy f70078d62a [Hotfix] Missed a mob offense section for PR #4328 (#4331) 2024-05-26 00:02:30 -04:00
Fryguy 34ae3094d6 [Bug Fix] When Mounts are allowed to zone, block them from zoning to disallowed zones. (#4330) 2024-05-25 18:03:23 -04:00
Fryguy c56742a2a8 [Rule] Allow maximum per kill AA amount (#4329)
* [Rule] Allow maximum per kill AA amount

* Adjustments per comments

* Finalize.

* Update ruletypes.h

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-05-25 17:48:58 -04:00
Fryguy 3e34447172 [Rule] Mob Offensive and Weapon Skill static tables (#4328)
* [Rule] Mob Offensive and Weapon Skill static tables

* Adjustments per comments

* Adjustments - Thanks KK
2024-05-25 17:38:45 -04:00
Fryguy ca25122bfa [Rule] Allow servers to adjust the filtering threshold for heals from damage (e.g. Mark of Kings). (#4327) 2024-05-25 14:28:20 -04:00
Chris Miles 13a7532ef8 [Crash] Fix player event crash in ITEM_DESTROY (#4326) 2024-05-24 21:54:22 -04:00
Chris Miles e1344039ff [Crash] Fix Zone deconstructor crashes (#4325) 2024-05-24 21:54:16 -04:00
Chris Miles 98b137154a [Crash] Add validation to RemoveXTarget (#4324) 2024-05-24 21:54:10 -04:00
Chris Miles fc9ef2fb7b [Mobs] Remove entity type checks from ScanCloseMobs (#4323) 2024-05-24 21:54:01 -04:00
Chris Miles 6dc661032f [Crash] Fix crash when map name is null (#4322) 2024-05-24 21:53:54 -04:00
Chris Miles 2586527157 [Crash] Fix player events reload when out of bounds (#4321) 2024-05-24 21:53:47 -04:00
Chris Miles 3a51f04291 [Crash] Fix crash issue when dividing by zero in CalcHPRegen (#4320)
* [Crash] Fix crash issue when dividing by zero in CalcHPRegen

* Update zone.cpp
2024-05-24 21:53:40 -04:00
Chris Miles 66af3d2f63 [Crash] Fix rarer crash in EntityList::MobProcess (#4319) 2024-05-24 21:53:33 -04:00
Alex King 6bcd8fea18 [Bug Fix] Fix Crash with null Argument in #modifynpcstat (#4318)
* [Bug Fix] Fix Crash with null Argument in #modifynpcstat

* Update modifynpcstat.cpp

* Update modifynpcstat.cpp
2024-05-24 19:27:43 -04:00
Alex King 0d1cbecb55 [Bug Fix] Fix RemoveAlternateCurrencyValue not updating Client (#4317)
* [Bug Fix] Fix issue with Client::RemoveAlternateCurrencyValue

* Update client.cpp
2024-05-23 17:47:43 -04:00
Alex King e33e076b2a [Bug Fix] Fix issue with #suspend (#4314)
* [Bug Fix] Fix issue with #suspend

* Add suspension clearing

* Update character_data_repository.h

* Final push.
2024-05-23 16:45:21 -04:00
Alex King e26d17182e [Bug Fix] Fix issue with KeepOneRecordPerCompletedTask (#4313) 2024-05-22 21:25:36 -05:00
Alex King 7e40c5bac2 [Commands] Cleanup #resetaa Command (#4310)
* [Commands] Cleanup #resetaa Command

* Update resetaa.cpp
2024-05-22 16:06:51 -05:00
Alex King ca69cc67e8 [Bug Fix] Fix issue with #hotfix (#4316) 2024-05-22 15:38:47 -05:00
Chris Miles 099c6d657b [Spells] Add content filtering to NPC spells (#4309)
* [Spells] Add content filtering to NPC spells

* Update mob_ai.cpp

* Add NPC spell reloading

* Oops

* Naming

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-05-17 11:59:20 -04:00
Paul Coene c0a8fd097e [Merchants] Add New Classic Greed/Faction/Charisma Prices Rule (#4301)
* [Merchants] Add New Classic Greed/Faction/Charisma Prices Rule

* Fix size of greed field.

* Fix { formatting and add {} to one liners

* Fix return type of GetGreedPercent

* Remove code that slipped in from another patch

* Fix greed to be unsigned

* Update client.cpp

* Update client_packet.cpp

* Update client.cpp

Fix bad name in extra log message added manually from merge.

* Update client_packet.cpp

Spacing.

* Update client.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-05-17 11:16:02 -04:00
Mitch Freeman a80ab75260 [Feature] Add parcel container support (#4305)
* Add parcel container support

This allows sending containers with items as a parcel
When sending a item via a parcel, if the player had multiples of that item, the wrong item would be removed from inventory.

* Rebase updates
2024-05-17 01:58:26 -04:00
twincannon c87aadbf0c [Commands] #npcspawn Changes (#4311)
* Changes to npcspawn create command so it takes more stats from the target npc

* Add see invis stats to npccreate command

* WIP npcspawn command changes

* Add npcspawn clone and help args, fix some broken things with npcspawn

* Cleanup comments and add apostraphes to zone shortname query

* Make it so npcspawn remove only removes spawn2 row and optionally removes spawngroup and spawnentry, make create and add spawn the npc at client loc

* Make npcspawn create use the same syntax for spawngroup naming as npcspawn add

* Revert npcspawn create and add to use npc location rather than client, other misc tweaks
2024-05-16 15:17:37 -04:00
Akkadius 1be86edf20 [Release] 22.50.1 2024-05-12 14:56:55 -05:00
Mitch Freeman b49b564940 [Fix] Clear GuildOnlineStatus on world boot (#4306)
Ensure that the guild member online status is set to offline (0) when world boots.
2024-05-12 14:02:06 -05:00
Mitch Freeman d302b9c02e [Fix} Correct a guild bank dup issue (#4308)
When depositing an item in the guild bank with an unlimited charge (-1) a db error would occur resulting in a duplication issue.
Can test with item id 70208
2024-05-12 07:53:42 -04:00
273 changed files with 24884 additions and 10499 deletions
+459 -13
View File
@@ -1,3 +1,449 @@
## [22.59.1] 11/13/2024
### Hotfix
* Fix faulty database migration condition with databuckets (9285)
## [22.59.0] 11/13/2024
### Databuckets
* Add database index to data_buckets ([#4535](https://github.com/EQEmu/Server/pull/4535)) @Akkadius 2024-11-09
### Fixes
* Bazaar two edge case issues resolved ([#4533](https://github.com/EQEmu/Server/pull/4533)) @neckkola 2024-11-09
* Check if the mob is already in the close mobs list before inserting @Akkadius 2024-11-11
* ScanCloseMobs - Ensure scanning mob has an entity ID @Akkadius 2024-11-10
### Performance
* Improvements to ScanCloseMobs logic ([#4534](https://github.com/EQEmu/Server/pull/4534)) @Akkadius 2024-11-08
### Quest API
* Add Native Database Querying Interface ([#4531](https://github.com/EQEmu/Server/pull/4531)) @hgtw 2024-11-13
### Rules
* Add Rule for restricting client versions to world server ([#4527](https://github.com/EQEmu/Server/pull/4527)) @knervous 2024-11-12
## [22.58.0] 11/5/2024
### Code
* Add mysql prepared statement support ([#4530](https://github.com/EQEmu/Server/pull/4530)) @hgtw 2024-11-06
* Update perlbind to 1.1.0 ([#4529](https://github.com/EQEmu/Server/pull/4529)) @hgtw 2024-11-06
### Feature
* Focus Skill Attack Spells ([#4528](https://github.com/EQEmu/Server/pull/4528)) @mmcgarvey 2024-10-31
### Fixes
* Add Missing Lua Registers ([#4525](https://github.com/EQEmu/Server/pull/4525)) @Kinglykrab 2024-10-24
* Fix cross_zone_set_entity_variable_by_char_id in Lua ([#4526](https://github.com/EQEmu/Server/pull/4526)) @Kinglykrab 2024-10-24
### Loginserver
* Automatifc Opcode File Creation ([#4521](https://github.com/EQEmu/Server/pull/4521)) @KimLS 2024-10-22
### Quest API
* Add Spawn Circle/Grid Methods to Perl/Lua ([#4524](https://github.com/EQEmu/Server/pull/4524)) @Kinglykrab 2024-10-24
## [22.57.1] 10/22/2024
### Bots
* Enable Bot Commands Only if Rule Enabled ([#4519](https://github.com/EQEmu/Server/pull/4519)) @Kinglykrab 2024-10-22
* Fix pet buffs from saving duplicates every save ([#4520](https://github.com/EQEmu/Server/pull/4520)) @nytmyr 2024-10-22
### Loginserver
* Automatic Opcode File Creation ([#4521](https://github.com/EQEmu/Server/pull/4521)) @KimLS 2024-10-22
## [22.57.0] 10/20/2024
### Bots
* Add "silent" option to ^spawn and mute raid spawn ([#4494](https://github.com/EQEmu/Server/pull/4494)) @nytmyr 2024-10-05
* Add attack flag when told to attack ([#4490](https://github.com/EQEmu/Server/pull/4490)) @nytmyr 2024-09-29
* Fix timers loading on spawn and zone ([#4516](https://github.com/EQEmu/Server/pull/4516)) @nytmyr 2024-10-20
### Code
* Fixed a typo in Zoning.cpp ([#4515](https://github.com/EQEmu/Server/pull/4515)) @carolus21rex 2024-10-20
* Optimization Code Cleanup ([#4489](https://github.com/EQEmu/Server/pull/4489)) @Akkadius 2024-09-30
* Remove Extra Skill in EQ::skills::GetExtraDamageSkills() ([#4486](https://github.com/EQEmu/Server/pull/4486)) @Kinglykrab 2024-10-03
### Crash
* Fixes a crash when the faction_list db table is empty. ([#4511](https://github.com/EQEmu/Server/pull/4511)) @KimLS 2024-10-14
### Fixes
* Add character_instance_safereturns to tables_to_zero_id ([#4485](https://github.com/EQEmu/Server/pull/4485)) @Morzain 2024-09-26
* Correctly limit max targets of PBAOE ([#4507](https://github.com/EQEmu/Server/pull/4507)) @catapultam-habeo 2024-10-11
* FindBestZ selecting false zone floor as bestz - Results in roambox failures ([#4504](https://github.com/EQEmu/Server/pull/4504)) @fryguy503 2024-10-13
* Fix #set motd Crash ([#4495](https://github.com/EQEmu/Server/pull/4495)) @Kinglykrab 2024-10-05
* Fix `character_exp_modifiers` Default Values ([#4502](https://github.com/EQEmu/Server/pull/4502)) @Kinglykrab 2024-10-09
* Fix a display error regarding a few trader/buyer query errors ([#4514](https://github.com/EQEmu/Server/pull/4514)) @neckkola 2024-10-17
* Fix Group ID 0 in Group::SaveGroupLeaderAA() ([#4487](https://github.com/EQEmu/Server/pull/4487)) @Kinglykrab 2024-10-03
* Fix Mercenary Encounter Crash ([#4509](https://github.com/EQEmu/Server/pull/4509)) @Kinglykrab 2024-10-12
* Fix NPC::CanTalk() Crash ([#4499](https://github.com/EQEmu/Server/pull/4499)) @Kinglykrab 2024-10-07
* Fix Spells:DefaultAOEMaxTargets Default Value ([#4508](https://github.com/EQEmu/Server/pull/4508)) @Kinglykrab 2024-10-12
* Fix Targeted AOE Max Targets Rule ([#4488](https://github.com/EQEmu/Server/pull/4488)) @Kinglykrab 2024-10-03
* fixed a bug where it would use npc value instead of faction value in the database. ([#4491](https://github.com/EQEmu/Server/pull/4491)) @regneq 2024-09-29
* Master of Disguise should apply to illusions casted by others. ([#4506](https://github.com/EQEmu/Server/pull/4506)) @fryguy503 2024-10-11
* Spells - Self Only (Yellow) cast when non group member is targeted ([#4503](https://github.com/EQEmu/Server/pull/4503)) @fryguy503 2024-10-11
### Loginserver
* Larion loginserver support ([#4492](https://github.com/EQEmu/Server/pull/4492)) @KimLS 2024-10-03
* Login Fatal Error Spamming ([#4476](https://github.com/EQEmu/Server/pull/4476)) @KimLS 2024-10-09
### Logs
* Add NPC Trades to Player Events ([#4505](https://github.com/EQEmu/Server/pull/4505)) @Kinglykrab 2024-10-13
### Quest API
* Add Buff Fade Methods to Perl/Lua ([#4501](https://github.com/EQEmu/Server/pull/4501)) @Kinglykrab 2024-10-09
* Add EVENT_READ_ITEM to Perl/Lua ([#4497](https://github.com/EQEmu/Server/pull/4497)) @Kinglykrab 2024-10-08
* Add NPC List Filter Methods to Perl/Lua ([#4493](https://github.com/EQEmu/Server/pull/4493)) @Kinglykrab 2024-10-04
* Add Scripting Support to Mercenaries ([#4500](https://github.com/EQEmu/Server/pull/4500)) @Kinglykrab 2024-10-11
### Rules
* Add Rule to disable PVP Regions ([#4513](https://github.com/EQEmu/Server/pull/4513)) @Kinglykrab 2024-10-17
## [22.56.3] 9/23/2024
### Fixes
* Fix issue with Client::SaveDisciplines() not specifying character ID ([#4481](https://github.com/EQEmu/Server/pull/4477)) @Kinglykrab 2024-09-23
## [22.56.2] 9/20/2024
### Fixes
* Fix Issue with Database::ReserveName ([#4477](https://github.com/EQEmu/Server/pull/4477)) @Kinglykrab 2024-09-20
### Quest API
* Add GrantAllAAPoints() Overload To Perl/Lua ([#4474](https://github.com/EQEmu/Server/pull/4474)) @Kinglykrab 2024-09-20
## [22.56.1] 9/20/2024
### Fixes
* Fix Untrained Disciplines in Client::SaveDisciplines() ([#4472](https://github.com/EQEmu/Server/pull/4472)) @Kinglykrab 2024-09-13
* Fix Infinite Loop in Adventure::Finished() ([#4473](https://github.com/EQEmu/Server/pull/4473)) @oddx2k 2024-09-13
## [22.56.0] 9/12/2024
### Code
* Add IsCloseToBanker method ([#4462](https://github.com/EQEmu/Server/pull/4462)) @Akkadius 2024-08-27
### Feature
* Add Rule to Limit Task Update Messages ([#4459](https://github.com/EQEmu/Server/pull/4459)) @Kinglykrab 2024-08-28
* Allow NPCs to cast Sacrifice ([#4470](https://github.com/EQEmu/Server/pull/4470)) @fuzzlecutter 2024-09-12
* Lazy Load Bank Contents ([#4453](https://github.com/EQEmu/Server/pull/4453)) @catapultam-habeo 2024-08-27
### Fixes
* Add RULE_STRING to RuleManager::ResetRules ([#4467](https://github.com/EQEmu/Server/pull/4467)) @Kinglykrab 2024-09-07
* Fix Bard Effect in Migration 9237 ([#4468](https://github.com/EQEmu/Server/pull/4468)) @Kinglykrab 2024-09-09
* ModernAAScalingEnabled() Calculation Error ([#4469](https://github.com/EQEmu/Server/pull/4469)) @carolus21rex 2024-09-11
### Performance
* Move Discipline Loading to Client::CompleteConnect() ([#4466](https://github.com/EQEmu/Server/pull/4466)) @Kinglykrab 2024-09-09
### Rules
* Add a Bandolier Swap Delay Rule ([#4465](https://github.com/EQEmu/Server/pull/4465)) @Kinglykrab 2024-09-08
## [22.55.1] 8/26/2024
### Code
* Remove unused methods ([#4449](https://github.com/EQEmu/Server/pull/4449)) @Kinglykrab 2024-08-22
### Feature
* Add Character:DefaultGuildRank Rule ([#4438](https://github.com/EQEmu/Server/pull/4438)) @Kinglykrab 2024-08-04
* Add Optional Return to EVENT_DAMAGE_TAKEN ([#4454](https://github.com/EQEmu/Server/pull/4454)) @Kinglykrab 2024-08-27
* Extend Spell Buckets Functionality ([#4441](https://github.com/EQEmu/Server/pull/4441)) @Kinglykrab 2024-08-22
### Fixes
* Apply Race & Class restrictions to Auto-Combines ([#4452](https://github.com/EQEmu/Server/pull/4452)) @catapultam-habeo 2024-08-20
* Attune Augments when Equipped ([#4446](https://github.com/EQEmu/Server/pull/4446)) @fryguy503 2024-08-10
* Correct missed maxlevel reference in exp.cpp ([#4463](https://github.com/EQEmu/Server/pull/4463)) @N0ctrnl 2024-08-27
* Ensure close of Tribute Item search ([#4439](https://github.com/EQEmu/Server/pull/4439)) @joligario 2024-08-04
* Fix AddCrystals() in Perl/Lua ([#4445](https://github.com/EQEmu/Server/pull/4445)) @Kinglykrab 2024-08-10
* Fix Bot Spell Entries IDs Capping at 32,767 ([#4444](https://github.com/EQEmu/Server/pull/4444)) @Kinglykrab 2024-08-27
* Fix Character ID of 0 being inserted into character_stats_record ([#4458](https://github.com/EQEmu/Server/pull/4458)) @Kinglykrab 2024-08-22
* Fix Issue with Removed #setfaction Command ([#4448](https://github.com/EQEmu/Server/pull/4448)) @Kinglykrab 2024-08-11
* Fix Lua Client FilteredMessage ([#4437](https://github.com/EQEmu/Server/pull/4437)) @Kinglykrab 2024-07-31
* Fix client hotbar exchanging items when zoning ([#4460](https://github.com/EQEmu/Server/pull/4460)) @neckkola 2024-08-27
* Fix issue with killed mob coordinates ([#4457](https://github.com/EQEmu/Server/pull/4457)) @Kinglykrab 2024-08-22
* Imitate Death should also clear zone feign aggro ([#4436](https://github.com/EQEmu/Server/pull/4436)) @fryguy503 2024-07-31
* client_max_level allow leveling to end of level ([#4455](https://github.com/EQEmu/Server/pull/4455)) @fryguy503 2024-08-20
### Improvement
* Filtered Messages Extension ([#4435](https://github.com/EQEmu/Server/pull/4435)) @fryguy503 2024-07-31
### Quest API
* Add AreTasksCompleted() to Perl/Lua. ([#4456](https://github.com/EQEmu/Server/pull/4456)) @Kinglykrab 2024-08-23
* Add Area-Based Quest Methods to Perl/Lua ([#4447](https://github.com/EQEmu/Server/pull/4447)) @Kinglykrab 2024-08-27
* Add Several Door Methods to Perl/Lua ([#4451](https://github.com/EQEmu/Server/pull/4451)) @Kinglykrab 2024-08-16
### World
* Fix slow world bootup bug ([#4461](https://github.com/EQEmu/Server/pull/4461)) @Akkadius 2024-08-27
## [22.54.0] 7/30/2024
### Code
* Cleanup Client File Exporting ([#4348](https://github.com/EQEmu/Server/pull/4348)) @Kinglykrab 2024-07-31
* Cleanup Stance Code ([#4368](https://github.com/EQEmu/Server/pull/4368)) @Kinglykrab 2024-07-03
* Mask GM Show Buff message behind EntityVariable ([#4419](https://github.com/EQEmu/Server/pull/4419)) @nytmyr 2024-07-22
### Commands
* Extend #devtools Functionality ([#4425](https://github.com/EQEmu/Server/pull/4425)) @Kinglykrab 2024-07-23
### Databuckets
* Remove memory reserve from bulk load ([#4427](https://github.com/EQEmu/Server/pull/4427)) @Akkadius 2024-07-23
### Feature
* Add Barter/Buyer Features ([#4405](https://github.com/EQEmu/Server/pull/4405)) @neckkola 2024-07-30
* Add Parcel notification for online players when using the Quest API ([#4418](https://github.com/EQEmu/Server/pull/4418)) @neckkola 2024-07-22
* Implement Move Multiple Items ([#4259](https://github.com/EQEmu/Server/pull/4259)) @catapultam-habeo 2024-07-30
### Fixes
* Aegolism Spell line stacking ([#4399](https://github.com/EQEmu/Server/pull/4399)) @KayenEQ 2024-07-07
* AllowRaidTargetBlind logic backwards ([#4400](https://github.com/EQEmu/Server/pull/4400)) @fryguy503 2024-07-01
* AutoSplit unknown bug and cleanup. ([#4401](https://github.com/EQEmu/Server/pull/4401)) @fryguy503 2024-07-07
* Corpse Call removing Resurrection Effects ([#4410](https://github.com/EQEmu/Server/pull/4410)) @fryguy503 2024-07-22
* Fix #parcels add subcommand ([#4431](https://github.com/EQEmu/Server/pull/4431)) @neckkola 2024-07-29
* Fix #setlevel Allowing Skills Above Max ([#4423](https://github.com/EQEmu/Server/pull/4423)) @Kinglykrab 2024-07-23
* Fix Bot::SetBotStance ([#4426](https://github.com/EQEmu/Server/pull/4426)) @Kinglykrab 2024-07-23
* Fix Client::RemoveTitle ([#4421](https://github.com/EQEmu/Server/pull/4421)) @Kinglykrab 2024-07-23
* Fix EVENT_USE_SKILL with Sense Heading ([#4424](https://github.com/EQEmu/Server/pull/4424)) @Kinglykrab 2024-07-23
* Fix for random disconnects when a large number of guild members zone or disconnect ([#4402](https://github.com/EQEmu/Server/pull/4402)) @neckkola 2024-07-10
* Fix issue with quest::echo and quest::me ([#4433](https://github.com/EQEmu/Server/pull/4433)) @Kinglykrab 2024-07-30
* Personal tributes for bard items were not applying correctly ([#4416](https://github.com/EQEmu/Server/pull/4416)) @neckkola 2024-07-16
* Potential fix for some undesired ranged explotative behavior. ([#4413](https://github.com/EQEmu/Server/pull/4413)) @fryguy503 2024-07-22
* Proximity Aggro for Frustrated and Undead ([#4411](https://github.com/EQEmu/Server/pull/4411)) @fryguy503 2024-07-22
* Slay Adjustments ([#4389](https://github.com/EQEmu/Server/pull/4389)) @fryguy503 2024-07-07
* Stop DOSing ourselves with OP_WearChange ([#4432](https://github.com/EQEmu/Server/pull/4432)) @catapultam-habeo 2024-07-30
* [Quest API] Fix getraididbycharid and getgroupidbycharid ([#4417](https://github.com/EQEmu/Server/pull/4417)) @nytmyr 2024-07-16
### Improvement
* Flee Overhaul ([#4407](https://github.com/EQEmu/Server/pull/4407)) @fryguy503 2024-07-30
### Rules
* Add HasteCap and Hastev3Cap rules for NPCs, Bots and Mercs ([#4406](https://github.com/EQEmu/Server/pull/4406)) @nytmyr 2024-07-22
### Zone Instances
* Revert " Handle routing to instances when using evac/succor " (#4429) ([#4297](https://github.com/EQEmu/Server/pull/4297)) @Akkadius 2024-07-30
### Zoning
* Improve zone routing ([#4428](https://github.com/EQEmu/Server/pull/4428)) @Akkadius 2024-07-30
## [22.53.1] 6/16/2024
### Fixes
* Fix trader mode ([#4397](https://github.com/EQEmu/Server/pull/4397)) @joligario 2024-06-17
## [22.53.0] 6/14/2024
### Bug
* Anon players should not show in /who all ([#4392](https://github.com/EQEmu/Server/pull/4392)) @fryguy503 2024-06-14
* Escape should put player into SOS if owned. ([#4388](https://github.com/EQEmu/Server/pull/4388)) @fryguy503 2024-06-07
* Prevent Resurrection Spells from being resisted ([#4393](https://github.com/EQEmu/Server/pull/4393)) @fryguy503 2024-06-14
### Code
* Cleanup Account Status Code ([#4376](https://github.com/EQEmu/Server/pull/4376)) @Kinglykrab 2024-06-02
* Cleanup Body Type Code ([#4366](https://github.com/EQEmu/Server/pull/4366)) @Kinglykrab 2024-06-02
* Cleanup Object Type Code ([#4375](https://github.com/EQEmu/Server/pull/4375)) @Kinglykrab 2024-06-14
* Remove unused code in emu_constants.h ([#4384](https://github.com/EQEmu/Server/pull/4384)) @Kinglykrab 2024-06-14
### Fixes
* Fix #goto Target ([#4382](https://github.com/EQEmu/Server/pull/4382)) @Kinglykrab 2024-06-03
* Fix Swarm Pet Damage Messages ([#4383](https://github.com/EQEmu/Server/pull/4383)) @Kinglykrab 2024-06-04
* Fix for players having empty bazaar window dropdown list, even though trader is tagged as a trader. ([#4391](https://github.com/EQEmu/Server/pull/4391)) @neckkola 2024-06-14
* Fix potential trader crash when serialized item not found ([#4386](https://github.com/EQEmu/Server/pull/4386)) @joligario 2024-06-14
### Rules
* Add Invisible Augment Rules ([#4385](https://github.com/EQEmu/Server/pull/4385)) @Kinglykrab 2024-06-14
* Classic Harm Touch Formula ([#4394](https://github.com/EQEmu/Server/pull/4394)) @fryguy503 2024-06-14
* Mend/Sneak allow success tuning ([#4390](https://github.com/EQEmu/Server/pull/4390)) @fryguy503 2024-06-14
* Snare Override Movement Bonus ([#4381](https://github.com/EQEmu/Server/pull/4381)) @fryguy503 2024-06-02
## [22.52.0] 6/1/2024
### Code
* Cleanup Bucket Comparison Code ([#4374](https://github.com/EQEmu/Server/pull/4374)) @Kinglykrab 2024-06-02
* Cleanup Bug Category Code ([#4367](https://github.com/EQEmu/Server/pull/4367)) @Kinglykrab 2024-06-01
* Cleanup Deity Code ([#4363](https://github.com/EQEmu/Server/pull/4363)) @Kinglykrab 2024-06-01
* Cleanup Special Ability Code ([#4365](https://github.com/EQEmu/Server/pull/4365)) @Kinglykrab 2024-06-01
* Remove unused code in common/eq_constants.h ([#4364](https://github.com/EQEmu/Server/pull/4364)) @Kinglykrab 2024-06-01
### Combat
* Adjustments to Crippling Blows/Slay Undead and Confirmed Critical Code ([#4354](https://github.com/EQEmu/Server/pull/4354)) @fryguy503 2024-05-27
### Fixes
* Add protection to ensure adventure points award are only attempted on players ([#4371](https://github.com/EQEmu/Server/pull/4371)) @joligario 2024-05-31
* Adjust Kick/RoundKick Damage Lower levels ([#4355](https://github.com/EQEmu/Server/pull/4355)) @fryguy503 2024-05-28
* Bazaar Search not working correctly for Iksar, Vashir, Drakkin and Froglok races ([#4379](https://github.com/EQEmu/Server/pull/4379)) @neckkola 2024-06-02
* Fix Unescaped String in Client::GotoPlayer ([#4373](https://github.com/EQEmu/Server/pull/4373)) @Kinglykrab 2024-06-01
### NPC Spells
* Fixed an issue where the repository spell adj value was overriding the spell difficulty default value ([#4370](https://github.com/EQEmu/Server/pull/4370)) @regneq 2024-06-01
### Quest API
* Add Item Link Methods to Perl/Lua ([#4359](https://github.com/EQEmu/Server/pull/4359)) @Kinglykrab 2024-06-01
### Quests
* Fix Lua encounter double register ([#4369](https://github.com/EQEmu/Server/pull/4369)) @Akkadius 2024-05-31
* Fix issue with Lua encounters loading in certain circumstances ([#4378](https://github.com/EQEmu/Server/pull/4378)) @Akkadius 2024-06-01
### Rules
* Add Skill Base Damage Rules ([#4360](https://github.com/EQEmu/Server/pull/4360)) @Kinglykrab 2024-06-01
### Skills
* Fix caps out of bounds issue ([#4377](https://github.com/EQEmu/Server/pull/4377)) @Akkadius 2024-06-01
## [22.51.1] 5/27/2024
### Fixes
* Adjust return for perl release check @Akkadius 2024-05-26
* Corrected issue with bazaar purchase via parcels where an incorrect quantity would be calculated. ([#4352](https://github.com/EQEmu/Server/pull/4352)) @neckkola 2024-05-27
### Performance
* Improve SkillCaps::GetTrainLevel() Efficiency ([#4350](https://github.com/EQEmu/Server/pull/4350)) @Kinglykrab 2024-05-26
### Rules
* Legacy Compute Defense against modern agi based defense. ([#4349](https://github.com/EQEmu/Server/pull/4349)) @fryguy503 2024-05-27
## [22.51.0] 5/26/2024
### Commands
* #npcspawn Changes ([#4311](https://github.com/EQEmu/Server/pull/4311)) @twincannon 2024-05-16
* Cleanup #resetaa Command ([#4310](https://github.com/EQEmu/Server/pull/4310)) @Kinglykrab 2024-05-22
### Crash
* Add validation to RemoveXTarget ([#4324](https://github.com/EQEmu/Server/pull/4324)) @Akkadius 2024-05-25
* Fix Zone deconstructor crashes ([#4325](https://github.com/EQEmu/Server/pull/4325)) @Akkadius 2024-05-25
* Fix crash issue when dividing by zero in CalcHPRegen ([#4320](https://github.com/EQEmu/Server/pull/4320)) @Akkadius 2024-05-25
* Fix crash when map name is null ([#4322](https://github.com/EQEmu/Server/pull/4322)) @Akkadius 2024-05-25
* Fix player event crash in ITEM_DESTROY ([#4326](https://github.com/EQEmu/Server/pull/4326)) @Akkadius 2024-05-25
* Fix player events reload when out of bounds ([#4321](https://github.com/EQEmu/Server/pull/4321)) @Akkadius 2024-05-25
* Fix rarer crash in EntityList::MobProcess ([#4319](https://github.com/EQEmu/Server/pull/4319)) @Akkadius 2024-05-25
### Feature
* Add RoF2 Bazaar Support ([#4315](https://github.com/EQEmu/Server/pull/4315)) @neckkola 2024-05-26
* Add SE_IncreaseArchery and rules to tune archery ([#4335](https://github.com/EQEmu/Server/pull/4335)) @fryguy503 2024-05-26
* Add parcel container support ([#4305](https://github.com/EQEmu/Server/pull/4305)) @neckkola 2024-05-17
### Fixes
* Accuracy, Avoidance and Atk adjustments ([#4336](https://github.com/EQEmu/Server/pull/4336)) @fryguy503 2024-05-26
* Fix Crash with null Argument in #modifynpcstat ([#4318](https://github.com/EQEmu/Server/pull/4318)) @Kinglykrab 2024-05-24
* Fix RemoveAlternateCurrencyValue not updating Client ([#4317](https://github.com/EQEmu/Server/pull/4317)) @Kinglykrab 2024-05-23
* Fix Using Bind Wound Above 70% Health ([#4340](https://github.com/EQEmu/Server/pull/4340)) @Kinglykrab 2024-05-26
* Fix issue with #hotfix ([#4316](https://github.com/EQEmu/Server/pull/4316)) @Kinglykrab 2024-05-22
* Fix issue with #suspend ([#4314](https://github.com/EQEmu/Server/pull/4314)) @Kinglykrab 2024-05-23
* Fix issue with KeepOneRecordPerCompletedTask ([#4313](https://github.com/EQEmu/Server/pull/4313)) @Kinglykrab 2024-05-23
* Fix mistaken removed RULE_CATEGORY_END() ([#4341](https://github.com/EQEmu/Server/pull/4341)) @fryguy503 2024-05-26
* Missed a mob offense section for PR #4328 ([#4331](https://github.com/EQEmu/Server/pull/4331)) @fryguy503 2024-05-26
* Raid Targets should not be Blindable as this will break all spell casting AI. ([#4334](https://github.com/EQEmu/Server/pull/4334)) @fryguy503 2024-05-26
* When Mounts are allowed to zone, block them from zoning to disallowed zones. ([#4330](https://github.com/EQEmu/Server/pull/4330)) @fryguy503 2024-05-25
* When refreshing buffs, attempt to use the same buffslot if the buff still exists. ([#4338](https://github.com/EQEmu/Server/pull/4338)) @fryguy503 2024-05-26
### Lua Mod
* Fix issue with SetAAEXP and SetEXP firing when uninitialized ([#4345](https://github.com/EQEmu/Server/pull/4345)) @Akkadius 2024-05-26
### Merchants
* Add New Classic Greed/Faction/Charisma Prices Rule ([#4301](https://github.com/EQEmu/Server/pull/4301)) @noudess 2024-05-17
### Mobs
* Remove entity type checks from ScanCloseMobs ([#4323](https://github.com/EQEmu/Server/pull/4323)) @Akkadius 2024-05-25
### NPC Spells
* Fix an issue where procs wouldn't fire if no spell entries in list ([#4344](https://github.com/EQEmu/Server/pull/4344)) @Akkadius 2024-05-26
### Perl
* Linux /opt/eqemu-perl checks when using release binaries ([#4346](https://github.com/EQEmu/Server/pull/4346)) @Akkadius 2024-05-26
### Quest API
* Add Zone Uptime Exports to Perl/Lua ([#4339](https://github.com/EQEmu/Server/pull/4339)) @Kinglykrab 2024-05-26
### Rules
* Added MeleeMitigation Level Difference Roll Adjusted for level diffs ([#4332](https://github.com/EQEmu/Server/pull/4332)) @fryguy503 2024-05-26
* Allow maximum per kill AA amount ([#4329](https://github.com/EQEmu/Server/pull/4329)) @fryguy503 2024-05-25
* Allow servers to adjust the filtering threshold for heals from damage (e.g. Mark of Kings). ([#4327](https://github.com/EQEmu/Server/pull/4327)) @fryguy503 2024-05-25
* Backstab Haste Correction ([#4337](https://github.com/EQEmu/Server/pull/4337)) @fryguy503 2024-05-26
* Mob Offensive and Weapon Skill static tables ([#4328](https://github.com/EQEmu/Server/pull/4328)) @fryguy503 2024-05-25
* Remove hard coded initial aggro in favor or an adjustable Rule ([#4333](https://github.com/EQEmu/Server/pull/4333)) @fryguy503 2024-05-26
### Scripts
* Fix zone data load ordering issue ([#4343](https://github.com/EQEmu/Server/pull/4343)) @Akkadius 2024-05-26
### Spells
* Add content filtering to NPC spells ([#4309](https://github.com/EQEmu/Server/pull/4309)) @Akkadius 2024-05-17
## [22.50.1] 5/12/2024
### Fixes
* Clear GuildOnlineStatus on world boot ([#4306](https://github.com/EQEmu/Server/pull/4306)) @neckkola 2024-05-12
## [22.50.0] 5/9/2024
### Code
@@ -1283,7 +1729,7 @@
### EQTime
Hotfix for world not spamming save messages by setting to detail level logging @Akkadius 2023-11-20
Hotfix for world not spamming save messages by setting to detail level logging @Akkadius 2023-11-20
## [22.34.0] - 11/19/2023
@@ -2365,7 +2811,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Telnet encoding fix ([#3269](https://github.com/EQEmu/Server/pull/3269)) @Akkadius 2023-04-05
## [22.9.1] - 04/03/2023
## [22.9.1] - 04/03/2023
### Code
@@ -2410,7 +2856,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Change to use Pass by reference where valid. ([#3163](https://github.com/EQEmu/Server/pull/3163)) @Aeadoin 2023-04-02
## [22.9.0] - 04/01/2023
## [22.9.0] - 04/01/2023
### Bots
@@ -2434,7 +2880,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Add missing Luabind definitions to lua_general.cpp ([#3167](https://github.com/EQEmu/Server/pull/3167)) @Kinglykrab 2023-04-01
## [22.8.2] - 03/30/2023
## [22.8.2] - 03/30/2023
### Code
@@ -2458,13 +2904,13 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Remove Guild Bank Zone ID Rule ([#3156](https://github.com/EQEmu/Server/pull/3156)) @Kinglykrab 2023-03-29
## [22.8.1] - 03/27/2023
## [22.8.1] - 03/27/2023
### Fixes
* Fix for NPCs having spells interrupted. ([#3150](https://github.com/EQEmu/Server/pull/3150)) @Aeadoin 2023-03-27
## [22.8.0] - 03/25/2023
## [22.8.0] - 03/25/2023
### Code
@@ -2484,7 +2930,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Fix for Items looted from corpses. ([#3147](https://github.com/EQEmu/Server/pull/3147)) @Aeadoin 2023-03-26
* Fix for SQL Query in npc_scale_global_base ([#3144](https://github.com/EQEmu/Server/pull/3144)) @Aeadoin 2023-03-26
## [22.7.0] - 03/24/2023
## [22.7.0] - 03/24/2023
### Bots
@@ -2641,7 +3087,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Add exception handling to converters themselves ([#3029](https://github.com/EQEmu/Server/pull/3029)) @Akkadius 2023-03-05
* Add more number formatters ([#2873](https://github.com/EQEmu/Server/pull/2873)) @Kinglykrab 2023-03-04
## [22.4.5] - 03/03/2023
## [22.4.5] - 03/03/2023
### Bots
@@ -2683,7 +3129,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Add IsFindable() and IsTrackable() to Perl/Lua ([#2996](https://github.com/EQEmu/Server/pull/2996)) @Kinglykrab 2023-03-01
* Add IsUnderwaterOnly() to Perl/Lua ([#2995](https://github.com/EQEmu/Server/pull/2995)) @Kinglykrab 2023-03-01
## [22.4.4] - 02/24/2023
## [22.4.4] - 02/24/2023
### Bots
@@ -2730,7 +3176,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Fix for Lore Conflict ([#2977](https://github.com/EQEmu/Server/pull/2977)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-24
## [22.4.3] - 02/21/2023
## [22.4.3] - 02/21/2023
### Bots
@@ -2777,7 +3223,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Add date to optional Drakkin Guktan Faction Update ([#2965](https://github.com/EQEmu/Server/pull/2965)) ([joligario](https://github.com/joligario)) 2023-02-19
## [22.4.2] - 02/18/2023
## [22.4.2] - 02/18/2023
### Content
@@ -2799,7 +3245,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Fix regression caused by #2932 ([#2956](https://github.com/EQEmu/Server/pull/2956)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-18
## [22.4.1] - 02/17/2023
## [22.4.1] - 02/17/2023
### Bots
@@ -2820,7 +3266,7 @@ Revert Perl regression in #3648 causing scripts to not reliably initialize on zo
* Fix rare out of bound issue when loading event types ([#2946](https://github.com/EQEmu/Server/pull/2946)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
* Turn off KILLED_NPC (trash) off by default ([#2948](https://github.com/EQEmu/Server/pull/2948)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
## [22.4.0] - 02/17/2023
## [22.4.0] - 02/17/2023
### Bots
+39 -140
View File
@@ -29,9 +29,13 @@
#include "../../common/content/world_content_service.h"
#include "../../common/zone_store.h"
#include "../../common/path_manager.h"
#include "../../common/repositories/base_data_repository.h"
#include "../../common/repositories/db_str_repository.h"
#include "../../common/repositories/skill_caps_repository.h"
#include "../../common/repositories/spells_new_repository.h"
#include "../../common/file.h"
#include "../../common/events/player_event_logs.h"
#include "../../common/skill_caps.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
@@ -98,25 +102,22 @@ int main(int argc, char **argv)
->LoadLogDatabaseSettings()
->StartFileLogs();
std::string arg_1;
std::string export_type;
if (argv[1]) {
arg_1 = argv[1];
export_type = argv[1];
}
if (arg_1 == "spells") {
if (Strings::EqualFold(export_type, "spells")) {
ExportSpells(&content_db);
return 0;
}
if (arg_1 == "skills") {
} else if (Strings::EqualFold(export_type, "skills")) {
ExportSkillCaps(&content_db);
return 0;
}
if (arg_1 == "basedata") {
} else if (Strings::EqualFold(export_type, "basedata") || Strings::EqualFold(export_type, "base_data")) {
ExportBaseData(&content_db);
return 0;
}
if (arg_1 == "dbstring") {
} else if (Strings::EqualFold(export_type, "dbstr") || Strings::EqualFold(export_type, "dbstring")) {
ExportDBStrings(&database);
return 0;
}
@@ -131,181 +132,79 @@ int main(int argc, char **argv)
return 0;
}
void ExportSpells(SharedDatabase *db)
void ExportSpells(SharedDatabase* db)
{
LogInfo("Exporting Spells");
std::string file = fmt::format("{}/export/spells_us.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "w");
if (!f) {
std::ofstream file(fmt::format("{}/export/spells_us.txt", path.GetServerPath()));
if (!file || !file.is_open()) {
LogError("Unable to open export/spells_us.txt to write, skipping.");
return;
}
const std::string query = "SELECT * FROM spells_new ORDER BY id";
auto results = db->QueryDatabase(query);
const auto& lines = SpellsNewRepository::GetSpellFileLines(*db);
if (results.Success()) {
for (auto row = results.begin(); row != results.end(); ++row) {
std::string line;
unsigned int fields = results.ColumnCount();
for (unsigned int i = 0; i < fields; ++i) {
if (i != 0) {
line.push_back('^');
}
const std::string& file_string = Strings::Implode("\n", lines);
if (row[i] != nullptr) {
line += row[i];
}
}
file << file_string;
fprintf(f, "%s\n", line.c_str());
}
}
else {
}
file.close();
fclose(f);
}
bool SkillUsable(SharedDatabase* db, int skill_id, int class_id)
{
const auto& l = SkillCapsRepository::GetWhere(
*db,
fmt::format(
"`class_id` = {} AND `skill_id` = {} ORDER BY `cap` DESC LIMIT 1",
class_id,
skill_id
)
);
return !l.empty();
}
uint32 GetSkill(SharedDatabase* db, int skill_id, int class_id, int level)
{
const auto& l = SkillCapsRepository::GetWhere(
*db,
fmt::format(
"`class_id` = {} AND `skill_id` = {} AND `level` = {}",
class_id,
skill_id,
level
)
);
if (l.empty()) {
return 0;
}
auto e = l.front();
return e.cap;
LogInfo("Exported [{}] Spell{}", lines.size(), lines.size() != 1 ? "s" : "");
}
void ExportSkillCaps(SharedDatabase* db)
{
LogInfo("Exporting Skill Caps");
std::ofstream file(fmt::format("{}/export/SkillCaps.txt", path.GetServerPath()));
if (!file || !file.is_open()) {
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
return;
}
const uint8 skill_cap_max_level = (
RuleI(Character, SkillCapMaxLevel) > 0 ?
RuleI(Character, SkillCapMaxLevel) :
RuleI(Character, MaxLevel)
);
const auto& lines = SkillCapsRepository::GetSkillCapFileLines(*db);
for (uint8 class_id = Class::Warrior; class_id <= Class::Berserker; class_id++) {
for (uint8 skill_id = EQ::skills::Skill1HBlunt; skill_id <= EQ::skills::Skill2HPiercing; skill_id++) {
if (SkillUsable(db, skill_id, class_id)) {
uint32 previous_cap = 0;
for (uint8 level = 1; level <= skill_cap_max_level; level++) {
uint32 cap = GetSkill(db, skill_id, class_id, level);
if (cap < previous_cap) {
cap = previous_cap;
}
const std::string& file_string = Strings::Implode("\n", lines);
file << fmt::format("{}^{}^{}^{}^0", class_id, skill_id, level, cap) << std::endl;
previous_cap = cap;
}
}
}
}
file << file_string;
file.close();
LogInfo("Exported [{}] Skill Cap{}", lines.size(), lines.size() != 1 ? "s" : "");
}
void ExportBaseData(SharedDatabase *db)
{
LogInfo("Exporting Base Data");
std::string file = fmt::format("{}/export/BaseData.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "w");
if (!f) {
std::ofstream file(fmt::format("{}/export/BaseData.txt", path.GetServerPath()));
if (!file || !file.is_open()) {
LogError("Unable to open export/BaseData.txt to write, skipping.");
return;
}
const std::string query = "SELECT * FROM base_data ORDER BY level, class";
auto results = db->QueryDatabase(query);
if (results.Success()) {
for (auto row = results.begin(); row != results.end(); ++row) {
std::string line;
unsigned int fields = results.ColumnCount();
for (unsigned int rowIndex = 0; rowIndex < fields; ++rowIndex) {
if (rowIndex != 0) {
line.push_back('^');
}
const auto& lines = BaseDataRepository::GetBaseDataFileLines(*db);
if (row[rowIndex] != nullptr) {
line += row[rowIndex];
}
}
const std::string& file_string = Strings::Implode("\n", lines);
fprintf(f, "%s\n", line.c_str());
}
}
file << file_string;
fclose(f);
file.close();
LogInfo("Exported [{}] Base Data Entr{}", lines.size(), lines.size() != 1 ? "ies" : "y");
}
void ExportDBStrings(SharedDatabase *db)
{
LogInfo("Exporting DB Strings");
std::string file = fmt::format("{}/export/dbstr_us.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "w");
if (!f) {
std::ofstream file(fmt::format("{}/export/dbstr_us.txt", path.GetServerPath()));
if (!file || !file.is_open()) {
LogError("Unable to open export/dbstr_us.txt to write, skipping.");
return;
}
fprintf(f, "Major^Minor^String(New)\n");
const std::string query = "SELECT * FROM db_str ORDER BY id, type";
auto results = db->QueryDatabase(query);
if (results.Success()) {
for (auto row = results.begin(); row != results.end(); ++row) {
std::string line;
unsigned int fields = results.ColumnCount();
for (unsigned int rowIndex = 0; rowIndex < fields; ++rowIndex) {
if (rowIndex != 0) {
line.push_back('^');
}
const auto& lines = DbStrRepository::GetDBStrFileLines(*db);
if (row[rowIndex] != nullptr) {
line += row[rowIndex];
}
}
const std::string& file_string = Strings::Implode("\n", lines);
fprintf(f, "%s\n", line.c_str());
}
}
file << file_string;
fclose(f);
file.close();
LogInfo("Exported [{}] Database String{}", lines.size(), lines.size() != 1 ? "s" : "");
}
+10 -1
View File
@@ -2,6 +2,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
SET(common_sources
base_packet.cpp
bazaar.cpp
bodytypes.cpp
classes.cpp
cli/eqemu_command_handler.cpp
compression.cpp
@@ -60,6 +62,7 @@ SET(common_sources
mutex.cpp
mysql_request_result.cpp
mysql_request_row.cpp
mysql_stmt.cpp
opcode_map.cpp
opcodemgr.cpp
packet_dump.cpp
@@ -156,6 +159,7 @@ SET(repositories
repositories/base/base_bugs_repository.h
repositories/base/base_bug_reports_repository.h
repositories/base/base_buyer_repository.h
repositories/base/base_buyer_trade_items_repository.h
repositories/base/base_character_activities_repository.h
repositories/base/base_character_alternate_abilities_repository.h
repositories/base/base_character_alt_currency_repository.h
@@ -178,6 +182,7 @@ SET(repositories
repositories/base/base_character_material_repository.h
repositories/base/base_character_memmed_spells_repository.h
repositories/base/base_character_parcels_repository.h
repositories/base/base_character_parcels_containers_repository.h
repositories/base/base_character_peqzone_flags_repository.h
repositories/base/base_character_pet_buffs_repository.h
repositories/base/base_character_pet_info_repository.h
@@ -336,7 +341,8 @@ SET(repositories
repositories/books_repository.h
repositories/bugs_repository.h
repositories/bug_reports_repository.h
repositories/buyer_repository.h
repositories/buyer_buy_lines_repository.h
repositories/buyer_trade_items_repository.h
repositories/character_activities_repository.h
repositories/character_alternate_abilities_repository.h
repositories/character_alt_currency_repository.h
@@ -359,6 +365,7 @@ SET(repositories
repositories/character_material_repository.h
repositories/character_memmed_spells_repository.h
repositories/character_parcels_repository.h
repositories/character_parcels_containers_repository.h
repositories/character_peqzone_flags_repository.h
repositories/character_pet_buffs_repository.h
repositories/character_pet_info_repository.h
@@ -499,6 +506,7 @@ SET(repositories
SET(common_headers
additive_lagged_fibonacci_engine.h
bazaar.h
base_packet.h
bodytypes.h
classes.h
@@ -579,6 +587,7 @@ SET(common_headers
mutex.h
mysql_request_result.h
mysql_request_row.h
mysql_stmt.h
op_codes.h
opcode_dispatch.h
opcodemgr.h
+360
View File
@@ -0,0 +1,360 @@
#include "bazaar.h"
#include "../../common/item_instance.h"
#include "repositories/trader_repository.h"
#include <memory>
std::vector<BazaarSearchResultsFromDB_Struct>
Bazaar::GetSearchResults(
SharedDatabase &db,
BazaarSearchCriteria_Struct search,
uint32 char_zone_id
)
{
LogTrading(
"Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] "
"max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] "
"search_scope [{}] char_zone_id [{}]",
search.item_name,
search.min_cost,
search.max_cost,
search.min_level,
search.max_level,
search.max_results,
search.prestige,
search.augment,
search.trader_entity_id,
search.trader_id,
search.search_scope,
char_zone_id
);
std::string search_criteria_trader("TRUE ");
if (search.search_scope == NonRoFBazaarSearchScope) {
search_criteria_trader.append(
fmt::format(
" AND trader.char_entity_id = {} AND trader.char_zone_id = {}",
search.trader_entity_id,
Zones::BAZAAR
)
);
}
else if (search.search_scope == Local_Scope) {
search_criteria_trader.append(fmt::format(" AND trader.char_zone_id = {}", char_zone_id));
}
else if (search.trader_id > 0) {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
}
if (search.min_cost != 0) {
search_criteria_trader.append(fmt::format(" AND trader.item_cost >= {}", search.min_cost * 1000));
}
if (search.max_cost != 0) {
search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000));
}
// not yet implemented
// if (search.prestige != 0) {
// 0xffffffff prestige only, 0xfffffffe non-prestige, 0 all
// search_criteria.append(fmt::format(" AND items.type = {} ", search.prestige));
// }
std::string query = fmt::format(
"SELECT COUNT(item_id), trader.char_id, trader.item_id, trader.item_sn, trader.item_charges, trader.item_cost, "
"trader.slot_id, SUM(trader.item_charges), trader.char_zone_id, trader.char_entity_id, character_data.name, "
"aug_slot_1, aug_slot_2, aug_slot_3, aug_slot_4, aug_slot_5, aug_slot_6 "
"FROM trader, character_data "
"WHERE {} AND trader.char_id = character_data.id "
"GROUP BY trader.item_sn, trader.item_charges, trader.char_id",
search_criteria_trader.c_str()
);
std::vector<BazaarSearchResultsFromDB_Struct> all_entries;
auto results = db.QueryDatabase(query);
if (!results.Success()) {
return all_entries;
}
struct ItemSearchType {
EQ::item::ItemType type;
bool condition;
};
struct AddititiveSearchCriteria {
bool should_check;
bool condition;
};
for (auto row: results) {
BazaarSearchResultsFromDB_Struct r{};
r.item_id = Strings::ToInt(row[2]);
r.charges = Strings::ToInt(row[4]);
auto item = db.GetItem(r.item_id);
if (!item) {
continue;
}
uint32 aug_slot_1 = Strings::ToUnsignedInt(row[11]);
uint32 aug_slot_2 = Strings::ToUnsignedInt(row[12]);
uint32 aug_slot_3 = Strings::ToUnsignedInt(row[13]);
uint32 aug_slot_4 = Strings::ToUnsignedInt(row[14]);
uint32 aug_slot_5 = Strings::ToUnsignedInt(row[15]);
uint32 aug_slot_6 = Strings::ToUnsignedInt(row[16]);
std::unique_ptr<EQ::ItemInstance> inst(
db.CreateItem(
item,
r.charges,
aug_slot_1,
aug_slot_2,
aug_slot_3,
aug_slot_4,
aug_slot_5,
aug_slot_6
)
);
if (!inst->GetItem()) {
continue;
}
r.count = Strings::ToInt(row[0]);
r.trader_id = Strings::ToInt(row[1]);
r.serial_number = Strings::ToInt(row[3]);
r.cost = Strings::ToInt(row[5]);
r.slot_id = Strings::ToInt(row[6]);
r.sum_charges = Strings::ToInt(row[7]);
r.stackable = item->Stackable;
r.icon_id = item->Icon;
r.trader_zone_id = Strings::ToInt(row[8]);
r.trader_entity_id = Strings::ToInt(row[9]);
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
r.item_name = fmt::format("{:.63}\0", item->Name);
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
LogTradingDetail(
"Searching against item [{}] ({}) for trader [{}]",
item->Name,
item->ID,
r.trader_name
);
// item stat searches
std::map<uint32, uint32> item_stat_searches = {
{STAT_AC, inst->GetItemArmorClass(true)},
{STAT_AGI, static_cast<uint32>(inst->GetItemAgi(true))},
{STAT_CHA, static_cast<uint32>(inst->GetItemCha(true))},
{STAT_DEX, static_cast<uint32>(inst->GetItemDex(true))},
{STAT_INT, static_cast<uint32>(inst->GetItemInt(true))},
{STAT_STA, static_cast<uint32>(inst->GetItemSta(true))},
{STAT_STR, static_cast<uint32>(inst->GetItemStr(true))},
{STAT_WIS, static_cast<uint32>(inst->GetItemWis(true))},
{STAT_COLD, static_cast<uint32>(inst->GetItemCR(true))},
{STAT_DISEASE, static_cast<uint32>(inst->GetItemDR(true))},
{STAT_FIRE, static_cast<uint32>(inst->GetItemFR(true))},
{STAT_MAGIC, static_cast<uint32>(inst->GetItemMR(true))},
{STAT_POISON, static_cast<uint32>(inst->GetItemPR(true))},
{STAT_HP, static_cast<uint32>(inst->GetItemHP(true))},
{STAT_MANA, static_cast<uint32>(inst->GetItemMana(true))},
{STAT_ENDURANCE, static_cast<uint32>(inst->GetItemEndur(true))},
{STAT_ATTACK, static_cast<uint32>(inst->GetItemAttack(true))},
{STAT_HP_REGEN, static_cast<uint32>(inst->GetItemRegen(true))},
{STAT_MANA_REGEN, static_cast<uint32>(inst->GetItemManaRegen(true))},
{STAT_HASTE, static_cast<uint32>(inst->GetItemHaste(true))},
{STAT_DAMAGE_SHIELD, static_cast<uint32>(inst->GetItemDamageShield(true))},
{STAT_DS_MITIGATION, static_cast<uint32>(inst->GetItemDSMitigation(true))},
{STAT_HEAL_AMOUNT, static_cast<uint32>(inst->GetItemHealAmt(true))},
{STAT_SPELL_DAMAGE, static_cast<uint32>(inst->GetItemSpellDamage(true))},
{STAT_CLAIRVOYANCE, static_cast<uint32>(inst->GetItemClairvoyance(true))},
{STAT_HEROIC_AGILITY, static_cast<uint32>(inst->GetItemHeroicAgi(true))},
{STAT_HEROIC_CHARISMA, static_cast<uint32>(inst->GetItemHeroicCha(true))},
{STAT_HEROIC_DEXTERITY, static_cast<uint32>(inst->GetItemHeroicDex(true))},
{STAT_HEROIC_INTELLIGENCE, static_cast<uint32>(inst->GetItemHeroicInt(true))},
{STAT_HEROIC_STAMINA, static_cast<uint32>(inst->GetItemHeroicSta(true))},
{STAT_HEROIC_STRENGTH, static_cast<uint32>(inst->GetItemHeroicStr(true))},
{STAT_HEROIC_WISDOM, static_cast<uint32>(inst->GetItemHeroicWis(true))},
{STAT_BASH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillBash, true))},
{STAT_BACKSTAB, static_cast<uint32>(inst->GetItemBackstabDamage(true))},
{STAT_DRAGON_PUNCH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillDragonPunch, true))},
{STAT_EAGLE_STRIKE, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillEagleStrike, true))},
{STAT_FLYING_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFlyingKick, true))},
{STAT_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillKick, true))},
{STAT_ROUND_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillRoundKick, true))},
{STAT_TIGER_CLAW, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillTigerClaw, true))},
{STAT_FRENZY, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFrenzy, true))},
};
r.item_stat = item_stat_searches.contains(search.item_stat) ? item_stat_searches[search.item_stat] : 0;
if (item_stat_searches.contains(search.item_stat) && item_stat_searches[search.item_stat] <= 0) {
continue;
}
static std::map<uint8, uint32> item_slot_searches = {
{EQ::invslot::slotCharm, 1},
{EQ::invslot::slotEar1, 2},
{EQ::invslot::slotHead, 4},
{EQ::invslot::slotFace, 8},
{EQ::invslot::slotEar2, 16},
{EQ::invslot::slotNeck, 32},
{EQ::invslot::slotShoulders, 64},
{EQ::invslot::slotArms, 128},
{EQ::invslot::slotBack, 256},
{EQ::invslot::slotWrist1, 512},
{EQ::invslot::slotWrist2, 1024},
{EQ::invslot::slotRange, 2048},
{EQ::invslot::slotHands, 4096},
{EQ::invslot::slotPrimary, 8192},
{EQ::invslot::slotSecondary, 16384},
{EQ::invslot::slotFinger1, 32768},
{EQ::invslot::slotFinger2, 65536},
{EQ::invslot::slotChest, 131072},
{EQ::invslot::slotLegs, 262144},
{EQ::invslot::slotFeet, 524288},
{EQ::invslot::slotWaist, 1048576},
{EQ::invslot::slotPowerSource, 2097152},
{EQ::invslot::slotAmmo, 4194304},
};
auto GetEquipmentSlotBit = [&](uint32 slot) -> uint32 {
return item_slot_searches.contains(slot) ? item_slot_searches[slot] : 0;
};
auto FindItemAugSlot = [&]() -> bool {
for (auto const &s: inst->GetItem()->AugSlotType) {
return s == search.augment;
}
return false;
};
// item type searches
std::vector<ItemSearchType> item_search_types = {
{EQ::item::ItemType::ItemTypeAll, true},
{EQ::item::ItemType::ItemTypeBook, item->ItemClass == EQ::item::ItemType::ItemTypeBook},
{EQ::item::ItemType::ItemTypeContainer, item->ItemClass == EQ::item::ItemType::ItemTypeContainer ||
item->IsClassBag()},
{EQ::item::ItemType::ItemTypeAllEffects, item->Scroll.Effect > 0 && item->Scroll.Effect < 65000},
{EQ::item::ItemType::ItemTypeUnknown9, item->Worn.Effect == 998},
{EQ::item::ItemType::ItemTypeUnknown10, item->Worn.Effect >= 1298 && item->Worn.Effect <= 1307},
{EQ::item::ItemType::ItemTypeFocusEffect, item->Focus.Effect > 0},
{EQ::item::ItemType::ItemTypeArmor, item->ItemType == EQ::item::ItemType::ItemTypeArmor},
{EQ::item::ItemType::ItemType1HBlunt, item->ItemType == EQ::item::ItemType::ItemType1HBlunt},
{EQ::item::ItemType::ItemType1HPiercing, item->ItemType == EQ::item::ItemType::ItemType1HPiercing},
{EQ::item::ItemType::ItemType1HSlash, item->ItemType == EQ::item::ItemType::ItemType1HSlash},
{EQ::item::ItemType::ItemType2HBlunt, item->ItemType == EQ::item::ItemType::ItemType2HBlunt},
{EQ::item::ItemType::ItemType2HSlash, item->ItemType == EQ::item::ItemType::ItemType2HSlash},
{EQ::item::ItemType::ItemTypeBow, item->ItemType == EQ::item::ItemType::ItemTypeBow},
{EQ::item::ItemType::ItemTypeShield, item->ItemType == EQ::item::ItemType::ItemTypeShield},
{EQ::item::ItemType::ItemTypeMisc, item->ItemType == EQ::item::ItemType::ItemTypeMisc},
{EQ::item::ItemType::ItemTypeFood, item->ItemType == EQ::item::ItemType::ItemTypeFood},
{EQ::item::ItemType::ItemTypeDrink, item->ItemType == EQ::item::ItemType::ItemTypeDrink},
{EQ::item::ItemType::ItemTypeLight, item->ItemType == EQ::item::ItemType::ItemTypeLight},
{EQ::item::ItemType::ItemTypeCombinable, item->ItemType == EQ::item::ItemType::ItemTypeCombinable},
{EQ::item::ItemType::ItemTypeBandage, item->ItemType == EQ::item::ItemType::ItemTypeBandage},
{EQ::item::ItemType::ItemTypeSmallThrowing, item->ItemType == EQ::item::ItemType::ItemTypeSmallThrowing ||
item->ItemType == EQ::item::ItemType::ItemTypeLargeThrowing},
{EQ::item::ItemType::ItemTypeSpell, item->ItemType == EQ::item::ItemType::ItemTypeSpell},
{EQ::item::ItemType::ItemTypePotion, item->ItemType == EQ::item::ItemType::ItemTypePotion},
{EQ::item::ItemType::ItemTypeBrassInstrument, item->ItemType == EQ::item::ItemType::ItemTypeBrassInstrument},
{EQ::item::ItemType::ItemTypeWindInstrument, item->ItemType == EQ::item::ItemType::ItemTypeWindInstrument},
{EQ::item::ItemType::ItemTypeStringedInstrument, item->ItemType == EQ::item::ItemType::ItemTypeStringedInstrument},
{EQ::item::ItemType::ItemTypePercussionInstrument, item->ItemType == EQ::item::ItemType::ItemTypePercussionInstrument},
{EQ::item::ItemType::ItemTypeArrow, item->ItemType == EQ::item::ItemType::ItemTypeArrow},
{EQ::item::ItemType::ItemTypeJewelry, item->ItemType == EQ::item::ItemType::ItemTypeJewelry},
{EQ::item::ItemType::ItemTypeNote, item->ItemType == EQ::item::ItemType::ItemTypeNote},
{EQ::item::ItemType::ItemTypeKey, item->ItemType == EQ::item::ItemType::ItemTypeKey},
{EQ::item::ItemType::ItemType2HPiercing, item->ItemType == EQ::item::ItemType::ItemType2HPiercing},
{EQ::item::ItemType::ItemTypeAlcohol, item->ItemType == EQ::item::ItemType::ItemTypeAlcohol},
{EQ::item::ItemType::ItemTypeMartial, item->ItemType == EQ::item::ItemType::ItemTypeMartial},
{EQ::item::ItemType::ItemTypeAugmentation, item->ItemType == EQ::item::ItemType::ItemTypeAugmentation},
{EQ::item::ItemType::ItemTypeAlternateAbility, item->ItemType == EQ::item::ItemType::ItemTypeAlternateAbility},
{EQ::item::ItemType::ItemTypeCount, item->ItemType == EQ::item::ItemType::ItemTypeCount},
{EQ::item::ItemType::ItemTypeCollectible, item->ItemType == EQ::item::ItemType::ItemTypeCollectible}
};
bool met_filter = false;
bool has_filter = false;
for (auto &i: item_search_types) {
if (i.type == search.type) {
has_filter = true;
if (i.condition) {
LogTradingDetail("Item [{}] met search criteria for type [{}]", item->Name, uint8(i.type));
met_filter = true;
break;
}
}
}
if (has_filter && !met_filter) {
continue;
}
// TODO: Add catch-all item type filter for specific item types
// item additive searches
std::vector<AddititiveSearchCriteria> item_additive_searches = {
{
.should_check = search.min_level != 1 && inst->GetItemRequiredLevel(true) > 0,
.condition = inst->GetItemRequiredLevel(true) >= search.min_level
},
{
.should_check = search.max_level != 1 && inst->GetItemRequiredLevel(true) > 0,
.condition = inst->GetItemRequiredLevel(true) <= search.max_level
},
{
.should_check = !std::string(search.item_name).empty(),
.condition = Strings::ContainsLower(item->Name, search.item_name)
},
{
.should_check = search._class != 0xFFFFFFFF,
.condition = static_cast<bool>(item->Classes & GetPlayerClassBit(search._class))
},
{
.should_check = search.race != 0xFFFFFFFF,
.condition = static_cast<bool>(item->Races & GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race)))
},
{
.should_check = search.augment != 0,
.condition = FindItemAugSlot()
},
{
.should_check = search.slot != 0xFFFFFFFF,
.condition = static_cast<bool>(item->Slots & GetEquipmentSlotBit(search.slot))
},
};
bool should_add = true;
for (auto &i: item_additive_searches) {
LogTradingDetail(
"Checking item [{}] for search criteria - should_check [{}] condition [{}]",
item->Name,
i.should_check,
i.condition
);
if (i.should_check && !i.condition) {
should_add = false;
continue;
}
}
if (!should_add) {
continue;
}
LogTradingDetail("Found item [{}] meeting search criteria.", r.item_name);
all_entries.push_back(r);
}
if (all_entries.size() > search.max_results) {
all_entries.resize(search.max_results);
}
LogTrading("Returning [{}] items from search results", all_entries.size());
return all_entries;
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef EQEMU_BAZAAR_H
#define EQEMU_BAZAAR_H
#include <vector>
#include "shareddb.h"
class Bazaar {
public:
static std::vector<BazaarSearchResultsFromDB_Struct>
GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id);
};
#endif //EQEMU_BAZAAR_H
+12
View File
@@ -0,0 +1,12 @@
#include "../common/global_define.h"
#include "../common/bodytypes.h"
std::string BodyType::GetName(uint8 body_type_id)
{
return IsValid(body_type_id) ? body_type_names[body_type_id] : "UNKNOWN BODY TYPE";
}
bool BodyType::IsValid(uint8 body_type_id)
{
return body_type_names.find(body_type_id) != body_type_names.end();
}
+90 -46
View File
@@ -18,52 +18,96 @@
#ifndef BODYTYPES_H
#define BODYTYPES_H
typedef enum {
BT_Humanoid = 1,
BT_Lycanthrope = 2,
BT_Undead = 3,
BT_Giant = 4,
BT_Construct = 5,
BT_Extraplanar = 6,
BT_Magical = 7, //this name might be a bit off,
BT_SummonedUndead = 8,
BT_RaidGiant = 9, //Velious era Raid Giant
BT_RaidColdain = 10, //Velious era Raid Coldain
BT_NoTarget = 11, //no name, can't target this bodytype
BT_Vampire = 12,
BT_Atenha_Ra = 13,
BT_Greater_Akheva = 14,
BT_Khati_Sha = 15,
BT_Seru = 16,
BT_Grieg_Veneficus = 17,
BT_Draz_Nurakk = 18,
BT_Zek = 19, //"creatures from the Plane of War."
BT_Luggald = 20,
BT_Animal = 21,
BT_Insect = 22,
BT_Monster = 23,
BT_Summoned = 24, //Elemental?
BT_Plant = 25,
BT_Dragon = 26,
BT_Summoned2 = 27,
BT_Summoned3 = 28,
BT_Dragon2 = 29, //database data indicates this is a dragon type (kunark and DoN?)
BT_VeliousDragon = 30, //might not be a tight set
BT_Familiar = 31,
BT_Dragon3 = 32,
BT_Boxes = 33,
BT_Muramite = 34, //tribal dudes
// ...
BT_NoTarget2 = 60,
// ...
BT_SwarmPet = 63, //Looks like weapon proc related temp pets and few misc pets, should not be used for checking swarm pets in general.
BT_MonsterSummon = 64,
// 65, trap or effect related?
BT_InvisMan = 66, //no name, seen on 'InvisMan', can be /targeted
BT_Special = 67
} bodyType;
/* bodytypes above 64 make the mob not show up */
#include "types.h"
#include <map>
#include <string>
constexpr int format_as(bodyType type) { return static_cast<int>(type); }
// body types above 64 make the mob invisible
namespace BodyType {
constexpr uint8 Humanoid = 1;
constexpr uint8 Lycanthrope = 2;
constexpr uint8 Undead = 3;
constexpr uint8 Giant = 4;
constexpr uint8 Construct = 5;
constexpr uint8 Extraplanar = 6;
constexpr uint8 Magical = 7; // this name might be a bit off,
constexpr uint8 SummonedUndead = 8;
constexpr uint8 RaidGiant = 9; // Velious era Raid Giant
constexpr uint8 RaidColdain = 10; // Velious era Raid Coldain
constexpr uint8 NoTarget = 11; // no name, can't target this bodytype
constexpr uint8 Vampire = 12;
constexpr uint8 AtenHaRa = 13;
constexpr uint8 GreaterAkheva = 14;
constexpr uint8 KhatiSha = 15;
constexpr uint8 Seru = 16;
constexpr uint8 GriegVeneficus = 17;
constexpr uint8 DrazNurakk = 18;
constexpr uint8 Zek = 19; //"creatures from the Plane of War."
constexpr uint8 Luggald = 20;
constexpr uint8 Animal = 21;
constexpr uint8 Insect = 22;
constexpr uint8 Monster = 23;
constexpr uint8 Summoned = 24; // Elemental?
constexpr uint8 Plant = 25;
constexpr uint8 Dragon = 26;
constexpr uint8 Summoned2 = 27;
constexpr uint8 Summoned3 = 28;
constexpr uint8 Dragon2 = 29; // database data indicates this is a dragon type (Kunark and DoN?)
constexpr uint8 VeliousDragon = 30; // might not be a tight set
constexpr uint8 Familiar = 31;
constexpr uint8 Dragon3 = 32;
constexpr uint8 Boxes = 33;
constexpr uint8 Muramite = 34; // tribal dudes
constexpr uint8 NoTarget2 = 60;
constexpr uint8 SwarmPet = 63; // Looks like weapon proc related temp pets and few misc pets, should not be used for checking swarm pets in general.
constexpr uint8 MonsterSummon = 64;
constexpr uint8 InvisibleMan = 66; // no name, seen on 'InvisMan', can be /targeted
constexpr uint8 Special = 67;
std::string GetName(uint8 body_type_id);
bool IsValid(uint8 body_type_id);
}
static std::map<uint8, std::string> body_type_names = {
{ BodyType::Humanoid, "Humanoid" },
{ BodyType::Lycanthrope, "Lycanthrope" },
{ BodyType::Undead, "Undead" },
{ BodyType::Giant, "Giant" },
{ BodyType::Construct, "Construct" },
{ BodyType::Extraplanar, "Extraplanar" },
{ BodyType::Magical, "Magical" },
{ BodyType::SummonedUndead, "Summoned Undead" },
{ BodyType::RaidGiant, "Raid Giant" },
{ BodyType::RaidColdain, "Raid Coldain" },
{ BodyType::NoTarget, "Untargetable" },
{ BodyType::Vampire, "Vampire" },
{ BodyType::AtenHaRa, "Aten Ha Ra" },
{ BodyType::GreaterAkheva, "Greater Akheva" },
{ BodyType::KhatiSha, "Khati Sha" },
{ BodyType::Seru, "Seru" },
{ BodyType::GriegVeneficus, "Grieg Veneficus" },
{ BodyType::DrazNurakk, "Draz Nurakk" },
{ BodyType::Zek, "Zek" },
{ BodyType::Luggald, "Luggald" },
{ BodyType::Animal, "Animal" },
{ BodyType::Insect, "Insect" },
{ BodyType::Monster, "Monster" },
{ BodyType::Summoned, "Summoned" },
{ BodyType::Plant, "Plant" },
{ BodyType::Dragon, "Dragon" },
{ BodyType::Summoned2, "Summoned 2" },
{ BodyType::Summoned3, "Summoned 3" },
{ BodyType::Dragon2, "Dragon 2" },
{ BodyType::VeliousDragon, "Velious Dragon" },
{ BodyType::Familiar, "Familiar" },
{ BodyType::Dragon3, "Dragon 3" },
{ BodyType::Boxes, "Boxes" },
{ BodyType::Muramite, "Muramite" },
{ BodyType::NoTarget2, "Untargetable 2" },
{ BodyType::SwarmPet, "Swarm Pet" },
{ BodyType::MonsterSummon, "Monster Summon" },
{ BodyType::InvisibleMan, "Invisible Man" },
{ BodyType::Special, "Special" },
};
#endif
+61 -81
View File
@@ -6,6 +6,7 @@
#include "../rulesys.h"
#include "../eqemu_logsys.h"
#include "../repositories/instance_list_repository.h"
#include "../zone_store.h"
WorldContentService::WorldContentService()
@@ -183,8 +184,8 @@ void WorldContentService::ReloadContentFlags()
}
SetContentFlags(set_content_flags);
LoadZones();
LoadStaticGlobalZoneInstances();
zone_store.LoadZones(*m_content_database);
}
Database *WorldContentService::GetDatabase() const
@@ -236,18 +237,6 @@ void WorldContentService::SetContentFlag(const std::string &content_flag_name, b
ReloadContentFlags();
}
// HandleZoneRoutingMiddleware is meant to handle content and context aware zone routing
//
// example # 1
// lavastorm (pre-don) version 0 (classic)
// lavastorm (don) version 1
// we want to route players to the correct version of lavastorm based on the current server side expansion
// in order to do that the simplest and cleanest way we intercept the zoning process and route players to an "instance" of the zone
// the reason why we're doing this is because all of the zoning logic already is handled by two keys "zone_id" and "instance_id"
// we can leverage static, never expires instances to handle this but to the client they don't see it any other way than a public normal zone
// scripts handle all the same way, you don't have to think about instances, the middleware will handle the magic
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
// we decide to route the client to the correct version of the zone based on the current server side expansion
void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
{
auto r = FindZone(zc->zoneID, zc->instanceID);
@@ -261,93 +250,72 @@ void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
// LoadStaticGlobalZoneInstances loads all static global zone instances
// these are zones that are never set to expire and are global
// these are used commonly in v1/v2/v3 versions of the same zone for expansion routing
WorldContentService * WorldContentService::LoadStaticGlobalZoneInstances()
WorldContentService *WorldContentService::LoadStaticGlobalZoneInstances()
{
m_zone_instances = InstanceListRepository::GetWhere(*GetDatabase(), fmt::format("never_expires = 1 AND is_global = 1"));
m_zone_static_instances = InstanceListRepository::GetWhere(
*GetDatabase(),
fmt::format("never_expires = 1 AND is_global = 1")
);
LogInfo("Loaded [{}] zone_instances", m_zone_instances.size());
LogInfo("Loaded [{}] zone_instances", m_zone_static_instances.size());
return this;
}
// LoadZones sets the zones for the world content service
// this is used for zone routing middleware
// we pull the zone list from the zone repository and feed from the zone store for now
// we're holding a copy in the content service - but we're talking 250kb of data in memory to handle routing of zoning
WorldContentService * WorldContentService::LoadZones()
{
m_zones = ZoneRepository::All(*GetContentDatabase());
LogInfo("Loaded [{}] zones", m_zones.size());
return this;
}
// FindZone is critical to the zone routing middleware and any logic that needs to route players to the correct zone
// era contextual routing, multiple version of zones, etc
// FindZone handles content and context aware zone routing (middleware)
//
// this is a middleware function that is meant to be used in the zone change process
// this hooks all core zone changes within the server and routes the player to the correct zone
// returning a zone_id of non-zero means the middleware will route the player
// returning a zone_id of 0 means the middleware will not route the player
// this is useful for handling multiple versions of the same zone
//
// implementation >
// the zoning and process spawning logic already is handled by two keys "zone_id" and "instance_id"
// we leverage static, never expires instances to handle this and client still sees it as a normal zone
//
// content awareness >
// simply use the zone_id, server content settings and the middleware will handle the rest
// you don't have to think about instances in any data tables (use instance_id 0)
// you don't have to keep track of instance ids in scripts (use instance_id 0)
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
// we decide to route the client to the correct version of the zone based on the current server side expansion
//
// example >
// we want to route players to the correct version of lavastorm based on the current server side expansion (DoesZonePassContentFiltering)
// lavastorm (pre-don) version 0 (classic)
// zone table entry for version = 0, min_expansion = 0, max_expansion = 8
// instance_list table entry for lavastorm has version = 0, is_global = 1, never_expires = 1
// lavastorm (don) version 1
// zone table entry for version = 1, min_expansion = 9, max_expansion = 99
// instance_list table entry for lavastorm has version = 1, is_global = 1, never_expires = 1
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
{
// if there's an active dynamic instance, we don't need to route
if (instance_id > 0) {
auto inst = InstanceListRepository::FindOne(*GetDatabase(), instance_id);
if (inst.id != 0 && !inst.is_global && !inst.never_expires) {
return WorldContentService::FindZoneResult{
.zone_id = 0,
};
}
}
for (const auto &z: zone_store.GetZones()) {
for (auto &i: m_zone_static_instances) {
if (
z.zoneidnumber == zone_id &&
DoesZonePassContentFiltering(z) &&
i.zone == zone_id &&
i.version == z.version) {
for (auto &z: m_zones) {
if (z.zoneidnumber == zone_id) {
auto f = ContentFlags{
.min_expansion = z.min_expansion,
.max_expansion = z.max_expansion,
.content_flags = z.content_flags,
.content_flags_disabled = z.content_flags_disabled
};
if (DoesPassContentFiltering(f)) {
LogInfo(
"Attempting to route player to zone [{}] ({}) version [{}] long_name [{}]",
z.short_name,
z.zoneidnumber,
z.version,
z.long_name
);
// first pass, explicit match on public static global zone instances
for (auto &i: m_zone_instances) {
if (i.zone == zone_id && i.version == z.version) {
LogInfo(
"Routed player to instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
i.id,
z.short_name,
z.zoneidnumber,
z.version,
z.long_name,
i.notes
);
return WorldContentService::FindZoneResult{
.zone_id = static_cast<uint32>(z.zoneidnumber),
.instance = i,
.zone = z
};
}
if (instance_id > 0 && i.id != instance_id) {
continue;
}
LogInfo(
"Routed player to non-instance zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
"Routed player to public static instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
i.id,
z.short_name,
z.zoneidnumber,
z.version,
z.long_name,
z.note
i.notes
);
return WorldContentService::FindZoneResult{
.zone_id = static_cast<uint32>(z.zoneidnumber),
.instance = InstanceListRepository::NewEntity(),
.instance = i,
.zone = z
};
}
@@ -359,7 +327,7 @@ WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id
bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
{
for (auto &i: m_zone_instances) {
for (auto &i: m_zone_static_instances) {
if (i.id == instance_id) {
return true;
}
@@ -367,3 +335,15 @@ bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
return false;
}
bool WorldContentService::DoesZonePassContentFiltering(const ZoneRepository::Zone &z)
{
auto f = ContentFlags{
.min_expansion = z.min_expansion,
.max_expansion = z.max_expansion,
.content_flags = z.content_flags,
.content_flags_disabled = z.content_flags_disabled
};
return DoesPassContentFiltering(f);
}
+2 -3
View File
@@ -160,6 +160,7 @@ public:
WorldContentService * SetExpansionContext();
bool DoesPassContentFiltering(const ContentFlags& f);
bool DoesZonePassContentFiltering(const ZoneRepository::Zone& z);
WorldContentService * SetDatabase(Database *database);
Database *GetDatabase() const;
@@ -189,10 +190,8 @@ private:
Database *m_content_database;
// holds a record of the zone table from the database
std::vector<ZoneRepository::Zone> m_zones = {};
WorldContentService *LoadStaticGlobalZoneInstances();
std::vector<InstanceListRepository::InstanceList> m_zone_instances;
WorldContentService * LoadZones();
std::vector<InstanceListRepository::InstanceList> m_zone_static_instances;
};
extern WorldContentService content_service;
+75 -17
View File
@@ -66,6 +66,7 @@
#endif
#include "database.h"
#include "data_verification.h"
#include "eq_packet_structs.h"
#include "extprofile.h"
#include "strings.h"
@@ -77,6 +78,8 @@
#include "zone_store.h"
#include "repositories/merchantlist_temp_repository.h"
#include "repositories/bot_data_repository.h"
#include "repositories/trader_repository.h"
#include "repositories/buyer_repository.h"
extern Client client;
@@ -206,9 +209,19 @@ void Database::LoginIP(uint32 account_id, const std::string& login_ip)
QueryDatabase(query);
}
int16 Database::CheckStatus(uint32 account_id)
int16 Database::GetAccountStatus(uint32 account_id)
{
return AccountRepository::GetAccountStatus(*this, account_id);
auto e = AccountRepository::FindOne(*this, account_id);
if (e.suspendeduntil > 0 && e.suspendeduntil < std::time(nullptr)) {
e.status = 0;
e.suspendeduntil = 0;
e.suspend_reason = "";
AccountRepository::UpdateOne(*this, e);
}
return e.status;
}
uint32 Database::CreateAccount(
@@ -272,16 +285,31 @@ bool Database::SetAccountStatus(const std::string& account_name, int16 status)
bool Database::ReserveName(uint32 account_id, const std::string& name)
{
const auto& l = CharacterDataRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}'",
Strings::Escape(name)
)
const std::string& where_filter = fmt::format(
"`name` = '{}'",
Strings::Escape(name)
);
if (!l.empty()) {
LogInfo("Account: [{}] tried to request name: [{}], but it is already taken", account_id, name);
if (RuleB(Bots, Enabled)) {
const auto& b = BotDataRepository::GetWhere(*this, where_filter);
if (!b.empty()) {
LogInfo("Account [{}] requested name [{}] but name is already taken by a bot", account_id, name);
return false;
}
}
const auto& c = CharacterDataRepository::GetWhere(*this, where_filter);
if (!c.empty()) {
LogInfo("Account [{}] requested name [{}] but name is already taken by a character", account_id, name);
return false;
}
const auto& n = NpcTypesRepository::GetWhere(*this, where_filter);
if (!n.empty()) {
LogInfo("Account [{}] requested name [{}] but name is already taken by an NPC", account_id, name);
return false;
}
@@ -296,13 +324,15 @@ bool Database::ReserveName(uint32 account_id, const std::string& name)
return false;
}
const int guild_id = RuleI(Character, DefaultGuild);
const uint32 guild_id = RuleI(Character, DefaultGuild);
const uint8 guild_rank = EQ::Clamp(RuleI(Character, DefaultGuildRank), 0, 8);
if (guild_id != 0) {
if (e.id) {
auto g = GuildMembersRepository::NewEntity();
g.char_id = e.id;
g.guild_id = guild_id;
g.rank_ = guild_rank;
GuildMembersRepository::InsertOne(*this, g);
}
@@ -741,7 +771,7 @@ bool Database::SetVariable(const std::string& name, const std::string& value)
auto l = VariablesRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}'",
"`varname` = '{}'",
Strings::Escape(name)
)
);
@@ -1618,16 +1648,29 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
uint32 Database::GetGroupIDByCharID(uint32 character_id)
{
const auto& e = GroupIdRepository::FindOne(*this, character_id);
const auto& e = GroupIdRepository::GetWhere(
*this,
fmt::format(
"`character_id` = {}",
character_id
)
);
return e.character_id ? e.group_id : 0;
return e.size() == 1 ? e.front().group_id : 0;
}
uint32 Database::GetRaidIDByCharID(uint32 character_id)
{
const auto& e = RaidMembersRepository::FindOne(*this, character_id);
return e.charid ? e.raidid : 0;
const auto& e = RaidMembersRepository::GetWhere(
*this,
fmt::format(
"`charid` = {}",
character_id
)
);
return e.size() == 1 ? e.front().raidid : 0;
}
int64 Database::CountInvSnapshots()
@@ -1817,7 +1860,7 @@ bool Database::CopyCharacter(
const int64 new_character_id = (CharacterDataRepository::GetMaxId(*this) + 1);
std::vector<std::string> tables_to_zero_id = { "keyring", "data_buckets" };
std::vector<std::string> tables_to_zero_id = { "keyring", "data_buckets", "character_instance_safereturns" };
TransactionBegin();
@@ -2089,3 +2132,18 @@ void Database::PurgeCharacterParcels()
RuleI(Parcel, ParcelPruneDelay)
);
}
void Database::ClearGuildOnlineStatus()
{
GuildMembersRepository::ClearOnlineStatus(*this);
}
void Database::ClearTraderDetails()
{
TraderRepository::Truncate(*this);
}
void Database::ClearBuyerDetails()
{
BuyerRepository::DeleteBuyer(*this, 0);
}
+4 -1
View File
@@ -170,7 +170,7 @@ public:
bool SetAccountStatus(const std::string& account_name, int16 status);
bool SetLocalPassword(uint32 account_id, const std::string& password);
bool UpdateLiveChar(const std::string& name, uint32 account_id);
int16 CheckStatus(uint32 account_id);
int16 GetAccountStatus(uint32 account_id);
void SetAccountCRCField(uint32 account_id, const std::string& field_name, uint64 checksum);
uint32 CheckLogin(const std::string& name, const std::string& password, const std::string& loginserver, int16* status = 0);
uint32 CreateAccount(
@@ -243,6 +243,9 @@ public:
void SetRaidGroupLeaderInfo(uint32 group_id, uint32 raid_id);
void PurgeAllDeletedDataBuckets();
void ClearGuildOnlineStatus();
void ClearTraderDetails();
void ClearBuyerDetails();
/* Database Variables */
+278 -1
View File
@@ -4947,7 +4947,7 @@ UPDATE `aa_ability` SET `auto_grant_enabled` = 1 WHERE `grant_only` = 0 AND `cha
.version = 9237,
.description = "2023_10_15_import_13th_floor.sql",
.check = "SHOW COLUMNS FROM `items` LIKE 'bardeffect';",
.condition = "contains",
.condition = "missing",
.match = "mediumint",
.sql = R"(
ALTER TABLE `items`
@@ -5567,6 +5567,283 @@ ADD COLUMN `is_parcel_merchant` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `
.sql = R"(
ALTER TABLE `character_data`
ADD COLUMN `extra_haste` int(11) NOT NULL DEFAULT 0 AFTER `wis`;
)"
},
ManifestEntry{
.version = 9276,
.description = "2024_05_12_fix_guild_bank_dup_issue.sql",
.check = "SHOW COLUMNS FROM `guild_bank` WHERE FIELD = 'qty' AND Type LIKE '%unsigned';",
.condition = "not_empty",
.match = "",
.sql = R"(
ALTER TABLE `guild_bank`
CHANGE COLUMN `qty` `qty` INT(10) NOT NULL DEFAULT '0' AFTER `itemid`;
)"
},
ManifestEntry{
.version = 9277,
.description = "2024_05_09_parcel_enable_containers.sql",
.check = "SHOW TABLES LIKE 'character_parcels_containers'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE `character_parcels_containers` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`parcels_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`slot_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`item_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`aug_slot_1` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`aug_slot_2` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`aug_slot_3` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`aug_slot_4` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`aug_slot_5` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`aug_slot_6` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`quantity` INT(10) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
INDEX `fk_character_parcels_id` (`parcels_id`) USING BTREE,
CONSTRAINT `fk_character_parcels_id` FOREIGN KEY (`parcels_id`) REFERENCES `character_parcels` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;
)"
},
ManifestEntry{
.version = 9278,
.description = "2024_05_06_npc_greed.sql",
.check = "SHOW COLUMNS FROM `npc_types` LIKE 'greed'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `npc_types`
ADD COLUMN `greed` tinyint(8) UNSIGNED NOT NULL DEFAULT 0 AFTER `merchant_id`;
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9279,
.description = "2024_05_13_content_flagging_npc_spells_entries.sql",
.check = "SHOW COLUMNS FROM `npc_spells_entries` LIKE 'content_flags'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `npc_spells_entries` ADD `min_expansion` tinyint(4) NOT NULL DEFAULT -1;
ALTER TABLE `npc_spells_entries` ADD `max_expansion` tinyint(4) NOT NULL DEFAULT -1;
ALTER TABLE `npc_spells_entries` ADD `content_flags` varchar(100) NULL;
ALTER TABLE `npc_spells_entries` ADD `content_flags_disabled` varchar(100) NULL;
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9280,
.description = "2024_05_11_update_trader_support.sql",
.check = "SHOW COLUMNS FROM `trader` LIKE 'aug_slot_1'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `trader`
ADD COLUMN `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
CHANGE COLUMN `char_id` `char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`,
CHANGE COLUMN `item_id` `item_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_id`,
ADD COLUMN `aug_slot_1` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `item_id`,
ADD COLUMN `aug_slot_2` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_1`,
ADD COLUMN `aug_slot_3` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_2`,
ADD COLUMN `aug_slot_4` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_3`,
ADD COLUMN `aug_slot_5` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_4`,
ADD COLUMN `aug_slot_6` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_5`,
CHANGE COLUMN `serialnumber` `item_sn` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `aug_slot_6`,
CHANGE COLUMN `charges` `item_charges` INT(11) NOT NULL DEFAULT '0' AFTER `item_sn`,
ADD COLUMN `char_entity_id` INT(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `slot_id`,
ADD COLUMN `char_zone_id` INT(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `char_entity_id`,
ADD COLUMN `active_transaction` TINYINT(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `char_zone_id`,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`id`),
ADD INDEX `charid_slotid` (`char_id`, `slot_id`);
)"
},
ManifestEntry{
.version = 9281,
.description = "2024_06_24_update_buyer_support.sql",
.check = "SHOW COLUMNS FROM `buyer` LIKE 'id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `buyer`
ADD COLUMN `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
CHANGE COLUMN `charid` `char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`,
ADD COLUMN `char_entity_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_id`,
ADD COLUMN `char_name` VARCHAR(64) NULL DEFAULT NULL AFTER `char_entity_id`,
ADD COLUMN `char_zone_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_name`,
ADD COLUMN `char_zone_instance_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_zone_id`,
ADD COLUMN `transaction_date` DATETIME NULL DEFAULT NULL AFTER `char_zone_instance_id`,
ADD COLUMN `welcome_message` VARCHAR(256) NULL DEFAULT NULL AFTER `transaction_date`,
DROP COLUMN `buyslot`,
DROP COLUMN `itemid`,
DROP COLUMN `itemname`,
DROP COLUMN `quantity`,
DROP COLUMN `price`,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`id`) USING BTREE,
ADD INDEX `charid` (`char_id`);
CREATE TABLE `buyer_buy_lines` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`buyer_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
`char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`buy_slot_id` INT(11) NOT NULL DEFAULT '0',
`item_id` INT(11) NOT NULL DEFAULT '0',
`item_qty` INT(11) NOT NULL DEFAULT '0',
`item_price` INT(11) NOT NULL DEFAULT '0',
`item_icon` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`item_name` VARCHAR(64) NOT NULL DEFAULT '' COLLATE 'latin1_swedish_ci',
PRIMARY KEY (`id`) USING BTREE,
INDEX `buyerid_charid_buyslotid` (`buyer_id`, `char_id`, `buy_slot_id`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
CREATE TABLE `buyer_trade_items` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`buyer_buy_lines_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
`item_id` INT(11) NOT NULL DEFAULT '0',
`item_qty` INT(11) NOT NULL DEFAULT '0',
`item_icon` INT(11) NOT NULL DEFAULT '0',
`item_name` VARCHAR(64) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
PRIMARY KEY (`id`) USING BTREE,
INDEX `buyerbuylinesid` (`buyer_buy_lines_id`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
)"
},
ManifestEntry{
.version = 9282,
.description = "2024_08_02_spell_buckets_comparison.sql",
.check = "SHOW COLUMNS FROM `spell_buckets` LIKE 'bucket_comparison'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `spell_buckets`
CHANGE COLUMN `spellid` `spell_id` int UNSIGNED NOT NULL FIRST,
CHANGE COLUMN `key` `bucket_name` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '' AFTER `spell_id`,
CHANGE COLUMN `value` `bucket_value` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '' AFTER `bucket_name`,
ADD COLUMN `bucket_comparison` tinyint UNSIGNED NOT NULL DEFAULT 0 AFTER `bucket_value`,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`spell_id`) USING BTREE;
)"
},
ManifestEntry{
.version = 9283,
.description = "2024_08_05_fix_client_hotbar",
.check = "SHOW COLUMNS FROM `inventory` LIKE 'guid'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `inventory`
ADD COLUMN `guid` BIGINT UNSIGNED NULL DEFAULT '0' AFTER `ornament_hero_model`;
ALTER TABLE `inventory_snapshots`
ADD COLUMN `guid` BIGINT UNSIGNED NULL DEFAULT '0' AFTER `ornament_hero_model`;
)"
},
ManifestEntry{
.version = 9284,
.description = "2024_10_08_character_exp_modifiers_default.sql",
.check = "SHOW CREATE TABLE `character_exp_modifiers`",
.condition = "contains",
.match = "`exp_modifier` float NOT NULL,",
.sql = R"(
ALTER TABLE `character_exp_modifiers`
MODIFY COLUMN `aa_modifier` float NOT NULL DEFAULT 1.0 AFTER `instance_version`,
MODIFY COLUMN `exp_modifier` float NOT NULL DEFAULT 1.0 AFTER `aa_modifier`;
)"
},
ManifestEntry{
.version = 9285,
.description = "2024_11_08_data_buckets_indexes.sql",
.check = "SHOW CREATE TABLE `data_buckets`",
.condition = "missing",
.match = "idx_character_expires",
.sql = R"(
CREATE INDEX idx_character_expires ON data_buckets (character_id, expires);
CREATE INDEX idx_npc_expires ON data_buckets (npc_id, expires);
CREATE INDEX idx_bot_expires ON data_buckets (bot_id, expires);
)"
},
ManifestEntry{
.version = 9286,
.description = "2024_10_24_sharedbank_guid_primary_key.sql",
.check = "SHOW COLUMN FROM `sharedbank` LIKE 'guid'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `sharedbank`
CHANGE COLUMN `acctid` `account_id` int(11) UNSIGNED NOT NULL DEFAULT 0 FIRST,
CHANGE COLUMN `slotid` `slot_id` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `account_id`,
CHANGE COLUMN `itemid` `item_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `slot_id`,
CHANGE COLUMN `augslot1` `augment_one` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `charges`,
CHANGE COLUMN `augslot2` `augment_two` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_one`,
CHANGE COLUMN `augslot3` `augment_three` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_two`,
CHANGE COLUMN `augslot4` `augment_four` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_three`,
CHANGE COLUMN `augslot5` `augment_five` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_four`,
CHANGE COLUMN `augslot6` `augment_six` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_five`,
MODIFY COLUMN `charges` smallint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `item_id`,
ADD COLUMN `color` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `charges`,
ADD COLUMN `ornament_icon` int(11) UNSIGNED NOT NULL AFTER `custom_data`,
ADD COLUMN `ornament_idfile` int(11) UNSIGNED NOT NULL AFTER `ornament_icon`,
ADD COLUMN `ornament_hero_model` int(11) NOT NULL AFTER `ornament_idfile`,
ADD COLUMN `guid` bigint(20) UNSIGNED NOT NULL DEFAULT 0 AFTER `ornament_hero_model`,
ADD PRIMARY KEY (`account_id`, `slot_id`);
)"
},
ManifestEntry{
.version = 9287,
.description = "2024_10_24_inventory_changes.sql",
.check = "SHOW COLUMN FROM `inventory` LIKE 'charid'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `inventory`
CHANGE COLUMN `charid` `character_id` int(11) UNSIGNED NOT NULL DEFAULT 0 FIRST,
CHANGE COLUMN `slotid` `slot_id` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `character_id`,
CHANGE COLUMN `itemid` `item_id` int(11) UNSIGNED NULL DEFAULT 0 AFTER `slot_id`,
CHANGE COLUMN `augslot1` `augment_one` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `color`,
CHANGE COLUMN `augslot2` `augment_two` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_one`,
CHANGE COLUMN `augslot3` `augment_three` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_two`,
CHANGE COLUMN `augslot4` `augment_four` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_three`,
CHANGE COLUMN `augslot5` `augment_five` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_four`,
CHANGE COLUMN `augslot6` `augment_six` mediumint(7) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_five`,
CHANGE COLUMN `ornamenticon` `ornament_icon` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `custom_data`,
CHANGE COLUMN `ornamentidfile` `ornament_idfile` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `ornament_icon`,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`character_id`, `slot_id`) USING BTREE;
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 251) + 4010) WHERE `slot_id` BETWEEN 251 AND 260; -- Bag 1
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 261) + 4210) WHERE `slot_id` BETWEEN 261 AND 270; -- Bag 2
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 271) + 4410) WHERE `slot_id` BETWEEN 271 AND 280; -- Bag 3
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 281) + 4610) WHERE `slot_id` BETWEEN 281 AND 290; -- Bag 4
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 291) + 4810) WHERE `slot_id` BETWEEN 291 AND 300; -- Bag 5
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 301) + 5010) WHERE `slot_id` BETWEEN 301 AND 310; -- Bag 6
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 311) + 5210) WHERE `slot_id` BETWEEN 311 AND 320; -- Bag 7
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 321) + 5410) WHERE `slot_id` BETWEEN 321 AND 330; -- Bag 8
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 331) + 5610) WHERE `slot_id` BETWEEN 331 AND 340; -- Bag 9
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 341) + 5810) WHERE `slot_id` BETWEEN 341 AND 350; -- Bag 10
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 351) + 6010) WHERE `slot_id` BETWEEN 351 AND 360; -- Cursor Bag
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 2031) + 6210) WHERE `slot_id` BETWEEN 2031 AND 2270; -- Bank Bags
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 2531) + 11010) WHERE `slot_id` BETWEEN 2531 AND 2550; -- Shared Bank Bags
)"
},
ManifestEntry{
.version = 9288,
.description = "2024_10_24_merchantlist_temp_uncap.sql",
.check = "SHOW CREATE TABLE `merchantlist_temp`",
.condition = "contains",
.match = "`slot` tinyint(3)",
.sql = R"(
ALTER TABLE `merchantlist_temp`
MODIFY COLUMN `slot` int UNSIGNED NOT NULL DEFAULT 0 AFTER `npcid`;
)"
}
// -- template; copy/paste this when you need to create a new entry
@@ -150,6 +150,17 @@ ADD COLUMN `augment_six` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_five
.sql = R"(
ALTER TABLE `bot_data`
ADD COLUMN `extra_haste` mediumint(8) NOT NULL DEFAULT 0 AFTER `wis`;
)"
},
ManifestEntry{
.version = 9045,
.description = "2024_08_05_bot_spells_entries_unsigned_spell_id.sql",
.check = "SHOW COLUMNS FROM `bot_spells_entries` LIKE 'spell_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `bot_spells_entries`
CHANGE COLUMN `spellid` `spell_id` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `npc_spells_id`;
)"
}
// -- template; copy/paste this when you need to create a new entry
+7 -1
View File
@@ -36,7 +36,6 @@ namespace DatabaseSchema {
{
return {
{"adventure_stats", "player_id"},
{"buyer", "charid"},
{"char_recipe_list", "char_id"},
{"character_activities", "charid"},
{"character_alt_currency", "char_id"},
@@ -60,6 +59,7 @@ namespace DatabaseSchema {
{"character_material", "id"},
{"character_memmed_spells", "id"},
{"character_parcels", "char_id"},
{"character_parcels_containers", "id"},
{"character_pet_buffs", "char_id"},
{"character_pet_info", "char_id"},
{"character_pet_inventory", "char_id"},
@@ -106,6 +106,8 @@ namespace DatabaseSchema {
"adventure_details",
"adventure_stats",
"buyer",
"buyer_buy_lines",
"buyer_trade_items",
"char_recipe_list",
"character_activities",
"character_alt_currency",
@@ -130,6 +132,7 @@ namespace DatabaseSchema {
"character_material",
"character_memmed_spells",
"character_parcels",
"character_parcels_containers",
"character_pet_buffs",
"character_pet_info",
"character_pet_inventory",
@@ -323,6 +326,9 @@ namespace DatabaseSchema {
"banned_ips",
"bug_reports",
"bugs",
"buyer",
"buyer_buy_lines",
"buyer_trade_items",
"completed_shared_task_activity_state",
"completed_shared_task_members",
"completed_shared_tasks",
+6
View File
@@ -7,6 +7,7 @@
#include "timer.h"
#include "dbcore.h"
#include "mysql_stmt.h"
#include <fstream>
#include <iostream>
@@ -436,3 +437,8 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
return r;
}
mysql::PreparedStmt DBcore::Prepare(std::string query)
{
return mysql::PreparedStmt(*mysql, std::move(query), m_mutex);
}
+7
View File
@@ -17,6 +17,8 @@
#define CR_SERVER_GONE_ERROR 2006
#define CR_SERVER_LOST 2013
namespace mysql { class PreparedStmt; }
class DBcore {
public:
enum eStatus {
@@ -48,6 +50,11 @@ public:
}
void SetMutex(Mutex *mutex);
// only safe on connections shared with other threads if results buffered
// unsafe to use off main thread due to internal server logging
// throws std::runtime_error on failure
mysql::PreparedStmt Prepare(std::string query);
protected:
bool Open(
const char *iHost,
+6 -70
View File
@@ -19,81 +19,17 @@
#include "deity.h"
EQ::deity::DeityTypeBit EQ::deity::GetDeityBitmask(DeityType deity_type)
uint32 Deity::GetBitmask(uint32 deity_id)
{
switch (deity_type) {
case DeityBertoxxulous:
return bit_DeityBertoxxulous;
case DeityBrellSirilis:
return bit_DeityBrellSirilis;
case DeityCazicThule:
return bit_DeityCazicThule;
case DeityErollisiMarr:
return bit_DeityErollisiMarr;
case DeityBristlebane:
return bit_DeityBristlebane;
case DeityInnoruuk:
return bit_DeityInnoruuk;
case DeityKarana:
return bit_DeityKarana;
case DeityMithanielMarr:
return bit_DeityMithanielMarr;
case DeityPrexus:
return bit_DeityPrexus;
case DeityQuellious:
return bit_DeityQuellious;
case DeityRallosZek:
return bit_DeityRallosZek;
case DeityRodcetNife:
return bit_DeityRodcetNife;
case DeitySolusekRo:
return bit_DeitySolusekRo;
case DeityTheTribunal:
return bit_DeityTheTribunal;
case DeityTunare:
return bit_DeityTunare;
case DeityVeeshan:
return bit_DeityVeeshan;
case DeityAgnostic_LB:
case DeityAgnostic:
return bit_DeityAgnostic;
default:
return bit_DeityAll;
}
return IsValid(deity_id) ? deity_bitmasks[deity_id] : Deity::Bitmask::All;
}
const std::map<EQ::deity::DeityType, std::string>& EQ::deity::GetDeityMap()
std::string Deity::GetName(uint32 deity_id)
{
static const std::map<EQ::deity::DeityType, std::string> deity_map = {
{ DeityAgnostic, "Agnostic" },
{ DeityAgnostic_LB, "Agnostic" },
{ DeityBertoxxulous, "Bertoxxulous" },
{ DeityBrellSirilis, "Brell Serilis" },
{ DeityBristlebane, "Bristlebane" },
{ DeityCazicThule, "Cazic-Thule" },
{ DeityErollisiMarr, "Erollisi Marr" },
{ DeityInnoruuk, "Innoruuk" },
{ DeityKarana, "Karana" },
{ DeityMithanielMarr, "Mithaniel Marr" },
{ DeityPrexus, "Prexus" },
{ DeityQuellious, "Quellious" },
{ DeityRallosZek, "Rallos Zek" },
{ DeityRodcetNife, "Rodcet Nife" },
{ DeitySolusekRo, "Solusek Ro" },
{ DeityTheTribunal, "The Tribunal" },
{ DeityTunare, "Tunare" },
{ DeityVeeshan, "Veeshan" }
};
return deity_map;
return IsValid(deity_id) ? deity_names[deity_id] : "UNKNOWN DEITY";
}
std::string EQ::deity::GetDeityName(DeityType deity_type)
bool Deity::IsValid(uint32 deity_id)
{
if (EQ::deity::GetDeityMap().find(deity_type) != EQ::deity::GetDeityMap().end()) {
return EQ::deity::GetDeityMap().find(deity_type)->second;
}
return std::string();
return deity_names.find(deity_id) != deity_names.end();
}
+85 -52
View File
@@ -23,62 +23,95 @@
#include "types.h"
#include <map>
#include <string>
#include <limits>
namespace Deity {
constexpr uint32 Unknown = 0;
constexpr uint32 Agnostic1 = 140;
constexpr uint32 Bertoxxulous = 201;
constexpr uint32 BrellSirilis = 202;
constexpr uint32 CazicThule = 203;
constexpr uint32 ErollisiMarr = 204;
constexpr uint32 Bristlebane = 205;
constexpr uint32 Innoruuk = 206;
constexpr uint32 Karana = 207;
constexpr uint32 MithanielMarr = 208;
constexpr uint32 Prexus = 209;
constexpr uint32 Quellious = 210;
constexpr uint32 RallosZek = 211;
constexpr uint32 RodcetNife = 212;
constexpr uint32 SolusekRo = 213;
constexpr uint32 TheTribunal = 214;
constexpr uint32 Tunare = 215;
constexpr uint32 Veeshan = 216;
constexpr uint32 Agnostic2 = 396;
namespace EQ
{
namespace deity {
enum DeityType {
DeityUnknown = 0,
DeityAgnostic_LB = 140,
DeityBertoxxulous = 201,
DeityBrellSirilis,
DeityCazicThule,
DeityErollisiMarr,
DeityBristlebane,
DeityInnoruuk,
DeityKarana,
DeityMithanielMarr,
DeityPrexus,
DeityQuellious,
DeityRallosZek,
DeityRodcetNife,
DeitySolusekRo,
DeityTheTribunal,
DeityTunare,
DeityVeeshan,
DeityAgnostic = 396
};
namespace Bitmask {
constexpr uint32 Agnostic = 1;
constexpr uint32 Bertoxxulous = 2;
constexpr uint32 BrellSirilis = 4;
constexpr uint32 CazicThule = 8;
constexpr uint32 ErollisiMarr = 16;
constexpr uint32 Bristlebane = 32;
constexpr uint32 Innoruuk = 64;
constexpr uint32 Karana = 128;
constexpr uint32 MithanielMarr = 256;
constexpr uint32 Prexus = 512;
constexpr uint32 Quellious = 1024;
constexpr uint32 RallosZek = 2048;
constexpr uint32 RodcetNife = 4096;
constexpr uint32 SolusekRo = 8192;
constexpr uint32 TheTribunal = 16384;
constexpr uint32 Tunare = 32768;
constexpr uint32 Veeshan = 65536;
constexpr uint32 All = std::numeric_limits<uint32>::max();
}
enum DeityTypeBit : uint32 {
bit_DeityAgnostic = 0x00000001,
bit_DeityBertoxxulous = 0x00000002,
bit_DeityBrellSirilis = 0x00000004,
bit_DeityCazicThule = 0x00000008,
bit_DeityErollisiMarr = 0x00000010,
bit_DeityBristlebane = 0x00000020,
bit_DeityInnoruuk = 0x00000040,
bit_DeityKarana = 0x00000080,
bit_DeityMithanielMarr = 0x00000100,
bit_DeityPrexus = 0x00000200,
bit_DeityQuellious = 0x00000400,
bit_DeityRallosZek = 0x00000800,
bit_DeityRodcetNife = 0x00001000,
bit_DeitySolusekRo = 0x00002000,
bit_DeityTheTribunal = 0x00004000,
bit_DeityTunare = 0x00008000,
bit_DeityVeeshan = 0x00010000,
bit_DeityAll = UINT32_MAX
};
uint32 GetBitmask(uint32 deity_id);
std::string GetName(uint32 deity_id);
bool IsValid(uint32 deity_id);
}
constexpr int format_as(DeityType type) { return static_cast<int>(type); }
static std::map<uint32, std::string> deity_names = {
{ Deity::Agnostic1, "Agnostic" },
{ Deity::Agnostic2, "Agnostic" },
{ Deity::Bertoxxulous, "Bertoxxulous" },
{ Deity::BrellSirilis, "Brell Serilis" },
{ Deity::Bristlebane, "Bristlebane" },
{ Deity::CazicThule, "Cazic-Thule" },
{ Deity::ErollisiMarr, "Erollisi Marr" },
{ Deity::Innoruuk, "Innoruuk" },
{ Deity::Karana, "Karana" },
{ Deity::MithanielMarr, "Mithaniel Marr" },
{ Deity::Prexus, "Prexus" },
{ Deity::Quellious, "Quellious" },
{ Deity::RallosZek, "Rallos Zek" },
{ Deity::RodcetNife, "Rodcet Nife" },
{ Deity::SolusekRo, "Solusek Ro" },
{ Deity::TheTribunal, "The Tribunal" },
{ Deity::Tunare, "Tunare" },
{ Deity::Veeshan, "Veeshan" }
};
extern DeityTypeBit GetDeityBitmask(DeityType deity_type);
extern std::string GetDeityName(DeityType deity_type);
extern const std::map<DeityType, std::string>& GetDeityMap();
} /*deity*/
} /*EQEmu*/
static std::map<uint32, uint32> deity_bitmasks = {
{ Deity::Agnostic1, Deity::Bitmask::Agnostic },
{ Deity::Agnostic2, Deity::Bitmask::Agnostic },
{ Deity::Bertoxxulous, Deity::Bitmask::Bertoxxulous },
{ Deity::BrellSirilis, Deity::Bitmask::BrellSirilis },
{ Deity::CazicThule, Deity::Bitmask::CazicThule },
{ Deity::ErollisiMarr, Deity::Bitmask::ErollisiMarr },
{ Deity::Bristlebane, Deity::Bitmask::Bristlebane },
{ Deity::Innoruuk, Deity::Bitmask::Innoruuk },
{ Deity::Karana, Deity::Bitmask::Karana },
{ Deity::MithanielMarr, Deity::Bitmask::MithanielMarr },
{ Deity::Prexus, Deity::Bitmask::Prexus },
{ Deity::Quellious, Deity::Bitmask::Quellious },
{ Deity::RallosZek, Deity::Bitmask::RallosZek },
{ Deity::RodcetNife, Deity::Bitmask::RodcetNife },
{ Deity::SolusekRo, Deity::Bitmask::SolusekRo },
{ Deity::TheTribunal, Deity::Bitmask::TheTribunal },
{ Deity::Tunare, Deity::Bitmask::Tunare },
{ Deity::Veeshan, Deity::Bitmask::Veeshan }
};
#endif /* COMMON_DEITY_H */
+61 -338
View File
@@ -59,103 +59,40 @@ int16 EQ::invtype::GetInvTypeSize(int16 inv_type) {
return local_array[inv_type];
}
const char* EQ::bug::CategoryIDToCategoryName(CategoryID category_id) {
switch (category_id) {
case catVideo:
return "Video";
case catAudio:
return "Audio";
case catPathing:
return "Pathing";
case catQuest:
return "Quest";
case catTradeskills:
return "Tradeskills";
case catSpellStacking:
return "Spell stacking";
case catDoorsPortals:
return "Doors/Portals";
case catItems:
return "Items";
case catNPC:
return "NPC";
case catDialogs:
return "Dialogs";
case catLoNTCG:
return "LoN - TCG";
case catMercenaries:
return "Mercenaries";
case catOther:
default:
return "Other";
}
}
EQ::bug::CategoryID EQ::bug::CategoryNameToCategoryID(const char* category_name) {
if (!category_name)
return catOther;
if (!strcmp(category_name, "Video"))
return catVideo;
if (!strcmp(category_name, "Audio"))
return catAudio;
if (!strcmp(category_name, "Pathing"))
return catPathing;
if (!strcmp(category_name, "Quest"))
return catQuest;
if (!strcmp(category_name, "Tradeskills"))
return catTradeskills;
if (!strcmp(category_name, "Spell stacking"))
return catSpellStacking;
if (!strcmp(category_name, "Doors/Portals"))
return catDoorsPortals;
if (!strcmp(category_name, "Items"))
return catItems;
if (!strcmp(category_name, "NPC"))
return catNPC;
if (!strcmp(category_name, "Dialogs"))
return catDialogs;
if (!strcmp(category_name, "LoN - TCG"))
return catLoNTCG;
if (!strcmp(category_name, "Mercenaries"))
return catMercenaries;
return catOther;
}
const char *EQ::constants::GetStanceName(StanceType stance_type) {
switch (stance_type) {
case stanceUnknown:
return "Unknown";
case stancePassive:
return "Passive";
case stanceBalanced:
return "Balanced";
case stanceEfficient:
return "Efficient";
case stanceReactive:
return "Reactive";
case stanceAggressive:
return "Aggressive";
case stanceAssist:
return "Assist";
case stanceBurn:
return "Burn";
case stanceEfficient2:
return "Efficient2";
case stanceBurnAE:
return "BurnAE";
default:
return "Invalid";
}
}
int EQ::constants::ConvertStanceTypeToIndex(StanceType stance_type) {
if (EQ::ValueWithin(stance_type, EQ::constants::stancePassive, EQ::constants::stanceBurnAE)) {
return (stance_type - EQ::constants::stancePassive);
uint32 Bug::GetID(const std::string& category_name)
{
for (const auto& e : bug_category_names) {
if (e.second == category_name) {
return e.first;
}
}
return 0;
return Bug::Category::Other;
}
std::string Bug::GetName(uint32 category_id)
{
return IsValid(category_id) ? bug_category_names[category_id] : "UNKNOWN BUG CATEGORY";
}
bool Bug::IsValid(uint32 category_id)
{
return bug_category_names.find(category_id) != bug_category_names.end();
}
std::string Stance::GetName(uint8 stance_id)
{
return IsValid(stance_id) ? stance_names[stance_id] : "UNKNOWN STANCE";
}
bool Stance::IsValid(uint8 stance_id)
{
return stance_names.find(stance_id) != stance_names.end();
}
uint8 Stance::GetIndex(uint8 stance_id)
{
return IsValid(stance_id) ? (stance_id - Stance::Passive) : 0;
}
const std::map<uint8, std::string>& EQ::constants::GetLanguageMap()
@@ -249,102 +186,6 @@ std::string EQ::constants::GetFlyModeName(int8 flymode_id)
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
}
const std::map<bodyType, std::string>& EQ::constants::GetBodyTypeMap()
{
static const std::map<bodyType, std::string> bodytype_map = {
{ BT_Humanoid, "Humanoid" },
{ BT_Lycanthrope, "Lycanthrope" },
{ BT_Undead, "Undead" },
{ BT_Giant, "Giant" },
{ BT_Construct, "Construct" },
{ BT_Extraplanar, "Extraplanar" },
{ BT_Magical, "Magical" },
{ BT_SummonedUndead, "Summoned Undead" },
{ BT_RaidGiant, "Raid Giant" },
{ BT_RaidColdain, "Raid Coldain" },
{ BT_NoTarget, "Untargetable" },
{ BT_Vampire, "Vampire" },
{ BT_Atenha_Ra, "Aten Ha Ra" },
{ BT_Greater_Akheva, "Greater Akheva" },
{ BT_Khati_Sha, "Khati Sha" },
{ BT_Seru, "Seru" },
{ BT_Grieg_Veneficus, "Grieg Veneficus" },
{ BT_Draz_Nurakk, "Draz Nurakk" },
{ BT_Zek, "Zek" },
{ BT_Luggald, "Luggald" },
{ BT_Animal, "Animal" },
{ BT_Insect, "Insect" },
{ BT_Monster, "Monster" },
{ BT_Summoned, "Summoned" },
{ BT_Plant, "Plant" },
{ BT_Dragon, "Dragon" },
{ BT_Summoned2, "Summoned 2" },
{ BT_Summoned3, "Summoned 3" },
{ BT_Dragon2, "Dragon 2" },
{ BT_VeliousDragon, "Velious Dragon" },
{ BT_Familiar, "Familiar" },
{ BT_Dragon3, "Dragon 3" },
{ BT_Boxes, "Boxes" },
{ BT_Muramite, "Muramite" },
{ BT_NoTarget2, "Untargetable 2" },
{ BT_SwarmPet, "Swarm Pet" },
{ BT_MonsterSummon, "Monster Summon" },
{ BT_InvisMan, "Invisible Man" },
{ BT_Special, "Special" },
};
return bodytype_map;
}
std::string EQ::constants::GetBodyTypeName(bodyType bodytype_id)
{
if (EQ::constants::GetBodyTypeMap().find(bodytype_id) != EQ::constants::GetBodyTypeMap().end()) {
return EQ::constants::GetBodyTypeMap().find(bodytype_id)->second;
}
return std::string();
}
const std::map<uint8, std::string>& EQ::constants::GetAccountStatusMap()
{
static const std::map<uint8, std::string> account_status_map = {
{ AccountStatus::Player, "Player" },
{ AccountStatus::Steward, "Steward" },
{ AccountStatus::ApprenticeGuide, "Apprentice Guide" },
{ AccountStatus::Guide, "Guide" },
{ AccountStatus::QuestTroupe, "Quest Troupe" },
{ AccountStatus::SeniorGuide, "Senior Guide" },
{ AccountStatus::GMTester, "GM Tester" },
{ AccountStatus::EQSupport, "EQ Support" },
{ AccountStatus::GMStaff, "GM Staff" },
{ AccountStatus::GMAdmin, "GM Admin" },
{ AccountStatus::GMLeadAdmin, "GM Lead Admin" },
{ AccountStatus::QuestMaster, "Quest Master" },
{ AccountStatus::GMAreas, "GM Areas" },
{ AccountStatus::GMCoder, "GM Coder" },
{ AccountStatus::GMMgmt, "GM Mgmt" },
{ AccountStatus::GMImpossible, "GM Impossible" },
{ AccountStatus::Max, "GM Max" }
};
return account_status_map;
}
std::string EQ::constants::GetAccountStatusName(uint8 account_status)
{
for (
auto status_level = EQ::constants::GetAccountStatusMap().rbegin();
status_level != EQ::constants::GetAccountStatusMap().rend();
++status_level
) {
if (account_status >= status_level->first) {
return status_level->second;
}
}
return std::string();
}
const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
{
static const std::map<uint8, std::string> consider_level_map = {
@@ -435,84 +276,6 @@ std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id)
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
}
const std::map<int, std::string>& EQ::constants::GetObjectTypeMap()
{
static const std::map<int, std::string> object_type_map = {
{ ObjectTypes::SmallBag, "Small Bag" },
{ ObjectTypes::LargeBag, "Large Bag" },
{ ObjectTypes::Quiver, "Quiver" },
{ ObjectTypes::BeltPouch, "Belt Pouch" },
{ ObjectTypes::WristPouch, "Wrist Pouch" },
{ ObjectTypes::Backpack, "Backpack" },
{ ObjectTypes::SmallChest, "Small Chest" },
{ ObjectTypes::LargeChest, "Large Chest" },
{ ObjectTypes::Bandolier, "Bandolier" },
{ ObjectTypes::Medicine, "Medicine" },
{ ObjectTypes::Tinkering, "Tinkering" },
{ ObjectTypes::Lexicon, "Lexicon" },
{ ObjectTypes::PoisonMaking, "Mortar and Pestle" },
{ ObjectTypes::Quest, "Quest" },
{ ObjectTypes::MixingBowl, "Mixing Bowl" },
{ ObjectTypes::Baking, "Baking" },
{ ObjectTypes::Tailoring, "Tailoring" },
{ ObjectTypes::Blacksmithing, "Blacksmithing" },
{ ObjectTypes::Fletching, "Fletching" },
{ ObjectTypes::Brewing, "Brewing" },
{ ObjectTypes::JewelryMaking, "Jewelry Making" },
{ ObjectTypes::Pottery, "Pottery" },
{ ObjectTypes::Kiln, "Kiln" },
{ ObjectTypes::KeyMaker, "Key Maker" },
{ ObjectTypes::ResearchWIZ, "Lexicon" },
{ ObjectTypes::ResearchMAG, "Lexicon" },
{ ObjectTypes::ResearchNEC, "Lexicon" },
{ ObjectTypes::ResearchENC, "Lexicon" },
{ ObjectTypes::Unknown, "Unknown" },
{ ObjectTypes::ResearchPractice, "Lexicon" },
{ ObjectTypes::Alchemy, "Alchemy" },
{ ObjectTypes::HighElfForge, "High Elf Forge" },
{ ObjectTypes::DarkElfForge, "Dark Elf Forge" },
{ ObjectTypes::OgreForge, "Ogre Forge" },
{ ObjectTypes::DwarfForge, "Dwarf Forge" },
{ ObjectTypes::GnomeForge, "Gnome Forge" },
{ ObjectTypes::BarbarianForge, "Barbarian Forge" },
{ ObjectTypes::IksarForge, "Iksar Forge" },
{ ObjectTypes::HumanForgeOne, "Human Forge" },
{ ObjectTypes::HumanForgeTwo, "Human Forge" },
{ ObjectTypes::HalflingTailoringOne, "Halfling Tailoring" },
{ ObjectTypes::HalflingTailoringTwo, "Halfling Tailoring" },
{ ObjectTypes::EruditeTailoring, "Erudite Tailoring" },
{ ObjectTypes::WoodElfTailoring, "Wood Elf Tailoring" },
{ ObjectTypes::WoodElfFletching, "Wood Elf Fletching" },
{ ObjectTypes::IksarPottery, "Iksar Pottery" },
{ ObjectTypes::Fishing, "Fishing" },
{ ObjectTypes::TrollForge, "Troll Forge" },
{ ObjectTypes::WoodElfForge, "Wood Elf Forge" },
{ ObjectTypes::HalflingForge, "Halfling Forge" },
{ ObjectTypes::EruditeForge, "Erudite Forge" },
{ ObjectTypes::Merchant, "Merchant" },
{ ObjectTypes::FroglokForge, "Froglok Forge" },
{ ObjectTypes::Augmenter, "Augmenter" },
{ ObjectTypes::Churn, "Churn" },
{ ObjectTypes::TransformationMold, "Transformation Mold" },
{ ObjectTypes::DetransformationMold, "Detransformation Mold" },
{ ObjectTypes::Unattuner, "Unattuner" },
{ ObjectTypes::TradeskillBag, "Tradeskill Bag" },
{ ObjectTypes::CollectibleBag, "Collectible Bag" },
{ ObjectTypes::NoDeposit, "No Deposit" }
};
return object_type_map;
}
std::string EQ::constants::GetObjectTypeName(int object_type)
{
if (!EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) {
return std::string();
}
return EQ::constants::GetObjectTypeMap().find(object_type)->second;
}
const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
{
static const std::map<uint8, std::string> weather_type_map = {
@@ -640,79 +403,14 @@ std::string EQ::constants::GetAppearanceTypeName(uint32 appearance_type)
return std::string();
}
const std::map<uint32, std::string>& EQ::constants::GetSpecialAbilityMap()
std::string SpecialAbility::GetName(int ability_id)
{
static const std::map<uint32, std::string> special_ability_map = {
{ SPECATK_SUMMON, "Summon" },
{ SPECATK_ENRAGE, "Enrage" },
{ SPECATK_RAMPAGE, "Rampage" },
{ SPECATK_AREA_RAMPAGE, "Area Rampage" },
{ SPECATK_FLURRY, "Flurry" },
{ SPECATK_TRIPLE, "Triple Attack" },
{ SPECATK_QUAD, "Quadruple Attack" },
{ SPECATK_INNATE_DW, "Dual Wield" },
{ SPECATK_BANE, "Bane Attack" },
{ SPECATK_MAGICAL, "Magical Attack" },
{ SPECATK_RANGED_ATK, "Ranged Attack" },
{ UNSLOWABLE, "Immune to Slow" },
{ UNMEZABLE, "Immune to Mesmerize" },
{ UNCHARMABLE, "Immune to Charm" },
{ UNSTUNABLE, "Immune to Stun" },
{ UNSNAREABLE, "Immune to Snare" },
{ UNFEARABLE, "Immune to Fear" },
{ UNDISPELLABLE, "Immune to Dispell" },
{ IMMUNE_MELEE, "Immune to Melee" },
{ IMMUNE_MAGIC, "Immune to Magic" },
{ IMMUNE_FLEEING, "Immune to Fleeing" },
{ IMMUNE_MELEE_EXCEPT_BANE, "Immune to Melee except Bane" },
{ IMMUNE_MELEE_NONMAGICAL, "Immune to Non-Magical Melee" },
{ IMMUNE_AGGRO, "Immune to Aggro" },
{ IMMUNE_AGGRO_ON, "Immune to Being Aggro" },
{ IMMUNE_CASTING_FROM_RANGE, "Immune to Ranged Spells" },
{ IMMUNE_FEIGN_DEATH, "Immune to Feign Death" },
{ IMMUNE_TAUNT, "Immune to Taunt" },
{ NPC_TUNNELVISION, "Tunnel Vision" },
{ NPC_NO_BUFFHEAL_FRIENDS, "Does Not Heal of Buff Allies" },
{ IMMUNE_PACIFY, "Immune to Pacify" },
{ LEASH, "Leashed" },
{ TETHER, "Tethered" },
{ DESTRUCTIBLE_OBJECT, "Destructible Object" },
{ NO_HARM_FROM_CLIENT, "Immune to Harm from Client" },
{ ALWAYS_FLEE, "Always Flees" },
{ FLEE_PERCENT, "Flee Percentage" },
{ ALLOW_BENEFICIAL, "Allows Beneficial Spells" },
{ DISABLE_MELEE, "Melee is Disabled" },
{ NPC_CHASE_DISTANCE, "Chase Distance" },
{ ALLOW_TO_TANK, "Allowed to Tank" },
{ IGNORE_ROOT_AGGRO_RULES, "Ignores Root Aggro" },
{ CASTING_RESIST_DIFF, "Casting Resist Difficulty" },
{ COUNTER_AVOID_DAMAGE, "Counter Damage Avoidance" },
{ PROX_AGGRO, "Proximity Aggro" },
{ IMMUNE_RANGED_ATTACKS, "Immune to Ranged Attacks" },
{ IMMUNE_DAMAGE_CLIENT, "Immune to Client Damage" },
{ IMMUNE_DAMAGE_NPC, "Immune to NPC Damage" },
{ IMMUNE_AGGRO_CLIENT, "Immune to Client Aggro" },
{ IMMUNE_AGGRO_NPC, "Immune to NPC Aggro" },
{ MODIFY_AVOID_DAMAGE, "Modify Damage Avoidance" },
{ IMMUNE_FADING_MEMORIES, "Immune to Memory Fades" },
{ IMMUNE_OPEN, "Immune to Open" },
{ IMMUNE_ASSASSINATE, "Immune to Assassinate" },
{ IMMUNE_HEADSHOT, "Immune to Headshot" },
{ IMMUNE_AGGRO_BOT, "Immune to Bot Aggro" },
{ IMMUNE_DAMAGE_BOT, "Immune to Bot Damage" },
};
return special_ability_map;
return IsValid(ability_id) ? special_ability_names[ability_id] : "UNKNOWN SPECIAL ABILITY";
}
std::string EQ::constants::GetSpecialAbilityName(uint32 ability_id)
bool SpecialAbility::IsValid(int ability_id)
{
const auto& a = EQ::constants::GetSpecialAbilityMap().find(ability_id);
if (a != EQ::constants::GetSpecialAbilityMap().end()) {
return a->second;
}
return std::string();
return special_ability_names.find(ability_id) != special_ability_names.end();
}
const std::map<uint32, std::string>& EQ::constants::GetConsiderColorMap()
@@ -736,3 +434,28 @@ std::string EQ::constants::GetConsiderColorName(uint32 consider_color)
const auto& c = EQ::constants::GetConsiderColorMap().find(consider_color);
return c != EQ::constants::GetConsiderColorMap().end() ? c->second : std::string();
}
std::string AccountStatus::GetName(uint8 account_status)
{
for (
auto e = account_status_names.rbegin();
e != account_status_names.rend();
++e
) {
if (account_status >= e->first) {
return e->second;
}
}
return "UNKNOWN ACCOUNT STATUS";
}
std::string ComparisonType::GetName(uint8 type)
{
return IsValid(type) ? comparison_types[type] : "UNKNOWN COMPARISON TYPE";
}
bool ComparisonType::IsValid(uint8 type)
{
return comparison_types.find(type) != comparison_types.end();
}
+318 -254
View File
@@ -26,6 +26,76 @@
#include <string.h>
namespace AccountStatus {
constexpr uint8 Player = 0;
constexpr uint8 Steward = 10;
constexpr uint8 ApprenticeGuide = 20;
constexpr uint8 Guide = 50;
constexpr uint8 QuestTroupe = 80;
constexpr uint8 SeniorGuide = 81;
constexpr uint8 GMTester = 85;
constexpr uint8 EQSupport = 90;
constexpr uint8 GMStaff = 95;
constexpr uint8 GMAdmin = 100;
constexpr uint8 GMLeadAdmin = 150;
constexpr uint8 QuestMaster = 160;
constexpr uint8 GMAreas = 170;
constexpr uint8 GMCoder = 180;
constexpr uint8 GMMgmt = 200;
constexpr uint8 GMImpossible = 250;
constexpr uint8 Max = 255;
std::string GetName(uint8 account_status);
}
static std::map<uint8, std::string> account_status_names = {
{ AccountStatus::Player, "Player" },
{ AccountStatus::Steward, "Steward" },
{ AccountStatus::ApprenticeGuide, "Apprentice Guide" },
{ AccountStatus::Guide, "Guide" },
{ AccountStatus::QuestTroupe, "Quest Troupe" },
{ AccountStatus::SeniorGuide, "Senior Guide" },
{ AccountStatus::GMTester, "GM Tester" },
{ AccountStatus::EQSupport, "EQ Support" },
{ AccountStatus::GMStaff, "GM Staff" },
{ AccountStatus::GMAdmin, "GM Admin" },
{ AccountStatus::GMLeadAdmin, "GM Lead Admin" },
{ AccountStatus::QuestMaster, "Quest Master" },
{ AccountStatus::GMAreas, "GM Areas" },
{ AccountStatus::GMCoder, "GM Coder" },
{ AccountStatus::GMMgmt, "GM Mgmt" },
{ AccountStatus::GMImpossible, "GM Impossible" },
{ AccountStatus::Max, "GM Max" }
};
namespace ComparisonType {
constexpr uint8 Equal = 0;
constexpr uint8 NotEqual = 1;
constexpr uint8 GreaterOrEqual = 2;
constexpr uint8 LesserOrEqual = 3;
constexpr uint8 Greater = 4;
constexpr uint8 Lesser = 5;
constexpr uint8 Any = 6;
constexpr uint8 NotAny = 7;
constexpr uint8 Between = 8;
constexpr uint8 NotBetween = 9;
std::string GetName(uint8 type);
bool IsValid(uint8 type);
}
static std::map<uint8, std::string> comparison_types = {
{ ComparisonType::Equal, "Equal" },
{ ComparisonType::NotEqual, "Not Equal" },
{ ComparisonType::GreaterOrEqual, "Greater or Equal" },
{ ComparisonType::LesserOrEqual, "Lesser or Equal" },
{ ComparisonType::Greater, "Greater" },
{ ComparisonType::Lesser, "Lesser" },
{ ComparisonType::Any, "Any" },
{ ComparisonType::NotAny, "Not Any" },
{ ComparisonType::Between, "Between" },
{ ComparisonType::NotBetween, "Not Between" },
};
// local definitions are the result of using hybrid-client or server-only values and methods
namespace EQ
@@ -62,7 +132,7 @@ namespace EQ
using RoF2::invtype::KRONO_SIZE;
using RoF2::invtype::OTHER_SIZE;
using Titanium::invtype::TRADE_NPC_SIZE;
using RoF2::invtype::TRADE_NPC_SIZE;
using RoF2::invtype::TYPE_INVALID;
using RoF2::invtype::TYPE_BEGIN;
@@ -89,7 +159,7 @@ namespace EQ
using RoF2::invslot::SLOT_INVALID;
using RoF2::invslot::SLOT_BEGIN;
using Titanium::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE;
using RoF2::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE;
const int16 SLOT_AUGMENT_GENERIC_RETURN = 1001; // clients don't appear to use this method... (internal inventory return value)
@@ -109,28 +179,28 @@ namespace EQ
using RoF2::invslot::BONUS_STAT_END;
using RoF2::invslot::BONUS_SKILL_END;
using Titanium::invslot::BANK_BEGIN;
using SoF::invslot::BANK_END;
using RoF2::invslot::BANK_BEGIN;
using RoF2::invslot::BANK_END;
using Titanium::invslot::SHARED_BANK_BEGIN;
using Titanium::invslot::SHARED_BANK_END;
using RoF2::invslot::SHARED_BANK_BEGIN;
using RoF2::invslot::SHARED_BANK_END;
using Titanium::invslot::TRADE_BEGIN;
using Titanium::invslot::TRADE_END;
using RoF2::invslot::TRADE_BEGIN;
using RoF2::invslot::TRADE_END;
using Titanium::invslot::TRADE_NPC_END;
using RoF2::invslot::TRADE_NPC_END;
using Titanium::invslot::WORLD_BEGIN;
using Titanium::invslot::WORLD_END;
using RoF2::invslot::WORLD_BEGIN;
using RoF2::invslot::WORLD_END;
using Titanium::invslot::TRIBUTE_BEGIN;
using Titanium::invslot::TRIBUTE_END;
using RoF2::invslot::TRIBUTE_BEGIN;
using RoF2::invslot::TRIBUTE_END;
using Titanium::invslot::GUILD_TRIBUTE_BEGIN;
using Titanium::invslot::GUILD_TRIBUTE_END;
using RoF2::invslot::GUILD_TRIBUTE_BEGIN;
using RoF2::invslot::GUILD_TRIBUTE_END;
const int16 CORPSE_BEGIN = invslot::slotGeneral1;
const int16 CORPSE_END = CORPSE_BEGIN + invslot::slotCursor;
const int16 CORPSE_END = CORPSE_BEGIN + invslot::slotCursor;
using RoF2::invslot::EQUIPMENT_BITMASK;
using RoF2::invslot::GENERAL_BITMASK;
@@ -144,38 +214,40 @@ namespace EQ
} // namespace invslot
namespace invbag {
using Titanium::invbag::SLOT_INVALID;
using Titanium::invbag::SLOT_BEGIN;
using Titanium::invbag::SLOT_END;
using Titanium::invbag::SLOT_COUNT;
using RoF2::invbag::SLOT_INVALID;
using RoF2::invbag::SLOT_BEGIN;
using RoF2::invbag::SLOT_END;
using RoF2::invbag::SLOT_COUNT;
using Titanium::invbag::GENERAL_BAGS_BEGIN;
using RoF2::invslot::WORLD_END;
const int16 GENERAL_BAGS_BEGIN = WORLD_END + 1;
const int16 GENERAL_BAGS_COUNT = invslot::GENERAL_COUNT * SLOT_COUNT;
const int16 GENERAL_BAGS_END = (GENERAL_BAGS_BEGIN + GENERAL_BAGS_COUNT) - 1;
const int16 GENERAL_BAGS_END = (GENERAL_BAGS_BEGIN + GENERAL_BAGS_COUNT) - 1;
const int16 GENERAL_BAGS_8_COUNT = 8 * SLOT_COUNT;
const int16 GENERAL_BAGS_8_END = (GENERAL_BAGS_BEGIN + GENERAL_BAGS_8_COUNT) - 1;
const int16 GENERAL_BAGS_8_END = (GENERAL_BAGS_BEGIN + GENERAL_BAGS_8_COUNT) - 1;
const int16 CURSOR_BAG_BEGIN = 351;
const int16 CURSOR_BAG_BEGIN = GENERAL_BAGS_END + 1;
const int16 CURSOR_BAG_COUNT = SLOT_COUNT;
const int16 CURSOR_BAG_END = (CURSOR_BAG_BEGIN + CURSOR_BAG_COUNT) - 1;
const int16 CURSOR_BAG_END = (CURSOR_BAG_BEGIN + CURSOR_BAG_COUNT) - 1;
using Titanium::invbag::BANK_BAGS_BEGIN;
const int16 BANK_BAGS_BEGIN = CURSOR_BAG_END + 1;
const int16 BANK_BAGS_COUNT = (invtype::BANK_SIZE * SLOT_COUNT);
const int16 BANK_BAGS_END = (BANK_BAGS_BEGIN + BANK_BAGS_COUNT) - 1;
const int16 BANK_BAGS_END = (BANK_BAGS_BEGIN + BANK_BAGS_COUNT) - 1;
const int16 BANK_BAGS_16_COUNT = 16 * SLOT_COUNT;
const int16 BANK_BAGS_16_END = (BANK_BAGS_BEGIN + BANK_BAGS_16_COUNT) - 1;
const int16 BANK_BAGS_16_END = (BANK_BAGS_BEGIN + BANK_BAGS_16_COUNT) - 1;
using Titanium::invbag::SHARED_BANK_BAGS_BEGIN;
const int16 SHARED_BANK_BAGS_BEGIN = BANK_BAGS_END + 1;
const int16 SHARED_BANK_BAGS_COUNT = invtype::SHARED_BANK_SIZE * SLOT_COUNT;
const int16 SHARED_BANK_BAGS_END = (SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_COUNT) - 1;
const int16 SHARED_BANK_BAGS_END = (SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_COUNT) - 1;
using Titanium::invbag::TRADE_BAGS_BEGIN;
const int16 TRADE_BAGS_BEGIN = SHARED_BANK_BAGS_END + 1;
const int16 TRADE_BAGS_COUNT = invtype::TRADE_SIZE * SLOT_COUNT;
const int16 TRADE_BAGS_END = (TRADE_BAGS_BEGIN + TRADE_BAGS_COUNT) - 1;
const int16 TRADE_BAGS_END = (TRADE_BAGS_BEGIN + TRADE_BAGS_COUNT) - 1;
using Titanium::invbag::GetInvBagIndexName;
using RoF2::invbag::GetInvBagIndexName;
} // namespace invbag
@@ -204,19 +276,6 @@ namespace EQ
const size_t SAY_LINK_CLOSER_SIZE = 1;
const size_t SAY_LINK_MAXIMUM_SIZE = (SAY_LINK_OPENER_SIZE + SAY_LINK_BODY_SIZE + SAY_LINK_TEXT_SIZE + SAY_LINK_CLOSER_SIZE);
enum StanceType : int {
stanceUnknown = 0,
stancePassive,
stanceBalanced,
stanceEfficient,
stanceReactive,
stanceAggressive,
stanceAssist,
stanceBurn,
stanceEfficient2,
stanceBurnAE
};
enum BotSpellIDs : int {
Warrior = 3001,
Cleric,
@@ -267,70 +326,6 @@ namespace EQ
Looting
};
enum ObjectTypes : int {
SmallBag,
LargeBag,
Quiver,
BeltPouch,
WristPouch,
Backpack,
SmallChest,
LargeChest,
Bandolier,
Medicine,
Tinkering,
Lexicon,
PoisonMaking,
Quest,
MixingBowl,
Baking,
Tailoring,
Blacksmithing,
Fletching,
Brewing,
JewelryMaking,
Pottery,
Kiln,
KeyMaker,
ResearchWIZ,
ResearchMAG,
ResearchNEC,
ResearchENC,
Unknown,
ResearchPractice,
Alchemy,
HighElfForge,
DarkElfForge,
OgreForge,
DwarfForge,
GnomeForge,
BarbarianForge,
IksarForge,
HumanForgeOne,
HumanForgeTwo,
HalflingTailoringOne,
HalflingTailoringTwo,
EruditeTailoring,
WoodElfTailoring,
WoodElfFletching,
IksarPottery,
Fishing,
TrollForge,
WoodElfForge,
HalflingForge,
EruditeForge,
Merchant,
FroglokForge,
Augmenter,
Churn,
TransformationMold,
DetransformationMold,
Unattuner,
TradeskillBag,
CollectibleBag,
NoDeposit
};
enum WeatherTypes : uint8 {
None,
Raining,
@@ -356,9 +351,6 @@ namespace EQ
Proximity
};
const char *GetStanceName(StanceType stance_type);
int ConvertStanceTypeToIndex(StanceType stance_type);
extern const std::map<uint8, std::string>& GetLanguageMap();
std::string GetLanguageName(uint8 language_id);
@@ -368,12 +360,6 @@ namespace EQ
extern const std::map<int8, std::string>& GetFlyModeMap();
std::string GetFlyModeName(int8 flymode_id);
extern const std::map<bodyType, std::string>& GetBodyTypeMap();
std::string GetBodyTypeName(bodyType bodytype_id);
extern const std::map<uint8, std::string>& GetAccountStatusMap();
std::string GetAccountStatusName(uint8 account_status);
extern const std::map<uint8, std::string>& GetConsiderLevelMap();
std::string GetConsiderLevelName(uint8 consider_level);
@@ -386,9 +372,6 @@ namespace EQ
extern const std::map<uint8, std::string>& GetSpawnAnimationMap();
std::string GetSpawnAnimationName(uint8 animation_id);
extern const std::map<int, std::string>& GetObjectTypeMap();
std::string GetObjectTypeName(int object_type);
extern const std::map<uint8, std::string>& GetWeatherTypeMap();
std::string GetWeatherTypeName(uint8 weather_type);
@@ -401,16 +384,9 @@ namespace EQ
extern const std::map<uint32, std::string>& GetAppearanceTypeMap();
std::string GetAppearanceTypeName(uint32 animation_type);
extern const std::map<uint32, std::string>& GetSpecialAbilityMap();
std::string GetSpecialAbilityName(uint32 ability_id);
extern const std::map<uint32, std::string>& GetConsiderColorMap();
std::string GetConsiderColorName(uint32 consider_color);
const int STANCE_TYPE_FIRST = stancePassive;
const int STANCE_TYPE_LAST = stanceBurnAE;
const int STANCE_TYPE_COUNT = stanceBurnAE;
} /*constants*/
namespace profile {
@@ -464,37 +440,6 @@ namespace EQ
} // namespace spells
namespace bug {
enum CategoryID : uint32 {
catOther = 0,
catVideo,
catAudio,
catPathing,
catQuest,
catTradeskills,
catSpellStacking,
catDoorsPortals,
catItems,
catNPC,
catDialogs,
catLoNTCG,
catMercenaries
};
enum OptionalInfoFlag : uint32 {
infoNoOptionalInfo = 0x0,
infoCanDuplicate = 0x1,
infoCrashBug = 0x2,
infoTargetInfo = 0x4,
infoCharacterFlags = 0x8,
infoUnknownValue = 0xFFFFFFF0
};
const char* CategoryIDToCategoryName(CategoryID category_id);
CategoryID CategoryNameToCategoryID(const char* category_name);
} // namespace bug
enum WaypointStatus : int {
RoamBoxPauseInProgress = -3,
QuestControlNoGrid = -2,
@@ -508,7 +453,7 @@ namespace EQ
Raid,
Guild
};
}; // namespace consent
};
} /*EQEmu*/
enum ServerLockType : int {
@@ -517,26 +462,6 @@ enum ServerLockType : int {
Unlock
};
enum AccountStatus : uint8 {
Player = 0,
Steward = 10,
ApprenticeGuide = 20,
Guide = 50,
QuestTroupe = 80,
SeniorGuide = 81,
GMTester = 85,
EQSupport = 90,
GMStaff = 95,
GMAdmin = 100,
GMLeadAdmin = 150,
QuestMaster = 160,
GMAreas = 170,
GMCoder = 180,
GMMgmt = 200,
GMImpossible = 250,
Max = 255
};
enum Invisibility : uint8 {
Visible,
Invisible,
@@ -588,19 +513,6 @@ enum ReloadWorld : uint8 {
ForceRepop
};
enum BucketComparison : uint8 {
BucketEqualTo = 0,
BucketNotEqualTo,
BucketGreaterThanOrEqualTo,
BucketLesserThanOrEqualTo,
BucketGreaterThan,
BucketLesserThan,
BucketIsAny,
BucketIsNotAny,
BucketIsBetween,
BucketIsNotBetween
};
enum class EntityFilterType {
All,
Bots,
@@ -614,67 +526,131 @@ enum class ApplySpellType {
Raid
};
enum {
SPECATK_SUMMON = 1,
SPECATK_ENRAGE = 2,
SPECATK_RAMPAGE = 3,
SPECATK_AREA_RAMPAGE = 4,
SPECATK_FLURRY = 5,
SPECATK_TRIPLE = 6,
SPECATK_QUAD = 7,
SPECATK_INNATE_DW = 8,
SPECATK_BANE = 9,
SPECATK_MAGICAL = 10,
SPECATK_RANGED_ATK = 11,
UNSLOWABLE = 12,
UNMEZABLE = 13,
UNCHARMABLE = 14,
UNSTUNABLE = 15,
UNSNAREABLE = 16,
UNFEARABLE = 17,
UNDISPELLABLE = 18,
IMMUNE_MELEE = 19,
IMMUNE_MAGIC = 20,
IMMUNE_FLEEING = 21,
IMMUNE_MELEE_EXCEPT_BANE = 22,
IMMUNE_MELEE_NONMAGICAL = 23,
IMMUNE_AGGRO = 24,
IMMUNE_AGGRO_ON = 25,
IMMUNE_CASTING_FROM_RANGE = 26,
IMMUNE_FEIGN_DEATH = 27,
IMMUNE_TAUNT = 28,
NPC_TUNNELVISION = 29,
NPC_NO_BUFFHEAL_FRIENDS = 30,
IMMUNE_PACIFY = 31,
LEASH = 32,
TETHER = 33,
DESTRUCTIBLE_OBJECT = 34,
NO_HARM_FROM_CLIENT = 35,
ALWAYS_FLEE = 36,
FLEE_PERCENT = 37,
ALLOW_BENEFICIAL = 38,
DISABLE_MELEE = 39,
NPC_CHASE_DISTANCE = 40,
ALLOW_TO_TANK = 41,
IGNORE_ROOT_AGGRO_RULES = 42,
CASTING_RESIST_DIFF = 43,
COUNTER_AVOID_DAMAGE = 44, // Modify by percent NPC's opponents chance to riposte, block, parry or dodge individually, or for all skills
PROX_AGGRO = 45,
IMMUNE_RANGED_ATTACKS = 46,
IMMUNE_DAMAGE_CLIENT = 47,
IMMUNE_DAMAGE_NPC = 48,
IMMUNE_AGGRO_CLIENT = 49,
IMMUNE_AGGRO_NPC = 50,
MODIFY_AVOID_DAMAGE = 51, // Modify by percent the NPCs chance to riposte, block, parry or dodge individually, or for all skills
IMMUNE_FADING_MEMORIES = 52,
IMMUNE_OPEN = 53,
IMMUNE_ASSASSINATE = 54,
IMMUNE_HEADSHOT = 55,
IMMUNE_AGGRO_BOT = 56,
IMMUNE_DAMAGE_BOT = 57,
MAX_SPECIAL_ATTACK = 58
};
namespace SpecialAbility {
constexpr int Summon = 1;
constexpr int Enrage = 2;
constexpr int Rampage = 3;
constexpr int AreaRampage = 4;
constexpr int Flurry = 5;
constexpr int TripleAttack = 6;
constexpr int QuadrupleAttack = 7;
constexpr int DualWield = 8;
constexpr int BaneAttack = 9;
constexpr int MagicalAttack = 10;
constexpr int RangedAttack = 11;
constexpr int SlowImmunity = 12;
constexpr int MesmerizeImmunity = 13;
constexpr int CharmImmunity = 14;
constexpr int StunImmunity = 15;
constexpr int SnareImmunity = 16;
constexpr int FearImmunity = 17;
constexpr int DispellImmunity = 18;
constexpr int MeleeImmunity = 19;
constexpr int MagicImmunity = 20;
constexpr int FleeingImmunity = 21;
constexpr int MeleeImmunityExceptBane = 22;
constexpr int MeleeImmunityExceptMagical = 23;
constexpr int AggroImmunity = 24;
constexpr int BeingAggroImmunity = 25;
constexpr int CastingFromRangeImmunity = 26;
constexpr int FeignDeathImmunity = 27;
constexpr int TauntImmunity = 28;
constexpr int TunnelVision = 29;
constexpr int NoBuffHealFriends = 30;
constexpr int PacifyImmunity = 31;
constexpr int Leash = 32;
constexpr int Tether = 33;
constexpr int DestructibleObject = 34;
constexpr int HarmFromClientImmunity = 35;
constexpr int AlwaysFlee = 36;
constexpr int FleePercent = 37;
constexpr int AllowBeneficial = 38;
constexpr int DisableMelee = 39;
constexpr int NPCChaseDistance = 40;
constexpr int AllowedToTank = 41;
constexpr int IgnoreRootAggroRules = 42;
constexpr int CastingResistDifficulty = 43;
constexpr int CounterAvoidDamage = 44;
constexpr int ProximityAggro = 45;
constexpr int RangedAttackImmunity = 46;
constexpr int ClientDamageImmunity = 47;
constexpr int NPCDamageImmunity = 48;
constexpr int ClientAggroImmunity = 49;
constexpr int NPCAggroImmunity = 50;
constexpr int ModifyAvoidDamage = 51;
constexpr int MemoryFadeImmunity = 52;
constexpr int OpenImmunity = 53;
constexpr int AssassinateImmunity = 54;
constexpr int HeadshotImmunity = 55;
constexpr int BotAggroImmunity = 56;
constexpr int BotDamageImmunity = 57;
constexpr int Max = 58;
constexpr int MaxParameters = 9;
std::string GetName(int ability_id);
bool IsValid(int ability_id);
}
static std::map<int, std::string> special_ability_names = {
{ SpecialAbility::Summon, "Summon" },
{ SpecialAbility::Enrage, "Enrage" },
{ SpecialAbility::Rampage, "Rampage" },
{ SpecialAbility::AreaRampage, "Area Rampage" },
{ SpecialAbility::Flurry, "Flurry" },
{ SpecialAbility::TripleAttack, "Triple Attack" },
{ SpecialAbility::QuadrupleAttack, "Quadruple Attack" },
{ SpecialAbility::DualWield, "Dual Wield" },
{ SpecialAbility::BaneAttack, "Bane Attack" },
{ SpecialAbility::MagicalAttack, "Magical Attack" },
{ SpecialAbility::RangedAttack, "Ranged Attack" },
{ SpecialAbility::SlowImmunity, "Immune to Slow" },
{ SpecialAbility::MesmerizeImmunity, "Immune to Mesmerize" },
{ SpecialAbility::CharmImmunity, "Immune to Charm" },
{ SpecialAbility::StunImmunity, "Immune to Stun" },
{ SpecialAbility::SnareImmunity, "Immune to Snare" },
{ SpecialAbility::FearImmunity, "Immune to Fear" },
{ SpecialAbility::DispellImmunity, "Immune to Dispell" },
{ SpecialAbility::MeleeImmunity, "Immune to Melee" },
{ SpecialAbility::MagicImmunity, "Immune to Magic" },
{ SpecialAbility::FleeingImmunity, "Immune to Fleeing" },
{ SpecialAbility::MeleeImmunityExceptBane, "Immune to Melee except Bane" },
{ SpecialAbility::MeleeImmunityExceptMagical, "Immune to Non-Magical Melee" },
{ SpecialAbility::AggroImmunity, "Immune to Aggro" },
{ SpecialAbility::BeingAggroImmunity, "Immune to Being Aggro" },
{ SpecialAbility::CastingFromRangeImmunity, "Immune to Ranged Spells" },
{ SpecialAbility::FeignDeathImmunity, "Immune to Feign Death" },
{ SpecialAbility::TauntImmunity, "Immune to Taunt" },
{ SpecialAbility::TunnelVision, "Tunnel Vision" },
{ SpecialAbility::NoBuffHealFriends, "Does Not Heal or Buff Allies" },
{ SpecialAbility::PacifyImmunity, "Immune to Pacify" },
{ SpecialAbility::Leash, "Leashed" },
{ SpecialAbility::Tether, "Tethered" },
{ SpecialAbility::DestructibleObject, "Destructible Object" },
{ SpecialAbility::HarmFromClientImmunity, "Immune to Harm from Client" },
{ SpecialAbility::AlwaysFlee, "Always Flees" },
{ SpecialAbility::FleePercent, "Flee Percentage" },
{ SpecialAbility::AllowBeneficial, "Allows Beneficial Spells" },
{ SpecialAbility::DisableMelee, "Melee is Disabled" },
{ SpecialAbility::NPCChaseDistance, "Chase Distance" },
{ SpecialAbility::AllowedToTank, "Allowed to Tank" },
{ SpecialAbility::IgnoreRootAggroRules, "Ignores Root Aggro" },
{ SpecialAbility::CastingResistDifficulty, "Casting Resist Difficulty" },
{ SpecialAbility::CounterAvoidDamage, "Counter Damage Avoidance" },
{ SpecialAbility::ProximityAggro, "Proximity Aggro" },
{ SpecialAbility::RangedAttackImmunity, "Immune to Ranged Attacks" },
{ SpecialAbility::ClientDamageImmunity, "Immune to Client Damage" },
{ SpecialAbility::NPCDamageImmunity, "Immune to NPC Damage" },
{ SpecialAbility::ClientAggroImmunity, "Immune to Client Aggro" },
{ SpecialAbility::NPCAggroImmunity, "Immune to NPC Aggro" },
{ SpecialAbility::ModifyAvoidDamage, "Modify Damage Avoidance" },
{ SpecialAbility::MemoryFadeImmunity, "Immune to Memory Fades" },
{ SpecialAbility::OpenImmunity, "Immune to Open" },
{ SpecialAbility::AssassinateImmunity, "Immune to Assassinate" },
{ SpecialAbility::HeadshotImmunity, "Immune to Headshot" },
{ SpecialAbility::BotAggroImmunity, "Immune to Bot Aggro" },
{ SpecialAbility::BotDamageImmunity, "Immune to Bot Damage" },
};
namespace HeroicBonusBucket
{
@@ -700,4 +676,92 @@ namespace HeroicBonusBucket
const std::string DexEnduranceRegen = "HDEX-EnduranceRegen";
}
namespace Bug {
namespace Category {
constexpr uint32 Other = 0;
constexpr uint32 Video = 1;
constexpr uint32 Audio = 2;
constexpr uint32 Pathing = 3;
constexpr uint32 Quest = 4;
constexpr uint32 Tradeskills = 5;
constexpr uint32 SpellStacking = 6;
constexpr uint32 DoorsPortals = 7;
constexpr uint32 Items = 8;
constexpr uint32 NPC = 9;
constexpr uint32 Dialogs = 10;
constexpr uint32 LoNTCG = 11;
constexpr uint32 Mercenaries = 12;
}
namespace InformationFlag {
constexpr uint32 None = 0;
constexpr uint32 Repeatable = 1;
constexpr uint32 Crash = 2;
constexpr uint32 TargetInfo = 4;
constexpr uint32 CharacterFlags = 8;
constexpr uint32 Unknown = 4294967280;
}
uint32 GetID(const std::string& category_name);
std::string GetName(uint32 category_id);
bool IsValid(uint32 category_id);
}
static std::map<uint32, std::string> bug_category_names = {
{ Bug::Category::Other, "Other" },
{ Bug::Category::Video, "Video" },
{ Bug::Category::Audio, "Audio" },
{ Bug::Category::Pathing, "Pathing" },
{ Bug::Category::Quest, "Quest" },
{ Bug::Category::Tradeskills, "Tradeskills" },
{ Bug::Category::SpellStacking, "Spell Stacking" },
{ Bug::Category::DoorsPortals, "Doors and Portals" },
{ Bug::Category::Items, "Items" },
{ Bug::Category::NPC, "NPC" },
{ Bug::Category::Dialogs, "Dialogs" },
{ Bug::Category::LoNTCG, "LoN - TCG" },
{ Bug::Category::Mercenaries, "Mercenaries" }
};
namespace Stance {
constexpr uint32 Unknown = 0;
constexpr uint32 Passive = 1;
constexpr uint32 Balanced = 2;
constexpr uint32 Efficient = 3;
constexpr uint32 Reactive = 4;
constexpr uint32 Aggressive = 5;
constexpr uint32 Assist = 6;
constexpr uint32 Burn = 7;
constexpr uint32 Efficient2 = 8;
constexpr uint32 AEBurn = 9;
std::string GetName(uint8 stance_id);
uint8 GetIndex(uint8 stance_id);
bool IsValid(uint8 stance_id);
}
static std::map<uint32, std::string> stance_names = {
{ Stance::Unknown, "Unknown" },
{ Stance::Passive, "Passive" },
{ Stance::Balanced, "Balanced" },
{ Stance::Efficient, "Efficient" },
{ Stance::Reactive, "Reactive" },
{ Stance::Aggressive, "Aggressive" },
{ Stance::Assist, "Assist" },
{ Stance::Burn, "Burn" },
{ Stance::Efficient2, "Efficient" },
{ Stance::AEBurn, "AE Burn" }
};
namespace PCNPCOnlyFlagType {
constexpr int PC = 1;
constexpr int NPC = 2;
}
namespace BookType {
constexpr uint8 Scroll = 0;
constexpr uint8 Book = 1;
constexpr uint8 ItemInfo = 2;
}
#endif /*COMMON_EMU_CONSTANTS_H*/
+3
View File
@@ -67,6 +67,7 @@ N(OP_Buff),
N(OP_BuffCreate),
N(OP_BuffRemoveRequest),
N(OP_Bug),
N(OP_BuyerItems),
N(OP_CameraEffect),
N(OP_Camp),
N(OP_CancelSneakHide),
@@ -533,6 +534,7 @@ N(OP_Stamina),
N(OP_Stun),
N(OP_Surname),
N(OP_SwapSpell),
N(OP_SystemFingerprint),
N(OP_TargetBuffs),
N(OP_TargetCommand),
N(OP_TargetHoTT),
@@ -557,6 +559,7 @@ N(OP_TradeBusy),
N(OP_TradeCoins),
N(OP_TradeMoneyUpdate),
N(OP_Trader),
N(OP_TraderBulkSend),
N(OP_TraderBuy),
N(OP_TraderDelItem),
N(OP_TradeRequest),
+48 -65
View File
@@ -758,10 +758,10 @@ typedef enum {
FilterFocusEffects = 22, //0=show, 1=hide
FilterPetSpells = 23, //0=show, 1=hide
FilterHealOverTime = 24, //0=show, 1=mine only, 2=hide
FilterUnknown25 = 25,
FilterUnknown26 = 26,
FilterUnknown27 = 27,
FilterUnknown28 = 28,
FilterItemSpeech = 25, //0=show, 1=hide // RoF2 Confirmed
FilterStrikethrough = 26, //0=show, 1=hide // RoF2 Confirmed
FilterStuns = 27, //0=show, 1=hide // RoF2 Confirmed
FilterBardSongsOnPets = 28, //0=show, 1=hide // RoF2 Confirmed
_FilterCount
} eqFilterType;
@@ -772,67 +772,47 @@ typedef enum {
FilterShowSelfOnly
} eqFilterMode;
#define STAT_STR 0
#define STAT_STA 1
#define STAT_AGI 2
#define STAT_DEX 3
#define STAT_INT 4
#define STAT_WIS 5
#define STAT_CHA 6
#define STAT_MAGIC 7
#define STAT_COLD 8
#define STAT_FIRE 9
#define STAT_POISON 10
#define STAT_DISEASE 11
#define STAT_MANA 12
#define STAT_HP 13
#define STAT_AC 14
#define STAT_ENDURANCE 15
#define STAT_ATTACK 16
#define STAT_HP_REGEN 17
#define STAT_MANA_REGEN 18
#define STAT_HASTE 19
#define STAT_DAMAGE_SHIELD 20
/*
** Recast timer types. Used as an off set to charProfileStruct timers.
**
** (Another orphaned enumeration...)
*/
enum RecastTimerTypes
{
RecTimer_0 = 0,
RecTimer_1,
RecTimer_WeaponHealClick, // 2
RecTimer_MuramiteBaneNukeClick, // 3
RecTimer_4,
RecTimer_DispellClick, // 5 (also click heal orbs?)
RecTimer_Epic, // 6
RecTimer_OoWBPClick, // 7
RecTimer_VishQuestClassItem, // 8
RecTimer_HealPotion, // 9
RecTimer_10,
RecTimer_11,
RecTimer_12,
RecTimer_13,
RecTimer_14,
RecTimer_15,
RecTimer_16,
RecTimer_17,
RecTimer_18,
RecTimer_ModRod, // 19
_RecTimerCount
};
enum GroupUpdateAction
{
GUA_Joined = 0,
GUA_Left = 1,
GUA_LastLeft = 6,
GUA_FullGroupInfo = 7,
GUA_MakeLeader = 8,
GUA_Started = 9
};
#define STAT_STR 0
#define STAT_STA 1
#define STAT_AGI 2
#define STAT_DEX 3
#define STAT_INT 4
#define STAT_WIS 5
#define STAT_CHA 6
#define STAT_MAGIC 7
#define STAT_COLD 8
#define STAT_FIRE 9
#define STAT_POISON 10
#define STAT_DISEASE 11
#define STAT_MANA 12
#define STAT_HP 13
#define STAT_AC 14
#define STAT_ENDURANCE 15
#define STAT_ATTACK 16
#define STAT_HP_REGEN 17
#define STAT_MANA_REGEN 18
#define STAT_HASTE 19
#define STAT_DAMAGE_SHIELD 20
#define STAT_DS_MITIGATION 22
#define STAT_HEAL_AMOUNT 23
#define STAT_SPELL_DAMAGE 24
#define STAT_CLAIRVOYANCE 25
#define STAT_HEROIC_AGILITY 26
#define STAT_HEROIC_CHARISMA 27
#define STAT_HEROIC_DEXTERITY 28
#define STAT_HEROIC_INTELLIGENCE 29
#define STAT_HEROIC_STAMINA 30
#define STAT_HEROIC_STRENGTH 31
#define STAT_HEROIC_WISDOM 32
#define STAT_BASH 33
#define STAT_BACKSTAB 34
#define STAT_DRAGON_PUNCH 35
#define STAT_EAGLE_STRIKE 36
#define STAT_FLYING_KICK 37
#define STAT_KICK 38
#define STAT_ROUND_KICK 39
#define STAT_TIGER_CLAW 40
#define STAT_FRENZY 41
static const uint8 DamageTypeSomething = 0x1C; //0x1c is something...
static const uint8 DamageTypeFalling = 0xFC;
@@ -1149,4 +1129,7 @@ enum ExpSource
#define PARCEL_LIMIT 5
#define PARCEL_BEGIN_SLOT 1
namespace DoorType {
constexpr uint32 BuyerStall = 155;
}
#endif /*COMMON_EQ_CONSTANTS_H*/
+580 -135
View File
@@ -31,7 +31,6 @@
#include "../cereal/include/cereal/types/string.hpp"
#include "../cereal/include/cereal/types/vector.hpp"
static const uint32 BUFF_COUNT = 42;
static const uint32 PET_BUFF_COUNT = 30;
static const uint32 MAX_MERC = 100;
@@ -323,6 +322,8 @@ union
bool targetable_with_hotkey;
bool show_name;
bool guild_show;
bool trader;
bool buyer;
};
struct PlayerState_Struct {
@@ -1119,7 +1120,7 @@ struct PlayerProfile_Struct
/*19558*/ uint8 guildAutoconsent; // 0=off, 1=on
/*19559*/ uint8 unknown19595[5]; // ***Placeholder (6/29/2005)
/*19564*/ uint32 RestTimer;
/*19568*/
/*19568*/ uint32 char_id; // Found as part of bazaar revamp (5/15/2024)
// All player profile packets are translated and this overhead is ignored in out-bound packets
PlayerProfile_Struct() : m_player_profile_version(EQ::versions::MobVersion::Unknown) { }
@@ -1620,6 +1621,32 @@ struct MoveItem_Struct
/*0012*/
};
// New for RoF2 - Size: 12
struct InventorySlot_Struct
{
/*000*/ int16 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Delete Item = -1
/*002*/ int16 Unknown02;
/*004*/ int16 Slot;
/*006*/ int16 SubIndex;
/*008*/ int16 AugIndex; // Guessing - Seen 0xffff
/*010*/ int16 Unknown01; // Normally 0 - Seen 13262 when deleting an item, but didn't match item ID
/*012*/
};
struct MultiMoveItemSub_Struct
{
/*0000*/ InventorySlot_Struct from_slot;
/*0012*/ InventorySlot_Struct to_slot;
/*0024*/ uint32 number_in_stack;
/*0028*/ uint8 unknown[8];
};
struct MultiMoveItem_Struct
{
/*0000*/ uint32 count;
/*0004*/ MultiMoveItemSub_Struct moves[0];
};
// both MoveItem_Struct/DeleteItem_Struct server structures will be changing to a structure-based slot format..this will
// be used for handling SoF/SoD/etc... time stamps sent using the MoveItem_Struct format. (nothing will be done with this
// info at the moment..but, it is forwarded on to the server for handling/future use)
@@ -3002,26 +3029,26 @@ struct EnvDamage2_Struct {
//
enum {
BazaarTrader_StartTraderMode = 1,
BazaarTrader_EndTraderMode = 2,
BazaarTrader_UpdatePrice = 3,
BazaarTrader_EndTransaction = 4,
BazaarSearchResults = 7,
BazaarWelcome = 9,
BazaarBuyItem = 10,
BazaarTrader_ShowItems = 11,
BazaarSearchDone = 12,
BazaarTrader_StartTraderMode = 1,
BazaarTrader_EndTraderMode = 2,
BazaarTrader_UpdatePrice = 3,
BazaarTrader_EndTransaction = 4,
BazaarSearchResults = 7,
BazaarWelcome = 9,
BazaarBuyItem = 10,
BazaarTrader_ShowItems = 11,
BazaarSearchDone = 12,
BazaarTrader_CustomerBrowsing = 13,
BazaarInspectItem = 18,
BazaarSearchDone2 = 19,
BazaarInspectItem = 18,
BazaarSearchDone2 = 19,
BazaarTrader_StartTraderMode2 = 22
};
enum {
BazaarPriceChange_Fail = 0,
BazaarPriceChange_Fail = 0,
BazaarPriceChange_UpdatePrice = 1,
BazaarPriceChange_RemoveItem = 2,
BazaarPriceChange_AddItem = 3
BazaarPriceChange_RemoveItem = 2,
BazaarPriceChange_AddItem = 3
};
struct BazaarWindowStart_Struct {
@@ -3032,31 +3059,41 @@ struct BazaarWindowStart_Struct {
struct BazaarWelcome_Struct {
BazaarWindowStart_Struct Beginning;
uint32 Traders;
uint32 Items;
uint32 Unknown012;
uint32 Unknown016;
uint32 action;
uint32 traders;
uint32 items;
uint32 unknown_012;
uint32 unknown_016;
};
struct BazaarSearch_Struct {
BazaarWindowStart_Struct Beginning;
uint32 TraderID;
uint32 Class_;
uint32 Race;
uint32 ItemStat;
uint32 Slot;
uint32 Type;
char Name[64];
uint32 MinPrice;
uint32 MaxPrice;
uint32 Minlevel;
uint32 MaxLlevel;
struct BazaarSearchCriteria_Struct {
/*000*/ uint32 action{0};
/*004*/ uint32 search_scope{0}; // 1 all traders 0 local traders
/*008*/ uint32 unknown_008{0};
/*012*/ uint32 unknown_012{0};
/*016*/ uint32 trader_id{0};
/*020*/ uint32 _class{0};
/*024*/ uint32 race{0};
/*028*/ uint32 item_stat{0};
/*032*/ uint32 slot{0};
/*036*/ uint32 type{0};
/*040*/ char item_name[64]{""};
/*104*/ uint32 min_cost{0};
/*108*/ uint32 max_cost{0};
/*112*/ uint32 min_level{1};
/*116*/ uint32 max_level{0};
/*120*/ uint32 max_results{0};
/*124*/ uint32 prestige{0};
/*128*/ uint32 augment{0};
/*132*/ uint32 trader_entity_id{0};
};
struct BazaarInspect_Struct{
uint32 ItemID;
uint32 Unknown004;
char Name[64];
struct BazaarInspect_Struct {
uint32 action;
char player_name[64];
uint32 serial_number;
uint32 item_id;
uint32 trader_id;
};
struct NewBazaarInspect_Struct {
@@ -3076,6 +3113,14 @@ struct BazaarReturnDone_Struct{
uint32 Unknown012;
uint32 Unknown016;
};
struct BazaarDeliveryCost_Struct {
uint32 action;
uint16 voucher_delivery_cost;
float parcel_deliver_cost; //percentage of item cost
uint32 unknown_010;
};
struct BazaarSearchResults_Struct {
/*000*/ BazaarWindowStart_Struct Beginning;
/*004*/ uint32 NumItems;
@@ -3088,65 +3133,377 @@ struct BazaarSearchResults_Struct {
// New fields for SoD+, stripped off when encoding for older clients.
char SellerName[64];
uint32 ItemID;
uint32 ItemID2;
};
// Barter/Buyer
//
//
enum {
Barter_BuyerSearch = 0,
Barter_SellerSearch = 1,
Barter_BuyerModeOn = 2,
Barter_BuyerModeOff = 3,
Barter_BuyerItemUpdate = 5,
Barter_BuyerItemRemove = 6,
Barter_SellItem = 7,
#define MAX_BUYER_COMPENSATION_ITEMS 10
enum BarterBuyerActions {
Barter_BuyerSearch = 0,
Barter_SellerSearch = 1,
Barter_BuyerModeOn = 2,
Barter_BuyerModeOff = 3,
Barter_BuyerItemStart = 4,
Barter_BuyerItemUpdate = 5,
Barter_BuyerItemRemove = 6,
Barter_SellItem = 7,
Barter_SellerTransactionComplete = 8,
Barter_BuyerTransactionComplete = 9,
Barter_BuyerInspectBegin = 10,
Barter_BuyerInspectEnd = 11,
Barter_BuyerAppearance = 12,
Barter_BuyerInspectWindow = 13,
Barter_BarterItemInspect = 14,
Barter_SellerBrowsing = 15,
Barter_BuyerSearchResults = 16,
Barter_Welcome = 17,
Barter_WelcomeMessageUpdate = 19,
Barter_BuyerItemInspect = 21,
Barter_Unknown23 = 23
Barter_BuyerTransactionComplete = 9,
Barter_BuyerInspectBegin = 10,
Barter_BuyerInspectEnd = 11,
Barter_BuyerAppearance = 12,
Barter_BuyerInspectWindow = 13,
Barter_BarterItemInspect = 14,
Barter_SellerBrowsing = 15,
Barter_BuyerSearchResults = 16,
Barter_Welcome = 17,
Barter_WelcomeMessageUpdate = 19,
Barter_Greeting = 20,
Barter_BuyerItemInspect = 21,
Barter_OpenBarterWindow = 23,
Barter_AddToBarterWindow = 26,
Barter_RemoveFromBarterWindow = 27,
Barter_RemoveFromMerchantWindow = 50, //Not a client item. Used for internal communications.
Barter_FailedTransaction = 51,
Barter_BuyerCouldNotBeFound = 52,
Barter_FailedBuyerChecks = 53,
Barter_SellerCouldNotBeFound = 54,
Barter_FailedSellerChecks = 55
};
enum BarterBuyerSubActions {
Barter_Success = 0,
Barter_Failure = 1,
Barter_DataOutOfDate = 4,
Barter_SellerDoesNotHaveItem = 6,
Barter_SameZone = 8
};
enum BuyerBarter {
Off = 0,
On = 1
};
struct BuyerRemoveItem_Struct {
uint32 action;
uint32 buy_slot_id;
};
struct BuyerRemoveItemFromMerchantWindow_Struct {
uint32 action;
uint32 unknown_004;
uint32 buy_slot_id;
uint32 unknown_012;
};
struct BuyerGeneric_Struct {
uint32 action;
char payload[];
};
struct BuyerMessaging_Struct {
uint32 action;
uint32 sub_action;
uint32 zone_id;
uint32 buyer_id;
uint32 buyer_entity_id;
char buyer_name[64];
uint32 buy_item_id;
uint32 buy_item_qty;
uint64 buy_item_cost;
uint32 buy_item_icon;
uint32 seller_entity_id;
char seller_name[64];
char item_name[64];
uint32 slot;
uint32 seller_quantity;
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
};
struct BuyerAddBuyertoBarterWindow_Struct {
uint32 action;
uint32 zone_id;
uint32 buyer_id;
uint32 buyer_entity_id;
char buyer_name[64];
};
struct BuyerRemoveBuyerFromBarterWindow_Struct {
uint32 action;
uint32 buyer_id;
};
struct BuyerBrowsing_Struct {
uint32 action;
char char_name[64];
};
struct BuyerGreeting_Struct {
uint32 action;
uint32 buyer_id;
};
struct BuyerWelcomeMessageUpdate_Struct {
/*000*/ uint32 Action;
/*004*/ char WelcomeMessage[256];
uint32 action;
char welcome_message[256];
};
struct BuyerItemSearch_Struct {
/*000*/ uint32 Unknown000;
/*004*/ char SearchString[64];
struct BuyerLineTradeItems_Struct {
uint32 item_id;
uint32 item_quantity;
uint32 item_icon;
std::string item_name;
void operator*=(uint32 multiplier)
{
this->item_quantity *= multiplier;
}
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(item_id),
CEREAL_NVP(item_quantity),
CEREAL_NVP(item_icon),
CEREAL_NVP(item_name)
);
}
};
struct BuyerItemSearchResultEntry_Struct {
/*000*/ char ItemName[64];
/*064*/ uint32 ItemID;
/*068*/ uint32 Unknown068;
/*072*/ uint32 Unknown072;
struct BuyerLineItems_Struct {
uint32 slot;
uint8 enabled;
uint32 item_id;
std::string item_name;
uint32 item_icon;
uint32 item_quantity;
uint8 item_toggle;
uint32 item_cost;
std::vector<BuyerLineTradeItems_Struct> trade_items;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(slot),
CEREAL_NVP(enabled),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(item_icon),
CEREAL_NVP(item_quantity),
CEREAL_NVP(item_toggle),
CEREAL_NVP(item_cost),
CEREAL_NVP(trade_items)
);
}
};
#define MAX_BUYER_ITEMSEARCH_RESULTS 200
struct BuyerBuyLines_Struct {
uint32 action;
union {
uint32 no_items;
uint32 string_length;
};
std::vector<BuyerLineItems_Struct> buy_lines;
struct BuyerItemSearchResults_Struct {
uint32 Action;
uint32 ResultCount;
BuyerItemSearchResultEntry_Struct Results[MAX_BUYER_ITEMSEARCH_RESULTS];
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(action),
CEREAL_NVP(no_items),
CEREAL_NVP(buy_lines)
);
}
};
struct BuyerLineSellItem_Struct {
uint32 action;
uint32 sub_action;
uint32 error_code;
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
uint32 buyer_entity_id;
uint32 buyer_id;
std::string buyer_name;
uint32 seller_entity_id;
std::string seller_name;
uint32 slot;
uint8 enabled;
uint32 item_id;
char item_name[64];
uint32 item_icon;
uint32 item_quantity;
uint8 item_toggle;
uint32 item_cost;
uint32 no_trade_items;
std::vector<BuyerLineTradeItems_Struct> trade_items;
uint32 seller_quantity;
uint32 zone_id;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(action),
CEREAL_NVP(sub_action),
CEREAL_NVP(error_code),
CEREAL_NVP(purchase_method),
CEREAL_NVP(buyer_entity_id),
CEREAL_NVP(buyer_id),
CEREAL_NVP(buyer_name),
CEREAL_NVP(seller_entity_id),
CEREAL_NVP(seller_name),
CEREAL_NVP(slot),
CEREAL_NVP(enabled),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(item_icon),
CEREAL_NVP(item_quantity),
CEREAL_NVP(item_toggle),
CEREAL_NVP(item_cost),
CEREAL_NVP(no_trade_items),
CEREAL_NVP(trade_items),
CEREAL_NVP(seller_quantity),
CEREAL_NVP(zone_id)
);
}
};
struct BuyerLineItemsSearch_Struct {
uint32 slot;
uint8 enabled;
uint32 item_id;
char item_name[64];
uint32 item_icon;
uint32 item_quantity;
uint8 item_toggle;
uint32 item_cost;
uint32 buyer_id;
uint32 buyer_entity_id;
uint32 buyer_zone_id;
uint32 buyer_zone_instance_id;
std::string buyer_name;
std::vector<BuyerLineTradeItems_Struct> trade_items;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(slot),
CEREAL_NVP(enabled),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(item_icon),
CEREAL_NVP(item_quantity),
CEREAL_NVP(item_toggle),
CEREAL_NVP(item_cost),
CEREAL_NVP(buyer_id),
CEREAL_NVP(buyer_entity_id),
CEREAL_NVP(buyer_zone_id),
CEREAL_NVP(buyer_zone_instance_id),
CEREAL_NVP(buyer_name),
CEREAL_NVP(trade_items)
);
}
};
struct BuyerLineSearch_Struct {
uint32 action;
uint32 no_items;
std::string search_string;
uint32 transaction_id;
std::vector<BuyerLineItemsSearch_Struct> buy_line;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(action),
CEREAL_NVP(no_items),
CEREAL_NVP(search_string),
CEREAL_NVP(transaction_id),
CEREAL_NVP(buy_line)
);
}
};
struct BuyerSetAppearance_Struct {
uint32 action;
uint32 entity_id;
uint32 status; // 0 off 1 on
char buyer_name[64];
};
struct BarterItemSearchLinkRequest_Struct {
uint32 action;
uint32 searcher_id;
uint32 unknown_008;
uint32 unknown_012;
uint32 item_id;
uint32 unknown_020;
};
struct BuyerInspectRequest_Struct {
uint32 action;
uint32 buyer_id;
uint32 approval;
};
struct BarterSearchRequest_Struct {
uint32 Action;
char SearchString[64];
uint32 SearchID;
uint32 action;
char search_string[64];
uint32 transaction_id;
uint32 unknown_072;
uint32 buyer_id;
uint8 search_scope; //0 All Buyers, 1 Local Buyers
uint16 zone_id;
};
struct BuyerItemSearch_Struct {
uint32 action;
char search_string[64];
};
struct BuyerItemSearchResultEntry_Struct {
char item_name[64];
uint32 item_id;
uint32 item_icon;
uint32 unknown_072;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(item_name),
CEREAL_NVP(item_id),
CEREAL_NVP(item_icon),
CEREAL_NVP(unknown_072)
);
}
};
struct BuyerItemSearchResults_Struct {
uint32 action;
uint32 result_count;
std::vector<BuyerItemSearchResultEntry_Struct> results;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(action),
CEREAL_NVP(result_count),
CEREAL_NVP(results)
);
}
};
//old below here
struct BuyerItemSearchLinkRequest_Struct {
/*000*/ uint32 Action; // 0x00000015
/*004*/ uint32 ItemID;
@@ -3154,31 +3511,6 @@ struct BuyerItemSearchLinkRequest_Struct {
/*012*/ uint32 Unknown012;
};
struct BarterItemSearchLinkRequest_Struct {
/*000*/ uint32 Action; // 0x0000000E
/*004*/ uint32 SearcherID;
/*008*/ uint32 Unknown008;
/*012*/ uint32 Unknown012;
/*016*/ uint32 ItemID;
/*020*/ uint32 Unknown020;
};
struct BuyerInspectRequest_Struct {
uint32 Action;
uint32 BuyerID;
uint32 Approval;
};
struct BuyerBrowsing_Struct {
uint32 Action;
char PlayerName[64];
};
struct BuyerRemoveItem_Struct {
uint32 Action;
uint32 BuySlot;
};
struct ServerSideFilters_Struct {
uint8 clientattackfilters; // 0) No, 1) All (players) but self, 2) All (players) but group
uint8 npcattackfilters; // 0) No, 1) Ignore NPC misses (all), 2) Ignore NPC Misses + Attacks (all but self), 3) Ignores NPC Misses + Attacks (all but group)
@@ -3389,32 +3721,31 @@ struct WhoAllReturnStruct {
};
struct Trader_Struct {
/*000*/ uint32 Code;
/*004*/ uint32 Unknown004;
/*008*/ uint64 Items[80];
/*648*/ uint32 ItemCost[80];
/*000*/ uint32 action;
/*004*/ uint32 unknown_004;
/*008*/ uint64 items[EQ::invtype::BAZAAR_SIZE];
/*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE];
};
struct ClickTrader_Struct {
/*000*/ uint32 Code;
/*004*/ uint32 Unknown004;
/*008*/ int64 SerialNumber[80];
/*648*/ uint32 ItemCost[80];
/*000*/ uint32 action;
/*004*/ uint32 unknown_004;
/*008*/ int64 serial_number[EQ::invtype::BAZAAR_SIZE] {};
/*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE] {};
};
struct GetItems_Struct{
uint32 Items[80];
int32 SerialNumber[80];
int32 Charges[80];
uint32 items[EQ::invtype::BAZAAR_SIZE];
int32 serial_number[EQ::invtype::BAZAAR_SIZE];
int32 charges[EQ::invtype::BAZAAR_SIZE];
};
struct BecomeTrader_Struct
{
/*000*/ uint32 ID;
/*004*/ uint32 Code;
/*008*/ char Name[64];
/*072*/ uint32 Unknown072; // Observed 0x33,0x91 etc on zone-in, 0x00 when sent for a new trader after zone-in
/*076*/
struct BecomeTrader_Struct {
uint32 action;
uint32 zone_id;
uint32 trader_id;
uint32 entity_id;
char trader_name[64];
};
struct TraderStatus_Struct{
@@ -3424,20 +3755,30 @@ struct TraderStatus_Struct{
};
struct Trader_ShowItems_Struct{
/*000*/ uint32 Code;
/*004*/ uint32 TraderID;
/*000*/ uint32 action;
/*004*/ uint32 entity_id;
/*008*/ uint32 Unknown08[3];
/*020*/
};
struct TraderBuy_Struct{
/*000*/ uint32 Action;
/*004*/ uint32 TraderID;
/*008*/ uint32 ItemID;
/*012*/ uint32 AlreadySold;
/*016*/ uint32 Price;
/*020*/ uint32 Quantity;
/*024*/ char ItemName[64];
struct TraderBuy_Struct {
/*000*/ uint32 action;
/*004*/ uint32 method;
/*008*/ uint32 sub_action;
/*012*/ uint32 unknown_012;
/*016*/ uint32 trader_id;
/*020*/ char buyer_name[64];
/*084*/ char seller_name[64];
/*148*/ char unknown_148[32];
/*180*/ char item_name[64];
/*244*/ char serial_number[17];
/*261*/ char unknown_261[3];
/*264*/ uint32 item_id;
/*268*/ uint32 price;
/*272*/ uint32 already_sold;
/*276*/ uint32 unknown_276;
/*280*/ uint32 quantity;
/*284*/
};
struct TraderItemUpdate_Struct{
@@ -3465,15 +3806,15 @@ struct MoneyUpdate_Struct{
};
struct TraderDelItem_Struct{
uint32 Unknown000;
uint32 TraderID;
uint32 ItemID;
uint32 Unknown012;
uint32 unknown_000;
uint32 trader_id;
uint32 item_id;
uint32 unknown_012;
};
struct TraderClick_Struct{
/*000*/ uint32 TraderID;
/*004*/ uint32 Code;
/*000*/ uint32 Code;
/*004*/ uint32 TraderID;
/*008*/ uint32 Unknown008;
/*012*/ uint32 Approval;
/*016*/
@@ -5991,6 +6332,110 @@ struct UnderWorld {
/* 16 */
};
enum BazaarTraderBarterActions {
TraderOff = 0,
TraderOn = 1,
PriceUpdate = 3,
EndTransaction = 4,
BazaarSearch = 7,
WelcomeMessage = 9,
BuyTraderItem = 10,
ListTraderItems = 11,
CustomerBrowsing = 13,
BazaarInspect = 18,
ItemMove = 19,
TraderAck2 = 22,
AddTraderToBazaarWindow = 24,
RemoveTraderFromBazaarWindow = 25,
ClickTrader = 28,
DeliveryCostUpdate = 29
};
enum BazaarPurchaseActions {
BazaarByVendor = 0,
BazaarByParcel = 1,
BazaarByDirectToInventory = 2,
BarterByVendor = 0,
BarterInBazaar = 1,
BarterOutsideBazaar = 2
};
enum BazaarPurchaseSubActions {
Success = 0,
Failed = 1,
DataOutDated = 3,
TooManyParcels = 5,
TransactionInProgress = 6,
InsufficientFunds = 7
};
enum BazaarSearchScopes {
Local_Scope = 0,
AllTraders_Scope = 1,
NonRoFBazaarSearchScope = 99
};
struct BazaarSearchResultsFromDB_Struct {
uint32 count;
uint32 trader_id;
uint32 item_id;
uint32 serial_number;
uint32 charges;
uint32 cost;
uint32 slot_id;
uint32 icon_id;
uint32 sum_charges;
uint32 trader_zone_id;
uint32 trader_entity_id;
uint32 item_stat;
bool stackable;
std::string item_name;
std::string serial_number_RoF;
std::string trader_name;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(count),
CEREAL_NVP(trader_id),
CEREAL_NVP(item_id),
CEREAL_NVP(serial_number),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(slot_id),
CEREAL_NVP(icon_id),
CEREAL_NVP(sum_charges),
CEREAL_NVP(trader_zone_id),
CEREAL_NVP(trader_entity_id),
CEREAL_NVP(item_stat),
CEREAL_NVP(stackable),
CEREAL_NVP(item_name),
CEREAL_NVP(serial_number_RoF),
CEREAL_NVP(trader_name)
);
}
};
struct BazaarSearchMessaging_Struct {
uint32 action;
char payload[];
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(action),
CEREAL_NVP(payload)
);
}
};
struct BuylineItemDetails_Struct {
uint64 item_cost;
uint32 item_quantity;
};
// Restore structure packing to default
#pragma pack()
+1
View File
@@ -171,6 +171,7 @@ void EQEmuConfig::parse_config()
PluginDir = _root["server"]["directories"].get("plugins", "plugins/").asString();
LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString();
PatchDir = _root["server"]["directories"].get("patches", "./").asString();
OpcodeDir = _root["server"]["directories"].get("opcodes", "./").asString();
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
+1
View File
@@ -95,6 +95,7 @@ class EQEmuConfig
std::string PluginDir;
std::string LuaModuleDir;
std::string PatchDir;
std::string OpcodeDir;
std::string SharedMemDir;
std::string LogDir;
@@ -789,50 +789,36 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
);
}
std::string npc_info = fmt::format(
"{} ({})\n",
e.npc_name,
e.npc_id
);
npc_info += fmt::format(
"Is Quest Handin: {}",
e.is_quest_handin ? "Yes" : "No"
);
std::vector<DiscordField> f = {};
BuildDiscordField(&f, "NPC", npc_info);
if (!handin_items_info.empty()) {
BuildDiscordField(
&f,
"Handin Items",
fmt::format(
"{}",
handin_items_info
)
);
BuildDiscordField(&f, "Handin Items", handin_items_info);
}
if (!handin_money_info.empty()) {
BuildDiscordField(
&f,
"Handin Money",
fmt::format(
"{}",
handin_money_info
)
);
BuildDiscordField(&f, "Handin Money", handin_money_info);
}
if (!return_items_info.empty()) {
BuildDiscordField(
&f,
"Return Items",
fmt::format(
"{}",
return_items_info
)
);
BuildDiscordField(&f, "Return Items", return_items_info);
}
if (!return_money_info.empty()) {
BuildDiscordField(
&f,
"Return Money",
fmt::format(
"{}",
return_money_info
)
);
BuildDiscordField(&f, "Return Money", return_money_info);
}
std::vector<DiscordEmbed> embeds = {};
+52 -47
View File
@@ -642,6 +642,10 @@ void PlayerEventLogs::ProcessRetentionTruncation()
void PlayerEventLogs::ReloadSettings()
{
for (auto &e: PlayerEventLogSettingsRepository::All(*m_database)) {
if (e.id >= PlayerEvent::MAX || e.id < 0) {
continue;
}
m_settings[e.id] = e;
}
}
@@ -650,58 +654,59 @@ const int32_t RETENTION_DAYS_DEFAULT = 7;
void PlayerEventLogs::SetSettingsDefaults()
{
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
m_settings[PlayerEvent::ZONING].event_enabled = 1;
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
m_settings[PlayerEvent::TRADE].event_enabled = 1;
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SAY].event_enabled = 0;
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
m_settings[PlayerEvent::DEATH].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
m_settings[PlayerEvent::ZONING].event_enabled = 1;
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
m_settings[PlayerEvent::TRADE].event_enabled = 1;
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SAY].event_enabled = 0;
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
m_settings[PlayerEvent::DEATH].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
m_settings[PlayerEvent::GUILD_TRIBUTE_DONATE_ITEM].event_enabled = 1;
m_settings[PlayerEvent::GUILD_TRIBUTE_DONATE_PLAT].event_enabled = 1;
m_settings[PlayerEvent::PARCEL_SEND].event_enabled = 1;
m_settings[PlayerEvent::PARCEL_RETRIEVE].event_enabled = 1;
m_settings[PlayerEvent::PARCEL_DELETE].event_enabled = 1;
m_settings[PlayerEvent::BARTER_TRANSACTION].event_enabled = 1;
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
+41 -7
View File
@@ -60,7 +60,8 @@ namespace PlayerEvent {
GUILD_TRIBUTE_DONATE_PLAT,
PARCEL_SEND,
PARCEL_RETRIEVE,
PARCEL_DELETE,
PARCEL_DELETE,
BARTER_TRANSACTION,
MAX // dont remove
};
@@ -122,7 +123,8 @@ namespace PlayerEvent {
"Guild Tribute Donate Platinum",
"Parcel Item Sent",
"Parcel Item Retrieved",
"Parcel Prune Routine"
"Parcel Prune Routine",
"Barter Transaction"
};
// Generic struct used by all events
@@ -858,10 +860,12 @@ namespace PlayerEvent {
class HandinEntry {
public:
uint32 item_id;
std::string item_name;
uint16 charges;
bool attuned;
uint32 item_id;
std::string item_name;
std::vector<uint32> augment_ids;
std::vector<std::string> augment_names;
uint16 charges;
bool attuned;
// cereal
template<class Archive>
@@ -870,6 +874,8 @@ namespace PlayerEvent {
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(augment_ids),
CEREAL_NVP(augment_names),
CEREAL_NVP(charges),
CEREAL_NVP(attuned)
);
@@ -903,6 +909,7 @@ namespace PlayerEvent {
HandinMoney handin_money;
std::vector<HandinEntry> return_items;
HandinMoney return_money;
bool is_quest_handin;
// cereal
template<class Archive>
@@ -914,7 +921,8 @@ namespace PlayerEvent {
CEREAL_NVP(handin_items),
CEREAL_NVP(handin_money),
CEREAL_NVP(return_items),
CEREAL_NVP(return_money)
CEREAL_NVP(return_money),
CEREAL_NVP(is_quest_handin)
);
}
};
@@ -1081,6 +1089,32 @@ namespace PlayerEvent {
);
}
};
struct BarterTransaction {
std::string status;
uint32 item_id;
uint32 item_quantity;
std::string item_name;
std::vector<BuyerLineTradeItems_Struct> trade_items;
std::string buyer_name;
std::string seller_name;
uint64 total_cost;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(status),
CEREAL_NVP(item_id),
CEREAL_NVP(item_quantity),
CEREAL_NVP(item_name),
CEREAL_NVP(trade_items),
CEREAL_NVP(buyer_name),
CEREAL_NVP(seller_name),
CEREAL_NVP(total_cost)
);
}
};
}
#endif //EQEMU_PLAYER_EVENTS_H
File diff suppressed because it is too large Load Diff
+2 -9
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, uint8 class_id = Class::None, 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, uint32 deity_id = Deity::Unknown, uint8 level = 0);
// Remove item from inventory
bool DeleteItem(int16 slot_id, int16 quantity = 0);
@@ -176,6 +176,7 @@ namespace EQ
// Locate an available inventory slot
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = invslot::GENERAL_BEGIN, uint8 bag_start = invbag::SLOT_BEGIN);
int16 FindFirstFreeSlotThatFitsItem(const EQ::ItemData *inst);
// Calculate slot_id for an item within a bag
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
@@ -197,12 +198,6 @@ namespace EQ
uint8 FindBrightestLightType();
void dumpEntireInventory();
void dumpWornItems();
void dumpInventory();
void dumpBankItems();
void dumpSharedBankItems();
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, const std::string& value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, int value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, float value);
@@ -215,8 +210,6 @@ namespace EQ
///////////////////////////////
int GetSlotByItemInstCollection(const std::map<int16, ItemInstance*> &collection, ItemInstance *inst);
void dumpItemCollection(const std::map<int16, ItemInstance*> &collection);
void dumpBagContents(ItemInstance *inst, std::map<int16, ItemInstance*>::const_iterator *it);
// Retrieves item within an inventory bucket
ItemInstance* _GetItem(const std::map<int16, ItemInstance*>& bucket, int16 slot_id) const;
+55 -21
View File
@@ -81,45 +81,79 @@ bool IpUtil::IsIpInPrivateRfc1918(const std::string &ip)
);
}
/**
* Gets local address - pings google to inspect what interface was used locally
* @return
*/
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#endif
#include <iostream>
#include <string>
#include <cstring>
std::string IpUtil::GetLocalIPAddress()
{
char my_ip_address[16];
unsigned int my_port;
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
return "";
}
#endif
char my_ip_address[INET_ADDRSTRLEN];
struct sockaddr_in server_address{};
struct sockaddr_in my_address{};
int sockfd;
int sockfd;
// Connect to server
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
// Create a UDP socket
#ifdef _WIN32
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == INVALID_SOCKET) {
WSACleanup();
return "";
}
#else
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
return "";
}
#endif
// Set server_addr
// Set server_addr (dummy address)
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("172.217.160.99");
server_address.sin_port = htons(80);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("8.8.8.8"); // Google DNS
server_address.sin_port = htons(53); // DNS port
// Connect to server
if (connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
close(sockfd);
return "";
}
// Perform a dummy connection to the server (UDP)
connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
// Get my ip address and port
// Get my IP address
memset(&my_address, 0, sizeof(my_address));
socklen_t len = sizeof(my_address);
getsockname(sockfd, (struct sockaddr *) &my_address, &len);
inet_ntop(AF_INET, &my_address.sin_addr, my_ip_address, sizeof(my_ip_address));
my_port = ntohs(my_address.sin_port);
return fmt::format("{}", my_ip_address);
#ifdef _WIN32
closesocket(sockfd);
WSACleanup();
#else
close(sockfd);
#endif
LogInfo("Local IP Address [{}]", my_ip_address);
return std::string(my_ip_address);
}
/**
* Gets public address
* Uses various websites as options to return raw public IP back to the client
+69 -66
View File
@@ -58,72 +58,75 @@ namespace EQ
};
enum ItemType : uint8 {
/*9138*/ ItemType1HSlash = 0,
/*9141*/ ItemType2HSlash,
/*9140*/ ItemType1HPiercing,
/*9139*/ ItemType1HBlunt,
/*9142*/ ItemType2HBlunt,
/*5504*/ ItemTypeBow, // 5
/*----*/ ItemTypeUnknown1,
/*----*/ ItemTypeLargeThrowing,
/*5505*/ ItemTypeShield,
/*5506*/ ItemTypeScroll,
/*5507*/ ItemTypeArmor, // 10
/*5508*/ ItemTypeMisc, // a lot of random crap has this item use.
/*7564*/ ItemTypeLockPick,
/*----*/ ItemTypeUnknown2,
/*5509*/ ItemTypeFood,
/*5510*/ ItemTypeDrink, // 15
/*5511*/ ItemTypeLight,
/*5512*/ ItemTypeCombinable, // not all stackable items are this use...
/*5513*/ ItemTypeBandage,
/*----*/ ItemTypeSmallThrowing,
/*----*/ ItemTypeSpell, // 20 // spells and tomes
/*5514*/ ItemTypePotion,
/*----*/ ItemTypeUnknown3,
/*0406*/ ItemTypeWindInstrument,
/*0407*/ ItemTypeStringedInstrument,
/*0408*/ ItemTypeBrassInstrument, // 25
/*0405*/ ItemTypePercussionInstrument,
/*5515*/ ItemTypeArrow,
/*----*/ ItemTypeUnknown4,
/*5521*/ ItemTypeJewelry,
/*----*/ ItemTypeSkull, // 30
/*5516*/ ItemTypeBook, // skill-up tomes/books? (would probably need a pp flag if true...)
/*5517*/ ItemTypeNote,
/*5518*/ ItemTypeKey,
/*----*/ ItemTypeCoin,
/*5520*/ ItemType2HPiercing, // 35
/*----*/ ItemTypeFishingPole,
/*----*/ ItemTypeFishingBait,
/*5519*/ ItemTypeAlcohol,
/*----*/ ItemTypeKey2, // keys and satchels?? (questable keys?)
/*----*/ ItemTypeCompass, // 40
/*----*/ ItemTypeUnknown5,
/*----*/ ItemTypePoison, // might be wrong, but includes poisons
/*----*/ ItemTypeUnknown6,
/*----*/ ItemTypeUnknown7,
/*5522*/ ItemTypeMartial, // 45
/*----*/ ItemTypeUnknown8,
/*----*/ ItemTypeUnknown9,
/*----*/ ItemTypeUnknown10,
/*----*/ ItemTypeUnknown11,
/*----*/ ItemTypeSinging, // 50
/*5750*/ ItemTypeAllInstrumentTypes,
/*5776*/ ItemTypeCharm,
/*----*/ ItemTypeDye,
/*----*/ ItemTypeAugmentation,
/*----*/ ItemTypeAugmentationSolvent, // 55
/*----*/ ItemTypeAugmentationDistiller,
/*----*/ ItemTypeUnknown12,
/*----*/ ItemTypeFellowshipKit,
/*----*/ ItemTypeUnknown13,
/*----*/ ItemTypeRecipe, // 60
/*----*/ ItemTypeAdvancedRecipe,
/*----*/ ItemTypeJournal, // only one(1) database entry
/*----*/ ItemTypeAltCurrency, // alt-currency (as opposed to coinage)
/*5881*/ ItemTypePerfectedAugmentationDistiller,
/*----*/ ItemTypeCount
/*9138*/ ItemType1HSlash = 0,
/*9141*/ ItemType2HSlash,
/*9140*/ ItemType1HPiercing,
/*9139*/ ItemType1HBlunt,
/*9142*/ ItemType2HBlunt,
/*5504*/ ItemTypeBow, // 5
/*----*/ ItemTypeUnknown1,
/*----*/ ItemTypeLargeThrowing,
/*5505*/ ItemTypeShield,
/*5506*/ ItemTypeScroll,
/*5507*/ ItemTypeArmor, // 10
/*5508*/ ItemTypeMisc, // a lot of random crap has this item use.
/*7564*/ ItemTypeLockPick,
/*----*/ ItemTypeUnknown2,
/*5509*/ ItemTypeFood,
/*5510*/ ItemTypeDrink, // 15
/*5511*/ ItemTypeLight,
/*5512*/ ItemTypeCombinable, // not all stackable items are this use...
/*5513*/ ItemTypeBandage,
/*----*/ ItemTypeSmallThrowing,
/*----*/ ItemTypeSpell, // 20 // spells and tomes
/*5514*/ ItemTypePotion,
/*----*/ ItemTypeUnknown3,
/*0406*/ ItemTypeWindInstrument,
/*0407*/ ItemTypeStringedInstrument,
/*0408*/ ItemTypeBrassInstrument, // 25
/*0405*/ ItemTypePercussionInstrument,
/*5515*/ ItemTypeArrow,
/*----*/ ItemTypeUnknown4,
/*5521*/ ItemTypeJewelry,
/*----*/ ItemTypeSkull, // 30
/*5516*/ ItemTypeBook, // skill-up tomes/books? (would probably need a pp flag if true...)
/*5517*/ ItemTypeNote,
/*5518*/ ItemTypeKey,
/*----*/ ItemTypeCoin,
/*5520*/ ItemType2HPiercing, // 35
/*----*/ ItemTypeFishingPole,
/*----*/ ItemTypeFishingBait,
/*5519*/ ItemTypeAlcohol,
/*----*/ ItemTypeKey2, // keys and satchels?? (questable keys?)
/*----*/ ItemTypeCompass, // 40
/*----*/ ItemTypeUnknown5,
/*----*/ ItemTypePoison, // might be wrong, but includes poisons
/*----*/ ItemTypeUnknown6,
/*----*/ ItemTypeUnknown7,
/*5522*/ ItemTypeMartial, // 45
/*----*/ ItemTypeAllEffects,
/*----*/ ItemTypeUnknown9,
/*----*/ ItemTypeUnknown10,
/*----*/ ItemTypeFocusEffect,
/*----*/ ItemTypeSinging, // 50
/*5750*/ ItemTypeAllInstrumentTypes,
/*5776*/ ItemTypeCharm,
/*----*/ ItemTypeDye,
/*----*/ ItemTypeAugmentation,
/*----*/ ItemTypeAugmentationSolvent, // 55
/*----*/ ItemTypeAugmentationDistiller,
/*----*/ ItemTypeAlternateAbility,
/*----*/ ItemTypeFellowshipKit,
/*----*/ ItemTypeUnknown13,
/*----*/ ItemTypeRecipe, // 60
/*----*/ ItemTypeAdvancedRecipe,
/*----*/ ItemTypeJournal, // only one(1) database entry
/*----*/ ItemTypeAltCurrency, // alt-currency (as opposed to coinage)
/*5881*/ ItemTypePerfectedAugmentationDistiller,
/*----*/ ItemTypeCount,
/*----*/ ItemTypeCollectible,
/*----*/ ItemTypeContainer,
/*----*/ ItemTypeAll = 0xFF
/*
Unknowns:
+175 -36
View File
@@ -32,10 +32,11 @@
//#include <iostream>
int32 NextItemInstSerialNumber = 1;
static inline int32 GetNextItemInstSerialNumber() {
int32 next_item_serial_number = 1;
std::unordered_set<uint64> guids{};
static inline int32 GetNextItemInstSerialNumber()
{
// The Bazaar relies on each item a client has up for Trade having a unique
// identifier. This 'SerialNumber' is sent in Serialized item packets and
// is used in Bazaar packets to identify the item a player is buying or inspecting.
@@ -46,12 +47,18 @@ static inline int32 GetNextItemInstSerialNumber() {
// NextItemInstSerialNumber is the next one to hand out.
//
// It is very unlikely to reach 2,147,483,647. Maybe we should call abort(), rather than wrapping back to 1.
if(NextItemInstSerialNumber >= INT_MAX)
NextItemInstSerialNumber = 1;
else
NextItemInstSerialNumber++;
if (next_item_serial_number >= INT32_MAX) {
next_item_serial_number = 1;
}
else {
next_item_serial_number++;
}
return NextItemInstSerialNumber;
while (guids.contains(next_item_serial_number)) {
next_item_serial_number++;
}
return next_item_serial_number;
}
//
@@ -303,47 +310,34 @@ int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const
return INVALID_INDEX;
}
auto i = invaug::SOCKET_BEGIN;
for (; i <= invaug::SOCKET_END; ++i) {
if (GetItem(i)) {
continue;
}
if (
augment_type == -1 ||
(
m_item->AugSlotType[i] &&
((1 << (m_item->AugSlotType[i] - 1)) & augment_type)
)
) {
break;
for (int16 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; ++slot_id) {
if (IsAugmentSlotAvailable(augment_type, slot_id)) {
return slot_id;
}
}
return (i <= invaug::SOCKET_END) ? i : INVALID_INDEX;
return INVALID_INDEX;
}
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const
{
if (!m_item || !m_item->IsClassCommon()) {
if (!m_item || !m_item->IsClassCommon() || GetItem(slot)) {
return false;
}
if (
return (
(
!GetItem(slot) &&
m_item->AugSlotVisible[slot]
augment_type == -1 ||
(
m_item->AugSlotType[slot] &&
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
)
) &&
augment_type == -1 ||
(
m_item->AugSlotType[slot] &&
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
RuleB(Items, AugmentItemAllowInvisibleAugments) ||
m_item->AugSlotVisible[slot]
)
) {
return true;
}
return false;
);
}
// Retrieve item inside container
@@ -1292,7 +1286,7 @@ int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
return race;
}
int EQ::ItemInstance::GetItemBaneDamageBody(bodyType against, bool augments) const
int EQ::ItemInstance::GetItemBaneDamageBody(uint8 against, bool augments) const
{
int64 damage = 0;
const auto item = GetItem();
@@ -1812,6 +1806,151 @@ std::vector<uint32> EQ::ItemInstance::GetAugmentIDs() const
return augments;
}
int EQ::ItemInstance::GetItemRegen(bool augments) const
{
int stat = 0;
const auto item = GetItem();
if (item) {
stat = item->Regen;
if (augments) {
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
if (GetAugment(i)) {
stat += GetAugment(i)->GetItemRegen();
}
}
}
}
return stat;
}
int EQ::ItemInstance::GetItemManaRegen(bool augments) const
{
int stat = 0;
const auto item = GetItem();
if (item) {
stat = item->ManaRegen;
if (augments) {
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
if (GetAugment(i)) {
stat += GetAugment(i)->GetItemManaRegen();
}
}
}
}
return stat;
}
int EQ::ItemInstance::GetItemDamageShield(bool augments) const
{
int stat = 0;
const auto item = GetItem();
if (item) {
stat = item->DamageShield;
if (augments) {
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
if (GetAugment(i)) {
stat += GetAugment(i)->GetItemDamageShield();
}
}
}
}
return stat;
}
int EQ::ItemInstance::GetItemDSMitigation(bool augments) const
{
int stat = 0;
const auto item = GetItem();
if (item) {
stat = item->DSMitigation;
if (augments) {
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
if (GetAugment(i)) {
stat += GetAugment(i)->GetItemDSMitigation();
}
}
}
}
return stat;
}
int EQ::ItemInstance::GetItemHealAmt(bool augments) const
{
int stat = 0;
const auto item = GetItem();
if (item) {
stat = item->HealAmt;
if (augments) {
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
if (GetAugment(i)) {
stat += GetAugment(i)->GetItemHealAmt();
}
}
}
}
return stat;
}
int EQ::ItemInstance::GetItemSpellDamage(bool augments) const
{
int stat = 0;
const auto item = GetItem();
if (item) {
stat = item->SpellDmg;
if (augments) {
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
if (GetAugment(i)) {
stat += GetAugment(i)->GetItemSpellDamage();
}
}
}
}
return stat;
}
int EQ::ItemInstance::GetItemClairvoyance(bool augments) const
{
int stat = 0;
const auto item = GetItem();
if (item) {
stat = item->Clairvoyance;
if (augments) {
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
if (GetAugment(i)) {
stat += GetAugment(i)->GetItemClairvoyance();
}
}
}
}
return stat;
}
int EQ::ItemInstance::GetItemSkillsStat(EQ::skills::SkillType skill, bool augments) const
{
int stat = 0;
const auto item = GetItem();
if (item) {
stat = item->ExtraDmgSkill == skill ? item->ExtraDmgAmt : 0;
if (augments) {
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
if (GetAugment(i)) {
stat += GetAugment(i)->GetItemSkillsStat(skill);
}
}
}
}
return stat;
}
void EQ::ItemInstance::AddGUIDToMap(uint64 existing_serial_number)
{
guids.emplace(existing_serial_number);
}
void EQ::ItemInstance::ClearGUIDMap()
{
guids.clear();
}
//
// class EvolveInfo
//
+11 -1
View File
@@ -265,11 +265,12 @@ namespace EQ
// these two are just quick checks
int GetItemBaneDamageBody(bool augments = false) const;
int GetItemBaneDamageRace(bool augments = false) const;
int GetItemBaneDamageBody(bodyType against, bool augments = false) const;
int GetItemBaneDamageBody(uint8 against, bool augments = false) const;
int GetItemBaneDamageRace(uint16 against, bool augments = false) const;
int GetItemMagical(bool augments = false) const;
int GetItemHP(bool augments = false) const;
int GetItemMana(bool augments = false) const;
int GetItemManaRegen(bool augments = false) const;
int GetItemEndur(bool augments = false) const;
int GetItemAttack(bool augments = false) const;
int GetItemStr(bool augments = false) const;
@@ -299,8 +300,17 @@ namespace EQ
int GetItemHeroicDR(bool augments = false) const;
int GetItemHeroicCorrup(bool augments = false) const;
int GetItemHaste(bool augments = false) const;
int GetItemRegen(bool augments = false) const;
int GetItemDamageShield(bool augments = false) const;
int GetItemDSMitigation(bool augments = false) const;
int GetItemHealAmt(bool augments = false) const;
int GetItemSpellDamage(bool augments = false) const;
int GetItemClairvoyance(bool augments = false) const;
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
uint32 GetItemGuildFavor() const;
std::vector<uint32> GetAugmentIDs() const;
static void AddGUIDToMap(uint64 existing_serial_number);
static void ClearGUIDMap();
protected:
//////////////////////////
+586
View File
@@ -0,0 +1,586 @@
#include "mysql_stmt.h"
#include "eqemu_logsys.h"
#include "mutex.h"
#include "timer.h"
#include <charconv>
namespace mysql
{
void PreparedStmt::StmtDeleter::operator()(MYSQL_STMT* stmt) noexcept
{
// The connection must be locked when closing the stmt to avoid mysql errors
// in case another thread tries to use it during the close. If the mutex is
// changed to one that throws then exceptions need to be caught here.
LockMutex lock(mutex);
mysql_stmt_close(stmt);
}
PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts)
: m_stmt(mysql_stmt_init(&mysql), { mutex }), m_query(std::move(query)), m_mutex(mutex), m_options(opts)
{
LockMutex lock(m_mutex);
if (mysql_stmt_prepare(m_stmt.get(), m_query.c_str(), static_cast<unsigned long>(m_query.size())) != 0)
{
ThrowError(fmt::format("Prepare error: {}", GetStmtError()));
}
m_params.resize(mysql_stmt_param_count(m_stmt.get()));
m_inputs.resize(m_params.size());
}
void PreparedStmt::ThrowError(const std::string& error)
{
LogMySQLError("{}", error);
throw std::runtime_error(error);
}
std::string PreparedStmt::GetStmtError()
{
auto err = mysql_stmt_errno(m_stmt.get());
auto str = mysql_stmt_error(m_stmt.get());
return fmt::format("({}) [{}] for query [{}]", err, str, m_query);
}
template <typename T>
void PreparedStmt::BindInput(size_t index, T value)
{
if (index >= m_inputs.size())
{
ThrowError(fmt::format("Cannot bind input, index {} out of range", index));
}
impl::Bind& arg = m_inputs[index];
arg.is_null = std::is_same_v<T, std::nullptr_t>;
MYSQL_BIND& bind = m_params[index];
bind.is_unsigned = std::is_unsigned_v<T>;
bind.is_null = &arg.is_null;
bind.length = &arg.length;
auto old_type = bind.buffer_type;
if constexpr (std::is_arithmetic_v<T>)
{
if (arg.buffer.size() < sizeof(T))
{
arg.buffer.resize(std::max(sizeof(T), sizeof(int64_t)));
bind.buffer = arg.buffer.data();
m_need_bind = true;
}
memcpy(arg.buffer.data(), &value, sizeof(T));
}
if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, uint8_t> || std::is_same_v<T, bool>)
{
bind.buffer_type = MYSQL_TYPE_TINY;
}
else if constexpr (std::is_same_v<T, int16_t> || std::is_same_v<T, uint16_t>)
{
bind.buffer_type = MYSQL_TYPE_SHORT;
}
else if constexpr (std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>)
{
bind.buffer_type = MYSQL_TYPE_LONG;
}
else if constexpr (std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>)
{
bind.buffer_type = MYSQL_TYPE_LONGLONG;
}
else if constexpr (std::is_same_v<T, float>)
{
bind.buffer_type = MYSQL_TYPE_FLOAT;
}
else if constexpr (std::is_same_v<T, double>)
{
bind.buffer_type = MYSQL_TYPE_DOUBLE;
}
else if constexpr (std::is_same_v<T, std::string_view>)
{
bind.buffer_type = MYSQL_TYPE_STRING;
if (arg.buffer.empty() || arg.buffer.size() < value.size())
{
arg.buffer.resize(static_cast<size_t>((value.size() + 1) * 1.5));
bind.buffer = arg.buffer.data();
bind.buffer_length = static_cast<unsigned long>(arg.buffer.size());
m_need_bind = true;
}
std::copy(value.begin(), value.end(), arg.buffer.begin());
arg.length = static_cast<unsigned long>(value.size());
}
else if constexpr (!std::is_same_v<T, std::nullptr_t>)
{
static_assert(false_v<T>, "Cannot bind unsupported type");
}
if (old_type != bind.buffer_type)
{
m_need_bind = true;
}
}
void PreparedStmt::BindInput(size_t index, const char* str)
{
BindInput(index, std::string_view(str));
}
void PreparedStmt::BindInput(size_t index, const std::string& str)
{
BindInput(index, std::string_view(str));
}
StmtResult PreparedStmt::Execute()
{
CheckArgs(0);
return DoExecute();
}
StmtResult PreparedStmt::Execute(const std::vector<param_t>& args)
{
CheckArgs(args.size());
for (size_t i = 0; i < args.size(); ++i)
{
std::visit([&](const auto& arg) { BindInput(i, arg); }, args[i]);
}
return DoExecute();
}
template <typename T>
StmtResult PreparedStmt::Execute(const std::vector<T>& args)
{
CheckArgs(args.size());
for (size_t i = 0; i < args.size(); ++i)
{
BindInput(i, args[i]);
}
return DoExecute();
}
void PreparedStmt::CheckArgs(size_t argc)
{
if (argc != m_params.size())
{
ThrowError(fmt::format("Bad arg count (got {}, expected {}) for [{}]", argc, m_params.size(), m_query));
}
}
StmtResult PreparedStmt::DoExecute()
{
BenchTimer timer;
LockMutex lock(m_mutex);
if (m_need_bind && mysql_stmt_bind_param(m_stmt.get(), m_params.data()) != 0)
{
ThrowError(fmt::format("Bind param error: {}", GetStmtError()));
}
m_need_bind = false;
if (mysql_stmt_execute(m_stmt.get()) != 0)
{
ThrowError(fmt::format("Execute error: {}", GetStmtError()));
}
my_bool attr = m_options.use_max_length;
mysql_stmt_attr_set(m_stmt.get(), STMT_ATTR_UPDATE_MAX_LENGTH, &attr);
if (m_options.buffer_results && mysql_stmt_store_result(m_stmt.get()) != 0)
{
ThrowError(fmt::format("Store result error: {}", GetStmtError()));
}
// Result buffers are bound on first execute and re-used if needed
if (m_results.empty())
{
BindResults();
}
StmtResult res(m_stmt.get(), m_results.size());
if (m_results.empty())
{
LogMySQLQuery("{} -- ({} row(s) affected) ({:.6f}s)", m_query, res.RowsAffected(), timer.elapsed());
}
else
{
LogMySQLQuery("{} -- ({} row(s) returned) ({:.6f}s)", m_query, res.RowCount(), timer.elapsed());
}
return res;
}
void PreparedStmt::BindResults()
{
MYSQL_RES* res = mysql_stmt_result_metadata(m_stmt.get());
if (!res)
{
return; // did not produce a result set
}
MYSQL_FIELD* fields = mysql_fetch_fields(res);
m_columns.resize(mysql_num_fields(res));
m_results.resize(m_columns.size());
for (int i = 0; i < static_cast<int>(m_columns.size()); ++i)
{
impl::BindColumn& col = m_columns[i].m_col;
MYSQL_BIND& bind = m_results[i];
col.index = i;
col.name = fields[i].name;
col.buffer_type = fields[i].type;
col.is_unsigned = (fields[i].flags & UNSIGNED_FLAG) != 0;
col.buffer.resize(GetResultBufferSize(fields[i]));
bind.buffer_type = col.buffer_type;
bind.buffer = col.buffer.data();
bind.buffer_length = static_cast<unsigned long>(col.buffer.size());
bind.is_unsigned = col.is_unsigned;
bind.is_null = &col.is_null;
bind.length = &col.length;
bind.error = &col.error;
}
mysql_free_result(res);
if (!m_results.empty() && mysql_stmt_bind_result(m_stmt.get(), m_results.data()) != 0)
{
ThrowError(fmt::format("Bind result error: {}", GetStmtError()));
}
}
int PreparedStmt::GetResultBufferSize(const MYSQL_FIELD& field) const
{
switch (field.type)
{
case MYSQL_TYPE_TINY:
return sizeof(int8_t);
case MYSQL_TYPE_SHORT:
return sizeof(int16_t);
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return sizeof(int32_t);
case MYSQL_TYPE_LONGLONG:
return sizeof(int64_t);
case MYSQL_TYPE_FLOAT:
return sizeof(float);
case MYSQL_TYPE_DOUBLE:
return sizeof(double);
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
return sizeof(MYSQL_TIME);
default: // if max_length is unavailable for strings buffers are resized on fetch
return field.max_length + 1; // ensure valid buffer created
}
}
StmtRow PreparedStmt::Fetch()
{
StmtRow row;
if (!m_columns.empty())
{
int rc = mysql_stmt_fetch(m_stmt.get());
if (rc == 1)
{
ThrowError(fmt::format("Fetch error: {}", GetStmtError()));
}
if (rc != MYSQL_NO_DATA)
{
if (rc == MYSQL_DATA_TRUNCATED)
{
FetchTruncated();
}
row = StmtRow(m_columns);
}
}
return row;
}
void PreparedStmt::FetchTruncated()
{
for (int i = 0; i < static_cast<int>(m_columns.size()); ++i)
{
impl::BindColumn& col = m_columns[i].m_col;
if (col.error)
{
MYSQL_BIND& bind = m_results[i];
col.buffer.resize(static_cast<size_t>(col.length * 1.5));
bind.buffer = col.buffer.data();
bind.buffer_length = static_cast<unsigned long>(col.buffer.size());
mysql_stmt_fetch_column(m_stmt.get(), &bind, i, 0);
}
}
if (mysql_stmt_bind_result(m_stmt.get(), m_results.data()) != 0)
{
ThrowError(fmt::format("Fetch rebind result error: {}", GetStmtError()));
}
}
// ---------------------------------------------------------------------------
StmtResult::StmtResult(MYSQL_STMT* stmt, size_t columns)
{
m_num_cols = static_cast<int>(columns);
m_num_rows = mysql_stmt_num_rows(stmt); // requires buffered results
m_affected = mysql_stmt_affected_rows(stmt);
m_insert_id = mysql_stmt_insert_id(stmt);
}
// ---------------------------------------------------------------------------
const StmtColumn* StmtRow::GetColumn(size_t index) const
{
return index < m_columns.size() ? &m_columns[index] : nullptr;
}
const StmtColumn* StmtRow::GetColumn(std::string_view name) const
{
auto it = std::ranges::find_if(m_columns,
[name](const StmtColumn& col) { return col.Name() == name; });
return it != m_columns.end() ? &(*it) : nullptr;
}
std::optional<std::string> StmtRow::operator[](size_t index) const
{
return GetStr(index);
}
std::optional<std::string> StmtRow::operator[](std::string_view name) const
{
return GetStr(name);
}
std::optional<std::string> StmtRow::GetStr(size_t index) const
{
const StmtColumn* col = GetColumn(index);
return col ? col->GetStr() : std::nullopt;
}
std::optional<std::string> StmtRow::GetStr(std::string_view name) const
{
const StmtColumn* col = GetColumn(name);
return col ? col->GetStr() : std::nullopt;
}
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> StmtRow::Get(size_t index) const
{
const StmtColumn* col = GetColumn(index);
return col ? col->Get<T>() : std::nullopt;
}
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> StmtRow::Get(std::string_view name) const
{
const StmtColumn* col = GetColumn(name);
return col ? col->Get<T>() : std::nullopt;
}
// ---------------------------------------------------------------------------
static time_t MakeTime(const MYSQL_TIME& mt)
{
// buffer mt given in mysql session time zone (assumes local)
std::tm tm{};
tm.tm_year = mt.year - 1900;
tm.tm_mon = mt.month - 1;
tm.tm_mday = mt.day;
tm.tm_hour = mt.hour;
tm.tm_min = mt.minute;
tm.tm_sec = mt.second;
tm.tm_isdst = -1;
return std::mktime(&tm);
}
static int MakeSeconds(const MYSQL_TIME& mt)
{
return (mt.neg ? -1 : 1) * static_cast<int>(mt.hour * 3600 + mt.minute * 60 + mt.second);
}
static uint64_t MakeBits(std::span<const uint8_t> data)
{
// byte stream for bits is in big endian
uint64_t bits = 0;
for (size_t i = 0; i < data.size() && i < sizeof(uint64_t); ++i)
{
bits |= static_cast<uint64_t>(data[data.size() - i - 1] & 0xff) << (i * 8);
}
return bits;
}
template <typename T>
static T FromString(std::string_view sv)
{
if constexpr (std::is_same_v<T, bool>)
{
// return false for empty (zero-length) strings
return !sv.empty();
}
else
{
// non numbers return a zero initialized T (could return nullopt instead)
T value = {};
std::from_chars(sv.data(), sv.data() + sv.size(), value);
return value;
}
}
static std::string FormatTime(enum_field_types type, const MYSQL_TIME& mt)
{
switch (type)
{
case MYSQL_TYPE_TIME: // hhh:mm:ss '-838:59:59' to '838:59:59'
return fmt::format("{}{:02d}:{:02d}:{:02d}", mt.neg ? "-" : "", mt.hour, mt.minute, mt.second);
case MYSQL_TYPE_DATE: // YYYY-MM-DD '1000-01-01' to '9999-12-31'
return fmt::format("{}-{:02d}-{:02d}", mt.year, mt.month, mt.day);
case MYSQL_TYPE_DATETIME: // YYYY-MM-DD hh:mm:ss '1000-01-01 00:00:00' to '9999-12-31 23:59:59'
case MYSQL_TYPE_TIMESTAMP: // YYYY-MM-DD hh:mm:ss '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC
return fmt::format("{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}", mt.year, mt.month, mt.day, mt.hour, mt.minute, mt.second);
default:
return std::string();
}
}
std::optional<std::string_view> StmtColumn::GetStrView() const
{
if (m_col.is_null)
{
return std::nullopt;
}
switch (m_col.buffer_type)
{
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return std::make_optional<std::string_view>(reinterpret_cast<const char*>(m_col.buffer.data()), m_col.length);
default:
return std::nullopt;
}
}
std::optional<std::string> StmtColumn::GetStr() const
{
if (m_col.is_null)
{
return std::nullopt;
}
switch (m_col.buffer_type)
{
case MYSQL_TYPE_TINY:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint8_t>()).c_str() : fmt::format_int(BitCast<int8_t>()).c_str();
case MYSQL_TYPE_SHORT:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint16_t>()).c_str() : fmt::format_int(BitCast<int16_t>()).c_str();
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint32_t>()).c_str() : fmt::format_int(BitCast<int32_t>()).c_str();
case MYSQL_TYPE_LONGLONG:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint64_t>()).c_str() : fmt::format_int(BitCast<int64_t>()).c_str();
case MYSQL_TYPE_FLOAT:
return fmt::format("{}", BitCast<float>());
case MYSQL_TYPE_DOUBLE:
return fmt::format("{}", BitCast<double>());
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
return FormatTime(m_col.buffer_type, BitCast<MYSQL_TIME>());
case MYSQL_TYPE_BIT:
return fmt::format_int(*Get<uint64_t>()).c_str();
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return std::make_optional<std::string>(reinterpret_cast<const char*>(m_col.buffer.data()), m_col.length);
default:
return std::nullopt;
}
}
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> StmtColumn::Get() const
{
if (m_col.is_null)
{
return std::nullopt;
}
switch (m_col.buffer_type)
{
case MYSQL_TYPE_TINY:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint8_t>()) : static_cast<T>(BitCast<int8_t>());
case MYSQL_TYPE_SHORT:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint16_t>()) : static_cast<T>(BitCast<int16_t>());
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint32_t>()) : static_cast<T>(BitCast<int32_t>());
case MYSQL_TYPE_LONGLONG:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint64_t>()) : static_cast<T>(BitCast<int64_t>());
case MYSQL_TYPE_FLOAT:
return static_cast<T>(BitCast<float>());
case MYSQL_TYPE_DOUBLE:
return static_cast<T>(BitCast<double>());
case MYSQL_TYPE_TIME: // return as total seconds
return static_cast<T>(MakeSeconds(BitCast<MYSQL_TIME>()));
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP: // return as epoch timestamp
return static_cast<T>(MakeTime(BitCast<MYSQL_TIME>()));
case MYSQL_TYPE_BIT:
return static_cast<T>(MakeBits({ m_col.buffer.data(), m_col.length }));
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return FromString<T>({ reinterpret_cast<const char*>(m_col.buffer.data()), m_col.length });
default:
return std::nullopt;
}
}
// ---------------------------------------------------------------------------
// explicit template instantiations for supported types
template void PreparedStmt::BindInput(size_t, std::string_view);
template void PreparedStmt::BindInput(size_t, std::nullptr_t);
template StmtResult PreparedStmt::Execute(const std::vector<std::string_view>&);
template StmtResult PreparedStmt::Execute(const std::vector<std::string>&);
template StmtResult PreparedStmt::Execute(const std::vector<const char*>&);
#define INSTANTIATE(T) \
template void PreparedStmt::BindInput(size_t, T); \
template StmtResult PreparedStmt::Execute(const std::vector<T>&); \
template std::optional<T> StmtRow::Get(size_t) const; \
template std::optional<T> StmtRow::Get(std::string_view) const; \
template std::optional<T> StmtColumn::Get() const;
INSTANTIATE(bool);
INSTANTIATE(int8_t);
INSTANTIATE(uint8_t);
INSTANTIATE(int16_t);
INSTANTIATE(uint16_t);
INSTANTIATE(int32_t);
INSTANTIATE(uint32_t);
INSTANTIATE(int64_t);
INSTANTIATE(uint64_t);
INSTANTIATE(float);
INSTANTIATE(double);
} // namespace mysql
+221
View File
@@ -0,0 +1,221 @@
#pragma once
#include "mysql.h"
#include <cassert>
#include <cstring>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
class Mutex;
namespace mysql
{
// support MySQL 8.0.1+ API which removed the my_bool type
#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80001
using my_bool = bool;
#endif
template <typename>
inline constexpr bool false_v = false;
namespace impl
{
struct Bind
{
std::vector<uint8_t> buffer;
unsigned long length = 0;
my_bool is_null = false;
my_bool error = false;
};
struct BindColumn : Bind
{
int index = 0;
std::string name;
bool is_unsigned = false;
enum_field_types buffer_type = {};
};
} // namespace impl
// ---------------------------------------------------------------------------
struct StmtOptions
{
// Enable buffering (storing) entire result set after executing a statement
bool buffer_results = true;
// Enable MySQL to update max_length of fields in execute result set (requires buffering)
bool use_max_length = true;
};
// ---------------------------------------------------------------------------
// Holds ownership of bound column value buffer
class StmtColumn
{
public:
int Index() const { return m_col.index; }
bool IsNull() const { return m_col.is_null; }
bool IsUnsigned() const { return m_col.is_unsigned; }
enum_field_types Type() const { return m_col.buffer_type; }
const std::string& Name() const { return m_col.name; }
// Get view of column value buffer
std::span<const uint8_t> GetBuf() const { return { m_col.buffer.data(), m_col.length }; }
// Get view of column string value. Returns nullopt if value is NULL or not a string
std::optional<std::string_view> GetStrView() const;
// Get column value as string. Returns nullopt if value is NULL or field type unsupported
std::optional<std::string> GetStr() const;
// Get column value as numeric T. Returns nullopt if value NULL or field type unsupported
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> Get() const;
private:
// uses memcpy for type punning buffer data to avoid UB with strict aliasing
template <typename T>
T BitCast() const
{
T val;
assert(sizeof(T) == m_col.length);
memcpy(&val, m_col.buffer.data(), sizeof(T));
return val;
}
friend class PreparedStmt; // access to allocate and bind buffers
friend class StmtResult; // access to resize truncated buffers
impl::BindColumn m_col;
};
// ---------------------------------------------------------------------------
// Provides a non-owning view of PreparedStmt column value buffers
// Evaluates false if it does not contain a valid row
class StmtRow
{
public:
StmtRow() = default;
StmtRow(std::span<const StmtColumn> columns) : m_columns(columns) {};
explicit operator bool() const noexcept { return !m_columns.empty(); }
int ColumnCount() const { return static_cast<int>(m_columns.size()); }
const StmtColumn* GetColumn(size_t index) const;
const StmtColumn* GetColumn(std::string_view name) const;
// Get specified column value as string
// Returns nullopt if column invalid, value is NULL, or field type unsupported
std::optional<std::string> operator[](size_t index) const;
std::optional<std::string> operator[](std::string_view name) const;
std::optional<std::string> GetStr(size_t index) const;
std::optional<std::string> GetStr(std::string_view name) const;
// Get specified column value as numeric T
// Returns nullopt if column invalid, value is NULL, or field type unsupported
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> Get(size_t index) const;
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> Get(std::string_view name) const;
auto begin() const { return m_columns.begin(); }
auto end() const { return m_columns.end(); }
private:
std::span<const StmtColumn> m_columns;
};
// ---------------------------------------------------------------------------
// Result meta data for an executed prepared statement
class StmtResult
{
public:
StmtResult() = default;
StmtResult(MYSQL_STMT* stmt, size_t columns);
int ColumnCount() const { return m_num_cols; }
uint64_t RowCount() const { return m_num_rows; }
uint64_t RowsAffected() const { return m_affected; }
uint64_t LastInsertID() const { return m_insert_id; }
private:
int m_num_cols = 0;
uint64_t m_num_rows = 0;
uint64_t m_affected = 0;
uint64_t m_insert_id = 0;
};
// ---------------------------------------------------------------------------
class PreparedStmt
{
public:
// Supported argument types for execute
using param_t = std::variant<int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
int64_t, uint64_t, float, double, bool, std::string_view, std::nullptr_t>;
PreparedStmt() = delete;
PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts = {});
const std::string& GetQuery() const { return m_query; }
StmtOptions GetOptions() const { return m_options; }
void SetOptions(StmtOptions options) { m_options = options; }
void FreeResult() { mysql_stmt_free_result(m_stmt.get()); }
// Execute the prepared statement with specified arguments
// Throws exception on error
template <typename T>
StmtResult Execute(const std::vector<T>& args);
StmtResult Execute(const std::vector<param_t>& args);
StmtResult Execute();
// Fetch the next row into column buffers (overwrites previous row values)
// Return value evaluates false if no more rows to fetch
// Throws exception on error
StmtRow Fetch();
private:
void CheckArgs(size_t argc);
StmtResult DoExecute();
void BindResults();
void FetchTruncated();
int GetResultBufferSize(const MYSQL_FIELD& field) const;
void ThrowError(const std::string& error);
std::string GetStmtError();
// bind an input value to a query parameter by index
template <typename T>
void BindInput(size_t index, T value);
void BindInput(size_t index, const char* str);
void BindInput(size_t index, const std::string& str);
struct StmtDeleter
{
Mutex* mutex = nullptr;
void operator()(MYSQL_STMT* stmt) noexcept;
};
private:
std::unique_ptr<MYSQL_STMT, StmtDeleter> m_stmt;
std::vector<MYSQL_BIND> m_params; // input binds
std::vector<MYSQL_BIND> m_results; // result binds
std::vector<impl::Bind> m_inputs; // execute buffers (addresses bound)
std::vector<StmtColumn> m_columns; // fetch buffers (addresses bound)
std::string m_query;
StmtOptions m_options = {};
bool m_need_bind = true;
Mutex* m_mutex = nullptr; // connection mutex
};
} // namespace mysql
+24 -26
View File
@@ -3494,14 +3494,13 @@ namespace RoF
ENCODE_LENGTH_EXACT(ClickTrader_Struct);
SETUP_DIRECT_ENCODE(ClickTrader_Struct, structs::ClickTrader_Struct);
eq->Code = emu->Code;
// Live actually has 200 items now, but 80 is the most our internal struct supports
for (uint32 i = 0; i < 200; i++)
eq->Code = emu->action;
for (uint32 i = 0; i < RoF::invtype::BAZAAR_SIZE; i++)
{
strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber));
eq->items[i].Unknown18 = 0;
if (i < 80) {
eq->ItemCost[i] = emu->ItemCost[i];
eq->ItemCost[i] = emu->item_cost[i];
}
else {
eq->ItemCost[i] = 0;
@@ -3515,9 +3514,9 @@ namespace RoF
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
eq->Code = emu->Code;
eq->Code = emu->action;
strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber));
eq->TraderID = emu->TraderID;
eq->TraderID = emu->entity_id;
eq->Stacksize = 0;
eq->Price = 0;
@@ -3543,13 +3542,13 @@ namespace RoF
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
OUT(Action);
OUT(Price);
OUT(TraderID);
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
OUT(ItemID);
OUT(Quantity);
OUT(AlreadySold);
OUT(action);
OUT(price);
OUT(trader_id);
memcpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
OUT(item_id);
OUT(quantity);
OUT(already_sold);
FINISH_ENCODE();
}
@@ -5041,12 +5040,11 @@ namespace RoF
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct);
MEMSET_IN(ClickTrader_Struct);
emu->Code = eq->Code;
// Live actually has 200 items now, but 80 is the most our internal struct supports
for (uint32 i = 0; i < 80; i++)
emu->action = eq->Code;
for (uint32 i = 0; i < RoF::invtype::BAZAAR_SIZE; i++)
{
emu->SerialNumber[i] = 0; // eq->SerialNumber[i];
emu->ItemCost[i] = eq->ItemCost[i];
emu->serial_number[i] = 0; // eq->SerialNumber[i];
emu->item_cost[i] = eq->ItemCost[i];
}
FINISH_DIRECT_DECODE();
@@ -5057,8 +5055,8 @@ namespace RoF
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
MEMSET_IN(Trader_ShowItems_Struct);
emu->Code = eq->Code;
emu->TraderID = eq->TraderID;
emu->action = eq->Code;
emu->entity_id = eq->TraderID;
FINISH_DIRECT_DECODE();
}
@@ -5080,12 +5078,12 @@ namespace RoF
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
MEMSET_IN(TraderBuy_Struct);
IN(Action);
IN(Price);
IN(TraderID);
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
IN(ItemID);
IN(Quantity);
IN(action);
IN(price);
IN(trader_id);
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
IN(item_id);
IN(quantity);
FINISH_DIRECT_DECODE();
}
+1080 -277
View File
File diff suppressed because it is too large Load Diff
+81 -49
View File
@@ -1,5 +1,5 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
@@ -37,7 +37,7 @@ namespace RoF2
const bool AllowOverLevelEquipment = true;
const bool AllowEmptyBagInBag = true;
const bool AllowEmptyBagInBag = true;
const bool AllowClickCastFromBag = true;
} /*inventory*/
@@ -77,38 +77,38 @@ namespace RoF2
} // namespace enum_
using namespace enum_;
const int16 POSSESSIONS_SIZE = 34;
const int16 BANK_SIZE = 24;
const int16 SHARED_BANK_SIZE = 2;
const int16 TRADE_SIZE = 8;
const int16 WORLD_SIZE = 10;
const int16 LIMBO_SIZE = 36;
const int16 TRIBUTE_SIZE = 5;
const int16 TROPHY_TRIBUTE_SIZE = 0;//unknown
const int16 GUILD_TRIBUTE_SIZE = 2;//unverified
const int16 MERCHANT_SIZE = 200;
const int16 DELETED_SIZE = 0;//unknown - "Recovery Tab"
const int16 CORPSE_SIZE = POSSESSIONS_SIZE;
const int16 BAZAAR_SIZE = 200;
const int16 INSPECT_SIZE = 23;
const int16 REAL_ESTATE_SIZE = 0;//unknown
const int16 VIEW_MOD_PC_SIZE = POSSESSIONS_SIZE;
const int16 VIEW_MOD_BANK_SIZE = BANK_SIZE;
const int16 POSSESSIONS_SIZE = 34;
const int16 BANK_SIZE = 24;
const int16 SHARED_BANK_SIZE = 2;
const int16 TRADE_SIZE = 8;
const int16 WORLD_SIZE = 10;
const int16 LIMBO_SIZE = 36;
const int16 TRIBUTE_SIZE = 5;
const int16 TROPHY_TRIBUTE_SIZE = 0;//unknown
const int16 GUILD_TRIBUTE_SIZE = 2;//unverified
const int16 MERCHANT_SIZE = 500;
const int16 DELETED_SIZE = 0;//unknown - "Recovery Tab"
const int16 CORPSE_SIZE = POSSESSIONS_SIZE;
const int16 BAZAAR_SIZE = 200;
const int16 INSPECT_SIZE = 23;
const int16 REAL_ESTATE_SIZE = 0;//unknown
const int16 VIEW_MOD_PC_SIZE = POSSESSIONS_SIZE;
const int16 VIEW_MOD_BANK_SIZE = BANK_SIZE;
const int16 VIEW_MOD_SHARED_BANK_SIZE = SHARED_BANK_SIZE;
const int16 VIEW_MOD_LIMBO_SIZE = LIMBO_SIZE;
const int16 ALT_STORAGE_SIZE = 0;//unknown - "Shroud Bank"
const int16 ARCHIVED_SIZE = 0;//unknown
const int16 MAIL_SIZE = 0;//unknown
const int16 VIEW_MOD_LIMBO_SIZE = LIMBO_SIZE;
const int16 ALT_STORAGE_SIZE = 0;//unknown - "Shroud Bank"
const int16 ARCHIVED_SIZE = 0;//unknown
const int16 MAIL_SIZE = 0;//unknown
const int16 GUILD_TROPHY_TRIBUTE_SIZE = 0;//unknown
const int16 KRONO_SIZE = 0;//unknown
const int16 OTHER_SIZE = 0;//unknown
const int16 KRONO_SIZE = 0;//unknown
const int16 OTHER_SIZE = 0;//unknown
const int16 TRADE_NPC_SIZE = 4; // defined by implication
const int16 TYPE_INVALID = IINVALID;
const int16 TYPE_BEGIN = typePossessions;
const int16 TYPE_END = typeOther;
const int16 TYPE_COUNT = (TYPE_END - TYPE_BEGIN) + 1;
const int16 TYPE_BEGIN = typePossessions;
const int16 TYPE_END = typeOther;
const int16 TYPE_COUNT = (TYPE_END - TYPE_BEGIN) + 1;
int16 GetInvTypeSize(int16 inv_type);
const char* GetInvTypeName(int16 inv_type);
@@ -162,33 +162,54 @@ namespace RoF2
} // namespace enum_
using namespace enum_;
const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL;
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL;
const int16 BANK_BEGIN = 2000;
const int16 BANK_END = (BANK_BEGIN + invtype::BANK_SIZE) - 1;
const int16 SHARED_BANK_BEGIN = 2500;
const int16 SHARED_BANK_END = (SHARED_BANK_BEGIN + invtype::SHARED_BANK_SIZE) - 1;
const int16 TRADE_BEGIN = 3000;
const int16 TRADE_END = (TRADE_BEGIN + invtype::TRADE_SIZE) - 1;
const int16 TRADE_NPC_END = (TRADE_BEGIN + invtype::TRADE_NPC_SIZE) - 1; // defined by implication
const int16 WORLD_BEGIN = 4000;
const int16 WORLD_END = (WORLD_BEGIN + invtype::WORLD_SIZE) - 1;
const int16 TRIBUTE_BEGIN = 400;
const int16 TRIBUTE_END = (TRIBUTE_BEGIN + invtype::TRIBUTE_SIZE) - 1;
const int16 GUILD_TRIBUTE_BEGIN = 450;
const int16 GUILD_TRIBUTE_END = (GUILD_TRIBUTE_BEGIN + invtype::GUILD_TRIBUTE_SIZE) - 1;
const int16 POSSESSIONS_BEGIN = slotCharm;
const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
const int16 EQUIPMENT_BEGIN = slotCharm;
const int16 EQUIPMENT_END = slotAmmo;
const int16 EQUIPMENT_END = slotAmmo;
const int16 EQUIPMENT_COUNT = (EQUIPMENT_END - EQUIPMENT_BEGIN) + 1;
const int16 GENERAL_BEGIN = slotGeneral1;
const int16 GENERAL_END = slotGeneral10;
const int16 GENERAL_END = slotGeneral10;
const int16 GENERAL_COUNT = (GENERAL_END - GENERAL_BEGIN) + 1;
const int16 BONUS_BEGIN = invslot::slotCharm;
const int16 BONUS_STAT_END = invslot::slotPowerSource;
const int16 BONUS_BEGIN = invslot::slotCharm;
const int16 BONUS_STAT_END = invslot::slotPowerSource;
const int16 BONUS_SKILL_END = invslot::slotAmmo;
const int16 CORPSE_BEGIN = invslot::slotGeneral1;
const int16 CORPSE_END = invslot::slotGeneral1 + invslot::slotCursor;
const int16 CORPSE_END = invslot::slotGeneral1 + invslot::slotCursor;
const uint64 EQUIPMENT_BITMASK = 0x00000000007FFFFF;
const uint64 GENERAL_BITMASK = 0x00000001FF800000;
const uint64 CURSOR_BITMASK = 0x0000000200000000;
const uint64 EQUIPMENT_BITMASK = 0x00000000007FFFFF;
const uint64 GENERAL_BITMASK = 0x00000001FF800000;
const uint64 CURSOR_BITMASK = 0x0000000200000000;
const uint64 POSSESSIONS_BITMASK = (EQUIPMENT_BITMASK | GENERAL_BITMASK | CURSOR_BITMASK); // based on 34-slot count (RoF+)
const uint64 CORPSE_BITMASK = (GENERAL_BITMASK | CURSOR_BITMASK | (EQUIPMENT_BITMASK << 34)); // based on 34-slot count (RoF+)
const uint64 CORPSE_BITMASK = (GENERAL_BITMASK | CURSOR_BITMASK | (EQUIPMENT_BITMASK << 34)); // based on 34-slot count (RoF+)
const char* GetInvPossessionsSlotName(int16 inv_slot);
@@ -199,10 +220,21 @@ namespace RoF2
namespace invbag {
inline EQ::versions::ClientVersion GetInvBagRef() { return EQ::versions::ClientVersion::RoF2; }
const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL;
const int16 SLOT_END = 9; //254;
const int16 SLOT_COUNT = 10; //255; // server Size will be 255..unsure what actual client is (test)
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL;
const int16 SLOT_COUNT = 200;
const int16 SLOT_END = SLOT_COUNT - 1;
const int16 GENERAL_BAGS_BEGIN = 251;
const int16 CURSOR_BAG_BEGIN = 351;
const int16 BANK_BAGS_BEGIN = 2031;
const int16 SHARED_BANK_BAGS_BEGIN = 2531;
const int16 TRADE_BAGS_BEGIN = 3031;
const char* GetInvBagIndexName(int16 bag_index);
@@ -212,9 +244,9 @@ namespace RoF2
inline EQ::versions::ClientVersion GetInvAugRef() { return EQ::versions::ClientVersion::RoF2; }
const int16 SOCKET_INVALID = IINVALID;
const int16 SOCKET_BEGIN = INULL;
const int16 SOCKET_END = 5;
const int16 SOCKET_COUNT = 6;
const int16 SOCKET_BEGIN = INULL;
const int16 SOCKET_END = 5;
const int16 SOCKET_COUNT = 6;
const char* GetInvAugIndexName(int16 aug_index);
@@ -291,7 +323,7 @@ namespace RoF2
namespace spells {
inline EQ::versions::ClientVersion GetSkillsRef() { return EQ::versions::ClientVersion::RoF2; }
enum class CastingSlot : uint32 {
Gem1 = 0,
Gem2 = 1,
@@ -314,7 +346,7 @@ namespace RoF2
const int SPELL_ID_MAX = 45000;
const int SPELLBOOK_SIZE = 720;
const int SPELL_GEM_COUNT = static_cast<uint32>(CastingSlot::MaxGems);
const int LONG_BUFFS = 42;
const int SHORT_BUFFS = 20;
const int DISC_BUFFS = 1;
+4
View File
@@ -43,10 +43,12 @@ E(OP_ApplyPoison)
E(OP_AugmentInfo)
E(OP_Barter)
E(OP_BazaarSearch)
E(OP_BecomeTrader)
E(OP_BeginCast)
E(OP_BlockedBuffs)
E(OP_Buff)
E(OP_BuffCreate)
E(OP_BuyerItems)
E(OP_CancelTrade)
E(OP_CastSpell)
E(OP_ChannelMessage)
@@ -148,11 +150,13 @@ D(OP_Animation)
D(OP_ApplyPoison)
D(OP_AugmentInfo)
D(OP_AugmentItem)
D(OP_Barter)
D(OP_BazaarSearch)
D(OP_BlockedBuffs)
D(OP_BookButton)
D(OP_Buff)
D(OP_BuffRemoveRequest)
D(OP_BuyerItems)
D(OP_CastSpell)
D(OP_ChannelMessage)
D(OP_CharacterCreate)
+271 -121
View File
@@ -354,15 +354,15 @@ struct Spawn_Struct_Bitfields
/*29*/ unsigned showname:1;
/*30*/ unsigned idleanimationsoff:1; // what we called statue?
/*31*/ unsigned untargetable:1; // bClickThrough
/* do these later
32 unsigned buyer:1;
33 unsigned offline:1;
34 unsigned interactiveobject:1;
35 unsigned flung:1; // hmm this vfunc appears to do stuff with leve and flung variables
36 unsigned title:1;
37 unsigned suffix:1;
38 unsigned padding1:1;
39 unsigned padding2:1;
// byte 5
/*32 unsigned buyer:1;
/*33 unsigned offline:1;
/*34 unsigned interactiveobject:1;
/*35 unsigned flung:1; // hmm this vfunc appears to do stuff with leve and flung variables
/*36 unsigned title:1;
/*37 unsigned suffix:1;
/*38 unsigned padding1:1;
/*39 unsigned padding2:1;
40 unsinged padding3:1;
*/
/*
@@ -3106,28 +3106,163 @@ struct EnvDamage2_Struct {
};
//Bazaar Stuff
enum RoF2BazaarTraderBuyerActions {
Zero = 0,
BeginTraderMode = 1,
EndTraderMode = 2,
PriceUpdate = 3,
EndTransaction = 4,
BazaarSearch = 7,
WelcomeMessage = 9,
BuyTraderItem = 10,
ListTraderItems = 11,
BazaarInspect = 18,
ClickTrader = 28,
ItemMove = 19,
ReconcileItems = 20
};
enum RoF2BuyerActions {
BuyerSearchResults = 0x00,
BuyerBuyLine = 0x06,
BuyerModifyBuyLine = 0x07,
BuyerRemoveItem = 0x08,
BuyerSellItem = 0x09,
BuyerBuyItem = 0x0a,
BuyerInspectBegin = 0x0b,
BuyerInspectEnd = 0x0c,
BuyerAppearance = 0x0d,
BuyerSendBuyLine = 0x0e,
BuyerItemInspect = 0x0f,
BuyerBrowsingBuyLine = 0x10,
BarterWelcomeMessage = 0x11,
BuyerWelcomeMessage = 0x13,
BuyerGreeting = 0x14,
BuyerInventoryFull = 0x16
};
struct BarterItemSearchLinkRequest_Struct {
uint32 action;
uint32 unknown_004;
uint32 seller_id;
uint32 buyer_id;
uint32 unknown_016;
uint32 slot_id; // 0xffffffff main buy line 0x0 trade_item_1, 0x1 trade_item_2
uint32 item_id;
uint32 unknown_028;
};
struct BuyerWelcomeMessageUpdate_Struct {
uint32 action;
char unknown_004[64];
uint32 unknown_068;
char welcome_message[256];
};
struct Buyer_SetAppearance_Struct {
uint32 action;
uint32 entity_id;
char unknown[64];
uint32 enabled;
};
struct BuyerRemoveItem_Struct {
uint32 action;
uint32 unknown004;
uint32 slot_id;
uint32 toggle;
};
struct BuyerLineSellItem_Struct {
uint32 action;
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
uint32 unknown008;
uint32 buyer_entity_id;
uint32 seller_entity_id;
char unknown[15];
uint32 slot;
uint8 enabled;
uint32 item_id;
char item_name[64];
uint32 item_icon;
uint32 item_quantity;
uint8 item_toggle;
uint32 item_cost;
uint32 no_trade_items;
BuyerLineTradeItems_Struct trade_items[10];
char unknown2[13];
uint32 seller_quantity;
};
struct BuyerLineItemsSearch_Struct {
uint32 slot;
uint8 enabled;
uint32 item_id;
char item_name[64];
uint32 item_icon;
uint32 item_quantity;
uint8 item_toggle;
uint32 item_cost;
uint32 buyer_id;
BuyerLineTradeItems_Struct trade_items[MAX_BUYER_COMPENSATION_ITEMS];
};
struct BuyerLineSearch_Struct {
uint32 action;
uint32 no_items;
std::vector<BuyerLineItemsSearch_Struct> buy_line;
};
struct BuyerStart_Struct {
uint32 action;
uint16 no_buyer_lines;
uint32 slot;
uint8 enabled;
uint32 item_id;
char item_name[1]; // vary length
uint32 item_icon;
uint32 item_quantity;
uint8 toggle;
uint32 item_cost;
uint32 no_trade_items;
BuyerLineTradeItems_Struct trade_items[1]; // size is actually no_trade_items. If 0, then this is not in packet
char unknown[13];
};
struct BuyerItemSearchResultEntry_Struct {
char item_name[64];
uint32 item_id;
uint32 item_icon;
uint32 unknown_072;
};
struct BuyerItemSearchResults_Struct {
uint32 action;
uint32 result_count;
BuyerItemSearchResultEntry_Struct results[];
};
enum {
BazaarTrader_StartTraderMode = 1,
BazaarTrader_EndTraderMode = 2,
BazaarTrader_UpdatePrice = 3,
BazaarTrader_EndTransaction = 4,
BazaarSearchResults = 7,
BazaarWelcome = 9,
BazaarBuyItem = 10,
BazaarTrader_ShowItems = 11,
BazaarSearchDone = 12,
BazaarTrader_StartTraderMode = 1,
BazaarTrader_EndTraderMode = 2,
BazaarTrader_UpdatePrice = 3,
BazaarTrader_EndTransaction = 4,
BazaarSearchResults = 7,
BazaarWelcome = 9,
BazaarBuyItem = 10,
BazaarTrader_ShowItems = 11,
BazaarSearchDone = 12,
BazaarTrader_CustomerBrowsing = 13,
BazaarInspectItem = 18,
BazaarSearchDone2 = 19,
BazaarInspectItem = 18,
BazaarSearchDone2 = 19,
BazaarTrader_StartTraderMode2 = 22
};
enum {
BazaarPriceChange_Fail = 0,
BazaarPriceChange_Fail = 0,
BazaarPriceChange_UpdatePrice = 1,
BazaarPriceChange_RemoveItem = 2,
BazaarPriceChange_AddItem = 3
BazaarPriceChange_RemoveItem = 2,
BazaarPriceChange_AddItem = 3
};
struct BazaarWindowStart_Struct {
@@ -3136,34 +3271,51 @@ struct BazaarWindowStart_Struct {
uint16 Unknown002;
};
struct BazaarDeliveryCost_Struct {
uint32 action;
uint32 voucher_delivery_cost;
float parcel_deliver_cost; //percentage of item cost
uint32 unknown_010;
};
struct BazaarWelcome_Struct {
uint32 Code;
uint32 EntityID;
uint32 Traders;
uint32 Items;
uint32 Traders2;
uint32 Items2;
uint32 action;
uint32 unknown_004;
uint32 num_of_traders;
uint32 num_of_items;
};
struct BazaarSearch_Struct {
BazaarWindowStart_Struct Beginning;
uint32 TraderID;
uint32 Class_;
uint32 Race;
uint32 ItemStat;
uint32 Slot;
uint32 Type;
char Name[64];
uint32 MinPrice;
uint32 MaxPrice;
uint32 Minlevel;
uint32 MaxLlevel;
/*000*/ uint32 action;
/*004*/ uint8 search_scope;//1 all traders 0 local traders
/*005*/ uint8 unknown_005{0};
/*006*/ uint16 unknown_006{0};
/*008*/ uint32 unknown_008{0};
/*012*/ uint32 unknown_012{0};
/*016*/ uint32 trader_id;
/*020*/ uint32 _class;
/*024*/ uint32 race;
/*028*/ uint32 item_stat;
/*032*/ uint32 slot;
/*036*/ uint32 type;
/*040*/ char item_name[64];
/*104*/ uint32 min_cost;
/*108*/ uint32 max_cost;
/*112*/ uint32 min_level;
/*116*/ uint32 max_level;
/*120*/ uint32 max_results;
/*124*/ uint32 prestige;
/*128*/ uint32 augment;
};
struct BazaarInspect_Struct{
uint32 ItemID;
uint32 Unknown004;
char Name[64];
struct BazaarInspect_Struct {
uint32 action;
uint32 unknown_004;
uint32 trader_id;
char serial_number[17];
char unknown_029[3];
uint32 item_id;
uint32 unknown_036;
};
struct NewBazaarInspect_Struct {
@@ -3184,18 +3336,23 @@ struct BazaarReturnDone_Struct{
uint32 Unknown016;
};
struct BazaarSearchResults_Struct {
/*000*/ BazaarWindowStart_Struct Beginning;
/*004*/ uint32 SellerID;
/*008*/ char SellerName[64];
/*072*/ uint32 NumItems;
/*076*/ uint32 ItemID;
/*080*/ uint32 SerialNumber;
/*084*/ uint32 Unknown084;
/*088*/ char ItemName[64];
/*152*/ uint32 Cost;
/*156*/ uint32 ItemStat;
/*160*/
struct BazaarSearchDetails_Struct { //24+name+17
/*014*/ uint32 trader_id;
/*018*/ char serial_num[17];
/*022*/ uint32 cost;
/*026*/ uint32 quanity;
/*030*/ uint32 id;
/*034*/ uint32 icon;
/*038*/ char name[1];
/*039*/ uint32 stat;
};
struct BazaarSearchResults_Struct { //14
/*000*/ uint32 unknown000;
/*004*/ uint16 zone_id;
/*006*/ uint32 entity_id;
/*010*/ uint32 num_items;
/*014*/ BazaarSearchDetails_Struct items[];
};
struct ServerSideFilters_Struct {
@@ -3398,21 +3555,26 @@ struct WhoAllPlayerPart4 {
};
struct TraderItemSerial_Struct {
char SerialNumber[17];
uint8 Unknown18;
char serial_number[17];
uint8 unknown_018;
void operator=(uint32 a) {
auto _tmp = fmt::format("{:016}", a);
strn0cpy(this->serial_number, _tmp.c_str(), sizeof(this->serial_number));
}
};
struct Trader_Struct {
/*0000*/ uint32 Code;
/*0004*/ TraderItemSerial_Struct items[200];
/*3604*/ uint32 ItemCost[200];
struct BeginTrader_Struct {
/*0000*/ uint32 action;
/*0004*/ TraderItemSerial_Struct items[200];
/*3604*/ uint32 item_cost[200];
/*4404*/
};
struct ClickTrader_Struct {
/*0000*/ uint32 Code;
/*0004*/ TraderItemSerial_Struct items[200];
/*3604*/ uint32 ItemCost[200];
/*0000*/ uint32 action;
/*0004*/ TraderItemSerial_Struct items[200];
/*3604*/ uint32 item_cost[200];
/*4404*/
};
@@ -3421,67 +3583,55 @@ struct GetItems_Struct {
};
struct BecomeTrader_Struct {
uint32 id;
uint32 code;
uint32 entity_id;
uint32 action;
};
struct BazaarWindowRemoveTrader_Struct {
uint32 action;
uint32 trader_id;
};
struct TraderPriceUpdate_Struct {
uint32 action;
char serial_number[17];
char unknown_021[3];
uint32 unknown_024;
uint32 new_price;
};
struct Trader_ShowItems_Struct {
/*000*/ uint32 Code;
/*004*/ uint16 TraderID;
/*008*/ uint32 Unknown08;
/*012*/
};
struct Trader_ShowItems_Struct_WIP {
/*000*/ uint32 Code;
/*004*/ char SerialNumber[17];
/*021*/ uint8 Unknown21;
/*022*/ uint16 TraderID;
/*026*/ uint32 Stacksize;
/*030*/ uint32 Price;
/*032*/
/*000*/ uint32 action;
/*004*/ uint32 entity_id;
/*008*/ uint32 unknown_008;
/*012*/
};
struct TraderStatus_Struct {
/*000*/ uint32 Code;
/*004*/ uint32 Uknown04;
/*008*/ uint32 Uknown08;
/*000*/ uint32 action;
/*004*/ uint32 sub_action;
/*008*/ uint32 uknown_008;
/*012*/
};
struct TraderBuy_Struct {
/*000*/ uint32 Action;
/*004*/ uint32 Unknown004;
/*008*/ uint32 Unknown008;
/*012*/ uint32 Unknown012;
/*016*/ uint32 TraderID;
/*020*/ char BuyerName[64];
/*084*/ char SellerName[64];
/*148*/ char Unknown148[32];
/*180*/ char ItemName[64];
/*244*/ char SerialNumber[16];
/*260*/ uint32 Unknown076;
/*264*/ uint32 ItemID;
/*268*/ uint32 Price;
/*272*/ uint32 AlreadySold;
/*276*/ uint32 Unknown276;
/*280*/ uint32 Quantity;
/*284*/
};
struct TraderBuy_Struct_OLD {
/*000*/ uint32 Action;
/*004*/ uint32 Unknown004;
/*008*/ uint32 Price;
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
/*016*/ uint32 TraderID;
/*020*/ char ItemName[64];
/*084*/ uint32 Unknown076;
/*088*/ uint32 ItemID;
/*092*/ uint32 AlreadySold;
/*096*/ uint32 Quantity;
/*100*/ uint32 Unknown092;
/*104*/
/*000*/ uint32 action;
/*004*/ uint32 method;
/*008*/ uint32 sub_action;
/*012*/ uint32 unknown_012;
/*016*/ uint32 trader_id;
/*020*/ char buyer_name[64];
/*084*/ char seller_name[64];
/*148*/ char unknown_148[32];
/*180*/ char item_name[64];
/*244*/ char serial_number[17];
/*261*/ char unknown_261[3];
/*264*/ uint32 item_id;
/*268*/ uint32 price;
/*272*/ uint32 already_sold;
/*276*/ uint32 unknown_276;
/*280*/ uint32 quantity;
/*284*/
};
struct TraderItemUpdate_Struct{
@@ -3502,15 +3652,15 @@ struct MoneyUpdate_Struct{
struct TraderDelItem_Struct{
/*000*/ uint32 Unknown000;
/*004*/ uint32 TraderID;
/*008*/ char SerialNumber[16];
/*008*/ char SerialNumber[17];
/*024*/ uint32 Unknown012;
/*028*/
};
struct TraderClick_Struct{
/*000*/ uint32 Code;
/*004*/ uint32 TraderID;
/*008*/ uint32 Approval;
/*000*/ uint32 action;
/*004*/ uint32 trader_id;
/*008*/ uint32 unknown_008;
/*012*/
};
+11 -11
View File
@@ -3376,17 +3376,17 @@ struct TraderStatus_Struct {
};
struct TraderBuy_Struct {
/*000*/ uint32 Action;
/*004*/ uint32 Unknown004;
/*008*/ uint32 Price;
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
/*016*/ uint32 TraderID;
/*020*/ char ItemName[64];
/*084*/ uint32 Unknown076;
/*088*/ uint32 ItemID;
/*092*/ uint32 AlreadySold;
/*096*/ uint32 Quantity;
/*100*/ uint32 Unknown092;
/*000*/ uint32 action;
/*004*/ uint32 unknown_004;
/*008*/ uint32 price;
/*012*/ uint32 unknown_008; // Probably high order bits of a 64 bit price.
/*016*/ uint32 trader_id;
/*020*/ char item_name[64];
/*084*/ uint32 unknown_076;
/*088*/ uint32 item_id;
/*092*/ uint32 already_sold;
/*096*/ uint32 quantity;
/*100*/ uint32 unknown_092;
/*104*/
};
+13 -13
View File
@@ -2286,13 +2286,13 @@ namespace SoD
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
OUT(Action);
OUT(Price);
OUT(TraderID);
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
OUT(ItemID);
OUT(Quantity);
OUT(AlreadySold);
OUT(action);
OUT(price);
OUT(trader_id);
memcpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
OUT(item_id);
OUT(quantity);
OUT(already_sold);
FINISH_ENCODE();
}
@@ -3517,12 +3517,12 @@ namespace SoD
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
MEMSET_IN(TraderBuy_Struct);
IN(Action);
IN(Price);
IN(TraderID);
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
IN(ItemID);
IN(Quantity);
IN(action);
IN(price);
IN(trader_id);
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
IN(item_id);
IN(quantity);
FINISH_DIRECT_DECODE();
}
+12 -11
View File
@@ -2879,20 +2879,21 @@ struct Trader_ShowItems_Struct{
};
struct TraderBuy_Struct {
/*000*/ uint32 Action;
/*004*/ uint32 Unknown004;
/*008*/ uint32 Price;
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
/*016*/ uint32 TraderID;
/*020*/ char ItemName[64];
/*084*/ uint32 Unknown076;
/*088*/ uint32 ItemID;
/*092*/ uint32 AlreadySold;
/*096*/ uint32 Quantity;
/*100*/ uint32 Unknown092;
/*000*/ uint32 action;
/*004*/ uint32 unknown_004;
/*008*/ uint32 price;
/*012*/ uint32 unknown_008; // Probably high order bits of a 64 bit price.
/*016*/ uint32 trader_id;
/*020*/ char item_name[64];
/*084*/ uint32 unknown_076;
/*088*/ uint32 item_id;
/*092*/ uint32 already_sold;
/*096*/ uint32 quantity;
/*100*/ uint32 unknown_092;
/*104*/
};
struct TraderItemUpdate_Struct{
uint32 unknown0;
uint32 traderid;
+16 -16
View File
@@ -270,8 +270,8 @@ namespace SoF
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
OUT(ID);
OUT(Code);
OUT(trader_id);
OUT(action);
FINISH_ENCODE();
}
@@ -1902,13 +1902,13 @@ namespace SoF
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
OUT(Action);
OUT(Price);
OUT(TraderID);
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
OUT(ItemID);
OUT(Quantity);
OUT(AlreadySold);
OUT(action);
OUT(price);
OUT(trader_id);
memcpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
OUT(item_id);
OUT(quantity);
OUT(already_sold);
FINISH_ENCODE();
}
@@ -2349,7 +2349,7 @@ namespace SoF
DECODE_LENGTH_EXACT(structs::BugReport_Struct);
SETUP_DIRECT_DECODE(BugReport_Struct, structs::BugReport_Struct);
emu->category_id = EQ::bug::CategoryNameToCategoryID(eq->category_name);
emu->category_id = Bug::GetID(eq->category_name);
memcpy(emu->category_name, eq, sizeof(structs::BugReport_Struct));
FINISH_DIRECT_DECODE();
@@ -2908,12 +2908,12 @@ namespace SoF
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
MEMSET_IN(TraderBuy_Struct);
IN(Action);
IN(Price);
IN(TraderID);
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
IN(ItemID);
IN(Quantity);
IN(action);
IN(price);
IN(trader_id);
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
IN(item_id);
IN(quantity);
FINISH_DIRECT_DECODE();
}
+11 -11
View File
@@ -2771,8 +2771,8 @@ struct GetItems_Struct{
};
struct BecomeTrader_Struct{
uint32 ID;
uint32 Code;
uint32 trader_id;
uint32 action;
};
struct Trader_ShowItems_Struct{
@@ -2782,15 +2782,15 @@ struct Trader_ShowItems_Struct{
};
struct TraderBuy_Struct {
/*000*/ uint32 Action;
/*004*/ uint32 Price;
/*008*/ uint32 TraderID;
/*012*/ char ItemName[64];
/*076*/ uint32 Unknown076;
/*080*/ uint32 ItemID;
/*084*/ uint32 AlreadySold;
/*088*/ uint32 Quantity;
/*092*/ uint32 Unknown092;
/*000*/ uint32 action;
/*004*/ uint32 price;
/*008*/ uint32 trader_id;
/*012*/ char item_name[64];
/*076*/ uint32 unknown_076;
/*080*/ uint32 item_id;
/*084*/ uint32 already_sold;
/*088*/ uint32 quantity;
/*092*/ uint32 unknown_092;
};
struct TraderItemUpdate_Struct{
+3 -3
View File
@@ -60,7 +60,7 @@
eq_struct *eq = (eq_struct *) __packet->pBuffer; \
#define ALLOC_LEN_ENCODE(len) \
__packet->pBuffer = new unsigned char[len]; \
__packet->pBuffer = new unsigned char[len] {}; \
__packet->size = len; \
memset(__packet->pBuffer, 0, len); \
@@ -124,7 +124,7 @@
#define SETUP_DIRECT_DECODE(emu_struct, eq_struct) \
unsigned char *__eq_buffer = __packet->pBuffer; \
__packet->size = sizeof(emu_struct); \
__packet->pBuffer = new unsigned char[__packet->size]; \
__packet->pBuffer = new unsigned char[__packet->size] {}; \
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
eq_struct *eq = (eq_struct *) __eq_buffer;
@@ -133,7 +133,7 @@
eq_struct* in = (eq_struct*)__packet->pBuffer; \
auto size = strlen(in->var_field); \
__packet->size = sizeof(emu_struct) + size + 1; \
__packet->pBuffer = new unsigned char[__packet->size]; \
__packet->pBuffer = new unsigned char[__packet->size] {}; \
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
eq_struct *eq = (eq_struct *) __eq_buffer;
+399 -70
View File
@@ -32,6 +32,7 @@
#include "../strings.h"
#include "../item_instance.h"
#include "titanium_structs.h"
#include "../rulesys.h"
#include "../path_manager.h"
#include "../raid.h"
#include "../guilds.h"
@@ -197,64 +198,135 @@ namespace Titanium
ENCODE(OP_BazaarSearch)
{
if (((*p)->size == sizeof(BazaarReturnDone_Struct)) || ((*p)->size == sizeof(BazaarWelcome_Struct))) {
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
return;
}
//consume the packet
EQApplicationPacket *in = *p;
*p = nullptr;
//store away the emu struct
unsigned char *__emu_buffer = in->pBuffer;
BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer;
uint32 action = *(uint32 *)in->pBuffer;
//determine and verify length
int entrycount = in->size / sizeof(BazaarSearchResults_Struct);
if (entrycount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0) {
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d",
opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
delete in;
return;
switch (action) {
case BazaarSearch: {
LogTrading(
"Encode OP_BazaarSearch(Ti) BazaarSearch action <green>[{}]",
action
);
std::vector<BazaarSearchResultsFromDB_Struct> results {};
auto bsms = (BazaarSearchMessaging_Struct *)in->pBuffer;
EQ::Util::MemoryStreamReader ss(
reinterpret_cast<char *>(bsms->payload),
in->size - sizeof(BazaarSearchMessaging_Struct)
);
cereal::BinaryInputArchive ar(ss);
ar(results);
auto size = results.size() * sizeof(structs::BazaarSearchResults_Struct);
auto buffer = new uchar[size];
uchar *bufptr = buffer;
memset(buffer, 0, size);
for (auto row = results.begin(); row != results.end(); ++row) {
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, structs::TiBazaarTraderBuyerActions::BazaarSearch);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->trader_entity_id);
bufptr += 4;
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
bufptr += 4;
if (row->stackable) {
strn0cpy(
reinterpret_cast<char *>(bufptr),
fmt::format("{}({})", row->item_name.c_str(), row->charges).c_str(),
64
);
}
else {
strn0cpy(
reinterpret_cast<char *>(bufptr),
fmt::format("{}({})", row->item_name.c_str(), row->count).c_str(),
64
);
}
bufptr += 64;
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->cost);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->item_stat);
}
auto outapp = new EQApplicationPacket(OP_BazaarSearch, size);
memcpy(outapp->pBuffer, buffer, size);
dest->FastQueuePacket(&outapp);
safe_delete(outapp);
safe_delete_array(buffer);
safe_delete(in);
break;
}
case BazaarInspect:
case WelcomeMessage: {
LogTrading(
"Encode OP_BazaarSearch(Ti) BazaarInspect/WelcomeMessage action <green>[{}]",
action
);
dest->FastQueuePacket(&in, ack_req);
break;
}
default: {
LogTrading(
"Encode OP_BazaarSearch(Ti) unhandled action <red>[{}]",
action
);
dest->FastQueuePacket(&in, ack_req);
}
}
//make the EQ struct.
in->size = sizeof(structs::BazaarSearchResults_Struct)*entrycount;
in->pBuffer = new unsigned char[in->size];
structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *) in->pBuffer;
//zero out the packet. We could avoid this memset by setting all fields (including unknowns) in the loop.
memset(in->pBuffer, 0, in->size);
for (int i = 0; i < entrycount; i++, eq++, emu++) {
eq->Beginning.Action = emu->Beginning.Action;
eq->Beginning.Unknown001 = emu->Beginning.Unknown001;
eq->Beginning.Unknown002 = emu->Beginning.Unknown002;
eq->NumItems = emu->NumItems;
eq->SerialNumber = emu->SerialNumber;
eq->SellerID = emu->SellerID;
eq->Cost = emu->Cost;
eq->ItemStat = emu->ItemStat;
strcpy(eq->ItemName, emu->ItemName);
}
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_BecomeTrader)
{
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
uint32 action = *(uint32 *)(*p)->pBuffer;
OUT(ID);
OUT(Code);
FINISH_ENCODE();
switch (action)
{
case TraderOff:
{
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
LogTrading(
"Encode OP_BecomeTrader(Ti) TraderOff action <green>[{}] entity_id <green>[{}] trader_name "
"<green>[{}]",
emu->action,
emu->entity_id,
emu->trader_name
);
eq->action = structs::TiBazaarTraderBuyerActions::Zero;
eq->entity_id = emu->entity_id;
FINISH_ENCODE();
break;
}
case TraderOn:
{
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
LogTrading(
"Encode OP_BecomeTrader(Ti) TraderOn action <green>[{}] entity_id <green>[{}] trader_name "
"<green>[{}]",
emu->action,
emu->entity_id,
emu->trader_name
);
eq->action = structs::TiBazaarTraderBuyerActions::BeginTraderMode;
eq->entity_id = emu->entity_id;
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
FINISH_ENCODE();
break;
}
default:
{
LogTrading(
"Encode OP_BecomeTrader(Ti) unhandled action <red>[{}] Sending packet as is.",
action
);
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
}
}
}
ENCODE(OP_Buff)
@@ -734,7 +806,7 @@ namespace Titanium
break;
}
}
break;
break;
}
case AppearanceType::GuildShow: {
FAIL_ENCODE();
@@ -2010,32 +2082,170 @@ namespace Titanium
ENCODE(OP_Trader)
{
if ((*p)->size != sizeof(TraderBuy_Struct)) {
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
return;
}
auto action = *(uint32 *) (*p)->pBuffer;
ENCODE_FORWARD(OP_TraderBuy);
switch (action) {
case TraderOn: {
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
LogTrading(
"Encode OP_Trader BeginTraderMode action <green>[{}]",
action
);
eq->action = structs::TiBazaarTraderBuyerActions::BeginTraderMode;
OUT(entity_id);
FINISH_ENCODE();
break;
}
case TraderOff: {
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
LogTrading(
"Encode OP_Trader EndTraderMode action <green>[{}]",
action
);
eq->action = structs::TiBazaarTraderBuyerActions::EndTraderMode;
OUT(entity_id);
FINISH_ENCODE();
break;
}
case ListTraderItems: {
ENCODE_LENGTH_EXACT(Trader_Struct);
SETUP_DIRECT_ENCODE(Trader_Struct, structs::Trader_Struct);
LogTrading(
"Encode OP_Trader ListTraderItems action <green>[{}]",
action
);
eq->action = structs::TiBazaarTraderBuyerActions::ListTraderItems;
std::copy_n(emu->items, UF::invtype::BAZAAR_SIZE, eq->item_id);
std::copy_n(emu->item_cost, UF::invtype::BAZAAR_SIZE, eq->item_cost);
FINISH_ENCODE();
break;
}
case BuyTraderItem: {
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
LogTrading(
"Encode OP_Trader item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
eq->item_id,
eq->price,
eq->quantity,
eq->trader_id
);
eq->action = structs::TiBazaarTraderBuyerActions::BuyTraderItem;
OUT(price);
OUT(trader_id);
OUT(item_id);
OUT(already_sold);
OUT(quantity);
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
FINISH_ENCODE();
break;
}
case ItemMove: {
LogTrading(
"Encode OP_Trader ItemMove action <green>[{}]",
action
);
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
break;
}
default: {
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
LogError("Unknown Encode OP_Trader action <red>{} received. Unhandled.", action);
}
}
}
ENCODE(OP_TraderBuy)
{
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
LogTrading(
"Encode OP_TraderBuy item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
emu->item_id,
emu->price,
emu->quantity,
emu->trader_id
);
OUT(Action);
OUT(Price);
OUT(TraderID);
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
OUT(ItemID);
OUT(Quantity);
OUT(AlreadySold);
OUT(action);
OUT(price);
OUT(trader_id);
OUT(item_id);
OUT(already_sold);
OUT(quantity);
OUT_str(item_name);
FINISH_ENCODE();
}
ENCODE(OP_TraderShop)
{
auto action = *(uint32 *)(*p)->pBuffer;
switch (action) {
case ClickTrader: {
ENCODE_LENGTH_EXACT(TraderClick_Struct);
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
LogTrading(
"ClickTrader action <green>[{}] trader_id <green>[{}]",
action,
emu->TraderID
);
eq->action = 0;
eq->trader_id = emu->TraderID;
eq->approval = emu->Approval;
FINISH_ENCODE();
break;
}
case BuyTraderItem: {
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
LogTrading(
"Encode OP_TraderShop item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
eq->item_id,
eq->price,
eq->quantity,
eq->trader_id
);
eq->action = structs::TiBazaarTraderBuyerActions::BuyTraderItem;
OUT(price);
OUT(trader_id);
OUT(item_id);
OUT(already_sold);
OUT(quantity);
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
FINISH_ENCODE();
break;
}
default: {
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
LogError("Unknown Encode OP_TraderShop action <red>[{}] received. Unhandled.", action);
}
}
}
ENCODE(OP_TributeItem)
{
ENCODE_LENGTH_EXACT(TributeItem_Struct);
@@ -2286,6 +2496,53 @@ namespace Titanium
FINISH_DIRECT_DECODE();
}
DECODE(OP_BazaarSearch)
{
uint32 action = *(uint32 *) __packet->pBuffer;
switch (action) {
case structs::TiBazaarTraderBuyerActions::BazaarSearch: {
DECODE_LENGTH_EXACT(structs::BazaarSearch_Struct);
SETUP_DIRECT_DECODE(BazaarSearchCriteria_Struct, structs::BazaarSearch_Struct);
emu->action = eq->Beginning.Action;
emu->item_stat = eq->ItemStat;
emu->max_cost = eq->MaxPrice;
emu->min_cost = eq->MinPrice;
emu->max_level = eq->MaxLlevel;
emu->min_level = eq->Minlevel;
emu->race = eq->Race;
emu->slot = eq->Slot;
emu->type = eq->Type == UINT32_MAX ? UINT8_MAX : eq->Type;
emu->trader_entity_id = eq->TraderID;
emu->trader_id = 0;
emu->_class = eq->Class_;
emu->search_scope = eq->TraderID > 0 ? NonRoFBazaarSearchScope : Local_Scope;
emu->max_results = RuleI(Bazaar, MaxSearchResults);
strn0cpy(emu->item_name, eq->Name, sizeof(emu->item_name));
FINISH_DIRECT_DECODE();
break;
}
case structs::TiBazaarTraderBuyerActions::BazaarInspect: {
SETUP_DIRECT_DECODE(BazaarInspect_Struct, structs::BazaarInspect_Struct);
IN(action);
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
IN(serial_number);
FINISH_DIRECT_DECODE();
break;
}
case structs::TiBazaarTraderBuyerActions::WelcomeMessage: {
break;
}
default: {
LogTrading("(Ti) Unhandled action <red>[{}]", action);
}
}
}
DECODE(OP_Buff)
{
DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct);
@@ -2310,7 +2567,7 @@ namespace Titanium
DECODE_LENGTH_EXACT(structs::BugReport_Struct);
SETUP_DIRECT_DECODE(BugReport_Struct, structs::BugReport_Struct);
emu->category_id = EQ::bug::CategoryNameToCategoryID(eq->category_name);
emu->category_id = Bug::GetID(eq->category_name);
memcpy(emu->category_name, eq, sizeof(structs::BugReport_Struct));
FINISH_DIRECT_DECODE();
@@ -2925,18 +3182,90 @@ namespace Titanium
FINISH_DIRECT_DECODE();
}
DECODE(OP_Trader)
{
auto action = (uint32) __packet->pBuffer[0];
switch (action) {
case structs::TiBazaarTraderBuyerActions::BeginTraderMode: {
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
LogTrading(
"Decode OP_Trader BeginTraderMode action <red>[{}]",
action
);
emu->action = TraderOn;
emu->unknown_004 = 0;
std::copy_n(eq->serial_number, Titanium::invtype::BAZAAR_SIZE, emu->serial_number);
std::copy_n(eq->cost, Titanium::invtype::BAZAAR_SIZE, emu->item_cost);
FINISH_DIRECT_DECODE();
break;
}
case structs::TiBazaarTraderBuyerActions::EndTraderMode: {
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
LogTrading(
"Decode OP_Trader(Ti) EndTraderMode action <red>[{}]",
action
);
emu->action = TraderOff;
IN(entity_id);
FINISH_DIRECT_DECODE();
break;
}
case structs::TiBazaarTraderBuyerActions::PriceUpdate:
case structs::TiBazaarTraderBuyerActions::ItemMove:
case structs::TiBazaarTraderBuyerActions::EndTransaction:
case structs::TiBazaarTraderBuyerActions::ListTraderItems: {
LogTrading(
"Decode OP_Trader(Ti) Price/ItemMove/EndTransaction/ListTraderItems action <red>[{}]",
action
);
break;
}
case structs::TiBazaarTraderBuyerActions::ReconcileItems: {
break;
}
default: {
LogError("Unhandled(Ti) action <red>[{}] received.", action);
}
}
}
DECODE(OP_TraderBuy)
{
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
MEMSET_IN(TraderBuy_Struct);
IN(Action);
IN(Price);
IN(TraderID);
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
IN(ItemID);
IN(Quantity);
IN(action);
IN(price);
IN(trader_id);
memcpy(emu->item_name, eq->item_name, sizeof(emu->item_name));
IN(item_id);
IN(quantity);
FINISH_DIRECT_DECODE();
}
DECODE(OP_TraderShop)
{
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
LogTrading(
"(Ti) action <green>[{}] trader_id <green>[{}] approval <green>[{}]",
eq->action,
eq->trader_id,
eq->approval
);
emu->Code = ClickTrader;
emu->TraderID = eq->trader_id;
emu->Approval = eq->approval;
FINISH_DIRECT_DECODE();
}
+4
View File
@@ -82,6 +82,7 @@ E(OP_TaskDescription)
E(OP_Track)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_TraderShop)
E(OP_TributeItem)
E(OP_VetRewardsAvaliable)
E(OP_WearChange)
@@ -92,6 +93,7 @@ E(OP_ZoneSpawns)
D(OP_AdventureMerchantSell)
D(OP_ApplyPoison)
D(OP_AugmentItem)
D(OP_BazaarSearch)
D(OP_Buff)
D(OP_Bug)
D(OP_CastSpell)
@@ -123,7 +125,9 @@ D(OP_ReadBook)
D(OP_SetServerFilter)
D(OP_ShopPlayerSell)
D(OP_ShopRequest)
D(OP_Trader)
D(OP_TraderBuy)
D(OP_TraderShop)
D(OP_TradeSkillCombine)
D(OP_TributeItem)
D(OP_WearChange)
+75 -45
View File
@@ -2273,24 +2273,29 @@ struct BazaarWelcome_Struct {
};
struct BazaarSearch_Struct {
BazaarWindowStart_Struct beginning;
uint32 traderid;
uint32 class_;
uint32 race;
uint32 stat;
uint32 slot;
uint32 type;
char name[64];
uint32 minprice;
uint32 maxprice;
uint32 minlevel;
uint32 maxlevel;
BazaarWindowStart_Struct Beginning;
uint32 TraderID;
uint32 Class_;
uint32 Race;
uint32 ItemStat;
uint32 Slot;
uint32 Type;
char Name[64];
uint32 MinPrice;
uint32 MaxPrice;
uint32 Minlevel;
uint32 MaxLlevel;
};
struct BazaarInspect_Struct{
struct BazaarInspect_Struct {
uint32 action;
char player_name[64];
uint32 unknown_068;
uint32 serial_number;
uint32 unknown_076;
uint32 item_id;
uint32 unknown;
char name[64];
};
struct BazaarReturnDone_Struct{
uint32 type;
uint32 traderid;
@@ -2298,16 +2303,17 @@ struct BazaarReturnDone_Struct{
uint32 unknown12;
uint32 unknown16;
};
struct BazaarSearchResults_Struct {
BazaarWindowStart_Struct Beginning;
uint32 SellerID;
uint32 NumItems; // Don't know. Don't know the significance of this field.
uint32 SerialNumber;
uint32 Unknown016;
uint32 Unknown020; // Something to do with stats as well
char ItemName[64];
uint32 Cost;
uint32 ItemStat;
uint32 entity_id;
uint32 unknown_008;
uint32 item_id;
uint32 serial_number;
uint32 unknown_020;
char item_name[64];
uint32 item_cost;
uint32 item_stat;
};
struct ServerSideFilters_Struct {
@@ -2454,44 +2460,52 @@ struct WhoAllReturnStruct {
struct WhoAllPlayer player[0];
};
struct BeginTrader_Struct {
uint32 action;
uint32 unknown04;
uint64 serial_number[EQ::invtype::BAZAAR_SIZE];
uint32 cost[EQ::invtype::BAZAAR_SIZE];
};
struct Trader_Struct {
uint32 code;
uint32 itemid[160];
uint32 unknown;
uint32 itemcost[80];
uint32 action;
uint32 unknown004;
uint64 item_id[EQ::invtype::BAZAAR_SIZE];
uint32 item_cost[EQ::invtype::BAZAAR_SIZE];
};
struct ClickTrader_Struct {
uint32 code;
uint32 unknown[161];//damn soe this is totally pointless :/ but at least your finally using memset! Good job :) -LE
uint32 itemcost[80];
uint32 itemcost[EQ::invtype::BAZAAR_SIZE];
};
struct GetItems_Struct{
uint32 items[80];
uint32 items[EQ::invtype::BAZAAR_SIZE];
};
struct BecomeTrader_Struct{
uint32 ID;
uint32 Code;
struct BecomeTrader_Struct {
uint32 entity_id;
uint32 action;
char trader_name[64];
};
struct Trader_ShowItems_Struct{
uint32 code;
uint32 traderid;
uint32 action;
uint32 entity_id;
uint32 unknown08[3];
};
struct TraderBuy_Struct {
/*000*/ uint32 Action;
/*004*/ uint32 Price;
/*008*/ uint32 TraderID;
/*012*/ char ItemName[64];
/*076*/ uint32 Unknown076;
/*080*/ uint32 ItemID;
/*084*/ uint32 AlreadySold;
/*088*/ uint32 Quantity;
/*092*/ uint32 Unknown092;
/*000*/ uint32 action;
/*004*/ uint32 price;
/*008*/ uint32 trader_id;
/*012*/ char item_name[64];
/*076*/ uint32 unknown_076;
/*080*/ uint32 item_id;
/*084*/ uint32 already_sold;
/*088*/ uint32 quantity;
/*092*/ uint32 unknown_092;
};
@@ -2517,8 +2531,9 @@ struct TraderDelItem_Struct{
};
struct TraderClick_Struct{
uint32 traderid;
uint32 unknown4[2];
uint32 trader_id;
uint32 action;
uint32 unknown_004;
uint32 approval;
};
@@ -3744,6 +3759,21 @@ struct GuildMemberRank_Struct {
/*076*/ uint32 alt_banker; //Banker/Alt bit 00 - none 10 - Alt 11 - Alt and Banker 01 - Banker. Banker not functional for RoF2+
};
enum TiBazaarTraderBuyerActions {
Zero = 0,
BeginTraderMode = 1,
EndTraderMode = 2,
PriceUpdate = 3,
EndTransaction = 4,
BazaarSearch = 7,
WelcomeMessage = 9,
BuyTraderItem = 10,
ListTraderItems = 11,
BazaarInspect = 18,
ItemMove = 19,
ReconcileItems = 20
};
}; /*structs*/
}; /*Titanium*/
+401 -69
View File
@@ -37,6 +37,8 @@
#include "../races.h"
#include "../raid.h"
#include "../guilds.h"
//#include "../repositories/trader_repository.h"
#include "../cereal/include/cereal/types/vector.hpp"
#include <iostream>
#include <sstream>
@@ -307,50 +309,134 @@ namespace UF
EQApplicationPacket *in = *p;
*p = nullptr;
char *Buffer = (char *)in->pBuffer;
uint32 action = *(uint32 *)in->pBuffer;
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
switch (action) {
case BazaarSearch: {
LogTrading(
"Encode OP_BazaarSearch(UF) BazaarSearch action <green>[{}]",
action
);
std::vector<BazaarSearchResultsFromDB_Struct> results {};
auto bsms = (BazaarSearchMessaging_Struct *)in->pBuffer;
EQ::Util::MemoryStreamReader ss(
reinterpret_cast<char *>(bsms->payload),
in->size - sizeof(BazaarSearchMessaging_Struct)
);
cereal::BinaryInputArchive ar(ss);
ar(results);
if (SubAction != BazaarSearchResults)
{
dest->FastQueuePacket(&in, ack_req);
return;
auto size = results.size() * sizeof(BazaarSearchResults_Struct);
auto buffer = new uchar[size];
uchar *bufptr = buffer;
memset(buffer, 0, size);
for (auto row = results.begin(); row != results.end(); ++row) {
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, structs::UFBazaarTraderBuyerActions::BazaarSearch);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->trader_entity_id);
strn0cpy(reinterpret_cast<char *>(bufptr), row->trader_name.c_str(), 64);
bufptr += 64;
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 1);
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->item_id);
VARSTRUCT_ENCODE_TYPE(int32, bufptr, row->serial_number);
bufptr += 4;
if (row->stackable) {
strn0cpy(
reinterpret_cast<char *>(bufptr),
fmt::format("{}({})", row->item_name.c_str(), row->charges).c_str(),
64
);
}
else {
strn0cpy(
reinterpret_cast<char *>(bufptr),
fmt::format("{}({})", row->item_name.c_str(), row->count).c_str(),
64
);
}
bufptr += 64;
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->cost);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, row->item_stat);
}
auto outapp = new EQApplicationPacket(OP_BazaarSearch, size);
memcpy(outapp->pBuffer, buffer, size);
dest->FastQueuePacket(&outapp);
safe_delete(outapp);
safe_delete_array(buffer);
safe_delete(in);
break;
}
case BazaarInspect:
case WelcomeMessage: {
LogTrading(
"Encode OP_BazaarSearch(UF) BazaarInspect/WelcomeMessage action <green>[{}]",
action
);
dest->FastQueuePacket(&in, ack_req);
break;
}
default: {
LogTrading(
"Encode OP_BazaarSearch(UF) unhandled action <red>[{}]",
action
);
dest->FastQueuePacket(&in, ack_req);
}
}
}
unsigned char *__emu_buffer = in->pBuffer;
ENCODE(OP_BecomeTrader)
{
uint32 action = *(uint32 *)(*p)->pBuffer;
BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer;
int EntryCount = in->size / sizeof(BazaarSearchResults_Struct);
if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0)
switch (action)
{
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
delete in;
return;
case TraderOff:
{
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
LogTrading(
"Encode OP_BecomeTrader(UF) TraderOff action <green>[{}] entity_id <green>[{}] trader_name "
"<green>[{}]",
emu->action,
emu->entity_id,
emu->trader_name
);
eq->action = structs::UFBazaarTraderBuyerActions::Zero;
eq->entity_id = emu->entity_id;
FINISH_ENCODE();
break;
}
case TraderOn:
{
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
LogTrading(
"Encode OP_BecomeTrader(UF) TraderOn action <green>[{}] entity_id <green>[{}] trader_name "
"<green>[{}]",
emu->action,
emu->entity_id,
emu->trader_name
);
eq->action = structs::UFBazaarTraderBuyerActions::BeginTraderMode;
eq->entity_id = emu->entity_id;
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
FINISH_ENCODE();
break;
}
default:
{
LogTrading(
"Encode OP_BecomeTrader(UF) unhandled action <red>[{}] Sending packet as is.",
action
);
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
}
}
in->size = EntryCount * sizeof(structs::BazaarSearchResults_Struct);
in->pBuffer = new unsigned char[in->size];
memset(in->pBuffer, 0, in->size);
structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *)in->pBuffer;
for (int i = 0; i < EntryCount; ++i, ++emu, ++eq)
{
OUT(Beginning.Action);
OUT(SellerID);
memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName));
OUT(NumItems);
OUT(ItemID);
OUT(SerialNumber);
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
OUT(Cost);
OUT(ItemStat);
}
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_Buff)
@@ -2743,32 +2829,170 @@ namespace UF
ENCODE(OP_Trader)
{
if ((*p)->size != sizeof(TraderBuy_Struct)) {
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
return;
}
auto action = *(uint32 *) (*p)->pBuffer;
ENCODE_FORWARD(OP_TraderBuy);
switch (action) {
case TraderOn: {
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
LogTrading(
"Encode OP_Trader BeginTraderMode action <green>[{}]",
action
);
eq->action = structs::UFBazaarTraderBuyerActions::BeginTraderMode;
OUT(entity_id);
FINISH_ENCODE();
break;
}
case TraderOff: {
ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct);
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
LogTrading(
"Encode OP_Trader EndTraderMode action <green>[{}]",
action
);
eq->action = structs::UFBazaarTraderBuyerActions::EndTraderMode;
OUT(entity_id);
FINISH_ENCODE();
break;
}
case ListTraderItems: {
ENCODE_LENGTH_EXACT(Trader_Struct);
SETUP_DIRECT_ENCODE(Trader_Struct, structs::Trader_Struct);
LogTrading(
"Encode OP_Trader ListTraderItems action <green>[{}]",
action
);
eq->action = structs::UFBazaarTraderBuyerActions::ListTraderItems;
std::copy_n(emu->items, UF::invtype::BAZAAR_SIZE, eq->item_id);
std::copy_n(emu->item_cost, UF::invtype::BAZAAR_SIZE, eq->item_cost);
FINISH_ENCODE();
break;
}
case BuyTraderItem: {
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
LogTrading(
"Encode OP_Trader item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
eq->item_id,
eq->price,
eq->quantity,
eq->trader_id
);
eq->action = structs::UFBazaarTraderBuyerActions::BuyTraderItem;
OUT(price);
OUT(trader_id);
OUT(item_id);
OUT(already_sold);
OUT(quantity);
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
FINISH_ENCODE();
break;
}
case ItemMove: {
LogTrading(
"Encode OP_Trader ItemMove action <green>[{}]",
action
);
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
break;
}
default: {
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
LogError("Unknown Encode OP_Trader action <red>{} received. Unhandled.", action);
}
}
}
ENCODE(OP_TraderBuy)
{
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
LogTrading(
"Encode OP_TraderBuy item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
emu->item_id,
emu->price,
emu->quantity,
emu->trader_id
);
OUT(Action);
OUT(Price);
OUT(TraderID);
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
OUT(ItemID);
OUT(Quantity);
OUT(AlreadySold);
OUT(action);
OUT(price);
OUT(trader_id);
OUT(item_id);
OUT(already_sold);
OUT(quantity);
OUT_str(item_name);
FINISH_ENCODE();
}
ENCODE(OP_TraderShop)
{
auto action = *(uint32 *)(*p)->pBuffer;
switch (action) {
case ClickTrader: {
ENCODE_LENGTH_EXACT(TraderClick_Struct);
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
LogTrading(
"ClickTrader action <green>[{}] trader_id <green>[{}]",
action,
emu->TraderID
);
eq->action = 0;
eq->trader_id = emu->TraderID;
eq->approval = emu->Approval;
FINISH_ENCODE();
break;
}
case BuyTraderItem: {
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
LogTrading(
"Encode OP_TraderShop item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
eq->item_id,
eq->price,
eq->quantity,
eq->trader_id
);
eq->action = structs::UFBazaarTraderBuyerActions::BuyTraderItem;
OUT(price);
OUT(trader_id);
OUT(item_id);
OUT(already_sold);
OUT(quantity);
strn0cpy(eq->item_name, emu->item_name, sizeof(eq->item_name));
FINISH_ENCODE();
break;
}
default: {
EQApplicationPacket *in = *p;
*p = nullptr;
dest->FastQueuePacket(&in, ack_req);
LogError("Unknown Encode OP_TraderShop action <red>[{}] received. Unhandled.", action);
}
}
}
ENCODE(OP_TributeItem)
{
ENCODE_LENGTH_EXACT(TributeItem_Struct);
@@ -3040,7 +3264,7 @@ namespace UF
Bitfields->targetable = 1;
Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0;
Bitfields->statue = 0;
Bitfields->trader = 0;
Bitfields->trader = emu->trader ? 1 : 0;
Bitfields->buyer = 0;
Bitfields->showname = ShowName;
@@ -3363,20 +3587,49 @@ namespace UF
DECODE(OP_BazaarSearch)
{
char *Buffer = (char *)__packet->pBuffer;
uint32 action = *(uint32 *) __packet->pBuffer;
uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
switch (action) {
case structs::UFBazaarTraderBuyerActions::BazaarSearch: {
DECODE_LENGTH_EXACT(structs::BazaarSearch_Struct);
SETUP_DIRECT_DECODE(BazaarSearchCriteria_Struct, structs::BazaarSearch_Struct);
if ((SubAction != BazaarInspectItem) || (__packet->size != sizeof(structs::NewBazaarInspect_Struct)))
return;
emu->action = eq->Beginning.Action;
emu->item_stat = eq->ItemStat;
emu->max_cost = eq->MaxPrice;
emu->min_cost = eq->MinPrice;
emu->max_level = eq->MaxLlevel;
emu->min_level = eq->Minlevel;
emu->race = eq->Race;
emu->slot = eq->Slot;
emu->type = eq->Type == UINT32_MAX ? UINT8_MAX : eq->Type;
emu->trader_entity_id = eq->TraderID;
emu->trader_id = 0;
emu->_class = eq->Class_;
emu->search_scope = eq->TraderID > 0 ? NonRoFBazaarSearchScope : Local_Scope;
emu->max_results = RuleI(Bazaar, MaxSearchResults);
strn0cpy(emu->item_name, eq->Name, sizeof(emu->item_name));
SETUP_DIRECT_DECODE(NewBazaarInspect_Struct, structs::NewBazaarInspect_Struct);
MEMSET_IN(structs::NewBazaarInspect_Struct);
IN(Beginning.Action);
memcpy(emu->Name, eq->Name, sizeof(emu->Name));
IN(SerialNumber);
FINISH_DIRECT_DECODE();
break;
}
case structs::UFBazaarTraderBuyerActions::BazaarInspect: {
SETUP_DIRECT_DECODE(BazaarInspect_Struct, structs::BazaarInspect_Struct);
FINISH_DIRECT_DECODE();
IN(action);
memcpy(emu->player_name, eq->player_name, sizeof(emu->player_name));
IN(serial_number);
FINISH_DIRECT_DECODE();
break;
}
case structs::UFBazaarTraderBuyerActions::WelcomeMessage: {
break;
}
default: {
LogTrading("(UF) Unhandled action <red>[{}]", action);
}
}
}
DECODE(OP_BookButton)
@@ -4059,18 +4312,97 @@ namespace UF
FINISH_DIRECT_DECODE();
}
DECODE(OP_Trader)
{
auto action = (uint32) __packet->pBuffer[0];
switch (action) {
case structs::UFBazaarTraderBuyerActions::BeginTraderMode: {
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::BeginTrader_Struct);
LogTrading(
"Decode OP_Trader BeginTraderMode action <red>[{}]",
action
);
emu->action = TraderOn;
emu->unknown_004 = 0;
std::copy_n(eq->serial_number, UF::invtype::BAZAAR_SIZE, emu->serial_number);
std::copy_n(eq->cost, UF::invtype::BAZAAR_SIZE, emu->item_cost);
FINISH_DIRECT_DECODE();
break;
}
case structs::UFBazaarTraderBuyerActions::EndTraderMode: {
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
LogTrading(
"Decode OP_Trader(UF) EndTraderMode action <red>[{}]",
action
);
emu->action = TraderOff;
IN(entity_id);
FINISH_DIRECT_DECODE();
break;
}
case structs::UFBazaarTraderBuyerActions::PriceUpdate:
case structs::UFBazaarTraderBuyerActions::ItemMove:
case structs::UFBazaarTraderBuyerActions::EndTransaction:
case structs::UFBazaarTraderBuyerActions::ListTraderItems: {
LogTrading(
"Decode OP_Trader(UF) Price/ItemMove/EndTransaction/ListTraderItems action <red>[{}]",
action
);
break;
}
case structs::UFBazaarTraderBuyerActions::ReconcileItems: {
break;
}
default: {
LogError("Unhandled(UF) action <red>[{}] received.", action);
}
}
}
DECODE(OP_TraderBuy)
{
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
MEMSET_IN(TraderBuy_Struct);
LogTrading(
"Decode OP_TraderBuy(UF) item_id <green>[{}] price <green>[{}] quantity <green>[{}] trader_id <green>[{}]",
eq->item_id,
eq->price,
eq->quantity,
eq->trader_id
);
IN(Action);
IN(Price);
IN(TraderID);
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
IN(ItemID);
IN(Quantity);
emu->action = BuyTraderItem;
IN(price);
IN(trader_id);
IN(item_id);
IN(quantity);
IN(already_sold);
strn0cpy(emu->item_name, eq->item_name, sizeof(eq->item_name));
FINISH_DIRECT_DECODE();
}
DECODE(OP_TraderShop)
{
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
LogTrading(
"(UF) action <green>[{}] trader_id <green>[{}] approval <green>[{}]",
eq->action,
eq->trader_id,
eq->approval
);
emu->Code = ClickTrader;
emu->TraderID = eq->trader_id;
emu->Approval = eq->approval;
FINISH_DIRECT_DECODE();
}
+4
View File
@@ -27,6 +27,7 @@ E(OP_ApplyPoison)
E(OP_AugmentInfo)
E(OP_Barter)
E(OP_BazaarSearch)
E(OP_BecomeTrader)
E(OP_Buff)
E(OP_BuffCreate)
E(OP_CancelTrade)
@@ -100,6 +101,7 @@ E(OP_TaskDescription)
E(OP_Track)
E(OP_Trader)
E(OP_TraderBuy)
E(OP_TraderShop)
E(OP_TributeItem)
E(OP_VetRewardsAvaliable)
E(OP_WearChange)
@@ -160,7 +162,9 @@ D(OP_SetServerFilter)
D(OP_ShopPlayerBuy)
D(OP_ShopPlayerSell)
D(OP_ShopRequest)
D(OP_Trader)
D(OP_TraderBuy)
D(OP_TraderShop)
D(OP_TradeSkillCombine)
D(OP_TributeItem)
D(OP_WearChange)
+75 -39
View File
@@ -2640,23 +2640,23 @@ struct EnvDamage2_Struct {
//Bazaar Stuff
enum {
BazaarTrader_StartTraderMode = 1,
BazaarTrader_EndTraderMode = 2,
BazaarTrader_UpdatePrice = 3,
BazaarTrader_EndTransaction = 4,
BazaarSearchResults = 7,
BazaarWelcome = 9,
BazaarBuyItem = 10,
BazaarTrader_ShowItems = 11,
BazaarSearchDone = 12,
BazaarTrader_StartTraderMode = 1,
BazaarTrader_EndTraderMode = 2,
BazaarTrader_UpdatePrice = 3,
BazaarTrader_EndTransaction = 4,
BazaarSearchResults = 7,
BazaarWelcome = 9,
BazaarBuyItem = 10,
BazaarTrader_ShowItems = 11,
BazaarSearchDone = 12,
BazaarTrader_CustomerBrowsing = 13
};
enum {
BazaarPriceChange_Fail = 0,
BazaarPriceChange_Fail = 0,
BazaarPriceChange_UpdatePrice = 1,
BazaarPriceChange_RemoveItem = 2,
BazaarPriceChange_AddItem = 3
BazaarPriceChange_RemoveItem = 2,
BazaarPriceChange_AddItem = 3
};
struct BazaarWindowStart_Struct {
@@ -2687,10 +2687,14 @@ struct BazaarSearch_Struct {
uint32 Minlevel;
uint32 MaxLlevel;
};
struct BazaarInspect_Struct{
uint32 ItemID;
uint32 Unknown004;
char Name[64];
struct BazaarInspect_Struct {
uint32 action;
char player_name[64];
uint32 unknown_068;
uint32 serial_number;
uint32 unknown_076;
uint32 item_id;
};
struct NewBazaarInspect_Struct {
@@ -2929,10 +2933,17 @@ struct WhoAllPlayerPart4 {
};
struct Trader_Struct {
uint32 code;
uint32 itemid[160];
uint32 unknown;
uint32 itemcost[80];
uint32 action;
uint32 unknown004;
uint64 item_id[80];
uint32 item_cost[80];
};
struct BeginTrader_Struct {
uint32 action;
uint32 unknown04;
uint64 serial_number[80];
uint32 cost[80];
};
struct ClickTrader_Struct {
@@ -2945,30 +2956,30 @@ struct GetItems_Struct{
uint32 items[80];
};
struct BecomeTrader_Struct{
uint32 id;
uint32 code;
struct BecomeTrader_Struct {
uint32 entity_id;
uint32 action;
char trader_name[64];
};
struct Trader_ShowItems_Struct{
uint32 code;
uint32 traderid;
uint32 action;
uint32 entity_id;
uint32 unknown08[3];
};
struct TraderBuy_Struct {
/*000*/ uint32 Action;
/*004*/ uint32 Unknown004;
/*008*/ uint32 Price;
/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price.
/*016*/ uint32 TraderID;
/*020*/ char ItemName[64];
/*084*/ uint32 Unknown076;
/*088*/ uint32 ItemID;
/*092*/ uint32 AlreadySold;
/*096*/ uint32 Quantity;
/*100*/ uint32 Unknown092;
/*104*/
uint32 action;
uint32 unknown_004;
uint32 price;
uint32 unknown_008; // Probably high order bits of a 64 bit price.
uint32 trader_id;
char item_name[64];
uint32 unknown_076;
uint32 item_id;
uint32 already_sold;
uint32 quantity;
uint32 unknown_092;
};
struct TraderItemUpdate_Struct{
@@ -3002,8 +3013,9 @@ struct TraderDelItem_Struct{
};
struct TraderClick_Struct{
uint32 traderid;
uint32 unknown4[2];
uint32 trader_id;
uint32 action;
uint32 unknown_004;
uint32 approval;
};
@@ -4674,6 +4686,30 @@ struct SayLinkBodyFrame_Struct {
/*050*/
};
struct TraderPriceUpdate_Struct {
/*000*/ uint32 action;
/*004*/ uint32 sub_action;
/*008*/ int32 serial_number;
/*012*/ uint32 unknown_012;
/*016*/ uint32 new_price;
/*020*/ uint32 unknown_016;
};
enum UFBazaarTraderBuyerActions {
Zero = 0,
BeginTraderMode = 1,
EndTraderMode = 2,
PriceUpdate = 3,
EndTransaction = 4,
BazaarSearch = 7,
WelcomeMessage = 9,
BuyTraderItem = 10,
ListTraderItems = 11,
BazaarInspect = 18,
ItemMove = 19,
ReconcileItems = 20
};
}; /*structs*/
}; /*UF*/
+11
View File
@@ -74,6 +74,11 @@ void PathManager::LoadPaths()
m_patch_path = fs::relative(fs::path{m_server_path + "/" + c->PatchDir}).string();
}
// patches
if (File::Exists(fs::path{ m_server_path + "/" + c->OpcodeDir }.string())) {
m_opcode_path = fs::relative(fs::path{ m_server_path + "/" + c->OpcodeDir }).string();
}
// shared_memory_path
if (File::Exists(fs::path{m_server_path + "/" + c->SharedMemDir}.string())) {
m_shared_memory_path = fs::relative(fs::path{ m_server_path + "/" + c->SharedMemDir }).string();
@@ -89,6 +94,7 @@ void PathManager::LoadPaths()
LogInfo("lua_modules path [{}]", m_lua_modules_path);
LogInfo("maps path [{}]", m_maps_path);
LogInfo("patches path [{}]", m_patch_path);
LogInfo("opcode path [{}]", m_opcode_path);
LogInfo("plugins path [{}]", m_plugins_path);
LogInfo("quests path [{}]", m_quests_path);
LogInfo("shared_memory path [{}]", m_shared_memory_path);
@@ -129,6 +135,11 @@ const std::string &PathManager::GetPatchPath() const
return m_patch_path;
}
const std::string &PathManager::GetOpcodePath() const
{
return m_opcode_path;
}
const std::string &PathManager::GetLuaModulesPath() const
{
return m_lua_modules_path;
+2
View File
@@ -13,6 +13,7 @@ public:
[[nodiscard]] const std::string &GetLuaModulesPath() const;
[[nodiscard]] const std::string &GetMapsPath() const;
[[nodiscard]] const std::string &GetPatchPath() const;
[[nodiscard]] const std::string &GetOpcodePath() const;
[[nodiscard]] const std::string &GetPluginsPath() const;
[[nodiscard]] const std::string &GetQuestsPath() const;
[[nodiscard]] const std::string &GetServerPath() const;
@@ -24,6 +25,7 @@ private:
std::string m_lua_modules_path;
std::string m_maps_path;
std::string m_patch_path;
std::string m_opcode_path;
std::string m_plugins_path;
std::string m_quests_path;
std::string m_server_path;
@@ -21,7 +21,7 @@ public:
struct BotSpellsEntries {
uint32_t id;
int32_t npc_spells_id;
int16_t spellid;
uint16_t spell_id;
uint32_t type;
uint8_t minlevel;
uint8_t maxlevel;
@@ -46,7 +46,7 @@ public:
return {
"id",
"npc_spells_id",
"spellid",
"spell_id",
"type",
"minlevel",
"maxlevel",
@@ -67,7 +67,7 @@ public:
return {
"id",
"npc_spells_id",
"spellid",
"spell_id",
"type",
"minlevel",
"maxlevel",
@@ -122,7 +122,7 @@ public:
e.id = 0;
e.npc_spells_id = 0;
e.spellid = 0;
e.spell_id = 0;
e.type = 0;
e.minlevel = 0;
e.maxlevel = 255;
@@ -173,7 +173,7 @@ public:
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.spellid = row[2] ? static_cast<int16_t>(atoi(row[2])) : 0;
e.spell_id = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
@@ -220,7 +220,7 @@ public:
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.npc_spells_id));
v.push_back(columns[2] + " = " + std::to_string(e.spellid));
v.push_back(columns[2] + " = " + std::to_string(e.spell_id));
v.push_back(columns[3] + " = " + std::to_string(e.type));
v.push_back(columns[4] + " = " + std::to_string(e.minlevel));
v.push_back(columns[5] + " = " + std::to_string(e.maxlevel));
@@ -256,7 +256,7 @@ public:
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_spells_id));
v.push_back(std::to_string(e.spellid));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.minlevel));
v.push_back(std::to_string(e.maxlevel));
@@ -300,7 +300,7 @@ public:
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_spells_id));
v.push_back(std::to_string(e.spellid));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.minlevel));
v.push_back(std::to_string(e.maxlevel));
@@ -348,7 +348,7 @@ public:
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.spellid = row[2] ? static_cast<int16_t>(atoi(row[2])) : 0;
e.spell_id = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
@@ -387,7 +387,7 @@ public:
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.spellid = row[2] ? static_cast<int16_t>(atoi(row[2])) : 0;
e.spell_id = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
@@ -476,7 +476,7 @@ public:
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_spells_id));
v.push_back(std::to_string(e.spellid));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.minlevel));
v.push_back(std::to_string(e.maxlevel));
@@ -513,7 +513,7 @@ public:
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_spells_id));
v.push_back(std::to_string(e.spellid));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.minlevel));
v.push_back(std::to_string(e.maxlevel));
@@ -0,0 +1,475 @@
/**
* 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://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_BUYER_BUY_LINES_REPOSITORY_H
#define EQEMU_BASE_BUYER_BUY_LINES_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseBuyerBuyLinesRepository {
public:
struct BuyerBuyLines {
uint64_t id;
uint64_t buyer_id;
uint32_t char_id;
int32_t buy_slot_id;
int32_t item_id;
int32_t item_qty;
int32_t item_price;
uint32_t item_icon;
std::string item_name;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"buyer_id",
"char_id",
"buy_slot_id",
"item_id",
"item_qty",
"item_price",
"item_icon",
"item_name",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"buyer_id",
"char_id",
"buy_slot_id",
"item_id",
"item_qty",
"item_price",
"item_icon",
"item_name",
};
}
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("buyer_buy_lines");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static BuyerBuyLines NewEntity()
{
BuyerBuyLines e{};
e.id = 0;
e.buyer_id = 0;
e.char_id = 0;
e.buy_slot_id = 0;
e.item_id = 0;
e.item_qty = 0;
e.item_price = 0;
e.item_icon = 0;
e.item_name = "";
return e;
}
static BuyerBuyLines GetBuyerBuyLines(
const std::vector<BuyerBuyLines> &buyer_buy_liness,
int buyer_buy_lines_id
)
{
for (auto &buyer_buy_lines : buyer_buy_liness) {
if (buyer_buy_lines.id == buyer_buy_lines_id) {
return buyer_buy_lines;
}
}
return NewEntity();
}
static BuyerBuyLines FindOne(
Database& db,
int buyer_buy_lines_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
buyer_buy_lines_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
BuyerBuyLines e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.buyer_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.buy_slot_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.item_qty = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
e.item_price = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
e.item_icon = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.item_name = row[8] ? row[8] : "";
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int buyer_buy_lines_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
buyer_buy_lines_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const BuyerBuyLines &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.buyer_id));
v.push_back(columns[2] + " = " + std::to_string(e.char_id));
v.push_back(columns[3] + " = " + std::to_string(e.buy_slot_id));
v.push_back(columns[4] + " = " + std::to_string(e.item_id));
v.push_back(columns[5] + " = " + std::to_string(e.item_qty));
v.push_back(columns[6] + " = " + std::to_string(e.item_price));
v.push_back(columns[7] + " = " + std::to_string(e.item_icon));
v.push_back(columns[8] + " = '" + Strings::Escape(e.item_name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static BuyerBuyLines InsertOne(
Database& db,
BuyerBuyLines e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.buyer_id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.buy_slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_qty));
v.push_back(std::to_string(e.item_price));
v.push_back(std::to_string(e.item_icon));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
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<BuyerBuyLines> &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.buyer_id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.buy_slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_qty));
v.push_back(std::to_string(e.item_price));
v.push_back(std::to_string(e.item_icon));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
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<BuyerBuyLines> All(Database& db)
{
std::vector<BuyerBuyLines> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
BuyerBuyLines e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.buyer_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.buy_slot_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.item_qty = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
e.item_price = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
e.item_icon = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.item_name = row[8] ? row[8] : "";
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<BuyerBuyLines> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<BuyerBuyLines> 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) {
BuyerBuyLines e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.buyer_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.buy_slot_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.item_qty = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
e.item_price = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
e.item_icon = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.item_name = row[8] ? row[8] : "";
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);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const BuyerBuyLines &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.buyer_id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.buy_slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_qty));
v.push_back(std::to_string(e.item_price));
v.push_back(std::to_string(e.item_icon));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
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<BuyerBuyLines> &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.buyer_id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.buy_slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_qty));
v.push_back(std::to_string(e.item_price));
v.push_back(std::to_string(e.item_icon));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
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_BUYER_BUY_LINES_REPOSITORY_H
@@ -19,40 +19,46 @@
class BaseBuyerRepository {
public:
struct Buyer {
int32_t charid;
int32_t buyslot;
int32_t itemid;
std::string itemname;
int32_t quantity;
int32_t price;
uint64_t id;
uint32_t char_id;
uint32_t char_entity_id;
std::string char_name;
uint32_t char_zone_id;
uint32_t char_zone_instance_id;
time_t transaction_date;
std::string welcome_message;
};
static std::string PrimaryKey()
{
return std::string("charid");
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"charid",
"buyslot",
"itemid",
"itemname",
"quantity",
"price",
"id",
"char_id",
"char_entity_id",
"char_name",
"char_zone_id",
"char_zone_instance_id",
"transaction_date",
"welcome_message",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"charid",
"buyslot",
"itemid",
"itemname",
"quantity",
"price",
"id",
"char_id",
"char_entity_id",
"char_name",
"char_zone_id",
"char_zone_instance_id",
"UNIX_TIMESTAMP(transaction_date)",
"welcome_message",
};
}
@@ -93,12 +99,14 @@ public:
{
Buyer e{};
e.charid = 0;
e.buyslot = 0;
e.itemid = 0;
e.itemname = "";
e.quantity = 0;
e.price = 0;
e.id = 0;
e.char_id = 0;
e.char_entity_id = 0;
e.char_name = "";
e.char_zone_id = 0;
e.char_zone_instance_id = 0;
e.transaction_date = 0;
e.welcome_message = "";
return e;
}
@@ -109,7 +117,7 @@ public:
)
{
for (auto &buyer : buyers) {
if (buyer.charid == buyer_id) {
if (buyer.id == buyer_id) {
return buyer;
}
}
@@ -135,12 +143,14 @@ public:
if (results.RowCount() == 1) {
Buyer e{};
e.charid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.buyslot = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.itemid = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.itemname = row[3] ? row[3] : "";
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.price = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.char_entity_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.char_name = row[3] ? row[3] : "";
e.char_zone_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.char_zone_instance_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.transaction_date = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
e.welcome_message = row[7] ? row[7] : "";
return e;
}
@@ -174,12 +184,13 @@ public:
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.charid));
v.push_back(columns[1] + " = " + std::to_string(e.buyslot));
v.push_back(columns[2] + " = " + std::to_string(e.itemid));
v.push_back(columns[3] + " = '" + Strings::Escape(e.itemname) + "'");
v.push_back(columns[4] + " = " + std::to_string(e.quantity));
v.push_back(columns[5] + " = " + std::to_string(e.price));
v.push_back(columns[1] + " = " + std::to_string(e.char_id));
v.push_back(columns[2] + " = " + std::to_string(e.char_entity_id));
v.push_back(columns[3] + " = '" + Strings::Escape(e.char_name) + "'");
v.push_back(columns[4] + " = " + std::to_string(e.char_zone_id));
v.push_back(columns[5] + " = " + std::to_string(e.char_zone_instance_id));
v.push_back(columns[6] + " = FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
v.push_back(columns[7] + " = '" + Strings::Escape(e.welcome_message) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -187,7 +198,7 @@ public:
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.charid
e.id
)
);
@@ -201,12 +212,14 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.buyslot));
v.push_back(std::to_string(e.itemid));
v.push_back("'" + Strings::Escape(e.itemname) + "'");
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.price));
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back("'" + Strings::Escape(e.char_name) + "'");
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -217,7 +230,7 @@ public:
);
if (results.Success()) {
e.charid = results.LastInsertedID();
e.id = results.LastInsertedID();
return e;
}
@@ -236,12 +249,14 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.buyslot));
v.push_back(std::to_string(e.itemid));
v.push_back("'" + Strings::Escape(e.itemname) + "'");
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.price));
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back("'" + Strings::Escape(e.char_name) + "'");
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -275,12 +290,14 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Buyer e{};
e.charid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.buyslot = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.itemid = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.itemname = row[3] ? row[3] : "";
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.price = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.char_entity_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.char_name = row[3] ? row[3] : "";
e.char_zone_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.char_zone_instance_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.transaction_date = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
e.welcome_message = row[7] ? row[7] : "";
all_entries.push_back(e);
}
@@ -305,12 +322,14 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Buyer e{};
e.charid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.buyslot = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.itemid = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.itemname = row[3] ? row[3] : "";
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.price = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.char_entity_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.char_name = row[3] ? row[3] : "";
e.char_zone_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.char_zone_instance_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.transaction_date = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
e.welcome_message = row[7] ? row[7] : "";
all_entries.push_back(e);
}
@@ -385,12 +404,14 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.buyslot));
v.push_back(std::to_string(e.itemid));
v.push_back("'" + Strings::Escape(e.itemname) + "'");
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.price));
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back("'" + Strings::Escape(e.char_name) + "'");
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -413,12 +434,14 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.buyslot));
v.push_back(std::to_string(e.itemid));
v.push_back("'" + Strings::Escape(e.itemname) + "'");
v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.price));
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back("'" + Strings::Escape(e.char_name) + "'");
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -0,0 +1,439 @@
/**
* 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://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_BUYER_TRADE_ITEMS_REPOSITORY_H
#define EQEMU_BASE_BUYER_TRADE_ITEMS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseBuyerTradeItemsRepository {
public:
struct BuyerTradeItems {
uint64_t id;
uint64_t buyer_buy_lines_id;
int32_t item_id;
int32_t item_qty;
int32_t item_icon;
std::string item_name;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"buyer_buy_lines_id",
"item_id",
"item_qty",
"item_icon",
"item_name",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"buyer_buy_lines_id",
"item_id",
"item_qty",
"item_icon",
"item_name",
};
}
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("buyer_trade_items");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static BuyerTradeItems NewEntity()
{
BuyerTradeItems e{};
e.id = 0;
e.buyer_buy_lines_id = 0;
e.item_id = 0;
e.item_qty = 0;
e.item_icon = 0;
e.item_name = "0";
return e;
}
static BuyerTradeItems GetBuyerTradeItems(
const std::vector<BuyerTradeItems> &buyer_trade_itemss,
int buyer_trade_items_id
)
{
for (auto &buyer_trade_items : buyer_trade_itemss) {
if (buyer_trade_items.id == buyer_trade_items_id) {
return buyer_trade_items;
}
}
return NewEntity();
}
static BuyerTradeItems FindOne(
Database& db,
int buyer_trade_items_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
buyer_trade_items_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
BuyerTradeItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.item_name = row[5] ? row[5] : "0";
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int buyer_trade_items_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
buyer_trade_items_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const BuyerTradeItems &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.buyer_buy_lines_id));
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
v.push_back(columns[3] + " = " + std::to_string(e.item_qty));
v.push_back(columns[4] + " = " + std::to_string(e.item_icon));
v.push_back(columns[5] + " = '" + Strings::Escape(e.item_name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static BuyerTradeItems InsertOne(
Database& db,
BuyerTradeItems e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.buyer_buy_lines_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_qty));
v.push_back(std::to_string(e.item_icon));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
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<BuyerTradeItems> &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.buyer_buy_lines_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_qty));
v.push_back(std::to_string(e.item_icon));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
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<BuyerTradeItems> All(Database& db)
{
std::vector<BuyerTradeItems> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
BuyerTradeItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.item_name = row[5] ? row[5] : "0";
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<BuyerTradeItems> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<BuyerTradeItems> 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) {
BuyerTradeItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.item_name = row[5] ? row[5] : "0";
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);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const BuyerTradeItems &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.buyer_buy_lines_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_qty));
v.push_back(std::to_string(e.item_icon));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
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<BuyerTradeItems> &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.buyer_buy_lines_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.item_qty));
v.push_back(std::to_string(e.item_icon));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
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_BUYER_TRADE_ITEMS_REPOSITORY_H
@@ -0,0 +1,499 @@
/**
* 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://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
#define EQEMU_BASE_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseCharacterParcelsContainersRepository {
public:
struct CharacterParcelsContainers {
uint32_t id;
uint32_t parcels_id;
uint32_t slot_id;
uint32_t item_id;
uint32_t aug_slot_1;
uint32_t aug_slot_2;
uint32_t aug_slot_3;
uint32_t aug_slot_4;
uint32_t aug_slot_5;
uint32_t aug_slot_6;
uint32_t quantity;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"parcels_id",
"slot_id",
"item_id",
"aug_slot_1",
"aug_slot_2",
"aug_slot_3",
"aug_slot_4",
"aug_slot_5",
"aug_slot_6",
"quantity",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"parcels_id",
"slot_id",
"item_id",
"aug_slot_1",
"aug_slot_2",
"aug_slot_3",
"aug_slot_4",
"aug_slot_5",
"aug_slot_6",
"quantity",
};
}
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("character_parcels_containers");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static CharacterParcelsContainers NewEntity()
{
CharacterParcelsContainers e{};
e.id = 0;
e.parcels_id = 0;
e.slot_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.quantity = 0;
return e;
}
static CharacterParcelsContainers GetCharacterParcelsContainers(
const std::vector<CharacterParcelsContainers> &character_parcels_containerss,
int character_parcels_containers_id
)
{
for (auto &character_parcels_containers : character_parcels_containerss) {
if (character_parcels_containers.id == character_parcels_containers_id) {
return character_parcels_containers;
}
}
return NewEntity();
}
static CharacterParcelsContainers FindOne(
Database& db,
int character_parcels_containers_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
character_parcels_containers_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
CharacterParcelsContainers e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int character_parcels_containers_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
character_parcels_containers_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const CharacterParcelsContainers &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.parcels_id));
v.push_back(columns[2] + " = " + std::to_string(e.slot_id));
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
v.push_back(columns[4] + " = " + std::to_string(e.aug_slot_1));
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_2));
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_3));
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_4));
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_5));
v.push_back(columns[9] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[10] + " = " + std::to_string(e.quantity));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static CharacterParcelsContainers InsertOne(
Database& db,
CharacterParcelsContainers e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.parcels_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity));
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<CharacterParcelsContainers> &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.parcels_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity));
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<CharacterParcelsContainers> All(Database& db)
{
std::vector<CharacterParcelsContainers> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterParcelsContainers e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<CharacterParcelsContainers> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<CharacterParcelsContainers> 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) {
CharacterParcelsContainers e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.parcels_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.slot_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_1 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_2 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_3 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_4 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
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);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const CharacterParcelsContainers &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.parcels_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity));
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<CharacterParcelsContainers> &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.parcels_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity));
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_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
@@ -19,70 +19,73 @@
class BaseInventoryRepository {
public:
struct Inventory {
uint32_t charid;
uint32_t slotid;
uint32_t itemid;
uint32_t character_id;
uint32_t slot_id;
uint32_t item_id;
uint16_t charges;
uint32_t color;
uint32_t augslot1;
uint32_t augslot2;
uint32_t augslot3;
uint32_t augslot4;
uint32_t augslot5;
int32_t augslot6;
uint32_t augment_one;
uint32_t augment_two;
uint32_t augment_three;
uint32_t augment_four;
uint32_t augment_five;
uint32_t augment_six;
uint8_t instnodrop;
std::string custom_data;
uint32_t ornamenticon;
uint32_t ornamentidfile;
uint32_t ornament_icon;
uint32_t ornament_idfile;
int32_t ornament_hero_model;
uint64_t guid;
};
static std::string PrimaryKey()
{
return std::string("charid");
return std::string("character_id");
}
static std::vector<std::string> Columns()
{
return {
"charid",
"slotid",
"itemid",
"character_id",
"slot_id",
"item_id",
"charges",
"color",
"augslot1",
"augslot2",
"augslot3",
"augslot4",
"augslot5",
"augslot6",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"instnodrop",
"custom_data",
"ornamenticon",
"ornamentidfile",
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"charid",
"slotid",
"itemid",
"character_id",
"slot_id",
"item_id",
"charges",
"color",
"augslot1",
"augslot2",
"augslot3",
"augslot4",
"augslot5",
"augslot6",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"instnodrop",
"custom_data",
"ornamenticon",
"ornamentidfile",
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
};
}
@@ -123,22 +126,23 @@ public:
{
Inventory e{};
e.charid = 0;
e.slotid = 0;
e.itemid = 0;
e.character_id = 0;
e.slot_id = 0;
e.item_id = 0;
e.charges = 0;
e.color = 0;
e.augslot1 = 0;
e.augslot2 = 0;
e.augslot3 = 0;
e.augslot4 = 0;
e.augslot5 = 0;
e.augslot6 = 0;
e.augment_one = 0;
e.augment_two = 0;
e.augment_three = 0;
e.augment_four = 0;
e.augment_five = 0;
e.augment_six = 0;
e.instnodrop = 0;
e.custom_data = "";
e.ornamenticon = 0;
e.ornamentidfile = 0;
e.ornament_icon = 0;
e.ornament_idfile = 0;
e.ornament_hero_model = 0;
e.guid = 0;
return e;
}
@@ -149,7 +153,7 @@ public:
)
{
for (auto &inventory : inventorys) {
if (inventory.charid == inventory_id) {
if (inventory.character_id == inventory_id) {
return inventory;
}
}
@@ -175,22 +179,23 @@ public:
if (results.RowCount() == 1) {
Inventory e{};
e.charid = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.slotid = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.itemid = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.character_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.slot_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.charges = row[3] ? static_cast<uint16_t>(strtoul(row[3], nullptr, 10)) : 0;
e.color = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augslot1 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augslot2 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augslot3 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augslot4 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augslot5 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augslot6 = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.augment_one = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_two = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_three = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_four = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_five = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_six = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.instnodrop = row[11] ? static_cast<uint8_t>(strtoul(row[11], nullptr, 10)) : 0;
e.custom_data = row[12] ? row[12] : "";
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_icon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_idfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
return e;
}
@@ -224,22 +229,23 @@ public:
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.charid));
v.push_back(columns[1] + " = " + std::to_string(e.slotid));
v.push_back(columns[2] + " = " + std::to_string(e.itemid));
v.push_back(columns[0] + " = " + std::to_string(e.character_id));
v.push_back(columns[1] + " = " + std::to_string(e.slot_id));
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
v.push_back(columns[3] + " = " + std::to_string(e.charges));
v.push_back(columns[4] + " = " + std::to_string(e.color));
v.push_back(columns[5] + " = " + std::to_string(e.augslot1));
v.push_back(columns[6] + " = " + std::to_string(e.augslot2));
v.push_back(columns[7] + " = " + std::to_string(e.augslot3));
v.push_back(columns[8] + " = " + std::to_string(e.augslot4));
v.push_back(columns[9] + " = " + std::to_string(e.augslot5));
v.push_back(columns[10] + " = " + std::to_string(e.augslot6));
v.push_back(columns[5] + " = " + std::to_string(e.augment_one));
v.push_back(columns[6] + " = " + std::to_string(e.augment_two));
v.push_back(columns[7] + " = " + std::to_string(e.augment_three));
v.push_back(columns[8] + " = " + std::to_string(e.augment_four));
v.push_back(columns[9] + " = " + std::to_string(e.augment_five));
v.push_back(columns[10] + " = " + std::to_string(e.augment_six));
v.push_back(columns[11] + " = " + std::to_string(e.instnodrop));
v.push_back(columns[12] + " = '" + Strings::Escape(e.custom_data) + "'");
v.push_back(columns[13] + " = " + std::to_string(e.ornamenticon));
v.push_back(columns[14] + " = " + std::to_string(e.ornamentidfile));
v.push_back(columns[13] + " = " + std::to_string(e.ornament_icon));
v.push_back(columns[14] + " = " + std::to_string(e.ornament_idfile));
v.push_back(columns[15] + " = " + std::to_string(e.ornament_hero_model));
v.push_back(columns[16] + " = " + std::to_string(e.guid));
auto results = db.QueryDatabase(
fmt::format(
@@ -247,7 +253,7 @@ public:
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.charid
e.character_id
)
);
@@ -261,22 +267,23 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.slotid));
v.push_back(std::to_string(e.itemid));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augslot1));
v.push_back(std::to_string(e.augslot2));
v.push_back(std::to_string(e.augslot3));
v.push_back(std::to_string(e.augslot4));
v.push_back(std::to_string(e.augslot5));
v.push_back(std::to_string(e.augslot6));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.instnodrop));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
auto results = db.QueryDatabase(
fmt::format(
@@ -287,7 +294,7 @@ public:
);
if (results.Success()) {
e.charid = results.LastInsertedID();
e.character_id = results.LastInsertedID();
return e;
}
@@ -306,22 +313,23 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.slotid));
v.push_back(std::to_string(e.itemid));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augslot1));
v.push_back(std::to_string(e.augslot2));
v.push_back(std::to_string(e.augslot3));
v.push_back(std::to_string(e.augslot4));
v.push_back(std::to_string(e.augslot5));
v.push_back(std::to_string(e.augslot6));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.instnodrop));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -355,22 +363,23 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Inventory e{};
e.charid = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.slotid = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.itemid = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.character_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.slot_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.charges = row[3] ? static_cast<uint16_t>(strtoul(row[3], nullptr, 10)) : 0;
e.color = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augslot1 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augslot2 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augslot3 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augslot4 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augslot5 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augslot6 = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.augment_one = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_two = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_three = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_four = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_five = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_six = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.instnodrop = row[11] ? static_cast<uint8_t>(strtoul(row[11], nullptr, 10)) : 0;
e.custom_data = row[12] ? row[12] : "";
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_icon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_idfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
all_entries.push_back(e);
}
@@ -395,22 +404,23 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Inventory e{};
e.charid = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.slotid = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.itemid = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.character_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.slot_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.charges = row[3] ? static_cast<uint16_t>(strtoul(row[3], nullptr, 10)) : 0;
e.color = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augslot1 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augslot2 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augslot3 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augslot4 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augslot5 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augslot6 = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.augment_one = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_two = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_three = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_four = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_five = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_six = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.instnodrop = row[11] ? static_cast<uint8_t>(strtoul(row[11], nullptr, 10)) : 0;
e.custom_data = row[12] ? row[12] : "";
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_icon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_idfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
all_entries.push_back(e);
}
@@ -485,22 +495,23 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.slotid));
v.push_back(std::to_string(e.itemid));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augslot1));
v.push_back(std::to_string(e.augslot2));
v.push_back(std::to_string(e.augslot3));
v.push_back(std::to_string(e.augslot4));
v.push_back(std::to_string(e.augslot5));
v.push_back(std::to_string(e.augslot6));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.instnodrop));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
auto results = db.QueryDatabase(
fmt::format(
@@ -523,22 +534,23 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.slotid));
v.push_back(std::to_string(e.itemid));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augslot1));
v.push_back(std::to_string(e.augslot2));
v.push_back(std::to_string(e.augslot3));
v.push_back(std::to_string(e.augslot4));
v.push_back(std::to_string(e.augslot5));
v.push_back(std::to_string(e.augslot6));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back(std::to_string(e.instnodrop));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -36,6 +36,7 @@ public:
uint32_t ornamenticon;
uint32_t ornamentidfile;
int32_t ornament_hero_model;
uint64_t guid;
};
static std::string PrimaryKey()
@@ -63,6 +64,7 @@ public:
"ornamenticon",
"ornamentidfile",
"ornament_hero_model",
"guid",
};
}
@@ -86,6 +88,7 @@ public:
"ornamenticon",
"ornamentidfile",
"ornament_hero_model",
"guid",
};
}
@@ -143,6 +146,7 @@ public:
e.ornamenticon = 0;
e.ornamentidfile = 0;
e.ornament_hero_model = 0;
e.guid = 0;
return e;
}
@@ -196,6 +200,7 @@ public:
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
return e;
}
@@ -246,6 +251,7 @@ public:
v.push_back(columns[14] + " = " + std::to_string(e.ornamenticon));
v.push_back(columns[15] + " = " + std::to_string(e.ornamentidfile));
v.push_back(columns[16] + " = " + std::to_string(e.ornament_hero_model));
v.push_back(columns[17] + " = " + std::to_string(e.guid));
auto results = db.QueryDatabase(
fmt::format(
@@ -284,6 +290,7 @@ public:
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
auto results = db.QueryDatabase(
fmt::format(
@@ -330,6 +337,7 @@ public:
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -380,6 +388,7 @@ public:
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
all_entries.push_back(e);
}
@@ -421,6 +430,7 @@ public:
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
all_entries.push_back(e);
}
@@ -512,6 +522,7 @@ public:
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
auto results = db.QueryDatabase(
fmt::format(
@@ -551,6 +562,7 @@ public:
v.push_back(std::to_string(e.ornamenticon));
v.push_back(std::to_string(e.ornamentidfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -19,18 +19,22 @@
class BaseNpcSpellsEntriesRepository {
public:
struct NpcSpellsEntries {
uint32_t id;
int32_t npc_spells_id;
uint16_t spellid;
uint32_t type;
uint8_t minlevel;
uint8_t maxlevel;
int16_t manacost;
int32_t recast_delay;
int16_t priority;
int32_t resist_adjust;
int16_t min_hp;
int16_t max_hp;
uint32_t id;
int32_t npc_spells_id;
uint16_t spellid;
uint32_t type;
uint8_t minlevel;
uint8_t maxlevel;
int16_t manacost;
int32_t recast_delay;
int16_t priority;
int32_t resist_adjust;
int16_t min_hp;
int16_t max_hp;
int8_t min_expansion;
int8_t max_expansion;
std::string content_flags;
std::string content_flags_disabled;
};
static std::string PrimaryKey()
@@ -53,6 +57,10 @@ public:
"resist_adjust",
"min_hp",
"max_hp",
"min_expansion",
"max_expansion",
"content_flags",
"content_flags_disabled",
};
}
@@ -71,6 +79,10 @@ public:
"resist_adjust",
"min_hp",
"max_hp",
"min_expansion",
"max_expansion",
"content_flags",
"content_flags_disabled",
};
}
@@ -111,18 +123,22 @@ public:
{
NpcSpellsEntries e{};
e.id = 0;
e.npc_spells_id = 0;
e.spellid = 0;
e.type = 0;
e.minlevel = 0;
e.maxlevel = 255;
e.manacost = -1;
e.recast_delay = -1;
e.priority = 0;
e.resist_adjust = 0;
e.min_hp = 0;
e.max_hp = 0;
e.id = 0;
e.npc_spells_id = 0;
e.spellid = 0;
e.type = 0;
e.minlevel = 0;
e.maxlevel = 255;
e.manacost = -1;
e.recast_delay = -1;
e.priority = 0;
e.resist_adjust = 0;
e.min_hp = 0;
e.max_hp = 0;
e.min_expansion = -1;
e.max_expansion = -1;
e.content_flags = "";
e.content_flags_disabled = "";
return e;
}
@@ -159,18 +175,22 @@ public:
if (results.RowCount() == 1) {
NpcSpellsEntries e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
e.min_expansion = row[12] ? static_cast<int8_t>(atoi(row[12])) : -1;
e.max_expansion = row[13] ? static_cast<int8_t>(atoi(row[13])) : -1;
e.content_flags = row[14] ? row[14] : "";
e.content_flags_disabled = row[15] ? row[15] : "";
return e;
}
@@ -215,6 +235,10 @@ public:
v.push_back(columns[9] + " = " + std::to_string(e.resist_adjust));
v.push_back(columns[10] + " = " + std::to_string(e.min_hp));
v.push_back(columns[11] + " = " + std::to_string(e.max_hp));
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(
@@ -248,6 +272,10 @@ public:
v.push_back(std::to_string(e.resist_adjust));
v.push_back(std::to_string(e.min_hp));
v.push_back(std::to_string(e.max_hp));
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(
@@ -289,6 +317,10 @@ public:
v.push_back(std::to_string(e.resist_adjust));
v.push_back(std::to_string(e.min_hp));
v.push_back(std::to_string(e.max_hp));
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) + ")");
}
@@ -322,18 +354,22 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
NpcSpellsEntries e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
e.min_expansion = row[12] ? static_cast<int8_t>(atoi(row[12])) : -1;
e.max_expansion = row[13] ? static_cast<int8_t>(atoi(row[13])) : -1;
e.content_flags = row[14] ? row[14] : "";
e.content_flags_disabled = row[15] ? row[15] : "";
all_entries.push_back(e);
}
@@ -358,18 +394,22 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
NpcSpellsEntries e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.spellid = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
e.manacost = row[6] ? static_cast<int16_t>(atoi(row[6])) : -1;
e.recast_delay = row[7] ? static_cast<int32_t>(atoi(row[7])) : -1;
e.priority = row[8] ? static_cast<int16_t>(atoi(row[8])) : 0;
e.resist_adjust = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.min_hp = row[10] ? static_cast<int16_t>(atoi(row[10])) : 0;
e.max_hp = row[11] ? static_cast<int16_t>(atoi(row[11])) : 0;
e.min_expansion = row[12] ? static_cast<int8_t>(atoi(row[12])) : -1;
e.max_expansion = row[13] ? static_cast<int8_t>(atoi(row[13])) : -1;
e.content_flags = row[14] ? row[14] : "";
e.content_flags_disabled = row[15] ? row[15] : "";
all_entries.push_back(e);
}
@@ -456,6 +496,10 @@ public:
v.push_back(std::to_string(e.resist_adjust));
v.push_back(std::to_string(e.min_hp));
v.push_back(std::to_string(e.max_hp));
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(
@@ -490,6 +534,10 @@ public:
v.push_back(std::to_string(e.resist_adjust));
v.push_back(std::to_string(e.min_hp));
v.push_back(std::to_string(e.max_hp));
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) + ")");
}
@@ -38,6 +38,7 @@ public:
int64_t mana_regen_rate;
uint32_t loottable_id;
uint32_t merchant_id;
uint8_t greed;
uint32_t alt_currency_id;
uint32_t npc_spells_id;
uint32_t npc_spells_effects_id;
@@ -176,6 +177,7 @@ public:
"mana_regen_rate",
"loottable_id",
"merchant_id",
"greed",
"alt_currency_id",
"npc_spells_id",
"npc_spells_effects_id",
@@ -310,6 +312,7 @@ public:
"mana_regen_rate",
"loottable_id",
"merchant_id",
"greed",
"alt_currency_id",
"npc_spells_id",
"npc_spells_effects_id",
@@ -478,6 +481,7 @@ public:
e.mana_regen_rate = 0;
e.loottable_id = 0;
e.merchant_id = 0;
e.greed = 0;
e.alt_currency_id = 0;
e.npc_spells_id = 0;
e.npc_spells_effects_id = 0;
@@ -642,115 +646,116 @@ public:
e.mana_regen_rate = row[16] ? strtoll(row[16], nullptr, 10) : 0;
e.loottable_id = row[17] ? static_cast<uint32_t>(strtoul(row[17], nullptr, 10)) : 0;
e.merchant_id = row[18] ? static_cast<uint32_t>(strtoul(row[18], nullptr, 10)) : 0;
e.alt_currency_id = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
e.npc_spells_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
e.npc_spells_effects_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
e.npc_faction_id = row[22] ? static_cast<int32_t>(atoi(row[22])) : 0;
e.adventure_template_id = row[23] ? static_cast<uint32_t>(strtoul(row[23], nullptr, 10)) : 0;
e.trap_template = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
e.mindmg = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
e.maxdmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
e.attack_count = row[27] ? static_cast<int16_t>(atoi(row[27])) : -1;
e.npcspecialattks = row[28] ? row[28] : "";
e.special_abilities = row[29] ? row[29] : "";
e.aggroradius = row[30] ? static_cast<uint32_t>(strtoul(row[30], nullptr, 10)) : 0;
e.assistradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
e.face = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 1;
e.luclin_hairstyle = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
e.luclin_haircolor = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
e.luclin_eyecolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
e.luclin_eyecolor2 = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
e.luclin_beardcolor = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
e.luclin_beard = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 0;
e.drakkin_heritage = row[39] ? static_cast<int32_t>(atoi(row[39])) : 0;
e.drakkin_tattoo = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
e.drakkin_details = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
e.armortint_id = row[42] ? static_cast<uint32_t>(strtoul(row[42], nullptr, 10)) : 0;
e.armortint_red = row[43] ? static_cast<uint8_t>(strtoul(row[43], nullptr, 10)) : 0;
e.armortint_green = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
e.armortint_blue = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
e.d_melee_texture1 = row[46] ? static_cast<uint32_t>(strtoul(row[46], nullptr, 10)) : 0;
e.d_melee_texture2 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
e.ammo_idfile = row[48] ? row[48] : "IT10";
e.prim_melee_type = row[49] ? static_cast<uint8_t>(strtoul(row[49], nullptr, 10)) : 28;
e.sec_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
e.ranged_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 7;
e.runspeed = row[52] ? strtof(row[52], nullptr) : 0;
e.MR = row[53] ? static_cast<int16_t>(atoi(row[53])) : 0;
e.CR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
e.DR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
e.FR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
e.PR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
e.Corrup = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
e.PhR = row[59] ? static_cast<uint16_t>(strtoul(row[59], nullptr, 10)) : 0;
e.see_invis = row[60] ? static_cast<int16_t>(atoi(row[60])) : 0;
e.see_invis_undead = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
e.qglobal = row[62] ? static_cast<uint32_t>(strtoul(row[62], nullptr, 10)) : 0;
e.AC = row[63] ? static_cast<int16_t>(atoi(row[63])) : 0;
e.npc_aggro = row[64] ? static_cast<int8_t>(atoi(row[64])) : 0;
e.spawn_limit = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
e.attack_speed = row[66] ? strtof(row[66], nullptr) : 0;
e.attack_delay = row[67] ? static_cast<uint8_t>(strtoul(row[67], nullptr, 10)) : 30;
e.findable = row[68] ? static_cast<int8_t>(atoi(row[68])) : 0;
e.STR = row[69] ? static_cast<uint32_t>(strtoul(row[69], nullptr, 10)) : 75;
e.STA = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
e.DEX = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
e.AGI = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
e._INT = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 80;
e.WIS = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 75;
e.CHA = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
e.see_hide = row[76] ? static_cast<int8_t>(atoi(row[76])) : 0;
e.see_improved_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
e.trackable = row[78] ? static_cast<int8_t>(atoi(row[78])) : 1;
e.isbot = row[79] ? static_cast<int8_t>(atoi(row[79])) : 0;
e.exclude = row[80] ? static_cast<int8_t>(atoi(row[80])) : 1;
e.ATK = row[81] ? static_cast<int32_t>(atoi(row[81])) : 0;
e.Accuracy = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
e.Avoidance = row[83] ? static_cast<uint32_t>(strtoul(row[83], nullptr, 10)) : 0;
e.slow_mitigation = row[84] ? static_cast<int16_t>(atoi(row[84])) : 0;
e.version = row[85] ? static_cast<uint16_t>(strtoul(row[85], nullptr, 10)) : 0;
e.maxlevel = row[86] ? static_cast<int8_t>(atoi(row[86])) : 0;
e.scalerate = row[87] ? static_cast<int32_t>(atoi(row[87])) : 100;
e.private_corpse = row[88] ? static_cast<uint8_t>(strtoul(row[88], nullptr, 10)) : 0;
e.unique_spawn_by_name = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
e.underwater = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
e.isquest = row[91] ? static_cast<int8_t>(atoi(row[91])) : 0;
e.emoteid = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 0;
e.spellscale = row[93] ? strtof(row[93], nullptr) : 100;
e.healscale = row[94] ? strtof(row[94], nullptr) : 100;
e.no_target_hotkey = row[95] ? static_cast<uint8_t>(strtoul(row[95], nullptr, 10)) : 0;
e.raid_target = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
e.armtexture = row[97] ? static_cast<int8_t>(atoi(row[97])) : 0;
e.bracertexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
e.handtexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
e.legtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
e.feettexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
e.light = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
e.walkspeed = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
e.peqid = row[104] ? static_cast<int32_t>(atoi(row[104])) : 0;
e.unique_ = row[105] ? static_cast<int8_t>(atoi(row[105])) : 0;
e.fixed = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
e.ignore_despawn = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
e.show_name = row[108] ? static_cast<int8_t>(atoi(row[108])) : 1;
e.untargetable = row[109] ? static_cast<int8_t>(atoi(row[109])) : 0;
e.charm_ac = row[110] ? static_cast<int16_t>(atoi(row[110])) : 0;
e.charm_min_dmg = row[111] ? static_cast<int32_t>(atoi(row[111])) : 0;
e.charm_max_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
e.charm_attack_delay = row[113] ? static_cast<int8_t>(atoi(row[113])) : 0;
e.charm_accuracy_rating = row[114] ? static_cast<int32_t>(atoi(row[114])) : 0;
e.charm_avoidance_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
e.charm_atk = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
e.skip_global_loot = row[117] ? static_cast<int8_t>(atoi(row[117])) : 0;
e.rare_spawn = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
e.stuck_behavior = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
e.model = row[120] ? static_cast<int16_t>(atoi(row[120])) : 0;
e.flymode = row[121] ? static_cast<int8_t>(atoi(row[121])) : -1;
e.always_aggro = row[122] ? static_cast<int8_t>(atoi(row[122])) : 0;
e.exp_mod = row[123] ? static_cast<int32_t>(atoi(row[123])) : 100;
e.heroic_strikethrough = row[124] ? static_cast<int32_t>(atoi(row[124])) : 0;
e.faction_amount = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
e.keeps_sold_items = row[126] ? static_cast<uint8_t>(strtoul(row[126], nullptr, 10)) : 1;
e.is_parcel_merchant = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 0;
e.greed = row[19] ? static_cast<uint8_t>(strtoul(row[19], nullptr, 10)) : 0;
e.alt_currency_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
e.npc_spells_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
e.npc_spells_effects_id = row[22] ? static_cast<uint32_t>(strtoul(row[22], nullptr, 10)) : 0;
e.npc_faction_id = row[23] ? static_cast<int32_t>(atoi(row[23])) : 0;
e.adventure_template_id = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
e.trap_template = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
e.mindmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
e.maxdmg = row[27] ? static_cast<uint32_t>(strtoul(row[27], nullptr, 10)) : 0;
e.attack_count = row[28] ? static_cast<int16_t>(atoi(row[28])) : -1;
e.npcspecialattks = row[29] ? row[29] : "";
e.special_abilities = row[30] ? row[30] : "";
e.aggroradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
e.assistradius = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 0;
e.face = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
e.luclin_hairstyle = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
e.luclin_haircolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
e.luclin_eyecolor = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
e.luclin_eyecolor2 = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
e.luclin_beardcolor = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 1;
e.luclin_beard = row[39] ? static_cast<uint32_t>(strtoul(row[39], nullptr, 10)) : 0;
e.drakkin_heritage = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
e.drakkin_tattoo = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
e.drakkin_details = row[42] ? static_cast<int32_t>(atoi(row[42])) : 0;
e.armortint_id = row[43] ? static_cast<uint32_t>(strtoul(row[43], nullptr, 10)) : 0;
e.armortint_red = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
e.armortint_green = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
e.armortint_blue = row[46] ? static_cast<uint8_t>(strtoul(row[46], nullptr, 10)) : 0;
e.d_melee_texture1 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
e.d_melee_texture2 = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0;
e.ammo_idfile = row[49] ? row[49] : "IT10";
e.prim_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
e.sec_melee_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 28;
e.ranged_type = row[52] ? static_cast<uint8_t>(strtoul(row[52], nullptr, 10)) : 7;
e.runspeed = row[53] ? strtof(row[53], nullptr) : 0;
e.MR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
e.CR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
e.DR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
e.FR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
e.PR = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
e.Corrup = row[59] ? static_cast<int16_t>(atoi(row[59])) : 0;
e.PhR = row[60] ? static_cast<uint16_t>(strtoul(row[60], nullptr, 10)) : 0;
e.see_invis = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
e.see_invis_undead = row[62] ? static_cast<int16_t>(atoi(row[62])) : 0;
e.qglobal = row[63] ? static_cast<uint32_t>(strtoul(row[63], nullptr, 10)) : 0;
e.AC = row[64] ? static_cast<int16_t>(atoi(row[64])) : 0;
e.npc_aggro = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
e.spawn_limit = row[66] ? static_cast<int8_t>(atoi(row[66])) : 0;
e.attack_speed = row[67] ? strtof(row[67], nullptr) : 0;
e.attack_delay = row[68] ? static_cast<uint8_t>(strtoul(row[68], nullptr, 10)) : 30;
e.findable = row[69] ? static_cast<int8_t>(atoi(row[69])) : 0;
e.STR = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
e.STA = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
e.DEX = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
e.AGI = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 75;
e._INT = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 80;
e.WIS = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
e.CHA = row[76] ? static_cast<uint32_t>(strtoul(row[76], nullptr, 10)) : 75;
e.see_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
e.see_improved_hide = row[78] ? static_cast<int8_t>(atoi(row[78])) : 0;
e.trackable = row[79] ? static_cast<int8_t>(atoi(row[79])) : 1;
e.isbot = row[80] ? static_cast<int8_t>(atoi(row[80])) : 0;
e.exclude = row[81] ? static_cast<int8_t>(atoi(row[81])) : 1;
e.ATK = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
e.Accuracy = row[83] ? static_cast<int32_t>(atoi(row[83])) : 0;
e.Avoidance = row[84] ? static_cast<uint32_t>(strtoul(row[84], nullptr, 10)) : 0;
e.slow_mitigation = row[85] ? static_cast<int16_t>(atoi(row[85])) : 0;
e.version = row[86] ? static_cast<uint16_t>(strtoul(row[86], nullptr, 10)) : 0;
e.maxlevel = row[87] ? static_cast<int8_t>(atoi(row[87])) : 0;
e.scalerate = row[88] ? static_cast<int32_t>(atoi(row[88])) : 100;
e.private_corpse = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
e.unique_spawn_by_name = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
e.underwater = row[91] ? static_cast<uint8_t>(strtoul(row[91], nullptr, 10)) : 0;
e.isquest = row[92] ? static_cast<int8_t>(atoi(row[92])) : 0;
e.emoteid = row[93] ? static_cast<uint32_t>(strtoul(row[93], nullptr, 10)) : 0;
e.spellscale = row[94] ? strtof(row[94], nullptr) : 100;
e.healscale = row[95] ? strtof(row[95], nullptr) : 100;
e.no_target_hotkey = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
e.raid_target = row[97] ? static_cast<uint8_t>(strtoul(row[97], nullptr, 10)) : 0;
e.armtexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
e.bracertexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
e.handtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
e.legtexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
e.feettexture = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
e.light = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
e.walkspeed = row[104] ? static_cast<int8_t>(atoi(row[104])) : 0;
e.peqid = row[105] ? static_cast<int32_t>(atoi(row[105])) : 0;
e.unique_ = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
e.fixed = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
e.ignore_despawn = row[108] ? static_cast<int8_t>(atoi(row[108])) : 0;
e.show_name = row[109] ? static_cast<int8_t>(atoi(row[109])) : 1;
e.untargetable = row[110] ? static_cast<int8_t>(atoi(row[110])) : 0;
e.charm_ac = row[111] ? static_cast<int16_t>(atoi(row[111])) : 0;
e.charm_min_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
e.charm_max_dmg = row[113] ? static_cast<int32_t>(atoi(row[113])) : 0;
e.charm_attack_delay = row[114] ? static_cast<int8_t>(atoi(row[114])) : 0;
e.charm_accuracy_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
e.charm_avoidance_rating = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
e.charm_atk = row[117] ? static_cast<int32_t>(atoi(row[117])) : 0;
e.skip_global_loot = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
e.rare_spawn = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
e.stuck_behavior = row[120] ? static_cast<int8_t>(atoi(row[120])) : 0;
e.model = row[121] ? static_cast<int16_t>(atoi(row[121])) : 0;
e.flymode = row[122] ? static_cast<int8_t>(atoi(row[122])) : -1;
e.always_aggro = row[123] ? static_cast<int8_t>(atoi(row[123])) : 0;
e.exp_mod = row[124] ? static_cast<int32_t>(atoi(row[124])) : 100;
e.heroic_strikethrough = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
return e;
}
@@ -802,115 +807,116 @@ public:
v.push_back(columns[16] + " = " + std::to_string(e.mana_regen_rate));
v.push_back(columns[17] + " = " + std::to_string(e.loottable_id));
v.push_back(columns[18] + " = " + std::to_string(e.merchant_id));
v.push_back(columns[19] + " = " + std::to_string(e.alt_currency_id));
v.push_back(columns[20] + " = " + std::to_string(e.npc_spells_id));
v.push_back(columns[21] + " = " + std::to_string(e.npc_spells_effects_id));
v.push_back(columns[22] + " = " + std::to_string(e.npc_faction_id));
v.push_back(columns[23] + " = " + std::to_string(e.adventure_template_id));
v.push_back(columns[24] + " = " + std::to_string(e.trap_template));
v.push_back(columns[25] + " = " + std::to_string(e.mindmg));
v.push_back(columns[26] + " = " + std::to_string(e.maxdmg));
v.push_back(columns[27] + " = " + std::to_string(e.attack_count));
v.push_back(columns[28] + " = '" + Strings::Escape(e.npcspecialattks) + "'");
v.push_back(columns[29] + " = '" + Strings::Escape(e.special_abilities) + "'");
v.push_back(columns[30] + " = " + std::to_string(e.aggroradius));
v.push_back(columns[31] + " = " + std::to_string(e.assistradius));
v.push_back(columns[32] + " = " + std::to_string(e.face));
v.push_back(columns[33] + " = " + std::to_string(e.luclin_hairstyle));
v.push_back(columns[34] + " = " + std::to_string(e.luclin_haircolor));
v.push_back(columns[35] + " = " + std::to_string(e.luclin_eyecolor));
v.push_back(columns[36] + " = " + std::to_string(e.luclin_eyecolor2));
v.push_back(columns[37] + " = " + std::to_string(e.luclin_beardcolor));
v.push_back(columns[38] + " = " + std::to_string(e.luclin_beard));
v.push_back(columns[39] + " = " + std::to_string(e.drakkin_heritage));
v.push_back(columns[40] + " = " + std::to_string(e.drakkin_tattoo));
v.push_back(columns[41] + " = " + std::to_string(e.drakkin_details));
v.push_back(columns[42] + " = " + std::to_string(e.armortint_id));
v.push_back(columns[43] + " = " + std::to_string(e.armortint_red));
v.push_back(columns[44] + " = " + std::to_string(e.armortint_green));
v.push_back(columns[45] + " = " + std::to_string(e.armortint_blue));
v.push_back(columns[46] + " = " + std::to_string(e.d_melee_texture1));
v.push_back(columns[47] + " = " + std::to_string(e.d_melee_texture2));
v.push_back(columns[48] + " = '" + Strings::Escape(e.ammo_idfile) + "'");
v.push_back(columns[49] + " = " + std::to_string(e.prim_melee_type));
v.push_back(columns[50] + " = " + std::to_string(e.sec_melee_type));
v.push_back(columns[51] + " = " + std::to_string(e.ranged_type));
v.push_back(columns[52] + " = " + std::to_string(e.runspeed));
v.push_back(columns[53] + " = " + std::to_string(e.MR));
v.push_back(columns[54] + " = " + std::to_string(e.CR));
v.push_back(columns[55] + " = " + std::to_string(e.DR));
v.push_back(columns[56] + " = " + std::to_string(e.FR));
v.push_back(columns[57] + " = " + std::to_string(e.PR));
v.push_back(columns[58] + " = " + std::to_string(e.Corrup));
v.push_back(columns[59] + " = " + std::to_string(e.PhR));
v.push_back(columns[60] + " = " + std::to_string(e.see_invis));
v.push_back(columns[61] + " = " + std::to_string(e.see_invis_undead));
v.push_back(columns[62] + " = " + std::to_string(e.qglobal));
v.push_back(columns[63] + " = " + std::to_string(e.AC));
v.push_back(columns[64] + " = " + std::to_string(e.npc_aggro));
v.push_back(columns[65] + " = " + std::to_string(e.spawn_limit));
v.push_back(columns[66] + " = " + std::to_string(e.attack_speed));
v.push_back(columns[67] + " = " + std::to_string(e.attack_delay));
v.push_back(columns[68] + " = " + std::to_string(e.findable));
v.push_back(columns[69] + " = " + std::to_string(e.STR));
v.push_back(columns[70] + " = " + std::to_string(e.STA));
v.push_back(columns[71] + " = " + std::to_string(e.DEX));
v.push_back(columns[72] + " = " + std::to_string(e.AGI));
v.push_back(columns[73] + " = " + std::to_string(e._INT));
v.push_back(columns[74] + " = " + std::to_string(e.WIS));
v.push_back(columns[75] + " = " + std::to_string(e.CHA));
v.push_back(columns[76] + " = " + std::to_string(e.see_hide));
v.push_back(columns[77] + " = " + std::to_string(e.see_improved_hide));
v.push_back(columns[78] + " = " + std::to_string(e.trackable));
v.push_back(columns[79] + " = " + std::to_string(e.isbot));
v.push_back(columns[80] + " = " + std::to_string(e.exclude));
v.push_back(columns[81] + " = " + std::to_string(e.ATK));
v.push_back(columns[82] + " = " + std::to_string(e.Accuracy));
v.push_back(columns[83] + " = " + std::to_string(e.Avoidance));
v.push_back(columns[84] + " = " + std::to_string(e.slow_mitigation));
v.push_back(columns[85] + " = " + std::to_string(e.version));
v.push_back(columns[86] + " = " + std::to_string(e.maxlevel));
v.push_back(columns[87] + " = " + std::to_string(e.scalerate));
v.push_back(columns[88] + " = " + std::to_string(e.private_corpse));
v.push_back(columns[89] + " = " + std::to_string(e.unique_spawn_by_name));
v.push_back(columns[90] + " = " + std::to_string(e.underwater));
v.push_back(columns[91] + " = " + std::to_string(e.isquest));
v.push_back(columns[92] + " = " + std::to_string(e.emoteid));
v.push_back(columns[93] + " = " + std::to_string(e.spellscale));
v.push_back(columns[94] + " = " + std::to_string(e.healscale));
v.push_back(columns[95] + " = " + std::to_string(e.no_target_hotkey));
v.push_back(columns[96] + " = " + std::to_string(e.raid_target));
v.push_back(columns[97] + " = " + std::to_string(e.armtexture));
v.push_back(columns[98] + " = " + std::to_string(e.bracertexture));
v.push_back(columns[99] + " = " + std::to_string(e.handtexture));
v.push_back(columns[100] + " = " + std::to_string(e.legtexture));
v.push_back(columns[101] + " = " + std::to_string(e.feettexture));
v.push_back(columns[102] + " = " + std::to_string(e.light));
v.push_back(columns[103] + " = " + std::to_string(e.walkspeed));
v.push_back(columns[104] + " = " + std::to_string(e.peqid));
v.push_back(columns[105] + " = " + std::to_string(e.unique_));
v.push_back(columns[106] + " = " + std::to_string(e.fixed));
v.push_back(columns[107] + " = " + std::to_string(e.ignore_despawn));
v.push_back(columns[108] + " = " + std::to_string(e.show_name));
v.push_back(columns[109] + " = " + std::to_string(e.untargetable));
v.push_back(columns[110] + " = " + std::to_string(e.charm_ac));
v.push_back(columns[111] + " = " + std::to_string(e.charm_min_dmg));
v.push_back(columns[112] + " = " + std::to_string(e.charm_max_dmg));
v.push_back(columns[113] + " = " + std::to_string(e.charm_attack_delay));
v.push_back(columns[114] + " = " + std::to_string(e.charm_accuracy_rating));
v.push_back(columns[115] + " = " + std::to_string(e.charm_avoidance_rating));
v.push_back(columns[116] + " = " + std::to_string(e.charm_atk));
v.push_back(columns[117] + " = " + std::to_string(e.skip_global_loot));
v.push_back(columns[118] + " = " + std::to_string(e.rare_spawn));
v.push_back(columns[119] + " = " + std::to_string(e.stuck_behavior));
v.push_back(columns[120] + " = " + std::to_string(e.model));
v.push_back(columns[121] + " = " + std::to_string(e.flymode));
v.push_back(columns[122] + " = " + std::to_string(e.always_aggro));
v.push_back(columns[123] + " = " + std::to_string(e.exp_mod));
v.push_back(columns[124] + " = " + std::to_string(e.heroic_strikethrough));
v.push_back(columns[125] + " = " + std::to_string(e.faction_amount));
v.push_back(columns[126] + " = " + std::to_string(e.keeps_sold_items));
v.push_back(columns[127] + " = " + std::to_string(e.is_parcel_merchant));
v.push_back(columns[19] + " = " + std::to_string(e.greed));
v.push_back(columns[20] + " = " + std::to_string(e.alt_currency_id));
v.push_back(columns[21] + " = " + std::to_string(e.npc_spells_id));
v.push_back(columns[22] + " = " + std::to_string(e.npc_spells_effects_id));
v.push_back(columns[23] + " = " + std::to_string(e.npc_faction_id));
v.push_back(columns[24] + " = " + std::to_string(e.adventure_template_id));
v.push_back(columns[25] + " = " + std::to_string(e.trap_template));
v.push_back(columns[26] + " = " + std::to_string(e.mindmg));
v.push_back(columns[27] + " = " + std::to_string(e.maxdmg));
v.push_back(columns[28] + " = " + std::to_string(e.attack_count));
v.push_back(columns[29] + " = '" + Strings::Escape(e.npcspecialattks) + "'");
v.push_back(columns[30] + " = '" + Strings::Escape(e.special_abilities) + "'");
v.push_back(columns[31] + " = " + std::to_string(e.aggroradius));
v.push_back(columns[32] + " = " + std::to_string(e.assistradius));
v.push_back(columns[33] + " = " + std::to_string(e.face));
v.push_back(columns[34] + " = " + std::to_string(e.luclin_hairstyle));
v.push_back(columns[35] + " = " + std::to_string(e.luclin_haircolor));
v.push_back(columns[36] + " = " + std::to_string(e.luclin_eyecolor));
v.push_back(columns[37] + " = " + std::to_string(e.luclin_eyecolor2));
v.push_back(columns[38] + " = " + std::to_string(e.luclin_beardcolor));
v.push_back(columns[39] + " = " + std::to_string(e.luclin_beard));
v.push_back(columns[40] + " = " + std::to_string(e.drakkin_heritage));
v.push_back(columns[41] + " = " + std::to_string(e.drakkin_tattoo));
v.push_back(columns[42] + " = " + std::to_string(e.drakkin_details));
v.push_back(columns[43] + " = " + std::to_string(e.armortint_id));
v.push_back(columns[44] + " = " + std::to_string(e.armortint_red));
v.push_back(columns[45] + " = " + std::to_string(e.armortint_green));
v.push_back(columns[46] + " = " + std::to_string(e.armortint_blue));
v.push_back(columns[47] + " = " + std::to_string(e.d_melee_texture1));
v.push_back(columns[48] + " = " + std::to_string(e.d_melee_texture2));
v.push_back(columns[49] + " = '" + Strings::Escape(e.ammo_idfile) + "'");
v.push_back(columns[50] + " = " + std::to_string(e.prim_melee_type));
v.push_back(columns[51] + " = " + std::to_string(e.sec_melee_type));
v.push_back(columns[52] + " = " + std::to_string(e.ranged_type));
v.push_back(columns[53] + " = " + std::to_string(e.runspeed));
v.push_back(columns[54] + " = " + std::to_string(e.MR));
v.push_back(columns[55] + " = " + std::to_string(e.CR));
v.push_back(columns[56] + " = " + std::to_string(e.DR));
v.push_back(columns[57] + " = " + std::to_string(e.FR));
v.push_back(columns[58] + " = " + std::to_string(e.PR));
v.push_back(columns[59] + " = " + std::to_string(e.Corrup));
v.push_back(columns[60] + " = " + std::to_string(e.PhR));
v.push_back(columns[61] + " = " + std::to_string(e.see_invis));
v.push_back(columns[62] + " = " + std::to_string(e.see_invis_undead));
v.push_back(columns[63] + " = " + std::to_string(e.qglobal));
v.push_back(columns[64] + " = " + std::to_string(e.AC));
v.push_back(columns[65] + " = " + std::to_string(e.npc_aggro));
v.push_back(columns[66] + " = " + std::to_string(e.spawn_limit));
v.push_back(columns[67] + " = " + std::to_string(e.attack_speed));
v.push_back(columns[68] + " = " + std::to_string(e.attack_delay));
v.push_back(columns[69] + " = " + std::to_string(e.findable));
v.push_back(columns[70] + " = " + std::to_string(e.STR));
v.push_back(columns[71] + " = " + std::to_string(e.STA));
v.push_back(columns[72] + " = " + std::to_string(e.DEX));
v.push_back(columns[73] + " = " + std::to_string(e.AGI));
v.push_back(columns[74] + " = " + std::to_string(e._INT));
v.push_back(columns[75] + " = " + std::to_string(e.WIS));
v.push_back(columns[76] + " = " + std::to_string(e.CHA));
v.push_back(columns[77] + " = " + std::to_string(e.see_hide));
v.push_back(columns[78] + " = " + std::to_string(e.see_improved_hide));
v.push_back(columns[79] + " = " + std::to_string(e.trackable));
v.push_back(columns[80] + " = " + std::to_string(e.isbot));
v.push_back(columns[81] + " = " + std::to_string(e.exclude));
v.push_back(columns[82] + " = " + std::to_string(e.ATK));
v.push_back(columns[83] + " = " + std::to_string(e.Accuracy));
v.push_back(columns[84] + " = " + std::to_string(e.Avoidance));
v.push_back(columns[85] + " = " + std::to_string(e.slow_mitigation));
v.push_back(columns[86] + " = " + std::to_string(e.version));
v.push_back(columns[87] + " = " + std::to_string(e.maxlevel));
v.push_back(columns[88] + " = " + std::to_string(e.scalerate));
v.push_back(columns[89] + " = " + std::to_string(e.private_corpse));
v.push_back(columns[90] + " = " + std::to_string(e.unique_spawn_by_name));
v.push_back(columns[91] + " = " + std::to_string(e.underwater));
v.push_back(columns[92] + " = " + std::to_string(e.isquest));
v.push_back(columns[93] + " = " + std::to_string(e.emoteid));
v.push_back(columns[94] + " = " + std::to_string(e.spellscale));
v.push_back(columns[95] + " = " + std::to_string(e.healscale));
v.push_back(columns[96] + " = " + std::to_string(e.no_target_hotkey));
v.push_back(columns[97] + " = " + std::to_string(e.raid_target));
v.push_back(columns[98] + " = " + std::to_string(e.armtexture));
v.push_back(columns[99] + " = " + std::to_string(e.bracertexture));
v.push_back(columns[100] + " = " + std::to_string(e.handtexture));
v.push_back(columns[101] + " = " + std::to_string(e.legtexture));
v.push_back(columns[102] + " = " + std::to_string(e.feettexture));
v.push_back(columns[103] + " = " + std::to_string(e.light));
v.push_back(columns[104] + " = " + std::to_string(e.walkspeed));
v.push_back(columns[105] + " = " + std::to_string(e.peqid));
v.push_back(columns[106] + " = " + std::to_string(e.unique_));
v.push_back(columns[107] + " = " + std::to_string(e.fixed));
v.push_back(columns[108] + " = " + std::to_string(e.ignore_despawn));
v.push_back(columns[109] + " = " + std::to_string(e.show_name));
v.push_back(columns[110] + " = " + std::to_string(e.untargetable));
v.push_back(columns[111] + " = " + std::to_string(e.charm_ac));
v.push_back(columns[112] + " = " + std::to_string(e.charm_min_dmg));
v.push_back(columns[113] + " = " + std::to_string(e.charm_max_dmg));
v.push_back(columns[114] + " = " + std::to_string(e.charm_attack_delay));
v.push_back(columns[115] + " = " + std::to_string(e.charm_accuracy_rating));
v.push_back(columns[116] + " = " + std::to_string(e.charm_avoidance_rating));
v.push_back(columns[117] + " = " + std::to_string(e.charm_atk));
v.push_back(columns[118] + " = " + std::to_string(e.skip_global_loot));
v.push_back(columns[119] + " = " + std::to_string(e.rare_spawn));
v.push_back(columns[120] + " = " + std::to_string(e.stuck_behavior));
v.push_back(columns[121] + " = " + std::to_string(e.model));
v.push_back(columns[122] + " = " + std::to_string(e.flymode));
v.push_back(columns[123] + " = " + std::to_string(e.always_aggro));
v.push_back(columns[124] + " = " + std::to_string(e.exp_mod));
v.push_back(columns[125] + " = " + std::to_string(e.heroic_strikethrough));
v.push_back(columns[126] + " = " + std::to_string(e.faction_amount));
v.push_back(columns[127] + " = " + std::to_string(e.keeps_sold_items));
v.push_back(columns[128] + " = " + std::to_string(e.is_parcel_merchant));
auto results = db.QueryDatabase(
fmt::format(
@@ -951,6 +957,7 @@ public:
v.push_back(std::to_string(e.mana_regen_rate));
v.push_back(std::to_string(e.loottable_id));
v.push_back(std::to_string(e.merchant_id));
v.push_back(std::to_string(e.greed));
v.push_back(std::to_string(e.alt_currency_id));
v.push_back(std::to_string(e.npc_spells_id));
v.push_back(std::to_string(e.npc_spells_effects_id));
@@ -1108,6 +1115,7 @@ public:
v.push_back(std::to_string(e.mana_regen_rate));
v.push_back(std::to_string(e.loottable_id));
v.push_back(std::to_string(e.merchant_id));
v.push_back(std::to_string(e.greed));
v.push_back(std::to_string(e.alt_currency_id));
v.push_back(std::to_string(e.npc_spells_id));
v.push_back(std::to_string(e.npc_spells_effects_id));
@@ -1269,115 +1277,116 @@ public:
e.mana_regen_rate = row[16] ? strtoll(row[16], nullptr, 10) : 0;
e.loottable_id = row[17] ? static_cast<uint32_t>(strtoul(row[17], nullptr, 10)) : 0;
e.merchant_id = row[18] ? static_cast<uint32_t>(strtoul(row[18], nullptr, 10)) : 0;
e.alt_currency_id = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
e.npc_spells_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
e.npc_spells_effects_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
e.npc_faction_id = row[22] ? static_cast<int32_t>(atoi(row[22])) : 0;
e.adventure_template_id = row[23] ? static_cast<uint32_t>(strtoul(row[23], nullptr, 10)) : 0;
e.trap_template = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
e.mindmg = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
e.maxdmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
e.attack_count = row[27] ? static_cast<int16_t>(atoi(row[27])) : -1;
e.npcspecialattks = row[28] ? row[28] : "";
e.special_abilities = row[29] ? row[29] : "";
e.aggroradius = row[30] ? static_cast<uint32_t>(strtoul(row[30], nullptr, 10)) : 0;
e.assistradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
e.face = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 1;
e.luclin_hairstyle = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
e.luclin_haircolor = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
e.luclin_eyecolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
e.luclin_eyecolor2 = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
e.luclin_beardcolor = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
e.luclin_beard = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 0;
e.drakkin_heritage = row[39] ? static_cast<int32_t>(atoi(row[39])) : 0;
e.drakkin_tattoo = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
e.drakkin_details = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
e.armortint_id = row[42] ? static_cast<uint32_t>(strtoul(row[42], nullptr, 10)) : 0;
e.armortint_red = row[43] ? static_cast<uint8_t>(strtoul(row[43], nullptr, 10)) : 0;
e.armortint_green = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
e.armortint_blue = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
e.d_melee_texture1 = row[46] ? static_cast<uint32_t>(strtoul(row[46], nullptr, 10)) : 0;
e.d_melee_texture2 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
e.ammo_idfile = row[48] ? row[48] : "IT10";
e.prim_melee_type = row[49] ? static_cast<uint8_t>(strtoul(row[49], nullptr, 10)) : 28;
e.sec_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
e.ranged_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 7;
e.runspeed = row[52] ? strtof(row[52], nullptr) : 0;
e.MR = row[53] ? static_cast<int16_t>(atoi(row[53])) : 0;
e.CR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
e.DR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
e.FR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
e.PR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
e.Corrup = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
e.PhR = row[59] ? static_cast<uint16_t>(strtoul(row[59], nullptr, 10)) : 0;
e.see_invis = row[60] ? static_cast<int16_t>(atoi(row[60])) : 0;
e.see_invis_undead = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
e.qglobal = row[62] ? static_cast<uint32_t>(strtoul(row[62], nullptr, 10)) : 0;
e.AC = row[63] ? static_cast<int16_t>(atoi(row[63])) : 0;
e.npc_aggro = row[64] ? static_cast<int8_t>(atoi(row[64])) : 0;
e.spawn_limit = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
e.attack_speed = row[66] ? strtof(row[66], nullptr) : 0;
e.attack_delay = row[67] ? static_cast<uint8_t>(strtoul(row[67], nullptr, 10)) : 30;
e.findable = row[68] ? static_cast<int8_t>(atoi(row[68])) : 0;
e.STR = row[69] ? static_cast<uint32_t>(strtoul(row[69], nullptr, 10)) : 75;
e.STA = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
e.DEX = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
e.AGI = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
e._INT = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 80;
e.WIS = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 75;
e.CHA = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
e.see_hide = row[76] ? static_cast<int8_t>(atoi(row[76])) : 0;
e.see_improved_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
e.trackable = row[78] ? static_cast<int8_t>(atoi(row[78])) : 1;
e.isbot = row[79] ? static_cast<int8_t>(atoi(row[79])) : 0;
e.exclude = row[80] ? static_cast<int8_t>(atoi(row[80])) : 1;
e.ATK = row[81] ? static_cast<int32_t>(atoi(row[81])) : 0;
e.Accuracy = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
e.Avoidance = row[83] ? static_cast<uint32_t>(strtoul(row[83], nullptr, 10)) : 0;
e.slow_mitigation = row[84] ? static_cast<int16_t>(atoi(row[84])) : 0;
e.version = row[85] ? static_cast<uint16_t>(strtoul(row[85], nullptr, 10)) : 0;
e.maxlevel = row[86] ? static_cast<int8_t>(atoi(row[86])) : 0;
e.scalerate = row[87] ? static_cast<int32_t>(atoi(row[87])) : 100;
e.private_corpse = row[88] ? static_cast<uint8_t>(strtoul(row[88], nullptr, 10)) : 0;
e.unique_spawn_by_name = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
e.underwater = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
e.isquest = row[91] ? static_cast<int8_t>(atoi(row[91])) : 0;
e.emoteid = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 0;
e.spellscale = row[93] ? strtof(row[93], nullptr) : 100;
e.healscale = row[94] ? strtof(row[94], nullptr) : 100;
e.no_target_hotkey = row[95] ? static_cast<uint8_t>(strtoul(row[95], nullptr, 10)) : 0;
e.raid_target = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
e.armtexture = row[97] ? static_cast<int8_t>(atoi(row[97])) : 0;
e.bracertexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
e.handtexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
e.legtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
e.feettexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
e.light = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
e.walkspeed = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
e.peqid = row[104] ? static_cast<int32_t>(atoi(row[104])) : 0;
e.unique_ = row[105] ? static_cast<int8_t>(atoi(row[105])) : 0;
e.fixed = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
e.ignore_despawn = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
e.show_name = row[108] ? static_cast<int8_t>(atoi(row[108])) : 1;
e.untargetable = row[109] ? static_cast<int8_t>(atoi(row[109])) : 0;
e.charm_ac = row[110] ? static_cast<int16_t>(atoi(row[110])) : 0;
e.charm_min_dmg = row[111] ? static_cast<int32_t>(atoi(row[111])) : 0;
e.charm_max_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
e.charm_attack_delay = row[113] ? static_cast<int8_t>(atoi(row[113])) : 0;
e.charm_accuracy_rating = row[114] ? static_cast<int32_t>(atoi(row[114])) : 0;
e.charm_avoidance_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
e.charm_atk = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
e.skip_global_loot = row[117] ? static_cast<int8_t>(atoi(row[117])) : 0;
e.rare_spawn = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
e.stuck_behavior = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
e.model = row[120] ? static_cast<int16_t>(atoi(row[120])) : 0;
e.flymode = row[121] ? static_cast<int8_t>(atoi(row[121])) : -1;
e.always_aggro = row[122] ? static_cast<int8_t>(atoi(row[122])) : 0;
e.exp_mod = row[123] ? static_cast<int32_t>(atoi(row[123])) : 100;
e.heroic_strikethrough = row[124] ? static_cast<int32_t>(atoi(row[124])) : 0;
e.faction_amount = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
e.keeps_sold_items = row[126] ? static_cast<uint8_t>(strtoul(row[126], nullptr, 10)) : 1;
e.is_parcel_merchant = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 0;
e.greed = row[19] ? static_cast<uint8_t>(strtoul(row[19], nullptr, 10)) : 0;
e.alt_currency_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
e.npc_spells_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
e.npc_spells_effects_id = row[22] ? static_cast<uint32_t>(strtoul(row[22], nullptr, 10)) : 0;
e.npc_faction_id = row[23] ? static_cast<int32_t>(atoi(row[23])) : 0;
e.adventure_template_id = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
e.trap_template = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
e.mindmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
e.maxdmg = row[27] ? static_cast<uint32_t>(strtoul(row[27], nullptr, 10)) : 0;
e.attack_count = row[28] ? static_cast<int16_t>(atoi(row[28])) : -1;
e.npcspecialattks = row[29] ? row[29] : "";
e.special_abilities = row[30] ? row[30] : "";
e.aggroradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
e.assistradius = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 0;
e.face = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
e.luclin_hairstyle = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
e.luclin_haircolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
e.luclin_eyecolor = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
e.luclin_eyecolor2 = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
e.luclin_beardcolor = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 1;
e.luclin_beard = row[39] ? static_cast<uint32_t>(strtoul(row[39], nullptr, 10)) : 0;
e.drakkin_heritage = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
e.drakkin_tattoo = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
e.drakkin_details = row[42] ? static_cast<int32_t>(atoi(row[42])) : 0;
e.armortint_id = row[43] ? static_cast<uint32_t>(strtoul(row[43], nullptr, 10)) : 0;
e.armortint_red = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
e.armortint_green = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
e.armortint_blue = row[46] ? static_cast<uint8_t>(strtoul(row[46], nullptr, 10)) : 0;
e.d_melee_texture1 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
e.d_melee_texture2 = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0;
e.ammo_idfile = row[49] ? row[49] : "IT10";
e.prim_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
e.sec_melee_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 28;
e.ranged_type = row[52] ? static_cast<uint8_t>(strtoul(row[52], nullptr, 10)) : 7;
e.runspeed = row[53] ? strtof(row[53], nullptr) : 0;
e.MR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
e.CR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
e.DR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
e.FR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
e.PR = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
e.Corrup = row[59] ? static_cast<int16_t>(atoi(row[59])) : 0;
e.PhR = row[60] ? static_cast<uint16_t>(strtoul(row[60], nullptr, 10)) : 0;
e.see_invis = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
e.see_invis_undead = row[62] ? static_cast<int16_t>(atoi(row[62])) : 0;
e.qglobal = row[63] ? static_cast<uint32_t>(strtoul(row[63], nullptr, 10)) : 0;
e.AC = row[64] ? static_cast<int16_t>(atoi(row[64])) : 0;
e.npc_aggro = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
e.spawn_limit = row[66] ? static_cast<int8_t>(atoi(row[66])) : 0;
e.attack_speed = row[67] ? strtof(row[67], nullptr) : 0;
e.attack_delay = row[68] ? static_cast<uint8_t>(strtoul(row[68], nullptr, 10)) : 30;
e.findable = row[69] ? static_cast<int8_t>(atoi(row[69])) : 0;
e.STR = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
e.STA = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
e.DEX = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
e.AGI = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 75;
e._INT = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 80;
e.WIS = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
e.CHA = row[76] ? static_cast<uint32_t>(strtoul(row[76], nullptr, 10)) : 75;
e.see_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
e.see_improved_hide = row[78] ? static_cast<int8_t>(atoi(row[78])) : 0;
e.trackable = row[79] ? static_cast<int8_t>(atoi(row[79])) : 1;
e.isbot = row[80] ? static_cast<int8_t>(atoi(row[80])) : 0;
e.exclude = row[81] ? static_cast<int8_t>(atoi(row[81])) : 1;
e.ATK = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
e.Accuracy = row[83] ? static_cast<int32_t>(atoi(row[83])) : 0;
e.Avoidance = row[84] ? static_cast<uint32_t>(strtoul(row[84], nullptr, 10)) : 0;
e.slow_mitigation = row[85] ? static_cast<int16_t>(atoi(row[85])) : 0;
e.version = row[86] ? static_cast<uint16_t>(strtoul(row[86], nullptr, 10)) : 0;
e.maxlevel = row[87] ? static_cast<int8_t>(atoi(row[87])) : 0;
e.scalerate = row[88] ? static_cast<int32_t>(atoi(row[88])) : 100;
e.private_corpse = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
e.unique_spawn_by_name = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
e.underwater = row[91] ? static_cast<uint8_t>(strtoul(row[91], nullptr, 10)) : 0;
e.isquest = row[92] ? static_cast<int8_t>(atoi(row[92])) : 0;
e.emoteid = row[93] ? static_cast<uint32_t>(strtoul(row[93], nullptr, 10)) : 0;
e.spellscale = row[94] ? strtof(row[94], nullptr) : 100;
e.healscale = row[95] ? strtof(row[95], nullptr) : 100;
e.no_target_hotkey = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
e.raid_target = row[97] ? static_cast<uint8_t>(strtoul(row[97], nullptr, 10)) : 0;
e.armtexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
e.bracertexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
e.handtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
e.legtexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
e.feettexture = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
e.light = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
e.walkspeed = row[104] ? static_cast<int8_t>(atoi(row[104])) : 0;
e.peqid = row[105] ? static_cast<int32_t>(atoi(row[105])) : 0;
e.unique_ = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
e.fixed = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
e.ignore_despawn = row[108] ? static_cast<int8_t>(atoi(row[108])) : 0;
e.show_name = row[109] ? static_cast<int8_t>(atoi(row[109])) : 1;
e.untargetable = row[110] ? static_cast<int8_t>(atoi(row[110])) : 0;
e.charm_ac = row[111] ? static_cast<int16_t>(atoi(row[111])) : 0;
e.charm_min_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
e.charm_max_dmg = row[113] ? static_cast<int32_t>(atoi(row[113])) : 0;
e.charm_attack_delay = row[114] ? static_cast<int8_t>(atoi(row[114])) : 0;
e.charm_accuracy_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
e.charm_avoidance_rating = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
e.charm_atk = row[117] ? static_cast<int32_t>(atoi(row[117])) : 0;
e.skip_global_loot = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
e.rare_spawn = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
e.stuck_behavior = row[120] ? static_cast<int8_t>(atoi(row[120])) : 0;
e.model = row[121] ? static_cast<int16_t>(atoi(row[121])) : 0;
e.flymode = row[122] ? static_cast<int8_t>(atoi(row[122])) : -1;
e.always_aggro = row[123] ? static_cast<int8_t>(atoi(row[123])) : 0;
e.exp_mod = row[124] ? static_cast<int32_t>(atoi(row[124])) : 100;
e.heroic_strikethrough = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -1421,115 +1430,116 @@ public:
e.mana_regen_rate = row[16] ? strtoll(row[16], nullptr, 10) : 0;
e.loottable_id = row[17] ? static_cast<uint32_t>(strtoul(row[17], nullptr, 10)) : 0;
e.merchant_id = row[18] ? static_cast<uint32_t>(strtoul(row[18], nullptr, 10)) : 0;
e.alt_currency_id = row[19] ? static_cast<uint32_t>(strtoul(row[19], nullptr, 10)) : 0;
e.npc_spells_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
e.npc_spells_effects_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
e.npc_faction_id = row[22] ? static_cast<int32_t>(atoi(row[22])) : 0;
e.adventure_template_id = row[23] ? static_cast<uint32_t>(strtoul(row[23], nullptr, 10)) : 0;
e.trap_template = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
e.mindmg = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
e.maxdmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
e.attack_count = row[27] ? static_cast<int16_t>(atoi(row[27])) : -1;
e.npcspecialattks = row[28] ? row[28] : "";
e.special_abilities = row[29] ? row[29] : "";
e.aggroradius = row[30] ? static_cast<uint32_t>(strtoul(row[30], nullptr, 10)) : 0;
e.assistradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
e.face = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 1;
e.luclin_hairstyle = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
e.luclin_haircolor = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
e.luclin_eyecolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
e.luclin_eyecolor2 = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
e.luclin_beardcolor = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
e.luclin_beard = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 0;
e.drakkin_heritage = row[39] ? static_cast<int32_t>(atoi(row[39])) : 0;
e.drakkin_tattoo = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
e.drakkin_details = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
e.armortint_id = row[42] ? static_cast<uint32_t>(strtoul(row[42], nullptr, 10)) : 0;
e.armortint_red = row[43] ? static_cast<uint8_t>(strtoul(row[43], nullptr, 10)) : 0;
e.armortint_green = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
e.armortint_blue = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
e.d_melee_texture1 = row[46] ? static_cast<uint32_t>(strtoul(row[46], nullptr, 10)) : 0;
e.d_melee_texture2 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
e.ammo_idfile = row[48] ? row[48] : "IT10";
e.prim_melee_type = row[49] ? static_cast<uint8_t>(strtoul(row[49], nullptr, 10)) : 28;
e.sec_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
e.ranged_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 7;
e.runspeed = row[52] ? strtof(row[52], nullptr) : 0;
e.MR = row[53] ? static_cast<int16_t>(atoi(row[53])) : 0;
e.CR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
e.DR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
e.FR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
e.PR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
e.Corrup = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
e.PhR = row[59] ? static_cast<uint16_t>(strtoul(row[59], nullptr, 10)) : 0;
e.see_invis = row[60] ? static_cast<int16_t>(atoi(row[60])) : 0;
e.see_invis_undead = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
e.qglobal = row[62] ? static_cast<uint32_t>(strtoul(row[62], nullptr, 10)) : 0;
e.AC = row[63] ? static_cast<int16_t>(atoi(row[63])) : 0;
e.npc_aggro = row[64] ? static_cast<int8_t>(atoi(row[64])) : 0;
e.spawn_limit = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
e.attack_speed = row[66] ? strtof(row[66], nullptr) : 0;
e.attack_delay = row[67] ? static_cast<uint8_t>(strtoul(row[67], nullptr, 10)) : 30;
e.findable = row[68] ? static_cast<int8_t>(atoi(row[68])) : 0;
e.STR = row[69] ? static_cast<uint32_t>(strtoul(row[69], nullptr, 10)) : 75;
e.STA = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
e.DEX = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
e.AGI = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
e._INT = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 80;
e.WIS = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 75;
e.CHA = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
e.see_hide = row[76] ? static_cast<int8_t>(atoi(row[76])) : 0;
e.see_improved_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
e.trackable = row[78] ? static_cast<int8_t>(atoi(row[78])) : 1;
e.isbot = row[79] ? static_cast<int8_t>(atoi(row[79])) : 0;
e.exclude = row[80] ? static_cast<int8_t>(atoi(row[80])) : 1;
e.ATK = row[81] ? static_cast<int32_t>(atoi(row[81])) : 0;
e.Accuracy = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
e.Avoidance = row[83] ? static_cast<uint32_t>(strtoul(row[83], nullptr, 10)) : 0;
e.slow_mitigation = row[84] ? static_cast<int16_t>(atoi(row[84])) : 0;
e.version = row[85] ? static_cast<uint16_t>(strtoul(row[85], nullptr, 10)) : 0;
e.maxlevel = row[86] ? static_cast<int8_t>(atoi(row[86])) : 0;
e.scalerate = row[87] ? static_cast<int32_t>(atoi(row[87])) : 100;
e.private_corpse = row[88] ? static_cast<uint8_t>(strtoul(row[88], nullptr, 10)) : 0;
e.unique_spawn_by_name = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
e.underwater = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
e.isquest = row[91] ? static_cast<int8_t>(atoi(row[91])) : 0;
e.emoteid = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 0;
e.spellscale = row[93] ? strtof(row[93], nullptr) : 100;
e.healscale = row[94] ? strtof(row[94], nullptr) : 100;
e.no_target_hotkey = row[95] ? static_cast<uint8_t>(strtoul(row[95], nullptr, 10)) : 0;
e.raid_target = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
e.armtexture = row[97] ? static_cast<int8_t>(atoi(row[97])) : 0;
e.bracertexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
e.handtexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
e.legtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
e.feettexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
e.light = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
e.walkspeed = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
e.peqid = row[104] ? static_cast<int32_t>(atoi(row[104])) : 0;
e.unique_ = row[105] ? static_cast<int8_t>(atoi(row[105])) : 0;
e.fixed = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
e.ignore_despawn = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
e.show_name = row[108] ? static_cast<int8_t>(atoi(row[108])) : 1;
e.untargetable = row[109] ? static_cast<int8_t>(atoi(row[109])) : 0;
e.charm_ac = row[110] ? static_cast<int16_t>(atoi(row[110])) : 0;
e.charm_min_dmg = row[111] ? static_cast<int32_t>(atoi(row[111])) : 0;
e.charm_max_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
e.charm_attack_delay = row[113] ? static_cast<int8_t>(atoi(row[113])) : 0;
e.charm_accuracy_rating = row[114] ? static_cast<int32_t>(atoi(row[114])) : 0;
e.charm_avoidance_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
e.charm_atk = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
e.skip_global_loot = row[117] ? static_cast<int8_t>(atoi(row[117])) : 0;
e.rare_spawn = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
e.stuck_behavior = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
e.model = row[120] ? static_cast<int16_t>(atoi(row[120])) : 0;
e.flymode = row[121] ? static_cast<int8_t>(atoi(row[121])) : -1;
e.always_aggro = row[122] ? static_cast<int8_t>(atoi(row[122])) : 0;
e.exp_mod = row[123] ? static_cast<int32_t>(atoi(row[123])) : 100;
e.heroic_strikethrough = row[124] ? static_cast<int32_t>(atoi(row[124])) : 0;
e.faction_amount = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
e.keeps_sold_items = row[126] ? static_cast<uint8_t>(strtoul(row[126], nullptr, 10)) : 1;
e.is_parcel_merchant = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 0;
e.greed = row[19] ? static_cast<uint8_t>(strtoul(row[19], nullptr, 10)) : 0;
e.alt_currency_id = row[20] ? static_cast<uint32_t>(strtoul(row[20], nullptr, 10)) : 0;
e.npc_spells_id = row[21] ? static_cast<uint32_t>(strtoul(row[21], nullptr, 10)) : 0;
e.npc_spells_effects_id = row[22] ? static_cast<uint32_t>(strtoul(row[22], nullptr, 10)) : 0;
e.npc_faction_id = row[23] ? static_cast<int32_t>(atoi(row[23])) : 0;
e.adventure_template_id = row[24] ? static_cast<uint32_t>(strtoul(row[24], nullptr, 10)) : 0;
e.trap_template = row[25] ? static_cast<uint32_t>(strtoul(row[25], nullptr, 10)) : 0;
e.mindmg = row[26] ? static_cast<uint32_t>(strtoul(row[26], nullptr, 10)) : 0;
e.maxdmg = row[27] ? static_cast<uint32_t>(strtoul(row[27], nullptr, 10)) : 0;
e.attack_count = row[28] ? static_cast<int16_t>(atoi(row[28])) : -1;
e.npcspecialattks = row[29] ? row[29] : "";
e.special_abilities = row[30] ? row[30] : "";
e.aggroradius = row[31] ? static_cast<uint32_t>(strtoul(row[31], nullptr, 10)) : 0;
e.assistradius = row[32] ? static_cast<uint32_t>(strtoul(row[32], nullptr, 10)) : 0;
e.face = row[33] ? static_cast<uint32_t>(strtoul(row[33], nullptr, 10)) : 1;
e.luclin_hairstyle = row[34] ? static_cast<uint32_t>(strtoul(row[34], nullptr, 10)) : 1;
e.luclin_haircolor = row[35] ? static_cast<uint32_t>(strtoul(row[35], nullptr, 10)) : 1;
e.luclin_eyecolor = row[36] ? static_cast<uint32_t>(strtoul(row[36], nullptr, 10)) : 1;
e.luclin_eyecolor2 = row[37] ? static_cast<uint32_t>(strtoul(row[37], nullptr, 10)) : 1;
e.luclin_beardcolor = row[38] ? static_cast<uint32_t>(strtoul(row[38], nullptr, 10)) : 1;
e.luclin_beard = row[39] ? static_cast<uint32_t>(strtoul(row[39], nullptr, 10)) : 0;
e.drakkin_heritage = row[40] ? static_cast<int32_t>(atoi(row[40])) : 0;
e.drakkin_tattoo = row[41] ? static_cast<int32_t>(atoi(row[41])) : 0;
e.drakkin_details = row[42] ? static_cast<int32_t>(atoi(row[42])) : 0;
e.armortint_id = row[43] ? static_cast<uint32_t>(strtoul(row[43], nullptr, 10)) : 0;
e.armortint_red = row[44] ? static_cast<uint8_t>(strtoul(row[44], nullptr, 10)) : 0;
e.armortint_green = row[45] ? static_cast<uint8_t>(strtoul(row[45], nullptr, 10)) : 0;
e.armortint_blue = row[46] ? static_cast<uint8_t>(strtoul(row[46], nullptr, 10)) : 0;
e.d_melee_texture1 = row[47] ? static_cast<uint32_t>(strtoul(row[47], nullptr, 10)) : 0;
e.d_melee_texture2 = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0;
e.ammo_idfile = row[49] ? row[49] : "IT10";
e.prim_melee_type = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 28;
e.sec_melee_type = row[51] ? static_cast<uint8_t>(strtoul(row[51], nullptr, 10)) : 28;
e.ranged_type = row[52] ? static_cast<uint8_t>(strtoul(row[52], nullptr, 10)) : 7;
e.runspeed = row[53] ? strtof(row[53], nullptr) : 0;
e.MR = row[54] ? static_cast<int16_t>(atoi(row[54])) : 0;
e.CR = row[55] ? static_cast<int16_t>(atoi(row[55])) : 0;
e.DR = row[56] ? static_cast<int16_t>(atoi(row[56])) : 0;
e.FR = row[57] ? static_cast<int16_t>(atoi(row[57])) : 0;
e.PR = row[58] ? static_cast<int16_t>(atoi(row[58])) : 0;
e.Corrup = row[59] ? static_cast<int16_t>(atoi(row[59])) : 0;
e.PhR = row[60] ? static_cast<uint16_t>(strtoul(row[60], nullptr, 10)) : 0;
e.see_invis = row[61] ? static_cast<int16_t>(atoi(row[61])) : 0;
e.see_invis_undead = row[62] ? static_cast<int16_t>(atoi(row[62])) : 0;
e.qglobal = row[63] ? static_cast<uint32_t>(strtoul(row[63], nullptr, 10)) : 0;
e.AC = row[64] ? static_cast<int16_t>(atoi(row[64])) : 0;
e.npc_aggro = row[65] ? static_cast<int8_t>(atoi(row[65])) : 0;
e.spawn_limit = row[66] ? static_cast<int8_t>(atoi(row[66])) : 0;
e.attack_speed = row[67] ? strtof(row[67], nullptr) : 0;
e.attack_delay = row[68] ? static_cast<uint8_t>(strtoul(row[68], nullptr, 10)) : 30;
e.findable = row[69] ? static_cast<int8_t>(atoi(row[69])) : 0;
e.STR = row[70] ? static_cast<uint32_t>(strtoul(row[70], nullptr, 10)) : 75;
e.STA = row[71] ? static_cast<uint32_t>(strtoul(row[71], nullptr, 10)) : 75;
e.DEX = row[72] ? static_cast<uint32_t>(strtoul(row[72], nullptr, 10)) : 75;
e.AGI = row[73] ? static_cast<uint32_t>(strtoul(row[73], nullptr, 10)) : 75;
e._INT = row[74] ? static_cast<uint32_t>(strtoul(row[74], nullptr, 10)) : 80;
e.WIS = row[75] ? static_cast<uint32_t>(strtoul(row[75], nullptr, 10)) : 75;
e.CHA = row[76] ? static_cast<uint32_t>(strtoul(row[76], nullptr, 10)) : 75;
e.see_hide = row[77] ? static_cast<int8_t>(atoi(row[77])) : 0;
e.see_improved_hide = row[78] ? static_cast<int8_t>(atoi(row[78])) : 0;
e.trackable = row[79] ? static_cast<int8_t>(atoi(row[79])) : 1;
e.isbot = row[80] ? static_cast<int8_t>(atoi(row[80])) : 0;
e.exclude = row[81] ? static_cast<int8_t>(atoi(row[81])) : 1;
e.ATK = row[82] ? static_cast<int32_t>(atoi(row[82])) : 0;
e.Accuracy = row[83] ? static_cast<int32_t>(atoi(row[83])) : 0;
e.Avoidance = row[84] ? static_cast<uint32_t>(strtoul(row[84], nullptr, 10)) : 0;
e.slow_mitigation = row[85] ? static_cast<int16_t>(atoi(row[85])) : 0;
e.version = row[86] ? static_cast<uint16_t>(strtoul(row[86], nullptr, 10)) : 0;
e.maxlevel = row[87] ? static_cast<int8_t>(atoi(row[87])) : 0;
e.scalerate = row[88] ? static_cast<int32_t>(atoi(row[88])) : 100;
e.private_corpse = row[89] ? static_cast<uint8_t>(strtoul(row[89], nullptr, 10)) : 0;
e.unique_spawn_by_name = row[90] ? static_cast<uint8_t>(strtoul(row[90], nullptr, 10)) : 0;
e.underwater = row[91] ? static_cast<uint8_t>(strtoul(row[91], nullptr, 10)) : 0;
e.isquest = row[92] ? static_cast<int8_t>(atoi(row[92])) : 0;
e.emoteid = row[93] ? static_cast<uint32_t>(strtoul(row[93], nullptr, 10)) : 0;
e.spellscale = row[94] ? strtof(row[94], nullptr) : 100;
e.healscale = row[95] ? strtof(row[95], nullptr) : 100;
e.no_target_hotkey = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 0;
e.raid_target = row[97] ? static_cast<uint8_t>(strtoul(row[97], nullptr, 10)) : 0;
e.armtexture = row[98] ? static_cast<int8_t>(atoi(row[98])) : 0;
e.bracertexture = row[99] ? static_cast<int8_t>(atoi(row[99])) : 0;
e.handtexture = row[100] ? static_cast<int8_t>(atoi(row[100])) : 0;
e.legtexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
e.feettexture = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
e.light = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
e.walkspeed = row[104] ? static_cast<int8_t>(atoi(row[104])) : 0;
e.peqid = row[105] ? static_cast<int32_t>(atoi(row[105])) : 0;
e.unique_ = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
e.fixed = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
e.ignore_despawn = row[108] ? static_cast<int8_t>(atoi(row[108])) : 0;
e.show_name = row[109] ? static_cast<int8_t>(atoi(row[109])) : 1;
e.untargetable = row[110] ? static_cast<int8_t>(atoi(row[110])) : 0;
e.charm_ac = row[111] ? static_cast<int16_t>(atoi(row[111])) : 0;
e.charm_min_dmg = row[112] ? static_cast<int32_t>(atoi(row[112])) : 0;
e.charm_max_dmg = row[113] ? static_cast<int32_t>(atoi(row[113])) : 0;
e.charm_attack_delay = row[114] ? static_cast<int8_t>(atoi(row[114])) : 0;
e.charm_accuracy_rating = row[115] ? static_cast<int32_t>(atoi(row[115])) : 0;
e.charm_avoidance_rating = row[116] ? static_cast<int32_t>(atoi(row[116])) : 0;
e.charm_atk = row[117] ? static_cast<int32_t>(atoi(row[117])) : 0;
e.skip_global_loot = row[118] ? static_cast<int8_t>(atoi(row[118])) : 0;
e.rare_spawn = row[119] ? static_cast<int8_t>(atoi(row[119])) : 0;
e.stuck_behavior = row[120] ? static_cast<int8_t>(atoi(row[120])) : 0;
e.model = row[121] ? static_cast<int16_t>(atoi(row[121])) : 0;
e.flymode = row[122] ? static_cast<int8_t>(atoi(row[122])) : -1;
e.always_aggro = row[123] ? static_cast<int8_t>(atoi(row[123])) : 0;
e.exp_mod = row[124] ? static_cast<int32_t>(atoi(row[124])) : 100;
e.heroic_strikethrough = row[125] ? static_cast<int32_t>(atoi(row[125])) : 0;
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -1623,6 +1633,7 @@ public:
v.push_back(std::to_string(e.mana_regen_rate));
v.push_back(std::to_string(e.loottable_id));
v.push_back(std::to_string(e.merchant_id));
v.push_back(std::to_string(e.greed));
v.push_back(std::to_string(e.alt_currency_id));
v.push_back(std::to_string(e.npc_spells_id));
v.push_back(std::to_string(e.npc_spells_effects_id));
@@ -1773,6 +1784,7 @@ public:
v.push_back(std::to_string(e.mana_regen_rate));
v.push_back(std::to_string(e.loottable_id));
v.push_back(std::to_string(e.merchant_id));
v.push_back(std::to_string(e.greed));
v.push_back(std::to_string(e.alt_currency_id));
v.push_back(std::to_string(e.npc_spells_id));
v.push_back(std::to_string(e.npc_spells_effects_id));
@@ -0,0 +1,560 @@
/**
* 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://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_SHAREDBANK_REPOSITORY_H
#define EQEMU_BASE_SHAREDBANK_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseSharedbankRepository {
public:
struct Sharedbank {
uint32_t account_id;
uint32_t slot_id;
uint32_t item_id;
uint16_t charges;
uint32_t color;
uint32_t augment_one;
uint32_t augment_two;
uint32_t augment_three;
uint32_t augment_four;
uint32_t augment_five;
uint32_t augment_six;
std::string custom_data;
uint32_t ornament_icon;
uint32_t ornament_idfile;
int32_t ornament_hero_model;
uint64_t guid;
};
static std::string PrimaryKey()
{
return std::string("account_id");
}
static std::vector<std::string> Columns()
{
return {
"account_id",
"slot_id",
"item_id",
"charges",
"color",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"custom_data",
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"account_id",
"slot_id",
"item_id",
"charges",
"color",
"augment_one",
"augment_two",
"augment_three",
"augment_four",
"augment_five",
"augment_six",
"custom_data",
"ornament_icon",
"ornament_idfile",
"ornament_hero_model",
"guid",
};
}
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("sharedbank");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static Sharedbank NewEntity()
{
Sharedbank e{};
e.account_id = 0;
e.slot_id = 0;
e.item_id = 0;
e.charges = 0;
e.color = 0;
e.augment_one = 0;
e.augment_two = 0;
e.augment_three = 0;
e.augment_four = 0;
e.augment_five = 0;
e.augment_six = 0;
e.custom_data = "";
e.ornament_icon = 0;
e.ornament_idfile = 0;
e.ornament_hero_model = 0;
e.guid = 0;
return e;
}
static Sharedbank GetSharedbank(
const std::vector<Sharedbank> &sharedbanks,
int sharedbank_id
)
{
for (auto &sharedbank : sharedbanks) {
if (sharedbank.account_id == sharedbank_id) {
return sharedbank;
}
}
return NewEntity();
}
static Sharedbank FindOne(
Database& db,
int sharedbank_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
sharedbank_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
Sharedbank e{};
e.account_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.slot_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.charges = row[3] ? static_cast<uint16_t>(strtoul(row[3], nullptr, 10)) : 0;
e.color = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augment_one = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_two = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_three = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_four = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_five = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_six = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.custom_data = row[11] ? row[11] : "";
e.ornament_icon = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.ornament_idfile = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_hero_model = row[14] ? static_cast<int32_t>(atoi(row[14])) : 0;
e.guid = row[15] ? strtoull(row[15], nullptr, 10) : 0;
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int sharedbank_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
sharedbank_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const Sharedbank &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.account_id));
v.push_back(columns[1] + " = " + std::to_string(e.slot_id));
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
v.push_back(columns[3] + " = " + std::to_string(e.charges));
v.push_back(columns[4] + " = " + std::to_string(e.color));
v.push_back(columns[5] + " = " + std::to_string(e.augment_one));
v.push_back(columns[6] + " = " + std::to_string(e.augment_two));
v.push_back(columns[7] + " = " + std::to_string(e.augment_three));
v.push_back(columns[8] + " = " + std::to_string(e.augment_four));
v.push_back(columns[9] + " = " + std::to_string(e.augment_five));
v.push_back(columns[10] + " = " + std::to_string(e.augment_six));
v.push_back(columns[11] + " = '" + Strings::Escape(e.custom_data) + "'");
v.push_back(columns[12] + " = " + std::to_string(e.ornament_icon));
v.push_back(columns[13] + " = " + std::to_string(e.ornament_idfile));
v.push_back(columns[14] + " = " + std::to_string(e.ornament_hero_model));
v.push_back(columns[15] + " = " + std::to_string(e.guid));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.account_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static Sharedbank InsertOne(
Database& db,
Sharedbank e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.account_id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<Sharedbank> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
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<Sharedbank> All(Database& db)
{
std::vector<Sharedbank> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Sharedbank e{};
e.account_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.slot_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.charges = row[3] ? static_cast<uint16_t>(strtoul(row[3], nullptr, 10)) : 0;
e.color = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augment_one = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_two = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_three = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_four = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_five = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_six = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.custom_data = row[11] ? row[11] : "";
e.ornament_icon = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.ornament_idfile = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_hero_model = row[14] ? static_cast<int32_t>(atoi(row[14])) : 0;
e.guid = row[15] ? strtoull(row[15], nullptr, 10) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<Sharedbank> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<Sharedbank> 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) {
Sharedbank e{};
e.account_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.slot_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.charges = row[3] ? static_cast<uint16_t>(strtoul(row[3], nullptr, 10)) : 0;
e.color = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augment_one = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_two = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_three = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_four = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_five = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_six = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.custom_data = row[11] ? row[11] : "";
e.ornament_icon = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
e.ornament_idfile = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.ornament_hero_model = row[14] ? static_cast<int32_t>(atoi(row[14])) : 0;
e.guid = row[15] ? strtoull(row[15], nullptr, 10) : 0;
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);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const Sharedbank &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
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<Sharedbank> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.color));
v.push_back(std::to_string(e.augment_one));
v.push_back(std::to_string(e.augment_two));
v.push_back(std::to_string(e.augment_three));
v.push_back(std::to_string(e.augment_four));
v.push_back(std::to_string(e.augment_five));
v.push_back(std::to_string(e.augment_six));
v.push_back("'" + Strings::Escape(e.custom_data) + "'");
v.push_back(std::to_string(e.ornament_icon));
v.push_back(std::to_string(e.ornament_idfile));
v.push_back(std::to_string(e.ornament_hero_model));
v.push_back(std::to_string(e.guid));
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_SHAREDBANK_REPOSITORY_H
@@ -19,31 +19,34 @@
class BaseSpellBucketsRepository {
public:
struct SpellBuckets {
uint64_t spellid;
std::string key_;
std::string value;
uint32_t spell_id;
std::string bucket_name;
std::string bucket_value;
uint8_t bucket_comparison;
};
static std::string PrimaryKey()
{
return std::string("spellid");
return std::string("spell_id");
}
static std::vector<std::string> Columns()
{
return {
"spellid",
"`key`",
"value",
"spell_id",
"bucket_name",
"bucket_value",
"bucket_comparison",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"spellid",
"`key`",
"value",
"spell_id",
"bucket_name",
"bucket_value",
"bucket_comparison",
};
}
@@ -84,9 +87,10 @@ public:
{
SpellBuckets e{};
e.spellid = 0;
e.key_ = "";
e.value = "";
e.spell_id = 0;
e.bucket_name = "";
e.bucket_value = "";
e.bucket_comparison = 0;
return e;
}
@@ -97,7 +101,7 @@ public:
)
{
for (auto &spell_buckets : spell_bucketss) {
if (spell_buckets.spellid == spell_buckets_id) {
if (spell_buckets.spell_id == spell_buckets_id) {
return spell_buckets;
}
}
@@ -123,9 +127,10 @@ public:
if (results.RowCount() == 1) {
SpellBuckets e{};
e.spellid = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.key_ = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.spell_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.bucket_name = row[1] ? row[1] : "";
e.bucket_value = row[2] ? row[2] : "";
e.bucket_comparison = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
return e;
}
@@ -159,9 +164,10 @@ public:
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.spellid));
v.push_back(columns[1] + " = '" + Strings::Escape(e.key_) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.value) + "'");
v.push_back(columns[0] + " = " + std::to_string(e.spell_id));
v.push_back(columns[1] + " = '" + Strings::Escape(e.bucket_name) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.bucket_value) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.bucket_comparison));
auto results = db.QueryDatabase(
fmt::format(
@@ -169,7 +175,7 @@ public:
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.spellid
e.spell_id
)
);
@@ -183,9 +189,10 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.spellid));
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.spell_id));
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
v.push_back(std::to_string(e.bucket_comparison));
auto results = db.QueryDatabase(
fmt::format(
@@ -196,7 +203,7 @@ public:
);
if (results.Success()) {
e.spellid = results.LastInsertedID();
e.spell_id = results.LastInsertedID();
return e;
}
@@ -215,9 +222,10 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.spellid));
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.spell_id));
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
v.push_back(std::to_string(e.bucket_comparison));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -251,9 +259,10 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
SpellBuckets e{};
e.spellid = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.key_ = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.spell_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.bucket_name = row[1] ? row[1] : "";
e.bucket_value = row[2] ? row[2] : "";
e.bucket_comparison = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -278,9 +287,10 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
SpellBuckets e{};
e.spellid = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.key_ = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.spell_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.bucket_name = row[1] ? row[1] : "";
e.bucket_value = row[2] ? row[2] : "";
e.bucket_comparison = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -355,9 +365,10 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.spellid));
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.spell_id));
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
v.push_back(std::to_string(e.bucket_comparison));
auto results = db.QueryDatabase(
fmt::format(
@@ -380,9 +391,10 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.spellid));
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.spell_id));
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
v.push_back(std::to_string(e.bucket_comparison));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
+168 -49
View File
@@ -19,40 +19,70 @@
class BaseTraderRepository {
public:
struct Trader {
uint64_t id;
uint32_t char_id;
uint32_t item_id;
uint32_t serialnumber;
int32_t charges;
uint32_t item_cost;
uint32_t aug_slot_1;
uint32_t aug_slot_2;
uint32_t aug_slot_3;
uint32_t aug_slot_4;
uint32_t aug_slot_5;
uint32_t aug_slot_6;
int32_t item_sn;
int32_t item_charges;
uint64_t item_cost;
uint8_t slot_id;
uint32_t char_entity_id;
uint32_t char_zone_id;
int8_t active_transaction;
};
static std::string PrimaryKey()
{
return std::string("char_id");
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"char_id",
"item_id",
"serialnumber",
"charges",
"aug_slot_1",
"aug_slot_2",
"aug_slot_3",
"aug_slot_4",
"aug_slot_5",
"aug_slot_6",
"item_sn",
"item_charges",
"item_cost",
"slot_id",
"char_entity_id",
"char_zone_id",
"active_transaction",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"char_id",
"item_id",
"serialnumber",
"charges",
"aug_slot_1",
"aug_slot_2",
"aug_slot_3",
"aug_slot_4",
"aug_slot_5",
"aug_slot_6",
"item_sn",
"item_charges",
"item_cost",
"slot_id",
"char_entity_id",
"char_zone_id",
"active_transaction",
};
}
@@ -93,12 +123,22 @@ public:
{
Trader e{};
e.char_id = 0;
e.item_id = 0;
e.serialnumber = 0;
e.charges = 0;
e.item_cost = 0;
e.slot_id = 0;
e.id = 0;
e.char_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.item_sn = 0;
e.item_charges = 0;
e.item_cost = 0;
e.slot_id = 0;
e.char_entity_id = 0;
e.char_zone_id = 0;
e.active_transaction = 0;
return e;
}
@@ -109,7 +149,7 @@ public:
)
{
for (auto &trader : traders) {
if (trader.char_id == trader_id) {
if (trader.id == trader_id) {
return trader;
}
}
@@ -135,12 +175,22 @@ public:
if (results.RowCount() == 1) {
Trader e{};
e.char_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.serialnumber = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_cost = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.slot_id = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
return e;
}
@@ -174,12 +224,21 @@ public:
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.char_id));
v.push_back(columns[1] + " = " + std::to_string(e.item_id));
v.push_back(columns[2] + " = " + std::to_string(e.serialnumber));
v.push_back(columns[3] + " = " + std::to_string(e.charges));
v.push_back(columns[4] + " = " + std::to_string(e.item_cost));
v.push_back(columns[5] + " = " + std::to_string(e.slot_id));
v.push_back(columns[1] + " = " + std::to_string(e.char_id));
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
v.push_back(columns[3] + " = " + std::to_string(e.aug_slot_1));
v.push_back(columns[4] + " = " + std::to_string(e.aug_slot_2));
v.push_back(columns[5] + " = " + std::to_string(e.aug_slot_3));
v.push_back(columns[6] + " = " + std::to_string(e.aug_slot_4));
v.push_back(columns[7] + " = " + std::to_string(e.aug_slot_5));
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[9] + " = " + std::to_string(e.item_sn));
v.push_back(columns[10] + " = " + std::to_string(e.item_charges));
v.push_back(columns[11] + " = " + std::to_string(e.item_cost));
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
v.push_back(columns[13] + " = " + std::to_string(e.char_entity_id));
v.push_back(columns[14] + " = " + std::to_string(e.char_zone_id));
v.push_back(columns[15] + " = " + std::to_string(e.active_transaction));
auto results = db.QueryDatabase(
fmt::format(
@@ -187,7 +246,7 @@ public:
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.char_id
e.id
)
);
@@ -201,12 +260,22 @@ public:
{
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));
v.push_back(std::to_string(e.serialnumber));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.item_sn));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.item_cost));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.active_transaction));
auto results = db.QueryDatabase(
fmt::format(
@@ -217,7 +286,7 @@ public:
);
if (results.Success()) {
e.char_id = results.LastInsertedID();
e.id = results.LastInsertedID();
return e;
}
@@ -236,12 +305,22 @@ public:
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));
v.push_back(std::to_string(e.serialnumber));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.item_sn));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.item_cost));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.active_transaction));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -275,12 +354,22 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Trader e{};
e.char_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.serialnumber = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_cost = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.slot_id = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
all_entries.push_back(e);
}
@@ -305,12 +394,22 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Trader e{};
e.char_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.serialnumber = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_cost = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.slot_id = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
all_entries.push_back(e);
}
@@ -385,12 +484,22 @@ public:
{
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));
v.push_back(std::to_string(e.serialnumber));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.item_sn));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.item_cost));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.active_transaction));
auto results = db.QueryDatabase(
fmt::format(
@@ -413,12 +522,22 @@ public:
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));
v.push_back(std::to_string(e.serialnumber));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.aug_slot_1));
v.push_back(std::to_string(e.aug_slot_2));
v.push_back(std::to_string(e.aug_slot_3));
v.push_back(std::to_string(e.aug_slot_4));
v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.item_sn));
v.push_back(std::to_string(e.item_charges));
v.push_back(std::to_string(e.item_cost));
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.active_transaction));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -44,7 +44,24 @@ public:
*/
// Custom extended repository methods here
static std::vector<std::string> GetBaseDataFileLines(Database& db)
{
std::vector<std::string> lines;
auto results = db.QueryDatabase(
fmt::format(
"SELECT CONCAT_WS('^', {}) FROM {} ORDER BY `level`, `class` ASC",
ColumnsRaw(),
TableName()
)
);
for (auto row : results) {
lines.emplace_back(row[0]);
}
return lines;
}
};
#endif //EQEMU_BASE_DATA_REPOSITORY_H
@@ -0,0 +1,360 @@
#ifndef EQEMU_BUYER_BUY_LINES_REPOSITORY_H
#define EQEMU_BUYER_BUY_LINES_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_buyer_buy_lines_repository.h"
#include "buyer_trade_items_repository.h"
#include "character_data_repository.h"
#include "buyer_repository.h"
#include "../eq_packet_structs.h"
class BuyerBuyLinesRepository: public BaseBuyerBuyLinesRepository {
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
*
* BuyerBuyLinesRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* BuyerBuyLinesRepository::GetWhereNeverExpires()
* BuyerBuyLinesRepository::GetWhereXAndY()
* BuyerBuyLinesRepository::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
struct WelcomeData_Struct {
uint32 count_of_buyers;
uint32 count_of_items;
};
static int CreateBuyLine(Database& db, const BuyerLineItems_Struct b, uint32 char_id)
{
auto buyer = BuyerRepository::GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1", char_id));
if (buyer.empty()){
return 0;
}
BuyerBuyLinesRepository::BuyerBuyLines buy_lines{};
buy_lines.id = 0;
buy_lines.buyer_id = buyer.front().id;
buy_lines.char_id = char_id;
buy_lines.buy_slot_id = b.slot;
buy_lines.item_id = b.item_id;
buy_lines.item_name = b.item_name;
buy_lines.item_icon = b.item_icon;
buy_lines.item_qty = b.item_quantity;
buy_lines.item_price = b.item_cost;
auto e = InsertOne(db, buy_lines);
std::vector<BuyerTradeItemsRepository::BuyerTradeItems> queue;
for (auto const &r: b.trade_items) {
BuyerTradeItemsRepository::BuyerTradeItems bti{};
bti.id = 0;
bti.buyer_buy_lines_id = e.id;
bti.item_id = r.item_id;
bti.item_qty = r.item_quantity;
bti.item_icon = r.item_icon;
bti.item_name = r.item_name;
if (bti.item_id) {
queue.push_back(bti);
}
}
if (!queue.empty()) {
BuyerTradeItemsRepository::InsertMany(db, queue);
}
return e.id;
}
static int ModifyBuyLine(Database& db, const BuyerLineItems_Struct b, uint32 char_id)
{
auto b_lines = GetWhere(db, fmt::format("`char_id` = '{}' AND `buy_slot_id` = '{}';", char_id, b.slot));
if (b_lines.empty() || b_lines.size() > 1){
return 0;
}
auto b_line = b_lines.front();
b_line.item_qty = b.item_quantity;
b_line.item_price = b.item_cost;
b_line.item_icon = b.item_icon;
auto e = UpdateOne(db, b_line);
std::vector<BuyerTradeItemsRepository::BuyerTradeItems> queue;
BuyerTradeItemsRepository::DeleteWhere(db, fmt::format("`buyer_buy_lines_id` = '{}';", b_line.id));
for (auto const &r: b.trade_items) {
BuyerTradeItemsRepository::BuyerTradeItems bti{};
bti.id = 0;
bti.buyer_buy_lines_id = b_line.id;
bti.item_id = r.item_id;
bti.item_qty = r.item_quantity;
bti.item_icon = r.item_icon;
bti.item_name = r.item_name;
if (bti.item_id) {
queue.push_back(bti);
}
}
if (!queue.empty()) {
BuyerTradeItemsRepository::InsertMany(db, queue);
}
return 1;
}
static bool DeleteBuyLine(Database &db, uint32 char_id, int32 slot_id = 0xffffffff)
{
std::vector<BuyerBuyLines> buylines{};
if (slot_id == 0xffffffff) {
auto buylines = GetWhere(db, fmt::format("`char_id` = '{}'", char_id));
DeleteWhere(db, fmt::format("`char_id` = '{}'", char_id));
}
else {
auto buylines = GetWhere(db, fmt::format("`char_id` = '{}' AND `buy_slot_id` = '{}'", char_id, slot_id));
DeleteWhere(db, fmt::format("`char_id` = '{}' AND `buy_slot_id` = '{}'", char_id, slot_id));
}
if (buylines.empty()) {
return 0;
}
std::vector<std::string> buyline_ids{};
for (auto const &bl: buylines) {
buyline_ids.push_back((std::to_string(bl.id)));
}
if (!buyline_ids.empty()) {
BuyerTradeItemsRepository::DeleteWhere(
db,
fmt::format(
"`buyer_buy_lines_id` IN({})",
Strings::Implode(", ", buyline_ids)
)
);
}
return 1;
}
static std::vector<BuyerLineItems_Struct> GetBuyLines(Database &db, uint32 char_id)
{
std::vector<BuyerLineItems_Struct> all_entries{};
auto buy_line = GetWhere(db, fmt::format("`char_id` = '{}';", char_id));
if (buy_line.empty()){
return all_entries;
}
auto buy_line_trade_items = BuyerTradeItemsRepository::GetWhere(
db,
fmt::format(
"`buyer_buy_lines_id` IN (SELECT b.id FROM buyer_buy_lines AS b WHERE b.char_id = '{}')",
char_id
)
);
all_entries.reserve(buy_line.size());
for (auto const &l: buy_line) {
BuyerLineItems_Struct bli{};
bli.item_id = l.item_id;
bli.item_cost = l.item_price;
bli.item_quantity = l.item_qty;
bli.slot = l.buy_slot_id;
bli.item_name = l.item_name;
for (auto const &i: GetSubIDs(buy_line_trade_items, l.id)) {
BuyerLineTradeItems_Struct blti{};
blti.item_id = i.item_id;
blti.item_icon = i.item_icon;
blti.item_quantity = i.item_qty;
blti.item_id = i.item_id;
blti.item_name = i.item_name;
bli.trade_items.push_back(blti);
}
all_entries.push_back(bli);
}
return all_entries;
}
static BuyerLineSearch_Struct SearchBuyLines(
Database &db,
std::string &search_string,
uint32 char_id = 0,
uint32 zone_id = 0,
uint32 zone_instance_id = 0
)
{
BuyerLineSearch_Struct all_entries{};
std::string where_clause(fmt::format("`item_name` LIKE \"%{}%\" ", search_string));
if (char_id) {
where_clause += fmt::format("AND `char_id` = '{}' ", char_id);
}
if (zone_id) {
auto buyers = BuyerRepository::GetWhere(
db,
fmt::format(
"`char_zone_id` = '{}' AND char_zone_instance_id = '{}'",
zone_id,
zone_instance_id
)
);
if (buyers.empty()) {
return all_entries;
}
std::vector<std::string> char_ids{};
for (auto const &bl : buyers) {
char_ids.push_back((std::to_string(bl.char_id)));
}
where_clause += fmt::format("AND `char_id` IN ({}) ", Strings::Implode(", ", char_ids));
}
auto buy_line = GetWhere(db, where_clause);
if (buy_line.empty()){
return all_entries;
}
std::vector<std::string> ids{};
std::vector<std::string> char_ids{};
for (auto const &bl : buy_line) {
if (std::find(ids.begin(), ids.end(), std::to_string(bl.id)) == std::end(ids)) {
ids.push_back(std::to_string(bl.id));
}
if (std::find(char_ids.begin(), char_ids.end(), std::to_string(bl.char_id)) == std::end(char_ids)) {
char_ids.push_back((std::to_string(bl.char_id)));
}
}
auto buy_line_trade_items = BuyerTradeItemsRepository::GetWhere(
db,
fmt::format(
"`buyer_buy_lines_id` IN ({});",
Strings::Implode(", ", ids)
)
);
auto char_names = BuyerRepository::GetWhere(
db,
fmt::format(
"`char_id` IN ({});",
Strings::Implode(", ", char_ids)
)
);
all_entries.no_items = buy_line.size();
for (auto const &l: buy_line) {
BuyerLineItemsSearch_Struct blis{};
blis.slot = l.buy_slot_id;
blis.item_id = l.item_id;
blis.item_cost = l.item_price;
blis.item_icon = l.item_icon;
blis.item_quantity = l.item_qty;
blis.buyer_id = l.char_id;
auto it = std::find_if(
char_names.cbegin(),
char_names.cend(),
[&](BuyerRepository::Buyer e) { return e.char_id == l.char_id; }
);
blis.buyer_name = it != char_names.end() ? it->char_name : std::string("");
blis.buyer_entity_id = it != char_names.end() ? it->char_entity_id : 0;
blis.buyer_zone_id = it != char_names.end() ? it->char_zone_id : 0;
blis.buyer_zone_instance_id = it != char_names.end() ? it->char_zone_instance_id : 0;
strn0cpy(blis.item_name, l.item_name.c_str(), sizeof(blis.item_name));
for (auto const &i: GetSubIDs(buy_line_trade_items, l.id)) {
BuyerLineTradeItems_Struct e{};
e.item_id = i.item_id;
e.item_icon = i.item_icon;
e.item_quantity = i.item_qty;
e.item_id = i.item_id;
e.item_name = i.item_name;
blis.trade_items.push_back(e);
}
all_entries.buy_line.push_back(blis);
}
return all_entries;
}
static std::vector<BuyerTradeItemsRepository::BuyerTradeItems>
GetSubIDs(std::vector<BuyerTradeItemsRepository::BuyerTradeItems> &in, uint64 id)
{
std::vector<BuyerTradeItemsRepository::BuyerTradeItems> results{};
std::vector<uint64> indices{};
auto it = in.begin();
while ((it = std::find_if(
it,
in.end(),
[&](BuyerTradeItemsRepository::BuyerTradeItems const &e) {
return e.buyer_buy_lines_id == id;
}
))
!= in.end()
) {
indices.push_back(std::distance(in.begin(), it));
results.push_back(*it);
it++;
}
return results;
}
static WelcomeData_Struct GetWelcomeData(Database &db)
{
WelcomeData_Struct e{};
auto results = db.QueryDatabase("SELECT COUNT(DISTINCT char_id), COUNT(char_id) FROM buyer;");
if (!results.RowCount()) {
return e;
}
auto r = results.begin();
e.count_of_buyers = Strings::ToInt(r[0]);
e.count_of_items = Strings::ToInt(r[1]);
return e;
}
};
#endif //EQEMU_BUYER_BUY_LINES_REPOSITORY_H
+93
View File
@@ -4,6 +4,8 @@
#include "../database.h"
#include "../strings.h"
#include "base/base_buyer_repository.h"
#include "base/base_buyer_trade_items_repository.h"
#include "base/base_buyer_buy_lines_repository.h"
class BuyerRepository: public BaseBuyerRepository {
public:
@@ -45,6 +47,97 @@ public:
// Custom extended repository methods here
static bool UpdateWelcomeMessage(Database& db, uint32 char_id, const char *message) {
auto const b = GetWhere(db, fmt::format("`char_id` = '{}';", char_id));
if (b.empty()) {
return false;
}
auto buyer = b.front();
buyer.welcome_message = message;
return UpdateOne(db, buyer);
}
static std::string GetWelcomeMessage(Database& db, uint32 char_id) {
auto const b = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
if (b.empty()) {
return std::string();
}
return b.front().welcome_message;
}
static int UpdateTransactionDate(Database& db, uint32 char_id, time_t transaction_date) {
auto b = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
if (b.empty()) {
return 0;
}
auto e = b.front();
e.transaction_date = transaction_date;
return UpdateOne(db, e);
}
static time_t GetTransactionDate(Database& db, uint32 char_id) {
auto b = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
if (b.empty()) {
return 0;
}
auto e = b.front();
return e.transaction_date;
}
static bool DeleteBuyer(Database &db, uint32 char_id)
{
if (char_id == 0) {
Truncate(db);
BaseBuyerBuyLinesRepository::Truncate(db);
BaseBuyerTradeItemsRepository::Truncate(db);
}
else {
auto buyer = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
if (buyer.empty()) {
return false;
}
auto buy_lines = BaseBuyerBuyLinesRepository::GetWhere(
db,
fmt::format("`buyer_id` = '{}'", buyer.front().id)
);
if (buy_lines.empty()) {
return false;
}
std::vector<std::string> buy_line_ids{};
for (auto const &bl: buy_lines) {
buy_line_ids.push_back(std::to_string(bl.id));
}
DeleteWhere(db, fmt::format("`char_id` = '{}';", char_id));
if (buy_line_ids.empty()) {
return false;
}
BaseBuyerBuyLinesRepository::DeleteWhere(
db,
fmt::format("`id` IN({})", Strings::Implode(", ", buy_line_ids))
);
BaseBuyerTradeItemsRepository::DeleteWhere(
db,
fmt::format(
"`buyer_buy_lines_id` IN({})",
Strings::Implode(", ", buy_line_ids))
);
}
return true;
}
};
#endif //EQEMU_BUYER_REPOSITORY_H
@@ -0,0 +1,81 @@
#ifndef EQEMU_BUYER_TRADE_ITEMS_REPOSITORY_H
#define EQEMU_BUYER_TRADE_ITEMS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_buyer_trade_items_repository.h"
class BuyerTradeItemsRepository: public BaseBuyerTradeItemsRepository {
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
*
* BuyerTradeItemsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* BuyerTradeItemsRepository::GetWhereNeverExpires()
* BuyerTradeItemsRepository::GetWhereXAndY()
* BuyerTradeItemsRepository::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
static std::vector<BuyerTradeItems> GetTradeItems(Database& db, const uint32 char_id)
{
std::vector<BuyerTradeItems> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"SELECT bti.* "
"FROM buyer_trade_items AS bti "
"INNER JOIN buyer_buy_lines AS bbl ON bti.buyer_buy_lines_id = bbl.id "
"WHERE bbl.char_id = '{}';",
char_id
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
BuyerTradeItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.item_name = row[5] ? row[5] : "0";
all_entries.push_back(e);
}
return all_entries;
}
};
#endif //EQEMU_BUYER_TRADE_ITEMS_REPOSITORY_H
@@ -64,6 +64,22 @@ public:
return Strings::ToUnsignedInt(row[0]);
}
static CharacterData FindByName(
Database& db,
const std::string& character_name
)
{
auto l = CharacterDataRepository::GetWhere(
db,
fmt::format(
"`name` = '{}' LIMIT 1",
Strings::Escape(character_name)
)
);
return l.empty() ? CharacterDataRepository::NewEntity() : l.front();
}
};
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H
@@ -0,0 +1,50 @@
#ifndef EQEMU_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
#define EQEMU_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_character_parcels_containers_repository.h"
class CharacterParcelsContainersRepository: public BaseCharacterParcelsContainersRepository {
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
*
* CharacterParcelsContainersRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* CharacterParcelsContainersRepository::GetWhereNeverExpires()
* CharacterParcelsContainersRepository::GetWhereXAndY()
* CharacterParcelsContainersRepository::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_CHARACTER_PARCELS_CONTAINERS_REPOSITORY_H
@@ -49,8 +49,11 @@ public:
// these are the base definitions for command_subsettings and can be over-ridden by the database
std::vector<CommandSubsettingsRepository::CommandSubsettings> static_records = {
{.parent_command = "find", .sub_command = "aa", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaa"},
{.parent_command = "find", .sub_command = "body_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbodytype"},
{.parent_command = "find", .sub_command = "bug_category", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbugcategory"},
{.parent_command = "find", .sub_command = "character", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcharacter"},
{.parent_command = "find", .sub_command = "class", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findclass"},
{.parent_command = "find", .sub_command = "comparison_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcomparisontype"},
{.parent_command = "find", .sub_command = "currency", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcurrency"},
{.parent_command = "find", .sub_command = "deity", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "finddeity"},
{.parent_command = "find", .sub_command = "emote", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findemote"},
@@ -58,9 +61,12 @@ public:
{.parent_command = "find", .sub_command = "item", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fi|finditem|itemsearch"},
{.parent_command = "find", .sub_command = "language", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findlanguage"},
{.parent_command = "find", .sub_command = "npc_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fn|findnpc|findnpctype"},
{.parent_command = "find", .sub_command = "object_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findobjecttype"},
{.parent_command = "find", .sub_command = "race", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrace"},
{.parent_command = "find", .sub_command = "recipe", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrecipe"},
{.parent_command = "find", .sub_command = "skill", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findskill"},
{.parent_command = "find", .sub_command = "special_ability", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fsa|findspecialability"},
{.parent_command = "find", .sub_command = "stance", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findstance"},
{.parent_command = "find", .sub_command = "spell", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fs|findspell"},
{.parent_command = "find", .sub_command = "task", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findtask"},
{.parent_command = "find", .sub_command = "zone", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fz|findzone"},
@@ -79,7 +85,6 @@ public:
{.parent_command = "set", .sub_command = "endurance", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setendurance"},
{.parent_command = "set", .sub_command = "endurance_full", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "endurance"},
{.parent_command = "set", .sub_command = "exp", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setxp|setexp"},
{.parent_command = "set", .sub_command = "faction", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setfaction"},
{.parent_command = "set", .sub_command = "flymode", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "flymode"},
{.parent_command = "set", .sub_command = "freeze", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "freeze|unfreeze"},
{.parent_command = "set", .sub_command = "gender", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "gender"},
+17
View File
@@ -44,7 +44,24 @@ public:
*/
// Custom extended repository methods here
static std::vector<std::string> GetDBStrFileLines(Database& db)
{
std::vector<std::string> lines;
auto results = db.QueryDatabase(
fmt::format(
"SELECT CONCAT(CONCAT_WS('^', {}), '^0') FROM {} ORDER BY `id`, `type` ASC",
ColumnsRaw(),
TableName()
)
);
for (auto row : results) {
lines.emplace_back(row[0]);
}
return lines;
}
};
#endif //EQEMU_DB_STR_REPOSITORY_H
@@ -190,6 +190,17 @@ public:
return UpdateOne(db, m);
}
static void ClearOnlineStatus(Database &db)
{
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET `online` = 0 "
"WHERE `online` = 1;",
TableName()
)
);
}
};
#endif //EQEMU_GUILD_MEMBERS_REPOSITORY_H
+2 -37
View File
@@ -7,43 +7,6 @@
class ItemsRepository: public BaseItemsRepository {
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
*
* ItemsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* ItemsRepository::GetWhereNeverExpires()
* ItemsRepository::GetWhereXAndY()
* ItemsRepository::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
static std::vector<int32> GetItemIDsBySearchCriteria(
Database& db,
std::string search_string,
@@ -73,6 +36,8 @@ public:
return item_id_list;
}
};
#endif //EQEMU_ITEMS_REPOSITORY_H
+37 -300
View File
@@ -3,310 +3,47 @@
#include "../database.h"
#include "../strings.h"
#include "base/base_sharedbank_repository.h"
class SharedbankRepository {
class SharedbankRepository: public BaseSharedbankRepository {
public:
struct Sharedbank {
int acctid;
int slotid;
int itemid;
int16 charges;
int augslot1;
int augslot2;
int augslot3;
int augslot4;
int augslot5;
int augslot6;
std::string custom_data;
};
static std::string PrimaryKey()
{
return std::string("");
}
/**
* 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
*
* SharedbankRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* SharedbankRepository::GetWhereNeverExpires()
* SharedbankRepository::GetWhereXAndY()
* SharedbankRepository::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
*/
static std::vector<std::string> Columns()
{
return {
"acctid",
"slotid",
"itemid",
"charges",
"augslot1",
"augslot2",
"augslot3",
"augslot4",
"augslot5",
"augslot6",
"custom_data",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string InsertColumnsRaw()
{
std::vector<std::string> insert_columns;
for (auto &column : Columns()) {
if (column == PrimaryKey()) {
continue;
}
insert_columns.push_back(column);
}
return std::string(Strings::Implode(", ", insert_columns));
}
static std::string TableName()
{
return std::string("sharedbank");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
ColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
InsertColumnsRaw()
);
}
static Sharedbank NewEntity()
{
Sharedbank entry{};
entry.acctid = 0;
entry.slotid = 0;
entry.itemid = 0;
entry.charges = 0;
entry.augslot1 = 0;
entry.augslot2 = 0;
entry.augslot3 = 0;
entry.augslot4 = 0;
entry.augslot5 = 0;
entry.augslot6 = 0;
entry.custom_data = 0;
return entry;
}
static Sharedbank GetSharedbankEntry(
const std::vector<Sharedbank> &sharedbanks,
int sharedbank_id
)
{
for (auto &sharedbank : sharedbanks) {
if (sharedbank. == sharedbank_id) {
return sharedbank;
}
}
return NewEntity();
}
static Sharedbank FindOne(
int sharedbank_id
)
{
auto results = database.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
sharedbank_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
Sharedbank entry{};
entry.acctid = atoi(row[0]);
entry.slotid = atoi(row[1]);
entry.itemid = atoi(row[2]);
entry.charges = atoi(row[3]);
entry.augslot1 = atoi(row[4]);
entry.augslot2 = atoi(row[5]);
entry.augslot3 = atoi(row[6]);
entry.augslot4 = atoi(row[7]);
entry.augslot5 = atoi(row[8]);
entry.augslot6 = atoi(row[9]);
entry.custom_data = row[10];
return entry;
}
return NewEntity();
}
static int DeleteOne(
int sharedbank_id
)
{
auto results = database.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
sharedbank_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Sharedbank sharedbank_entry
)
{
std::vector<std::string> update_values;
auto columns = Columns();
update_values.push_back(columns[0] + " = " + std::to_string(sharedbank_entry.acctid));
update_values.push_back(columns[1] + " = " + std::to_string(sharedbank_entry.slotid));
update_values.push_back(columns[2] + " = " + std::to_string(sharedbank_entry.itemid));
update_values.push_back(columns[3] + " = " + std::to_string(sharedbank_entry.charges));
update_values.push_back(columns[4] + " = " + std::to_string(sharedbank_entry.augslot1));
update_values.push_back(columns[5] + " = " + std::to_string(sharedbank_entry.augslot2));
update_values.push_back(columns[6] + " = " + std::to_string(sharedbank_entry.augslot3));
update_values.push_back(columns[7] + " = " + std::to_string(sharedbank_entry.augslot4));
update_values.push_back(columns[8] + " = " + std::to_string(sharedbank_entry.augslot5));
update_values.push_back(columns[9] + " = " + std::to_string(sharedbank_entry.augslot6));
update_values.push_back(columns[10] + " = '" + Strings::Escape(sharedbank_entry.custom_data) + "'");
auto results = database.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", update_values),
PrimaryKey(),
sharedbank_entry.
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static Sharedbank InsertOne(
Sharedbank sharedbank_entry
)
{
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(sharedbank_entry.acctid));
insert_values.push_back(std::to_string(sharedbank_entry.slotid));
insert_values.push_back(std::to_string(sharedbank_entry.itemid));
insert_values.push_back(std::to_string(sharedbank_entry.charges));
insert_values.push_back(std::to_string(sharedbank_entry.augslot1));
insert_values.push_back(std::to_string(sharedbank_entry.augslot2));
insert_values.push_back(std::to_string(sharedbank_entry.augslot3));
insert_values.push_back(std::to_string(sharedbank_entry.augslot4));
insert_values.push_back(std::to_string(sharedbank_entry.augslot5));
insert_values.push_back(std::to_string(sharedbank_entry.augslot6));
insert_values.push_back("'" + Strings::Escape(sharedbank_entry.custom_data) + "'");
auto results = database.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", insert_values)
)
);
if (results.Success()) {
sharedbank_entry.id = results.LastInsertedID();
return sharedbank_entry;
}
sharedbank_entry = InstanceListRepository::NewEntity();
return sharedbank_entry;
}
static int InsertMany(
std::vector<Sharedbank> sharedbank_entries
)
{
std::vector<std::string> insert_chunks;
for (auto &sharedbank_entry: sharedbank_entries) {
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(sharedbank_entry.acctid));
insert_values.push_back(std::to_string(sharedbank_entry.slotid));
insert_values.push_back(std::to_string(sharedbank_entry.itemid));
insert_values.push_back(std::to_string(sharedbank_entry.charges));
insert_values.push_back(std::to_string(sharedbank_entry.augslot1));
insert_values.push_back(std::to_string(sharedbank_entry.augslot2));
insert_values.push_back(std::to_string(sharedbank_entry.augslot3));
insert_values.push_back(std::to_string(sharedbank_entry.augslot4));
insert_values.push_back(std::to_string(sharedbank_entry.augslot5));
insert_values.push_back(std::to_string(sharedbank_entry.augslot6));
insert_values.push_back("'" + Strings::Escape(sharedbank_entry.custom_data) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", insert_values) + ")");
}
std::vector<std::string> insert_values;
auto results = database.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<Sharedbank> All()
{
std::vector<Sharedbank> all_entries;
auto results = database.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Sharedbank entry{};
entry.acctid = atoi(row[0]);
entry.slotid = atoi(row[1]);
entry.itemid = atoi(row[2]);
entry.charges = atoi(row[3]);
entry.augslot1 = atoi(row[4]);
entry.augslot2 = atoi(row[5]);
entry.augslot3 = atoi(row[6]);
entry.augslot4 = atoi(row[7]);
entry.augslot5 = atoi(row[8]);
entry.augslot6 = atoi(row[9]);
entry.custom_data = row[10];
all_entries.push_back(entry);
}
return all_entries;
}
// Custom extended repository methods here
};
@@ -44,7 +44,23 @@ public:
*/
// Custom extended repository methods here
static std::vector<std::string> GetSkillCapFileLines(Database& db)
{
std::vector<std::string> lines;
auto results = db.QueryDatabase(
fmt::format(
"SELECT CONCAT_WS('^', `class_id`, `skill_id`, `level`, `cap`, `class_`) FROM {} ORDER BY `class_id`, `skill_id`, `level` ASC",
TableName()
)
);
for (auto row : results) {
lines.emplace_back(row[0]);
}
return lines;
}
};
#endif //EQEMU_SKILL_CAPS_REPOSITORY_H
@@ -44,7 +44,25 @@ public:
*/
// Custom extended repository methods here
static std::vector<std::string> GetSpellFileLines(Database& db)
{
std::vector<std::string> lines;
auto results = db.QueryDatabase(
fmt::format(
"SELECT CONCAT_WS('^', {}) FROM {} ORDER BY {} ASC",
ColumnsRaw(),
TableName(),
PrimaryKey()
)
);
for (auto row : results) {
lines.emplace_back(row[0]);
}
return lines;
}
};
#endif //EQEMU_SPELLS_NEW_REPOSITORY_H
+213 -37
View File
@@ -1,50 +1,226 @@
#ifndef EQEMU_TRADER_REPOSITORY_H
#define EQEMU_TRADER_REPOSITORY_H
#include "../database.h"
#include "../../common/shareddb.h"
#include "../strings.h"
#include "base/base_trader_repository.h"
#include "items_repository.h"
#include "../../common/item_data.h"
#include "../../common/races.h"
#include "../cereal/include/cereal/archives/binary.hpp"
#include "../cereal/include/cereal/types/string.hpp"
class TraderRepository: public BaseTraderRepository {
class TraderRepository : public BaseTraderRepository {
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
*
* TraderRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* TraderRepository::GetWhereNeverExpires()
* TraderRepository::GetWhereXAndY()
* TraderRepository::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
*/
struct DistinctTraders_Struct {
uint32 trader_id;
uint32 zone_id;
uint32 entity_id;
std::string trader_name;
};
// Custom extended repository methods here
struct BulkTraders_Struct {
uint32 count{0};
uint32 name_length{0};
std::vector<DistinctTraders_Struct> traders{};
};
struct WelcomeData_Struct {
uint32 count_of_traders;
uint32 count_of_items;
};
static std::vector<BazaarSearchResultsFromDB_Struct>
GetBazaarSearchResults(
SharedDatabase &db,
BazaarSearchCriteria_Struct search,
uint32 char_zone_id
);
static BulkTraders_Struct GetDistinctTraders(Database &db)
{
BulkTraders_Struct all_entries{};
std::vector<DistinctTraders_Struct> distinct_traders;
auto results = db.QueryDatabase(
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_entity_id, c.name "
"FROM trader AS t "
"JOIN character_data AS c ON t.char_id = c.id;"
);
distinct_traders.reserve(results.RowCount());
for (auto row: results) {
DistinctTraders_Struct e{};
e.trader_id = Strings::ToInt(row[0]);
e.zone_id = Strings::ToInt(row[1]);
e.entity_id = Strings::ToInt(row[2]);
e.trader_name = row[3] ? row[3] : "";
all_entries.name_length += e.trader_name.length() + 1;
all_entries.traders.push_back(e);
}
all_entries.count = results.RowCount();
return all_entries;
}
static WelcomeData_Struct GetWelcomeData(Database &db)
{
WelcomeData_Struct e{};
auto results = db.QueryDatabase("SELECT COUNT(DISTINCT char_id), count(char_id) FROM trader;");
if (!results.RowCount()) {
return e;
}
auto r = results.begin();
e.count_of_traders = Strings::ToInt(r[0]);
e.count_of_items = Strings::ToInt(r[1]);
return e;
}
static int UpdateItem(Database &db, uint32 char_id, uint32 new_price, uint32 item_id, uint32 item_charges)
{
std::vector<BaseTraderRepository::Trader> items{};
if (item_charges == 0) {
items = GetWhere(
db,
fmt::format(
"char_id = '{}' AND item_id = '{}'",
char_id,
item_id
)
);
}
else {
items = GetWhere(
db,
fmt::format(
"char_id = '{}' AND item_id = '{}' AND item_charges = '{}'",
char_id,
item_id,
item_charges
)
);
}
if (items.empty()) {
return 0;
}
for (auto &i: items) {
i.item_cost = new_price;
}
return ReplaceMany(db, items);
}
static Trader GetTraderItem(Database &db, uint32 trader_id, uint32 item_id, uint32 item_cost)
{
Trader item{};
auto query = fmt::format(
"SELECT t.char_id, t.item_id, t.serialnumber, t.charges, t.item_cost, t.slot_id, t.entity_id FROM trader AS t "
"WHERE t.entity_id = {} AND t.item_id = {} AND t.item_cost = {} "
"LIMIT 1;",
trader_id,
item_id,
item_cost
);
auto results = db.QueryDatabase(query);
if (results.RowCount() == 0) {
return item;
}
auto row = results.begin();
item.char_id = Strings::ToInt(row[0]);
item.item_id = Strings::ToInt(row[1]);
item.item_sn = Strings::ToInt(row[2]);
item.item_charges = Strings::ToInt(row[3]);
item.item_cost = Strings::ToInt(row[4]);
item.slot_id = Strings::ToInt(row[5]);
return item;
}
static int UpdateQuantity(Database &db, uint32 char_id, uint32 serial_number, int16 quantity)
{
const auto trader_item = GetWhere(
db,
fmt::format("char_id = '{}' AND item_sn = '{}' ", char_id, serial_number)
);
if (trader_item.empty() || trader_item.size() > 1) {
return 0;
}
auto m = trader_item[0];
m.item_charges = quantity;
return UpdateOne(db, m);
}
static Trader GetItemBySerialNumber(Database &db, uint32 serial_number, uint32 trader_id)
{
Trader e{};
const auto trader_item = GetWhere(
db,
fmt::format("`char_id` = '{}' AND `item_sn` = '{}' LIMIT 1", trader_id, serial_number)
);
if (trader_item.empty()) {
return e;
}
return trader_item.at(0);
}
static Trader GetItemBySerialNumber(Database &db, std::string serial_number, uint32 trader_id)
{
Trader e{};
auto sn = Strings::ToUnsignedBigInt(serial_number);
const auto trader_item = GetWhere(
db,
fmt::format("`char_id` = '{}' AND `item_sn` = '{}' LIMIT 1", trader_id, sn)
);
if (trader_item.empty()) {
return e;
}
return trader_item.at(0);
}
static int UpdateActiveTransaction(Database &db, uint32 id, bool status)
{
auto e = FindOne(db, id);
if (!e.id) {
return 0;
}
e.active_transaction = status == true ? 1 : 0;
return UpdateOne(db, e);
}
static int DeleteMany(Database &db, const std::vector<Trader> &entries)
{
std::vector<std::string> delete_ids;
for (auto const &e: entries) {
delete_ids.push_back(std::to_string(e.id));
}
if (delete_ids.empty()) {
return 0;
}
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
}
};
#endif //EQEMU_TRADER_REPOSITORY_H
+2
View File
@@ -189,6 +189,8 @@ void RuleManager::ResetRules(bool reload) {
m_RuleRealValues[ Real__##rule_name ] = default_value;
#define RULE_BOOL(category_name, rule_name, default_value, notes) \
m_RuleBoolValues[ Bool__##rule_name ] = default_value;
#define RULE_STRING(category_name, rule_name, default_value, notes) \
m_RuleStringValues[ String__##rule_name ] = default_value;
#include "ruletypes.h"
// restore these rules to their pre-reset values
+62 -2
View File
@@ -178,6 +178,7 @@ RULE_BOOL(Character, NoSkillsOnHorse, false, "Enabling this will prevent Bind Wo
RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing")
RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted")
RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated")
RULE_INT(Character, DefaultGuildRank, 8, "Default guild rank when Character:DefaultGuild is a non-0 value, default is 8 (Recruit)")
RULE_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared")
RULE_BOOL(Character, EnableCharacterEXPMods, false, "Enables character zone-based experience modifiers.")
RULE_BOOL(Character, PVPEnableGuardFactionAssist, true, "Enables faction based assisting against the aggresor in pvp.")
@@ -226,6 +227,9 @@ RULE_INT(Character, ClearXTargetDelay, 10, "Seconds between uses of the #clearxt
RULE_BOOL(Character, PreventMountsFromZoning, false, "Enable to prevent mounts from zoning - Prior to December 15, 2004 this is enabled.")
RULE_BOOL(Character, GroupInvitesRequireTarget, false, "Enable to require players to have invitee on target (Disables /invite name) - Classic Style")
RULE_BOOL(Character, PlayerTradingLoreFeedback, true, "If enabled, during a player to player trade, if lore items exist, it will output which items.")
RULE_INT(Character, MendAlwaysSucceedValue, 199, "Value at which mend will always succeed its skill check. Default: 199")
RULE_BOOL(Character, SneakAlwaysSucceedOver100, false, "When sneak skill is over 100, always succeed sneak/hide. Default: false")
RULE_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0")
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
@@ -240,6 +244,9 @@ RULE_INT(Mercs, AggroRadiusPuller, 25, "Determines the distance from which a mer
RULE_INT(Mercs, ResurrectRadius, 50, "Determines the distance from which a healer merc will attempt to resurrect a group member's corpse")
RULE_INT(Mercs, ScaleRate, 100, "Merc scale factor")
RULE_BOOL(Mercs, AllowMercSuspendInCombat, true, "Allow merc suspend in combat")
RULE_BOOL(Mercs, MercsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_INT(Mercs, MercsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
RULE_INT(Mercs, MercsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_CATEGORY_END()
RULE_CATEGORY(Guild)
@@ -331,6 +338,8 @@ RULE_STRING(World, IPExemptionZones, "", "Comma-delimited list of zones to exclu
RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to have this be used instead of variables table 'motd' value")
RULE_STRING(World, Rules, "", "Server Rules, change from empty to have this be used instead of variables table 'rules' value, lines are pipe (|) separated, example: A|B|C")
RULE_BOOL(World, EnableAutoLogin, false, "Enables or disables auto login of characters, allowing people to log characters in directly from loginserver to ingame")
RULE_BOOL(World, EnablePVPRegions, true, "Enables or disables PVP Regions automatically setting your PVP flag")
RULE_STRING(World, SupportedClients, "RoF2", "Comma-delimited list of clients to restrict to. Supported values are Titanium | SoF | SoD | UF | RoF | RoF2. Example: Titanium,RoF2")
RULE_CATEGORY_END()
RULE_CATEGORY(Zone)
@@ -468,7 +477,6 @@ RULE_BOOL(Spells, OldRainTargets, false, "Use old incorrectly implemented maximu
RULE_REAL(Spells, CallOfTheHeroAggroClearDist, 250.0, "Distance at which CoTH will wipe aggro. To disable and always enable aggro wipe on any distance of CoTH, set to 0.")
RULE_BOOL(Spells, NPCSpellPush, false, "Enable spell push on NPCs")
RULE_BOOL(Spells, July242002PetResists, true, "Enable Pets using PCs resist change from July 24 2002")
RULE_INT(Spells, AOEMaxTargets, 0, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.")
RULE_BOOL(Spells, CazicTouchTargetsPetOwner, true, "If True, causes Cazic Touch to swap targets from pet to pet owner if a pet is tanking.")
RULE_BOOL(Spells, PreventFactionWarOnCharmBreak, false, "Enable spell interupts and dot removal on charm break to prevent faction wars.")
RULE_BOOL(Spells, AllowDoubleInvis, true, "Allows you to cast invisibility spells on a player that is already invisible, live like behavior.")
@@ -503,8 +511,15 @@ RULE_BOOL(Spells, RequireMnemonicRetention, true, "Enabling will require spell s
RULE_BOOL(Spells, EvacClearCharmPet, false, "Enable to have evac in zone clear charm from charm pets and detach buffs.")
RULE_BOOL(Spells, ManaTapsRequireNPCMana, false, "Enabling will require target to have mana to tap. Default off as many npc's are caster class with 0 mana and need fixed.")
RULE_INT(Spells, HarmTouchCritRatio, 200, "Harmtouch crit bonus, on top of BaseCritRatio")
RULE_BOOL(Spells, UseClassicHarmTouchDamage, false, "Use pre 2007 Harm Touch calculations - Default: False")
RULE_BOOL(Spells, UseClassicSpellFocus, false, "Enabling will tell the server to handle random focus damage as classic spell imports lack the limit values.")
RULE_BOOL(Spells, ManaTapsOnAnyClass, false, "Enabling this will allow you to cast mana taps on any class, this will bypass ManaTapsRequireNPCMana rule.")
RULE_INT(Spells, HealAmountMessageFilterThreshold, 100, "Lifetaps below this threshold will not have a message sent to the client (Heal will still process) 0 to Disable.")
RULE_BOOL(Spells, SnareOverridesSpeedBonuses, false, "Enabling will allow snares to override any speed bonuses the entity may have. Default: False")
RULE_INT(Spells, TargetedAOEMaxTargets, 4, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.")
RULE_INT(Spells, PointBlankAOEMaxTargets, 0, "Max number of targets a Point-Blank AOE spell can cast on. Set to 0 for no limit.")
RULE_INT(Spells, DefaultAOEMaxTargets, 0, "Max number of targets that an AOE spell which does not meet other descriptions can cast on. Set to 0 for no limit.")
RULE_BOOL(Spells, AllowFocusOnSkillDamageSpells, false, "Allow focus effects 185, 459, and 482 to enhance SkillAttack spell effect 193")
RULE_CATEGORY_END()
RULE_CATEGORY(Combat)
@@ -520,6 +535,8 @@ RULE_BOOL(Combat, NPCCanCrit, false, "Setting whether an NPC can land critical h
RULE_BOOL(Combat, UseIntervalAC, true, "Switch whether bonuses, armour class, multipliers, classes and caps should be considered in the calculation of damage values")
RULE_INT(Combat, PetAttackMagicLevel, 10, "Level at which pets can cause magic damage, no longer used")
RULE_INT(Combat, NPCAttackMagicLevel, 10, "Level at which NPC and pets can cause magic damage")
RULE_INT(Combat, LevelDifferenceRollCheck, -1, "Level Difference to enable LeverDifferenceRollBonus for MeleeMitigation - Default: -1 is disabled, 20 is common")
RULE_REAL(Combat, LevelDifferenceRollBonus, 0.5, "Roll Bonus/Detrement if using LevelDifferenceRollCheck")
RULE_BOOL(Combat, EnableFearPathing, true, "Setting whether to use pathing during fear")
RULE_BOOL(Combat, FleeGray, true, "If true FleeGrayHPRatio will be used")
RULE_INT(Combat, FleeGrayHPRatio, 50, "HP percentage when a Gray NPC begins to flee")
@@ -589,6 +606,8 @@ RULE_BOOL(Combat, BackstabIgnoresElemental, false, "Enable or disable Elemental
RULE_BOOL(Combat, BackstabIgnoresBane, false, "Enable or disable Bane weapon damage affecting backstab damage, false by default.")
RULE_INT(Combat, DoubleBackstabLevelRequirement, 55, "Level requirement to enable double backstab attempts. The default is 55.")
RULE_BOOL(Combat, SummonMeleeRange, true, "Enable or disable summoning of a player when already in melee range of the summoner.")
RULE_REAL(Combat, ArcheryHitPenalty, 0, "Archery has a hit penalty to try to help balance it with the plethora of long term +hit modifiers for it - Default: 0")
RULE_REAL(Combat, ArcheryBaseDamageBonus, 1, "Percentage modifier to base archery Damage 0.5=50% base damage, 1=100%,2=200% - Default: 1")
RULE_BOOL(Combat, WaterMatchRequiredForAutoFireLoS, true, "Enable/Disable the requirement of both the attacker/victim being both in or out of water for AutoFire LoS to pass.")
RULE_INT(Combat, ExtraAllowedKickClassesBitmask, 0, "Bitmask for allowing extra classes beyond Warrior, Ranger, Beastlord, and Berserker to kick, No Extra Classes (0) by default")
RULE_INT(Combat, MaxProcs, 4, "Adjustable maximum number of procs per round, the hard cap is MAX_PROCS (11). Requires mob repop or client zone when changed")
@@ -603,6 +622,27 @@ RULE_INT(Combat, StunDuration, 2000, "Duration of stuns in ms. DEFAULT: 2000")
RULE_BOOL(Combat, ClientStunMessage, false, "Client stunning NPC produces message. DEFAULT false")
RULE_BOOL(Combat, BashTwoHanderUseShoulderAC, false, "Enable to use shoulder AC for bash calculations when two hander is equipped. Unproven if accurate DEFAULT: false")
RULE_REAL(Combat, BashACBonusDivisor, 25.0, "this divides the AC value contribution to bash damage, lower to increase damage")
RULE_BOOL(Combat, UseMobStaticOffenseSkill, false, "Toggle to enabled the use of a static offense skill for Mobs. DEFAULT: false")
RULE_BOOL(Combat, UseEnhancedMobStaticWeaponSkill, false, "Toggle to enabled the use of an enhanced (slightly higher hit rate) static weapon skill for Mobs. DEFAULT: false")
RULE_INT(Combat, PCAttackPowerScaling, 100, "Applies scaling to PC Attack Power (75 = 75%). DEFAULT: 100 to not adjust existing Servers")
RULE_INT(Combat, PCAccuracyAvoidanceMod2Scale, 100, "Scale Factor for PC Accuracy and Avoidance (Mod2, found on items). Found a value of 100 to make both too strong (75 = x0.75). DEFAULT: 100 to not adjust existing Servers")
RULE_BOOL(Combat, AllowRaidTargetBlind, false, "Toggle to allow raid targets to be blinded, default is false (Live-like)")
RULE_BOOL(Combat, RogueBackstabHasteCorrection, false, "Toggle to enable correction for Haste impacting Backstab DPS too much. DEFAULT: false")
RULE_BOOL(Combat, LegacyComputeDefense, false, "Trim AGI Scaling of defense mostly for lower levels to help compensate for the newer agi based defense system. Default: False")
RULE_REAL(Combat, SlayDamageMultiplier, 1.0, "Slay Damage Adjustment - Multiply final slay damage by this value. Default: 1.0")
RULE_REAL(Combat, SlayRateMultiplier, 1.0, "Slay Rate Adjustments - Multiply final slay rate check by this value. Default: 1.0")
RULE_INT(Combat, MaximumLevelStunsCripplingBlow, 55, "Maximum level that Crippling Blows will stun a npc. Default: 55")
RULE_INT(Combat, ArcheryBaseDamage, 0, "Archery base damage, default is 0")
RULE_INT(Combat, BackstabBaseDamage, 0, "Backstab base damage, default is 0")
RULE_INT(Combat, BashBaseDamage, 2, "Bash base damage, default is 2")
RULE_INT(Combat, DragonPunchBaseDamage, 12, "Dragon Punch base damage, default is 12")
RULE_INT(Combat, EagleStrikeBaseDamage, 7, "Eagle Strike base damage, default is 7")
RULE_INT(Combat, FlyingKickBaseDamage, 25, "Flying Kick base damage, default is 25")
RULE_INT(Combat, FrenzyBaseDamage, 10, "Frenzy base damage, default is 10")
RULE_INT(Combat, KickBaseDamage, 3, "Kick base damage, default is 3")
RULE_INT(Combat, RoundKickBaseDamage, 5, "Round Kick base damage, default is 5")
RULE_INT(Combat, ThrowingBaseDamage, 0, "Throwing base damage, default is 0")
RULE_INT(Combat, TigerClawBaseDamage, 4, "Tiger Claw base damage, default is 4")
RULE_CATEGORY_END()
RULE_CATEGORY(NPC)
@@ -638,6 +678,9 @@ RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the NPC will heal on gate if e
RULE_BOOL(NPC, AnimalsOpenDoors, true, "Determines or not whether animals open doors or not when they approach them")
RULE_INT(NPC, MaxRaceID, 732, "Maximum Race ID, RoF2 by default supports up to 732")
RULE_BOOL(NPC, DisableLastNames, false, "Enable to disable NPC Last Names")
RULE_BOOL(NPC, NPCIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_INT(NPC, NPCHasteCap, 150, "Haste cap for non-v3(over haste) haste")
RULE_INT(NPC, NPCHastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_CATEGORY_END()
RULE_CATEGORY(Aggro)
@@ -661,6 +704,9 @@ RULE_BOOL(Aggro, NPCAggroMaxDistanceEnabled, true, "If enabled, NPC's will drop
RULE_BOOL(Aggro, AggroPlayerPets, false, "If enabled, NPCs will aggro player pets")
RULE_BOOL(Aggro, UndeadAlwaysAggro, true, "should undead always aggro?")
RULE_INT(Aggro, BardAggroCap, 40, "per song bard aggro cap.")
RULE_INT(Aggro, InitialAggroBonus, 100, "Initial Aggro Bonus, Default: 100")
RULE_INT(Aggro, InitialPetAggroBonus, 100, "Initial Pet Aggro Bonus, Default 100")
RULE_STRING(Aggro, ExcludedFleeAllyFactionIDs, "0|5013|5014|5023|5032", "Common Faction IDs that are excluded from faction checks in EntityList::FleeAllyCount")
RULE_CATEGORY_END()
RULE_CATEGORY(TaskSystem)
@@ -675,6 +721,7 @@ RULE_BOOL(TaskSystem, ExpRewardsIgnoreLevelBasedEXPMods, false, "Rewarding Level
RULE_INT(TaskSystem, SharedTasksWorldProcessRate, 6000, "Timer interval (milliseconds) that shared tasks are processed in world")
RULE_INT(TaskSystem, SharedTasksTerminateTimerMS, 120000, "Delay (milliseconds) until a shared task is terminated if requirements are no longer met after member removal (default: 2 minutes)")
RULE_BOOL(TaskSystem, UpdateOneElementPerTask, true, "If true (live-like) task updates only increment the first matching activity. If false all matching elements will be incremented.")
RULE_INT(TaskSystem, MaxUpdateMessages, 50, "Maximum update messages for non-GiveCash activity types in IncrementDoneCount")
RULE_CATEGORY_END()
RULE_CATEGORY(Range)
@@ -686,6 +733,7 @@ RULE_INT(Range, SpellParticles, 135, "The packet range in which spell particles
RULE_INT(Range, DamageMessages, 50, "The packet range in which damage messages are sent (non-crit)")
RULE_INT(Range, SpellMessages, 75, "The packet range in which spell damage messages are sent")
RULE_INT(Range, SongMessages, 75, "The packet range in which song messages are sent")
RULE_INT(Range, StunMessages, 75, "The packet range in which stun messages are sent")
RULE_INT(Range, ClientPositionUpdates, 300, "Distance in which the own changed position is communicated to other clients")
RULE_INT(Range, CriticalDamage, 80, "The packet range in which critical hit messages are sent")
RULE_INT(Range, MobCloseScanDistance, 600, "Close scan distance")
@@ -725,8 +773,11 @@ RULE_BOOL(Bots, BotHealOnLevel, false, "Setting whether a bot should heal comple
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, BotsCanClickItems, true, "Enables 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_BOOL(Bots, BotsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_INT(Bots, BotsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
RULE_INT(Bots, BotsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_CATEGORY_END()
RULE_CATEGORY(Chat)
@@ -754,6 +805,7 @@ RULE_CATEGORY_END()
RULE_CATEGORY(Merchant)
RULE_BOOL(Merchant, UsePriceMod, true, "Use faction/charisma price modifiers")
RULE_BOOL(Merchant, UseClassicPriceMod, false, "Must also set UsePriceMod. Negates other rules for vendor price mods.")
RULE_REAL(Merchant, SellCostMod, 1.05, "Modifier for NPC sell price")
RULE_REAL(Merchant, BuyCostMod, 0.95, "Modifier for NPC buy price")
RULE_INT(Merchant, PriceBonusPct, 4, "Determines maximum price bonus from having good faction/CHA. Value is a percent")
@@ -769,6 +821,10 @@ RULE_BOOL(Bazaar, AuditTrail, false, "Setting whether a path to the trader shoul
RULE_INT(Bazaar, MaxSearchResults, 50, "Maximum number of search results in Bazaar")
RULE_BOOL(Bazaar, EnableWarpToTrader, true, "Setting whether teleport to the selected trader should be active")
RULE_INT(Bazaar, MaxBarterSearchResults, 200, "The maximum results returned in the /barter search")
RULE_REAL(Bazaar, ParcelDeliveryCostMod, 0.20, "Cost of parcel delivery for a bazaar purchase as a percentage of item cost. Default is 20% of item cost. RoF+ Only.")
RULE_INT(Bazaar, VoucherDeliveryCost, 200, "Number of vouchers for direct delivery for a bazaar purchase. Default is 200 vouchers. RoF+ Only.")
RULE_BOOL(Bazaar, EnableParcelDelivery, true, "Enable bazaar purchases via parcel delivery. Default is True.")
RULE_INT(Bazaar, MaxBuyerInventorySearchResults, 200, "Maximum number of search results when a Buyer searches the global item list. Default is 200. RoF+ Only.")
RULE_CATEGORY_END()
RULE_CATEGORY(Mail)
@@ -813,6 +869,7 @@ RULE_INT(AA, ModernAAScalingAAMinimum, 0, "The minimum number of earned AA befor
RULE_INT(AA, ModernAAScalingAALimit, 4000, "The number of earned AA when AA experience scaling ends")
RULE_BOOL(AA, SoundForAAEarned, false, "Play sound when AA point earned")
RULE_INT(AA, UnusedAAPointCap, -1, "Cap for Unused AA Points. Default: -1. NOTE: DO NOT LOWER THIS WITHOUT KNOWING WHAT YOU ARE DOING. MAY RESULT IN PLAYERS LOSING AAs.")
RULE_INT(AA, MaxAAEXPPerKill, -1, "Maximum AA EXP per Kill (3425214 is about 7%) - Default: -1 will disable the check")
RULE_CATEGORY_END()
RULE_CATEGORY(Console)
@@ -859,6 +916,7 @@ RULE_BOOL(Inventory, AllowAnyWeaponTransformation, false, "Weapons can use any w
RULE_BOOL(Inventory, TransformSummonedBags, false, "Transforms summoned bags into disenchanted ones instead of deleting")
RULE_BOOL(Inventory, AllowMultipleOfSameAugment, false, "Allows multiple of the same augment to be placed in an item via #augmentitem or MQ2, set to true to allow")
RULE_INT(Inventory, AlternateAugmentationSealer, 53, "Allows RoF+ clients to augment items from a special container type")
RULE_BOOL(Inventory, LazyLoadBank, true, "Don't load bank during zoning, only when in proximinity to a banker. May increase zone speed and stability")
RULE_CATEGORY_END()
RULE_CATEGORY(Client)
@@ -961,6 +1019,8 @@ RULE_BOOL(Items, DisableNoRent, false, "Enable this to disable No Rent Items")
RULE_BOOL(Items, DisableNoTransfer, false, "Enable this to disable No Transfer Items")
RULE_BOOL(Items, DisablePotionBelt, false, "Enable this to disable Potion Belt Items")
RULE_BOOL(Items, DisableSpellFocusEffects, false, "Enable this to disable Spell Focus Effects on Items")
RULE_BOOL(Items, SummonItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots of items in Client::SummonItem")
RULE_BOOL(Items, AugmentItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots by players")
RULE_CATEGORY_END()
RULE_CATEGORY(Parcel)
+26
View File
@@ -138,6 +138,10 @@
#define ServerOP_RaidMOTD 0x0113
#define ServerOP_RaidNote 0x0114
#define ServerOP_TraderMessaging 0x0120
#define ServerOP_BazaarPurchase 0x0121
#define ServerOP_BuyerMessaging 0x0122
#define ServerOP_InstanceUpdateTime 0x014F
#define ServerOP_AdventureRequest 0x0150
#define ServerOP_AdventureRequestAccept 0x0151
@@ -277,6 +281,7 @@
#define ServerOP_ReloadLoot 0x4127
#define ServerOP_ReloadBaseData 0x4128
#define ServerOP_ReloadSkillCaps 0x4129
#define ServerOP_ReloadNPCSpells 0x4130
#define ServerOP_CZDialogueWindow 0x4500
#define ServerOP_CZLDoNUpdate 0x4501
@@ -1937,6 +1942,27 @@ struct ServerOP_GuildMessage_Struct {
char url[2048]{0};
};
struct TraderMessaging_Struct {
uint32 action;
uint32 zone_id;
uint32 trader_id;
uint32 entity_id;
char trader_name[64];
};
struct BazaarPurchaseMessaging_Struct {
TraderBuy_Struct trader_buy_struct;
uint32 item_aug_1;
uint32 item_aug_2;
uint32 item_aug_3;
uint32 item_aug_4;
uint32 item_aug_5;
uint32 item_aug_6;
uint32 buyer_id;
uint32 item_quantity_available;
uint32 id;
};
#pragma pack()
#endif
+361 -411
View File
@@ -46,6 +46,9 @@
#include "repositories/character_item_recast_repository.h"
#include "repositories/character_corpses_repository.h"
#include "repositories/skill_caps_repository.h"
#include "repositories/inventory_repository.h"
#include "repositories/books_repository.h"
#include "repositories/sharedbank_repository.h"
namespace ItemField
{
@@ -188,242 +191,268 @@ SharedDatabase::MailKeys SharedDatabase::GetMailKey(int character_id)
return MailKeys{};
}
bool SharedDatabase::SaveCursor(uint32 char_id, std::list<EQ::ItemInstance*>::const_iterator &start, std::list<EQ::ItemInstance*>::const_iterator &end)
bool SharedDatabase::SaveCursor(
uint32 char_id,
std::list<EQ::ItemInstance*>::const_iterator& start,
std::list<EQ::ItemInstance*>::const_iterator& end
)
{
// Delete cursor items
const std::string query = StringFormat("DELETE FROM inventory WHERE charid = %i "
"AND ((slotid >= 8000 AND slotid <= 8999) "
"OR slotid = %i OR (slotid >= %i AND slotid <= %i) )",
char_id, EQ::invslot::slotCursor,
EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END);
const auto results = QueryDatabase(query);
if (!results.Success()) {
std::cout << "Clearing cursor failed: " << results.ErrorMessage() << std::endl;
return false;
}
const int deleted = InventoryRepository::DeleteWhere(
*this,
fmt::format(
"`character_id` = {} AND (`slot_id` = {} OR `slot_id` BETWEEN {} AND {})",
char_id,
EQ::invslot::slotCursor,
EQ::invbag::CURSOR_BAG_BEGIN,
EQ::invbag::CURSOR_BAG_END
)
);
int i = 8000;
for(auto& it = start; it != end; ++it, i++) {
if (i > 8999) { break; } // shouldn't be anything in the queue that indexes this high
const EQ::ItemInstance *inst = *it;
const int16 use_slot = (i == 8000) ? EQ::invslot::slotCursor : i;
int16 i = EQ::invslot::slotCursor;
for (auto& it = start; it != end; ++it, i++) {
// shouldn't be anything in the queue that indexes this high
if (i > EQ::invbag::CURSOR_BAG_END) {
break;
}
const EQ::ItemInstance* inst = *it;
const int16 use_slot = i == EQ::invslot::slotCursor ? EQ::invslot::slotCursor : i;
if (!SaveInventory(char_id, inst, use_slot)) {
return false;
}
}
}
return true;
}
bool SharedDatabase::VerifyInventory(uint32 account_id, int16 slot_id, const EQ::ItemInstance* inst)
{
// Delete cursor items
const std::string query = StringFormat("SELECT itemid, charges FROM sharedbank "
"WHERE acctid = %d AND slotid = %d",
account_id, slot_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
//returning true is less harmful in the face of a query error
return true;
if (!inst || !inst->GetItem()) {
return false;
}
if (results.RowCount() == 0)
return false;
const auto& l = SharedbankRepository::GetWhere(
*this,
fmt::format(
"`account_id` = {} AND `slot_id` = {} LIMIT 1",
account_id,
slot_id
)
);
auto& row = results.begin();
if (l.empty()) {
return false;
}
const uint32 id = Strings::ToUnsignedInt(row[0]);
const uint16 charges = Strings::ToUnsignedInt(row[1]);
const auto& e = l.front();
uint16 expect_charges;
uint16 expect_charges = inst->GetCharges() >= 0 ? inst->GetCharges() : std::numeric_limits<int16>::max();
if(inst->GetCharges() >= 0)
expect_charges = inst->GetCharges();
else
expect_charges = 0x7FFF;
if(id != inst->GetItem()->ID || charges != expect_charges)
return false;
return true;
return e.item_id == inst->GetID() && e.charges == expect_charges;
}
bool SharedDatabase::SaveInventory(uint32 char_id, const EQ::ItemInstance* inst, int16 slot_id) {
//never save tribute slots:
if (slot_id >= EQ::invslot::TRIBUTE_BEGIN && slot_id <= EQ::invslot::TRIBUTE_END)
return true;
if (slot_id >= EQ::invslot::GUILD_TRIBUTE_BEGIN && slot_id <= EQ::invslot::GUILD_TRIBUTE_END)
bool SharedDatabase::SaveInventory(uint32 char_id, const EQ::ItemInstance* inst, int16 slot_id)
{
// Don't save any Tribute slots
if (
EQ::ValueWithin(slot_id, EQ::invslot::GUILD_TRIBUTE_BEGIN, EQ::invslot::GUILD_TRIBUTE_END) ||
EQ::ValueWithin(slot_id, EQ::invslot::TRIBUTE_BEGIN, EQ::invslot::TRIBUTE_END)
) {
return true;
}
if (slot_id >= EQ::invslot::SHARED_BANK_BEGIN && slot_id <= EQ::invbag::SHARED_BANK_BAGS_END) {
// Shared bank inventory
if (
EQ::ValueWithin(slot_id, EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END) ||
EQ::ValueWithin(slot_id, EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END)
) {
if (!inst) {
return DeleteSharedBankSlot(char_id, slot_id);
}
else {
} else {
// Needed to clear out bag slots that 'REPLACE' in UpdateSharedBankSlot does not overwrite..otherwise, duplication occurs
// (This requires that parent then child items be sent..which should be how they are currently passed)
if (EQ::InventoryProfile::SupportsContainers(slot_id))
if (EQ::InventoryProfile::SupportsContainers(slot_id)) {
DeleteSharedBankSlot(char_id, slot_id);
}
return UpdateSharedBankSlot(char_id, inst, slot_id);
}
}
else if (!inst) { // All other inventory
} else if (!inst) { // All other inventory
return DeleteInventorySlot(char_id, slot_id);
}
// Needed to clear out bag slots that 'REPLACE' in UpdateInventorySlot does not overwrite..otherwise, duplication occurs
// (This requires that parent then child items be sent..which should be how they are currently passed)
if (EQ::InventoryProfile::SupportsContainers(slot_id))
if (EQ::InventoryProfile::SupportsContainers(slot_id)) {
DeleteInventorySlot(char_id, slot_id);
return UpdateInventorySlot(char_id, inst, slot_id);
}
bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const EQ::ItemInstance* inst, int16 slot_id) {
// need to check 'inst' argument for valid pointer
uint32 augslot[EQ::invaug::SOCKET_COUNT] = { 0, 0, 0, 0, 0, 0 };
if (inst->IsClassCommon()) {
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
const EQ::ItemInstance *auginst = inst->GetItem(i);
augslot[i] = (auginst && auginst->GetItem()) ? auginst->GetItem()->ID : 0;
}
}
uint16 charges;
if(inst->GetCharges() >= 0)
charges = inst->GetCharges();
else
charges = 0x7FFF;
// Update/Insert item
const std::string query = StringFormat("REPLACE INTO inventory "
"(charid, slotid, itemid, charges, instnodrop, custom_data, color, "
"augslot1, augslot2, augslot3, augslot4, augslot5, augslot6, ornamenticon, ornamentidfile, ornament_hero_model) "
"VALUES( %lu, %lu, %lu, %lu, %lu, '%s', %lu, "
"%lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu)",
static_cast<unsigned long>(char_id), static_cast<unsigned long>(slot_id), static_cast<unsigned long>(inst->GetItem()->ID),
static_cast<unsigned long>(charges), static_cast<unsigned long>(inst->IsAttuned() ? 1 : 0),
inst->GetCustomDataString().c_str(), static_cast<unsigned long>(inst->GetColor()),
static_cast<unsigned long>(augslot[0]), static_cast<unsigned long>(augslot[1]), static_cast<unsigned long>(augslot[2]),
static_cast<unsigned long>(augslot[3]), static_cast<unsigned long>(augslot[4]), static_cast<unsigned long>(augslot[5]), static_cast<unsigned long>(inst->GetOrnamentationIcon()),
static_cast<unsigned long>(inst->GetOrnamentationIDFile()), static_cast<unsigned long>(inst->GetOrnamentHeroModel()));
const auto results = QueryDatabase(query);
// Save bag contents, if slot supports bag contents
if (inst->IsClassBag() && EQ::InventoryProfile::SupportsContainers(slot_id))
// Limiting to bag slot count will get rid of 'hidden' duplicated items and 'Invalid Slot ID'
// messages through attrition (and the modded code in SaveInventory)
for (uint8 idx = EQ::invbag::SLOT_BEGIN; idx < inst->GetItem()->BagSlots && idx <= EQ::invbag::SLOT_END; idx++) {
const EQ::ItemInstance* baginst = inst->GetItem(idx);
SaveInventory(char_id, baginst, EQ::InventoryProfile::CalcSlotId(slot_id, idx));
}
if (!results.Success()) {
return false;
}
return true;
return UpdateInventorySlot(char_id, inst, slot_id);
}
bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const EQ::ItemInstance* inst, int16 slot_id) {
// need to check 'inst' argument for valid pointer
uint32 augslot[EQ::invaug::SOCKET_COUNT] = { 0, 0, 0, 0, 0, 0 };
if (inst->IsClassCommon()) {
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
const EQ::ItemInstance *auginst = inst->GetItem(i);
augslot[i] = (auginst && auginst->GetItem()) ? auginst->GetItem()->ID : 0;
}
bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const EQ::ItemInstance* inst, int16 slot_id)
{
if (!inst || !inst->GetItem()) {
return false;
}
// Update/Insert item
const uint32 account_id = GetAccountIDByChar(char_id);
uint16 charges;
if(inst->GetCharges() >= 0)
charges = inst->GetCharges();
else
charges = 0x7FFF;
std::vector<uint32> augment_ids = inst->GetAugmentIDs();
const std::string query = StringFormat("REPLACE INTO sharedbank "
"(acctid, slotid, itemid, charges, custom_data, "
"augslot1, augslot2, augslot3, augslot4, augslot5, augslot6) "
"VALUES( %lu, %lu, %lu, %lu, '%s', "
"%lu, %lu, %lu, %lu, %lu, %lu)",
static_cast<unsigned long>(account_id), static_cast<unsigned long>(slot_id), static_cast<unsigned long>(inst->GetItem()->ID),
static_cast<unsigned long>(charges), inst->GetCustomDataString().c_str(), static_cast<unsigned long>(augslot[0]),
static_cast<unsigned long>(augslot[1]), static_cast<unsigned long>(augslot[2]), static_cast<unsigned long>(augslot[3]), static_cast<unsigned long>(augslot[4]),
static_cast<unsigned long>(augslot[5]));
const auto results = QueryDatabase(query);
uint16 charges = inst->GetCharges() >= 0 ? inst->GetCharges() : std::numeric_limits<int16>::max();
// Save bag contents, if slot supports bag contents
auto e = InventoryRepository::NewEntity();
e.character_id = char_id;
e.slot_id = slot_id;
e.item_id = inst->GetID();
e.charges = charges;
e.color = inst->GetColor();
e.augment_one = augment_ids[0];
e.augment_two = augment_ids[1];
e.augment_three = augment_ids[2];
e.augment_four = augment_ids[3];
e.augment_five = augment_ids[4];
e.augment_six = augment_ids[5];
e.instnodrop = inst->IsAttuned() ? 1 : 0;
e.custom_data = inst->GetCustomDataString();
e.ornament_icon = inst->GetOrnamentationIcon();
e.ornament_idfile = inst->GetOrnamentationIDFile();
e.ornament_hero_model = inst->GetOrnamentHeroModel();
e.guid = inst->GetSerialNumber();
const int replaced = InventoryRepository::ReplaceOne(*this, e);
// Save bag contents, if slot supports bag contents
if (inst->IsClassBag() && EQ::InventoryProfile::SupportsContainers(slot_id)) {
// Limiting to bag slot count will get rid of 'hidden' duplicated items and 'Invalid Slot ID'
// messages through attrition (and the modded code in SaveInventory)
for (uint8 idx = EQ::invbag::SLOT_BEGIN; idx < inst->GetItem()->BagSlots && idx <= EQ::invbag::SLOT_END; idx++) {
const EQ::ItemInstance* baginst = inst->GetItem(idx);
SaveInventory(char_id, baginst, EQ::InventoryProfile::CalcSlotId(slot_id, idx));
for (
uint8 i = EQ::invbag::SLOT_BEGIN;
i < inst->GetItem()->BagSlots && i <= EQ::invbag::SLOT_END;
i++
) {
const EQ::ItemInstance* bag_inst = inst->GetItem(i);
SaveInventory(char_id, bag_inst, EQ::InventoryProfile::CalcSlotId(slot_id, i));
}
}
if (!results.Success()) {
return false;
}
return true;
return replaced;
}
bool SharedDatabase::DeleteInventorySlot(uint32 char_id, int16 slot_id) {
bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const EQ::ItemInstance* inst, int16 slot_id)
{
if (!inst || !inst->GetItem()) {
return false;
}
// Delete item
std::string query = StringFormat("DELETE FROM inventory WHERE charid = %i AND slotid = %i", char_id, slot_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
std::vector<uint32> augment_ids = inst->GetAugmentIDs();
// Delete bag slots, if need be
if (!EQ::InventoryProfile::SupportsContainers(slot_id))
return true;
uint16 charges = inst->GetCharges() >= 0 ? inst->GetCharges() : std::numeric_limits<int16>::max();
const int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(slot_id, EQ::invbag::SLOT_BEGIN);
query = StringFormat("DELETE FROM inventory WHERE charid = %i AND slotid >= %i AND slotid < %i",
char_id, base_slot_id, (base_slot_id+10));
results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
const uint32 account_id = GetAccountIDByChar(char_id);
// @merth: need to delete augments here
return true;
auto e = SharedbankRepository::NewEntity();
e.account_id = account_id;
e.slot_id = slot_id;
e.item_id = inst->GetID();
e.charges = charges;
e.color = inst->GetColor();
e.augment_one = augment_ids[0];
e.augment_two = augment_ids[1];
e.augment_three = augment_ids[2];
e.augment_four = augment_ids[3];
e.augment_five = augment_ids[4];
e.augment_six = augment_ids[5];
e.custom_data = inst->GetCustomDataString();
e.ornament_icon = inst->GetOrnamentationIcon();
e.ornament_idfile = inst->GetOrnamentationIDFile();
e.ornament_hero_model = inst->GetOrnamentHeroModel();
e.guid = inst->GetSerialNumber();
const int replaced = SharedbankRepository::ReplaceOne(*this, e);
// Save bag contents, if slot supports bag contents
if (inst->IsClassBag() && EQ::InventoryProfile::SupportsContainers(slot_id)) {
// Limiting to bag slot count will get rid of 'hidden' duplicated items and 'Invalid Slot ID'
// messages through attrition (and the modded code in SaveInventory)
for (
uint8 i = EQ::invbag::SLOT_BEGIN;
i < inst->GetItem()->BagSlots && i <= EQ::invbag::SLOT_END;
i++
) {
const EQ::ItemInstance* bag_inst = inst->GetItem(i);
SaveInventory(char_id, bag_inst, EQ::InventoryProfile::CalcSlotId(slot_id, i));
}
}
return replaced;
}
bool SharedDatabase::DeleteSharedBankSlot(uint32 char_id, int16 slot_id) {
bool SharedDatabase::DeleteInventorySlot(uint32 char_id, int16 slot_id)
{
const int deleted = InventoryRepository::DeleteWhere(
*this,
fmt::format(
"`character_id` = {} AND `slot_id` = {}",
char_id,
slot_id
)
);
// Delete item
const uint32 account_id = GetAccountIDByChar(char_id);
std::string query = StringFormat("DELETE FROM sharedbank WHERE acctid=%i AND slotid=%i", account_id, slot_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
if (!deleted) {
return false;
}
// Delete bag slots, if need be
if (!EQ::InventoryProfile::SupportsContainers(slot_id))
return true;
if (!EQ::InventoryProfile::SupportsContainers(slot_id)) {
return true;
}
const int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(slot_id, EQ::invbag::SLOT_BEGIN);
query = StringFormat("DELETE FROM sharedbank WHERE acctid = %i "
"AND slotid >= %i AND slotid < %i",
account_id, base_slot_id, (base_slot_id+10));
results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
const int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(slot_id, EQ::invbag::SLOT_BEGIN);
// @merth: need to delete augments here
return true;
return InventoryRepository::DeleteWhere(
*this,
fmt::format(
"`character_id` = {} AND `slot_id` BETWEEN {} AND {}",
char_id,
base_slot_id,
base_slot_id + (EQ::invbag::SLOT_COUNT - 1)
)
);
}
bool SharedDatabase::DeleteSharedBankSlot(uint32 char_id, int16 slot_id)
{
const uint32 account_id = GetAccountIDByChar(char_id);
const int deleted = SharedbankRepository::DeleteWhere(
*this,
fmt::format(
"`account_id` = {} AND `slot_id` = {}",
account_id,
slot_id
)
);
if (!deleted) {
return false;
}
if (!EQ::InventoryProfile::SupportsContainers(slot_id)) {
return true;
}
const int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(slot_id, EQ::invbag::SLOT_BEGIN);
return SharedbankRepository::DeleteWhere(
*this,
fmt::format(
"`account_id` = {} AND `slotid` BETWEEN {} AND {}",
account_id,
base_slot_id,
base_slot_id + (EQ::invbag::SLOT_COUNT - 1)
)
);
}
@@ -548,96 +577,81 @@ bool SharedDatabase::SetStartingItems(
// Retrieve shared bank inventory based on either account or character
bool SharedDatabase::GetSharedBank(uint32 id, EQ::InventoryProfile *inv, bool is_charid)
{
std::string query;
const uint32 account_id = is_charid ? GetAccountIDByChar(id) : id;
if (is_charid) {
query = fmt::format(
"SELECT sb.slotid, sb.itemid, sb.charges, "
"sb.augslot1, sb.augslot2, sb.augslot3, "
"sb.augslot4, sb.augslot5, sb.augslot6, sb.custom_data "
"FROM sharedbank sb INNER JOIN character_data ch "
"ON ch.account_id = sb.acctid WHERE ch.id = {} ORDER BY sb.slotid",
id
);
} else {
query = fmt::format(
"SELECT slotid, itemid, charges, "
"augslot1, augslot2, augslot3, "
"augslot4, augslot5, augslot6, custom_data "
"FROM sharedbank WHERE acctid = {} ORDER BY slotid",
id
);
}
auto results = QueryDatabase(query);
// If we have no results we still need to return true
if (!results.Success()) {
if (!account_id) {
return false;
}
for (auto row : results) {
int16 slot_id = static_cast<int16>(Strings::ToInt(row[0]));
uint32 item_id = Strings::ToUnsignedInt(row[1]);
const int16 charges = static_cast<int16>(Strings::ToInt(row[2]));
const auto& l = SharedbankRepository::GetWhere(
*this,
fmt::format(
"`account_id` = {}",
account_id
)
);
uint32 aug[EQ::invaug::SOCKET_COUNT];
aug[0] = Strings::ToUnsignedInt(row[3]);
aug[1] = Strings::ToUnsignedInt(row[4]);
aug[2] = Strings::ToUnsignedInt(row[5]);
aug[3] = Strings::ToUnsignedInt(row[6]);
aug[4] = Strings::ToUnsignedInt(row[7]);
aug[5] = Strings::ToUnsignedInt(row[8]);
if (l.empty()) {
return true;
}
const EQ::ItemData *item = GetItem(item_id);
for (const auto& e : l) {
uint32 augment_ids[EQ::invaug::SOCKET_COUNT] = {
e.augment_one,
e.augment_two,
e.augment_three,
e.augment_four,
e.augment_five,
e.augment_six
};
const EQ::ItemData* item = GetItem(e.item_id);
if (!item) {
LogError(
"Warning: [{}] [{}] has an invalid item_id [{}] in inventory slot [{}]",
is_charid ? "charid" : "acctid",
"Warning: {} [{}] has an invalid item_id [{}] in slot_id [{}]",
is_charid ? "character_id" : "account_id",
id,
item_id,
slot_id
e.item_id,
e.slot_id
);
continue;
}
auto inst = CreateBaseItem(item, charges);
EQ::ItemInstance* inst = CreateBaseItem(item, e.charges);
if (!inst) {
continue;
}
if (inst && item->IsClassCommon()) {
if (item->IsClassCommon()) {
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
if (aug[i]) {
inst->PutAugment(this, i, aug[i]);
if (augment_ids[i]) {
inst->PutAugment(this, i, augment_ids[i]);
}
}
}
if (inst && row[9]) {
std::string data_str(row[9]);
inst->SetCustomDataString(data_str);
if (!e.custom_data.empty()) {
inst->SetCustomDataString(e.custom_data);
}
// theoretically inst can be nullptr ... this would be very bad ...
const int16 put_slot_id = inv->PutItem(slot_id, *inst);
const int16 put_slot_id = inv->PutItem(e.slot_id, *inst);
safe_delete(inst);
// Save ptr to item in inventory
if (put_slot_id != INVALID_INDEX) {
continue;
}
LogError(
"Warning: Invalid slot_id for item in shared bank inventory: [{}]=[{}], item_id=[{}], slot_id=[{}]",
is_charid ? "charid" : "acctid",
"Warning: Invalid slot_id for item in shared bank inventory for {} [{}] item_id [{}] slot_id [{}]",
is_charid ? "character_id" : "account_id",
id,
item_id,
slot_id
e.item_id,
e.slot_id
);
if (is_charid) {
SaveInventory(id, nullptr, slot_id);
SaveInventory(id, nullptr, e.slot_id);
}
}
@@ -645,54 +659,78 @@ bool SharedDatabase::GetSharedBank(uint32 id, EQ::InventoryProfile *inv, bool is
}
// Overloaded: Retrieve character inventory based on character id (zone entry)
bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile* inv)
{
if (!char_id || !inv)
return false;
// Retrieve character inventory
const std::string query =
StringFormat("SELECT slotid, itemid, charges, color, augslot1, augslot2, augslot3, augslot4, augslot5, "
"augslot6, instnodrop, custom_data, ornamenticon, ornamentidfile, ornament_hero_model FROM "
"inventory WHERE charid = %i ORDER BY slotid",
char_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogError("If you got an error related to the 'instnodrop' field, run the "
"following SQL Queries:\nalter table inventory add instnodrop "
"tinyint(1) unsigned default 0 not null;\n");
if (!char_id || !inv) {
return false;
}
const auto timestamps = GetItemRecastTimestamps(char_id);
// Retrieve character inventory
auto results = InventoryRepository::GetWhere(
*this,
fmt::format(
"`character_id` = '{}' ORDER BY `slot_id`",
char_id
)
);
auto cv_conflict = false;
const auto pmask = inv->GetLookup()->PossessionsBitmask;
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
if (results.empty()) {
LogError("Error loading inventory for char_id {} from the database.", char_id);
return false;
}
for (auto& row = results.begin(); row != results.end(); ++row) {
int16 slot_id = Strings::ToInt(row[0]);
for (auto const& row: results) {
if (row.guid != 0) {
EQ::ItemInstance::AddGUIDToMap(row.guid);
}
}
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) { // Titanium thru UF check
const auto timestamps = GetItemRecastTimestamps(char_id);
auto cv_conflict = false;
const auto pmask = inv->GetLookup()->PossessionsBitmask;
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
std::vector<InventoryRepository::Inventory> queue{ };
for (auto& row: results) {
const int16 slot_id = row.slot_id;
const uint32 item_id = row.item_id;
const uint16 charges = row.charges;
const uint32 color = row.color;
const bool instnodrop = row.instnodrop;
const uint32 ornament_icon = row.ornament_icon;
const uint32 ornament_idfile = row.ornament_idfile;
const uint32 ornament_hero_model = row.ornament_hero_model;
uint32 augment_ids[EQ::invaug::SOCKET_COUNT] = {
row.augment_one,
row.augment_two,
row.augment_three,
row.augment_four,
row.augment_five,
row.augment_six
};
if (EQ::ValueWithin(slot_id, EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END)) {
// Titanium thru UF check
if (((static_cast<uint64>(1) << slot_id) & pmask) == 0) {
cv_conflict = true;
continue;
}
}
else if (slot_id <= EQ::invbag::GENERAL_BAGS_END && slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN) { // Titanium thru UF check
} else if (EQ::ValueWithin(slot_id, EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END)) {
// Titanium thru UF check
const auto parent_slot = EQ::invslot::GENERAL_BEGIN + ((slot_id - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
if (((static_cast<uint64>(1) << parent_slot) & pmask) == 0) {
cv_conflict = true;
continue;
}
}
else if (slot_id <= EQ::invslot::BANK_END && slot_id >= EQ::invslot::BANK_BEGIN) { // Titanium check
} else if (EQ::ValueWithin(slot_id, EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END)) {
// Titanium check
if ((slot_id - EQ::invslot::BANK_BEGIN) >= bank_size) {
cv_conflict = true;
continue;
}
}
else if (slot_id <= EQ::invbag::BANK_BAGS_END && slot_id >= EQ::invbag::BANK_BAGS_BEGIN) { // Titanium check
} else if (EQ::ValueWithin(slot_id, EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END)) {
// Titanium check
const auto parent_index = ((slot_id - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
if (parent_index >= bank_size) {
cv_conflict = true;
@@ -700,102 +738,98 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
}
}
uint32 item_id = Strings::ToUnsignedInt(row[1]);
const uint16 charges = Strings::ToUnsignedInt(row[2]);
const uint32 color = Strings::ToUnsignedInt(row[3]);
uint32 aug[EQ::invaug::SOCKET_COUNT];
aug[0] = Strings::ToUnsignedInt(row[4]);
aug[1] = Strings::ToUnsignedInt(row[5]);
aug[2] = Strings::ToUnsignedInt(row[6]);
aug[3] = Strings::ToUnsignedInt(row[7]);
aug[4] = Strings::ToUnsignedInt(row[8]);
aug[5] = Strings::ToUnsignedInt(row[9]);
const bool instnodrop = (row[10] && static_cast<uint16>(Strings::ToUnsignedInt(row[10])));
const uint32 ornament_icon = Strings::ToUnsignedInt(row[12]);
const uint32 ornament_idfile = Strings::ToUnsignedInt(row[13]);
uint32 ornament_hero_model = Strings::ToUnsignedInt(row[14]);
const EQ::ItemData *item = GetItem(item_id);
auto* item = GetItem(item_id);
if (!item) {
LogError("Warning: charid [{}] has an invalid item_id [{}] in inventory slot [{}]", char_id, item_id,
slot_id);
LogError(
"Warning: charid [{}] has an invalid item_id [{}] in inventory slot [{}]",
char_id,
item_id,
slot_id
);
continue;
}
EQ::ItemInstance *inst = CreateBaseItem(item, charges);
if (inst == nullptr)
auto* inst = CreateBaseItem(item, charges);
if (!inst) {
continue;
}
if (row[11]) {
std::string data_str(row[11]);
inst->SetCustomDataString(data_str);
if (!row.custom_data.empty()) {
inst->SetCustomDataString(row.custom_data);
}
inst->SetOrnamentIcon(ornament_icon);
inst->SetOrnamentationIDFile(ornament_idfile);
inst->SetOrnamentHeroModel(item->HerosForgeModel);
if (instnodrop || (inst->GetItem()->Attuneable && slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <= EQ::invslot::EQUIPMENT_END))
if (
instnodrop ||
(
inst->GetItem()->Attuneable &&
EQ::ValueWithin(slot_id, EQ::invslot::EQUIPMENT_BEGIN, EQ::invslot::EQUIPMENT_END)
)
) {
inst->SetAttuned(true);
}
if (color > 0)
if (color > 0) {
inst->SetColor(color);
}
if (charges == 0x7FFF)
if (charges == std::numeric_limits<int16>::max()) {
inst->SetCharges(-1);
else if (charges == 0 && inst->IsStackable()) // Stackable items need a minimum charge of 1 remain moveable.
} else if (charges == 0 && inst->IsStackable()) {
// Stackable items need a minimum charge of 1 remain moveable.
inst->SetCharges(1);
else
} else {
inst->SetCharges(charges);
}
if (item->RecastDelay) {
if (item->RecastType != RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->RecastType)) {
inst->SetRecastTimestamp(timestamps.at(item->RecastType));
} else if (item->RecastType == RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->ID)) {
inst->SetRecastTimestamp(timestamps.at(item->ID));
}
else {
} else {
inst->SetRecastTimestamp(0);
}
}
if (item->IsClassCommon()) {
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
if (aug[i])
inst->PutAugment(this, i, aug[i]);
if (augment_ids[i]) {
inst->PutAugment(this, i, augment_ids[i]);
}
}
}
int16 put_slot_id;
if (slot_id >= 8000 && slot_id <= 8999) {
put_slot_id = inv->PushCursor(*inst);
} else if (slot_id >= 3111 && slot_id <= 3179) {
// Admins: please report any occurrences of this error
LogError("Warning: Defunct location for item in inventory: charid={}, item_id={}, slot_id={} .. pushing to cursor...",
char_id, item_id, slot_id);
if (EQ::ValueWithin(slot_id, EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END)) {
put_slot_id = inv->PushCursor(*inst);
} else {
put_slot_id = inv->PutItem(slot_id, *inst);
}
row.guid = inst->GetSerialNumber();
queue.push_back(row);
safe_delete(inst);
// Save ptr to item in inventory
if (put_slot_id == INVALID_INDEX) {
LogError("Warning: Invalid slot_id for item in inventory: charid=[{}], item_id=[{}], slot_id=[{}]",
char_id, item_id, slot_id);
LogError(
"Warning: Invalid slot_id for item in inventory for character_id [{}] item_id [{}] slot_id [{}]",
char_id,
item_id,
slot_id
);
}
}
if (cv_conflict) {
const std::string& char_name = GetCharName(char_id);
LogError("ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
LogError(
"ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
char_name,
char_id,
EQ::versions::MobVersionName(inv->InventoryVersion()),
@@ -803,98 +837,16 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
);
}
if (!queue.empty()) {
InventoryRepository::ReplaceMany(*this, queue);
}
EQ::ItemInstance::ClearGUIDMap();
// Retrieve shared inventory
return GetSharedBank(char_id, inv, true);
}
// Overloaded: Retrieve character inventory based on account_id and character name (char select)
bool SharedDatabase::GetInventory(uint32 account_id, char *name, EQ::InventoryProfile *inv) // deprecated
{
// Retrieve character inventory
const std::string query =
StringFormat("SELECT slotid, itemid, charges, color, augslot1, "
"augslot2, augslot3, augslot4, augslot5, augslot6, instnodrop, custom_data, ornamenticon, "
"ornamentidfile, ornament_hero_model "
"FROM inventory INNER JOIN character_data ch "
"ON ch.id = charid WHERE ch.name = '%s' AND ch.account_id = %i ORDER BY slotid",
name, account_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
LogError("If you got an error related to the 'instnodrop' field, run the "
"following SQL Queries:\nalter table inventory add instnodrop "
"tinyint(1) unsigned default 0 not null;\n");
return false;
}
for (auto& row = results.begin(); row != results.end(); ++row) {
int16 slot_id = Strings::ToInt(row[0]);
uint32 item_id = Strings::ToUnsignedInt(row[1]);
const int8 charges = Strings::ToInt(row[2]);
const uint32 color = Strings::ToUnsignedInt(row[3]);
uint32 aug[EQ::invaug::SOCKET_COUNT];
aug[0] = Strings::ToUnsignedInt(row[4]);
aug[1] = Strings::ToUnsignedInt(row[5]);
aug[2] = Strings::ToUnsignedInt(row[6]);
aug[3] = Strings::ToUnsignedInt(row[7]);
aug[4] = Strings::ToUnsignedInt(row[8]);
aug[5] = Strings::ToUnsignedInt(row[9]);
const bool instnodrop = (row[10] && static_cast<uint16>(Strings::ToUnsignedInt(row[10])));
const uint32 ornament_icon = Strings::ToUnsignedInt(row[12]);
const uint32 ornament_idfile = Strings::ToUnsignedInt(row[13]);
uint32 ornament_hero_model = Strings::ToUnsignedInt(row[14]);
const EQ::ItemData *item = GetItem(item_id);
if (!item)
continue;
EQ::ItemInstance *inst = CreateBaseItem(item, charges);
if (inst == nullptr)
continue;
inst->SetAttuned(instnodrop);
if (row[11]) {
std::string data_str(row[11]);
inst->SetCustomDataString(data_str);
}
inst->SetOrnamentIcon(ornament_icon);
inst->SetOrnamentationIDFile(ornament_idfile);
inst->SetOrnamentHeroModel(item->HerosForgeModel);
if (color > 0)
inst->SetColor(color);
inst->SetCharges(charges);
if (item->IsClassCommon()) {
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
if (aug[i])
inst->PutAugment(this, i, aug[i]);
}
}
int16 put_slot_id;
if (slot_id >= 8000 && slot_id <= 8999)
put_slot_id = inv->PushCursor(*inst);
else
put_slot_id = inv->PutItem(slot_id, *inst);
safe_delete(inst);
// Save ptr to item in inventory
if (put_slot_id == INVALID_INDEX)
LogError("Warning: Invalid slot_id for item in inventory: name={}, acctid={}, item_id={}, slot_id={}",
name, account_id, item_id, slot_id);
}
// Retrieve shared inventory
return GetSharedBank(account_id, inv, false);
}
std::map<uint32, uint32> SharedDatabase::GetItemRecastTimestamps(uint32 char_id)
{
std::map<uint32, uint32> timers;
@@ -1246,7 +1198,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
// Bag
item.BagSize = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::bagsize]));
item.BagSlots = static_cast<uint8>(EQ::Clamp(Strings::ToInt(row[ItemField::bagslots]), 0, 10)); // Will need to be changed from std::min to just use database value when bag slots are increased
item.BagSlots = static_cast<uint8>(EQ::Clamp(Strings::ToInt(row[ItemField::bagslots]), 0, static_cast<int>(EQ::invbag::SLOT_COUNT)));
item.BagType = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::bagtype]));
item.BagWR = static_cast<uint8>(EQ::Clamp(Strings::ToInt(row[ItemField::bagwr]), 0, 100));
@@ -1359,30 +1311,28 @@ const EQ::ItemData* SharedDatabase::IterateItems(uint32* id) const
return nullptr;
}
std::string SharedDatabase::GetBook(const char *txtfile, int16 *language)
Book_Struct SharedDatabase::GetBook(const std::string& text_file)
{
char txtfile2[20];
std::string txtout;
strcpy(txtfile2, txtfile);
const auto& l = BooksRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}'",
Strings::Escape(text_file)
)
);
const std::string query = StringFormat("SELECT txtfile, language FROM books WHERE name = '%s'", txtfile2);
auto results = QueryDatabase(query);
if (!results.Success()) {
txtout.assign(" ",1);
return txtout;
Book_Struct b;
if (l.empty()) {
return b;
}
if (results.RowCount() == 0) {
LogError("No book to send, ({})", txtfile);
txtout.assign(" ",1);
return txtout;
}
const auto& e = l.front();
auto& row = results.begin();
txtout.assign(row[0],strlen(row[0]));
*language = static_cast<int16>(Strings::ToInt(row[1]));
b.language = e.language;
b.text = e.txtfile;
return txtout;
return b;
}
// Create appropriate EQ::ItemInstance class
+8 -4
View File
@@ -41,8 +41,7 @@ struct NPCFactionList;
struct FactionAssociations;
namespace EQ
{
namespace EQ {
struct ItemData;
class ItemInstance;
@@ -50,6 +49,12 @@ namespace EQ
class MemoryMappedFile;
}
struct Book_Struct
{
uint8 language;
std::string text;
};
/*
This object is inherited by world and zone's DB object,
and is mainly here to facilitate shared memory, and other
@@ -99,7 +104,6 @@ public:
int32 GetSharedPlatinum(uint32 account_id);
bool SetSharedPlatinum(uint32 account_id, int32 amount_to_add);
bool GetInventory(uint32 char_id, EQ::InventoryProfile *inv);
bool GetInventory(uint32 account_id, char *name, EQ::InventoryProfile *inv); // deprecated
std::map<uint32, uint32> GetItemRecastTimestamps(uint32 char_id);
uint32 GetItemRecastTimestamp(uint32 char_id, uint32 recast_type);
void ClearOldRecastTimestamps(uint32 char_id);
@@ -114,7 +118,7 @@ public:
int admin
);
std::string GetBook(const char *txtfile, int16 *language);
Book_Struct GetBook(const std::string& text_file);
/**
* items
+55 -20
View File
@@ -1,4 +1,14 @@
#include "skill_caps.h"
#include "timer.h"
// cache the skill cap max level in the database
std::map<uint8_t, int32_t> skill_max_level = {};
uint8 skill_cap_max_level = (
RuleI(Character, SkillCapMaxLevel) > 0 ?
RuleI(Character, SkillCapMaxLevel) :
RuleI(Character, MaxLevel)
);
SkillCaps *SkillCaps::SetContentDatabase(Database *db)
{
@@ -7,21 +17,38 @@ SkillCaps *SkillCaps::SetContentDatabase(Database *db)
return this;
}
int32_t SkillCaps::GetSkillCapMaxLevel(uint8 class_id, EQ::skills::SkillType skill_id)
{
// pull the max value defined in the database if it exists
auto it = skill_max_level.find((class_id * 1000000) + skill_id);
if (it != skill_max_level.end()) {
return it->second;
}
return skill_cap_max_level;
}
SkillCapsRepository::SkillCaps SkillCaps::GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
{
if (!IsPlayerClass(class_id)) {
if (!IsPlayerClass(class_id) || static_cast<uint32>(skill_id) > EQ::skills::HIGHEST_SKILL + 1) {
return SkillCapsRepository::NewEntity();
}
uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
auto pos = m_skill_caps.find(key);
const uint8 max_level = GetSkillCapMaxLevel(class_id, skill_id);
if (level > max_level) {
level = max_level;
}
const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
auto pos = m_skill_caps.find(key);
if (pos != m_skill_caps.end()) {
return pos->second;
}
return SkillCapsRepository::NewEntity();
}
uint8 SkillCaps::GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
uint8 SkillCaps::GetSkillTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
{
if (
!IsPlayerClass(class_id) ||
@@ -31,21 +58,12 @@ uint8 SkillCaps::GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, u
return 0;
}
const uint8 skill_cap_max_level = (
RuleI(Character, SkillCapMaxLevel) > 0 ?
RuleI(Character, SkillCapMaxLevel) :
RuleI(Character, MaxLevel)
);
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
for (const auto &e: m_skill_caps) {
for (uint8 current_level = 1; current_level <= max_level; current_level++) {
uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
auto pos = m_skill_caps.find(key);
if (pos != m_skill_caps.end()) {
return current_level;
}
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
for (uint8 current_level = 1; current_level <= max_level; current_level++) {
auto pos = m_skill_caps.find(key);
if (pos != m_skill_caps.end()) {
return current_level;
}
}
@@ -67,8 +85,25 @@ void SkillCaps::LoadSkillCaps()
continue;
}
uint64_t key = (e.class_id * 1000000) + (e.level * 1000) + e.skill_id;
const uint64_t key = (e.class_id * 1000000) + (e.level * 1000) + e.skill_id;
m_skill_caps[key] = e;
const int max_level_key = (e.class_id * 1000000) + e.skill_id;
auto it = skill_max_level.find(max_level_key);
if (it != skill_max_level.end()) {
// Key found, update the value if the new level is higher
if (e.level > it->second) {
it->second = e.level;
}
// we never want to exceed the defined rule skill cap max level
if (it->second > skill_cap_max_level) {
it->second = skill_cap_max_level;
}
}
else {
// Key not found, insert the new key-value pair
skill_max_level[max_level_key] = e.level;
}
}
LogInfo(
+2 -1
View File
@@ -10,9 +10,10 @@ class SkillCaps {
public:
inline void ClearSkillCaps() { m_skill_caps.clear(); }
SkillCapsRepository::SkillCaps GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
uint8 GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
uint8 GetSkillTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
void LoadSkillCaps();
void ReloadSkillCaps();
static int32_t GetSkillCapMaxLevel(uint8 class_id, EQ::skills::SkillType skill_id);
SkillCaps *SetContentDatabase(Database *db);
private:
+24 -19
View File
@@ -127,24 +127,30 @@ bool EQ::skills::IsCastingSkill(SkillType skill)
int32 EQ::skills::GetBaseDamage(SkillType skill)
{
switch (skill) {
case SkillBash:
return 2;
case SkillDragonPunch:
return 12;
case SkillEagleStrike:
return 7;
case SkillFlyingKick:
return 25;
case SkillKick:
return 3;
case SkillRoundKick:
return 5;
case SkillTigerClaw:
return 4;
case SkillFrenzy:
return 10;
default:
return 0;
case SkillArchery:
return RuleI(Combat, ArcheryBaseDamage);
case SkillBackstab:
return RuleI(Combat, BackstabBaseDamage);
case SkillBash:
return RuleI(Combat, BashBaseDamage);
case SkillDragonPunch:
return RuleI(Combat, DragonPunchBaseDamage);
case SkillEagleStrike:
return RuleI(Combat, EagleStrikeBaseDamage);
case SkillFlyingKick:
return RuleI(Combat, FlyingKickBaseDamage);
case SkillFrenzy:
return RuleI(Combat, FrenzyBaseDamage);
case SkillKick:
return RuleI(Combat, KickBaseDamage);
case SkillRoundKick:
return RuleI(Combat, RoundKickBaseDamage);
case SkillThrowing:
return RuleI(Combat, ThrowingBaseDamage);
case SkillTigerClaw:
return RuleI(Combat, TigerClawBaseDamage);
default:
return 0;
}
}
@@ -243,7 +249,6 @@ const std::vector<EQ::skills::SkillType>& EQ::skills::GetExtraDamageSkills()
EQ::skills::SkillFlyingKick,
EQ::skills::SkillKick,
EQ::skills::SkillRoundKick,
EQ::skills::SkillRoundKick,
EQ::skills::SkillTigerClaw,
EQ::skills::SkillFrenzy
};
+115
View File
@@ -431,6 +431,16 @@ bool IsCharmSpell(uint16 spell_id)
return IsEffectInSpell(spell_id, SE_Charm);
}
bool IsResurrectionSicknessSpell(uint16 spell_id) {
return (
spell_id == SPELL_RESURRECTION_SICKNESS ||
spell_id == SPELL_RESURRECTION_SICKNESS2 ||
spell_id == SPELL_RESURRECTION_SICKNESS3 ||
spell_id == SPELL_RESURRECTION_SICKNESS4 ||
spell_id == SPELL_REVIVAL_SICKNESS
);
}
bool IsBlindSpell(uint16 spell_id)
{
return IsEffectInSpell(spell_id, SE_Blind);
@@ -2315,3 +2325,108 @@ bool IsCastNotStandingSpell(uint16 spell_id) {
*/
return spells[spell_id].cast_not_standing;
}
bool IsAegolismSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return 0;
}
bool has_max_hp = false;
bool has_current_hp = false;
bool has_ac = false;
for (int i = 0; i < EFFECT_COUNT; ++i) {
if (i == 0 && spells[spell_id].effect_id[i] != SE_StackingCommand_Block) {
return 0;
}
if (i == 1 && spells[spell_id].effect_id[i] == SE_TotalHP) {
has_max_hp = true;
}
if (i == 2 && spells[spell_id].effect_id[i] == SE_CurrentHPOnce) {
has_current_hp = true;
}
if (i == 3 && spells[spell_id].effect_id[i] == SE_ArmorClass) {
has_ac = true;
}
if (i == 4 && spells[spell_id].effect_id[i] != SE_StackingCommand_Overwrite) {
return 0;
}
}
if (has_max_hp && has_current_hp && has_ac) {
return 1;
}
return 0;
}
bool AegolismStackingIsSymbolSpell(uint16 spell_id) {
/*
This is hardcoded to be specific to the type of HP buffs that are removed if a mob has an Aegolism buff.
*/
if (!IsValidSpell(spell_id)) {
return 0;
}
bool has_max_hp = false;
bool has_current_hp = false;
for (int i = 0; i < EFFECT_COUNT; ++i) {
if ((i < 2 && spells[spell_id].effect_id[i] != SE_CHA) ||
i > 3 && spells[spell_id].effect_id[i] != SE_Blank) {
return 0;;
}
if (i == 2 && spells[spell_id].effect_id[i] == SE_TotalHP) {
has_max_hp = true;
}
if (i == 3 && spells[spell_id].effect_id[i] == SE_CurrentHPOnce) {
has_current_hp = true;
}
}
if (has_max_hp && has_current_hp) {
return 1;
}
return 0;
}
bool AegolismStackingIsArmorClassSpell(uint16 spell_id) {
/*
This is hardcoded to be specific to the type of AC buffs that are removed if a mob has an Aegolism buff.
*/
if (!IsValidSpell(spell_id)) {
return 0;
}
bool has_ac = false;
for (int i = 0; i < EFFECT_COUNT; ++i) {
if ((i < 3 && spells[spell_id].effect_id[i] != SE_CHA) ||
i > 3 && spells[spell_id].effect_id[i] != SE_Blank) {
return 0;
}
if (i == 3 && spells[spell_id].effect_id[i] == SE_ArmorClass) {
has_ac = true;
}
}
if (has_ac) {
return 1;
}
return 0;
}
+5 -1
View File
@@ -904,7 +904,7 @@ typedef enum {
#define SE_AlterNPCLevel 107 // implemented - not used on live
#define SE_Familiar 108 // implemented
#define SE_SummonItemIntoBag 109 // implemented - summons stuff into container
//#define SE_IncreaseArchery 110 // not used
#define SE_IncreaseArchery 110 // implemented
#define SE_ResistAll 111 // implemented - Note: Physical Resists are not modified by this effect.
#define SE_CastingLevel 112 // implemented
#define SE_SummonHorse 113 // implemented
@@ -1522,6 +1522,7 @@ bool IsSummonPetSpell(uint16 spell_id);
bool IsSummonPCSpell(uint16 spell_id);
bool IsPetSpell(uint16 spell_id);
bool IsCharmSpell(uint16 spell_id);
bool IsResurrectionSicknessSpell(uint16 spell_id);
bool IsBlindSpell(uint16 spell_id);
bool IsHealthSpell(uint16 spell_id);
bool IsCastTimeReductionSpell(uint16 spell_id);
@@ -1624,5 +1625,8 @@ bool IsSpellUsableInThisZoneType(uint16 spell_id, uint8 zone_type);
const char *GetSpellName(uint16 spell_id);
int GetSpellStatValue(uint16 spell_id, const char* stat_identifier, uint8 slot = 0);
bool IsCastRestrictedSpell(uint16 spell_id);
bool IsAegolismSpell(uint16 spell_id);
bool AegolismStackingIsSymbolSpell(uint16 spell_id);
bool AegolismStackingIsArmorClassSpell(uint16 spell_id);
#endif
+9
View File
@@ -745,6 +745,15 @@ bool Strings::Contains(const std::string& subject, const std::string& search)
return subject.find(search) != std::string::npos;
}
bool Strings::ContainsLower(const std::string& subject, const std::string& search)
{
if (subject.length() < search.length()) {
return false;
}
return ToLower(subject).find(ToLower(search)) != std::string::npos;
}
uint32 Strings::TimeToSeconds(std::string time_string)
{
if (time_string.empty()) {
+1
View File
@@ -86,6 +86,7 @@ class Strings {
public:
static bool Contains(std::vector<std::string> container, const std::string& element);
static bool Contains(const std::string& subject, const std::string& search);
static bool ContainsLower(const std::string& subject, const std::string& search);
static int ToInt(const std::string &s, int fallback = 0);
static int64 ToBigInt(const std::string &s, int64 fallback = 0);
static uint32 ToUnsignedInt(const std::string &s, uint32 fallback = 0);
+3 -3
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.50.0-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.59.1-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,8 +42,8 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9275
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9044
#define CURRENT_BINARY_DATABASE_VERSION 9288
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
#endif
+2
View File
@@ -251,4 +251,6 @@ private:
scalar m_value;
};
using ref = reference;
} // namespace perlbind
+4 -3
View File
@@ -28,8 +28,8 @@ struct pusher
++m_pushed;
}
void push(const std::string& value) { mPUSHp(value.c_str(), value.size()); ++m_pushed; }
void push(scalar value) { mPUSHs(value.release()); ++m_pushed; };
void push(reference value) { mPUSHs(value.release()); ++m_pushed; };
void push(scalar value) { mPUSHs(value.release()); ++m_pushed; }
void push(reference value) { mPUSHs(value.release()); ++m_pushed; }
void push(array value)
{
@@ -38,7 +38,8 @@ struct pusher
for (int i = 0; i < count; ++i)
{
// mortalizes one reference to array element to avoid copying
PUSHs(sv_2mortal(SvREFCNT_inc(value[i].sv())));
SV** sv = av_fetch(static_cast<AV*>(value), i, true);
mPUSHs(SvREFCNT_inc(*sv));
}
m_pushed += count;
}
+1 -1
View File
@@ -242,7 +242,7 @@ struct read_as<hash>
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
{
int remaining = items - i;
return remaining > 0 && remaining % 2 == 0 && SvTYPE(ST(i)) == SVt_PV;
return remaining > 0 && remaining % 2 == 0 && SvTYPE(ST(i)) < SVt_PVAV;
}
static hash get(PerlInterpreter* my_perl, int i, int ax, int items)
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
constexpr int perlbind_version_major = 1;
constexpr int perlbind_version_minor = 0;
constexpr int perlbind_version_minor = 1;
constexpr int perlbind_version_patch = 0;
constexpr int perlbind_version()
+17
View File
@@ -224,6 +224,23 @@ void Client::Handle_Login(const char *data, unsigned int size)
if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id)) {
result = VerifyLoginHash(user, db_loginserver, cred, db_account_password_hash);
#ifdef LSPX
// if user updated their password on the login server, update it here by validating their credentials with the login server
if (!result && db_loginserver == "eqemu") {
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(user, cred);
if (account_id > 0) {
auto encryption_mode = server.options.GetEncryptionMode();
server.db->UpdateLoginserverAccountPasswordHash(
user,
db_loginserver,
eqcrypt_hash(user, cred, encryption_mode)
);
LogInfo("Updating eqemu account [{}] password hash", account_id);
result = true;
}
}
#endif
LogDebug("Success [{0}]", (result ? "true" : "false"));
}
else {
+7
View File
@@ -138,6 +138,13 @@ public:
*/
unsigned int GetPlaySequence() const { return m_play_sequence_id; }
/**
* Gets the client version
*
* @return
*/
LSClientVersion GetClientVersion() const { return m_client_version; }
/**
* Gets the connection for this client
*

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