Compare commits

...

439 Commits

Author SHA1 Message Date
KayenEQ 79f250da2d [API] Perl functions added to apply spell effects directly to NPCs without requiring buffs. (#1975)
* script functions working

* Update perl_npc.cpp

* [API] Perl functions added to apply spell effects directly to NPCs without requiring buffs.
2022-02-08 18:32:13 -05:00
KayenEQ 752e6c89f3 [Spells] Allow damage spells to heal if quest based spell mitigation is over 100 pct. (#1978)
* heal from nuke

* Update mob.cpp
2022-02-08 09:03:31 -05:00
KayenEQ e962ad3a35 procs silence (#1973) 2022-02-08 07:36:20 -05:00
KayenEQ 872d494bb6 [Bug Fix] Summon Companion causing pets to warps away. (#1972)
* Update spell_effects.cpp

* Update spell_effects.cpp
2022-02-08 07:36:04 -05:00
KayenEQ 8a48473dbc [Spells] Fix for AA and Discipline recast timers being set on spell casting failure. (#1971)
* recast timer updates

* reworked

* removed unneeded param

* fix expendible AA

* fixed

* Update spells.cpp

* [Spells] Fix for AA and Discipline recast timers being set on spell casting failure.

don't check recasts from triggered spells.
2022-02-08 07:35:47 -05:00
KayenEQ a208801d1f [Spells] Major update to Bard song pulsing, Bard item clicks while singing, and spell casting restriction logic. (#1954)
* test

* complete

* Update effects.cpp

* Update spells.cpp

* Update effects.cpp

* [Spells] Support for bards using Disciplines while casting or /melody.

Support for spell field 'cast not standing' not allow casting from divine aura

* [Spells] Support for bards using Disciplines while casting or /melody.

DA bypass logic for spells with field 'cast_not_standing'

* updates

* stun and mez bypass

* Update spdat.cpp

* Update spdat.cpp

* Update spells.cpp

* clean

* requirement messages

* update

* pct

* save work

* Reform code 1_22_22

* updated

* update id to pointer

* Update spells.cpp

* rework 2

* update 1_23_22

* Update spells.cpp

* updates

* msg string works

* fix disc timers not be set

* more optimization

* update 1_23_22 PM

moved stop casting out
charm and harmony moved in

* update 1_25_22

rework of functions

* updates 1_26_22

* remove old checks

* gm override added for some

* update bard AA casting checks

* updates

* addbuff exception for bard

* debugs

* charm working

* update

* moved skill check here

* cast from item while singing

* lets not attack mounts

* instant cast items click

* aug clicks working

* aug tests

Bug? Cast time not display on aug clicks for bards

* aug recast from items semi ok

* added item timer function

* unified setting item recast timer

* clean up time

* update

* bard AA cast updates

* debugs removed

* debugs removed

* clean up

* clean up

* better placement of bindsight and numhits fix

* move and rename function

* Update spells.cpp

* add logs

* delete old DoCastingChecks

* Removed old bard pulse functions

* remove AEBardPulse and GroupPulse

* removed Raid::GroupBardPulse

* Pulse Restriction: Divine Aura

* Pulse Restrictions : Fear behavior

* Update spells.cpp

* Update spells.cpp

* [Spells] Major update to Bard song pulsing, Bard item clicks while singing, and spell casting restriction logic.

bots...

* [Spells] Major update to Bard song pulsing, Bard item clicks while singing, and spell casting restriction logic.

added recommended isvalidspell check

* [Spells] Major update to Bard song pulsing, Bard item clicks while singing, and spell casting restriction logic.

merged

* [Spells] Major update to Bard song pulsing, Bard item clicks while singing, and spell casting restriction logic.

removed defines since we have them as constants
2022-02-07 07:48:52 -05:00
Kinglykrab a5d8a64792 [Quest API] Add inventory->CountItemEquippedByID(item_id) and inventory->HasItemEquippedByID(item_id) to Perl/Lua. (#1963)
- Add $inventory->CountItemEquippedByID(item_id) to Perl.
- Add $inventory->HasItemEquippedByID(item_id) to Perl.
- Add inventory:CountItemEquippedByID(item_id) to Lua.
- Add inventory:HasItemEquippedByID(item_id) to Lua
2022-02-06 13:21:48 -05:00
Chris Miles ee1f0ea91f [Maintenance Script] Pull from different maps mirror for now 2022-02-05 00:34:28 -06:00
KayenEQ 7c20a86f23 escape fix for different target types (#1962) 2022-02-04 21:14:53 -05:00
KayenEQ dbe6adbed0 [Spells] SPA 311 SE_LimitCombatSkills should prevent focusing of procs even if proc is a 'casted' spell. (#1961)
* proc limiter update

* Update spdat.h

* [Spells] SPA 311 SE_LimitCombatSkills should prevent focusing of procs even if proc is a 'casted' spell.
2022-02-04 21:14:40 -05:00
KayenEQ d300e78b39 [Spells] Illusions will now persist onto the corpse when mob is killed. (#1960)
* illusion applies to corpse

* Update spell_effects.cpp

* [Spells] Illusions will now persist onto the corpse when mob is killed.

addressed comments
2022-02-04 21:14:29 -05:00
Kinglykrab 0400504adc [Bug Fix] NPC::CountItem and Corpse::CountItem 0 Charge Item Fix. (#1959)
- Fixes an issue where 0 charged or out of charge items do not count towards the return value.
2022-02-04 06:07:46 -05:00
KayenEQ 5ce2889210 [Bug Fix] Illusions will now properly display armor to other clients when they zone in. (#1958)
* Fix for illusion wear change

On zone in, mobs with illusions were not displaying correct armor.

* [Bug Fix] Illusions will now properly display armor to other clients when they zone in

better looping
2022-02-03 22:04:15 -05:00
KayenEQ cc0371c16e [Spells] Swarm pet aggro logic fix (#1956)
* temp commit

* swarm pet logic fix

* [Spells] Swarm pet aggro logic fix
2022-02-03 22:00:52 -05:00
Kinglykrab 4e297f3d96 [Commands] #ginfo Cleanup. (#1955)
* [Commands] #ginfo Cleanup.
- Use popup over chat messages.

* Remove leader since GetLeaderName() is wrong.
2022-02-03 18:52:31 -05:00
Kinglykrab e9f48d5fba [Commands] Cleanup #npceditmass command. (#1957)
* [Commands] Cleanup #npceditmass command.
- Cleanup messages and logic.
- Fix crash with SQL format.

* Message change.
2022-02-03 15:25:37 -06:00
KayenEQ 00c41dda8c [Spells] Support for 'HateAdded' spell field to apply negative values to reduce hate. (#1953)
* HateAdded field can be negative

* [Spells] Support for 'HateAdded' spell field to apply negative values to reduce hate.
2022-02-02 21:43:17 -05:00
Kinglykrab 7b235a6ede [Bug Fix] Fix issue where you can set your title to titles you don't have. (#1917)
* [Bug Fix] Fix issue where you can set your title to titles you don't have.

* Fixes.

* Fix missing logic check for HasTitle

Co-authored-by: Natedog2012 <jwalters_06@yahoo.com>
2022-01-29 20:09:02 -06:00
mmcgarvey 58d5983ef1 [Skills] Configurable Exponential Decay Formula for Skill Up (#1887)
* [Skills] Exponential Decay Skill Up Formula

Added an exponential decay skill up formula option.
The current, linear, formula results in negative chances to skill up, which
have been mitigated via a multiplier and minimum of 1%

* [Skills]Configurable Exponential Decay Formala for Skill Up

What this fixes:
The existing formula for determining whether or not to skill up could result
in negative chances, and made an assumption around the number 252.
This would ultimately result in an override that would set the chance to 1.

My fix:
I created 2 new rules:
Character:SkillUpMaximumChancePercentage
Character:SkillUpMinimumChancePercentage

I changed the forumla to:
chance = ((max - min + skill_modification) * (.99^skill)) + min

This results in an exponential decay that starts at skill-modified maximum
and approaches minimum.

I decided that max-min+skill_modification should never be less than min
I also decided to continue to apply the Character:SkillUpModifier rule
post-calculation.  I do not really think this is necessary anymore, given
this new formula, but we can discuss removing it.
I chose 25 and 2 as default maximum and minimum based on feel.

Related method signature fix:

Client::mod_increase_skill_chance was changed to return a double and
accept a double as an input for chance.  This matches the actual data types
provided while calling the method and eliminates some type coersion and
resultant truncation.  Right now, this method doesn't do anything, but in the
future we could implement skill-specific training dummies that accelerate
skill ups.  I deduce that this is the purpose of this method call.

* [Skills]Configurable Exponential Decay Formula for Skill Up

What this fixes:
The existing formula for determining whether or not to skill up could result
in negative chances, and made an assumption around the number 252.
This would ultimately result in an override that would set the chance to 1.

My fix:
I created 2 new rules:
Character:SkillUpMaximumChancePercentage
Character:SkillUpMinimumChancePercentage

I changed the forumla to:
chance = ((max - min + skill_modification) * (.99^skill)) + min

This results in an exponential decay that starts at skill-modified maximum
and approaches minimum.

I decided that max-min+skill_modification should never be less than min
I also decided to continue to apply the Character:SkillUpModifier rule
post-calculation.  I do not really think this is necessary anymore, given
this new formula, but we can discuss removing it.
I chose 25 and 2 as default maximum and minimum based on feel.

Related method signature fix:

Client::mod_increase_skill_chance was changed to return a double and
accept a double as an input for chance.  This matches the actual data types
provided while calling the method and eliminates some type coersion and
resultant truncation.  Right now, this method doesn't do anything, but in the
future we could implement skill-specific training dummies that accelerate
skill ups.  I deduce that this is the purpose of this method call.

* fixup! [Skills]Configurable Exponential Decay Formula for Skill Up

* fixup! [Skills]Configurable Exponential Decay Formula for Skill Up
2022-01-29 20:01:58 -06:00
Paul Coene 7749c626f0 [Bug Fix] Fix issue with mobs summoning PCs into ceilings (#1921) 2022-01-29 19:55:40 -06:00
KayenEQ a6cd0bc33a [Bug Fix] Do not allow /open to be used on traps or auras, causes crash (#1951)
* Update client_packet.cpp

* [Bug Fix] Do not allow /open to be used on traps or auras, causes crash

* [Bug Fix] Do not allow /open to be used on traps or auras, causes crash
2022-01-29 19:54:26 -06:00
Chris Miles cba95851a2 [Combat] Legacy Combat Middleware Affected by PR #1858 (#1939) 2022-01-29 19:47:35 -06:00
KayenEQ 7f5706abcf bard throw while casting (#1937) 2022-01-28 22:07:23 -05:00
KayenEQ 44b8c9203a [Spells] Updates to spell field 'cast not stands' to ignore casting restrictions (#1938)
* test

* complete

* Update effects.cpp

* Update spells.cpp

* Update effects.cpp

* [Spells] Support for bards using Disciplines while casting or /melody.

Support for spell field 'cast not standing' not allow casting from divine aura

* [Spells] Support for bards using Disciplines while casting or /melody.

DA bypass logic for spells with field 'cast_not_standing'

* updates

* stun and mez bypass

* Update spdat.cpp

* Update spdat.cpp

* Update spells.cpp
2022-01-28 22:05:45 -05:00
KayenEQ afdbc0ce80 bug fix for push while rooted (#1949) 2022-01-28 22:05:29 -05:00
Paul Coene e850d80656 [Bug Fix (faction)] Do not award faction if NPC is charmed. (#1945)
* Do not award faction if npc is charmed.

* No faction on kill of charmed mob or questreward of same
2022-01-26 18:17:25 -05:00
Paul Coene b9722c6d28 [Bug Fix] Any use of TempName left old clean_name. (#1946)
* [Bug Fix] Any use of TempName left old clean_name.

* Dunsel change
2022-01-26 17:02:37 -05:00
Kinglykrab 5a7ee28740 [Bug Fix] Fix quest::updatespawntimer() Perl croak. (#1947) 2022-01-26 14:57:18 -06:00
mmcgarvey e4f2aec11e [XTarget] Revert All XTarget Corpse Changes (#1944) 2022-01-23 20:18:38 -06:00
KayenEQ e99c8dafc5 spellbar lock bug fix (#1943) 2022-01-23 20:27:45 -05:00
KayenEQ 936043a53c bind sight pets (#1942) 2022-01-23 20:27:32 -05:00
KayenEQ 3c09448e90 [Spells] NPC spell push should work on rooted mobs. (#1941)
* Update spells.cpp

* [Spells] NPC spell push should work on rooted mobs.

don't push perma or psuedorooted mobs
2022-01-20 12:13:14 -05:00
KayenEQ e09a8f8f8f [Spells] Support for bards using Disciplines while casting or /melody. (#1936)
* test

* complete

* Update effects.cpp

* Update spells.cpp

* Update effects.cpp

* [Spells] Support for bards using Disciplines while casting or /melody.

Support for spell field 'cast not standing' not allow casting from divine aura

* [Spells] Support for bards using Disciplines while casting or /melody.

DA bypass logic for spells with field 'cast_not_standing'
2022-01-19 22:44:17 -05:00
Randy Girard 804f0681a9 [Content Flags] Load the content flags before loading shared data. (#1935) 2022-01-19 12:58:15 -06:00
KayenEQ 71c53cb18b [Spells] Updates and fixes to Target Locked Pets (#1932)
* start of rework

* reworked v2 no timer

* fix

* more mechanics

* Update pets.cpp

* move to pet.cpp

* [Spells] Updates and fixes to Target Locked Pets

* [Spells] Updates and fixes to Target Locked Pets
2022-01-18 21:48:36 -05:00
Natedog2012 176bfc8524 [Bug Fix] Loading pets from database will make unique name to not overlap existing pets with same name in zone (#1933) 2022-01-18 16:43:58 -06:00
KayenEQ 28b1abe1a7 [Bug Fix] Fixes Enchanter AA Doppleganger crash issue (#1931)
* Fix crash bug

* [Bug Fix] Fixes Enchanter AA Doppleganger crash issue
2022-01-17 09:10:37 -05:00
Kinglykrab 3a94132749 [Quest API] Add multiple augment related methods to Perl/Lua. (#1930)
* [Quest API] Add multiple augment related methods to Perl/Lua.
- Add $inventory->CountAugmentEquippedByID(item_id) to Perl.
- Add $inventory->HasAugmentEquippedByID(item_id) to Perl.
- Add $item->ContainsAugmentByID(item_id) to Perl.
- Add $item->CountAugmentByID(item_id) to Perl.
- Add inventory:CountAugmentEquippedByID(item_id) to Perl.
- Add inventory:HasAugmentEquippedByID(item_id) to Perl.
- Add item:ContainsAugmentByID(item_id) to Perl.
- Add item:CountAugmentByID(item_id) to Perl.

* Update inventory_profile.cpp
2022-01-16 18:04:51 -05:00
KayenEQ 5ebbbf647b [Spells] SPA 299 Wake the Dead updates and crash fixes. SPA 306 Army of Dead implemented. (#1929)
* start

* wtd fix v1

* Update aa.cpp

* rework done, army of dead supported

* debugs

* Update aa.cpp

* Update spdat.h
2022-01-16 14:55:51 -05:00
KayenEQ 5f482a9b30 [Combat] Implemented rule for live like Riposte mechanics (#1927)
* Live like Riposte

* [Combat] Implemented rule for live like Riposte mechanics

bot fix
2022-01-15 19:37:47 -05:00
KayenEQ 91aa950304 fix for hasten AA (#1928) 2022-01-15 18:28:21 -05:00
JJ 613066976d [Bug Fix] Update to #1893 (#1926)
* Update to #1893

* Missed bonuses.cpp
2022-01-12 22:04:58 -05:00
mmcgarvey 1a556f4451 [XTarget] Performance Improvement After Corpse Change (#1918)
Removed a conditional that was rendered obsolete by moving the addition of a
mob to the auto haters list to fire after an IsValidXTarget check.  This
made an entity_list call unnecessary.  [zone/client.cpp]

Removed said unnecessary entity_list call.  [zone/client.cpp]

Removed a superfluous call to ProcessXTargetAutoHaters [zone/attack.cpp]
2022-01-12 16:04:18 -06:00
KayenEQ d10145fc6f [Bug Fix] Fix Tradeskill Salvage (#1925) 2022-01-11 18:24:47 -05:00
Kinglykrab f3002d9656 [Commands] Cleanup #who Command. (#1924)
* [Commands] Cleanup #who Command.
- Cleanup messages and logic.
- Add GetAccountStatusMap() and GetAccountStatusName() helpers for account status stuff.
- Use Chat::Who instead of Chat::Magenta so you can more easily see saylinks.
- Add a summon saylink to the list of saylinks so you can summon the player.

* New line.
2022-01-11 06:09:29 -05:00
KayenEQ 59c373bcff Update client_packet.cpp (#1923)
bug fix
2022-01-10 21:22:56 -05:00
Kinglykrab ae8273e0b1 [Commands] #guild create argument count bug fix. (#1920)
- Names with spaces were breaking command.
2022-01-10 17:33:28 -05:00
KayenEQ 10083387b6 [Spells] SPA 193 SE_SkillAttack will no longer trigger procs (#1919)
* fixed

* [Spells] SPA 193 SE_SkillAttack will no longer trigger procs
2022-01-09 08:32:09 -05:00
Chris Miles 7e065ad966 [Docs] Update Readme to reflect new docs 2022-01-08 13:57:31 -06:00
Kinglykrab ffa968f64f [Bug Fix] Disallow multiple augments in same item. (#1916)
- Disallows multiple augments via #augmentitem or otherwise.
- Added ItemInstance::ContainsAugmentByID(item_id) helper method for finding an augment in an item instance.
2022-01-04 17:18:17 -05:00
Natedog2012 6bf5608cf3 [Bug Fix] Add range check to OP_PickPocket (#1912)
* [Bug Fix] Add range check to OP_PickPocket

* Pickpocket distance is 15 constant according to Mackal

* Re-add wiggle room for distance check due to pathing
2022-01-03 22:26:37 -05:00
mmcgarvey 3853c4f150 [Bug Fix] XTarget Changes Causing Crashes (#1915)
* [Bugfix] XTarget Changes Causing Crashes

Added nullptr check when processing XTargetAutoHaters for pet owner.

* [Bugfix] XTarget Changes Causing Crashes

Added another needed sanity check after the nullptr check.

* [Bugfix] XTarget Changes Causing Crashes

Added another check against nullptr.

* [Bugfix] XTarget Changes Causing Crashes

Cleaned up nullptr checks per PR comments.
2022-01-03 22:22:21 -05:00
Chris Miles d6d4c458e7 [Database] Mark titles as a server table so it at least shows up in dumps (#1914) 2022-01-03 14:55:10 -06:00
Natedog2012 26b160c59b [Bug Fix] OP_Taunt checks if we have the skill (#1913) 2022-01-03 14:54:36 -06:00
Akkadius d107ff3069 [Hotfix] Add additional check to IsContentFlagEnabled given refactor from #1909 2022-01-03 01:06:17 -06:00
mmcgarvey 220d8497dd [XTarget] Disallow Corpses in XTarget Auto Slots (#1881)
* [XTarget] Disallow Corpses in XTarget Auto Slots

Why:
There exists an odd state where corpses will fill up your XTarget window.
This is reproducable using a combination of a pet to kill a mob
and timely feign death to wipe the owner's aggro.

What:
Added an IsCorpse check to IsXTarget.
Added a block to mark corpse XTargets as dirty to ProcessXTargetAutoHaters

* fixup! [XTarget] Disallow Corpses in XTarget Auto Slots

* fixup! [XTarget] Disallow Corpses in XTarget Auto Slots

* [XTarget] Disallow Corpses Code Cleanup

Added some safety, performance, and code readability changes per PR request.
2022-01-02 21:07:57 -06:00
Kinglykrab 645251992d [Bug Fix] Remove possible Duel exploit. (#1911)
* [Duels] Cleanup duel response/request logic.

* Fixes and function name cleanup.

* Patch file name changes.
2022-01-02 21:06:31 -06:00
Chris Miles 9815f50efa [Expansion] Content Filtering Adjustments (#1910)
* Change default expansion values for ALL to -1 from 0

* Adjust content_filter_criteria

* Refactor content filtering logic

* Allow flag strings to also just be empty instead of null

* Formatting

* Editor oops
2022-01-02 20:52:29 -06:00
Kinglykrab c0f57bed1f [Bug Fix] Cleanup Perl croaks for Spire parser. (#1908)
- Client::SendToInstance()
- Mob::DeleteBucket()
- Mob::GetBucket()
- Mob::GetBucketExpires()
- Mob::GetBucketRemaining()
- Mob::SetBucket()
2021-12-30 19:47:52 -06:00
j883376 d280d54446 [Spells] Allow GMs to remove buffs from any target (#1907) 2021-12-30 19:40:14 -06:00
Kinglykrab c99c5c1f1c [Bug Fix] Fix #guild rename, #killallnpcs, and #worldwide message errors. (#1904)
- #guild rename was checking argument count and not allowing you to rename guilds to names that had spaces.
- #killallnpcs was crashing zones when used sometimes due to getting a nullptr somewhere in the loop.
- #worldwide message was using just the first word of the message sent using the command, not all of them.
2021-12-29 12:06:51 -05:00
Natedog2012 e45f02af95 [Skills] RoF+ allows other classes to have feign death if set in skill_caps (#1902) 2021-12-29 11:17:31 -05:00
KayenEQ 323b35989c [Spells] Implemented SPA 281 SE_PetFeignMinion (#1900)
* start

* update

* debugs in

* test

* clean up

* debugs removed

* Update mob_ai.cpp

* Update spdat.h

* [Spells] Implemented SPA 281 SE_PetFeignMinion

debug remoevd

* [Spells] Implemented SPA 281 SE_PetFeignMinion

npc forget timer

* [Spells] Implemented SPA 281 SE_PetFeignMinion
2021-12-27 11:33:57 -05:00
Kinglykrab 7f23c93ce5 [Commands] Cleanup #setadventurepoints Command. (#1901)
- Cleanup message and logic.
2021-12-24 13:46:17 -05:00
Chris Miles 6a7782ab8d [Doors] Ignore Doors that Have Non-Zero Trigger or Door Param (#1899) 2021-12-23 14:47:24 -06:00
mmcgarvey 5457f30659 [Spells] Instant Heals honor IgnoreSpellDmgLvlRestriction (#1888)
Why:
Heal Over Time spells honor the Spells:IgnoreSpellDmgLvlRestriction rule,
shouldn't instant heals honor this rule too?

The fix:
Added a check for Spells:IgnoreSpellDmgLvlRestriction in the GetActSpellHealing
method.
2021-12-23 14:43:02 -06:00
KayenEQ 652ea89dea [Rule] Added rule to disable SPA 173 from making player immune to enrage. (#1897)
* immune enrage rule

* [Rule] Added rule to disable SPA 173 from making player immune to enrage.

spelling oops
2021-12-23 14:21:46 -06:00
mmcgarvey c79fbb99aa [Shared Tasks] Cross Zone Remove Fix (#1740)
* [Shared Tasks] Cross Zone Remove Fix

Why:
	The cross_zone_remove_task quest methods were not removing from
	shared_task_members database table and were not clearing shared task
	cache.  This resulted in a situation where a character could not
	request other shared tasks.

What:
	Shamelessly copied shared task logic from ClientTaskState::CancelTask
	into ClientTaskState::RemoveTaskByTaskID

* What:

Instead of copying code from CancelTask into RemoveTaskByTaskID, it is better
for code maintenance to simply call CancelTask from RemoveTaskByTaskID.
This is cleaner.

Note:  I chose to be explicit with the remove_from_db parameter, despite true
being the default.  I tend to do this to protect from the default value
changing in the future.

* [Shared Tasks] RemoveTaskByTaskID Cleanup

Removed unused variables.
Distinguished log messages for Shared Tasks from regular Tasks.
2021-12-23 14:20:15 -06:00
Paul Coene 4f0e9945c6 [Combat] Allow npcs/pets to kick vs opponents requiring magic weapons if wearing magic booties. (#1868)
* [Pets/NPC Kick] Allow pets/npcs kick vs mobs that req magic if using magic boots

* Backout accidental change to bash
2021-12-23 14:01:56 -06:00
mmcgarvey 4fbb98a5f7 [Skills] Make Tracking Skill Configurable (#1784)
Added 1 rule per class that defines tracking distance multiplier for that class
Kept the defaults of 12 for ranger, 10 for druid, and 7 for bard

Created 1 method for determining class tracking distance multiplier
Created 1 method for determining if a class can track, based on multiplier

Updated tracking logic to use these methods to determine whether a tracking
packet should and can be sent or not.
2021-12-23 13:57:53 -06:00
Paul Coene 8c78a19c95 [Bug Fix] Pick Lock was allowing skillups on doors above player skill (#1815)
* [Bux Fix] Pick Lock was allowing skillups on doors above player skill

* Fixed indentation

* Fix indentation #2 - I am not so bright :(

* Further refine messages for pick lock to match live

* sql to make pot pick locks book pickable by skill 1 and skillup
2021-12-23 13:56:06 -06:00
Kinglykrab 6a77764f8b [Commands] Cleanup #guild Command. (#1880)
- Cleanup messages and logic.
- Adds GetGuildNameByID, GetGuildRankName, GetGuildIDByCharacterID, and IsCharacterInGuild helper methods for guild stuff.
- Convert #guild info message to a popup display to tidy it up and make it more legible.
2021-12-23 13:04:26 -05:00
Natedog2012 d0ec0872b9 Client will give 1 second window to start casting at the end of DA effect but we interrupt it and need to allow spellbar active after (#1894) 2021-12-22 22:35:48 -06:00
Kinglykrab 724d47432b [Bug Fix] Fix Perl Croak for GetEnt() (#1898) 2021-12-22 15:27:25 -05:00
KayenEQ f26d56d6d5 validspell check (#1895) 2021-12-21 09:17:35 -05:00
KayenEQ 886b321e66 [Spells] Rework of SPA 288 SE_SkillAttackProc (#1893)
* start

* updated 288
2021-12-20 09:47:32 -05:00
Natedog2012 85971590c8 Re-enable spellbar and reset Discipline timer when stopping casts in EVENT_CAST_BEGIN (#1891) 2021-12-19 15:17:04 -06:00
KayenEQ 898b1ea4d1 Update attack.cpp (#1892) 2021-12-16 07:23:11 -05:00
KayenEQ d460fb3db8 [Spells] Update to SPA 440 SE_FinishingBlowMaxLevel limit value sets HP ratio for FB (#1890)
* fb max level update

* Update to SPA 440 SE_FinishingBlowMaxLevel limit value sets HP ratio for FB
2021-12-15 22:00:34 -05:00
Paul Coene fbc5d045de [Doors] Add new rule enabling classic "key on cursor" for pre keyring keys (#1869) 2021-12-15 13:26:31 -05:00
KayenEQ 3414d3a1ae fearstun update (#1889) 2021-12-15 13:17:15 -05:00
mmcgarvey feed584a41 [Database] Escape reserved mysql keyword rank w/ backticks (#1862)
Fixes #1567
2021-12-14 13:57:35 -05:00
KayenEQ 119b2d023f [Spells] Throwing procs fixed and other proc updates (#1871)
* first updating sbindex defines

* updates

* updates

* proctypes added for organization

* debug

* updates

* range procs cleaned up

* skill proc clean up

* fix

* remove debugs

* [Spells] Throwing procs fixed and other proc updates

* [Spells] Throwing procs fixed and other proc updates

bot fix

* [Spells] Throwing procs fixed and other proc updates

proctype updates
2021-12-14 12:34:51 -05:00
KayenEQ 73acc3310c [Spells] Updates and fixes to targeted focus effects (#1870) 2021-12-14 12:31:38 -05:00
KayenEQ 6da7116c66 [Bug Fix] Hero Forge armor graphics not displaying properly to other clients in zone. (#1883)
* fix part1

* updates

* Update inventory.cpp

* fixed

* Update inventory.cpp

* update

* [Bug Fix] Hero Forge armor graphics not displaying properly to other clients in zone.
2021-12-14 11:26:59 -05:00
KayenEQ 26b21673ad [Spells] Implemented SPA 245 SE_TrapCircumvention (#1885)
* implemented

* [Spells] Implemented SPA 245 SE_TrapCircumvention
2021-12-13 20:33:22 -05:00
KayenEQ ef1f6adf18 effective casting level update (#1886) 2021-12-13 20:32:25 -05:00
KayenEQ 1c2e1ea228 rampage updates (#1882) 2021-12-13 18:49:53 -05:00
KayenEQ 7cf66a2daa [Spells] Update SPA 238 SE_IllusionPersistence allow illusions to persist through deaths at higher AA ranks. (#1884)
* start

* working
2021-12-13 18:49:33 -05:00
KayenEQ 91c958ae63 Update spell_effects.cpp (#1877)
updated
2021-12-12 13:22:43 -05:00
KayenEQ 8de410ebb7 [Features] Appearance Effects will now be sent to clients upon zone in. GM commands. (#1874)
* start

* working

* Update perl_mob.cpp

* updates

* Update perl_mob.cpp

* illusion behavior

* rework start

* fix later

* Update mob.cpp

* rework

* updates

* Update mob.cpp

* update

* gm command updates

* updates

* Update CMakeLists.txt

* [Features] Appearance Effects will now be sent to clients upon zone in. GM commands.

remove debugs

* [Features] Appearance Effects will now be sent to clients upon zone in. GM commands.

perl fix

* [Features] Appearance Effects will now be sent to clients upon zone in. GM commands.

space fix

* [Features] Appearance Effects will now be sent to clients upon zone in. GM commands.

minor fix

* Update CMakeLists.txt

* [Features] Appearance Effects will now be sent to clients upon zone in. GM commands.

cleaned up some inconsistency

* [Features] Appearance Effects will now be sent to clients upon zone in. GM commands.
2021-12-10 13:46:23 -05:00
KayenEQ 550485ba33 [Spells] Fixed issue with permanent Illusions not being consistent when zoning. (#1876)
* start of work

* updates

* [Spells] Fixed issue with permanent Illusions not being consistent when zoning.
2021-12-10 12:21:19 -05:00
KayenEQ eb2b4fd9e0 [Spells] Update to SPA 58 SE_Levitate to support limit value (#1875)
* [Spells] Update to SPA 58 SE_Levitate to support limit value

* [Spells] Update to SPA 58 SE_Levitate to support limit value

apply same on zone in
2021-12-10 12:20:25 -05:00
Natedog2012 42f439c4b7 [Quest API] Add ResetCastbarCooldownBySlot / ResetCastbarCooldownBySpellID / ResetAllCastbarCooldowns (#1873)
* New function to reset spellbar in perl/lua ResetCastbarCooldownsBySlot -1 for all slots and anything else to do it by slot number

* Add ResetCastbarCooldownsBySlot / ResetCastbarCooldownsBySpellID / ResetAllCastbarCooldowns
2021-12-08 21:39:35 -06:00
Kinglykrab 294e51fca7 [Commands] Add #setaltcurrency Command. (#1850)
* [Commands] Add #setaltcurrency Command.
- Add #setaltcurrency [Currency ID] [Amount] command to allow you to set a specific alternate currency to a value.
- Add Zone::GetCurrencyID() and Zone::GetCurrencyItemID() helper methods.
- Cleanup loops through zone->AlternateCurrencies.
- Utilize helper methods where necessary.
- Convert old methods parameters and return values from int to uint32 where necessary.

* Typo.
2021-12-08 18:58:06 -05:00
Kinglykrab 94166e0f95 [Commands] Add #unmemspell and #unmemspells Commands. (#1867)
- Add #unmemspell [Spell ID] command to unmemorize a spell by ID from you or your target.
- Add #unmemspells command to unmemorize all spells from you or your target.
- Cleanup #memspell command and change arguments from #memspell [Slot] [Spell ID] to #memspell [Spell ID] [Spell Gem] for easier use.
- Add #memspell [Spell ID] functionality to memorize to first open spell gem if there are any using FindEmptyMemSlot helper method.
- Rename client->FindMemmedSpellByID(spell_id) to FindMemmedSpellBySpellID(spell_id).
- Add client->FindEmptyMemSlot() helper method.
- Add $client->FindEmptyMemSlot() to Perl.
- Add client:FindEmptyMemSlot() to Lua.
- Add $client->FindMemmedSpellBySpellID(spell_id) to Perl.
- Add client:FindMemmedSpellBySpellID(spell_id) to Lua.
2021-12-08 18:18:14 -05:00
Kinglykrab 1a1c3abc24 [Commands] Cleanup #setstartzone Command. (#1853)
- Add a message when setting start zone.
- Cleanup logic.
2021-12-08 18:18:06 -05:00
Natedog2012 0f4f5d7046 RemoveAllAppearanceEffects sends all relevant data so NPC appearance doesn't get altered. (#1864) 2021-12-07 15:15:28 -05:00
Kinglykrab 8ec4afe721 [Commands] Cleanup #wpinfo Command. (#1866)
- Cleanup message and logic.
- Only display grid/waypoints if NPC has a grid.
2021-12-04 21:53:29 -05:00
Kinglykrab aa4536e1ef [Quest API] Add GetLDoNThemeName() to Perl/Lua. (#1861)
* [Quest API] Add GetLDoNThemeName() to Perl/Lua.
- Add quest::getldonthemename(theme_id) to Perl.
- Add eq.get_ldon_theme_name(theme_id) to Lua.

* Update embparser_api.cpp
2021-12-03 19:53:00 -05:00
Kinglykrab 01a671918a [Quest API] Add GetBodyTypeName() to Perl/Lua. (#1863)
* [Quest API] Add GetBodyTypeName() to Perl/Lua.
- Add GetBodyTypeName() and GetBodyTypeMap() helper methods.
- Add quest::getbodytypename(bodytype_id) to Perl.
- Add eq.get_body_type_name(bodytype_id) to Lua.

* ShowStats() cleanup.
2021-12-03 19:52:42 -05:00
KayenEQ e09f28c62c [Spells] Update to SPA 296 and 483 item and AA support (#1857)
[Spells] Update to SPA 296 and 483 item and AA support
2021-12-03 15:39:21 -05:00
KayenEQ 82000949e3 [Spells] Update to SPA 297 and 484 to support focus from AA and items. (#1858)
[Spells] Update to SPA 297 and 484 to support focus from  AA and items.
2021-12-03 15:39:06 -05:00
Kinglykrab 4a154686e1 [Quest API] Add GetFactionName() to Perl/Lua. (#1859)
* [Quest API] Add GetFactionName() to Perl/Lua.
- Add quest::getfactionname(faction_id) to Perl.
- Add eq.get_faction_name(faction_id) to Lua.

* Update embparser_api.cpp

* Update embparser_api.cpp

* Update embparser_api.cpp
2021-12-02 10:09:15 -05:00
Kinglykrab 29dfe9d404 [Quest API] Add GetLanguageName() to Perl/Lua. (#1860)
- Add quest::getlanguagename(language_id) to Perl.
- Add eq.get_language_name(language_id) to Lua.
2021-12-01 20:31:20 -05:00
Kinglykrab 9a0c98397e [Bug Fix] Charm Break Invisibility Fix. (#1855)
- Invisibility vs. Undead and Invisibility vs. Animals were not breaking charm.
- Add Invisibility enumerator.
- Add special identifier for Invisibility vs. Undead and Invisibility vs. Animals.
2021-12-01 12:01:19 -05:00
KayenEQ bc0795bb48 [Spells] SPA 310 SE_ReduceReuseTimer will now work on spell recast time (#1856)
* [Spells] SPA 310 SE_ReduceReuseTimer	will now work on spell recast time

[Spells] SPA 310 SE_ReduceReuseTimer	will now work on spell recast time

* [Spells] SPA 310 SE_ReduceReuseTimer will now work on spell recast time

[Spells] SPA 310 SE_ReduceReuseTimer will now work on spell recast time
2021-12-01 00:22:10 -06:00
JJ d972183a79 [Cleanup] holdzones not used. (#1852)
Fixes #1116.
2021-11-28 22:35:52 -05:00
Natedog2012 f70b4a79b2 SetPetID after we assign the new NPC an ID (#1851) 2021-11-28 15:42:42 -06:00
Kinglykrab 7cac2e2bc3 [Commands] Add #viewcurrencies Command. (#1844)
* [Commands] Add #viewcurrencies Command.
- Add #viewcurrencies command to view your or your target's currencies (Money, Crystals, Alternate Currency, LDoN, and PVP).
- Add GetLDoNThemeName() helper method.

* Update viewcurrencies.cpp

* Cleanup name of map method.

* Cleanup.
2021-11-28 00:09:07 -05:00
Kinglykrab 2be1321aa9 [Commands] Add #removeitem Command. (#1847)
- Add #removeitem [Item ID] [Amount] command to remove items by amount versus nuking them all, removes all if amount is greater than what you or your target have.
2021-11-27 21:41:54 -05:00
Kinglykrab ba5bb09af7 [Commands] Cleanup #flymode Command. (#1845)
- Cleanup message and logic.
- Add GetFlyModeName() and GetFlyModeMap() helper methods.
- Cleanup #npcedit flymode to use helper methods.
2021-11-27 21:39:54 -05:00
Kinglykrab 5ab9b941e2 [Commands] Cleanup #titlesuffix Command. (#1834)
- Cleanup message and logic.
2021-11-27 21:29:56 -05:00
Kinglykrab d28f902ecc [Commands] Add #countitem Command. (#1842)
* [Commands] Add #countitem Command.
- Add #countitem [Item ID] command to count an item by ID on yourself or your player/NPC target.

* Cleanup.
2021-11-27 20:52:09 -05:00
Kinglykrab fd862d16bb [Commands] Cleanup #mysql Command. (#1837)
* [Commands] Cleanup #mysql Command.
- Cleanup messages and logic.

* Update mysql.cpp
2021-11-27 20:32:21 -05:00
Kinglykrab a6e5534b64 [Commands] Cleanup #texture Command. (#1835)
* [Commands] Cleanup #texture Command.
- Cleanup message and logic.

* Update command.cpp
2021-11-27 20:21:58 -05:00
Kinglykrab 225497337c [Commands] Add #setendurance Command. (#1841)
- Add #setendurance [Endurance] command to set an NPC or player's endurance to a specified amount, or to max if the amount is greater than their max.
- Cleanup #endurance command message and logic.
2021-11-27 19:08:07 -05:00
Kinglykrab a5348e207b [Commands] Add #sethp Command. (#1840)
- Add #sethp [Health] command to set an NPC or player's health to a specified amount, or to max if the amount is greater than their max.
- Cleanup #heal command message and logic.
2021-11-27 19:08:00 -05:00
Kinglykrab c4c5256438 [Commands] Add #setmana Command. (#1839)
* [Commands] Add #setmana Command.
- Add #setmana [Mana] command to set an NPC or player's mana to a specified amount, or to max if the amount is greater than their max.
- Cleanup #mana command message and logic.

* Update mana.cpp
2021-11-27 19:07:47 -05:00
Kinglykrab b3b9899a23 [Commands] Cleanup #movechar Command. (#1838)
- Cleanup messages and logic.
- Add support for Zone ID versus Zone Short Name.
- Add support for Character ID versus Character Name.
2021-11-27 19:06:40 -05:00
Kinglykrab 7d1d385418 [Commands] Cleanup #gmzone Command. (#1836)
- Cleanup messages and logic.
- Add support for Zone ID.
2021-11-27 18:19:03 -05:00
Kinglykrab 96cdf1b076 [Commands] Cleanup #title Command. (#1833)
- Cleanup message and logic.
2021-11-27 18:18:27 -05:00
KayenEQ 8688e9c9fa [Spells] Eye of Zomm will now despawn and stack properly (#1849)
* [Spells] Eye of Zomm stop chain spawning

No more chain spawning.

* [Spells] Eye of Zomm stop chain spawning

* [Spells] Eye of Zomm update
2021-11-27 12:11:23 -05:00
KayenEQ 6a28828e08 [API] mob->AppearanceEffects improved functionality. (#1821)
* appearanceffectscript

* update

* debugged

* [API] SendAppearanceEffect update

* [API] SendAppearanceEffect update

* [API] SendAppearanceEffect Upates

perl method RemoveAppearanceEffect to remove the apperanceeffect

* [API} AppearanceEffects update

* [API] SendAppearanceEffects update
2021-11-27 12:10:08 -05:00
Natedog2012 8566662d56 [Bug Fix] SendSpellBarEnable sends correct slotid to fix spellbar on RoF2 (#1848)
* SendSpellBarEnable sends correct slotid to fix spellbar on RoF2

* Send correct data when using StopCasting() to re-enable spellbar
2021-11-27 09:45:57 -05:00
Kinglykrab 298ae3e3ba [Bug Fix] Fix possible crash with #killallnpcs. (#1846) 2021-11-27 09:45:13 -05:00
Michael Cook (mackal) 4507b063f5 Switch server to use new style ManaChange_Struct (#1843)
This will allow us to fix some bugs the current handling has.

Note: the decoder isn't needed since the client always sends it up as a
0 length packet.
2021-11-26 21:33:49 -05:00
Natedog2012 774e0c7faa Do not set teleport doors to Open (#1786) 2021-11-26 15:26:07 -06:00
Kinglykrab 8b54bb34e4 [Commands] Cleanup #gmspeed Command. (#1831)
* [Commands] Cleanup #gmspeed Command.
- Cleanup message and logic.

* Update gmspeed.cpp

* Update gmspeed.cpp
2021-11-26 13:56:45 -05:00
Kinglykrab e87b8e2682 [Commands] Cleanup #gender Command. (#1832)
- Cleanup message and logic.
- Cleanup other spots using similar logic so they're all uniform.
2021-11-26 10:01:35 -05:00
Kinglykrab 2dc3ca52db [Commands] Cleanup #gm Command. (#1830)
- Cleanup message and logic.
- Cleanup SetGM() message.
2021-11-26 10:01:13 -05:00
Kinglykrab 514029a6bb [Commands] Cleanup #bind Command. (#1829)
- Add message and cleanup logic.
2021-11-26 10:01:04 -05:00
Kinglykrab b29f398239 [Commands] Cleanup #getplayerburiedcorpsecount Command. (#1818)
* [Commands] Cleanup #getplayerburiedcorpsecount Command.
- Cleanup message and logic.

* Update command.cpp
2021-11-25 21:01:23 -05:00
Kinglykrab e474b2a280 [Commands] Add #petitems Command. (#1823)
- Add #petitems command to show a person's pet items if they have access to the command.
- Adds a default false parameter to QueryLoot for NPCs that keeps messages and logic from being ran on pets for no reason.
- Cleaned up message a bit for loot and stuff.
- Remove check for loottable ID when using #npcstats for NPCs that get items from a script or otherwise.
2021-11-25 14:50:05 -05:00
Kinglykrab d38b8a4867 [Bug Fix] Fix possible crash in #givemoney. (#1828) 2021-11-25 13:55:06 -05:00
KayenEQ 1a5f48521d [Bug Fix] Bind Sight will now function properly (#1825)
* start

* bind sight fixed

* Update spdat.h

* Update spells.cpp

* Search or jump to… Pull requests Issues Marketplace Explore   @KayenEQ  EQEmu / Server Public 60 338 290 Code Issues 106 Pull requests 11 Actions Projects 1 Wiki Security Insights [Bug Fix] Bind Sight will now function properly #1825  Open KayenEQ wants to merge 4 commits into EQEmu:master from KayenEQ:bindsightfix2  Open [Bug Fix] Bind Sight will now function properly
2021-11-25 10:16:28 -05:00
KayenEQ ba427c64ba [Bug Fix] Numhits now display instantly on cast. (#1826) 2021-11-25 08:33:39 -05:00
KayenEQ 9d59b3def4 [Spells] Bard AA clicks should not receive song modifiers. (#1824) 2021-11-25 08:32:46 -05:00
KayenEQ a6f5bf72be Update spell_effects.cpp (#1822) 2021-11-24 19:43:43 -05:00
KayenEQ 6ff7f7aa53 [API] mob->SpellEffect small perl fix (#1820)
* Update perl_mob.cpp

* Update perl_mob.cpp
2021-11-24 12:48:23 -05:00
Kinglykrab 1a2897c423 [Commands] Cleanup #disablerecipe Command. (#1816)
- Cleanup message and logic.
2021-11-23 21:45:59 -05:00
Kinglykrab 8b5b19ae2c [Commands] Cleanup #enablerecipe Command. (#1817)
- Cleanup message and logic.
2021-11-23 21:45:52 -05:00
Kinglykrab 6fa41a3b73 [Commands] Remove duplicate commands. (#1819) 2021-11-23 19:53:39 -05:00
Kinglykrab 6496690123 [Commands] Cleanup #zsafecoords Command. (#1806)
* [Commands] Cleanup #zsafecoords Command.
- Cleanup message and logic.
- Add parameter to allow data to be saved to database.

* Typo.

* Update zsafecoords.cpp

* Update zsafecoords.cpp
2021-11-23 18:25:12 -05:00
Kinglykrab a11482ff23 [Cleanup] Utilize ConvertSecondsToTime() method. (#1805)
* [Cleanup] Utilize ConvertSecondsToTime() method.

* Lowercase.
2021-11-23 18:25:02 -05:00
Kinglykrab 4672e48fbd [Commands] Cleanup #zcolor Command. (#1813)
* [Commands] Cleanup #zcolor Command.
- Cleanup message and logic.
- Add parameter to allow data to be saved to database.

* Update zcolor.cpp
2021-11-23 16:45:31 -05:00
KayenEQ 8f3cce6585 send graphic to target correctly (#1785) 2021-11-23 12:55:58 -05:00
Kinglykrab 8d3a179ecc [Commands] Remove #zuwcoords Command. (#1810)
- Remove duplicate command of #zunderworld
2021-11-23 06:03:09 -05:00
Kinglykrab 2cbcefd9a0 [Commands] Cleanup #zheader Command. (#1814)
* [Commands] Cleanup #zheader Command.
- Cleanup message and logic.
- Add parameter to allow versions to be loaded.
- Cleanup parameter name in CFG methods from instance_id to instance_version.

* Update zonedb.cpp
2021-11-23 05:49:11 -05:00
Kinglykrab ef06a0d0b6 [Commands] Cleanup #zclip Command. (#1812)
* [Commands] Cleanup #zclip Command.
- Cleanup message and logic.
- Add parameter to allow data to be saved to database.

* Cleanup.
2021-11-23 05:48:47 -05:00
Kinglykrab 1935ea60d0 [Commands] Remove #zonespawn Command. (#1811)
* [Commands] Remove #zonespawn Command.
- Remove unimplemented command.

* Remove from CMakeLists.txt.

* Fix.
2021-11-23 05:48:39 -05:00
Kinglykrab 8c7e1be344 [Commands] Cleanup #givemoney Command. (#1804)
- Cleanup money message to use new helper method.
2021-11-22 21:18:04 -05:00
Kinglykrab 9240497cbc [Commands] Cleanup #zsky Command. (#1808)
- Cleanup message and logic.
- Add parameter to allow data to be saved to database.
2021-11-22 21:17:13 -05:00
Kinglykrab 0da4610249 [Commands] Cleanup #zsave Command. (#1807)
* [Commands] Cleanup #zsave Command.
- Cleanup message and logic.

* White.
2021-11-22 21:17:03 -05:00
Kinglykrab 26c7287997 [Commands] Cleanup #zunderworld Command. (#1809)
* [Commands] Cleanup #zunderworld Command.
- Cleanup message and logic.
- Add parameter to allow data to be saved to database.

* Update zunderworld.cpp
2021-11-22 21:16:42 -05:00
Kinglykrab cece66adc6 [Commands] Cleanup #instance Command. (#1803)
* [Commands] Cleanup #instance Command.
- Cleanups message and logic.
- Cleanup ListAllInstances() method.
- Fix day calculation in ConvertSecondsToTime().

* Cleanup.

* Add return.
2021-11-21 19:02:01 -05:00
Kinglykrab d29993fafa [Commands] Cleanup #nukebuffs Command. (#1795)
* [Commands] Cleanup #nukebuffs Command.
- Cleanup messages and logic.
- #nukebuffs now allows you to nuke all, beneficial, or detrimental buffs, also added a help menu.
- Add BuffFadeBeneficial().
- Cleanup logic in some buff fade methods.
- Fix several spots where we were using CalcBonuses() when it was unnecessary, i.e when you fade no buffs you do not need to recalculate bonuses.

* Update spells.cpp
2021-11-21 15:20:16 -05:00
Kinglykrab 39c27c987d [Commands] Cleanup #peqzone Command. (#1794)
- Cleanup messages and logic.
- Add RULE_INT(Zone, PEQZoneHPRatio, 75, "Required HP Ratio to use #peqzone")
- Modify #peqzone Timer rule to allow it to be disabled.
2021-11-21 14:19:08 -05:00
Kinglykrab 5470ec6293 [Commands] Cleanup #corpse Command. (#1790)
- Cleanup message and logic.
- Add ConvertMoneyToString(platinum, gold, silver, copper) helper method.
- Cleanup NPC::QueryLoot() and Corpse::QueryLoot().
2021-11-21 14:02:03 -05:00
Kinglykrab 1acdc6034b [Commands] Cleanup #permagender Command. (#1779)
- Cleanup message and logic.
2021-11-21 14:01:15 -05:00
KayenEQ e9fc80815a [Spells] Support for SPA 161 and 450 to give percent spell or dot mitigation from Items or AA's. (#1793)
* spell dot shield item AA support

* Update spdat.h

* Update attack.cpp
2021-11-21 10:16:55 -05:00
splose a84536cd05 [Bug Fix] Autofire attacking yourself (#1776)
* Fix being able to attack yourself with autofire if Combat:MinRangedAttackDist == 0

* requested changes

* 2
2021-11-21 10:16:20 -05:00
splose 0a34809bb3 [Bug Fix] - Monk AA Spirit of Master Wu (#1775)
* Monk AA Spirit of Master Wu sends message even if it grants 0 extra attacks.

* fomatting + put if statement in wrong place.. oops.

* Need to push something to set up my Tortoise Github Auth

* test

* test

* test

* test

* test

* requested changes

* Update special_attacks.cpp

Co-authored-by: Kinglykrab <89047260+Kinglykrab@users.noreply.github.com>
2021-11-21 10:15:36 -05:00
Kinglykrab 03847fb1ac [Commands] Cleanup #lastname Command. (#1802)
- Cleanup message and logic.
2021-11-21 10:12:47 -05:00
Kinglykrab 8a27fce3a8 [Commands] Cleanup #memspell Command. (#1801)
- Cleanup message and logic.
- Add support for memorizing spell to target if you have GM enabled.
2021-11-21 10:12:37 -05:00
Kinglykrab 6a42639386 [Commands] Cleanup #pvp Command. (#1800)
- Cleanup messages and logic.
2021-11-21 10:12:23 -05:00
Kinglykrab b9214bfdee [Commands] Cleanup #aggro Command. (#1799)
- Cleanup messages and logic.
- Cleanup constant names and references.
- Cleanup aggro description methods.
2021-11-21 10:12:12 -05:00
Kinglykrab 04fda24c8e [Commands] Cleanup #aggrozone Command. (#1798)
- Cleanup message and logic.
- Add the ability to aggro the zone on your target if you have one.
2021-11-21 10:12:02 -05:00
Kinglykrab 446c5d90ec [Commands] Cleanup #killallnpcs Command. (#1797)
- Cleanup message and logic.
2021-11-21 10:11:47 -05:00
Kinglykrab 80f15ed04a [Commands] Cleanup #myskills Command. (#1796)
- Cleanup popup window display and logic.
2021-11-21 10:11:29 -05:00
Kinglykrab 51fb46556d [Commands] Cleanup #setfaction Command. (#1792)
- Cleanup message and logic.
- Doesn't allow you to use invalid faction IDs anymore.
2021-11-21 10:11:03 -05:00
Kinglykrab d73194c1f6 [Commands] Cleanup #setanim Command. (#1791)
- Cleanup message and logic.
- SetAppearance was not sending to self, so if you modified your own appearance, you wouldn't be able to see it.
2021-11-21 10:10:52 -05:00
Kinglykrab ec1cf68ce2 [Commands] Cleanup #damage Command. (#1789)
- Cleanup logic.
2021-11-21 10:08:20 -05:00
Kinglykrab 39b39970f6 [Commands] Cleanup #ginfo Command. (#1788)
- Cleanup message and logic.
2021-11-21 10:03:31 -05:00
Kinglykrab 40edefa6f4 [Commands] Cleanup #camerashake Command. (#1787)
- Cleanup message and logic.
- Fix ConvertSecondsToTime logic for milliseconds.
- Add ConvertMillisecondsToTime inline function.
2021-11-21 10:03:20 -05:00
Kinglykrab 7154d5b841 [Commands] Cleanup #flags Command. (#1783)
- Cleanup message and logic.
2021-11-21 10:03:08 -05:00
Kinglykrab dfe43ce189 [Commands] Cleanup #nukeitem Command. (#1782)
* [Commands] Cleanup #nukeitem Command.
- Cleanup message and logic.

* Typo.
2021-11-21 09:59:07 -05:00
Kinglykrab 69d5fee471 [Commands] Cleanup #givemoney Command. (#1781)
* [Commands] Cleanup #givemoney Command.
- Cleanup message and logic.

* Update givemoney.cpp
2021-11-21 09:58:23 -05:00
Kinglykrab f1d9221b4c [Commands] Cleanup #invul Command. (#1780)
- Cleanup message and logic.
2021-11-21 09:58:13 -05:00
Kinglykrab fb2f901539 [Commands] Cleanup #permarace Command. (#1778)
- Cleanup message and logic.
2021-11-21 09:56:27 -05:00
Kinglykrab 7c12c5d5ef [Commands] Cleanup #permaclass Command. (#1777)
- Cleanup message and logic.
2021-11-21 09:56:10 -05:00
splose 7559732408 [Bug Fix] Frenzy is supposed to use 1H Animation. (#1774) 2021-11-21 01:19:04 -05:00
KayenEQ fac0d795f2 [Bug Fix] Melee Life tap overflowing and causing damage (#1773)
* Update mob.cpp

* Update mob.cpp
2021-11-18 09:10:02 -05:00
Kinglykrab 3efd9c7f60 [Cleanup] Convert DeleteItemInInventory quantity to int16. (#1767)
* [Cleanup] Convert DeleteItemInInventory quantity to int16.

* Type conversion.
2021-11-16 08:52:22 -05:00
Kinglykrab bf8a0328b3 [Cleanup] Add Entity ID to ShowStats() NPC display. (#1770) 2021-11-15 18:19:42 -05:00
Michael Cook (mackal) 0ebb1cc54c Fix linking tests due to ddcb18418 (#1769) 2021-11-15 13:27:01 -05:00
Akkadius a111668888 [Hotfix] Default PR #1758 to false 2021-11-15 04:07:55 -06:00
Chris Miles 0550fcfd3f [GM Commands] Split GM Commands Into Separate Files (#1766)
* Split GM commands into their own files

* Code cleanup
2021-11-14 22:48:47 -06:00
Kinglykrab 293361a1f7 [Cleanup] Make use of AccountStatus constants wherever status is checked or used. (#1764)
* [Cleanup] Make use of AccountStatus constants wherever status is checked or used.
- Cleanup all instances of SendEmoteMessage.
- Cleanup all instances of SendEmoteMessageRaw.
- Cleanup all instances of MessageStatus.
- Convert Quest API method defaults to use constants.

* Cleanup constant names.
2021-11-14 21:01:13 -06:00
Kinglykrab 5d75b7b365 [Commands] Cleanup #advnpcspawn and #npcspawn Commands. (#1754)
* [Commands] Cleanup #advnpcspawn and #npcspawn Commands.
- Cleanup messages and logic.
- Add enum for spawn types to remove magic numbers.
- Cleanup messages that were improper/unused.

* Cleanup.

* Cleanup.

* Cleanup.

* Typo.

* Update command.cpp
2021-11-14 19:58:55 -06:00
Natedog2012 6400e2f8bc [Rules] Add option rule to load AA based on CurrentExpansion rule (#1758)
* Add option rule to load AA based on CurrentExpansion rule

* Default UseCurrentExpansionAAOnly to true

* Only clear the PlayerAA when reloadingAA
2021-11-14 19:54:45 -06:00
JJ 76b0183a0f [Loginserver] Increase IP/hostname size a bit more (#1765) 2021-11-14 19:53:53 -06:00
JJ b3471c51df [Config] Delete extra versions (#1763)
* [Config] Delete extra versions [CI SKIP]

* Same
2021-11-14 19:53:14 -06:00
Kinglykrab b2c86f5571 [Commands] Cleanup #raidloot Command. (#1757)
- Cleanup message and logic.
- Add RaidLootTypes enum and map for names.
2021-11-14 19:50:51 -06:00
Kinglykrab 264c6cb019 [Commands] Cleanup #setcrystals Command. (#1745)
* [Commands] Cleanup #setcrystals Command.
- Add message.
- Increase cap from 100,000 to 2,000,000,000.

* Cleanup.

* Remove condition, ID is always defined.

* Cleanup.
2021-11-14 19:47:36 -06:00
Akkadius 9bcb617f90 [Hotfix] Line ending changes 2021-11-14 15:59:03 -06:00
Kinglykrab f5d37a9959 [Commands] Cleanup #setpvppoints Command. (#1755)
* [Commands] Cleanup #setpvppoints Command.
- Cleanup message and logic.

* Cleanup.
2021-11-14 14:47:25 -05:00
Kinglykrab c44b82500d [Commands] Cleanup #setaaxp Command. (#1751)
* [Commands] Cleanup #setaaxp Command.
- Add message.
- Cleanup logic.

* Update command.cpp

* Cleanup.
2021-11-14 14:47:17 -05:00
Kinglykrab 4f550fcbf3 [Commands] Cleanup #loc Command. (#1752)
- Cleanup message and logic.
2021-11-14 14:09:10 -05:00
Kinglykrab 1103d50733 [Commands] Cleanup #setaapts Command. (#1750)
* [Commands] Cleanup #setaapts Command.
- Cleanup message and logic.
- Increase cap from 5,000 to 2,000,000,000.

* Update command.cpp

* Update command.cpp

* Cleanup.

* Cleanup.
2021-11-14 14:06:57 -05:00
Kinglykrab ddcb184183 [Commands] Cleanup #stun Command. (#1749)
* [Commands] Cleanup #stun Command.
- Cleanup message.
- Add ConvertSecondsToTime() to string_util.h and convert Quest API Methods to use helper.

* Add days to ConvertSecondsToTime() and cleanup logic.

* Cleanup.

* Typo.

* Cleanup.

* Cleanup.
2021-11-14 14:05:44 -05:00
Kinglykrab 90bcc5f03c [Commands] Cleanup #zonelock Command. (#1711)
* [Commands] Cleanup #zonelock Command.
- Add support for Zone IDs.
- Cleanup messages and display.
- Fix dangling pointer in ZoneLongName() helper method so name is displayed properly.

* Add account status enum.

* Typo.

* Typo.

* Convert list to constants.

* Cleanup.

* Update command.cpp

* Fix compile.
2021-11-14 11:32:08 -05:00
JJ 27f8ae3999 [Hotfix] Optional SQL for existing servers (#1756) 2021-11-13 22:15:49 -05:00
JJ 80a891e541 Make room for host names.
Since m_remote_ip_address does not resolve IP address, world server may still use host name.
2021-11-13 20:14:39 -05:00
KayenEQ 776449aa3d [Spells] Update to IsCombatProc checks (#1741)
* Update spells.cpp

* Update spells.cpp

* Update spells.cpp

* Update spells.cpp
2021-11-13 14:47:42 -05:00
JJ cef352f0ac [Bug Fix] Removed unused pointer. Fixes #157. (#1748) 2021-11-13 10:39:35 -05:00
Kinglykrab e8607a0c78 [Commands] Cleanup #checklos Command. (#1744)
- Cleanup message and logic.
2021-11-13 05:25:58 -05:00
Kinglykrab 9c55cf9a8e [Bug Fix] Loginserver Error String Constants. (#1747)
- Constant was named after Windows macro.
2021-11-13 02:00:45 -05:00
Chris Miles a9d1034298 [Loginserver] Worldserver Name Sanitization (#1739)
* Sanitize bad words in server names

* Add config options and enforcement for dev/test servers and servers starting with a special character

* Refine bad word logic

* Add installer to dev/test servers

* Change server prefixes

* Special char prefix

* Formatting

* Remove multi words

* Add server types enum

* Add error constants

* Remove sanitize from world level

* Use strn0cpy
2021-11-12 23:02:05 -06:00
Kinglykrab 8b83a13560 [Rules] Add Archery/Throwing Ammo Consumption Rules. (#1743)
- Add RULE_BOOL(Combat, ArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption")
- Add RULE_BOOL(Combat, ThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption")
2021-11-12 23:04:09 -05:00
hg 3c87480553 [Quest API] Add back removed lua class properties (#1742)
Fixes regression from 7b6decae
2021-11-12 21:16:39 -05:00
Kinglykrab 1a69218045 [Commands] Cleanup #faction Command. (#1716)
* [Commands] Cleanup #faction Command.
- Remove find subcommand as we have #findfaction now.
- Cleanup message.

* Remove #setfaction message.
2021-11-12 18:28:14 -05:00
Kinglykrab e870ee5e0e [Commands] Remove #logtest Command. (#1731)
- Remove unused/deprecated command.
2021-11-12 14:46:05 -06:00
Kinglykrab 908c6c18af [Commands] Cleanup #findnpctype Command. (#1714)
* [Commands] Cleanup #findnpctype Command.
- Cleanup message and logic.

* Logic cleanup, found_count is always greater than 0.

* Fix order.

* Add return.
2021-11-12 09:19:43 -05:00
Kinglykrab f591378ed3 [Commands] Cleanup #viewnpctype Command. (#1713)
* [Commands] Cleanup #viewnpctype Command.
- Create a temporary NPC to use ShowStats() instead.
- Cleanup message.

* Cleanup spawn/emote/textures logic in ShowStats() when unused.

* Formatting.
2021-11-12 08:58:43 -05:00
Kinglykrab 0997a8a31e [Commands] Remove #bug Command. (#1737)
- Remove unused command.
2021-11-12 08:23:22 -05:00
Kinglykrab 0bf6627fb0 [Commands] Remove #crashtest Command. (#1734)
- Remove unused/deprecated command.
2021-11-12 08:19:58 -05:00
Kinglykrab fb8539e679 [Commands] Cleanup #endurance Command. (#1719)
- Add message.
2021-11-12 08:11:45 -05:00
Kinglykrab f8c2e85f3e [Commands] Cleanup #mana Command. (#1718)
* [Commands] Cleanup #mana Command.
- Add message.

* Add self message.
2021-11-12 08:10:43 -05:00
Kinglykrab 110d2a0e10 [Commands] Cleanup #heal Command. (#1717)
* [Commands] Cleanup #heal Command.
- Add message.

* Remove target requirement.

* Add self message.

* Typo.
2021-11-12 08:06:53 -05:00
Kinglykrab 8d9415191a [Commands] Cleanup #reloadquest Command. (#1712)
- Cleanup message and logic.
2021-11-12 07:42:22 -05:00
Kinglykrab 7178a7e55d [Commands] Remove #clearinvsnapshots Command. (#1736)
* [Commands] Remove #clearinvsnapshots Command.
- Remove unused command.

* Web editor conflict fail

Co-authored-by: JJ <3617814+joligario@users.noreply.github.com>
2021-11-12 07:41:46 -05:00
Kinglykrab 9e8d03d92d [Commands] Remove #connectworldserver Command. (#1735)
- Remove unused command.
2021-11-12 05:58:18 -05:00
Kinglykrab f4a70eff43 [Commands] Remove #d1 Command. (#1733)
- Remove unused command.
2021-11-12 05:58:01 -05:00
Kinglykrab f9ec45c7ff [Commands] Remove #ipc Command. (#1732)
- Remove unused command.
2021-11-12 05:57:43 -05:00
Kinglykrab cf8bf9e4fc [Commands] Remove #manastat Command. (#1730)
- Remove unused command.
2021-11-12 05:57:25 -05:00
Kinglykrab 575237d764 [Commands] Remove #mysqltest Command. (#1729)
- Removed unused/deprecated command.
2021-11-12 05:57:09 -05:00
Kinglykrab e12e8df3ef [Commands] Remove #numauths Command. (#1728)
- Remove unused command.
2021-11-12 05:56:50 -05:00
Kinglykrab 8d7b7d6cc4 [Commands] Remove #optest Command. (#1727)
- Remove unused command.
2021-11-12 05:56:32 -05:00
Kinglykrab 6f79ea117c [Commands] Remove #refundaa Command. (#1726)
- Remove unused command.
2021-11-12 05:56:11 -05:00
Kinglykrab 7b022502da [Commands] Remove #qtest Command. (#1725)
- Remove unused command.
2021-11-12 05:55:54 -05:00
Kinglykrab 4a376b7859 [Commands] Remove #testspawn and #testspawnkill Commands. (#1724)
- Remove unused commands.
2021-11-12 05:55:35 -05:00
Kinglykrab 87cdf7feb1 [Commands] Remove #synctod Command. (#1723)
- Remove unused command.
2021-11-12 05:55:06 -05:00
Kinglykrab caf32290b8 [Commands] Remove #sendop Command. (#1722)
- Remove unused command.
2021-11-12 05:54:44 -05:00
JJ 7d495c56b3 [Logs] Show local_address in correct location (#1721) 2021-11-12 05:54:21 -05:00
Kinglykrab dc1c7bb284 [Commands] Remove #serversidename Command. (#1720)
- Remove unused command.
2021-11-12 05:53:44 -05:00
Chris Miles a6c85babfc [Loginserver] Add config option to display player count (#1738)
* [Loginserver] Add config option to display player count

* Update name
2021-11-11 22:38:41 -06:00
hg cbea7045fa [Loginserver] Identify unknown login client packet fields (#1680)
* Add player login reply struct

* Use player login reply struct for failed logins

* Use base message struct for login requests

* Refactor server list reply serialization

Use BaseMessage and BaseReplyMessage structs for server list
and add flags for server type and status

* Use reply message struct for login handshake

Remove client version checks, the packets are the same for titanium and rof2

* Use base headers for join server requests

* Log correct server list ip

* Add compressed flag to base message header

Document encrypt type flag more
2021-11-11 20:13:30 -06:00
KayenEQ 099759c477 [Commands] #tune command rewrite (#1677)
* tune updates

* Update tune.cpp

* tune update

* updates

* updates

* less zero

* update

* up

* u

* Update tune.cpp

* Update tune.cpp

* avoidance working

* accuracy

* save1

* Update tune.cpp

* override

* Removed Old Tune Code

* cleanup1

* up

* finished v1

* Update command.cpp

* Update command.cpp

* spellfix

* Update command.cpp

* remove test command

* added SYNC comments

Hopefully if anyone changes these functions they will change the corresponding tune

* Tune_ to Tune

Co-authored-by: Akkadius <akkadius1@gmail.com>
2021-11-11 19:41:59 -06:00
cybernine186 65197ac027 [Rules] Gate /tgb, /autofire and /melody (#1679)
* Rules to negate /tgb, /autofire, and /melody

Created new rules to negate server and client side effects of commands: /tgb, /autofire, and /melody. These commands are enabled by default and can be disabled to enforce a classic EQ experience if using progression style play for example.

Rules
--------------
RULE_BOOL(Character, EnableBardMelody, true, "Enable Bard /melody by default, to disable change to false for a classic experience.")
RULE_BOOL(Character, EnableRangerAutoFire, true, "Enable Ranger /autofire by default, to disable change to false for a classic experience.")
RULE_BOOL(Character, EnableTGB, true, "Enable /tgb (Target Group Buff) by default, to disable change to false for a classic experience.")

* Removed sql query for rules per Mackal recommendation.
2021-11-11 19:41:03 -06:00
Alex e4bd6f5bd2 [Networking] Servertalk Legacy World Connections for Login (#1662)
* servertalk server connections will now attempt to parse legacy connections as well as modern ones

* Some fixes for legacy connections

* Change legacy default from local to eqemu
2021-11-11 19:37:35 -06:00
mmcgarvey acf5836253 [Rules] Add optional rule for lifetap heals (#1689)
What:
	Add toggle for compounding bonuses for lifetap heals.

Why:
	When spell damage and heal amount bonuses are scaled to ludicrous
	levels, this double dip results in very high heals from
	relatively weak lifetaps.

Created new rule:  Spells:CompoundLifetapHeals

If true (default):
	Apply spell damage bonuses to lifetap damage
	Pass that amount through heal bonuses
	Heal for this resulting amount
If false:
	Apply spell damage bonuses to lifetap damage
	Heal for this resulting amount
2021-11-11 19:37:14 -06:00
KayenEQ 17c8e8414c [Spells] Fixed proc rate for Ranged procs (#1715) 2021-11-11 19:27:50 -06:00
KayenEQ 239033a269 [Bug Fix] Prevent critical DOTs from affecting beneficial damage over time (#1710)
* no critical from lich

* better
2021-11-11 18:32:16 -05:00
Kinglykrab fa07064466 [Commands] Cleanup #cvs Command. (#1709)
* [Commands] Cleanup #cvs Command.
- Cleanup message and display.
- Add Total Clients to message.
- Add Unique IPs to message.

* Formatting.

* Formatting.
2021-11-11 16:48:50 -05:00
Kinglykrab 994ef712b2 [Commands] Cleanup #cast Command. (#1706)
* [Commands] Cleanup #cast Command.
- Cleanup message.

* Add optional cast non-instant parameter.
- Fix cast time.

* Fix message.
2021-11-11 16:48:35 -05:00
KayenEQ 33c30d3cbb [Bug Fix] Fix for dual wield animation when same delay weapons. (#1671)
* DW animation fix

* spelling

* better animation

looks better for low skill where dw doesn't fire as often.

* Update attack.cpp
2021-11-10 21:27:51 -05:00
KayenEQ d9c8e80bca [Spells] Allow item click effects to have cast time and recast time modified by focus effects. (#1695)
* prelim

* Spell Focus implemented

* AA implemented

* Update spdat.h

* Update spdat.h

* working

* Update spells.cpp

* prelim excludes

* enum limit expansion

* overhaul

* v2 testing

* updates

* working

* Fin

* Update spell_effects.cpp

* Update spell_effects.cpp

* update

* Update spells.cpp

* fix

* fix

* Update spell_effects.cpp

* remove debugs

* Update spells.cpp
2021-11-10 21:23:49 -05:00
Kinglykrab 990729fe21 [Commands] Cleanup #distance Command. (#1707)
- Cleanup message.
2021-11-10 21:21:06 -05:00
Kinglykrab aac0dd2993 [Commands] Cleanup #setlanguage Command. (#1705)
* [Commands] Cleanup #setlanguage Command.
- Cleanup message and lofic.
- Add GetLanguageName() helper and GetLanguageMap() for future use.

* Optimize GetLanguageName().
2021-11-10 21:20:51 -05:00
Kinglykrab b17c24d2df [Commands] Cleanup #setskill Command. (#1704)
* [Commands] Cleanup #setskill Command.
- Cleanup message and logic.

* Optimize GetSkillName().
2021-11-10 21:20:40 -05:00
Kinglykrab 32d606c667 [Bug Fix] Fix Mob::ShowStats() Proximity Display. (#1708) 2021-11-10 19:48:02 -05:00
Kinglykrab 6661672e2d [Commands] Cleanup #showskills Command. (#1698)
* [Commands] Cleanup #showskills Command.
- Cleanup display and use GetSkillName() helper method.

* Add optional "all" parameter to show all skills.

* Formatting.

* Formatting.

* Target, not c.
2021-11-09 23:24:46 -05:00
Kinglykrab b5391b9110 [Commands] Cleanup #showstats Command. (#1700)
- Convert Mob::ShowStats() to use the #npcstats code and make #npcstats use Mob::ShowStats().
2021-11-09 21:25:42 -05:00
Kinglykrab e306059f43 [Commands] Cleanup #showspellslist Command. (#1703)
- Cleanup messages and display.
2021-11-09 21:24:34 -05:00
Kinglykrab a64e326c68 [Commands] Cleanup #viewzoneloot Command. (#1702)
- Cleanup message logic.
2021-11-09 21:24:25 -05:00
Kinglykrab 605b3d3a27 [Commands] Cleanup #fov Command. (#1701)
- Cleanup message.
2021-11-09 21:24:17 -05:00
Kinglykrab 248e6d44db [Commands] Cleanup #npccast Command. (#1699)
- Cleanup messages and display.
2021-11-09 21:23:48 -05:00
Kinglykrab 328a94e2d4 [Commands] Add #findfaction Command. (#1697)
- Add #findfaction [search criteria] command.
- Cleanup other #find command messages/logic.
- Add GetMaxFaction() helper method.
- Add races.h defines for races 725-732.
2021-11-09 21:23:38 -05:00
Michael Cook (mackal) 211196a722 Fix Channel TellEcho issues (#1676)
These were missed switching them to TellEcho from a previous change
2021-11-09 10:54:54 -05:00
Kinglykrab 0b283e60db [Commands] Remove #listnpcs Command. (#1696)
- Unused command.
2021-11-07 18:32:33 -05:00
Kinglykrab 90871cb3d9 [Commands] Cleanup #worldshutdown Command. (#1694)
- Cleanup system messages and magic numbers.
2021-11-07 17:21:42 -05:00
Kinglykrab bf92845a4a [Rules] Add Resurrection Sickness rules for Characters/Bots. (#1692)
* [Rules] Add Resurrection Sickness rule for Characters/Bots.
- Add RULE_BOOL(Character, UseResurrectionSickness, true, "Use Resurrection Sickness based on Resurrection spell cast, set to false to disable Resurrection Sickness.")
- Add RULE_BOOL(Bots, UseOldRaceRezEffects, false, "Older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore")
- Add RULE_BOOL(Bots, UseResurrectionSickness, true, "Use Resurrection Sickness based on Resurrection spell cast, set to false to disable Resurrection Sickness.")

* Add rules for spell IDs.

* Fix bot health on spawn when resurrection sickness is disabled.
- Formatting.

* Remove 'this' keyword.
2021-11-07 17:21:34 -05:00
Kinglykrab f8cbc2faed [Commands] Further implement #worldwide functionality. (#1693)
- Add #worldwide remove [Spell ID] - Removes a spell from player buffs worldwide.
- Add #worldwide message [Message] - Sends a worldwide message in Chat::Yellow.
- Add #worldwide move [Zone ID] or #worldwide move [Zone Short Name] - Moves every player in the game to the specified zone.
- Add #worldwide moveinstance [Instance ID] - Moves every player in the game to the specified instance.
- All but `#worldwide message` send a message to sender client.
2021-11-07 17:21:22 -05:00
Kinglykrab 30fdb18945 [Bug Fix] Fix Elemental Illusion spells not using proper texture. (#1691) 2021-11-07 17:21:04 -05:00
Kinglykrab 062fb73f03 [Commands] Remove #test, #spon, and #spoff Commands. (#1686)
- These commands are unused or outdated.
2021-11-07 17:20:55 -05:00
Kinglykrab 194c71727d [Commands] Cleanup #npcstats Command. (#1690)
- Cleanup menu and add stats that were not there before.
- Only display some data if necessary (i.e only show loot/money if they have loot/money)
- Add skill name helper method.
- Add faction name helper method.
- Add Charmed stats and other getter methods.
- Cleanup QueryLoot() method.
2021-11-07 17:20:43 -05:00
Kinglykrab e1de3d2ae0 [Commands] Cleanup #zstats Command. (#1687)
- Add new data from NewZone_Struct to command and clean up display.
2021-11-07 17:15:03 -05:00
KayenEQ 7f497f9d32 [Spells] Implemented SPA 415 SE_FFItemClass (#1688)
* prelim

* Spell Focus implemented

* AA implemented

* Update spdat.h

* Update spdat.h

* prelim excludes

* enum limit expansion

* overhaul

* v2 testing

* updates

* working

* Fin

* Update spell_effects.cpp

* Update spell_effects.cpp

* var fix

* Update spell_effects.cpp

make it not apply to casted spells... oops

* Update spell_effects.cpp

* Update spell_effects.cpp
2021-11-07 16:35:30 -05:00
KayenEQ 1cdb1816a2 [Bug Fix] SOF+ clients item click recast timer not met check (#1682)
* Update client_packet.cpp

* Update spells.cpp

* augs working too
2021-11-06 23:14:36 -04:00
Kinglykrab bc82b897c5 [Commands] Add #emptyinventory Command. (#1684)
* [Commands] Add #emptyinventory Command.
- Allows you empty you or your target's inventory completely. (Equipment, General, Bank, and Shared Bank)
- Fixed an issue not allowing quest::removeitem(item_id, quanity) to remove 0 charge items.
- Fixed an issue not allowing eq.remove_item(item_id, quanity) to remove 0 charge items.

* Update command.cpp

* Update client.cpp
2021-11-06 22:34:04 -04:00
hg beb4de0b45 [Cleanup] Remove unused door variable. (#1685) 2021-11-06 21:57:05 -04:00
KayenEQ 785926a584 [Quest API] Added NPC special ability to modify Riposte/Dodge/Parry/Block chance (#1683)
* Update attack.cpp

* u

* Update attack.cpp

* spellchecked
2021-11-06 21:06:14 -04:00
Natedog2012 5c7972345a [Bug Fix] Fix startzone rule to default players to correct zone when not found … (#1669)
* Fix startzone rule to default players to correct zone when not found in database

* Formatting

Co-authored-by: Kinglykrab <89047260+Kinglykrab@users.noreply.github.com>
2021-11-06 18:22:52 -04:00
Natedog2012 886f00ed50 Fix resetAA to actually remove all AAs except granted AAs (#1681) 2021-11-06 17:36:19 -04:00
Kinglykrab b983fac860 [Quest API] Alphabetize Perl method exports. (#1672)
- Keeps things tidier.
Perl script was used to get this in order easily.
```pl
my @perl_file_types = (
	"bot",
	"client",
	"doors",
	"entity",
	"expedition",
	"groups",
	"hateentry",
	"inventory",
	"mob",
	"npc",
	"object",
	"perlpacket",
	"player_corpse",
	"questitem",
	"raids",
	"spell"
);

foreach my $file_type (sort {$a cmp $b} @perl_file_types) {
	my $perl_file = "perl_$file_type.cpp";
	open my $client_file, '<', $perl_file or die "Cannot open file_name $perl_file";
	{
		local $/;
		$content = <$client_file>;
	}
	close $client_file;

	open my $perl_data_file, ">", "perl_$file_type\_data.cpp";

	my @variables = ();

	foreach my $line (split("\n", $content)) {
		if ($line=~/newXSproto\(/i) {
			$line =~ s/\s+/ /g;
			my @line_data = split(/ /, $line);
			push(@variables, join(" ", @line_data));
		}
	}

	foreach my $variable (sort {$a cmp $b} @variables) {
		$variable =~ s/^ //ig;
		print $perl_data_file "\t$variable\n";
	}

	close $perl_data_file;
}```
2021-11-06 17:36:06 -04:00
Kinglykrab 7b6decaef3 [Quest API] Alphabetize Lua method exports. (#1673)
- Keeps things tidier.
- Removes unnecessary/outdated comments at the top of files.
2021-11-06 17:36:00 -04:00
Kinglykrab 8d8301fbd7 [Commands] Add #findskill [search criteria] Command. (#1674)
* [Commands] Add #findskill [search criteria] Command.
- Allows you to search for skills by ID or partial name.

* Add error message.

* Update command.cpp

* Update command.cpp

* Update command.cpp
2021-11-06 17:35:43 -04:00
Kinglykrab b4aa401210 [Commands] Add #findtask [search criteria] Command. (#1675)
* [Commands] Add #findtask [search criteria] Command.
- Allows you to search for Tasks by ID or partial name.

* Update command.cpp
2021-11-06 17:35:37 -04:00
KayenEQ f1bfd6bc2a [Spells] Implemented SPA 512 SE_Proc_Timer_Modifier, Fixed AA procs not working (#1646)
* update for SPA 511

* remove debugs, AA implemented

* update

* twinprocfix

* AA procs added

* format update

* update

* proctimer limits

* update

* rename function

renamed function
only check for buffs value > 0, don't need to check for AA's which are negative ID's

* pre merge

* variable updates

* Update spell_effects.cpp

* var rename

update var name to better represent its function.

* updated proc struct

added reuse timer

* reuse timer to spell procs

* updates

* debug remove

* Update mob.cpp

* fix

* merge
2021-11-05 14:14:11 -04:00
KayenEQ 8c95323728 [Spells] Update to Charm target restriction code (#1666)
* charm target restrictions

* fixed

* Update spells.cpp

* Update spells.cpp

* Update spells.cpp

only send spell bar when we have to, avoid potential exploit.

* logs
2021-11-05 10:39:17 -04:00
KayenEQ 5874deeffc Update spell_effects.cpp (#1670) 2021-11-03 21:07:45 -04:00
KayenEQ 18cc648c8d Update spell_effects.cpp (#1668) 2021-11-03 19:01:08 -04:00
Kinglykrab 9d515b20f2 [Quest API] Simplify bulk Scribe and Train logic. (#1660)
* [Quest API] Simplify bulk Scribe and Train logic.
- Add $client->GetFreeDisciplineSlot(starting_slot) to Perl.
- Add $client->ScribeSpells(min_level, max_level) to Perl.
- Add $client->LearnDisciplines(min_level, max_level) to Perl.
- Add client:GetNextAvailableDisciplineSlot(starting_slot) to Lua.
- Add client:ScribeSpells(min_level, max_level) to Lua.
- Add client:LearnDisciplines(min_level, max_level) to Lua.
Convert quest::scribespells() and quest::traindisc() to use new ScribeSpells and LearnDisciplines methods for consistency.

* Update command.cpp
2021-11-03 18:31:13 -04:00
Kinglykrab 17aaab1f9d [Quest API] Add Spell methods to Perl. (#1631)
* [Quest API] Add Spell methods to Perl.
- Add quest::getspell(spell_id) to Perl.
- Add eq.get_spell(spell_id) to Lua.
These methods return a spell object.

Exports $spell object references to spell events.

* Formatting.

* Remove comment.

* Update spdat.cpp

* Amplication typo.

* Fix conflicts.

* Remove repository changes.

* Fix typing.

* Update spell_effects.cpp
2021-11-03 17:47:15 -04:00
Chris Miles 6e26e8953c [Loginserver] Health Checks (#1665)
* Health checks stash

* Healthcheck work
2021-11-03 14:39:51 -05:00
Natedog2012 e4138b871b [Rules] Add optional rules for HealAmt and SpellAmt to scale DoTs/HoTs. (#1661)
* Add optional rules for itembonuses HealAmt and SpellAmt to scale for DoTs/HoTs

* Fix typo

* Only 1 rulecheck

* Apply +healingitems and +dmgitems after focus effects so they scale properly

* Fix dots / hots to not always use PVPScaling for extra_dmg / extra_healing

Adjust +healamt and +spelldmg to scale over the full duration of the spell, Thanks Kayen
2021-11-02 15:12:07 -05:00
splose 4ac525afc2 [Rules] Missing Character:TradeskillUpTailoring (#1667) 2021-11-02 12:57:16 -05:00
Chris Miles 05782433b8 [Loginserver] Add some resiliency to LS requests (#1663) 2021-11-02 00:19:13 -05:00
KayenEQ 9af7122b1d [BugFix] Remove potential nullptrs in Virus Code (#1658) 2021-10-31 00:06:32 -05:00
Chris Miles 9e7a763482 [Charm] Push up fragments of Kayen's PR back up (#1659) 2021-10-31 00:04:48 -05:00
Akkadius 1231d44b55 Revert "[BugFix] Charm Targeting and other issues. (#1655)"
This reverts commit df3161455a.
2021-10-30 22:18:40 -05:00
hg 873f1f7f34 [Hotfix] Add include to fix windows build (#1657) 2021-10-30 21:11:04 -05:00
Chris Miles d87db648c3 [Loginserver] Code Cleanup and Tweaks (#1653)
* if for whatever reason the world server is not sending an address, use the local address it sends

* Log when world is sending loginserver info

* Force legacy mode when login host is login.eqemulator.net to avoid misconfigurations at least until things change

* Add human IP translation to log messages

* Sanitize world server name

* Code cleanup and renaming member variables

* More cleanup

* Remove this->

* Validation constants

* Key worldserver lookups by both longname and shortname both

* Update allowed character list

* Fix short_name API response field; add world_id to response

* Shorten receiver verbosity

* Remove unnecessary member variables from database and rename database to m_database

* Adjust MAX_SERVER_VERSION_LENGTH

* Fix indents
2021-10-30 19:09:42 -05:00
Chris Miles 119c3d14b7 [Hotfix] Gate some new shared task logic behind task rule (#1656) 2021-10-30 19:06:38 -05:00
Chris Miles 3cda32c213 [Saylinks] In-Memory Saylink Lookups (#1644)
* Implement saylink memory lookups (performance)

* Ignore commands
2021-10-30 17:32:59 -05:00
KayenEQ df3161455a [BugFix] Charm Targeting and other issues. (#1655)
* fix for target change bug on client

* Update spell_effects.cpp
2021-10-30 16:48:55 -05:00
KayenEQ 4389f84ea5 [BugFix] Fix for bard song instrument mod formula from recent update (#1654)
* Update spell_effects.cpp

* Update spell_effects.cpp

* Update spell_effects.cpp
2021-10-30 08:50:15 -04:00
Chris Miles f9855fd097 [Rez] Fix Z during Resurrection (#1648) 2021-10-30 00:54:44 -05:00
Chris Miles f912814e13 [Commands] Fix Z on #spawnfix (#1647)
* Fix Z on spawnfix

* Slight adjustment
2021-10-30 00:54:33 -05:00
Paul Coene 5738958a2a Fix issue with droplimit code (#1650) 2021-10-28 14:43:40 -04:00
Michael Cook (mackal) d36d11653a Fix issue with new summmon method putting players OOB (#1649)
The FindClosestZ was finding the Z above them ... lets try just not
doing that for now :)
2021-10-27 23:42:31 -04:00
Chris Miles 7230714cbc [Spells/Disciplines] Bulk Train / Scribe (#1640)
* Bulk scribe spells

* Add bulk disc training

* Remove bulk from non bulk method

* PR adjustments
2021-10-27 21:45:27 -04:00
Chris Miles 6e5bf4b941 [Saylinks] Multiple saylinks in brackets (#1643)
* Saylink edge case where multiple saylinks show up within a bracket

* Update partial
2021-10-27 00:01:37 -05:00
KayenEQ fb66afd565 [Spells] Implemented SPA 511 SE_Ff_FocusTimerMin (#1645)
* update for SPA 511

* remove debugs, AA implemented

* update

* format update

* rename function

renamed function
only check for buffs value > 0, don't need to check for AA's which are negative ID's

* var rename

update var name to better represent its function.
2021-10-26 21:36:10 -04:00
Chris Miles ef5124d756 [Shared Tasks] World Reload Task Data on #task reloadall (#1641) 2021-10-24 21:53:29 -05:00
KayenEQ 987de17e93 [Spells] Rework for SPA 413 SE_FcBaseEffects and Bard updates (#1629)
* baseline start

* update1

* updates

* base effect implemented for bard

* instrument mod updates

amplification amps itself

* updates

* updates

* debug

* base effect updates

* baseeffects for spell focus updated

* update skill attack baseeffects

* focus will remain for quest functions

* song cap mod added back in

* remove debugs1

* fix cr

* base effects functionalish

* remove debug

* Update client_mods.cpp

* spdat instrumentmod

* Update spell_effects.cpp

* Update spdat.h

* remove new instrument mod check

split PR
2021-10-24 18:38:28 -05:00
KayenEQ 060be606e7 [Spells] Rework of Virus Effect code (#1593)
* start of rework

* functional

* virus updates

* Update npc.cpp

* updates

* updates

* update v2

* pre remove old code

* removed old code1

* remove debugs

* description

* Update spell_effects.cpp

* changed function name

* remove unused var

* merge error fix

* fix formating issue

* Update spdat.cpp

* Update spell_effects.cpp

* Convert virus entity range code to use vectors and GetCloseMobList

* Formatting [skip ci]

Co-authored-by: Akkadius <akkadius1@gmail.com>
2021-10-24 18:27:51 -05:00
Kinglykrab 1c5f9f2e0f [Bug Fix] Fix possible #proximity crash. (#1639) 2021-10-24 17:50:43 -04:00
Paul Coene 62253cc016 [Bug Fix] Edge cases where min_drop 1 not honored with valid choices (#1617)
* [Bug Fix] Edge cases where min_drop 1 not honored with valid choices

* Forgot header file change.

* Remove verbose option from MeetsLootDropLevelRequirements per @akka

* Fix spacing

* Restore verbose mode after further consideration

* Remove logging on counting of valid items

Co-authored-by: Noudess <noudess@gmail.com>
2021-10-24 16:17:42 -05:00
KayenEQ 0b18671e91 [Spells] Update to how Bard Instrument mods are applied to spell effects (#1628)
* new instrument mod spell effect checks

PR split

* format

* Update spdat.cpp

correction, all direct damage spells get modifiers. Made a mistake with the parse, was using wrong mod.

* restriction changes

cure effects can be modified.
decided to keep a list of known effects that are not modified to return false. and will keep the default to be true for anything as to not inhibit custom bard song development

* SE_ProcChance is modified

* Update spdat.cpp

* update

* Update spell_effects.cpp
2021-10-24 16:07:25 -05:00
Kinglykrab c98f3cfb4c [Quest API] Further char array cleanup. (#1634)
- Cleans up the rest of the char arrays used when exporting to events.
- Converts all events to use a similar variable name for export `export_string`.
- Needless calls to .c_str() removed.
2021-10-24 16:06:22 -05:00
Kinglykrab 624d11de4e [Bug Fix] Fix missing format in client message. (#1637) 2021-10-24 17:03:24 -04:00
Logan 5eb95a95d0 [Rules] Added rule to extend max race id (#1630)
* Added rule to extend max race id

* Cleaned fmt of MaxRaceID

* Added format command

* Updated MaxRaceID default to be 732
2021-10-24 15:53:49 -05:00
JJ da01156673 Update 2021_03_03_instance_safereturns.sql (#1636) 2021-10-24 11:53:23 -04:00
KayenEQ 6a244f16e1 Update spells.cpp (#1635) 2021-10-24 11:08:21 -04:00
KayenEQ 36d10462f7 [Combat] Updates to IMMUNE_MELEE_NONMAGICAL mechanics (#1616)
* pre remove debug

* Update attack.cpp

* Update attack.cpp

* Update attack.cpp

* Update attack.cpp

* apply to temp pets

* format fix

* changed to just use one rule

Merged into NPC's and Pet's into one rule.
2021-10-22 22:39:37 -04:00
Natedog2012 c30dbf6628 [Bug Fix] Do not check tics remaining on non-buff spells (#1633) 2021-10-22 17:16:56 -04:00
splose 657cbbcabe define caster to fix a crash from #1618 (#1632) 2021-10-22 13:48:15 -04:00
Kinglykrab 81e7cf5a32 [Quest API] Convert Spell Events to similar formats and exports. (#1618)
* [Quest API] Convert Spell Events to similar formats and exports.
Export spell ID, caster ID, caster level, tics remaining, and buff slot to Perl/Lua spell events.
- Export e.buff_slot, e.caster_id, e.caster_level, e.spell_id, and e.tics_remaining to `event_spell_buff_tic`, `event_spell_effect`, and `event_spell_fade` in Lua.
- Export $buff_slot, $caster_id, $caster_level, $spell_id, $tics_remaining to `EVENT_SPELL_EFFECT_BUFF_TIC_CLIENT`, `EVENT_SPELL_EFFECT_BUFF_TIC_NPC`, `EVENT_SPELL_EFFECT_CLIENT`, `EVENT_SPELL_EFFECT_NPC`, and `EVENT_SPELL_FADE` in Perl.

* Formatting.

* Remove debug variable.
2021-10-20 16:02:12 -04:00
Kinglykrab edf298685e [Quest API] Convert all char arrays to strings. (#1612)
* [Quest API] Convert all char arrays to strings.
Also change multiple loops for zone controller to one loop.

* Remove 'this' keyword'
2021-10-20 15:59:28 -04:00
Kinglykrab efab0c4b6b [Quest API] Add remove LDoN Win/Loss to Perl and Lua. (#1611)
* [Quest API] Add remove LDoN Win/Loss to Perl and Lua.
- Add $client->RemoveLDoNLoss(theme_id) to Perl.
- Add $client->RemoveLDoNWin(theme_id) to Perl.
- Add quest::removeldonloss(theme_id) to Perl.
- Add quest::removeldonwin(theme_id) to Perl.
- Add quest::crosszoneremoveldonlossbycharid(character_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonlossbygroupid(group_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonlossbyraidid(raid_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonlossbyguildid(guild_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonlossbyexpeditionid(expedition_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonlossbyclientname(client_name, theme_id) to Perl.
- Add quest::crosszoneremoveldonwinbycharid(character_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonwinbygroupid(group_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonwinbyraidid(raid_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonwinbyguildid(guild_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonwinbyexpeditionid(expedition_id, theme_id) to Perl.
- Add quest::crosszoneremoveldonwinbyclientname(client_name, theme_id) to Perl.
- Add quest::worldwideaddldonloss(theme_id, min_status, max_status) to Perl.
- Add quest::worldwideaddldonwin(theme_id, min_status, max_status) to Perl.
- Add client:RemoveLDoNLoss(theme_id) to Lua.
- Add client:RemoveLDoNWin(theme_id) to Lua.
- Add eq.remove_ldon_loss(theme_id) to Lua.
- Add eq.remove_ldon_win(theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_loss_by_char_id(character_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_loss_by_group_id(group_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_loss_by_raid_id(raid_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_loss_by_guild_id(guild_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_loss_by_expedition_id(expedition_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_loss_by_client_name(client_name, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_win_by_char_id(character_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_win_by_group_id(group_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_win_by_raid_id(raid_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_win_by_guild_id(guild_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_win_by_expedition_id(expedition_id, theme_id) to Lua.
- Add eq.cross_zone_remove_ldon_win_by_client_name(client_name, theme_id) to Lua.
- Add eq.world_wide_add_ldon_loss(theme_id, min_status, max_status) to Lua.
- Add eq.world_wide_add_ldon_win(theme_id, min_status, max_status) to Lua.
Adds enum for LDoN Themes and Theme Bitmasks so we're not using magic numbers.
Adds item links to item messages and augment messages on rejection/restriction/Lore.

* Update client_packet.cpp

* Update client_packet.cpp

* Update servertalk.h

Alphabetical.
2021-10-20 15:11:14 -04:00
Kinglykrab c838564023 [Bug Fix] Fix OpenSSL Support for Windows (#1625) 2021-10-19 22:28:10 -05:00
Chris Miles d197ee631e [Saylinks] Fix auto saylink injection edge cases (#1620)
* Fix auto saylink injection edge cases

* Add even more resiliency to edge cases

* Move to split based injection

* Add some constants
2021-10-19 22:25:13 -05:00
Kinglykrab 3dcddcba04 [Quest API] Add GetHateRandomBot(), GetHateRandomClient(), and GetHateRandomNPC() to Perl/Lua. (#1613)
- Add $mob->GetHateRandomBot() to Perl.
- Add $mob->GetHateRandomClient() to Perl.
- Add $mob->GetHateRandomNPC() to Perl.
- Add mob:GetHateRandomBot() to Lua.
- Add mob:GetHateRandomClient() to Lua.
- Add mob:GetHateRandomNPC() to Lua.
2021-10-17 23:41:10 -04:00
Natedog2012 7823ff5336 [Quest API] Add EVENT_LOOT_ZONE to zone_controller (#1608)
* Add EVENT_LOOT_ZONE to zone_controller

* Fix porting event_loot_zone to lua API

* Remove extra spacing and remove forced message to allow for scripted responses.

* Allow all script parsing to fire before sending a failed lootitem, add corpse_id

* Only search for zone_controller once
2021-10-16 23:19:19 -05:00
Chris Miles 11c335a015 [DiaWind] Tag Adjustments for title, button_one, button_two (#1610)
* Add a consistent way to handle a few different tags

* Simplify logic further
2021-10-16 21:35:03 -05:00
Kinglykrab 07d96ad921 [Bug Fix] Fix Character Recast Type -1 saving to database. (#1598) 2021-10-16 15:10:42 -04:00
Kinglykrab 5d522b149b [Bug Fix] Allow invisible to be cast on Raid Group members. (#1607)
When `Spells:InvisRequiresGroup` was true, you could only cast on Group members, intended functionality is to cast on Group members and/or people in your Raid Group.
2021-10-16 08:56:38 -04:00
splose 234bd89ed5 Merge pull request #1609 from KayenEQ/npcMagicAttack2
hotfix for PR #1606 (IMMUNE MELEE NONMAGICAL)
2021-10-16 00:38:06 -04:00
KayenEQ af5cfb9bed [Spells] Fix to prevent Charmed Pets from continuing fight target if owner is dead. (#1600)
* Fix for charm break if pet owner dead

* fix, can't check hatelist it is already wiped.

* Update spell_effects.cpp
2021-10-16 00:22:07 -04:00
KayenEQ 426f9c337b hotfix 2021-10-16 00:10:54 -04:00
KayenEQ 5235dcee95 Fix Immune Melee Nonmagical logic (#1606) 2021-10-15 20:46:57 -04:00
Paul Coene 203ba2d340 [Bug Fix] Urgent - Previous fix for TimeSync on static zones broke dynamic zones. (#1605)
* [BugFix] Urgent - Previous fix for TimeSync on static zones broke dynamic zones

* Use local variable instead of inline accessor for consistancy.

Co-authored-by: Noudess <noudess@gmail.com>
2021-10-15 13:17:51 -04:00
KayenEQ 9c67421ccc quick fix for persistent effects fading (#1604) 2021-10-15 09:04:14 -04:00
KayenEQ 6669fc8214 [Bug Fix] Healing pets not correctly dropping out of combat status (#1603)
* Fix for pets not correctly triggering in combat timers

* Update spells.cpp
2021-10-14 23:30:34 -04:00
Paul Coene cef873f793 [BugFix] Remove detection of client pets from Sense[Summoned|Undead|Animal] spells (#1601)
* Remove detection of client pets from Sense[Summoned|Undead|Animal]

* Use IsPetOwnerClient() function instead of individual checks

* Add option to exclude client pets from GetClosestMobByBodyType

* Add parameter

Co-authored-by: Noudess <noudess@gmail.com>
2021-10-14 10:52:29 -04:00
KayenEQ 6a962f2591 [Spells] Update SPA158 Reflect (#1590)
* update

* updates

* updates

* update

* update

* Update ruletypes.h

* Apply extra spell dmg

Mob with the reflect effect apply its Extra Spell Damage from item stat to the reflected spell.
Updated portion of formula for extra damage based on live parsing.

* correct formula
2021-10-12 15:30:36 -04:00
Kinglykrab 91adf9c0eb [Quest API] Add cross zone and world wide dialogue windows to Perl/Lua. (#1599)
* [Quest API] Add cross zone and world wide dialogue windows to Perl/Lua.
- Add quest::crosszonedialoguewindowbycharid(character_id, message) to Perl.
- Add quest::crosszonedialoguewindowbygroupid(group_id, message) to Perl.
- Add quest::crosszonedialoguewindowbyraidid(raid_id, message) to Perl.
- Add quest::crosszonedialoguewindowbyguildid(guild_id, message) to Perl.
- Add quest::crosszonedialoguewindowbyexpeditionid(expedition_id, message) to Perl.
- Add quest::crosszonedialoguewindowbyclientname(client_name, message) to Perl.
- Add quest::worldwidedialoguewindow(message, min_status, max_status) to Perl.
- Add eq.cross_zone_dialogue_window_by_char_id(character_id, message) to Lua.
- Add eq.cross_zone_dialogue_window_by_group_id(group_id, message) to Lua.
- Add eq.cross_zone_dialogue_window_by_raid_id(raid_id, message) to Lua.
- Add eq.cross_zone_dialogue_window_by_guild_id(guild_id, message) to Lua.
- Add eq.cross_zone_dialogue_window_by_expedition_id(expedition_id, message) to Lua.
- Add eq.cross_zone_dialogue_window_by_client_name(client_name, message) to Lua.
- Add eq.world_wide_dialogue_window(message, min_status, max_status) to Lua.

* Use string instead.
2021-10-11 16:33:18 -04:00
hg 9887580f9a Make columns in doors table not nullable (#1597)
This makes the float and integer fields in the doors table not nullable.
The only column this should affect is the buffer column which wasn't
being loaded in the old doors loading query. The other columns weren't
validated but they should still be made not nullable to avoid issues.

This will fix a crash in potimeb which is the only zone that had NULL
values in the buffer column with the current peq database. This column
can be removed in a future followup since it isn't being used anyway.
2021-10-09 13:45:38 -04:00
KayenEQ b7c62b5242 Merge pull request #1592 from KayenEQ/updateSPA157SpellDS
[Spells] Update to SPA 157 Spell Damage Shield
2021-10-09 12:05:15 -04:00
KayenEQ 89a40272c6 Merge pull request #1588 from KayenEQ/spa154and209updates
[Spells] Update to SPA 154 and SPA 209 Dispel Bene/Detrimental
2021-10-09 00:57:42 -04:00
Chris Miles db369c98c8 [HP Updates] Fix for Titanium clients not being updated properly by removing client version check (#1596) 2021-10-08 21:04:19 -07:00
KayenEQ 10ba5d6046 Merge pull request #1595 from KayenEQ/instanthealbug1
[Spells] Hotfix for healing code error from recent commit.
2021-10-08 18:54:54 -04:00
KayenEQ dd1a869531 hotfix 2021-10-08 18:43:47 -04:00
KayenEQ a9e23cf83a Merge pull request #1594 from KayenEQ/fixExtraSpellAmt
[Spells] Minor fix to Item Extra Spell Damage Amt formula
2021-10-08 18:00:46 -04:00
KayenEQ 783c12590e minor fix
was not correct, was comparing negative to a positive
2021-10-08 13:14:39 -04:00
Kinglykrab 6689b57a52 [Commands] Convert item ID search to use saylinks similar to name search. (#1589) 2021-10-08 05:41:37 -04:00
Paul Coene 7029c699a0 Merge pull request #1591 from noudess/aggro
[Bug Fix] always_aggro flag needed to be checked on assist
2021-10-07 16:25:51 -04:00
KayenEQ 3b9574af14 fix 2021-10-05 16:59:07 -04:00
Noudess 740f84dc22 always_aggro flag needed to be checked on assist 2021-10-05 15:51:22 -04:00
KayenEQ 55d45f9a98 updates 2021-10-05 15:50:26 -04:00
Cole-SoD 61d1eeab6f Minor corrections (#1582) 2021-10-04 17:26:02 -04:00
Kinglykrab 133c1e866c [Bug Fix] Send appearance wasn't setting size properly when changing races. (#1586) 2021-10-04 17:25:51 -04:00
Kinglykrab b730461894 [Bug Fix] Trim output in hidden dialogue response. (#1587) 2021-10-04 17:25:21 -04:00
KayenEQ 8b08e22dbc removed unused function 2021-10-04 14:33:20 -04:00
KayenEQ fc7c99fb0a Update spdat.h 2021-10-04 11:14:56 -04:00
KayenEQ f1d267bb2d Update spell_effects.cpp 2021-10-04 08:31:52 -04:00
Kinglykrab 07664eedc0 [Bug Fix] Trim trailing whitespace off output in Popup. (#1584) 2021-10-03 14:51:12 -04:00
hg 64b8d7c874 Remove unnecessary includes (#1585)
The include order here was causing a compile error when building with
perl 5.12 due to a bad interaction with the older fmt submodule version
being used
2021-10-03 13:25:49 -04:00
Kinglykrab ccab07bd66 [Dialogue] Add hidden response support. (#1583)
Allows operators to hide responses.
Syntax is `hiddenresponse`.
2021-10-03 13:06:39 -04:00
Kinglykrab 3a76d9a28e [Bug Fix] Dialogue Window Name replace. (#1581)
{name} was being replaced with the string "$name" because Perl would parse it properly, but when used here it doesn't return the client's name.
2021-10-03 13:06:31 -04:00
Kinglykrab 5720a5020d [Quest API] Add attuned/augment support to client->SummonBaggedItems() in Perl/Lua. (#1580)
Perl Example:
```pl
my @bag_items = (
      { item_id => 33649, charges => 1, attuned => 1, augment_one => 32940 }
    );
```

Lua Example:
```lua
local bag_items = {
	{ item_id = 33649, charges = 1, attuned = 1, augment_one = 32940 }
}
2021-10-02 19:35:35 -04:00
Kinglykrab b3e9e2099a [Quest API] Add GetIPExemption(), GetIPString(), and SetIPExemption(exemption_amount) to Perl/Lua.
- Add $client->GetIPExemption() to Perl.
- Add $client->GetIPString() to Perl.
- Add $client->SetIPExemption(exemption_amount) to Perl.
- Add client:GetIPExemption() to Lua.
- Add client:GetIPString() to Lua.
- Add client:SetIPExemption(exemption_amount) to Lua.

Will make plugin::IP unnecessary and allow people to get readable IP string easier, as well as set/get IP exemptions from Perl and Lua.
2021-10-02 13:39:32 -04:00
Kinglykrab 93acf50bb4 [Quest API] Add client->ReadBookByName(book_name, book_type) to Perl/Lua.
- Add $client->ReadBookByName(booK_name, book_type) to Perl.
- Add client:ReadBookByName(booK_name, book_type) to Lua.
- Allows server operators to put books in to their database and read from their database instead of storing the values in a script, also allows them to read pre-existing books using a script.
2021-10-02 13:09:30 -04:00
Kinglykrab ff46a854f9 [Quest API] Add LavaDamage and MinLavaDamage to UpdateZoneHeader in Perl/Lua. (#1578)
Allows operators to modify lava damage dynamically.
2021-10-02 12:01:54 -04:00
Kinglykrab 8c5f26ca5e [Quest API] Add IsNPCSpawned(npc_ids) and CountSpawnedNPCs(npc_ids) to Perl/Lua. (#1570)
- Add quest::isnpcspawned(npc_ids) to Perl.
- Add quest::countspawnednpcs(npc_ids) to Perl.
- Add eq.is_npc_spawned(npc_ids) to Lua.
- Add eq.count_spawned_npcs(npc_ids) to Lua.
2021-10-02 12:01:39 -04:00
hg 5560b198ca [Quest API] Add client->SummonBaggedItems(bag_item_id, bag_items_ref) to Perl/Lua.
Alternative apis using arrays of hash items for EQEmu/Server#1575

Perl usage:
```pl
    # create as an array, pass as reference
    my @bag_items = (
      { item_id => 1001, charges => 1 },
      { item_id => 1002, charges => 1 },
      { item_id => 10037, charges => 10 },
    );
    $client->SummonBaggedItems(17403, \@bag_items);

    # create directly as an array reference
    my $bag_items = [
      { item_id => 1001, charges => 1 },
      { item_id => 1002, charges => 1 },
      { item_id => 10037, charges => 10 },
    ];
    $client->SummonBaggedItems(17403, $bag_items); ```

Lua Usage:
```lua
    local bag_items = {
      { item_id = 1001, charges = 1 },
      { item_id = 1002, charges = 1 },
      { item_id = 10037, charges = 10 }
    }
    e.other:SummonBaggedItems(17403, bag_items);
2021-10-02 12:00:00 -04:00
Chris Miles 9a413cf553 [Shared Tasks] Task Kill Update Fix (#1573)
* Revert "Revert "Shared task kill update fix""

This reverts commit 859751f74d.

* Swap return for continue in this context

* Slight tweak

* Slight tweak

* Remove no longer needed task methods

* Update scope for IncrementDoneCount

* Create helper method Client::GetPartyMembers() and add client->HasTaskState()

* Move HandleUpdateTasksOnKill responsibility to TaskManager

* Remove unnecessary pointer
2021-10-01 20:57:00 -07:00
Kinglykrab bb5c491794 [Dialogue] Add support for Dialogue Window titles. (#1563)
* [Dialogue] Add support for Dialogue Window titles.
- Custom title allows defaults to be overridden where necessary, like a leaderboard or something.
- Default target to client in case people want to send Dialogue Windows from current client.

* Fix possible issue with markdown.
- Example: Using the word "title" or using any identifier and forgetting the colon.
2021-10-01 22:20:15 -05:00
Kinglykrab 2f5d360e53 [Quest API] Add UntrainDiscBySpellID(spell_id, update_client) to Perl/Lua. (#1565)
- Add $client->UntrainDiscBySpellID(spell_id, update_client) to Perl.
- Add client:UntrainDiscBySpellID(spell_id, update_client) to Lua.
2021-10-01 22:14:56 -05:00
hg 92e03dccb9 [Quest API] Add perl hash apis for dz creation (#1571)
Add hash overload to perl CreateExpedition api

  This adds an api to perl similar to the Lua api that accepts a reference
  to a hash table with expedition creation info

  Usage example:
    my $expedition_info = {
      expedition => { name => "Perl expedition", min_players => 2, max_players => 6 },
      instance   => { zone => "crushbone", version => 0, duration => 3600 },
      compass    => { zone => "gfaydark", x => 238, y => 987, z => -24.90 },
      safereturn => { zone => "gfaydark", x => 245.84, y => 987.93, z => -27.6, h => 484.0 },
      zonein     => { x => 479.44, y => -500.18, z => 5.75, h => 421.8 }
    };

    $client->CreateExpedition($expedition_info);

  Syntax for passing directly from a hash:
    my %expedition_info = (...);
    $client->CreateExpedition(\%expedition_info);

Add CreateTaskDynamicZone api to perl

  Usage example:
    sub EVENT_TASKACCEPTED {
      if ($task_id == 4795) {
        my %dz_hash = (
          "instance",   { zone=>"thundercrest", version => 11 },
          "compass",    { zone=>"broodlands", x=>1241.88, y=>511.147, z=>23.4192 },
          "safereturn", { zone=>"broodlands", x=>1242.0, y=>526.0, z=>27.0, h=>0.0 }
        );
        $client->CreateTaskDynamicZone($task_id, \%dz_hash)
      }
    }
2021-10-01 22:12:45 -05:00
hg 5ffe6284ca [Shared Tasks] Start solo task replay timers from completion time (#1568)
Shared tasks start replay timers based on accept time but solo tasks
should start from completion time. Solo tasks on live that have a
non-unlimited duration may require further investigation
2021-10-01 22:11:57 -05:00
hg fb98349bbd [Quest API] Add mob SetPet and RemovePet quest apis (#1569)
Will be required for tutoriala script and other similar events
2021-10-01 22:11:16 -05:00
hg 00a22ca12e [Repositories] Use repositories to load doors (#1572)
Remove Door struct that was being used to map db columns
2021-10-01 22:09:40 -05:00
Chris Miles 3883adcefc [Dialogue Window / Saylinks] Missing Changes (#1574)
* Implement auto saylink injection

* Cover Lua say since it takes a different code path

* [Dialogue] Dialogue Window Middleware (#1526)

* Dialogue window quest dialogue work

* Add rest of DialogueWindow hooks

* Remove spacing
2021-10-01 22:09:21 -05:00
Kinglykrab 0762ffa3dc [Quest API] Typo in Perl $entity_lsit->IsMobSpawnedByNpcTypeID(). (#1576)
This causes the wrong name to show up on Spire.
2021-10-01 21:19:26 -04:00
KayenEQ b70dc64d96 Update spell_effects.cpp 2021-10-01 20:36:54 -04:00
Akkadius 859751f74d Revert "Shared task kill update fix"
This reverts commit 91c451b6c5.
2021-10-01 18:42:36 -05:00
Akkadius 91c451b6c5 Shared task kill update fix 2021-10-01 18:42:02 -05:00
KayenEQ 30c7ed7e45 Merge pull request #1557 from KayenEQ/spa395fix2
[Spells] Healing focuses effects update and Fix for SPA 395
2021-10-01 15:52:25 -04:00
KayenEQ 509b6f2056 Merge pull request #1558 from KayenEQ/spa382update2
[Spells] More updates for SPA 382 SE_NegateSpellEffect
2021-10-01 15:51:32 -04:00
KayenEQ 558bebe710 updates 2021-10-01 15:50:26 -04:00
KayenEQ 08a85c5dae Merge remote-tracking branch 'upstream/master' into spa395fix2 2021-10-01 14:28:45 -04:00
KayenEQ d22f9ee294 Merge remote-tracking branch 'upstream/master' into spa382update2 2021-10-01 14:26:43 -04:00
Cole-SoD 0aeaf7c3b7 [Zone] Add LavaDamage and MinLavaDamage support to ZoneHeader (#1540)
* Add LavaDamage and MinLavaDamage support to ZoneHeader

* Add lava_damage and min_lava_damage to base_zone_repository.h

* Update version.h and utils/sql/git/required/ file

* Correct SQL Query, adjust utils/sql/db_update_manifest.txt to check one column

* Correct manifest
https://github.com/EQEmu/Server/pull/1540#discussion_r714330945
2021-09-30 11:44:22 -05:00
KayenEQ c04bcef273 Update spells.cpp (#1554) 2021-09-30 11:43:36 -05:00
KayenEQ 7fcea371c2 [Spells] Updated Memory Blur SPA 63 - Implemented Live Mechanics (#1559)
* memory blur updated

* Update spdat.h
2021-09-30 11:43:05 -05:00
Natedog2012 dd765238f7 Merge pull request #1553 from Natedog2012/tradeskill_fix
[Tradeskill] Fix logic in taught tradeskill recipes
2021-09-29 19:05:41 -05:00
Paul Coene 2c98a11696 Merge pull request #1561 from noudess/timesync
[Bug Fix] Zones no longer syncing time to world
2021-09-29 16:57:30 -04:00
Noudess d4f14efaa0 Fix TimeSync to work with new Servertalk connection order 2021-09-27 10:04:02 -04:00
KayenEQ 27787c247b Update spell_effects.cpp 2021-09-23 18:01:08 -04:00
KayenEQ ea9c07aa98 393 NegateEffect updates 2021-09-23 16:43:07 -04:00
KayenEQ 5cd9bfeb70 reminder
bot code needs to updated, then old function can be removed
2021-09-23 14:23:17 -04:00
KayenEQ b699196299 Update effects.cpp 2021-09-23 14:14:46 -04:00
KayenEQ e89c2aec4a Update bot.cpp 2021-09-23 13:48:15 -04:00
KayenEQ 456fb56e82 revert for bots 2021-09-23 13:42:36 -04:00
KayenEQ 03ac828134 Update bot.cpp 2021-09-23 12:28:34 -04:00
KayenEQ 34b2264d5d bots... 2021-09-23 12:21:53 -04:00
KayenEQ 933ede40f9 Update bot.cpp 2021-09-23 12:13:29 -04:00
KayenEQ 881dc33c9b update 2021-09-23 12:00:16 -04:00
KayenEQ 3faa0d2603 update 2021-09-23 11:41:36 -04:00
KayenEQ 1ce5087e2a Update effects.cpp 2021-09-23 09:35:09 -04:00
Natedog2012 bf8d94eb35 Fix SendTradeskillSearchResults row count was incorrect format. Remove extra database hits from last commit. 2021-09-22 21:43:49 -05:00
Natedog2012 9aac12f517 Hide tradeskill recipes that require being learned before crafting them, as well as fix how learned recipes are checked. 2021-09-22 18:21:57 -05:00
Kinglykrab 7b969173f4 [Door Manipulation] Resolve some typos and add a GM check. (#1550)
* [Door Manipulation] Resolve some typos and add a status check.

* Remove Status check and use GetGM() inside devtools check instead.
2021-09-22 16:43:01 -05:00
Kinglykrab ca77d22035 [Bug Fix] GetSpellStat() Identifiers were comparing improperly. (#1552)
- GetSpellStat() converts identifiers to lowercase and they were being checked against mixed case strings, causing certain identifiers to always fail.
2021-09-21 21:08:16 -04:00
Paul Coene ad3bf35397 Merge pull request #1548 from noudess/master
[Bug Fix] Fix bug where IVU could not be cast on char with Invis
2021-09-21 12:21:18 -04:00
Noudess 9b06221be0 [Bug Fix] Fix bug where IVU could not be cast on char with Invis 2021-09-20 11:30:33 -04:00
Kinglykrab c0de178173 [Commands] Overhauled #npcedit. (#1538)
* [Commands] Overhauled #npcedit.
- Added missing columns like untargetable, show_name, exp_mod, etc.
- Put stats in order of column appearance in table within help message and within code.
- Converted StringFormat to fmt::format.
- Added a GetGenderName() helper method.
- Prettified response messages of nearly every #npcedit option.

All tested and ready to go.

Would like input about possibly changing some of the command arguments to match the table column names more closely, example being "spell" should be "npc_spells_id".

* Cleanup.

* Fix indentation.
2021-09-19 16:32:21 -07:00
Kinglykrab 6a5face0aa [Dialogue] Add support for Dialogue Window buttons. (#1546)
* [Dialogue] Add support for Dialogue Window buttons.
- Also changes "mysterious" identifier to "{mysterious}".
- Both button names are required for anything to show up, otherwise it defaults to Yes/No similar to Client::SendFullPopup.

* Move SetEntityVariable so responses can override default button response.

* Add negativeid support so you can override button two popup ID.

* Fix log.

* Update dialogue_window.cpp

Convert button names to strings and negativeid to secondrespondid.
2021-09-19 16:24:04 -07:00
Kinglykrab c15c54e920 [Quest API] Cross zone and world wide method overhaul. (#1520)
* [Quest API] Cross zone and world wide method overhaul.
- Adds support for Character ID, Character Name, and Expedition ID to all cross zone methods that did not have a method.
- Adds worldwide LDoN Updates.
- Shrinks the number of packets and structs from 83 to 17.

No quest functionality will be affected by this, as the only changes are the underlying method used to send the cross zone and world wide data.

* Formatting, organization, and fixing of improper exports.

* Finalize comb through of variable types, update types, etc.

* Merge fixes.
2021-09-19 16:15:14 -07:00
Chris Miles 24c079dca4 [Hotfix] Fix freeze formatting for Quest API parsing (Spire) (#1547) 2021-09-19 15:25:52 -05:00
Kinglykrab 8eef7bb283 [Quest API] Add EVENT_COMBINE to Perl and Lua. (#1536)
- Exports $container_slot in Perl.
- Exports e.container_slot in Lua.

Allows you to perform events when clicking combine in a tradeskill container.
2021-09-19 15:22:51 -05:00
Michael Cook (mackal) 80493719f2 [Summoning] Make Summon a bit more live like (#1539)
Pretty sure the distance should probably be melee range / 2 but ahh
yeah. Can't do that. Hopefully 5 units isn't too far.
2021-09-19 15:19:29 -05:00
KayenEQ df9d6bc506 [Spells] Corrected implementation of SE_Purify 291 (#1541)
* Correct implementation of spa291

* debug removal
2021-09-19 15:17:10 -05:00
KayenEQ 71870cbd1c [Spells] Update to SPA 442 and 443 (SE_TriggerOnReqTarget, SE_TriggerOnReqCaster) (#1543)
* Update to SPA 442 and 443

Use SpellRestriction Id's and updated PassCastRestriction code

* Update mob.cpp
2021-09-19 15:16:56 -05:00
Kinglykrab f715ccd368 [Bug Fix] Fixes EVENT_DISCONNECT for /quit and /exit. (#1542)
/quit and /exit will now properly parse to EVENT_DISCONNECT so operators can do things on disconnect to these players, previously it only functioned for /camp.
2021-09-19 15:16:38 -05:00
KayenEQ 46edd56acc [Spells] Update SPA 101 SE_CompleteHeal (#1544)
Fixed buff stacking issue
2021-09-19 15:16:21 -05:00
KayenEQ 442850aebb [Spells] Update to SPA305 (#1545)
minor fix to allow for effects with negative values.
2021-09-19 15:16:02 -05:00
KayenEQ d4e752987e fixes 2021-09-17 23:21:03 -04:00
KayenEQ 9c6a85ff16 heal code updates 2021-09-17 22:27:45 -04:00
Kinglykrab fa8d8eccc2 [Quest API] Add corpse->RemoveItemByID(item_id, quantity) to Perl and Lua. (#1535)
* [Quest API] Add corpse->RemoveItemByID(item_id, quantity) to Perl and Lua.
- Add $corpse->RemoveItemByID(item_id, quantity) to Perl.
- Add corpse:RemoveItemByID(item_id, quantity) to Lua.

* Formatting.
2021-09-13 15:42:04 -04:00
Kinglykrab 6e76f89ca2 [Quest API] Add EVENT_CONSIDER to Perl and Lua. (#1531)
* [Quest API] Add EVENT_CONSIDER to Perl and Lua.
- Exports $entity_id in Perl.
- Exports e.entity_id in Lua.

Allows you to perform events on consider for server operators.

* Missing comma.

* Formatting.

* Add return capability to EVENT_CONSIDER and EVENT_CONSIDER_CORPSE so operators can break out of consider functions.
2021-09-13 15:30:17 -04:00
Akkadius 9589bf6bf8 [Hotfix] Crash fix that apparently didn't make it in another PR 2021-09-13 14:15:08 -05:00
Kinglykrab ce5fa9502f [Commands] Adds #dye command. (#1537)
* [Commands] Adds #dye command.

* Fix use tint.
2021-09-12 22:40:43 -05:00
Kinglykrab 7b1b05a35c [Bug Fix] Resolves issues with improper genders and textures on spells. (#1533)
* [Bug Fix] Resolves issues with improper genders and textures on spells.
Spells will now properly understand their expected gender and texture.
Logic is based on what I saw in a stock PEQ database, can be adjusted if need be.
Any feedback is helpful.

* Made use of GetRaceGenderDefaultHeight() and added all races to their proper conditions.

* Formatting.
2021-09-12 22:40:07 -05:00
Kinglykrab 38a86edc70 [Quest API] Add EVENT_CONSIDER_CORPSE to Perl and Lua. (#1530)
- Exports $corpse_entity_id in Perl.
- Exports e.corpse_entity_id in Lua.

Allows you to perform events on corpse consider for server operators.
2021-09-12 22:39:09 -05:00
Kinglykrab 56b9b6f2c4 [Quest API] Add corpse->GetLootList() and npc->GetLootList() to Perl and Lua. (#1529)
* [Quest API] Add corpse->GetLootList() and npc->GetLootList() to Perl and Lua.
- Add $corpse->GetLootList() to Perl.
- Add $npc->GetLootList() to Perl.
- Add corpse:GetLootList() to Lua.
- Add npc:GetLootList() to Lua.

Returns an array of item IDs for use with corpse and NPC methods such as HasItem(item_id), CountItem(item_id), and GetFirstSlotByItemID(item_id).

* Categories.

* Modify Lua to use classes.
2021-09-12 22:38:38 -05:00
Chris 97dcba70cf [Bots] Fix for Bot Pets Taunting (#1519)
Currently bot pets will taunt and there's no way to turn it off. This makes it so pets follow their owner's taunt settings.
2021-09-12 22:37:39 -05:00
Chris Miles 6b93130c13 [Saylinks] Implement Auto Saylink Injection (#1525)
* Implement auto saylink injection

* Cover Lua say since it takes a different code path
2021-09-12 22:08:30 -05:00
Chris Miles 94c1a50cc8 [GM Command] Door Manipulation Command Port (#1524)
* Initial commit

* Push latest

* Update door_manipulation.cpp

* More door work

* More doors work

* Upload notes

* Finalize changes

* Remove comment

* Add missing chat line

* Swapped URI parser with something not using deprecated C++ functions
2021-09-12 22:08:04 -05:00
Kinglykrab 31ab1d4287 Merge pull request #1522 from EQEmu/feature/temp_merchant_list_bug_fix
[Bug Fix] Resolves issue where loading temporary merchant list "fails" because there aren't any to load.
2021-09-11 10:35:39 -04:00
Paul Coene b6ba493450 Merge pull request #1528 from noudess/merchant
Fix bug where stacks of non-stackable items are removed when you buy 1.
2021-09-11 10:19:37 -04:00
Paul Coene c613db2338 Merge pull request #1527 from noudess/toofar
Hack to fix melee chasing fleeing mobs "too far" issues.
2021-09-10 18:21:38 -04:00
Noudess 05ac8499df Fix bug where stacks of non-stackable items are removed when you buy 1. 2021-09-10 10:18:59 -04:00
Chris Miles 69244a094d Update changelog.txt 2021-09-09 09:52:26 -05:00
Noudess 1155673642 Hack to fix melee chasing fleeing mobs "too far" issues. 2021-09-09 08:42:14 -04:00
Kinglykrab 930079959c [Bug Fix] Resolves issue where loading temporary merchant list "fails" because there aren't any to load. 2021-09-06 20:37:34 -04:00
578 changed files with 56116 additions and 34478 deletions
+2
View File
@@ -54,3 +54,5 @@ bin/
/Win32
/x64
/client_files/**/CMakeFiles/
.idea
+3
View File
@@ -224,6 +224,9 @@ IF(OpenSSL_FOUND AND MBEDTLS_FOUND)
SET(TLS_LIBRARY_LIBS ${OPENSSL_LIBRARIES})
SET(TLS_LIBRARY_INCLUDE ${OPENSSL_INCLUDE_DIR})
ADD_DEFINITIONS(-DEQEMU_USE_OPENSSL)
IF(${OPENSSL_VERSION} VERSION_GREATER_EQUAL "1.1.1")
ADD_DEFINITIONS(-DCPPHTTPLIB_OPENSSL_SUPPORT)
ENDIF()
ELSEIF(TLS_LIBRARY_SELECTION STREQUAL "mbedTLS")
SET(TLS_LIBRARY_TYPE " mbedTLS")
SET(TLS_LIBRARY_ENABLED ON)
+4 -4
View File
@@ -18,16 +18,16 @@
|**Install Count**|![Windows Install Count](http://analytics.akkadius.com/?install_count&windows_count)|![Linux Install Count](http://analytics.akkadius.com/?install_count&linux_count)|
### > Windows
* [Install Guide](https://eqemu.gitbook.io/server/categories/installation/server-installation-windows)
* [Install Guide](https://docs.eqemu.io/server/installation/server-installation-windows/)
### > Debian/Ubuntu/CentOS/Fedora
* [Install Guide](https://eqemu.gitbook.io/server/categories/installation/server-installation-linux)
* [Install Guide](https://docs.eqemu.io/server/installation/server-installation-linux/)
* You can use curl or wget to kick off the installer (whichever your OS has)
> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
## Supported Clients
@@ -56,7 +56,7 @@ forum, although pull requests will be much quicker and easier on all parties.
## Resources
- [EQEmulator Forums](http://www.eqemulator.org/forums)
- [EQEmulator Wiki](https://eqemu.gitbook.io/)
- [EQEmulator Wiki](https://docs.eqemu.io/)
## Related Repositories
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)
+1 -1
View File
@@ -3,7 +3,7 @@
############################################
#
# New changelog can be found here
# https://eqemu.gitbook.io/changelog/
# https://docs.eqemu.io/server/changelog/server
#
############################################
# Deprecated
+3 -1
View File
@@ -526,6 +526,7 @@ SET(common_headers
guild_base.h
guilds.h
http/httplib.h
http/uri.h
inventory_profile.h
inventory_slot.h
ipc_mutex.h
@@ -638,7 +639,8 @@ SET(common_headers
StackWalker/StackWalker.h
util/memory_stream.h
util/directory.h
util/uuid.h)
util/uuid.h
)
SOURCE_GROUP(Event FILES
event/event_loop.h
+93 -17
View File
@@ -35,8 +35,12 @@ int WorldContentService::GetCurrentExpansion() const
return current_expansion;
}
void WorldContentService::SetExpansionContext()
WorldContentService *WorldContentService::SetExpansionContext()
{
// do a rule manager reload until where we store expansion is changed to somewhere else
RuleManager::Instance()->LoadRules(GetDatabase(), "default", true);
// pull expansion from rules
int expansion = RuleI(Expansion, CurrentExpansion);
if (expansion >= Expansion::Classic && expansion <= Expansion::MaxId) {
content_service.SetCurrentExpansion(expansion);
@@ -47,6 +51,8 @@ void WorldContentService::SetExpansionContext()
GetCurrentExpansion(),
GetCurrentExpansionName()
);
return this;
}
std::string WorldContentService::GetCurrentExpansionName()
@@ -73,15 +79,47 @@ void WorldContentService::SetCurrentExpansion(int current_expansion)
/**
* @return
*/
const std::vector<std::string> &WorldContentService::GetContentFlags() const
const std::vector<ContentFlagsRepository::ContentFlags> &WorldContentService::GetContentFlags() const
{
return content_flags;
}
/**
* @return
*/
std::vector<std::string> WorldContentService::GetContentFlagsEnabled()
{
std::vector<std::string> enabled_flags;
for (auto &f: GetContentFlags()) {
if (f.enabled) {
enabled_flags.emplace_back(f.flag_name);
}
}
return enabled_flags;
}
/**
* @return
*/
std::vector<std::string> WorldContentService::GetContentFlagsDisabled()
{
std::vector<std::string> disabled_flags;
for (auto &f: GetContentFlags()) {
if (!f.enabled) {
disabled_flags.emplace_back(f.flag_name);
}
}
return disabled_flags;
}
/**
* @param content_flags
*/
void WorldContentService::SetContentFlags(std::vector<std::string> content_flags)
void WorldContentService::SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags)
{
WorldContentService::content_flags = content_flags;
}
@@ -90,10 +128,10 @@ void WorldContentService::SetContentFlags(std::vector<std::string> content_flags
* @param content_flag
* @return
*/
bool WorldContentService::IsContentFlagEnabled(const std::string& content_flag)
bool WorldContentService::IsContentFlagEnabled(const std::string &content_flag)
{
for (auto &flag : GetContentFlags()) {
if (flag == content_flag) {
for (auto &f: GetContentFlags()) {
if (f.flag_name == content_flag && f.enabled == true) {
return true;
}
}
@@ -101,20 +139,58 @@ bool WorldContentService::IsContentFlagEnabled(const std::string& content_flag)
return false;
}
void WorldContentService::ReloadContentFlags(Database &db)
void WorldContentService::ReloadContentFlags()
{
std::vector<std::string> set_content_flags;
auto content_flags = ContentFlagsRepository::GetWhere(db, "enabled = 1");
std::vector<ContentFlagsRepository::ContentFlags> set_content_flags;
auto flags = ContentFlagsRepository::All(*GetDatabase());
set_content_flags.reserve(content_flags.size());
for (auto &flags: content_flags) {
set_content_flags.push_back(flags.flag_name);
set_content_flags.reserve(flags.size());
for (auto &f: flags) {
set_content_flags.push_back(f);
LogInfo(
"Loaded content flag [{}] [{}]",
f.flag_name,
(f.enabled ? "Enabled" : "Disabled")
);
}
LogInfo(
"Enabled content flags [{}]",
implode(", ", set_content_flags)
);
SetContentFlags(set_content_flags);
}
Database *WorldContentService::GetDatabase() const
{
return m_database;
}
WorldContentService *WorldContentService::SetDatabase(Database *database)
{
WorldContentService::m_database = database;
return this;
}
void WorldContentService::SetContentFlag(const std::string &content_flag_name, bool enabled)
{
auto flags = ContentFlagsRepository::GetWhere(
*GetDatabase(),
fmt::format("flag_name = '{}'", content_flag_name)
);
auto f = ContentFlagsRepository::NewEntity();
if (!flags.empty()) {
f = flags.front();
}
f.enabled = enabled ? 1 : 0;
f.flag_name = content_flag_name;
if (!flags.empty()) {
ContentFlagsRepository::UpdateOne(*GetDatabase(), f);
}
else {
ContentFlagsRepository::InsertOne(*GetDatabase(), f);
}
ReloadContentFlags();
}
+18 -7
View File
@@ -23,6 +23,7 @@
#include <string>
#include <vector>
#include "../repositories/content_flags_repository.h"
class Database;
@@ -160,15 +161,25 @@ public:
bool IsCurrentExpansionTheBurningLands() { return current_expansion == Expansion::ExpansionNumber::TheBurningLands; }
bool IsCurrentExpansionTormentOfVelious() { return current_expansion == Expansion::ExpansionNumber::TormentOfVelious; }
const std::vector<ContentFlagsRepository::ContentFlags> &GetContentFlags() const;
std::vector<std::string> GetContentFlagsEnabled();
std::vector<std::string> GetContentFlagsDisabled();
bool IsContentFlagEnabled(const std::string& content_flag);
void SetContentFlags(std::vector<ContentFlagsRepository::ContentFlags> content_flags);
void ReloadContentFlags();
WorldContentService * SetExpansionContext();
WorldContentService * SetDatabase(Database *database);
Database *GetDatabase() const;
void SetContentFlag(const std::string &content_flag_name, bool enabled);
private:
int current_expansion{};
std::vector<std::string> content_flags;
public:
const std::vector<std::string> &GetContentFlags() const;
bool IsContentFlagEnabled(const std::string& content_flag);
void SetContentFlags(std::vector<std::string> content_flags);
void ReloadContentFlags(Database &db);
void SetExpansionContext();
std::vector<ContentFlagsRepository::ContentFlags> content_flags;
// reference to database
Database *m_database;
};
extern WorldContentService content_service;
+126 -28
View File
@@ -39,6 +39,7 @@
#include "unix.h"
#include <netinet/in.h>
#include <sys/time.h>
#endif
#include "database.h"
@@ -46,6 +47,8 @@
#include "extprofile.h"
#include "string_util.h"
#include "database_schema.h"
#include "http/httplib.h"
#include "http/uri.h"
extern Client client;
@@ -713,7 +716,7 @@ bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, Playe
/* HoTT Ability */
if(RuleB(Character, GrantHoTTOnCreate))
{
query = StringFormat("INSERT INTO `character_leadership_abilities` (id, slot, rank) VALUES (%u, %i, %i)", character_id, 14, 1);
query = StringFormat("INSERT INTO `character_leadership_abilities` (id, slot, `rank`) VALUES (%u, %i, %i)", character_id, 14, 1);
results = QueryDatabase(query);
}
@@ -2039,62 +2042,64 @@ void Database::ClearRaidLeader(uint32 gid, uint32 rid)
QueryDatabase(query);
}
void Database::UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win)
void Database::UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win, bool remove)
{
std::string field;
switch(theme)
{
case 1:
{
switch(theme) {
case LDoNThemes::GUK: {
field = "guk_";
break;
}
case 2:
{
case LDoNThemes::MIR: {
field = "mir_";
break;
}
case 3:
{
case LDoNThemes::MMC: {
field = "mmc_";
break;
}
case 4:
{
case LDoNThemes::RUJ: {
field = "ruj_";
break;
}
case 5:
{
case LDoNThemes::TAK: {
field = "tak_";
break;
}
default:
{
default: {
return;
}
}
if (win)
field += "wins";
else
field += "losses";
field += win ? "wins" : "losses";
std::string field_operation = remove ? "-" : "+";
std::string query = StringFormat("UPDATE `adventure_stats` SET %s=%s+1 WHERE player_id=%u",field.c_str(), field.c_str(), char_id);
std::string query = fmt::format(
"UPDATE `adventure_stats` SET {} = {} {} 1 WHERE player_id = {}",
field,
field,
field_operation,
char_id
);
auto results = QueryDatabase(query);
if (results.RowsAffected() != 0)
if (results.RowsAffected() != 0) {
return;
}
query = StringFormat("INSERT INTO `adventure_stats` SET %s=1, player_id=%u", field.c_str(), char_id);
QueryDatabase(query);
if (!remove) {
query = fmt::format(
"INSERT INTO `adventure_stats` SET {} = 1, player_id = {}",
field,
char_id
);
QueryDatabase(query);
}
}
bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
{
std::string query = StringFormat(
std::string query = fmt::format(
"SELECT "
"`guk_wins`, "
"`mir_wins`, "
@@ -2109,7 +2114,7 @@ bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
"FROM "
"`adventure_stats` "
"WHERE "
"player_id = %u ",
"player_id = {}",
char_id
);
auto results = QueryDatabase(query);
@@ -2268,6 +2273,35 @@ int Database::GetIPExemption(std::string account_ip) {
return RuleI(World, MaxClientsPerIP);
}
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
std::string query = fmt::format(
"SELECT `exemption_id` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'",
account_ip
);
auto results = QueryDatabase(query);
uint32 exemption_id = 0;
if (results.Success() && results.RowCount() > 0) {
auto row = results.begin();
exemption_id = atoi(row[0]);
}
query = fmt::format(
"INSERT INTO `ip_exemptions` (`exemption_ip`, `exemption_amount`) VALUES ('{}', {})",
account_ip,
exemption_amount
);
if (exemption_id != 0) {
query = fmt::format(
"UPDATE `ip_exemptions` SET `exemption_amount` = {} WHERE `exemption_ip` = '{}'",
exemption_amount,
account_ip
);
}
QueryDatabase(query);
}
int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
std::string query = StringFormat("SELECT instance_list.id FROM instance_list INNER JOIN instance_list_player ON instance_list.id = instance_list_player.id WHERE instance_list.zone = '%i' AND instance_list_player.charid = '%i'", zone_id, char_id);
auto results = QueryDatabase(query);
@@ -2418,3 +2452,67 @@ bool Database::CopyCharacter(
return true;
}
void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string url)
{
try {
uri request_uri(url);
LogHTTP(
"[SourceDatabaseTableFromUrl] parsing url [{}] path [{}] host [{}] query_string [{}] protocol [{}] port [{}]",
url,
request_uri.get_path(),
request_uri.get_host(),
request_uri.get_query(),
request_uri.get_scheme(),
request_uri.get_port()
);
if (!DoesTableExist(table_name)) {
LogMySQLQuery("Table [{}] does not exist. Downloading from Github and installing...", table_name);
// http get request
httplib::Client cli(
fmt::format(
"{}://{}",
request_uri.get_scheme(),
request_uri.get_host()
).c_str()
);
cli.set_connection_timeout(0, 60000000); // 60 sec
cli.set_read_timeout(60, 0); // 60 seconds
cli.set_write_timeout(60, 0); // 60 seconds
int sourced_queries = 0;
if (auto res = cli.Get(request_uri.get_path().c_str())) {
if (res->status == 200) {
for (auto &s: SplitString(res->body, ';')) {
if (!trim(s).empty()) {
auto results = QueryDatabase(s);
if (!results.ErrorMessage().empty()) {
LogError("Error sourcing SQL [{}]", results.ErrorMessage());
return;
}
sourced_queries++;
}
}
}
}
else {
LogError("Error retrieving URL [{}]", url);
}
LogMySQLQuery(
"Table [{}] installed. Sourced [{}] queries",
table_name,
sourced_queries
);
}
}
catch (std::invalid_argument iae) {
LogError("[SourceDatabaseTableFromUrl] URI parser error [{}]", iae.what());
}
}
+5 -2
View File
@@ -176,7 +176,7 @@ public:
/* Adventure related. */
void UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win);
void UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win = false, bool remove = false);
bool GetAdventureStats(uint32 char_id, AdventureStats_Struct *as);
/* Account Related */
@@ -198,7 +198,8 @@ public:
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
void SetAgreementFlag(uint32 acctid);
int GetIPExemption(std::string account_ip);
int GetIPExemption(std::string account_ip);
void SetIPExemption(std::string account_ip, int exemption_amount);
int GetInstanceID(uint32 char_id, uint32 zone_id);
@@ -269,6 +270,8 @@ public:
int CountInvSnapshots();
void ClearInvSnapshots(bool from_now = false);
void SourceDatabaseTableFromUrl(std::string table_name, std::string url);
private:
+1 -1
View File
@@ -1452,7 +1452,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
for (i = 0; i < MAX_LEADERSHIP_AA_ARRAY; i++){
if (pp->leader_abilities.ranks[i] > 0 && pp->leader_abilities.ranks[i] < 6){
if (first_entry != 1){
rquery = StringFormat("REPLACE INTO `character_leadership_abilities` (id, slot, rank) VALUES (%i, %u, %u)", character_id, i, pp->leader_abilities.ranks[i]);
rquery = StringFormat("REPLACE INTO `character_leadership_abilities` (id, slot, `rank`) VALUES (%i, %u, %u)", character_id, i, pp->leader_abilities.ranks[i]);
first_entry = 1;
}
rquery = rquery + StringFormat(", (%i, %u, %u)", character_id, i, pp->leader_abilities.ranks[i]);
+1 -2
View File
@@ -82,7 +82,6 @@ namespace DatabaseSchema {
{"player_titlesets", "char_id"},
{"quest_globals", "charid"},
{"timers", "char_id"},
{"titles", "char_id"},
{"trader", "char_id"},
{"zone_flags", "charID"}
};
@@ -158,7 +157,6 @@ namespace DatabaseSchema {
"spell_buckets",
"spell_globals",
"timers",
"titles",
"trader",
"trader_audit",
"zone_flags"
@@ -270,6 +268,7 @@ namespace DatabaseSchema {
"perl_event_export_settings",
"profanity_list",
"rule_sets",
"titles",
"rule_values",
"variables",
};
+186 -1
View File
@@ -18,6 +18,9 @@
*/
#include "emu_constants.h"
#include "languages.h"
#include "data_verification.h"
#include "bodytypes.h"
int16 EQ::invtype::GetInvTypeSize(int16 inv_type) {
@@ -147,8 +150,190 @@ const char *EQ::constants::GetStanceName(StanceType stance_type) {
}
int EQ::constants::ConvertStanceTypeToIndex(StanceType stance_type) {
if (stance_type >= EQ::constants::stancePassive && stance_type <= EQ::constants::stanceBurnAE)
if (EQ::ValueWithin(stance_type, EQ::constants::stancePassive, EQ::constants::stanceBurnAE)) {
return (stance_type - EQ::constants::stancePassive);
}
return 0;
}
const std::map<int, std::string>& EQ::constants::GetLanguageMap()
{
static const std::map<int, std::string> language_map = {
{ LANG_COMMON_TONGUE, "Common Tongue" },
{ LANG_BARBARIAN, "Barbarian" },
{ LANG_ERUDIAN, "Erudian" },
{ LANG_ELVISH, "Elvish" },
{ LANG_DARK_ELVISH, "Dark Elvish" },
{ LANG_DWARVISH, "Dwarvish" },
{ LANG_TROLL, "Troll" },
{ LANG_OGRE, "Ogre" },
{ LANG_GNOMISH, "Gnomish" },
{ LANG_HALFLING, "Halfling" },
{ LANG_THIEVES_CANT, "Thieves Cant" },
{ LANG_OLD_ERUDIAN, "Old Erudian" },
{ LANG_ELDER_ELVISH, "Elder Elvish" },
{ LANG_FROGLOK, "Froglok" },
{ LANG_GOBLIN, "Goblin" },
{ LANG_GNOLL, "Gnoll" },
{ LANG_COMBINE_TONGUE, "Combine Tongue" },
{ LANG_ELDER_TEIRDAL, "Elder Teirdal" },
{ LANG_LIZARDMAN, "Lizardman" },
{ LANG_ORCISH, "Orcish" },
{ LANG_FAERIE, "Faerie" },
{ LANG_DRAGON, "Dragon" },
{ LANG_ELDER_DRAGON, "Elder Dragon" },
{ LANG_DARK_SPEECH, "Dark Speech" },
{ LANG_VAH_SHIR, "Vah Shir" },
{ LANG_ALARAN, "Alaran" },
{ LANG_HADAL, "Hadal" },
{ LANG_UNKNOWN, "Unknown" }
};
return language_map;
}
std::string EQ::constants::GetLanguageName(int language_id)
{
if (EQ::ValueWithin(language_id, LANG_COMMON_TONGUE, LANG_UNKNOWN)) {
auto languages = EQ::constants::GetLanguageMap();
return languages[language_id];
}
return std::string();
}
const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
{
static const std::map<uint32, std::string> ldon_theme_map = {
{ LDoNThemes::Unused, "Unused" },
{ LDoNThemes::GUK, "Deepest Guk" },
{ LDoNThemes::MIR, "Miragul's Menagerie" },
{ LDoNThemes::MMC, "Mistmoore Catacombs" },
{ LDoNThemes::RUJ, "Rujarkian Hills" },
{ LDoNThemes::TAK, "Takish-Hiz" },
};
return ldon_theme_map;
}
std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
{
if (EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
auto ldon_themes = EQ::constants::GetLDoNThemeMap();
return ldon_themes[theme_id];
}
return std::string();
}
const std::map<uint8, std::string>& EQ::constants::GetFlyModeMap()
{
static const std::map<uint8, std::string> flymode_map = {
{ EQ::constants::GravityBehavior::Ground, "Ground" },
{ EQ::constants::GravityBehavior::Flying, "Flying" },
{ EQ::constants::GravityBehavior::Levitating, "Levitating" },
{ EQ::constants::GravityBehavior::Water, "Water" },
{ EQ::constants::GravityBehavior::Floating, "Floating" },
{ EQ::constants::GravityBehavior::LevitateWhileRunning, "Levitating While Running" },
};
return flymode_map;
}
std::string EQ::constants::GetFlyModeName(uint8 flymode_id)
{
if (EQ::ValueWithin(flymode_id, GravityBehavior::Ground, GravityBehavior::LevitateWhileRunning)) {
auto flymodes = EQ::constants::GetFlyModeMap();
return flymodes[flymode_id];
}
return std::string();
}
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)
{
auto bodytypes = EQ::constants::GetBodyTypeMap();
if (!bodytypes[bodytype_id].empty()) {
return bodytypes[bodytype_id];
}
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)
{
auto account_statuses = EQ::constants::GetAccountStatusMap();
std::string status_name;
for (auto status_level = account_statuses.rbegin(); status_level != account_statuses.rend(); ++status_level) {
if (account_status >= status_level->first) {
status_name = status_level->second;
break;
}
}
return status_name;
}
+64 -7
View File
@@ -22,6 +22,7 @@
#include "eq_limits.h"
#include "emu_versions.h"
#include "bodytypes.h"
#include <string.h>
@@ -220,9 +221,33 @@ namespace EQ
stanceBurnAE
};
enum GravityBehavior : uint8 {
Ground,
Flying,
Levitating,
Water,
Floating,
LevitateWhileRunning
};
const char *GetStanceName(StanceType stance_type);
int ConvertStanceTypeToIndex(StanceType stance_type);
extern const std::map<int, std::string>& GetLanguageMap();
std::string GetLanguageName(int language_id);
extern const std::map<uint32, std::string>& GetLDoNThemeMap();
std::string GetLDoNThemeName(uint32 theme_id);
extern const std::map<uint8, std::string>& GetFlyModeMap();
std::string GetFlyModeName(uint8 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);
const int STANCE_TYPE_FIRST = stancePassive;
const int STANCE_TYPE_LAST = stanceBurnAE;
const int STANCE_TYPE_COUNT = stanceBurnAE;
@@ -325,13 +350,45 @@ namespace EQ
Guild
};
}; // namespace consent
} /*EQEmu*/
enum ServerLockType : int {
List,
Lock,
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,
Special = 255
};
enum AugmentActions : int {
Insert,
Remove,
Swap,
Destroy
};
#endif /*COMMON_EMU_CONSTANTS_H*/
/* hack list to prevent circular references
eq_limits.h:EQ::inventory::LookupEntry::InventoryTypeSize[n];
*/
+2 -2
View File
@@ -129,8 +129,8 @@ N(OP_DisciplineTimer),
N(OP_DisciplineUpdate),
N(OP_DiscordMerchantInventory),
N(OP_DoGroupLeadershipAbility),
N(OP_DuelResponse),
N(OP_DuelResponse2),
N(OP_DuelDecline),
N(OP_DuelAccept),
N(OP_DumpName),
N(OP_Dye),
N(OP_DynamicWall),
+35
View File
@@ -974,4 +974,39 @@ enum class DynamicZoneMemberStatus : uint8_t
LinkDead
};
enum LDoNThemes {
Unused = 0,
GUK,
MIR,
MMC,
RUJ,
TAK
};
enum LDoNThemeBits {
UnusedBit = 0,
GUKBit = 1,
MIRBit = 2,
MMCBit = 4,
RUJBit = 8,
TAKBit = 16
};
enum StartZoneIndex {
Odus = 0,
Qeynos,
Halas,
Rivervale,
Freeport,
Neriak,
Grobb,
Oggok,
Kaladim,
GreaterFaydark,
Felwithe,
Akanon,
Cabilis,
SharVahl
};
#endif /*COMMON_EQ_CONSTANTS_H*/
+8 -5
View File
@@ -384,7 +384,9 @@ struct NewZone_Struct {
/*0716*/ uint32 FastRegenEndurance;
/*0720*/ uint32 NPCAggroMaxDist;
/*0724*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, if this value is 0, it prevents you from running off edges that would end up underworld
/*0728*/
/*0728*/ uint32 LavaDamage; // Seen 50
/*0732*/ uint32 MinLavaDamage; // Seen 10
/*0736*/
};
/*
@@ -446,6 +448,7 @@ struct ManaChange_Struct
/*08*/ uint32 spell_id;
/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting?
/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like
/*16*/ int32 slot; // -1 normal, otherwise clear ETA and GCD
};
struct SwapSpell_Struct
@@ -4340,8 +4343,8 @@ struct AARankPrereq_Struct
struct AARankEffect_Struct
{
int32 effect_id;
int32 base1;
int32 base2;
int32 base_value;
int32 limit_value;
int32 slot;
};
@@ -4349,8 +4352,8 @@ struct AARankEffect_Struct
struct AA_Ability {
/*00*/ uint32 skill_id;
/*04*/ uint32 base1;
/*08*/ uint32 base2;
/*04*/ uint32 base_value;
/*08*/ uint32 limit_value;
/*12*/ uint32 slot;
};
+14 -1
View File
@@ -44,6 +44,12 @@ void EQEmuConfig::parse_config()
if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; }
LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString();
LoginPassword = _root["server"]["world"]["loginserver"].get("password", "").asString();
// at least today, this is wrong a majority of the time
// remove this if eqemulator ever upgrades its loginserver
if (LoginHost.find("login.eqemulator.net") != std::string::npos) {
LoginLegacy = true;
}
}
else {
char str[32];
@@ -62,12 +68,19 @@ void EQEmuConfig::parse_config()
loginconfig->LoginLegacy = false;
if (_root["server"]["world"][str].get("legacy", "0").asString() == "1") { loginconfig->LoginLegacy = true; }
// at least today, this is wrong a majority of the time
// remove this if eqemulator ever upgrades its loginserver
if (loginconfig->LoginHost.find("login.eqemulator.net") != std::string::npos) {
loginconfig->LoginLegacy = true;
}
loginlist.Insert(loginconfig);
} while (LoginCount < 100);
}
//<locked> from xml converts to json as locked: "", so i default to "false".
//<locked> from xml converts to json as locked: "", so i default to "false".
//The only way to enable locked is by switching to true, meaning this value is always false until manually set true
Locked = false;
if (_root["server"]["world"].get("locked", "false").asString() == "true") { Locked = true; }
+2
View File
@@ -130,6 +130,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::Loot].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::Scheduler].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Cheat].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::HTTP].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::HTTP].log_to_gmsay = static_cast<uint8>(Logs::General);
/**
* RFC 5424
+4
View File
@@ -125,6 +125,8 @@ namespace Logs {
Cheat,
ClientList,
DiaWind,
HTTP,
Saylink,
MaxCategoryID /* Don't Remove this */
};
@@ -208,6 +210,8 @@ namespace Logs {
"Cheat",
"ClientList",
"DialogueWindow",
"HTTP",
"Saylink",
};
}
+26
View File
@@ -676,6 +676,26 @@
OutF(LogSys, Logs::Detail, Logs::DiaWind, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogHTTP(message, ...) do {\
if (LogSys.log_settings[Logs::HTTP].is_category_enabled == 1)\
OutF(LogSys, Logs::General, Logs::HTTP, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogHTTPDetail(message, ...) do {\
if (LogSys.log_settings[Logs::HTTP].is_category_enabled == 1)\
OutF(LogSys, Logs::Detail, Logs::HTTP, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogSaylink(message, ...) do {\
if (LogSys.log_settings[Logs::Saylink].is_category_enabled == 1)\
OutF(LogSys, Logs::General, Logs::Saylink, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogSaylinkDetail(message, ...) do {\
if (LogSys.log_settings[Logs::Saylink].is_category_enabled == 1)\
OutF(LogSys, Logs::Detail, Logs::Saylink, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
@@ -1066,6 +1086,12 @@
#define LogDiaWindDetail(message, ...) do {\
} while (0)
#define LogHTTP(message, ...) do {\
} while (0)
#define LogHTTPDetail(message, ...) do {\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
} while (0)
+22 -22
View File
@@ -20,31 +20,31 @@
#include "races.h"
#include "rulesys.h"
const char *FactionValueToString(FACTION_VALUE fv)
const char *FactionValueToString(FACTION_VALUE faction_value)
{
switch (fv) {
switch (faction_value) {
case FACTION_ALLY:
return ("Ally");
return "Ally";
case FACTION_WARMLY:
return ("Warmly");
return "Warmly";
case FACTION_KINDLY:
return ("Kindly");
case FACTION_AMIABLE:
return ("Amiable");
case FACTION_INDIFFERENT:
return ("Indifferent");
case FACTION_APPREHENSIVE:
return ("Apprehensive");
case FACTION_DUBIOUS:
return ("Dubious");
case FACTION_THREATENLY:
return ("Threatenly");
return "Kindly";
case FACTION_AMIABLY:
return "Amiably";
case FACTION_INDIFFERENTLY:
return "Indifferently";
case FACTION_APPREHENSIVELY:
return "Apprehensively";
case FACTION_DUBIOUSLY:
return "Dubiously";
case FACTION_THREATENINGLY:
return "Threateningly";
case FACTION_SCOWLS:
return ("Scowls, ready to attack.");
return "Scowls";
default:
break;
}
return ("Unknown Faction Con");
return "Unknown";
}
@@ -70,19 +70,19 @@ FACTION_VALUE CalculateFaction(FactionMods* fm, int32 tmpCharacter_value)
return FACTION_KINDLY;
}
if (character_value >= RuleI(Faction, AmiablyFactionMinimum)) {
return FACTION_AMIABLE;
return FACTION_AMIABLY;
}
if (character_value >= RuleI(Faction, IndifferentlyFactionMinimum)) {
return FACTION_INDIFFERENT;
return FACTION_INDIFFERENTLY;
}
if (character_value >= RuleI(Faction, ApprehensivelyFactionMinimum)) {
return FACTION_APPREHENSIVE;
return FACTION_APPREHENSIVELY;
}
if (character_value >= RuleI(Faction, DubiouslyFactionMinimum)) {
return FACTION_DUBIOUS;
return FACTION_DUBIOUSLY;
}
if (character_value >= RuleI(Faction, ThreateninglyFactionMinimum)) {
return FACTION_THREATENLY;
return FACTION_THREATENINGLY;
}
return FACTION_SCOWLS;
}
+6 -6
View File
@@ -27,13 +27,13 @@ enum FACTION_VALUE {
FACTION_ALLY = 1,
FACTION_WARMLY = 2,
FACTION_KINDLY = 3,
FACTION_AMIABLE = 4,
FACTION_AMIABLY = 4,
FACTION_INDIFFERENT = 5,
FACTION_INDIFFERENTLY = 5,
FACTION_APPREHENSIVE = 6,
FACTION_DUBIOUS = 7,
FACTION_THREATENLY = 8,
FACTION_APPREHENSIVELY = 6,
FACTION_DUBIOUSLY = 7,
FACTION_THREATENINGLY = 8,
FACTION_SCOWLS = 9
};
@@ -75,6 +75,6 @@ struct NPCFaction
uint8 temp;
};
const char *FactionValueToString(FACTION_VALUE fv);
const char *FactionValueToString(FACTION_VALUE faction_value);
FACTION_VALUE CalculateFaction(FactionMods* fm, int32 tmpCharacter_value);
#endif
+1 -1
View File
@@ -204,7 +204,7 @@ enum { //some random constants
#define MIN_LEVEL_ALCHEMY 25
//chance ratio that a
#define THREATENLY_ARRGO_CHANCE 32 // 32/128 (25%) chance that a mob will arrgo on con Threatenly
#define THREATENINGLY_AGGRO_CHANCE 32 // 32/128 (25%) chance that a mob will arrgo on con Threatenly
//max factions per npc faction list
#define MAX_NPC_FACTIONS 20
+6 -1
View File
@@ -64,4 +64,9 @@ void FileUtil::mkdir(const std::string& directory_name)
}
::mkdir(directory_name.c_str(), 0755);
#endif
}
}
bool file_exists(const std::string& name) {
std::ifstream f(name.c_str());
return f.good();
}
+1
View File
@@ -28,5 +28,6 @@ public:
static void mkdir(const std::string& directory_name);
};
bool file_exists(const std::string& name);
#endif //EQEMU_FILE_UTIL_H
+66 -6
View File
@@ -63,7 +63,7 @@ bool BaseGuildManager::LoadGuilds() {
for (auto row=results.begin();row!=results.end();++row)
_CreateGuild(atoi(row[0]), row[1], atoi(row[2]), atoi(row[3]), row[4], row[5], row[6], row[7]);
query = "SELECT guild_id,rank,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
query = "SELECT guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace FROM guild_ranks";
results = m_db->QueryDatabase(query);
if (!results.Success())
@@ -131,7 +131,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
info = _CreateGuild(guild_id, row[0], atoi(row[1]), atoi(row[2]), row[3], row[4], row[5], row[6]);
query = StringFormat("SELECT guild_id, rank, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace "
query = StringFormat("SELECT guild_id, `rank`, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace "
"FROM guild_ranks WHERE guild_id=%lu", (unsigned long)guild_id);
results = m_db->QueryDatabase(query);
@@ -268,7 +268,7 @@ bool BaseGuildManager::_StoreGuildDB(uint32 guild_id) {
m_db->DoEscapeString(title_esc, rankInfo.name.c_str(), rankInfo.name.length());
query = StringFormat("INSERT INTO guild_ranks "
"(guild_id,rank,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace)"
"(guild_id,`rank`,title,can_hear,can_speak,can_invite,can_remove,can_promote,can_demote,can_motd,can_warpeace)"
" VALUES(%d,%d,'%s',%d,%d,%d,%d,%d,%d,%d,%d)",
guild_id, rank, title_esc,
rankInfo.permissions[GUILD_HEAR],
@@ -738,7 +738,7 @@ bool BaseGuildManager::DBSetGuild(uint32 charid, uint32 guild_id, uint8 rank) {
std::string query;
if(guild_id != GUILD_NONE) {
query = StringFormat("REPLACE INTO guild_members (char_id,guild_id,rank,public_note) VALUES(%d,%d,%d,'')", charid, guild_id, rank);
query = StringFormat("REPLACE INTO guild_members (char_id,guild_id,`rank`,public_note) VALUES(%d,%d,%d,'')", charid, guild_id, rank);
auto results = m_db->QueryDatabase(query);
if (!results.Success()) {
@@ -758,7 +758,7 @@ bool BaseGuildManager::DBSetGuild(uint32 charid, uint32 guild_id, uint8 rank) {
}
bool BaseGuildManager::DBSetGuildRank(uint32 charid, uint8 rank) {
std::string query = StringFormat("UPDATE guild_members SET rank=%d WHERE char_id=%d", rank, charid);
std::string query = StringFormat("UPDATE guild_members SET `rank`=%d WHERE char_id=%d", rank, charid);
return(QueryWithLogging(query, "setting a guild member's rank"));
}
@@ -1208,7 +1208,7 @@ BaseGuildManager::RankInfo::RankInfo() {
BaseGuildManager::GuildInfo::GuildInfo() {
leader_char_id = 0;
minstatus = 0;
minstatus = AccountStatus::Player;
}
uint32 BaseGuildManager::DoesAccountContainAGuildLeader(uint32 AccountID)
@@ -1225,6 +1225,66 @@ uint32 BaseGuildManager::DoesAccountContainAGuildLeader(uint32 AccountID)
return results.RowCount();
}
std::string BaseGuildManager::GetGuildNameByID(uint32 guild_id) const {
if(guild_id == GUILD_NONE) {
return std::string();
}
std::map<uint32, GuildInfo *>::const_iterator res;
res = m_guilds.find(guild_id);
if(res == m_guilds.end()) {
return "Invalid Guild";
}
return res->second->name;
}
std::string BaseGuildManager::GetGuildRankName(uint32 guild_id, uint8 rank) const
{
if(rank > GUILD_MAX_RANK) {
return "Invalid Rank";
}
std::map<uint32, GuildInfo *>::const_iterator res;
res = m_guilds.find(guild_id);
if(res == m_guilds.end()) {
return "Invalid Guild Rank";
}
return res->second->ranks[rank].name;
}
uint32 BaseGuildManager::GetGuildIDByCharacterID(uint32 character_id)
{
if(!m_db) {
return GUILD_NONE;
}
std::string query = fmt::format(
"SELECT `guild_id` FROM `guild_members` WHERE char_id = {} LIMIT 1",
character_id
);
auto results = m_db->QueryDatabase(query);
if(!results.Success() || !results.RowCount()) {
return GUILD_NONE;
}
auto row = results.begin();
auto guild_id = std::stoul(row[0]);
return guild_id;
}
bool BaseGuildManager::IsCharacterInGuild(uint32 character_id, uint32 guild_id)
{
auto current_guild_id = GetGuildIDByCharacterID(character_id);
if (current_guild_id == GUILD_NONE) {
return false;
}
if (guild_id && current_guild_id != guild_id) {
return false;
}
return true;
}
+4
View File
@@ -76,8 +76,12 @@ class BaseGuildManager
bool GetGuildChannel(uint32 GuildID, char *ChannelBuffer) const;
const char *GetRankName(uint32 guild_id, uint8 rank) const;
const char *GetGuildName(uint32 guild_id) const;
std::string GetGuildNameByID(uint32 guild_id) const;
std::string GetGuildRankName(uint32 guild_id, uint8 rank) const;
bool IsCharacterInGuild(uint32 character_id, uint32 guild_id = 0);
bool GetGuildNameByID(uint32 guild_id, std::string &into) const;
uint32 GetGuildIDByName(const char *GuildName);
uint32 GetGuildIDByCharacterID(uint32 character_id);
bool IsGuildLeader(uint32 guild_id, uint32 char_id) const;
uint8 GetDisplayedRank(uint32 guild_id, uint8 rank, uint32 char_id) const;
bool CheckGMStatus(uint32 guild_id, uint8 status) const;
+633
View File
@@ -0,0 +1,633 @@
// Copyright (C) 2015 Ben Lewis <benjf5+github@gmail.com>
// Licensed under the MIT license.
// https://github.com/ben-zen/uri-library
#pragma once
#include <cctype>
#include <map>
#include <string>
#include <stdexcept>
#include <utility>
class uri {
/* URIs are broadly divided into two categories: hierarchical and
* non-hierarchical. Both hierarchical URIs and non-hierarchical URIs have a
* few elements in common; all URIs have a scheme of one or more alphanumeric
* characters followed by a colon, and they all may optionally have a query
* component preceded by a question mark, and a fragment component preceded by
* an octothorpe (hash mark: '#'). The query consists of stanzas separated by
* either ampersands ('&') or semicolons (';') (but only one or the other),
* and each stanza consists of a key and an optional value; if the value
* exists, the key and value must be divided by an equals sign.
*
* The following is an example from Wikipedia of a hierarchical URI:
* scheme:[//[user:password@]domain[:port]][/]path[?query][#fragment]
*/
public:
enum class scheme_category {
Hierarchical,
NonHierarchical
};
enum class component {
Scheme,
Content,
Username,
Password,
Host,
Port,
Path,
Query,
Fragment
};
enum class query_argument_separator {
ampersand,
semicolon
};
uri(
char const *uri_text, scheme_category category = scheme_category::Hierarchical,
query_argument_separator separator = query_argument_separator::ampersand
) :
m_category(category),
m_path_is_rooted(false),
m_port(0),
m_separator(separator)
{
setup(std::string(uri_text), category);
};
uri(
std::string const &uri_text, scheme_category category = scheme_category::Hierarchical,
query_argument_separator separator = query_argument_separator::ampersand
) :
m_category(category),
m_path_is_rooted(false),
m_port(0),
m_separator(separator)
{
setup(uri_text, category);
};
uri(
std::map<component, std::string> const &components,
scheme_category category,
bool rooted_path,
query_argument_separator separator = query_argument_separator::ampersand
) :
m_category(category),
m_path_is_rooted(rooted_path),
m_separator(separator)
{
if (components.count(component::Scheme)) {
if (components.at(component::Scheme).length() == 0) {
throw std::invalid_argument("Scheme cannot be empty.");
}
m_scheme = components.at(component::Scheme);
}
else {
throw std::invalid_argument("A URI must have a scheme.");
}
if (category == scheme_category::Hierarchical) {
if (components.count(component::Content)) {
throw std::invalid_argument("The content component is only for use in non-hierarchical URIs.");
}
bool has_username = components.count(component::Username);
bool has_password = components.count(component::Password);
if (has_username && has_password) {
m_username = components.at(component::Username);
m_password = components.at(component::Password);
}
else if ((has_username && !has_password) || (!has_username && has_password)) {
throw std::invalid_argument("If a username or password is supplied, both must be provided.");
}
if (components.count(component::Host)) {
m_host = components.at(component::Host);
}
if (components.count(component::Port)) {
m_port = std::stoul(components.at(component::Port));
}
if (components.count(component::Path)) {
m_path = components.at(component::Path);
}
else {
throw std::invalid_argument("A path is required on a hierarchical URI, even an empty path.");
}
}
else {
if (components.count(component::Username)
|| components.count(component::Password)
|| components.count(component::Host)
|| components.count(component::Port)
|| components.count(component::Path)) {
throw std::invalid_argument("None of the hierarchical components are allowed in a non-hierarchical URI.");
}
if (components.count(component::Content)) {
m_content = components.at(component::Content);
}
else {
throw std::invalid_argument(
"Content is a required component for a non-hierarchical URI, even an empty string."
);
}
}
if (components.count(component::Query)) {
m_query = components.at(component::Query);
}
if (components.count(component::Fragment)) {
m_fragment = components.at(component::Fragment);
}
}
uri(uri const &other, std::map<component, std::string> const &replacements) :
m_category(other.m_category),
m_path_is_rooted(other.m_path_is_rooted),
m_separator(other.m_separator)
{
m_scheme = (replacements.count(component::Scheme))
? replacements.at(component::Scheme) : other.m_scheme;
if (m_category == scheme_category::Hierarchical) {
m_username = (replacements.count(component::Username))
? replacements.at(component::Username) : other.m_username;
m_password = (replacements.count(component::Password))
? replacements.at(component::Password) : other.m_password;
m_host = (replacements.count(component::Host))
? replacements.at(component::Host) : other.m_host;
m_port = (replacements.count(component::Port))
? std::stoul(replacements.at(component::Port)) : other.m_port;
m_path = (replacements.count(component::Path))
? replacements.at(component::Path) : other.m_path;
}
else {
m_content = (replacements.count(component::Content))
? replacements.at(component::Content) : other.m_content;
}
m_query = (replacements.count(component::Query))
? replacements.at(component::Query) : other.m_query;
m_fragment = (replacements.count(component::Fragment))
? replacements.at(component::Fragment) : other.m_fragment;
}
// Copy constructor; just use the copy assignment operator internally.
uri(uri const &other)
{
*this = other;
};
// Copy assignment operator
uri &operator=(uri const &other)
{
if (this != &other) {
m_scheme = other.m_scheme;
m_content = other.m_content;
m_username = other.m_username;
m_password = other.m_password;
m_host = other.m_host;
m_path = other.m_path;
m_query = other.m_query;
m_fragment = other.m_fragment;
m_query_dict = other.m_query_dict;
m_category = other.m_category;
m_port = other.m_port;
m_path_is_rooted = other.m_path_is_rooted;
m_separator = other.m_separator;
}
return *this;
}
~uri() {};
std::string const &get_scheme() const
{
return m_scheme;
};
scheme_category get_scheme_category() const
{
return m_category;
};
std::string const &get_content() const
{
if (m_category != scheme_category::NonHierarchical) {
throw std::domain_error("The content component is only valid for non-hierarchical URIs.");
}
return m_content;
};
std::string const &get_username() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The username component is only valid for hierarchical URIs.");
}
return m_username;
};
std::string const &get_password() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The password component is only valid for hierarchical URIs.");
}
return m_password;
};
std::string const &get_host() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The host component is only valid for hierarchical URIs.");
}
return m_host;
};
unsigned long get_port() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The port component is only valid for hierarchical URIs.");
}
return m_port;
};
std::string const &get_path() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The path component is only valid for hierarchical URIs.");
}
return m_path;
};
std::string const &get_query() const
{
return m_query;
};
std::map<std::string, std::string> const &get_query_dictionary() const
{
return m_query_dict;
};
std::string const &get_fragment() const
{
return m_fragment;
};
std::string to_string() const
{
std::string full_uri;
full_uri.append(m_scheme);
full_uri.append(":");
if (m_content.length() > m_path.length()) {
full_uri.append("//");
if (!(m_username.empty() || m_password.empty())) {
full_uri.append(m_username);
full_uri.append(":");
full_uri.append(m_password);
full_uri.append("@");
}
full_uri.append(m_host);
if (m_port != 0) {
full_uri.append(":");
full_uri.append(std::to_string(m_port));
}
}
if (m_path_is_rooted) {
full_uri.append("/");
}
full_uri.append(m_path);
if (!m_query.empty()) {
full_uri.append("?");
full_uri.append(m_query);
}
if (!m_fragment.empty()) {
full_uri.append("#");
full_uri.append(m_fragment);
}
return full_uri;
};
private:
void setup(std::string const &uri_text, scheme_category category)
{
size_t const uri_length = uri_text.length();
if (uri_length == 0) {
throw std::invalid_argument("URIs cannot be of zero length.");
}
std::string::const_iterator cursor = parse_scheme(
uri_text,
uri_text.begin());
// After calling parse_scheme, *cursor == ':'; none of the following parsers
// expect a separator character, so we advance the cursor upon calling them.
cursor = parse_content(uri_text, (cursor + 1));
if ((cursor != uri_text.end()) && (*cursor == '?')) {
cursor = parse_query(uri_text, (cursor + 1));
}
if ((cursor != uri_text.end()) && (*cursor == '#')) {
cursor = parse_fragment(uri_text, (cursor + 1));
}
init_query_dictionary(); // If the query string is empty, this will be empty too.
};
std::string::const_iterator parse_scheme(
std::string const &uri_text,
std::string::const_iterator scheme_start
)
{
std::string::const_iterator scheme_end = scheme_start;
while ((scheme_end != uri_text.end()) && (*scheme_end != ':')) {
if (!(std::isalnum(*scheme_end) || (*scheme_end == '-')
|| (*scheme_end == '+') || (*scheme_end == '.'))) {
throw std::invalid_argument(
"Invalid character found in the scheme component. Supplied URI was: \""
+ uri_text + "\"."
);
}
++scheme_end;
}
if (scheme_end == uri_text.end()) {
throw std::invalid_argument(
"End of URI found while parsing the scheme. Supplied URI was: \""
+ uri_text + "\"."
);
}
if (scheme_start == scheme_end) {
throw std::invalid_argument(
"Scheme component cannot be zero-length. Supplied URI was: \""
+ uri_text + "\"."
);
}
m_scheme = std::move(std::string(scheme_start, scheme_end));
return scheme_end;
};
std::string::const_iterator parse_content(
std::string const &uri_text,
std::string::const_iterator content_start
)
{
std::string::const_iterator content_end = content_start;
while ((content_end != uri_text.end()) && (*content_end != '?') && (*content_end != '#')) {
++content_end;
}
m_content = std::move(std::string(content_start, content_end));
if ((m_category == scheme_category::Hierarchical) && (m_content.length() > 0)) {
// If it's a hierarchical URI, the content should be parsed for the hierarchical components.
std::string::const_iterator path_start = m_content.begin();
std::string::const_iterator path_end = m_content.end();
if (!m_content.compare(0, 2, "//")) {
// In this case an authority component is present.
std::string::const_iterator authority_cursor = (m_content.begin() + 2);
if (m_content.find_first_of('@') != std::string::npos) {
std::string::const_iterator userpass_divider = parse_username(
uri_text,
m_content,
authority_cursor
);
authority_cursor = parse_password(uri_text, m_content, (userpass_divider + 1));
// After this call, *authority_cursor == '@', so we skip over it.
++authority_cursor;
}
authority_cursor = parse_host(uri_text, m_content, authority_cursor);
if ((authority_cursor != m_content.end()) && (*authority_cursor == ':')) {
authority_cursor = parse_port(uri_text, m_content, (authority_cursor + 1));
}
if ((authority_cursor != m_content.end()) && (*authority_cursor == '/')) {
// Then the path is rooted, and we should note this.
m_path_is_rooted = true;
path_start = authority_cursor + 1;
}
// If we've reached the end and no path is present then set path_start
// to the end.
if (authority_cursor == m_content.end()) {
path_start = m_content.end();
}
}
else if (!m_content.compare(0, 1, "/")) {
m_path_is_rooted = true;
++path_start;
}
// We can now build the path based on what remains in the content string,
// since that's all that exists after the host and optional port component.
m_path = std::move(std::string(path_start, path_end));
}
return content_end;
};
std::string::const_iterator parse_username(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator username_start
)
{
std::string::const_iterator username_end = username_start;
// Since this is only reachable when '@' was in the content string, we can
// ignore the end-of-string case.
while (*username_end != ':') {
if (*username_end == '@') {
throw std::invalid_argument(
"Username must be followed by a password. Supplied URI was: \""
+ uri_text + "\"."
);
}
++username_end;
}
m_username = std::move(std::string(username_start, username_end));
return username_end;
};
std::string::const_iterator parse_password(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator password_start
)
{
std::string::const_iterator password_end = password_start;
while (*password_end != '@') {
++password_end;
}
m_password = std::move(std::string(password_start, password_end));
return password_end;
};
std::string::const_iterator parse_host(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator host_start
)
{
std::string::const_iterator host_end = host_start;
// So, the host can contain a few things. It can be a domain, it can be an
// IPv4 address, it can be an IPv6 address, or an IPvFuture literal. In the
// case of those last two, it's of the form [...] where what's between the
// brackets is a matter of which IPv?? version it is.
while (host_end != content.end()) {
if (*host_end == '[') {
// We're parsing an IPv6 or IPvFuture address, so we should handle that
// instead of the normal procedure.
while ((host_end != content.end()) && (*host_end != ']')) {
++host_end;
}
if (host_end == content.end()) {
throw std::invalid_argument(
"End of content component encountered "
"while parsing the host component. "
"Supplied URI was: \""
+ uri_text + "\"."
);
}
++host_end;
break;
// We can stop looping, we found the end of the IP literal, which is the
// whole of the host component when one's in use.
}
else if ((*host_end == ':') || (*host_end == '/')) {
break;
}
else {
++host_end;
}
}
m_host = std::move(std::string(host_start, host_end));
return host_end;
};
std::string::const_iterator parse_port(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator port_start
)
{
std::string::const_iterator port_end = port_start;
while ((port_end != content.end()) && (*port_end != '/')) {
if (!std::isdigit(*port_end)) {
throw std::invalid_argument(
"Invalid character while parsing the port. "
"Supplied URI was: \"" + uri_text + "\"."
);
}
++port_end;
}
m_port = std::stoul(std::string(port_start, port_end));
return port_end;
};
std::string::const_iterator parse_query(
std::string const &uri_text,
std::string::const_iterator query_start
)
{
std::string::const_iterator query_end = query_start;
while ((query_end != uri_text.end()) && (*query_end != '#')) {
// Queries can contain almost any character except hash, which is reserved
// for the start of the fragment.
++query_end;
}
m_query = std::move(std::string(query_start, query_end));
return query_end;
};
std::string::const_iterator parse_fragment(
std::string const &uri_text,
std::string::const_iterator fragment_start
)
{
m_fragment = std::move(std::string(fragment_start, uri_text.end()));
return uri_text.end();
};
void init_query_dictionary()
{
if (!m_query.empty()) {
// Loop over the query string looking for '&'s, then check each one for
// an '=' to find keys and values; if there's not an '=' then the key
// will have an empty value in the map.
char separator = (m_separator == query_argument_separator::ampersand) ? '&' : ';';
size_t carat = 0;
size_t stanza_end = m_query.find_first_of(separator);
do {
std::string stanza = m_query.substr(
carat,
((stanza_end != std::string::npos) ? (stanza_end - carat) : std::string::npos));
size_t key_value_divider = stanza.find_first_of('=');
std::string key = stanza.substr(0, key_value_divider);
std::string value;
if (key_value_divider != std::string::npos) {
value = stanza.substr((key_value_divider + 1));
}
if (m_query_dict.count(key) != 0) {
throw std::invalid_argument("Bad key in the query string!");
}
m_query_dict.emplace(key, value);
carat = ((stanza_end != std::string::npos) ? (stanza_end + 1)
: std::string::npos);
stanza_end = m_query.find_first_of(separator, carat);
} while ((stanza_end != std::string::npos)
|| (carat != std::string::npos));
}
}
std::string m_scheme;
std::string m_content;
std::string m_username;
std::string m_password;
std::string m_host;
std::string m_path;
std::string m_query;
std::string m_fragment;
std::map<std::string, std::string> m_query_dict;
scheme_category m_category;
unsigned long m_port;
bool m_path_is_rooted;
query_argument_separator m_separator;
};
+64 -2
View File
@@ -224,7 +224,7 @@ EQ::ItemInstance* EQ::InventoryProfile::GetItem(int16 slot_id, uint8 bagidx) con
return GetItem(InventoryProfile::CalcSlotId(slot_id, bagidx));
}
// Put an item snto specified slot
// Put an item into specified slot
int16 EQ::InventoryProfile::PutItem(int16 slot_id, const ItemInstance& inst)
{
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) {
@@ -399,7 +399,7 @@ bool EQ::InventoryProfile::SwapItem(
}
// Remove item from inventory (with memory delete)
bool EQ::InventoryProfile::DeleteItem(int16 slot_id, uint8 quantity) {
bool EQ::InventoryProfile::DeleteItem(int16 slot_id, int16 quantity) {
// Pop item out of inventory map (or queue)
ItemInstance *item_to_delete = PopItem(slot_id);
@@ -590,6 +590,68 @@ bool EQ::InventoryProfile::HasSpaceForItem(const ItemData *ItemToTry, int16 Quan
// Checks that user has at least 'quantity' number of items in a given inventory slot
// Returns first slot it was found in, or SLOT_INVALID if not found
bool EQ::InventoryProfile::HasAugmentEquippedByID(uint32 item_id)
{
bool has_equipped = false;
ItemInstance* item = nullptr;
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
item = GetItem(slot_id);
if (item && item->ContainsAugmentByID(item_id)) {
has_equipped = true;
break;
}
}
return has_equipped;
}
int EQ::InventoryProfile::CountAugmentEquippedByID(uint32 item_id)
{
int quantity = 0;
ItemInstance* item = nullptr;
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
item = GetItem(slot_id);
if (item && item->ContainsAugmentByID(item_id)) {
quantity += item->CountAugmentByID(item_id);
}
}
return quantity;
}
bool EQ::InventoryProfile::HasItemEquippedByID(uint32 item_id)
{
bool has_equipped = false;
ItemInstance* item = nullptr;
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
item = GetItem(slot_id);
if (item && item->GetID() == item_id) {
has_equipped = true;
break;
}
}
return has_equipped;
}
int EQ::InventoryProfile::CountItemEquippedByID(uint32 item_id)
{
int quantity = 0;
ItemInstance* item = nullptr;
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
item = GetItem(slot_id);
if (item && item->GetID() == item_id) {
quantity += item->IsStackable() ? item->GetCharges() : 1;
}
}
return quantity;
}
//This function has a flaw in that it only returns the last stack that it looked at
//when quantity is greater than 1 and not all of quantity can be found in 1 stack.
int16 EQ::InventoryProfile::HasItem(uint32 item_id, uint8 quantity, uint8 where)
+13 -1
View File
@@ -132,7 +132,7 @@ namespace EQ
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = 0, uint8 class_id = 0, uint16 deity_id = 0, uint8 level = 0);
// Remove item from inventory
bool DeleteItem(int16 slot_id, uint8 quantity = 0);
bool DeleteItem(int16 slot_id, int16 quantity = 0);
// Checks All items in a bag for No Drop
bool CheckNoDrop(int16 slot_id, bool recurse = true);
@@ -140,6 +140,18 @@ namespace EQ
// Remove item from inventory (and take control of memory)
ItemInstance* PopItem(int16 slot_id);
// Check if player has a specific item equipped by Item ID
bool HasItemEquippedByID(uint32 item_id);
// Check how many of a specific item the player has equipped by Item ID
int CountItemEquippedByID(uint32 item_id);
// Check if player has a specific augment equipped by Item ID
bool HasAugmentEquippedByID(uint32 item_id);
// Check how many of a specific augment the player has equipped by Item ID
int CountAugmentEquippedByID(uint32 item_id);
// Check whether there is space for the specified number of the specified item.
bool HasSpaceForItem(const ItemData *ItemToTry, int16 Quantity);
+1 -1
View File
@@ -482,7 +482,7 @@ namespace EQ
uint32 Haste;
uint32 DamageShield;
uint32 RecastDelay;
uint32 RecastType;
int RecastType;
uint32 AugDistiller;
bool Attuneable;
bool NoPet;
+40 -1
View File
@@ -689,6 +689,45 @@ bool EQ::ItemInstance::IsAugmented()
return false;
}
bool EQ::ItemInstance::ContainsAugmentByID(uint32 item_id)
{
if (!m_item || !m_item->IsClassCommon()) {
return false;
}
if (!item_id) {
return false;
}
for (uint8 augment_slot = invaug::SOCKET_BEGIN; augment_slot <= invaug::SOCKET_END; ++augment_slot) {
if (GetAugmentItemID(augment_slot) == item_id) {
return true;
}
}
return false;
}
int EQ::ItemInstance::CountAugmentByID(uint32 item_id)
{
int quantity = 0;
if (!m_item || !m_item->IsClassCommon()) {
return quantity;
}
if (!item_id) {
return quantity;
}
for (uint8 augment_slot = invaug::SOCKET_BEGIN; augment_slot <= invaug::SOCKET_END; ++augment_slot) {
if (GetAugmentItemID(augment_slot) == item_id) {
quantity++;
}
}
return quantity;
}
// Has attack/delay?
bool EQ::ItemInstance::IsWeapon() const
{
@@ -1706,4 +1745,4 @@ EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32
EvolveInfo::~EvolveInfo() {
}
}
+2
View File
@@ -132,6 +132,8 @@ namespace EQ
void DeleteAugment(uint8 slot);
ItemInstance* RemoveAugment(uint8 index);
bool IsAugmented();
bool ContainsAugmentByID(uint32 item_id);
int CountAugmentByID(uint32 item_id);
ItemInstance* GetOrnamentationAug(int32 ornamentationAugtype) const;
bool UpdateOrnamentationInfo();
static bool CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll = false);
+2 -2
View File
@@ -15,7 +15,7 @@ EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent,
memset(m_line, 0, MaxConsoleLineLength);
m_accept_messages = false;
m_user_id = 0;
m_admin = 0;
m_admin = AccountStatus::Player;
m_connection->OnRead(std::bind(&ConsoleServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
m_connection->OnDisconnect(std::bind(&ConsoleServerConnection::OnDisconnect, this, std::placeholders::_1));
@@ -29,7 +29,7 @@ EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent,
if (addr.find("127.0.0.1") != std::string::npos || addr.find("::0") != std::string::npos) {
SendLine("Connection established from localhost, assuming admin");
m_status = ConsoleStatusLoggedIn;
m_admin = 255;
m_admin = AccountStatus::Max;
SendPrompt();
}
else {
+161 -12
View File
@@ -11,6 +11,7 @@ EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<
m_connection->OnRead(std::bind(&ServertalkServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
m_connection->OnDisconnect(std::bind(&ServertalkServerConnection::OnDisconnect, this, std::placeholders::_1));
m_connection->Start();
m_legacy_mode = false;
}
EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
@@ -19,17 +20,73 @@ EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p)
{
// pad zero size packets
if (p.Length() == 0) {
p.PutUInt8(0, 0);
if (m_legacy_mode) {
if (!m_connection)
return;
if (opcode == ServerOP_UsertoWorldReq) {
auto req_in = (UsertoWorldRequest_Struct*)p.Data();
EQ::Net::DynamicPacket req;
size_t i = 0;
req.PutUInt32(i, req_in->lsaccountid); i += 4;
req.PutUInt32(i, req_in->worldid); i += 4;
req.PutUInt32(i, req_in->FromID); i += 4;
req.PutUInt32(i, req_in->ToID); i += 4;
req.PutData(i, req_in->IPAddr, 64); i += 64;
EQ::Net::DynamicPacket out;
out.PutUInt16(0, ServerOP_UsertoWorldReqLeg);
out.PutUInt16(2, req.Length() + 4);
out.PutPacket(4, req);
m_connection->Write((const char*)out.Data(), out.Length());
return;
}
if (opcode == ServerOP_LSClientAuth) {
auto req_in = (ClientAuth_Struct*)p.Data();
EQ::Net::DynamicPacket req;
size_t i = 0;
req.PutUInt32(i, req_in->loginserver_account_id); i += 4;
req.PutData(i, req_in->account_name, 30); i += 30;
req.PutData(i, req_in->key, 30); i += 30;
req.PutUInt8(i, req_in->lsadmin); i += 1;
req.PutUInt16(i, req_in->is_world_admin); i += 2;
req.PutUInt32(i, req_in->ip); i += 4;
req.PutUInt8(i, req_in->is_client_from_local_network); i += 1;
EQ::Net::DynamicPacket out;
out.PutUInt16(0, ServerOP_LSClientAuthLeg);
out.PutUInt16(2, req.Length() + 4);
out.PutPacket(4, req);
m_connection->Write((const char*)out.Data(), out.Length());
return;
}
EQ::Net::DynamicPacket out;
out.PutUInt16(0, opcode);
out.PutUInt16(2, p.Length() + 4);
out.PutPacket(4, p);
m_connection->Write((const char*)out.Data(), out.Length());
} else {
// pad zero size packets
// pad packets that would cause a collision with legacy identification code
// It's unlikely we'd send a 4MB msg for any reason but just incase.
if (p.Length() == 0 || p.Length() == 43061256) {
p.PutUInt8(0, 0);
}
EQ::Net::DynamicPacket out;
out.PutUInt32(0, p.Length());
out.PutUInt16(4, opcode);
out.PutPacket(6, p);
InternalSend(ServertalkMessage, out);
}
EQ::Net::DynamicPacket out;
out.PutUInt32(0, p.Length());
out.PutUInt16(4, opcode);
out.PutPacket(6, p);
InternalSend(ServertalkMessage, out);
}
void EQ::Net::ServertalkServerConnection::SendPacket(ServerPacket *p)
@@ -54,17 +111,41 @@ void EQ::Net::ServertalkServerConnection::OnMessage(std::function<void(uint16_t,
void EQ::Net::ServertalkServerConnection::OnRead(TCPConnection *c, const unsigned char *data, size_t sz)
{
m_buffer.insert(m_buffer.end(), (const char*)data, (const char*)data + sz);
ProcessReadBuffer();
if (m_legacy_mode) {
ProcessOldReadBuffer();
} else {
ProcessReadBuffer();
}
}
void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
{
size_t current = 0;
size_t total = m_buffer.size();
constexpr size_t ls_info_size = sizeof(ServerNewLSInfo_Struct);
while (current < total) {
auto left = total - current;
if (left < 4) {
break;
}
auto leg_opcode = *(uint16_t*)&m_buffer[current];
auto leg_size = *(uint16_t*)&m_buffer[current + 2] - 4;
//this creates a small edge case where the exact size of a
//packet from the modern protocol can't be "43061256"
//so in send we pad it one byte if that's the case
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(ServerNewLSInfo_Struct)) {
m_legacy_mode = true;
m_identifier = "World";
m_parent->ConnectionIdentified(this);
ProcessOldReadBuffer();
return;
}
/*
//header:
//uint32 length;
@@ -129,6 +210,57 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
}
}
void EQ::Net::ServertalkServerConnection::ProcessOldReadBuffer()
{
size_t current = 0;
size_t total = m_buffer.size();
while (current < total) {
auto left = total - current;
/*
//header:
//uint32 length;
//uint8 type;
*/
uint16_t length = 0;
uint16_t opcode = 0;
if (left < 4) {
break;
}
opcode = *(uint16_t*)&m_buffer[current];
length = *(uint16_t*)&m_buffer[current + 2];
if (length < 4) {
break;
}
length -= 4;
if (current + 4 + length > total) {
break;
}
if (length == 0) {
EQ::Net::DynamicPacket p;
ProcessMessageOld(opcode, p);
}
else {
EQ::Net::StaticPacket p(&m_buffer[current + 4], length);
ProcessMessageOld(opcode, p);
}
current += length + 4;
}
if (current == total) {
m_buffer.clear();
}
else {
m_buffer.erase(m_buffer.begin(), m_buffer.begin() + current);
}
}
void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c)
{
m_parent->ConnectionDisconnected(this);
@@ -144,7 +276,7 @@ void EQ::Net::ServertalkServerConnection::SendHello()
void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type, EQ::Net::Packet &p)
{
if (!m_connection)
if (!m_connection || m_legacy_mode)
return;
EQ::Net::DynamicPacket out;
@@ -201,3 +333,20 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
LogError("Error parsing message from client: {0}", ex.what());
}
}
void EQ::Net::ServertalkServerConnection::ProcessMessageOld(uint16_t opcode, EQ::Net::Packet &p)
{
try {
auto cb = m_message_callbacks.find(opcode);
if (cb != m_message_callbacks.end()) {
cb->second(opcode, p);
}
if (m_message_callback) {
m_message_callback(opcode, p);
}
}
catch (std::exception &ex) {
LogError("Error parsing legacy message from client: {0}", ex.what());
}
}
@@ -27,11 +27,13 @@ namespace EQ
private:
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
void ProcessReadBuffer();
void ProcessOldReadBuffer();
void OnDisconnect(TCPConnection* c);
void SendHello();
void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p);
void ProcessHandshake(EQ::Net::Packet &p);
void ProcessMessage(EQ::Net::Packet &p);
void ProcessMessageOld(uint16_t opcode, EQ::Net::Packet &p);
std::shared_ptr<EQ::Net::TCPConnection> m_connection;
ServertalkServer *m_parent;
@@ -41,6 +43,7 @@ namespace EQ
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
std::string m_identifier;
std::string m_uuid;
bool m_legacy_mode;
};
}
}
+3 -2
View File
@@ -5,6 +5,7 @@
#include <map>
#include <unordered_set>
#include <array>
#include "../emu_constants.h"
struct MethodHandlerEntry
{
@@ -174,13 +175,13 @@ Json::Value EQ::Net::WebsocketServer::Login(WebsocketServerConnection *connectio
auto r = _impl->login_handler(connection, user, pass);
if (r.logged_in) {
connection->SetAuthorized(true, r.account_name, r.account_id, 255);
connection->SetAuthorized(true, r.account_name, r.account_id, AccountStatus::Max);
ret["status"] = "Ok";
}
else if (user == "admin" && (connection->RemoteIP() == "127.0.0.1" || connection->RemoteIP() == "::")) {
r.logged_in = true;
r.account_id = 0;
connection->SetAuthorized(true, r.account_name, r.account_id, 255);
connection->SetAuthorized(true, r.account_name, r.account_id, AccountStatus::Max);
ret["status"] = "Ok";
}
else {
+2 -2
View File
@@ -115,8 +115,8 @@ IN(OP_GMTraining, GMTrainee_Struct);
IN(OP_GMEndTraining, GMTrainEnd_Struct);
IN(OP_GMTrainSkill, GMSkillChange_Struct);
IN(OP_RequestDuel, Duel_Struct);
IN(OP_DuelResponse, DuelResponse_Struct);
IN(OP_DuelResponse2, Duel_Struct);
IN(OP_DuelDecline, DuelResponse_Struct);
IN(OP_DuelAccept, Duel_Struct);
IN(OP_SpawnAppearance, SpawnAppearance_Struct);
IN(OP_BazaarInspect, BazaarInspect_Struct);
IN(OP_Death, Death_Struct);
+2 -2
View File
@@ -240,8 +240,8 @@ void load_opcode_names()
opcode_map[0x00a1] = "LiveOP_SaveOnZoneReq";
opcode_map[0x0185] = "LiveOP_Logout";
opcode_map[0x0298] = "LiveOP_RequestDuel";
opcode_map[0x0a5d] = "LiveOP_DuelResponse";
opcode_map[0x016e] = "LiveOP_DuelResponse2";
opcode_map[0x0a5d] = "LiveOP_DuelDecline";
opcode_map[0x016e] = "LiveOP_DuelAccept";
opcode_map[0x007c] = "LiveOP_InstillDoubt";
opcode_map[0x00ac] = "LiveOP_SafeFallSuccess";
opcode_map[0x02fb] = "LiveOP_DisciplineUpdate";
+2 -16
View File
@@ -1634,20 +1634,6 @@ namespace RoF
FINISH_ENCODE();
}
ENCODE(OP_ManaChange)
{
ENCODE_LENGTH_EXACT(ManaChange_Struct);
SETUP_DIRECT_ENCODE(ManaChange_Struct, structs::ManaChange_Struct);
OUT(new_mana);
OUT(stamina);
OUT(spell_id);
OUT(keepcasting);
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
FINISH_ENCODE();
}
ENCODE(OP_MercenaryDataResponse)
{
//consume the packet
@@ -1863,8 +1849,8 @@ namespace RoF
/*fill in some unknowns with observed values, hopefully it will help */
eq->unknown800 = -1;
eq->unknown844 = 600;
eq->unknown880 = 50;
eq->unknown884 = 10;
OUT(LavaDamage);
OUT(MinLavaDamage);
eq->unknown888 = 1;
eq->unknown889 = 0;
eq->unknown890 = 1;
+2 -16
View File
@@ -1683,20 +1683,6 @@ namespace RoF2
FINISH_ENCODE();
}
ENCODE(OP_ManaChange)
{
ENCODE_LENGTH_EXACT(ManaChange_Struct);
SETUP_DIRECT_ENCODE(ManaChange_Struct, structs::ManaChange_Struct);
OUT(new_mana);
OUT(stamina);
OUT(spell_id);
OUT(keepcasting);
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
FINISH_ENCODE();
}
ENCODE(OP_MercenaryDataResponse)
{
//consume the packet
@@ -1919,8 +1905,8 @@ namespace RoF2
eq->SkyRelated2 = -1;
eq->NPCAggroMaxDist = 600;
eq->FilterID = 2008; // Guild Lobby observed value
eq->LavaDamage = 50;
eq->MinLavaDamage = 10;
OUT(LavaDamage);
OUT(MinLavaDamage);
eq->bDisallowManaStone = 1;
eq->bNoBind = 0;
eq->bNoAttack = 0;
-1
View File
@@ -93,7 +93,6 @@ E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MercenaryDataResponse)
E(OP_MercenaryDataUpdate)
E(OP_MoveItem)
+2 -2
View File
@@ -4361,8 +4361,8 @@ struct UseAA_Struct {
struct AA_Ability {
/*00*/ uint32 skill_id;
/*04*/ uint32 base1;
/*08*/ uint32 base2;
/*04*/ uint32 base_value;
/*08*/ uint32 limit_value;
/*12*/ uint32 slot;
/*16*/
};
-1
View File
@@ -79,7 +79,6 @@ E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MercenaryDataResponse)
E(OP_MercenaryDataUpdate)
E(OP_MoveItem)
+4 -4
View File
@@ -581,8 +581,8 @@ struct NewZone_Struct {
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
/*0872*/ uint32 scriptIDSomething3;
/*0876*/ uint32 SuspendBuffs;
/*0880*/ uint32 unknown880; // Seen 50
/*0884*/ uint32 unknown884; // Seen 10
/*0880*/ uint32 LavaDamage; // Seen 50
/*0884*/ uint32 MinLavaDamage; // Seen 10
/*0888*/ uint8 unknown888; // Seen 1
/*0889*/ uint8 unknown889; // Seen 0 (POK) or 1 (rujj)
/*0890*/ uint8 unknown890; // Seen 1
@@ -4305,8 +4305,8 @@ struct UseAA_Struct {
struct AA_Ability {
/*00*/ uint32 skill_id;
/*04*/ uint32 base1;
/*08*/ uint32 base2;
/*04*/ uint32 base_value;
/*08*/ uint32 limit_value;
/*12*/ uint32 slot;
/*16*/
};
+4 -18
View File
@@ -1170,20 +1170,6 @@ namespace SoD
FINISH_ENCODE();
}
ENCODE(OP_ManaChange)
{
ENCODE_LENGTH_EXACT(ManaChange_Struct);
SETUP_DIRECT_ENCODE(ManaChange_Struct, structs::ManaChange_Struct);
OUT(new_mana);
OUT(stamina);
OUT(spell_id);
OUT(keepcasting);
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
FINISH_ENCODE();
}
ENCODE(OP_MercenaryDataResponse)
{
//consume the packet
@@ -1388,8 +1374,8 @@ namespace SoD
/*fill in some unknowns with observed values, hopefully it will help */
eq->unknown800 = -1;
eq->unknown844 = 600;
eq->unknown880 = 50;
eq->unknown884 = 10;
OUT(LavaDamage);
OUT(MinLavaDamage);
eq->unknown888 = 1;
eq->unknown889 = 0;
eq->unknown890 = 1;
@@ -1874,8 +1860,8 @@ namespace SoD
for(auto i = 0; i < eq->total_abilities; ++i) {
eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->abilities[i].base1 = inapp->ReadUInt32();
eq->abilities[i].base2 = inapp->ReadUInt32();
eq->abilities[i].base_value = inapp->ReadUInt32();
eq->abilities[i].limit_value = inapp->ReadUInt32();
eq->abilities[i].slot = inapp->ReadUInt32();
}
-1
View File
@@ -63,7 +63,6 @@ E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MercenaryDataResponse)
E(OP_MercenaryDataUpdate)
E(OP_MoveItem)
+4 -4
View File
@@ -450,8 +450,8 @@ struct NewZone_Struct {
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
/*0872*/ uint32 scriptIDSomething3;
/*0876*/ uint32 SuspendBuffs;
/*0880*/ uint32 unknown880; //seen 50
/*0884*/ uint32 unknown884; //seen 10
/*0880*/ uint32 LavaDamage; //seen 50
/*0884*/ uint32 MinLavaDamage; //seen 10
/*0888*/ uint8 unknown888; //seen 1
/*0889*/ uint8 unknown889; //seen 0 (POK) or 1 (rujj)
/*0890*/ uint8 unknown890; //seen 1
@@ -3748,8 +3748,8 @@ struct UseAA_Struct {
struct AA_Ability {
/*00*/ uint32 skill_id;
/*04*/ uint32 base1;
/*08*/ uint32 base2;
/*04*/ uint32 base_value;
/*08*/ uint32 limit_value;
/*12*/ uint32 slot;
/*16*/
};
+4 -18
View File
@@ -966,20 +966,6 @@ namespace SoF
FINISH_ENCODE();
}
ENCODE(OP_ManaChange)
{
ENCODE_LENGTH_EXACT(ManaChange_Struct);
SETUP_DIRECT_ENCODE(ManaChange_Struct, structs::ManaChange_Struct);
OUT(new_mana);
OUT(stamina);
OUT(spell_id);
OUT(keepcasting);
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
FINISH_ENCODE();
}
ENCODE(OP_MemorizeSpell)
{
ENCODE_LENGTH_EXACT(MemorizeSpell_Struct);
@@ -1066,8 +1052,8 @@ namespace SoF
/*fill in some unknowns with observed values, hopefully it will help */
eq->unknown796 = -1;
eq->unknown840 = 600;
eq->unknown876 = 50;
eq->unknown880 = 10;
OUT(LavaDamage);
OUT(MinLavaDamage);
eq->unknown884 = 1;
eq->unknown885 = 0;
eq->unknown886 = 1;
@@ -1545,8 +1531,8 @@ namespace SoF
for(auto i = 0; i < eq->total_abilities; ++i) {
eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->abilities[i].base1 = inapp->ReadUInt32();
eq->abilities[i].base2 = inapp->ReadUInt32();
eq->abilities[i].base_value = inapp->ReadUInt32();
eq->abilities[i].limit_value = inapp->ReadUInt32();
eq->abilities[i].slot = inapp->ReadUInt32();
}
-1
View File
@@ -59,7 +59,6 @@ E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MemorizeSpell)
E(OP_MoveItem)
E(OP_NewSpawn)
+4 -4
View File
@@ -454,8 +454,8 @@ struct NewZone_Struct {
/*0864*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
/*0868*/ uint32 scriptIDSomething3;
/*0872*/ uint32 SuspendBuffs;
/*0876*/ uint32 unknown876; //seen 50
/*0880*/ uint32 unknown880; //seen 10
/*0876*/ uint32 LavaDamage; //seen 50
/*0880*/ uint32 MinLavaDamage; //seen 10
/*0884*/ uint8 unknown884; //seen 1
/*0885*/ uint8 unknown885; //seen 0 (POK) or 1 (rujj)
/*0886*/ uint8 unknown886; //seen 1
@@ -3673,8 +3673,8 @@ struct UseAA_Struct {
struct AA_Ability {
/*00*/ uint32 skill_id;
/*04*/ uint32 base1;
/*08*/ uint32 base2;
/*04*/ uint32 base_value;
/*08*/ uint32 limit_value;
/*12*/ uint32 slot;
/*16*/
};
+15 -2
View File
@@ -932,6 +932,19 @@ namespace Titanium
FINISH_ENCODE();
}
ENCODE(OP_ManaChange)
{
ENCODE_LENGTH_EXACT(ManaChange_Struct);
SETUP_DIRECT_ENCODE(ManaChange_Struct, structs::ManaChange_Struct);
OUT(new_mana);
OUT(stamina);
OUT(spell_id);
OUT(keepcasting);
FINISH_ENCODE();
}
ENCODE(OP_MemorizeSpell)
{
ENCODE_LENGTH_EXACT(MemorizeSpell_Struct);
@@ -1338,8 +1351,8 @@ namespace Titanium
for(auto i = 0; i < eq->total_abilities; ++i) {
eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->abilities[i].base1 = inapp->ReadUInt32();
eq->abilities[i].base2 = inapp->ReadUInt32();
eq->abilities[i].base_value = inapp->ReadUInt32();
eq->abilities[i].limit_value = inapp->ReadUInt32();
eq->abilities[i].slot = inapp->ReadUInt32();
}
+1
View File
@@ -55,6 +55,7 @@ E(OP_ItemPacket)
E(OP_LeadershipExpUpdate)
E(OP_LFGuild)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MemorizeSpell)
E(OP_MoveItem)
E(OP_OnLevelMessage)
+2 -2
View File
@@ -3180,8 +3180,8 @@ struct UseAA_Struct {
struct AA_Ability {
/*00*/ uint32 skill_id;
/*04*/ uint32 base1;
/*08*/ uint32 base2;
/*04*/ uint32 base_value;
/*08*/ uint32 limit_value;
/*12*/ uint32 slot;
};
+4 -18
View File
@@ -1390,20 +1390,6 @@ namespace UF
FINISH_ENCODE();
}
ENCODE(OP_ManaChange)
{
ENCODE_LENGTH_EXACT(ManaChange_Struct);
SETUP_DIRECT_ENCODE(ManaChange_Struct, structs::ManaChange_Struct);
OUT(new_mana);
OUT(stamina);
OUT(spell_id);
OUT(keepcasting);
eq->slot = -1; // this is spell gem slot. It's -1 in normal operation
FINISH_ENCODE();
}
ENCODE(OP_MercenaryDataResponse)
{
//consume the packet
@@ -1614,8 +1600,8 @@ namespace UF
/*fill in some unknowns with observed values, hopefully it will help */
eq->unknown800 = -1;
eq->unknown844 = 600;
eq->unknown880 = 50;
eq->unknown884 = 10;
OUT(LavaDamage);
OUT(MinLavaDamage);
eq->unknown888 = 1;
eq->unknown889 = 0;
eq->unknown890 = 1;
@@ -2139,8 +2125,8 @@ namespace UF
for(auto i = 0; i < eq->total_abilities; ++i) {
eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->abilities[i].base1 = inapp->ReadUInt32();
eq->abilities[i].base2 = inapp->ReadUInt32();
eq->abilities[i].base_value = inapp->ReadUInt32();
eq->abilities[i].limit_value = inapp->ReadUInt32();
eq->abilities[i].slot = inapp->ReadUInt32();
}
-1
View File
@@ -68,7 +68,6 @@ E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
E(OP_LootItem)
E(OP_ManaChange)
E(OP_MercenaryDataResponse)
E(OP_MercenaryDataUpdate)
E(OP_MoveItem)
+4 -4
View File
@@ -450,8 +450,8 @@ struct NewZone_Struct {
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
/*0872*/ uint32 scriptIDSomething3;
/*0876*/ uint32 SuspendBuffs;
/*0880*/ uint32 unknown880; //seen 50
/*0884*/ uint32 unknown884; //seen 10
/*0880*/ uint32 LavaDamage; //seen 50
/*0884*/ uint32 MinLavaDamage; //seen 10
/*0888*/ uint8 unknown888; //seen 1
/*0889*/ uint8 unknown889; //seen 0 (POK) or 1 (rujj)
/*0890*/ uint8 unknown890; //seen 1
@@ -3803,8 +3803,8 @@ struct UseAA_Struct {
struct AA_Ability {
/*00*/ uint32 skill_id;
/*04*/ uint32 base1;
/*08*/ uint32 base2;
/*04*/ uint32 base_value;
/*08*/ uint32 limit_value;
/*12*/ uint32 slot;
/*16*/
};
+12
View File
@@ -2232,3 +2232,15 @@ bool PlayerAppearance::IsValidWoad(uint16 race_id, uint8 gender_id, uint8 woad_v
}
return false;
}
const char* GetGenderName(uint32 gender_id) {
const char* gender_name = "Unknown";
if (gender_id == MALE) {
gender_name = "Male";
} else if (gender_id == FEMALE) {
gender_name = "Female";
} else if (gender_id == NEUTER) {
gender_name = "Neuter";
}
return gender_name;
}
+9
View File
@@ -851,6 +851,7 @@
const char* GetRaceIDName(uint16 race_id);
const char* GetPlayerRaceName(uint32 player_race_value);
const char* GetGenderName(uint32 gender_id);
uint32 GetPlayerRaceValue(uint16 race_id);
uint32 GetPlayerRaceBit(uint16 race_id);
@@ -1602,6 +1603,14 @@ namespace PlayerAppearance
#define RACE_FALLEN_KNIGHT_722 722
#define RACE_SERVANT_OF_SHADOW_723 723
#define RACE_LUCLIN_724 724
#define RACE_XARIC_725 725
#define RACE_DERVISH_726 726
#define RACE_DERVISH_727 727
#define RACE_LUCLIN_728 728
#define RACE_LUCLIN_729 729
#define RACE_ORB_730 730
#define RACE_LUCLIN_731 731
#define RACE_PEGASUS_732 732
#define RACE_INTERACTIVE_OBJECT_2250 2250
#endif
@@ -148,7 +148,7 @@ public:
entry.zone_in_time = 1800;
entry.win_points = 0;
entry.lose_points = 0;
entry.theme = 1;
entry.theme = LDoNThemes::GUK;
entry.zone_in_zone_id = 0;
entry.zone_in_x = 0;
entry.zone_in_y = 0;
@@ -717,7 +717,7 @@ public:
entry.itemclass = 0;
entry.itemtype = 0;
entry.ldonprice = 0;
entry.ldontheme = 0;
entry.ldontheme = LDoNThemes::Unused;
entry.ldonsold = 0;
entry.light = 0;
entry.lore = "";
@@ -0,0 +1,346 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_TOOL_GAME_OBJECTS_REPOSITORY_H
#define EQEMU_BASE_TOOL_GAME_OBJECTS_REPOSITORY_H
#include "../../database.h"
#include "../../string_util.h"
#include <ctime>
class BaseToolGameObjectsRepository {
public:
struct ToolGameObjects {
int id;
int zoneid;
std::string zonesn;
std::string object_name;
std::string file_from;
int is_global;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"zoneid",
"zonesn",
"object_name",
"file_from",
"is_global",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"zoneid",
"zonesn",
"object_name",
"file_from",
"is_global",
};
}
static std::string ColumnsRaw()
{
return std::string(implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("tool_game_objects");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static ToolGameObjects NewEntity()
{
ToolGameObjects entry{};
entry.id = 0;
entry.zoneid = 0;
entry.zonesn = "";
entry.object_name = "";
entry.file_from = "";
entry.is_global = 0;
return entry;
}
static ToolGameObjects GetToolGameObjectsEntry(
const std::vector<ToolGameObjects> &tool_game_objectss,
int tool_game_objects_id
)
{
for (auto &tool_game_objects : tool_game_objectss) {
if (tool_game_objects.id == tool_game_objects_id) {
return tool_game_objects;
}
}
return NewEntity();
}
static ToolGameObjects FindOne(
Database& db,
int tool_game_objects_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
tool_game_objects_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
ToolGameObjects entry{};
entry.id = atoi(row[0]);
entry.zoneid = atoi(row[1]);
entry.zonesn = row[2] ? row[2] : "";
entry.object_name = row[3] ? row[3] : "";
entry.file_from = row[4] ? row[4] : "";
entry.is_global = atoi(row[5]);
return entry;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int tool_game_objects_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
tool_game_objects_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
ToolGameObjects tool_game_objects_entry
)
{
std::vector<std::string> update_values;
auto columns = Columns();
update_values.push_back(columns[1] + " = " + std::to_string(tool_game_objects_entry.zoneid));
update_values.push_back(columns[2] + " = '" + EscapeString(tool_game_objects_entry.zonesn) + "'");
update_values.push_back(columns[3] + " = '" + EscapeString(tool_game_objects_entry.object_name) + "'");
update_values.push_back(columns[4] + " = '" + EscapeString(tool_game_objects_entry.file_from) + "'");
update_values.push_back(columns[5] + " = " + std::to_string(tool_game_objects_entry.is_global));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
implode(", ", update_values),
PrimaryKey(),
tool_game_objects_entry.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static ToolGameObjects InsertOne(
Database& db,
ToolGameObjects tool_game_objects_entry
)
{
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(tool_game_objects_entry.id));
insert_values.push_back(std::to_string(tool_game_objects_entry.zoneid));
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.zonesn) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.object_name) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.file_from) + "'");
insert_values.push_back(std::to_string(tool_game_objects_entry.is_global));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
implode(",", insert_values)
)
);
if (results.Success()) {
tool_game_objects_entry.id = results.LastInsertedID();
return tool_game_objects_entry;
}
tool_game_objects_entry = NewEntity();
return tool_game_objects_entry;
}
static int InsertMany(
Database& db,
std::vector<ToolGameObjects> tool_game_objects_entries
)
{
std::vector<std::string> insert_chunks;
for (auto &tool_game_objects_entry: tool_game_objects_entries) {
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(tool_game_objects_entry.id));
insert_values.push_back(std::to_string(tool_game_objects_entry.zoneid));
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.zonesn) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.object_name) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.file_from) + "'");
insert_values.push_back(std::to_string(tool_game_objects_entry.is_global));
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
}
std::vector<std::string> insert_values;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<ToolGameObjects> All(Database& db)
{
std::vector<ToolGameObjects> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ToolGameObjects entry{};
entry.id = atoi(row[0]);
entry.zoneid = atoi(row[1]);
entry.zonesn = row[2] ? row[2] : "";
entry.object_name = row[3] ? row[3] : "";
entry.file_from = row[4] ? row[4] : "";
entry.is_global = atoi(row[5]);
all_entries.push_back(entry);
}
return all_entries;
}
static std::vector<ToolGameObjects> GetWhere(Database& db, std::string where_filter)
{
std::vector<ToolGameObjects> 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) {
ToolGameObjects entry{};
entry.id = atoi(row[0]);
entry.zoneid = atoi(row[1]);
entry.zonesn = row[2] ? row[2] : "";
entry.object_name = row[3] ? row[3] : "";
entry.file_from = row[4] ? row[4] : "";
entry.is_global = atoi(row[5]);
all_entries.push_back(entry);
}
return all_entries;
}
static int DeleteWhere(Database& db, 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);
}
};
#endif //EQEMU_BASE_TOOL_GAME_OBJECTS_REPOSITORY_H
@@ -110,6 +110,8 @@ public:
std::string content_flags;
std::string content_flags_disabled;
int underworld_teleport_index;
int lava_damage;
int min_lava_damage;
};
static std::string PrimaryKey()
@@ -212,6 +214,8 @@ public:
"content_flags",
"content_flags_disabled",
"underworld_teleport_index",
"lava_damage",
"min_lava_damage",
};
}
@@ -339,6 +343,8 @@ public:
entry.content_flags = "";
entry.content_flags_disabled = "";
entry.underworld_teleport_index = 0;
entry.lava_damage = 50;
entry.min_lava_damage = 10;
return entry;
}
@@ -466,6 +472,8 @@ public:
entry.content_flags = row[89] ? row[89] : "";
entry.content_flags_disabled = row[90] ? row[90] : "";
entry.underworld_teleport_index = atoi(row[91]);
entry.lava_damage = atoi(row[92]);
entry.min_lava_damage = atoi(row[93]);
return entry;
}
@@ -590,6 +598,8 @@ public:
update_values.push_back(columns[89] + " = '" + EscapeString(zone_entry.content_flags) + "'");
update_values.push_back(columns[90] + " = '" + EscapeString(zone_entry.content_flags_disabled) + "'");
update_values.push_back(columns[91] + " = " + std::to_string(zone_entry.underworld_teleport_index));
update_values.push_back(columns[92] + " = " + std::to_string(zone_entry.lava_damage));
update_values.push_back(columns[93] + " = " + std::to_string(zone_entry.min_lava_damage));
auto results = db.QueryDatabase(
fmt::format(
@@ -703,6 +713,8 @@ public:
insert_values.push_back("'" + EscapeString(zone_entry.content_flags) + "'");
insert_values.push_back("'" + EscapeString(zone_entry.content_flags_disabled) + "'");
insert_values.push_back(std::to_string(zone_entry.underworld_teleport_index));
insert_values.push_back(std::to_string(zone_entry.lava_damage));
insert_values.push_back(std::to_string(zone_entry.min_lava_damage));
auto results = db.QueryDatabase(
fmt::format(
@@ -824,6 +836,8 @@ public:
insert_values.push_back("'" + EscapeString(zone_entry.content_flags) + "'");
insert_values.push_back("'" + EscapeString(zone_entry.content_flags_disabled) + "'");
insert_values.push_back(std::to_string(zone_entry.underworld_teleport_index));
insert_values.push_back(std::to_string(zone_entry.lava_damage));
insert_values.push_back(std::to_string(zone_entry.min_lava_damage));
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
}
@@ -949,6 +963,8 @@ public:
entry.content_flags = row[89] ? row[89] : "";
entry.content_flags_disabled = row[90] ? row[90] : "";
entry.underworld_teleport_index = atoi(row[91]);
entry.lava_damage = atoi(row[92]);
entry.min_lava_damage = atoi(row[93]);
all_entries.push_back(entry);
}
@@ -1065,6 +1081,8 @@ public:
entry.content_flags = row[89] ? row[89] : "";
entry.content_flags_disabled = row[90] ? row[90] : "";
entry.underworld_teleport_index = atoi(row[91]);
entry.lava_damage = atoi(row[92]);
entry.min_lava_damage = atoi(row[93]);
all_entries.push_back(entry);
}
@@ -40,43 +40,48 @@ namespace ContentFilterCriteria {
}
criteria += fmt::format(
" AND ({}min_expansion <= {} OR {}min_expansion = 0)",
" AND ({}min_expansion <= {} OR {}min_expansion = -1)",
table_prefix,
current_expansion_filter_criteria,
table_prefix
);
criteria += fmt::format(
" AND ({}max_expansion >= {} OR {}max_expansion = 0)",
" AND ({}max_expansion >= {} OR {}max_expansion = -1)",
table_prefix,
current_expansion_filter_criteria,
table_prefix
);
std::vector<std::string> flags = content_service.GetContentFlags();
std::vector<std::string> flags_disabled = content_service.GetContentFlagsDisabled();
std::vector<std::string> flags_enabled = content_service.GetContentFlagsEnabled();
std::string flags_in_filter_enabled;
std::string flags_in_filter_disabled;
if (!flags.empty()) {
if (!flags_enabled.empty()) {
flags_in_filter_enabled = fmt::format(
" OR CONCAT(',', {}content_flags, ',') REGEXP ',({}),' ",
table_prefix,
implode("|", flags)
implode("|", flags_enabled)
);
}
if (!flags_disabled.empty()) {
flags_in_filter_disabled = fmt::format(
" OR CONCAT(',', {}content_flags_disabled, ',') NOT REGEXP ',({}),' ",
" OR CONCAT(',', {}content_flags_disabled, ',') REGEXP ',({}),' ",
table_prefix,
implode("|", flags)
implode("|", flags_disabled)
);
}
criteria += fmt::format(
" AND ({}content_flags IS NULL{}) ",
" AND (({}content_flags IS NULL OR {}content_flags = ''){}) ",
table_prefix,
table_prefix,
flags_in_filter_enabled
);
criteria += fmt::format(
" AND ({}content_flags_disabled IS NULL{}) ",
" AND (({}content_flags_disabled IS NULL OR {}content_flags_disabled = ''){}) ",
table_prefix,
table_prefix,
flags_in_filter_disabled
);
@@ -0,0 +1,70 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_TOOL_GAME_OBJECTS_REPOSITORY_H
#define EQEMU_TOOL_GAME_OBJECTS_REPOSITORY_H
#include "../database.h"
#include "../string_util.h"
#include "base/base_tool_game_objects_repository.h"
class ToolGameObjectsRepository: public BaseToolGameObjectsRepository {
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
*
* ToolGameObjectsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* ToolGameObjectsRepository::GetWhereNeverExpires()
* ToolGameObjectsRepository::GetWhereXAndY()
* ToolGameObjectsRepository::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_TOOL_GAME_OBJECTS_REPOSITORY_H
+56 -3
View File
@@ -139,6 +139,7 @@ RULE_INT(Character, TradeskillUpMakePoison, 2, "Make Poison skillup rate adjustm
RULE_INT(Character, TradeskillUpPottery, 4, "Pottery skillup rate adjustment. Lower is faster")
RULE_INT(Character, TradeskillUpResearch, 1, "Research skillup rate adjustment. Lower is faster")
RULE_INT(Character, TradeskillUpTinkering, 2, "Tinkering skillup rate adjustment. Lower is faster")
RULE_INT(Character, TradeskillUpTailoring, 2, "Tailoring skillup rate adjustment. Lower is faster")
RULE_BOOL(Character, MarqueeHPUpdates, false, "Will show health percentage in center of screen if health lesser than 100%")
RULE_INT(Character, IksarCommonTongue, 95, "Starting value for Common Tongue for Iksars")
RULE_INT(Character, OgreCommonTongue, 95, "Starting value for Common Tongue for Ogres")
@@ -167,6 +168,30 @@ RULE_BOOL(Character, EnableCharacterEXPMods, false, "Enables character zone-base
RULE_BOOL(Character, PVPEnableGuardFactionAssist, true, "Enables faction based assisting against the aggresor in pvp.")
RULE_BOOL(Character, SkillUpFromItems, true, "Allow Skill ups from clickable items")
RULE_BOOL(Character, EnableTestBuff, false, "Allow the use of /testbuff")
RULE_BOOL(Character, UseResurrectionSickness, true, "Use Resurrection Sickness based on Resurrection spell cast, set to false to disable Resurrection Sickness.")
RULE_INT(Character, OldResurrectionSicknessSpellID, 757, "757 is Default Old Resurrection Sickness Spell ID")
RULE_INT(Character, ResurrectionSicknessSpellID, 756, "756 is Default Resurrection Sickness Spell ID")
RULE_BOOL(Character, EnableBardMelody, true, "Enable Bard /melody by default, to disable change to false for a classic experience.")
RULE_BOOL(Character, EnableRangerAutoFire, true, "Enable Ranger /autofire by default, to disable change to false for a classic experience.")
RULE_BOOL(Character, EnableTGB, true, "Enable /tgb (Target Group Buff) by default, to disable change to false for a classic experience.")
RULE_INT(Character, SkillUpMaximumChancePercentage, 25, "Maximum chance to improve a combat skill, before skill-specific modifiers. This should be greater than SkillUpMinimumChancePercentage.")
RULE_INT(Character, SkillUpMinimumChancePercentage, 2, "Minimum chance to improve a combat skill, after skill-specific modifiers. This should be lesser than SkillUpMaximumChancePercentage.")
RULE_INT(Character, WarriorTrackingDistanceMultiplier, 0, "If you want warriors to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, ClericTrackingDistanceMultiplier, 0, "If you want clerics to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, PaladinTrackingDistanceMultiplier, 0, "If you want paladins to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, RangerTrackingDistanceMultiplier, 12, "If you want rangers to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, ShadowKnightTrackingDistanceMultiplier, 0, "If you want shadow knights to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, DruidTrackingDistanceMultiplier, 10, "If you want druids to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, MonkTrackingDistanceMultiplier, 0, "If you want monks to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, BardTrackingDistanceMultiplier, 7, "If you want bards to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, RogueTrackingDistanceMultiplier, 0, "If you want rogues to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, ShamanTrackingDistanceMultiplier, 0, "If you want shaman to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, NecromancerTrackingDistanceMultiplier, 0, "If you want necromancers to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, WizardTrackingDistanceMultiplier, 0, "If you want wizards to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, MagicianTrackingDistanceMultiplier, 0, "If you want magicians to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, EnchanterTrackingDistanceMultiplier, 0, "If you want enchanters to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, BeastlordTrackingDistanceMultiplier, 0, "If you want beastlords to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_INT(Character, BerserkerTrackingDistanceMultiplier, 0, "If you want berserkers to be able to track, increase this above 0. 0 disables tracking packets.")
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
@@ -256,10 +281,11 @@ RULE_INT(Zone, ClientLinkdeadMS, 90000, "The time a client remains link dead on
RULE_INT(Zone, GraveyardTimeMS, 1200000, "Time until a player corpse is moved to a zone's graveyard, if one is specified for the zone (milliseconds)")
RULE_BOOL(Zone, EnableShadowrest, 1, "Enables or disables the Shadowrest zone feature for player corpses. Default is turned on")
RULE_INT(Zone, AutoShutdownDelay, 5000, "How long a dynamic zone stays loaded while empty (milliseconds)")
RULE_INT(Zone, PEQZoneReuseTime, 900, "Time between two uses of the #peqzone command (seconds)")
RULE_INT(Zone, PEQZoneReuseTime, 900, "Seconds between two uses of the #peqzone command (Set to 0 to disable)")
RULE_INT(Zone, PEQZoneDebuff1, 4454, "First debuff casted by #peqzone Default is Cursed Keeper's Blight")
RULE_INT(Zone, PEQZoneDebuff2, 2209, "Second debuff casted by #peqzone Default is Tendrils of Apathy")
RULE_BOOL(Zone, UsePEQZoneDebuffs, true, "Setting if the command #peqzone applies the defined debuffs")
RULE_INT(Zone, PEQZoneHPRatio, 75, "Required HP Ratio to use #peqzone")
RULE_REAL(Zone, HotZoneBonus, 0.75, "Value which is added to the experience multiplier. This also applies to AA experience.")
RULE_INT(Zone, EbonCrystalItemID, 40902, "Item ID for Ebon Crystal")
RULE_INT(Zone, RadiantCrystalItemID, 40903, "Item ID for Radiant Crystal")
@@ -319,7 +345,7 @@ RULE_INT(Spells, MaxDiscSlotsNPC, 0, "Maximum number of NPC disc slots. NPC don'
RULE_INT(Spells, MaxTotalSlotsNPC, 60, "Maximum total of NPC slots. The default value is the limit of the Titanium client")
RULE_INT(Spells, MaxTotalSlotsPET, 30, "Maximum total of pet slots. The default value is the limit of the Titanium client")
RULE_BOOL (Spells, EnableBlockedBuffs, true, "Allow blocked spells")
RULE_INT(Spells, ReflectType, 3, "Reflect type. 0=disabled, 1=single target player spells only, 2=all player spells, 3=all single target spells, 4=all spells")
RULE_INT(Spells, ReflectType, 4, "Reflect type. 0=disabled, 1=single target player spells only, 2=all player spells, 3=all single target spells, 4=all spells")
RULE_BOOL(Spells, ReflectMessagesClose, true, "True (Live functionality) is for Reflect messages to show to players within close proximity. False shows just player reflecting")
RULE_INT(Spells, VirusSpreadDistance, 30, "The distance a viral spell will jump to its next victim")
RULE_BOOL(Spells, LiveLikeFocusEffects, true, "Determines whether specific healing, dmg and mana reduction focuses are randomized")
@@ -380,6 +406,10 @@ RULE_BOOL(Spells, PreventFactionWarOnCharmBreak, false, "Enable spell interupts
RULE_BOOL(Spells, AllowDoubleInvis, false, "Allows you to cast invisibility spells on a player that is already invisible")
RULE_BOOL(Spells, AllowSpellMemorizeFromItem, false, "Allows players to memorize spells by right-clicking spell scrolls")
RULE_BOOL(Spells, InvisRequiresGroup, false, "Invis requires the the target to be in group.")
RULE_INT(Spells, ClericInnateHealFocus, 5, "Clerics on live get a 5 pct innate heal focus")
RULE_BOOL(Spells, DOTsScaleWithSpellDmg, false, "Allow SpellDmg stat to affect DoT spells")
RULE_BOOL(Spells, HOTsScaleWithHealAmt, false, "Allow HealAmt stat to affect HoT spells")
RULE_BOOL(Spells, CompoundLifetapHeals, true, "True: Lifetap heals calculate damage bonuses and then heal bonuses. False: Lifetaps heal using the amount damaged to mob.")
RULE_CATEGORY_END()
RULE_CATEGORY(Combat)
@@ -391,7 +421,8 @@ RULE_INT(Combat, ArcheryCritDifficulty, 3400, "Value against which is rolled to
RULE_INT(Combat, ThrowingCritDifficulty, 1100, "Value against which is rolled to check if a throwing crit is triggered. Lower is easier")
RULE_BOOL(Combat, NPCCanCrit, false, "Setting whether an NPC can land critical hits")
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, 30, "Level at which pets can cause magic damage")
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_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")
@@ -477,6 +508,9 @@ RULE_BOOL(Combat, UseExtendedPoisonProcs, false, "Allow old school poisons to la
RULE_BOOL(Combat, EnableSneakPull, false, "Enable implementation of Sneak Pull")
RULE_INT(Combat, SneakPullAssistRange, 400, "Modified range of assist for sneak pull")
RULE_BOOL(Combat, Classic2HBAnimation, false, "2HB will use the 2 hand piercing animation instead of the overhead slashing animation")
RULE_BOOL(Combat, ArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption")
RULE_BOOL(Combat, ThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption")
RULE_BOOL(Combat, UseLiveRiposteMechanics, false, "Set to true to disable SPA 173 SE_RiposteChance from making those with the effect on them immune to enrage, can longer riposte from a riposte.")
RULE_CATEGORY_END()
RULE_CATEGORY(NPC)
@@ -508,6 +542,7 @@ RULE_BOOL(NPC, NPCHealOnGate, true, "Will the NPC Heal on Gate")
RULE_BOOL(NPC, UseMeditateBasedManaRegen, false, "Based NPC ooc regen on Meditate skill")
RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the NPC will heal on gate if enabled")
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_CATEGORY_END()
RULE_CATEGORY(Aggro)
@@ -580,6 +615,10 @@ RULE_REAL(Bots, LeashDistance, 562500.0f, "Distance a bot is allowed to travel f
RULE_BOOL(Bots, AllowApplyPoisonCommand, true, "Allows the use of the bot command 'applypoison'")
RULE_BOOL(Bots, AllowApplyPotionCommand, true, "Allows the use of the bot command 'applypotion'")
RULE_BOOL(Bots, RestrictApplyPotionToRogue, true, "Restricts the bot command 'applypotion' to rogue-usable potions (i.e., poisons)")
RULE_BOOL(Bots, OldRaceRezEffects, false, "Older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore")
RULE_BOOL(Bots, ResurrectionSickness, true, "Use Resurrection Sickness based on Resurrection spell cast, set to false to disable Resurrection Sickness.")
RULE_INT(Bots, OldResurrectionSicknessSpell, 757, "757 is Default Old Resurrection Sickness Spell")
RULE_INT(Bots, ResurrectionSicknessSpell, 756, "756 is Default Resurrection Sickness Spell")
RULE_CATEGORY_END()
#endif
@@ -598,6 +637,10 @@ RULE_INT(Chat, IntervalDurationMS, 60000, "Interval length in milliseconds")
RULE_INT(Chat, KarmaUpdateIntervalMS, 1200000, "Karma update interval in milliseconds")
RULE_INT(Chat, KarmaGlobalChatLimit, 72, "Amount of karma you need to be able to talk in ooc/auction/chat below the level limit")
RULE_INT(Chat, GlobalChatLevelLimit, 8, "Level limit you need to of reached to talk in ooc/auction/chat if your karma is too low")
RULE_BOOL(Chat, AutoInjectSaylinksToSay, true, "Automatically injects saylinks into dialogue that has [brackets in them]")
RULE_BOOL(Chat, AutoInjectSaylinksToClientMessage, true, "Automatically injects saylinks into dialogue that has [brackets in them]")
RULE_BOOL(Chat, QuestDialogueUsesDialogueWindow, false, "Pipes all quest dialogue to dialogue window")
RULE_BOOL(Chat, DialogueWindowAnimatesNPCsIfNoneSet, true, "If there is no animation specified in the dialogue window markdown then it will choose a random greet animation such as wave or salute")
RULE_CATEGORY_END()
RULE_CATEGORY(Merchant)
@@ -703,6 +746,7 @@ RULE_BOOL(Inventory, EnforceAugmentWear, true, "Forces augment wear slot validat
RULE_BOOL(Inventory, DeleteTransformationMold, true, "False if you want mold to last forever")
RULE_BOOL(Inventory, AllowAnyWeaponTransformation, false, "Weapons can use any weapon transformation")
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_CATEGORY_END()
RULE_CATEGORY(Client)
@@ -741,6 +785,7 @@ RULE_CATEGORY_END()
RULE_CATEGORY(Expansion)
RULE_INT(Expansion, CurrentExpansion, -1, "The current expansion enabled for the server [-1 = ALL, 0 = Classic, 1 = Kunark etc.]")
RULE_BOOL(Expansion, UseCurrentExpansionAAOnly, false, "When true will only load AA ranks that match CurrentExpansion rule")
RULE_CATEGORY_END()
RULE_CATEGORY(Instances)
@@ -779,6 +824,14 @@ RULE_BOOL(Cheat, EnableMQFastMemDetector, true, "Enable the MQFastMem Detector.
RULE_BOOL(Cheat, MarkMQWarpLT, false, "Mark clients makeing smaller warps")
RULE_CATEGORY_END()
RULE_CATEGORY(Command)
RULE_BOOL(Command, DyeCommandRequiresDyes, false, "Enable this to require a Prismatic Dye (32557) each time someone uses #dye.")
RULE_CATEGORY_END()
RULE_CATEGORY(Doors)
RULE_BOOL(Doors, RequireKeyOnCursor, false, "Enable this to require pre-keyring keys to be on player cursor to open doors.")
RULE_CATEGORY_END()
#undef RULE_CATEGORY
#undef RULE_INT
#undef RULE_REAL
+205 -37
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
@@ -11,7 +11,7 @@
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@@ -24,7 +24,10 @@
#include "item_instance.h"
#include "item_data.h"
#include "../zone/zonedb.h"
#include <algorithm>
// static bucket global
std::vector<SaylinkRepository::Saylink> g_cached_saylinks = {};
bool EQ::saylink::DegenerateLinkBody(SayLinkBody_Struct &say_link_body_struct, const std::string &say_link_body)
{
@@ -102,13 +105,13 @@ const std::string &EQ::SayLinkEngine::GenerateLink()
m_Link = "<LINKER ERROR>";
LogError("SayLinkEngine::GenerateLink() failed to generate a useable say link");
LogError(">> LinkType: {}, Lengths: [link: {}({}), body: {}({}), text: {}({})]",
m_LinkType,
m_Link.length(),
EQ::constants::SAY_LINK_MAXIMUM_SIZE,
m_LinkBody.length(),
EQ::constants::SAY_LINK_BODY_SIZE,
m_LinkText.length(),
EQ::constants::SAY_LINK_TEXT_SIZE
m_LinkType,
m_Link.length(),
EQ::constants::SAY_LINK_MAXIMUM_SIZE,
m_LinkBody.length(),
EQ::constants::SAY_LINK_BODY_SIZE,
m_LinkText.length(),
EQ::constants::SAY_LINK_TEXT_SIZE
);
LogError(">> LinkBody: {}", m_LinkBody.c_str());
LogError(">> LinkText: {}", m_LinkText.c_str());
@@ -295,33 +298,9 @@ std::string EQ::SayLinkEngine::GenerateQuestSaylink(std::string saylink_text, bo
{
uint32 saylink_id = 0;
/**
* Query for an existing phrase and id in the saylink table
*/
std::string query = StringFormat(
"SELECT `id` FROM `saylink` WHERE `phrase` = '%s' LIMIT 1",
EscapeString(saylink_text).c_str());
auto results = database.QueryDatabase(query);
if (results.Success()) {
if (results.RowCount() >= 1) {
for (auto row = results.begin(); row != results.end(); ++row)
saylink_id = static_cast<uint32>(atoi(row[0]));
}
else {
std::string insert_query = StringFormat(
"INSERT INTO `saylink` (`phrase`) VALUES ('%s')",
EscapeString(saylink_text).c_str());
results = database.QueryDatabase(insert_query);
if (!results.Success()) {
LogError("Error in saylink phrase queries {}", results.ErrorMessage().c_str());
}
else {
saylink_id = results.LastInsertedID();
}
}
SaylinkRepository::Saylink saylink = GetOrSaveSaylink(saylink_text);
if (saylink.id > 0) {
saylink_id = saylink.id;
}
/**
@@ -339,4 +318,193 @@ std::string EQ::SayLinkEngine::GenerateQuestSaylink(std::string saylink_text, bo
linker.SetProxyText(link_name.c_str());
return linker.GenerateLink();
}
}
std::string EQ::SayLinkEngine::InjectSaylinksIfNotExist(const char *message)
{
std::string new_message = message;
int link_index = 0;
int saylink_index = 0;
std::vector<std::string> links = {};
std::vector<std::string> saylinks = {};
int saylink_length = 50;
std::string saylink_separator = "\u0012";
std::string saylink_partial = "00000";
LogSaylinkDetail("new_message pre pass 1 [{}]", new_message);
// first pass - strip existing saylinks by putting placeholder anchors on them
for (auto &saylink: split_string(new_message, saylink_separator)) {
if (!saylink.empty() && saylink.length() > saylink_length &&
saylink.find(saylink_partial) != std::string::npos) {
saylinks.emplace_back(saylink);
LogSaylinkDetail("Found saylink [{}]", saylink);
// replace with anchor
find_replace(
new_message,
fmt::format("{}", saylink),
fmt::format("<saylink:{}>", saylink_index)
);
saylink_index++;
}
}
LogSaylinkDetail("new_message post pass 1 [{}]", new_message);
LogSaylinkDetail("saylink separator count [{}]", std::count(new_message.begin(), new_message.end(), '\u0012'));
// loop through brackets until none exist
if (new_message.find('[') != std::string::npos) {
for (auto &b: split_string(new_message, "[")) {
if (!b.empty() && b.find(']') != std::string::npos) {
std::vector<std::string> right_split = split_string(b, "]");
if (!right_split.empty()) {
std::string bracket_message = trim(right_split[0]);
// we shouldn't see a saylink fragment here, ignore this bracket
if (bracket_message.find(saylink_partial) != std::string::npos) {
continue;
}
// skip where multiple saylinks are within brackets
if (bracket_message.find(saylink_separator) != std::string::npos &&
std::count(bracket_message.begin(), bracket_message.end(), '\u0012') > 1) {
continue;
}
// if non empty bracket contents
if (!bracket_message.empty()) {
LogSaylinkDetail("Found bracket_message [{}]", bracket_message);
// already a saylink
// todo: improve this later
if (!bracket_message.empty() &&
(bracket_message.length() > saylink_length ||
bracket_message.find(saylink_separator) != std::string::npos)) {
links.emplace_back(bracket_message);
}
else {
links.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
bracket_message,
false,
bracket_message
)
);
}
// replace with anchor
find_replace(
new_message,
fmt::format("[{}]", bracket_message),
fmt::format("<prelink:{}>", link_index)
);
link_index++;
}
}
}
}
}
LogSaylinkDetail("new_message post pass 2 (post brackets) [{}]", new_message);
// strip any current delimiters of saylinks
find_replace(new_message, saylink_separator, "");
// pop links onto anchors
link_index = 0;
for (auto &link: links) {
// strip any current delimiters of saylinks
find_replace(link, saylink_separator, "");
find_replace(
new_message,
fmt::format("<prelink:{}>", link_index),
fmt::format("[\u0012{}\u0012]", link)
);
link_index++;
}
LogSaylinkDetail("new_message post pass 3 (post prelink anchor pop) [{}]", new_message);
// pop links onto anchors
saylink_index = 0;
for (auto &link: saylinks) {
// strip any current delimiters of saylinks
find_replace(link, saylink_separator, "");
// check to see if we did a double anchor pass (existing saylink that was also inside brackets)
// this means we found a saylink and we're checking to see if we're already encoded before double encoding
if (new_message.find(fmt::format("\u0012<saylink:{}>\u0012", saylink_index)) != std::string::npos) {
LogSaylinkDetail("Found encoded saylink at index [{}]", saylink_index);
find_replace(
new_message,
fmt::format("\u0012<saylink:{}>\u0012", saylink_index),
fmt::format("\u0012{}\u0012", link)
);
saylink_index++;
continue;
}
find_replace(
new_message,
fmt::format("<saylink:{}>", saylink_index),
fmt::format("\u0012{}\u0012", link)
);
saylink_index++;
}
LogSaylinkDetail("new_message post pass 4 (post saylink anchor pop) [{}]", new_message);
return new_message;
}
void EQ::SayLinkEngine::LoadCachedSaylinks()
{
auto saylinks = SaylinkRepository::GetWhere(database, "phrase not like '%#%'");
LogSaylink("Loaded [{}] saylinks into cache", saylinks.size());
g_cached_saylinks = saylinks;
}
SaylinkRepository::Saylink EQ::SayLinkEngine::GetOrSaveSaylink(std::string saylink_text)
{
// return cached saylink if exist
if (!g_cached_saylinks.empty()) {
for (auto &s: g_cached_saylinks) {
if (s.phrase == saylink_text) {
return s;
}
}
}
auto saylinks = SaylinkRepository::GetWhere(
database,
fmt::format("phrase = '{}'", EscapeString(saylink_text))
);
// return if found from the database
if (!saylinks.empty()) {
return saylinks[0];
}
// if not found in database - save
if (saylinks.empty()) {
auto new_saylink = SaylinkRepository::NewEntity();
new_saylink.phrase = saylink_text;
// persist to database
auto link = SaylinkRepository::InsertOne(database, new_saylink);
if (link.id > 0) {
g_cached_saylinks.emplace_back(link);
return link;
}
}
return {};
}
+7 -4
View File
@@ -1,17 +1,17 @@
/* 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
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@@ -23,7 +23,7 @@
#include "types.h"
#include <string>
#include "repositories/saylink_repository.h"
struct ServerLootItem_Struct;
@@ -105,6 +105,8 @@ namespace EQ
void Reset();
static std::string InjectSaylinksIfNotExist(const char *message);
static void LoadCachedSaylinks();
private:
void generate_body();
void generate_text();
@@ -120,6 +122,7 @@ namespace EQ
std::string m_LinkBody;
std::string m_LinkText;
bool m_Error;
static SaylinkRepository::Saylink GetOrSaveSaylink(std::string saylink_text);
};
} /*EQEmu*/
+189 -594
View File
@@ -226,91 +226,28 @@
#define ServerOP_UCSServerStatusReply 0x4010
#define ServerOP_HotReloadQuests 0x4011
#define ServerOP_UpdateSchedulerEvents 0x4012
#define ServerOP_ReloadContentFlags 0x4013
#define ServerOP_CZCastSpellPlayer 0x4500
#define ServerOP_CZCastSpellGroup 0x4501
#define ServerOP_CZCastSpellRaid 0x4502
#define ServerOP_CZCastSpellGuild 0x4503
#define ServerOP_CZMarqueePlayer 0x4504
#define ServerOP_CZMarqueeGroup 0x4505
#define ServerOP_CZMarqueeRaid 0x4506
#define ServerOP_CZMarqueeGuild 0x4507
#define ServerOP_CZMessagePlayer 0x4508
#define ServerOP_CZMessageGroup 0x4509
#define ServerOP_CZMessageRaid 0x4510
#define ServerOP_CZMessageGuild 0x4511
#define ServerOP_CZMovePlayer 0x4512
#define ServerOP_CZMoveGroup 0x4513
#define ServerOP_CZMoveRaid 0x4514
#define ServerOP_CZMoveGuild 0x4515
#define ServerOP_CZMoveInstancePlayer 0x4516
#define ServerOP_CZMoveInstanceGroup 0x4517
#define ServerOP_CZMoveInstanceRaid 0x4518
#define ServerOP_CZMoveInstanceGuild 0x4519
#define ServerOP_CZRemoveSpellPlayer 0x4520
#define ServerOP_CZRemoveSpellGroup 0x4521
#define ServerOP_CZRemoveSpellRaid 0x4522
#define ServerOP_CZRemoveSpellGuild 0x4523
#define ServerOP_CZSetEntityVariableByClientName 0x4524
#define ServerOP_CZSetEntityVariableByNPCTypeID 0x4525
#define ServerOP_CZSetEntityVariableByGroupID 0x4526
#define ServerOP_CZSetEntityVariableByRaidID 0x4527
#define ServerOP_CZSetEntityVariableByGuildID 0x4528
#define ServerOP_CZSignalClient 0x4529
#define ServerOP_CZSignalClientByName 0x4530
#define ServerOP_CZSignalNPC 0x4531
#define ServerOP_CZSignalGroup 0x4532
#define ServerOP_CZSignalRaid 0x4533
#define ServerOP_CZSignalGuild 0x4534
#define ServerOP_CZTaskActivityResetPlayer 0x4535
#define ServerOP_CZTaskActivityResetGroup 0x4536
#define ServerOP_CZTaskActivityResetRaid 0x4537
#define ServerOP_CZTaskActivityResetGuild 0x4538
#define ServerOP_CZTaskActivityUpdatePlayer 0x4539
#define ServerOP_CZTaskActivityUpdateGroup 0x4540
#define ServerOP_CZTaskActivityUpdateRaid 0x4541
#define ServerOP_CZTaskActivityUpdateGuild 0x4542
#define ServerOP_CZTaskAssignPlayer 0x4543
#define ServerOP_CZTaskAssignGroup 0x4544
#define ServerOP_CZTaskAssignRaid 0x4545
#define ServerOP_CZTaskAssignGuild 0x4546
#define ServerOP_CZTaskDisablePlayer 0x4547
#define ServerOP_CZTaskDisableGroup 0x4548
#define ServerOP_CZTaskDisableRaid 0x4549
#define ServerOP_CZTaskDisableGuild 0x4550
#define ServerOP_CZTaskEnablePlayer 0x4551
#define ServerOP_CZTaskEnableGroup 0x4552
#define ServerOP_CZTaskEnableRaid 0x4553
#define ServerOP_CZTaskEnableGuild 0x4554
#define ServerOP_CZTaskFailPlayer 0x4555
#define ServerOP_CZTaskFailGroup 0x4556
#define ServerOP_CZTaskFailRaid 0x4557
#define ServerOP_CZTaskFailGuild 0x4558
#define ServerOP_CZTaskRemovePlayer 0x4559
#define ServerOP_CZTaskRemoveGroup 0x4560
#define ServerOP_CZTaskRemoveRaid 0x4561
#define ServerOP_CZTaskRemoveGuild 0x4562
#define ServerOP_CZClientMessageString 0x4563
#define ServerOP_CZLDoNUpdate 0x4564
#define ServerOP_CZDialogueWindow 0x4500
#define ServerOP_CZLDoNUpdate 0x4501
#define ServerOP_CZMarquee 0x4502
#define ServerOP_CZMessage 0x4503
#define ServerOP_CZMove 0x4504
#define ServerOP_CZSetEntityVariable 0x4505
#define ServerOP_CZSignal 0x4506
#define ServerOP_CZSpell 0x4507
#define ServerOP_CZTaskUpdate 0x4508
#define ServerOP_CZClientMessageString 0x4509
#define ServerOP_WWAssignTask 0x4750
#define ServerOP_WWCastSpell 0x4751
#define ServerOP_WWCompleteActivity 0x4752
#define ServerOP_WWDisableTask 0x4753
#define ServerOP_WWEnableTask 0x4754
#define ServerOP_WWFailTask 0x4755
#define ServerOP_WWMarquee 0x4756
#define ServerOP_WWMessage 0x4757
#define ServerOP_WWMove 0x4758
#define ServerOP_WWMoveInstance 0x4759
#define ServerOP_WWRemoveSpell 0x4760
#define ServerOP_WWRemoveTask 0x4761
#define ServerOP_WWResetActivity 0x4762
#define ServerOP_WWSetEntityVariableClient 0x4763
#define ServerOP_WWSetEntityVariableNPC 0x4764
#define ServerOP_WWSignalClient 0x4765
#define ServerOP_WWSignalNPC 0x4766
#define ServerOP_WWUpdateActivity 0x4767
#define ServerOP_WWDialogueWindow 0x4750
#define ServerOP_WWLDoNUpdate 0x4751
#define ServerOP_WWMarquee 0x4752
#define ServerOP_WWMessage 0x4753
#define ServerOP_WWMove 0x4754
#define ServerOP_WWSetEntityVariable 0x4755
#define ServerOP_WWSignal 0x4756
#define ServerOP_WWSpell 0x4757
#define ServerOP_WWTaskUpdate 0x4758
/**
* QueryServer
@@ -325,17 +262,79 @@
#define ServerOP_QSPlayerDropItem 0x5007
enum {
CZLDoNUpdateType_Character = 0,
CZLDoNUpdateType_Group,
CZLDoNUpdateType_Raid,
CZLDoNUpdateType_Guild,
CZLDoNUpdateType_Expedition
CZUpdateType_Character,
CZUpdateType_Group,
CZUpdateType_Raid,
CZUpdateType_Guild,
CZUpdateType_Expedition,
CZUpdateType_ClientName,
CZUpdateType_NPC
};
enum {
CZLDoNUpdateSubtype_Win = 0,
CZLDoNUpdateSubtype_Loss,
CZLDoNUpdateSubtype_Points
CZLDoNUpdateSubtype_AddLoss,
CZLDoNUpdateSubtype_AddPoints,
CZLDoNUpdateSubtype_AddWin,
CZLDoNUpdateSubtype_RemoveLoss,
CZLDoNUpdateSubtype_RemoveWin,
};
enum {
CZMoveUpdateSubtype_MoveZone,
CZMoveUpdateSubtype_MoveZoneInstance
};
enum {
CZSpellUpdateSubtype_Cast,
CZSpellUpdateSubtype_Remove
};
enum {
CZTaskUpdateSubtype_ActivityReset,
CZTaskUpdateSubtype_ActivityUpdate,
CZTaskUpdateSubtype_AssignTask,
CZTaskUpdateSubtype_DisableTask,
CZTaskUpdateSubtype_EnableTask,
CZTaskUpdateSubtype_FailTask,
CZTaskUpdateSubtype_RemoveTask
};
enum {
WWLDoNUpdateType_AddLoss,
WWLDoNUpdateType_AddPoints,
WWLDoNUpdateType_AddWin,
WWLDoNUpdateType_RemoveLoss,
WWLDoNUpdateType_RemoveWin
};
enum {
WWMoveUpdateType_MoveZone,
WWMoveUpdateType_MoveZoneInstance
};
enum {
WWSetEntityVariableUpdateType_Character,
WWSetEntityVariableUpdateType_NPC
};
enum {
WWSignalUpdateType_Character,
WWSignalUpdateType_NPC
};
enum {
WWSpellUpdateType_Cast,
WWSpellUpdateType_Remove
};
enum {
WWTaskUpdateType_ActivityReset,
WWTaskUpdateType_ActivityUpdate,
WWTaskUpdateType_AssignTask,
WWTaskUpdateType_DisableTask,
WWTaskUpdateType_EnableTask,
WWTaskUpdateType_FailTask,
WWTaskUpdateType_RemoveTask
};
/* Query Serv Generic Packet Flag/Type Enumeration */
@@ -1440,489 +1439,107 @@ struct QSGeneralQuery_Struct {
char QueryString[0];
};
struct CZCastSpellPlayer_Struct {
int character_id;
uint32 spell_id;
};
struct CZCastSpellGroup_Struct {
int group_id;
uint32 spell_id;
};
struct CZCastSpellRaid_Struct {
int raid_id;
uint32 spell_id;
};
struct CZCastSpellGuild_Struct {
int guild_id;
uint32 spell_id;
};
struct CZClientSignal_Struct {
int character_id;
uint32 signal;
};
struct CZGroupSignal_Struct {
int group_id;
uint32 signal;
};
struct CZRaidSignal_Struct {
int raid_id;
uint32 signal;
};
struct CZGuildSignal_Struct {
int guild_id;
uint32 signal;
};
struct CZNPCSignal_Struct {
uint32 npctype_id;
uint32 signal;
};
struct CZClientMessageString_Struct {
uint32 string_id;
uint16 chat_type;
char character_name[64];
char client_name[64];
uint32 args_size;
char args[1]; // null delimited
};
struct CZClientSignalByName_Struct {
char character_name[64];
uint32 signal;
};
struct CZCompleteActivityPlayer_Struct {
int character_id;
uint32 task_id;
int activity_id;
};
struct CZCompleteActivityGroup_Struct {
int group_id;
uint32 task_id;
int activity_id;
};
struct CZCompleteActivityRaid_Struct {
int raid_id;
uint32 task_id;
int activity_id;
};
struct CZCompleteActivityGuild_Struct {
int guild_id;
uint32 task_id;
int activity_id;
};
struct CZMovePlayer_Struct {
int character_id;
char zone_short_name[32];
};
struct CZMarqueePlayer_Struct {
int character_id;
uint32 type;
uint32 priority;
uint32 fade_in;
uint32 fade_out;
uint32 duration;
char message[512];
};
struct CZMarqueeGroup_Struct {
int group_id;
uint32 type;
uint32 priority;
uint32 fade_in;
uint32 fade_out;
uint32 duration;
char message[512];
};
struct CZMarqueeRaid_Struct {
int raid_id;
uint32 type;
uint32 priority;
uint32 fade_in;
uint32 fade_out;
uint32 duration;
char message[512];
};
struct CZMarqueeGuild_Struct {
int guild_id;
uint32 type;
uint32 priority;
uint32 fade_in;
uint32 fade_out;
uint32 duration;
char message[512];
};
struct CZMessagePlayer_Struct {
uint32 type;
char character_name[64];
char message[512];
};
struct CZMessageGroup_Struct {
uint32 type;
int group_id;
char message[512];
};
struct CZMessageRaid_Struct {
uint32 type;
int raid_id;
char message[512];
};
struct CZMessageGuild_Struct {
uint32 type;
int guild_id;
char message[512];
};
struct CZMoveGroup_Struct {
int group_id;
char zone_short_name[32];
};
struct CZMoveRaid_Struct {
int raid_id;
char zone_short_name[32];
};
struct CZMoveGuild_Struct {
int guild_id;
char zone_short_name[32];
};
struct CZMoveInstancePlayer_Struct {
int character_id;
uint16 instance_id;
};
struct CZMoveInstanceGroup_Struct {
int group_id;
uint16 instance_id;
};
struct CZMoveInstanceRaid_Struct {
int raid_id;
uint16 instance_id;
};
struct CZMoveInstanceGuild_Struct {
int guild_id;
uint16 instance_id;
};
struct CZRemoveSpellPlayer_Struct {
int character_id;
uint32 spell_id;
};
struct CZRemoveSpellGroup_Struct {
int group_id;
uint32 spell_id;
};
struct CZRemoveSpellRaid_Struct {
int raid_id;
uint32 spell_id;
};
struct CZRemoveSpellGuild_Struct {
int guild_id;
uint32 spell_id;
};
struct CZRemoveTaskPlayer_Struct {
int character_id;
uint32 task_id;
};
struct CZRemoveTaskGroup_Struct {
int group_id;
uint32 task_id;
};
struct CZRemoveTaskRaid_Struct {
int raid_id;
uint32 task_id;
};
struct CZRemoveTaskGuild_Struct {
int guild_id;
uint32 task_id;
};
struct CZResetActivityPlayer_Struct {
int character_id;
uint32 task_id;
int activity_id;
};
struct CZResetActivityGroup_Struct {
int group_id;
uint32 task_id;
int activity_id;
};
struct CZResetActivityRaid_Struct {
int raid_id;
uint32 task_id;
int activity_id;
};
struct CZResetActivityGuild_Struct {
int guild_id;
uint32 task_id;
int activity_id;
};
struct CZSetEntVarByNPCTypeID_Struct {
uint32 npctype_id;
char variable_name[256];
char variable_value[256];
};
struct CZSetEntVarByClientName_Struct {
char character_name[64];
char variable_name[256];
char variable_value[256];
};
struct CZSetEntVarByGroupID_Struct {
int group_id;
char variable_name[256];
char variable_value[256];
};
struct CZSetEntVarByRaidID_Struct {
int raid_id;
char variable_name[256];
char variable_value[256];
};
struct CZSetEntVarByGuildID_Struct {
int guild_id;
char variable_name[256];
char variable_value[256];
};
struct CZTaskActivityResetPlayer_Struct {
int character_id;
uint32 task_id;
int activity_id;
};
struct CZTaskActivityResetGroup_Struct {
int group_id;
uint32 task_id;
int activity_id;
};
struct CZTaskActivityResetRaid_Struct {
int raid_id;
uint32 task_id;
int activity_id;
};
struct CZTaskActivityResetGuild_Struct {
int guild_id;
uint32 task_id;
int activity_id;
};
struct CZTaskActivityUpdatePlayer_Struct {
int character_id;
uint32 task_id;
int activity_id;
int activity_count;
};
struct CZTaskActivityUpdateGroup_Struct {
int group_id;
uint32 task_id;
int activity_id;
int activity_count;
};
struct CZTaskActivityUpdateRaid_Struct {
int raid_id;
uint32 task_id;
int activity_id;
int activity_count;
};
struct CZTaskActivityUpdateGuild_Struct {
int guild_id;
uint32 task_id;
int activity_id;
int activity_count;
};
struct CZTaskAssignPlayer_Struct {
uint16 npc_entity_id;
int character_id;
uint32 task_id;
bool enforce_level_requirement;
};
struct CZTaskAssignGroup_Struct {
uint16 npc_entity_id;
int group_id;
uint32 task_id;
bool enforce_level_requirement;
};
struct CZTaskAssignRaid_Struct {
uint16 npc_entity_id;
int raid_id;
uint32 task_id;
bool enforce_level_requirement;
};
struct CZTaskAssignGuild_Struct {
uint16 npc_entity_id;
int guild_id;
uint32 task_id;
bool enforce_level_requirement;
};
struct CZTaskDisablePlayer_Struct {
int character_id;
uint32 task_id;
};
struct CZTaskDisableGroup_Struct {
int group_id;
uint32 task_id;
};
struct CZTaskDisableRaid_Struct {
int raid_id;
uint32 task_id;
};
struct CZTaskDisableGuild_Struct {
int guild_id;
uint32 task_id;
};
struct CZTaskEnablePlayer_Struct {
int character_id;
uint32 task_id;
};
struct CZTaskEnableGroup_Struct {
int group_id;
uint32 task_id;
};
struct CZTaskEnableRaid_Struct {
int raid_id;
uint32 task_id;
};
struct CZTaskEnableGuild_Struct {
int guild_id;
uint32 task_id;
};
struct CZTaskFailPlayer_Struct {
int character_id;
uint32 task_id;
};
struct CZTaskFailGroup_Struct {
int group_id;
uint32 task_id;
};
struct CZTaskFailRaid_Struct {
int raid_id;
uint32 task_id;
};
struct CZTaskFailGuild_Struct {
int guild_id;
uint32 task_id;
};
struct CZTaskRemovePlayer_Struct {
uint16 npc_entity_id;
int character_id;
uint32 task_id;
};
struct CZTaskRemoveGroup_Struct {
uint16 npc_entity_id;
int group_id;
uint32 task_id;
};
struct CZTaskRemoveRaid_Struct {
uint16 npc_entity_id;
int raid_id;
uint32 task_id;
};
struct CZTaskRemoveGuild_Struct {
uint16 npc_entity_id;
int guild_id;
uint32 task_id;
struct CZDialogueWindow_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name
char message[4096];
char client_name[64]; // Only used by Character Name Type, else empty
};
struct CZLDoNUpdate_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition
uint8 update_subtype; // 0 - Win, 1 - Loss, 2 - Points
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name
uint8 update_subtype; // 0 - Loss, 1 - Points, 2 - Win
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name
uint32 theme_id;
int points; // Always 1, except for when Points are used
int points; // Only used in Points Subtype, else 1
char client_name[64]; // Only used by Character Name Type, else empty
};
struct WWAssignTask_Struct {
uint16 npc_entity_id;
uint32 task_id;
bool enforce_level_requirement;
uint8 min_status;
uint8 max_status;
struct CZMarquee_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name
uint32 type;
uint32 priority;
uint32 fade_in;
uint32 fade_out;
uint32 duration;
char message[512];
char client_name[64]; // Only used by Character Name Type, else empty
};
struct WWCastSpell_Struct {
struct CZMessage_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name
int update_identifier; // Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name
uint32 type;
char message[512];
char client_name[64]; // Only used by Character Name Type, else empty
};
struct CZMove_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name
uint8 update_subtype; // 0 - Move Zone, 1 - Move Zone Instance
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name
uint16 instance_id; // Only used by Move Zone Instance, else 0
char zone_short_name[32]; // Only by with Move Zone, else empty
char client_name[64]; // Only used by Character Name Type, else empty
};
struct CZSetEntityVariable_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name, 6 - NPC
int update_identifier; // Group ID, Raid ID, Guild ID, Expedition ID, or NPC ID based on update type, 0 for Character Name
char variable_name[256];
char variable_value[256];
char client_name[64]; // Only used by Character Type, else empty
};
struct CZSignal_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name, 6 - NPC
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, Expedition ID, or NPC ID based on update type, 0 for Character Name
uint32 signal;
char client_name[64]; // Only used by Character Name Type, else empty
};
struct CZSpell_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name
uint8 update_subtype; // 0 - Cast Spell, 1 - Remove Spell
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name
uint32 spell_id;
char client_name[64]; // Only used by Character Name Type, else empty
};
struct CZTaskUpdate_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name
uint8 update_subtype; // 0 - Activity Reset, 1 - Activity Update, 2 - Assign Task, 3 - Disable Task, 4 - Enable Task, 5 - Fail Task, 6 - Remove Task
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name
uint32 task_identifier;
int task_subidentifier; // Activity ID for Activity Reset and Activity Update, NPC Entity ID for Assign Task, else -1
int update_count; // Only used by Activity Update, else 1
bool enforce_level_requirement; // Only used by Assign Task
char client_name[64]; // Only used by Character Name Type, else empty
};
struct WWDialogueWindow_Struct {
char message[4096];
uint8 min_status;
uint8 max_status;
};
struct WWDisableTask_Struct {
uint32 task_id;
struct WWLDoNUpdate_Struct {
uint8 update_type; // 0 - Loss, 1 - Points, 2 - Win
uint32 theme_id;
int points; // Only used in Points Subtype, else 1
uint8 min_status;
uint8 max_status;
};
struct WWEnableTask_Struct {
uint32 task_id;
uint8 min_status;
uint8 max_status;
};
struct WWFailTask_Struct {
uint32 task_id;
uint8 min_status;
uint8 max_status;
};
struct WWMarquee_Struct {
uint32 type;
uint32 priority;
@@ -1942,63 +1559,41 @@ struct WWMessage_Struct {
};
struct WWMove_Struct {
char zone_short_name[32];
uint8 update_type; // 0 - Move Zone, 1 - Move Zone Instance
char zone_short_name[32]; // Used with Move Zone
uint16 instance_id; // Used with Move Zone Instance
uint8 min_status;
uint8 max_status;
};
struct WWMoveInstance_Struct {
uint16 instance_id;
struct WWSetEntityVariable_Struct {
uint8 update_type; // 0 - Character, 1 - NPC
char variable_name[256];
char variable_value[256];
uint8 min_status;
uint8 max_status;
};
struct WWRemoveSpell_Struct {
struct WWSignal_Struct {
uint8 update_type; // 0 - Character, 1 - NPC
uint32 signal;
uint8 min_status;
uint8 max_status;
};
struct WWSpell_Struct {
uint8 update_type; // 0 - Cast Spell, 1 - Remove Spell
uint32 spell_id;
uint8 min_status;
uint8 max_status;
};
struct WWRemoveTask_Struct {
uint32 task_id;
uint8 min_status;
uint8 max_status;
};
struct WWResetActivity_Struct {
uint32 task_id;
int activity_id;
uint8 min_status;
uint8 max_status;
};
struct WWSetEntVarClient_Struct {
char variable_name[256];
char variable_value[256];
uint8 min_status;
uint8 max_status;
};
struct WWSetEntVarNPC_Struct {
char variable_name[256];
char variable_value[256];
};
struct WWSignalClient_Struct {
uint32 signal;
uint8 min_status;
uint8 max_status;
};
struct WWSignalNPC_Struct {
uint32 signal;
};
struct WWUpdateActivity_Struct {
uint32 task_id;
int activity_id;
int activity_count;
struct WWTaskUpdate_Struct {
uint8 update_type; // 0 - Activity Reset, 1 - Activity Update, 2 - Assign Task, 3 - Disable Task, 4 - Enable Task, 5 - Fail Task, 6 - Remove Task
uint32 task_identifier;
int task_subidentifier; // Activity ID for Activity Reset and Activity Update, NPC Entity ID for Assign Task, else -1
int update_count; // Update Count for Activity Update, else 1
bool enforce_level_requirement; // Only used by Assign Task, else false
uint8 min_status;
uint8 max_status;
};
+59 -58
View File
@@ -1118,7 +1118,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
item.Haste = (uint32)atoul(row[ItemField::haste]);
item.DamageShield = (uint32)atoul(row[ItemField::damageshield]);
item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]);
item.RecastType = (uint32)atoul(row[ItemField::recasttype]);
item.RecastType = (int)atoi(row[ItemField::recasttype]);
item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]);
item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]);
item.Attuneable = (atoi(row[ItemField::attuneable]) == 0) ? false : true;
@@ -1682,7 +1682,7 @@ void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpe
for(auto row = results.begin(); row != results.end(); ++row) {
int spellID = atoi(row[0]);
if((spellID > 0) && (spellID <= iMaxSpellID))
sp[spellID].DamageShieldType = atoi(row[1]);
sp[spellID].damage_shield_type = atoi(row[1]);
}
}
@@ -1762,48 +1762,48 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
strn0cpy(sp[tempid].spell_fades, row[8], sizeof(sp[tempid].spell_fades));
sp[tempid].range=static_cast<float>(atof(row[9]));
sp[tempid].aoerange=static_cast<float>(atof(row[10]));
sp[tempid].pushback=static_cast<float>(atof(row[11]));
sp[tempid].pushup=static_cast<float>(atof(row[12]));
sp[tempid].aoe_range=static_cast<float>(atof(row[10]));
sp[tempid].push_back=static_cast<float>(atof(row[11]));
sp[tempid].push_up=static_cast<float>(atof(row[12]));
sp[tempid].cast_time=atoi(row[13]);
sp[tempid].recovery_time=atoi(row[14]);
sp[tempid].recast_time=atoi(row[15]);
sp[tempid].buffdurationformula=atoi(row[16]);
sp[tempid].buffduration=atoi(row[17]);
sp[tempid].AEDuration=atoi(row[18]);
sp[tempid].buff_duration_formula=atoi(row[16]);
sp[tempid].buff_duration=atoi(row[17]);
sp[tempid].aoe_duration=atoi(row[18]);
sp[tempid].mana=atoi(row[19]);
int y=0;
for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].base[y]=atoi(row[20+y]); // effect_base_value
sp[tempid].base_value[y]=atoi(row[20+y]); // effect_base_value
for(y=0; y < EFFECT_COUNT; y++)
sp[tempid].base2[y]=atoi(row[32+y]); // effect_limit_value
sp[tempid].limit_value[y]=atoi(row[32+y]); // effect_limit_value
for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].max[y]=atoi(row[44+y]);
sp[tempid].max_value[y]=atoi(row[44+y]);
for(y=0; y< 4;y++)
sp[tempid].components[y]=atoi(row[58+y]);
sp[tempid].component[y]=atoi(row[58+y]);
for(y=0; y< 4;y++)
sp[tempid].component_counts[y]=atoi(row[62+y]);
sp[tempid].component_count[y]=atoi(row[62+y]);
for(y=0; y< 4;y++)
sp[tempid].NoexpendReagent[y]=atoi(row[66+y]);
sp[tempid].no_expend_reagent[y]=atoi(row[66+y]);
for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].formula[y]=atoi(row[70+y]);
sp[tempid].goodEffect=atoi(row[83]);
sp[tempid].Activated=atoi(row[84]);
sp[tempid].resisttype=atoi(row[85]);
sp[tempid].good_effect=atoi(row[83]);
sp[tempid].activated=atoi(row[84]);
sp[tempid].resist_type=atoi(row[85]);
for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].effectid[y]=atoi(row[86+y]);
sp[tempid].effect_id[y]=atoi(row[86+y]);
sp[tempid].targettype = (SpellTargetType) atoi(row[98]);
sp[tempid].basediff=atoi(row[99]);
sp[tempid].target_type = (SpellTargetType) atoi(row[98]);
sp[tempid].base_difficulty=atoi(row[99]);
int tmp_skill = atoi(row[100]);;
@@ -1812,15 +1812,15 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
else
sp[tempid].skill = (EQ::skills::SkillType) tmp_skill;
sp[tempid].zonetype=atoi(row[101]);
sp[tempid].EnvironmentType=atoi(row[102]);
sp[tempid].TimeOfDay=atoi(row[103]);
sp[tempid].zone_type=atoi(row[101]);
sp[tempid].environment_type=atoi(row[102]);
sp[tempid].time_of_day=atoi(row[103]);
for(y=0; y < PLAYER_CLASS_COUNT;y++)
sp[tempid].classes[y]=atoi(row[104+y]);
sp[tempid].CastingAnim=atoi(row[120]);
sp[tempid].SpellAffectIndex=atoi(row[123]);
sp[tempid].casting_animation=atoi(row[120]);
sp[tempid].spell_affect_index=atoi(row[123]);
sp[tempid].disallow_sit=atoi(row[124]);
sp[tempid].deity_agnostic=atoi(row[125]);
@@ -1829,31 +1829,32 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].new_icon=atoi(row[144]);
sp[tempid].uninterruptable=atoi(row[146]) != 0;
sp[tempid].ResistDiff=atoi(row[147]);
sp[tempid].dot_stacking_exempt = atoi(row[148]) != 0;
sp[tempid].RecourseLink = atoi(row[150]);
sp[tempid].resist_difficulty=atoi(row[147]);
sp[tempid].unstackable_dot = atoi(row[148]) != 0;
sp[tempid].recourse_link = atoi(row[150]);
sp[tempid].no_partial_resist = atoi(row[151]) != 0;
sp[tempid].short_buff_box = atoi(row[154]);
sp[tempid].descnum = atoi(row[155]);
sp[tempid].typedescnum = atoi(row[156]);
sp[tempid].effectdescnum = atoi(row[157]);
sp[tempid].description_id = atoi(row[155]);
sp[tempid].type_description_id = atoi(row[156]);
sp[tempid].effect_description_id = atoi(row[157]);
sp[tempid].npc_no_los = atoi(row[159]) != 0;
sp[tempid].feedbackable = atoi(row[160]) != 0;
sp[tempid].reflectable = atoi(row[161]) != 0;
sp[tempid].bonushate=atoi(row[162]);
sp[tempid].bonus_hate=atoi(row[162]);
sp[tempid].ldon_trap = atoi(row[165]) != 0;
sp[tempid].EndurCost=atoi(row[166]);
sp[tempid].EndurTimerIndex=atoi(row[167]);
sp[tempid].IsDisciplineBuff = atoi(row[168]) != 0;
sp[tempid].HateAdded=atoi(row[173]);
sp[tempid].EndurUpkeep=atoi(row[174]);
sp[tempid].numhitstype = atoi(row[175]);
sp[tempid].numhits = atoi(row[176]);
sp[tempid].pvpresistbase=atoi(row[177]);
sp[tempid].pvpresistcalc=atoi(row[178]);
sp[tempid].pvpresistcap=atoi(row[179]);
sp[tempid].endurance_cost=atoi(row[166]);
sp[tempid].timer_id=atoi(row[167]);
sp[tempid].is_discipline = atoi(row[168]) != 0;
sp[tempid].hate_added=atoi(row[173]);
sp[tempid].endurance_upkeep=atoi(row[174]);
sp[tempid].hit_number_type = atoi(row[175]);
sp[tempid].hit_number = atoi(row[176]);
sp[tempid].pvp_resist_base=atoi(row[177]);
sp[tempid].pvp_resist_per_level=atoi(row[178]);
sp[tempid].pvp_resist_cap=atoi(row[179]);
sp[tempid].spell_category=atoi(row[180]);
sp[tempid].pvp_duration = atoi(row[181]);
sp[tempid].pvp_duration_cap = atoi(row[182]);
@@ -1861,11 +1862,11 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].cast_not_standing = atoi(row[184]) != 0;
sp[tempid].can_mgb=atoi(row[185]);
sp[tempid].dispel_flag = atoi(row[186]);
sp[tempid].MinResist = atoi(row[189]);
sp[tempid].MaxResist = atoi(row[190]);
sp[tempid].min_resist = atoi(row[189]);
sp[tempid].max_resist = atoi(row[190]);
sp[tempid].viral_targets = atoi(row[191]);
sp[tempid].viral_timer = atoi(row[192]);
sp[tempid].NimbusEffect = atoi(row[193]);
sp[tempid].nimbus_effect = atoi(row[193]);
sp[tempid].directional_start = static_cast<float>(atoi(row[194]));
sp[tempid].directional_end = static_cast<float>(atoi(row[195]));
sp[tempid].sneak = atoi(row[196]) != 0;
@@ -1873,29 +1874,29 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].no_detrimental_spell_aggro = atoi(row[198]) != 0;
sp[tempid].suspendable = atoi(row[200]) != 0;
sp[tempid].viral_range = atoi(row[201]);
sp[tempid].songcap = atoi(row[202]);
sp[tempid].song_cap = atoi(row[202]);
sp[tempid].no_block = atoi(row[205]);
sp[tempid].spellgroup=atoi(row[207]);
sp[tempid].spell_group=atoi(row[207]);
sp[tempid].rank = atoi(row[208]);
sp[tempid].no_resist=atoi(row[209]);
sp[tempid].CastRestriction = atoi(row[211]);
sp[tempid].AllowRest = atoi(row[212]) != 0;
sp[tempid].InCombat = atoi(row[213]) != 0;
sp[tempid].OutofCombat = atoi(row[214]) != 0;
sp[tempid].cast_restriction = atoi(row[211]);
sp[tempid].allow_rest = atoi(row[212]) != 0;
sp[tempid].can_cast_in_combat = atoi(row[213]) != 0;
sp[tempid].can_cast_out_of_combat = atoi(row[214]) != 0;
sp[tempid].override_crit_chance = atoi(row[217]);
sp[tempid].aemaxtargets = atoi(row[218]);
sp[tempid].aoe_max_targets = atoi(row[218]);
sp[tempid].no_heal_damage_item_mod = atoi(row[219]);
sp[tempid].caster_requirement_id = atoi(row[220]);
sp[tempid].spell_class = atoi(row[221]);
sp[tempid].spell_subclass = atoi(row[222]);
sp[tempid].persistdeath = atoi(row[224]) != 0;
sp[tempid].min_dist = atof(row[227]);
sp[tempid].min_dist_mod = atof(row[228]);
sp[tempid].max_dist = atof(row[229]);
sp[tempid].max_dist_mod = atof(row[230]);
sp[tempid].persist_death = atoi(row[224]) != 0;
sp[tempid].min_distance = atof(row[227]);
sp[tempid].min_distance_mod = atof(row[228]);
sp[tempid].max_distance = atof(row[229]);
sp[tempid].max_distance_mod = atof(row[230]);
sp[tempid].min_range = static_cast<float>(atoi(row[231]));
sp[tempid].no_remove = atoi(row[232]) != 0;
sp[tempid].DamageShieldType = 0;
sp[tempid].damage_shield_type = 0;
}
LoadDamageShieldTypes(sp, max_spells);
+10 -96
View File
@@ -177,8 +177,7 @@ bool EQ::skills::IsMeleeDmg(SkillType skill)
const std::map<EQ::skills::SkillType, std::string>& EQ::skills::GetSkillTypeMap()
{
/* VS2013 code
static const std::map<SkillUseTypes, std::string> skill_use_types_map = {
static const std::map<SkillType, std::string> skill_type_map = {
{ Skill1HBlunt, "1H Blunt" },
{ Skill1HSlashing, "1H Slashing" },
{ Skill2HBlunt, "2H Blunt" },
@@ -258,103 +257,18 @@ const std::map<EQ::skills::SkillType, std::string>& EQ::skills::GetSkillTypeMap(
{ SkillTripleAttack, "Triple Attack" },
{ Skill2HPiercing, "2H Piercing" }
};
*/
/* VS2012 code - begin */
static const char* skill_use_names[SkillCount] = {
"1H Blunt",
"1H Slashing",
"2H Blunt",
"2H Slashing",
"Abjuration",
"Alteration",
"Apply Poison",
"Archery",
"Backstab",
"Bind Wound",
"Bash",
"Block",
"Brass Instruments",
"Channeling",
"Conjuration",
"Defense",
"Disarm",
"Disarm Traps",
"Divination",
"Dodge",
"Double Attack",
"Dragon Punch",
"Dual Wield",
"Eagle Strike",
"Evocation",
"Feign Death",
"Flying Kick",
"Forage",
"Hand to Hand",
"Hide",
"Kick",
"Meditate",
"Mend",
"Offense",
"Parry",
"Pick Lock",
"1H Piercing",
"Riposte",
"Round Kick",
"Safe Fall",
"Sense Heading",
"Singing",
"Sneak",
"Specialize Abjuration",
"Specialize Alteration",
"Specialize Conjuration",
"Specialize Divination",
"Specialize Evocation",
"Pick Pockets",
"Stringed Instruments",
"Swimming",
"Throwing",
"Tiger Claw",
"Tracking",
"Wind Instruments",
"Fishing",
"Make Poison",
"Tinkering",
"Research",
"Alchemy",
"Baking",
"Tailoring",
"Sense Traps",
"Blacksmithing",
"Fletching",
"Brewing",
"Alcohol Tolerance",
"Begging",
"Jewelry Making",
"Pottery",
"Percussion Instruments",
"Intimidation",
"Berserking",
"Taunt",
"Frenzy",
"Remove Traps",
"Triple Attack",
"2H Piercing"
};
static std::map<SkillType, std::string> skill_type_map;
skill_type_map.clear();
for (int i = Skill1HBlunt; i < SkillCount; ++i)
skill_type_map[(SkillType)i] = skill_use_names[i];
/* VS2012 code - end */
return skill_type_map;
}
std::string EQ::skills::GetSkillName(SkillType skill)
{
if (skill >= Skill1HBlunt && skill <= Skill2HPiercing) {
auto skills = GetSkillTypeMap();
return skills[skill];
}
return std::string();
}
EQ::SkillProfile::SkillProfile()
{
memset(&Skill, 0, (sizeof(uint32) * PACKET_SKILL_ARRAY_SIZE));
+1
View File
@@ -171,6 +171,7 @@ namespace EQ
extern const std::map<SkillType, std::string>& GetSkillTypeMap();
std::string GetSkillName(SkillType skill);
} /*skills*/
struct SkillProfile { // prototype - not implemented
+395 -165
View File
File diff suppressed because it is too large Load Diff
+411 -362
View File
File diff suppressed because it is too large Load Diff
+801 -146
View File
File diff suppressed because it is too large Load Diff
+10
View File
@@ -45,6 +45,11 @@ std::vector<std::string> wrap(std::vector<std::string> &src, std::string charact
std::string implode(std::string glue, std::vector<std::string> src);
std::string convert2digit(int n, std::string suffix);
std::string numberToWords(unsigned long long int n);
std::string ConvertMoneyToString(uint32 platinum, uint32 gold = 0, uint32 silver = 0, uint32 copper = 0);
std::string ConvertSecondsToTime(int duration, bool is_milliseconds = false);
inline std::string ConvertMillisecondsToTime(int duration) {
return ConvertSecondsToTime(duration, true);
}
// For converstion of numerics into English
// Used for grid nodes, as NPC names remove numerals.
@@ -208,6 +213,11 @@ void RemoveApostrophes(std::string &s);
std::string convert2digit(int n, std::string suffix);
std::string numberToWords(unsigned long long int n);
std::string FormatName(const std::string& char_name);
bool IsAllowedWorldServerCharacterList(char c);
void SanitizeWorldServerName(char *name);
std::string SanitizeWorldServerName(std::string server_long_name);
std::string repeat(std::string s, int n);
std::vector<std::string> GetBadWords();
template<typename InputIterator, typename OutputIterator>
auto CleanMobName(InputIterator first, InputIterator last, OutputIterator result)
+1 -1
View File
@@ -34,7 +34,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9172
#define CURRENT_BINARY_DATABASE_VERSION 9175
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9028
+1 -1
View File
@@ -22,7 +22,7 @@ SET(eqlogin_headers
loginserver_command_handler.h
loginserver_webserver.h
login_server.h
login_structures.h
login_types.h
options.h
server_manager.h
world_server.h
+138 -30
View File
@@ -1,28 +1,9 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "account_management.h"
#include "login_server.h"
#include "../common/event/task_scheduler.h"
#include "../common/event/event_loop.h"
#include "../common/net/dns.h"
#include "../common/string_util.h"
extern LoginServer server;
EQ::Event::TaskScheduler task_runner;
@@ -300,6 +281,8 @@ bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordById(
return updated_account;
}
constexpr int REQUEST_TIMEOUT_MS = 1500;
/**
* @param in_account_username
* @param in_account_password
@@ -395,19 +378,33 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
}
);
EQ::Net::DNSLookup(
"login.eqemulator.net", 5999, false, [&](const std::string &addr) {
if (addr.empty()) {
ret = 0;
running = false;
}
auto s = SplitString(server.options.GetEQEmuLoginServerAddress(), ':');
if (s.size() == 2) {
auto address = s[0];
auto port = std::stoi(s[1]);
mgr.Connect(addr, 5999);
}
);
EQ::Net::DNSLookup(
address, port, false, [&](const std::string &addr) {
if (addr.empty()) {
ret = 0;
running = false;
}
mgr.Connect(addr, port);
}
);
}
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
auto &loop = EQ::EventLoop::Get();
while (running) {
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > REQUEST_TIMEOUT_MS) {
LogInfo("[CheckExternalLoginserverUserCredentials] Deadline exceeded [{}]", REQUEST_TIMEOUT_MS);
running = false;
}
loop.Process();
}
@@ -416,4 +413,115 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
);
return res.get();
}
}
uint32 AccountManagement::HealthCheckUserLogin()
{
std::string in_account_username = "healthcheckuser";
std::string in_account_password = "healthcheckpassword";
auto res = task_runner.Enqueue(
[&]() -> uint32 {
bool running = true;
uint32 ret = 0;
EQ::Net::DaybreakConnectionManager mgr;
std::shared_ptr<EQ::Net::DaybreakConnection> c;
mgr.OnNewConnection(
[&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
c = connection;
}
);
mgr.OnConnectionStateChange(
[&](
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
EQ::Net::DbProtocolStatus from,
EQ::Net::DbProtocolStatus to
) {
if (EQ::Net::StatusConnected == to) {
EQ::Net::DynamicPacket p;
p.PutUInt16(0, 1); //OP_SessionReady
p.PutUInt32(2, 2);
c->QueuePacket(p);
}
else if (EQ::Net::StatusDisconnected == to) {
running = false;
}
}
);
mgr.OnPacketRecv(
[&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p) {
auto opcode = p.GetUInt16(0);
switch (opcode) {
case 0x0017: //OP_ChatMessage
{
size_t buffer_len =
in_account_username.length() + in_account_password.length() + 2;
std::unique_ptr<char[]> buffer(new char[buffer_len]);
strcpy(&buffer[0], in_account_username.c_str());
strcpy(&buffer[in_account_username.length() + 1], in_account_password.c_str());
size_t encrypted_len = buffer_len;
if (encrypted_len % 8 > 0) {
encrypted_len = ((encrypted_len / 8) + 1) * 8;
}
EQ::Net::DynamicPacket p;
p.Resize(12 + encrypted_len);
p.PutUInt16(0, 2); //OP_Login
p.PutUInt32(2, 3);
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
c->QueuePacket(p);
break;
}
case 0x0018: {
auto encrypt_size = p.Length() - 12;
if (encrypt_size % 8 > 0) {
encrypt_size = (encrypt_size / 8) * 8;
}
std::unique_ptr<char[]> decrypted(new char[encrypt_size]);
eqcrypt_block((char *) p.Data() + 12, encrypt_size, &decrypted[0], false);
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
auto response_error = sp.GetUInt16(1);
{
// we only care to see the response code
ret = response_error;
running = false;
}
break;
}
}
}
);
mgr.Connect("127.0.0.1", 5999);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
auto &loop = EQ::EventLoop::Get();
while (running) {
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 2000) {
ret = 0;
running = false;
}
loop.Process();
}
return ret;
}
);
return res.get();
}
+2 -19
View File
@@ -1,22 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_ACCOUNT_MANAGEMENT_H
#define EQEMU_ACCOUNT_MANAGEMENT_H
@@ -108,6 +89,8 @@ public:
uint32 in_account_id,
const std::string &in_account_password_hash
);
static uint32 HealthCheckUserLogin();
};
+150 -199
View File
@@ -1,29 +1,10 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "client.h"
#include "login_server.h"
#include "../common/misc_functions.h"
#include "../common/eqemu_logsys.h"
#include "../common/string_util.h"
#include "encryption.h"
#include "account_management.h"
extern LoginServer server;
@@ -33,17 +14,17 @@ extern LoginServer server;
*/
Client::Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v)
{
connection = c;
version = v;
status = cs_not_sent_session_ready;
account_id = 0;
play_server_id = 0;
play_sequence_id = 0;
m_connection = c;
m_client_version = v;
m_client_status = cs_not_sent_session_ready;
m_account_id = 0;
m_play_server_id = 0;
m_play_sequence_id = 0;
}
bool Client::Process()
{
EQApplicationPacket *app = connection->PopPacket();
EQApplicationPacket *app = m_connection->PopPacket();
while (app) {
if (server.options.IsTraceOn()) {
LogDebug("Application packet received from client (size {0})", app->Size());
@@ -53,9 +34,9 @@ bool Client::Process()
DumpPacket(app);
}
if (status == cs_failed_to_login) {
if (m_client_status == cs_failed_to_login) {
delete app;
app = connection->PopPacket();
app = m_connection->PopPacket();
continue;
}
@@ -112,7 +93,7 @@ bool Client::Process()
}
delete app;
app = connection->PopPacket();
app = m_connection->PopPacket();
}
return true;
@@ -126,7 +107,7 @@ bool Client::Process()
*/
void Client::Handle_SessionReady(const char *data, unsigned int size)
{
if (status != cs_not_sent_session_ready) {
if (m_client_status != cs_not_sent_session_ready) {
LogError("Session ready received again after already being received");
return;
}
@@ -136,39 +117,23 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
return;
}
status = cs_waiting_for_login;
m_client_status = cs_waiting_for_login;
/**
* The packets are mostly the same but slightly different between the two versions
* The packets are identical between the two versions
*/
if (version == cv_sod) {
auto *outapp = new EQApplicationPacket(OP_ChatMessage, 17);
outapp->pBuffer[0] = 0x02;
outapp->pBuffer[10] = 0x01;
outapp->pBuffer[11] = 0x65;
auto *outapp = new EQApplicationPacket(OP_ChatMessage, sizeof(LoginHandShakeReply_Struct));
auto buf = reinterpret_cast<LoginHandShakeReply_Struct*>(outapp->pBuffer);
buf->base_header.sequence = 0x02;
buf->base_reply.success = true;
buf->base_reply.error_str_id = 0x65; // 101 "No Error"
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
connection->QueuePacket(outapp);
delete outapp;
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
else {
const char *msg = "ChatMessage";
auto *outapp = new EQApplicationPacket(OP_ChatMessage, 16 + strlen(msg));
outapp->pBuffer[0] = 0x02;
outapp->pBuffer[10] = 0x01;
outapp->pBuffer[11] = 0x65;
strcpy((char *) (outapp->pBuffer + 15), msg);
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
connection->QueuePacket(outapp);
delete outapp;
}
m_connection->QueuePacket(outapp);
delete outapp;
}
/**
@@ -179,19 +144,23 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
*/
void Client::Handle_Login(const char *data, unsigned int size)
{
if (status != cs_waiting_for_login) {
if (m_client_status != cs_waiting_for_login) {
LogError("Login received after already having logged in");
return;
}
if ((size - 12) % 8 != 0) {
LogError("Login received packet of size: {0}, this would cause a block corruption, discarding", size);
// login user/pass are variable length after unencrypted opcode and base message header (size includes opcode)
constexpr int header_size = sizeof(uint16_t) + sizeof(LoginBaseMessage_Struct);
int data_size = size - header_size;
if (size <= header_size) {
LogError("Login received packet of size: {0}, this would cause a buffer overflow, discarding", size);
return;
}
if (size < sizeof(LoginLoginRequest_Struct)) {
LogError("Login received packet of size: {0}, this would cause a buffer overflow, discarding", size);
if (data_size % 8 != 0) {
LogError("Login received packet of size: {0}, this would cause a block corruption, discarding", size);
return;
}
@@ -208,13 +177,14 @@ void Client::Handle_Login(const char *data, unsigned int size)
std::string db_account_password_hash;
std::string outbuffer;
outbuffer.resize(size - 12);
outbuffer.resize(data_size);
if (outbuffer.length() == 0) {
LogError("Corrupt buffer sent to server, no length");
return;
}
auto r = eqcrypt_block(data + 10, size - 12, &outbuffer[0], 0);
// data starts at base message header (opcode not included)
auto r = eqcrypt_block(data + sizeof(LoginBaseMessage_Struct), data_size, &outbuffer[0], 0);
if (r == nullptr) {
LogError("Failed to decrypt eqcrypt block");
return;
@@ -228,7 +198,8 @@ void Client::Handle_Login(const char *data, unsigned int size)
return;
}
memcpy(&llrs, data, sizeof(LoginLoginRequest_Struct));
// only need to copy the base header for reply options, ignore login info
memcpy(&m_llrs, data, sizeof(LoginBaseMessage_Struct));
bool result = false;
if (outbuffer[0] == 0 && outbuffer[1] == 0) {
@@ -236,7 +207,7 @@ void Client::Handle_Login(const char *data, unsigned int size)
cred = (&outbuffer[2 + user.length()]);
result = server.db->GetLoginTokenDataFromToken(
cred,
connection->GetRemoteAddr(),
m_connection->GetRemoteAddr(),
db_account_id,
db_loginserver,
user
@@ -252,11 +223,16 @@ void Client::Handle_Login(const char *data, unsigned int size)
user = components[1];
}
// health checks
if (ProcessHealthCheck(user)) {
DoFailedLogin();
return;
}
LogInfo(
"Attempting password based login [{0}] login [{1}] user [{2}]",
"Attempting password based login [{0}] login [{1}]",
user,
db_loginserver,
user
db_loginserver
);
ParseAccountString(user, user, db_loginserver);
@@ -267,7 +243,7 @@ void Client::Handle_Login(const char *data, unsigned int size)
LogDebug("[VerifyLoginHash] Success [{0}]", (result ? "true" : "false"));
}
else {
status = cs_creating_account;
m_client_status = cs_creating_account;
AttemptLoginAccountCreation(user, cred, db_loginserver);
return;
@@ -305,14 +281,14 @@ void Client::Handle_Login(const char *data, unsigned int size)
*/
void Client::Handle_Play(const char *data)
{
if (status != cs_logged_in) {
if (m_client_status != cs_logged_in) {
LogError("Client sent a play request when they were not logged in, discarding");
return;
}
const auto *play = (const PlayEverquestRequest_Struct *) data;
auto server_id_in = (unsigned int) play->ServerNumber;
auto sequence_in = (unsigned int) play->Sequence;
auto server_id_in = (unsigned int) play->server_number;
auto sequence_in = (unsigned int) play->base_header.sequence;
if (server.options.IsTraceOn()) {
LogInfo(
@@ -323,10 +299,10 @@ void Client::Handle_Play(const char *data)
);
}
this->play_server_id = (unsigned int) play->ServerNumber;
play_sequence_id = sequence_in;
play_server_id = server_id_in;
server.server_manager->SendUserToWorldRequest(server_id_in, account_id, loginserver_name);
m_play_server_id = (unsigned int) play->server_number;
m_play_sequence_id = sequence_in;
m_play_server_id = server_id_in;
server.server_manager->SendUserToWorldRequest(server_id_in, m_account_id, m_loginserver_name);
}
/**
@@ -334,14 +310,13 @@ void Client::Handle_Play(const char *data)
*/
void Client::SendServerListPacket(uint32 seq)
{
EQApplicationPacket *outapp = server.server_manager->CreateServerListPacket(this, seq);
auto outapp = server.server_manager->CreateServerListPacket(this, seq);
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
DumpPacket(outapp.get());
}
connection->QueuePacket(outapp);
delete outapp;
m_connection->QueuePacket(outapp.get());
}
void Client::SendPlayResponse(EQApplicationPacket *outapp)
@@ -350,12 +325,12 @@ void Client::SendPlayResponse(EQApplicationPacket *outapp)
LogDebug("Sending play response for {0}", GetAccountName());
// server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size);
}
connection->QueuePacket(outapp);
m_connection->QueuePacket(outapp);
}
void Client::GenerateKey()
{
key.clear();
m_key.clear();
int count = 0;
while (count < 10) {
static const char key_selection[] =
@@ -367,7 +342,7 @@ void Client::GenerateKey()
'6', '7', '8', '9'
};
key.append((const char *) &key_selection[random.Int(0, 35)], 1);
m_key.append((const char *) &key_selection[m_random.Int(0, 35)], 1);
count++;
}
}
@@ -383,6 +358,8 @@ void Client::AttemptLoginAccountCreation(
const std::string &loginserver
)
{
LogInfo("[AttemptLoginAccountCreation] user [{}] loginserver [{}]", user, loginserver);
#ifdef LSPX
if (loginserver == "eqemu") {
LogInfo("Attempting login account creation via '{0}'", loginserver);
@@ -393,59 +370,19 @@ void Client::AttemptLoginAccountCreation(
return;
}
if (server.options.GetEQEmuLoginServerAddress().length() == 0) {
DoFailedLogin();
return;
}
auto addr_components = SplitString(server.options.GetEQEmuLoginServerAddress(), ':');
if (addr_components.size() != 2) {
DoFailedLogin();
return;
}
stored_user = user;
stored_pass = pass;
auto address = addr_components[0];
auto port = std::stoi(addr_components[1]);
EQ::Net::DNSLookup(
address, port, false, [=](const std::string &addr) {
if (addr.empty()) {
DoFailedLogin();
return;
}
login_connection_manager.reset(new EQ::Net::DaybreakConnectionManager());
login_connection_manager->OnNewConnection(
std::bind(
&Client::LoginOnNewConnection,
this,
std::placeholders::_1
)
);
login_connection_manager->OnConnectionStateChange(
std::bind(
&Client::LoginOnStatusChange,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3
)
);
login_connection_manager->OnPacketRecv(
std::bind(
&Client::LoginOnPacketRecv,
this,
std::placeholders::_1,
std::placeholders::_2
)
);
login_connection_manager->Connect(addr, port);
}
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(
user,
pass
);
if (account_id > 0) {
LogInfo("[AttemptLoginAccountCreation] Found and creating eqemu account [{}]", account_id);
CreateEQEmuAccount(user, pass, account_id);
return;
}
DoFailedLogin();
return;
}
#endif
@@ -461,26 +398,36 @@ void Client::AttemptLoginAccountCreation(
void Client::DoFailedLogin()
{
stored_user.clear();
stored_pass.clear();
m_stored_user.clear();
m_stored_pass.clear();
EQApplicationPacket outapp(OP_LoginAccepted, sizeof(LoginLoginFailed_Struct));
auto *login_failed = (LoginLoginFailed_Struct *) outapp.pBuffer;
// unencrypted
LoginBaseMessage_Struct base_header{};
base_header.sequence = m_llrs.sequence; // login (3)
base_header.encrypt_type = m_llrs.encrypt_type;
login_failed->unknown1 = llrs.unknown1;
login_failed->unknown2 = llrs.unknown2;
login_failed->unknown3 = llrs.unknown3;
login_failed->unknown4 = llrs.unknown4;
login_failed->unknown5 = llrs.unknown5;
// encrypted
PlayerLoginReply_Struct login_reply{};
login_reply.base_reply.success = false;
login_reply.base_reply.error_str_id = 105; // Error - The username and/or password were not valid
memcpy(login_failed->unknown6, FailedLoginResponseData, sizeof(FailedLoginResponseData));
char encrypted_buffer[80] = {0};
auto rc = eqcrypt_block((const char*)&login_reply, sizeof(login_reply), encrypted_buffer, 1);
if (rc == nullptr) {
LogDebug("Failed to encrypt eqcrypt block for failed login");
}
constexpr int outsize = sizeof(LoginBaseMessage_Struct) + sizeof(encrypted_buffer);
EQApplicationPacket outapp(OP_LoginAccepted, outsize);
outapp.WriteData(&base_header, sizeof(base_header));
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(&outapp);
}
connection->QueuePacket(&outapp);
status = cs_failed_to_login;
m_connection->QueuePacket(&outapp);
m_client_status = cs_failed_to_login;
}
/**
@@ -576,68 +523,64 @@ void Client::DoSuccessfulLogin(
const std::string &db_loginserver
)
{
stored_user.clear();
stored_pass.clear();
m_stored_user.clear();
m_stored_pass.clear();
server.client_manager->RemoveExistingClient(db_account_id, db_loginserver);
in_addr in{};
in.s_addr = connection->GetRemoteIP();
in.s_addr = m_connection->GetRemoteIP();
server.db->UpdateLSAccountData(db_account_id, std::string(inet_ntoa(in)));
GenerateKey();
account_id = db_account_id;
account_name = in_account_name;
loginserver_name = db_loginserver;
m_account_id = db_account_id;
m_account_name = in_account_name;
m_loginserver_name = db_loginserver;
auto *outapp = new EQApplicationPacket(OP_LoginAccepted, 10 + 80);
auto *login_accepted = (LoginAccepted_Struct *) outapp->pBuffer;
login_accepted->unknown1 = llrs.unknown1;
login_accepted->unknown2 = llrs.unknown2;
login_accepted->unknown3 = llrs.unknown3;
login_accepted->unknown4 = llrs.unknown4;
login_accepted->unknown5 = llrs.unknown5;
// unencrypted
LoginBaseMessage_Struct base_header{};
base_header.sequence = m_llrs.sequence;
base_header.compressed = false;
base_header.encrypt_type = m_llrs.encrypt_type;
base_header.unk3 = m_llrs.unk3;
auto *login_failed_attempts = new LoginFailedAttempts_Struct;
memset(login_failed_attempts, 0, sizeof(LoginFailedAttempts_Struct));
login_failed_attempts->failed_attempts = 0;
login_failed_attempts->message = 0x01;
login_failed_attempts->lsid = db_account_id;
login_failed_attempts->unknown3[3] = 0x03;
login_failed_attempts->unknown4[3] = 0x02;
login_failed_attempts->unknown5[0] = 0xe7;
login_failed_attempts->unknown5[1] = 0x03;
login_failed_attempts->unknown6[0] = 0xff;
login_failed_attempts->unknown6[1] = 0xff;
login_failed_attempts->unknown6[2] = 0xff;
login_failed_attempts->unknown6[3] = 0xff;
login_failed_attempts->unknown7[0] = 0xa0;
login_failed_attempts->unknown7[1] = 0x05;
login_failed_attempts->unknown8[3] = 0x02;
login_failed_attempts->unknown9[0] = 0xff;
login_failed_attempts->unknown9[1] = 0x03;
login_failed_attempts->unknown11[0] = 0x63;
login_failed_attempts->unknown12[0] = 0x01;
memcpy(login_failed_attempts->key, key.c_str(), key.size());
// not serializing any of the variable length strings so just use struct directly
PlayerLoginReply_Struct login_reply{};
login_reply.base_reply.success = true;
login_reply.base_reply.error_str_id = 101; // No Error
login_reply.unk1 = 0;
login_reply.unk2 = 0;
login_reply.lsid = db_account_id;
login_reply.failed_attempts = 0;
login_reply.show_player_count = server.options.IsShowPlayerCountEnabled();
login_reply.offer_min_days = 99;
login_reply.offer_min_views = -1;
login_reply.offer_cooldown_minutes = 0;
login_reply.web_offer_number = 0;
login_reply.web_offer_min_days = 99;
login_reply.web_offer_min_views = -1;
login_reply.web_offer_cooldown_minutes = 0;
memcpy(login_reply.key, m_key.c_str(), m_key.size());
char encrypted_buffer[80] = {0};
auto rc = eqcrypt_block((const char *) login_failed_attempts, 75, encrypted_buffer, 1);
auto rc = eqcrypt_block((const char*)&login_reply, sizeof(login_reply), encrypted_buffer, 1);
if (rc == nullptr) {
LogDebug("Failed to encrypt eqcrypt block");
}
memcpy(login_accepted->encrypt, encrypted_buffer, 80);
constexpr int outsize = sizeof(LoginBaseMessage_Struct) + sizeof(encrypted_buffer);
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
outapp->WriteData(&base_header, sizeof(base_header));
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
DumpPacket(outapp.get());
}
connection->QueuePacket(outapp);
delete outapp;
m_connection->QueuePacket(outapp.get());
status = cs_logged_in;
m_client_status = cs_logged_in;
}
/**
@@ -689,7 +632,7 @@ void Client::CreateEQEmuAccount(
*/
void Client::LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection)
{
login_connection = connection;
m_login_connection = connection;
}
/**
@@ -751,16 +694,16 @@ void Client::LoginSendSessionReady()
p.PutUInt16(0, 1); //OP_SessionReady
p.PutUInt32(2, 2);
login_connection->QueuePacket(p);
m_login_connection->QueuePacket(p);
}
void Client::LoginSendLogin()
{
size_t buffer_len = stored_user.length() + stored_pass.length() + 2;
size_t buffer_len = m_stored_user.length() + m_stored_pass.length() + 2;
std::unique_ptr<char[]> buffer(new char[buffer_len]);
strcpy(&buffer[0], stored_user.c_str());
strcpy(&buffer[stored_user.length() + 1], stored_pass.c_str());
strcpy(&buffer[0], m_stored_user.c_str());
strcpy(&buffer[m_stored_user.length() + 1], m_stored_pass.c_str());
size_t encrypted_len = buffer_len;
@@ -775,7 +718,7 @@ void Client::LoginSendLogin()
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
login_connection->QueuePacket(p);
m_login_connection->QueuePacket(p);
}
/**
@@ -796,7 +739,7 @@ void Client::LoginProcessLoginResponse(const EQ::Net::Packet &p)
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
auto response_error = sp.GetUInt16(1);
login_connection_manager->OnConnectionStateChange(
m_login_connection_manager->OnConnectionStateChange(
std::bind(
&Client::LoginOnStatusChangeIgnored,
this,
@@ -809,18 +752,26 @@ void Client::LoginProcessLoginResponse(const EQ::Net::Packet &p)
if (response_error > 101) {
LogDebug("response [{0}] failed login", response_error);
DoFailedLogin();
login_connection->Close();
m_login_connection->Close();
}
else {
LogDebug(
"response [{0}] login succeeded user [{1}]",
response_error,
stored_user
m_stored_user
);
auto m_dbid = sp.GetUInt32(8);
CreateEQEmuAccount(stored_user, stored_pass, m_dbid);
login_connection->Close();
CreateEQEmuAccount(m_stored_user, m_stored_pass, m_dbid);
m_login_connection->Close();
}
}
bool Client::ProcessHealthCheck(std::string username)
{
if (username == "healthcheckuser") {
return true;
}
return false;
}
+24 -56
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_CLIENT_H
#define EQEMU_CLIENT_H
@@ -27,22 +7,9 @@
#include "../common/eq_stream_intf.h"
#include "../common/net/dns.h"
#include "../common/net/daybreak_connection.h"
#include "login_structures.h"
#include "login_types.h"
#include <memory>
enum LSClientVersion {
cv_titanium,
cv_sod
};
enum LSClientStatus {
cs_not_sent_session_ready,
cs_waiting_for_login,
cs_creating_account,
cs_failed_to_login,
cs_logged_in
};
/**
* Client class, controls a single client and it's connection to the login server
*/
@@ -116,49 +83,49 @@ public:
*
* @return
*/
unsigned int GetAccountID() const { return account_id; }
unsigned int GetAccountID() const { return m_account_id; }
/**
* Gets the loginserver name of this client
*
* @return
*/
std::string GetLoginServerName() const { return loginserver_name; }
std::string GetLoginServerName() const { return m_loginserver_name; }
/**
* Gets the account name of this client
*
* @return
*/
std::string GetAccountName() const { return account_name; }
std::string GetAccountName() const { return m_account_name; }
/**
* Gets the key generated at login for this client
*
* @return
*/
std::string GetKey() const { return key; }
std::string GetKey() const { return m_key; }
/**
* Gets the server selected to be played on for this client
*
* @return
*/
unsigned int GetPlayServerID() const { return play_server_id; }
unsigned int GetPlayServerID() const { return m_play_server_id; }
/**
* Gets the play sequence state for this client
*
* @return
*/
unsigned int GetPlaySequence() const { return play_sequence_id; }
unsigned int GetPlaySequence() const { return m_play_sequence_id; }
/**
* Gets the connection for this client
*
* @return
*/
std::shared_ptr<EQStreamInterface> GetConnection() { return connection; }
std::shared_ptr<EQStreamInterface> GetConnection() { return m_connection; }
/**
* Attempts to create a login account
@@ -195,24 +162,24 @@ public:
void CreateEQEmuAccount(const std::string &in_account_name, const std::string &in_account_password, unsigned int loginserver_account_id);
private:
EQ::Random random;
std::shared_ptr<EQStreamInterface> connection;
LSClientVersion version;
LSClientStatus status;
EQ::Random m_random;
std::shared_ptr<EQStreamInterface> m_connection;
LSClientVersion m_client_version;
LSClientStatus m_client_status;
std::string account_name;
unsigned int account_id;
std::string loginserver_name;
unsigned int play_server_id;
unsigned int play_sequence_id;
std::string key;
std::string m_account_name;
unsigned int m_account_id;
std::string m_loginserver_name;
unsigned int m_play_server_id;
unsigned int m_play_sequence_id;
std::string m_key;
std::unique_ptr<EQ::Net::DaybreakConnectionManager> login_connection_manager;
std::shared_ptr<EQ::Net::DaybreakConnection> login_connection;
LoginLoginRequest_Struct llrs;
std::unique_ptr<EQ::Net::DaybreakConnectionManager> m_login_connection_manager;
std::shared_ptr<EQ::Net::DaybreakConnection> m_login_connection;
LoginBaseMessage_Struct m_llrs;
std::string stored_user;
std::string stored_pass;
std::string m_stored_user;
std::string m_stored_pass;
void LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection);
void LoginOnStatusChange(
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
@@ -228,6 +195,7 @@ private:
void LoginSendSessionReady();
void LoginSendLogin();
void LoginProcessLoginResponse(const EQ::Net::Packet &p);
static bool ProcessHealthCheck(std::string username);
};
#endif
+6 -25
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "client_manager.h"
#include "login_server.h"
@@ -25,6 +5,7 @@ extern LoginServer server;
extern bool run_server;
#include "../common/eqemu_logsys.h"
#include "../common/misc.h"
ClientManager::ClientManager()
{
@@ -52,8 +33,8 @@ ClientManager::ClientManager()
titanium_stream->OnNewConnection(
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
LogInfo(
"New Titanium client connection from {0}:{1}",
stream->GetRemoteIP(),
"New Titanium client connection from [{0}:{1}]",
long2ip(stream->GetRemoteIP()),
stream->GetRemotePort()
);
@@ -87,13 +68,13 @@ ClientManager::ClientManager()
sod_stream->OnNewConnection(
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
LogInfo(
"New SoD client connection from {0}:{1}",
stream->GetRemoteIP(),
"New SoD+ client connection from [{0}:{1}]",
long2ip(stream->GetRemoteIP()),
stream->GetRemotePort()
);
stream->SetOpcodeManager(&sod_ops);
Client *c = new Client(stream, cv_sod);
auto *c = new Client(stream, cv_sod);
clients.push_back(c);
}
);
-20
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_CLIENTMANAGER_H
#define EQEMU_CLIENTMANAGER_H
+44 -66
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../common/global_define.h"
#include "database.h"
@@ -45,11 +25,6 @@ Database::Database(
std::string name
)
{
this->user = user;
this->pass = pass;
this->host = host;
this->name = name;
uint32 errnum = 0;
char errbuf[MYSQL_ERRMSG_SIZE];
if (!Open(
@@ -75,8 +50,8 @@ Database::Database(
*/
Database::~Database()
{
if (database) {
mysql_close(database);
if (m_database) {
mysql_close(m_database);
}
}
@@ -355,11 +330,13 @@ void Database::UpdateLoginserverAccountPasswordHash(
/**
* @param short_name
* @param long_name
* @param login_world_server_admin_id
* @return
*/
Database::DbWorldRegistration Database::GetWorldRegistration(
const std::string &short_name,
const std::string &long_name,
uint32 login_world_server_admin_id
)
{
@@ -375,45 +352,46 @@ Database::DbWorldRegistration Database::GetWorldRegistration(
" login_world_servers AS WSR\n"
" JOIN login_server_list_types AS SLT ON WSR.login_server_list_type_id = SLT.id\n"
"WHERE\n"
" WSR.short_name = '{0}' AND WSR.login_server_admin_id = {1} LIMIT 1",
" WSR.short_name = '{}' AND WSR.long_name = '{}' AND WSR.login_server_admin_id = {} LIMIT 1",
EscapeString(short_name),
EscapeString(long_name),
login_world_server_admin_id
);
Database::DbWorldRegistration world_registration{};
Database::DbWorldRegistration r{};
auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() != 1) {
return world_registration;
return r;
}
auto row = results.begin();
world_registration.loaded = true;
world_registration.server_id = std::stoi(row[0]);
world_registration.server_description = row[1];
world_registration.server_list_type = std::stoi(row[3]);
world_registration.is_server_trusted = std::stoi(row[2]) > 0;
world_registration.server_list_description = row[4];
world_registration.server_admin_id = std::stoi(row[5]);
r.loaded = true;
r.server_id = std::stoi(row[0]);
r.server_description = row[1];
r.server_list_type = std::stoi(row[3]);
r.is_server_trusted = std::stoi(row[2]) > 0;
r.server_list_description = row[4];
r.server_admin_id = std::stoi(row[5]);
if (world_registration.server_admin_id <= 0) {
return world_registration;
if (r.server_admin_id <= 0) {
return r;
}
auto world_registration_query = fmt::format(
"SELECT account_name, account_password FROM login_server_admins WHERE id = {0} LIMIT 1",
world_registration.server_admin_id
r.server_admin_id
);
auto world_registration_results = QueryDatabase(world_registration_query);
if (world_registration_results.Success() && world_registration_results.RowCount() == 1) {
auto world_registration_row = world_registration_results.begin();
world_registration.server_admin_account_name = world_registration_row[0];
world_registration.server_admin_account_password = world_registration_row[1];
r.server_admin_account_name = world_registration_row[0];
r.server_admin_account_password = world_registration_row[1];
}
return world_registration;
return r;
}
/**
@@ -665,21 +643,21 @@ Database::DbLoginServerAdmin Database::GetLoginServerAdmin(const std::string &ac
auto results = QueryDatabase(query);
Database::DbLoginServerAdmin login_server_admin{};
Database::DbLoginServerAdmin r{};
if (results.RowCount() == 1) {
auto row = results.begin();
login_server_admin.loaded = true;
login_server_admin.id = std::stoi(row[0]);
login_server_admin.account_name = row[1];
login_server_admin.account_password = row[2];
login_server_admin.first_name = row[3];
login_server_admin.last_name = row[4];
login_server_admin.email = row[5];
login_server_admin.registration_date = row[7];
login_server_admin.registration_ip_address = row[8];
r.loaded = true;
r.id = std::stoi(row[0]);
r.account_name = row[1];
r.account_password = row[2];
r.first_name = row[3];
r.last_name = row[4];
r.email = row[5];
r.registration_date = row[7];
r.registration_ip_address = row[8];
}
return login_server_admin;
return r;
}
/**
@@ -701,20 +679,20 @@ Database::DbLoginServerAccount Database::GetLoginServerAccountByAccountName(
auto results = QueryDatabase(query);
Database::DbLoginServerAccount login_server_account{};
Database::DbLoginServerAccount r{};
if (results.RowCount() == 1) {
auto row = results.begin();
login_server_account.loaded = true;
login_server_account.id = std::stoi(row[0]);
login_server_account.account_name = row[1];
login_server_account.account_password = row[2];
login_server_account.account_email = row[3];
login_server_account.source_loginserver = row[4];
login_server_account.last_ip_address = row[5];
login_server_account.last_login_date = row[6];
login_server_account.created_at = row[7];
login_server_account.updated_at = row[8];
r.loaded = true;
r.id = std::stoi(row[0]);
r.account_name = row[1];
r.account_password = row[2];
r.account_email = row[3];
r.source_loginserver = row[4];
r.last_ip_address = row[5];
r.last_login_date = row[6];
r.created_at = row[7];
r.updated_at = row[8];
}
return login_server_account;
return r;
}
+5 -24
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_DATABASEMYSQL_H
#define EQEMU_DATABASEMYSQL_H
@@ -32,7 +12,7 @@
class Database : public DBcore {
public:
Database() { database = nullptr; }
Database() { m_database = nullptr; }
/**
* Constructor, tries to set our database to connect to the supplied options.
@@ -49,7 +29,7 @@ public:
* Destructor, frees our database if needed.
*/
~Database();
bool IsConnected() { return (database != nullptr); }
bool IsConnected() { return (m_database != nullptr); }
/**
* Retrieves the login data (password hash and account id) from the account name provided needed for client login procedure.
@@ -158,11 +138,13 @@ public:
* Returns true if the record was found, false otherwise
*
* @param short_name
* @param long_name
* @param login_world_server_admin_id
* @return
*/
Database::DbWorldRegistration GetWorldRegistration(
const std::string &short_name,
const std::string &long_name,
uint32 login_world_server_admin_id
);
@@ -298,8 +280,7 @@ public:
);
protected:
std::string user, pass, host, port, name;
MYSQL *database{};
MYSQL *m_database{};
};
#endif
-20
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#pragma once
#include <string>
-20
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMUCAPI__H
#define EQEMUCAPI__H
+1 -23
View File
@@ -1,29 +1,7 @@
#include <utility>
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_LOGINSERVER_H
#define EQEMU_LOGINSERVER_H
#include <utility>
#include "../common/json_config.h"
#include "database.h"
#include "encryption.h"
-117
View File
@@ -1,117 +0,0 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_LOGINSTRUCTURES_H
#define EQEMU_LOGINSTRUCTURES_H
#pragma pack(1)
struct LoginChatMessage_Struct {
short Unknown0;
uint32 Unknown1;
uint32 Unknown2;
uint32 Unknown3;
uint8 Unknown4;
char ChatMessage[1];
};
struct LoginLoginRequest_Struct {
short unknown1;
short unknown2;
short unknown3;
short unknown4;
short unknown5;
char unknown6[16];
};
struct LoginAccepted_Struct {
short unknown1;
short unknown2;
short unknown3;
short unknown4;
short unknown5;
char encrypt[80];
};
struct LoginFailedAttempts_Struct {
char message; //0x01
char unknown2[7]; //0x00
uint32 lsid;
char key[11]; //10 char + null term;
uint32 failed_attempts;
char unknown3[4]; //0x00, 0x00, 0x00, 0x03
char unknown4[4]; //0x00, 0x00, 0x00, 0x02
char unknown5[4]; //0xe7, 0x03, 0x00, 0x00
char unknown6[4]; //0xff, 0xff, 0xff, 0xff
char unknown7[4]; //0xa0, 0x05, 0x00, 0x00
char unknown8[4]; //0x00, 0x00, 0x00, 0x02
char unknown9[4]; //0xff, 0x03, 0x00, 0x00
char unknown10[4]; //0x00, 0x00, 0x00, 0x00
char unknown11[4]; //0x63, 0x00, 0x00, 0x00
char unknown12[4]; //0x01, 0x00, 0x00, 0x00
char unknown13[4]; //0x00, 0x00, 0x00, 0x00
char unknown14[4]; //0x00, 0x00, 0x00, 0x00
};
struct LoginLoginFailed_Struct {
short unknown1;
short unknown2;
short unknown3;
short unknown4;
short unknown5;
char unknown6[74];
};
struct ServerListHeader_Struct {
uint32 Unknown1;
uint32 Unknown2;
uint32 Unknown3;
uint32 Unknown4;
uint32 NumberOfServers;
};
struct PlayEverquestRequest_Struct {
uint16 Sequence;
uint32 Unknown1;
uint32 Unknown2;
uint32 ServerNumber;
};
struct PlayEverquestResponse_Struct {
uint8 Sequence;
uint8 Unknown1[9];
uint8 Allowed;
uint16 Message;
uint8 Unknown2[3];
uint32 ServerNumber;
};
static const unsigned char FailedLoginResponseData[] = {
0xf6, 0x85, 0x9c, 0x23, 0x57, 0x7e, 0x3e, 0x55, 0xb3, 0x4c, 0xf8, 0xc8, 0xcb, 0x77, 0xd5, 0x16,
0x09, 0x7a, 0x63, 0xdc, 0x57, 0x7e, 0x3e, 0x55, 0xb3, 0x4c, 0xf8, 0xc8, 0xcb, 0x77, 0xd5, 0x16,
0x09, 0x7a, 0x63, 0xdc, 0x57, 0x7e, 0x3e, 0x55, 0xb3
};
#pragma pack()
#endif
+143
View File
@@ -0,0 +1,143 @@
#ifndef EQEMU_LOGINSTRUCTURES_H
#define EQEMU_LOGINSTRUCTURES_H
#pragma pack(1)
// unencrypted base message header in all packets
struct LoginBaseMessage_Struct {
int32_t sequence; // request type/login sequence (2: handshake, 3: login, 4: serverlist, ...)
bool compressed; // true: deflated
int8_t encrypt_type; // 1: invert (unused) 2: des (2 for encrypted player logins and order expansions) (client uses what it sent, ignores in reply)
int32_t unk3; // unused?
};
struct LoginBaseReplyMessage_Struct {
bool success; // 0: failure (shows error string) 1: success
int32_t error_str_id; // last error eqlsstr id, default: 101 (no error)
char str[1]; // variable length, unknown (may be unused, this struct is a common pattern elsewhere)
};
struct LoginHandShakeReply_Struct {
LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
char unknown[1]; // variable length string
};
// for reference, login buffer is variable (minimum size 8 due to encryption)
struct PlayerLogin_Struct {
LoginBaseMessage_Struct base_header;
char username[1];
char password[1];
};
// variable length, can use directly if not serializing strings
struct PlayerLoginReply_Struct {
// base header excluded to make struct data easier to encrypt
//LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
int8_t unk1; // (default: 0)
int8_t unk2; // (default: 0)
int32_t lsid; // (default: -1)
char key[11]; // client reads until null (variable length)
int32_t failed_attempts;
bool show_player_count; // admin flag, enables admin button and shows server player counts (default: false)
int32_t offer_min_days; // guess, needs more investigation, maybe expansion offers (default: 99)
int32_t offer_min_views; // guess (default: -1)
int32_t offer_cooldown_minutes; // guess (default: 0)
int32_t web_offer_number; // web order view number, 0 nothing (default: 0)
int32_t web_offer_min_days; // number of days to show offer (based on first offer time in client eqls ini) (default: 99)
int32_t web_offer_min_views; // mininum views, -1 for no minimum, 0 for never shows (based on client eqls ini) (default: -1)
int32_t web_offer_cooldown_minutes; // minimum minutes between offers (based on last offer time in client eqls ini) (default: 0)
char username[1]; // variable length, if not empty client attempts to re-login to server select when quitting from char select and sends this in a struct
char unknown[1]; // variable length, password unlikely? client doesn't send this on re-login from char select
};
// variable length, for reference
struct LoginClientServerData_Struct {
char ip[1];
int32_t server_type; // legends, preferred, standard
int32_t server_id;
char server_name[1];
char country_code[1]; // if doesn't match client locale then server is colored dark grey in list and joining is prevented (to block for "us" use one of "kr", "tw", "jp", "de", "fr", or "cn") (ISO 3166-1 alpha-2)
char language_code[1];
int32_t server_status; // see ServerStatusFlags
int32_t player_count;
};
// variable length, for reference
struct ServerListReply_Struct {
LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
int32_t server_count;
LoginClientServerData_Struct servers[0];
};
struct PlayEverquestRequest_Struct {
LoginBaseMessage_Struct base_header;
uint32 server_number;
};
// SCJoinServerReply
struct PlayEverquestResponse_Struct {
LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
uint32 server_number;
};
#pragma pack()
enum LSClientVersion {
cv_titanium,
cv_sod
};
enum LSClientStatus {
cs_not_sent_session_ready,
cs_waiting_for_login,
cs_creating_account,
cs_failed_to_login,
cs_logged_in
};
namespace LS {
namespace ServerStatusFlags {
enum eServerStatusFlags {
Up = 0, // default
Down = 1,
Unused = 2,
Locked = 4 // can be combined with Down to show "Locked (Down)"
};
}
namespace ServerTypeFlags {
enum eServerTypeFlags {
None = 0,
Standard = 1,
Unknown2 = 2,
Unknown4 = 4,
Preferred = 8,
Legends = 16 // can be combined with Preferred flag to override color in Legends section with Preferred color (green)
};
}
enum ServerType {
Standard = 3,
Preferred = 2,
Legends = 1,
};
namespace ErrStr {
constexpr static int ERROR_NONE = 101; // No Error
constexpr static int ERROR_UNKNOWN = 102; // Error - Unknown Error Occurred
constexpr static int ERROR_ACTIVE_CHARACTER = 111; // Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again.
constexpr static int ERROR_SERVER_UNAVAILABLE = 326; // That server is currently unavailable. Please check the EverQuest webpage for current server status and try again later.
constexpr static int ERROR_ACCOUNT_SUSPENDED = 337; // This account is currently suspended. Please contact customer service for more information.
constexpr static int ERROR_ACCOUNT_BANNED = 338; // This account is currently banned. Please contact customer service for more information.
constexpr static int ERROR_WORLD_MAX_CAPACITY = 339; // The world server is currently at maximum capacity and not allowing further logins until the number of players online decreases. Please try again later.
};
}
#endif
+3
View File
@@ -11,6 +11,9 @@
},
"worldservers": {
"unregistered_allowed": true,
"show_player_count": false,
"dev_test_servers_list_bottom": false,
"special_character_start_list_bottom": false,
"reject_duplicate_servers": false
},
"web_api": {
+4 -4
View File
@@ -5,7 +5,7 @@ CREATE TABLE `login_accounts` (
`account_password` text NOT NULL,
`account_email` varchar(100) NOT NULL,
`source_loginserver` varchar(64) DEFAULT NULL,
`last_ip_address` varchar(15) NOT NULL,
`last_ip_address` varchar(80) NOT NULL,
`last_login_date` datetime NOT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT current_timestamp(),
@@ -22,7 +22,7 @@ CREATE TABLE `login_server_admins` (
`last_name` varchar(50) NOT NULL,
`email` varchar(100) NOT NULL,
`registration_date` datetime NOT NULL,
`registration_ip_address` varchar(15) NOT NULL,
`registration_ip_address` varchar(80) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
@@ -45,7 +45,7 @@ CREATE TABLE `login_world_servers` (
`tag_description` varchar(50) NOT NULL DEFAULT '',
`login_server_list_type_id` int(11) NOT NULL,
`last_login_date` datetime DEFAULT NULL,
`last_ip_address` varchar(15) DEFAULT NULL,
`last_ip_address` varchar(80) DEFAULT NULL,
`login_server_admin_id` int(11) NOT NULL,
`is_server_trusted` int(11) NOT NULL,
`note` varchar(255) DEFAULT NULL,
@@ -61,4 +61,4 @@ CREATE TABLE `login_api_tokens` (
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
+21 -20
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <iostream>
#include <random>
#include "loginserver_command_handler.h"
@@ -58,6 +38,7 @@ namespace LoginserverCommandHandler {
function_map["web-api-token:list"] = &LoginserverCommandHandler::ListLoginserverApiTokens;
function_map["world-admin:create"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount;
function_map["world-admin:update"] = &LoginserverCommandHandler::UpdateLoginserverWorldAdminAccountPassword;
function_map["health:check-login"] = &LoginserverCommandHandler::HealthCheckLogin;
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
}
@@ -301,4 +282,24 @@ namespace LoginserverCommandHandler {
cmd(3).str()
);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void HealthCheckLogin(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Checks login health using a test user";
std::vector<std::string> arguments = {};
std::vector<std::string> options = {};
if (cmd[{"-h", "--help"}]) {
return;
}
LogInfo("[CLI] [HealthCheck] Response code [{}]", AccountManagement::HealthCheckUserLogin());
}
}
+1 -20
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "iostream"
#include "../common/cli/eqemu_command_handler.h"
@@ -34,6 +14,7 @@ namespace LoginserverCommandHandler {
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
void UpdateLoginserverWorldAdminAccountPassword(int argc, char **argv, argh::parser &cmd, std::string &description);
void HealthCheckLogin(int argc, char **argv, argh::parser &cmd, std::string &description);
};
+27 -28
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "loginserver_webserver.h"
#include "server_manager.h"
#include "login_server.h"
@@ -51,14 +31,15 @@ namespace LoginserverWebserver {
auto iter = server.server_manager->getWorldServers().begin();
while (iter != server.server_manager->getWorldServers().end()) {
Json::Value row;
row["server_long_name"] = (*iter)->GetServerLongName();
row["server_short_name"] = (*iter)->GetServerLongName();
row["server_list_id"] = (*iter)->GetServerListID();
row["server_status"] = (*iter)->GetStatus();
row["zones_booted"] = (*iter)->GetZonesBooted();
row["local_ip"] = (*iter)->GetLocalIP();
row["remote_ip"] = (*iter)->GetRemoteIP();
row["players_online"] = (*iter)->GetPlayersOnline();
row["server_long_name"] = (*iter)->GetServerLongName();
row["server_short_name"] = (*iter)->GetServerShortName();
row["server_list_type_id"] = (*iter)->GetServerListID();
row["server_status"] = (*iter)->GetStatus();
row["zones_booted"] = (*iter)->GetZonesBooted();
row["local_ip"] = (*iter)->GetLocalIP();
row["remote_ip"] = (*iter)->GetRemoteIP();
row["players_online"] = (*iter)->GetPlayersOnline();
row["world_id"] = (*iter)->GetServerId();
response.append(row);
++iter;
}
@@ -316,6 +297,24 @@ namespace LoginserverWebserver {
LoginserverWebserver::SendResponse(response, res);
}
);
api.Get(
"/probes/healthcheck", [](const httplib::Request &request, httplib::Response &res) {
Json::Value response;
uint32 login_response = AccountManagement::HealthCheckUserLogin();
response["status"] = login_response;
if (login_response == 0) {
response["message"] = "Process unresponsive, exiting...";
LogInfo("Probes healthcheck unresponsive, exiting...");
}
LoginserverWebserver::SendResponse(response, res);
if (login_response == 0) {
std::exit(0);
}
}
);
}
/**
-20
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_LOGINSERVER_WEBSERVER_H
#define EQEMU_LOGINSERVER_WEBSERVER_H
+41 -26
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../common/global_define.h"
#include "../common/types.h"
#include "../common/opcodemgr.h"
@@ -30,6 +10,7 @@
#include "login_server.h"
#include "loginserver_webserver.h"
#include "loginserver_command_handler.h"
#include "../common/string_util.h"
#include <time.h>
#include <stdlib.h>
#include <string>
@@ -40,6 +21,7 @@ LoginServer server;
EQEmuLogSys LogSys;
bool run_server = true;
void ResolveAddresses();
void CatchSignal(int sig_num)
{
}
@@ -80,8 +62,30 @@ void LoadServerConfig()
"worldservers",
"reject_duplicate_servers",
false
));
server.options.AllowUnregistered(server.config.GetVariableBool("worldservers", "unregistered_allowed", true));
)
);
server.options.SetShowPlayerCount(server.config.GetVariableBool("worldservers", "show_player_count", false));
server.options.AllowUnregistered(
server.config.GetVariableBool(
"worldservers",
"unregistered_allowed",
true
)
);
server.options.SetWorldDevTestServersListBottom(
server.config.GetVariableBool(
"worldservers",
"dev_test_servers_list_bottom",
false
)
);
server.options.SetWorldSpecialCharacterStartListBottom(
server.config.GetVariableBool(
"worldservers",
"special_character_start_list_bottom",
false
)
);
/**
* Account
@@ -138,11 +142,13 @@ void start_web_server()
httplib::Server api;
api.set_logger([](const auto& req, const auto& res) {
if (!req.path.empty()) {
LogInfo("[API] Request [{}] via [{}:{}]", req.path, req.remote_addr, req.remote_port);
api.set_logger(
[](const auto &req, const auto &res) {
if (!req.path.empty()) {
LogInfo("[API] Request [{}] via [{}:{}]", req.path, req.remote_addr, req.remote_port);
}
}
});
);
LoginserverWebserver::RegisterRoutes(api);
api.listen("0.0.0.0", web_api_port);
@@ -256,6 +262,15 @@ int main(int argc, char **argv)
#endif
LogInfo("[Config] [WorldServer] IsRejectingDuplicateServers [{0}]", server.options.IsRejectingDuplicateServers());
LogInfo("[Config] [WorldServer] IsUnregisteredAllowed [{0}]", server.options.IsUnregisteredAllowed());
LogInfo("[Config] [WorldServer] ShowPlayerCount [{0}]", server.options.IsShowPlayerCountEnabled());
LogInfo(
"[Config] [WorldServer] DevAndTestServersListBottom [{0}]",
server.options.IsWorldDevTestServersListBottom()
);
LogInfo(
"[Config] [WorldServer] SpecialCharactersStartListBottom [{0}]",
server.options.IsWorldSpecialCharacterStartListBottom()
);
LogInfo("[Config] [Security] GetEncryptionMode [{0}]", server.options.GetEncryptionMode());
LogInfo("[Config] [Security] IsTokenLoginAllowed [{0}]", server.options.IsTokenLoginAllowed());
LogInfo("[Config] [Security] IsPasswordLoginAllowed [{0}]", server.options.IsPasswordLoginAllowed());
+27 -20
View File
@@ -1,23 +1,3 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_OPTIONS_H
#define EQEMU_OPTIONS_H
@@ -133,6 +113,29 @@ public:
inline void UpdateInsecurePasswords(bool b) { update_insecure_passwords = b; }
inline bool IsUpdatingInsecurePasswords() const { return update_insecure_passwords; }
inline bool IsShowPlayerCountEnabled() const
{
return show_player_count;
}
inline void SetShowPlayerCount(bool show_player_count)
{
Options::show_player_count = show_player_count;
}
inline bool IsWorldDevTestServersListBottom() const { return world_dev_test_servers_list_bottom; }
inline void SetWorldDevTestServersListBottom(bool dev_test_servers_list_bottom)
{
Options::world_dev_test_servers_list_bottom = dev_test_servers_list_bottom;
}
inline bool IsWorldSpecialCharacterStartListBottom() const
{
return world_special_character_start_list_bottom;
}
inline void SetWorldSpecialCharacterStartListBottom(bool world_special_character_start_list_bottom)
{
Options::world_special_character_start_list_bottom = world_special_character_start_list_bottom;
}
private:
bool allow_unregistered;
bool trace;
@@ -140,8 +143,11 @@ private:
bool dump_in_packets;
bool dump_out_packets;
bool reject_duplicate_servers;
bool world_dev_test_servers_list_bottom;
bool world_special_character_start_list_bottom;
bool allow_token_login;
bool allow_password_login;
bool show_player_count;
bool auto_create_accounts;
bool auto_link_accounts;
bool update_insecure_passwords;
@@ -150,5 +156,6 @@ private:
std::string default_loginserver_name;
};
#endif
+68 -173
View File
@@ -1,26 +1,6 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "server_manager.h"
#include "login_server.h"
#include "login_structures.h"
#include "login_types.h"
#include <stdlib.h>
#include "../common/eqemu_logsys.h"
@@ -33,15 +13,15 @@ ServerManager::ServerManager()
{
int listen_port = server.config.GetVariableInt("general", "listen_port", 5998);
server_connection = std::make_unique<EQ::Net::ServertalkServer>();
m_server_connection = std::make_unique<EQ::Net::ServertalkServer>();
EQ::Net::ServertalkServerOptions opts;
opts.port = listen_port;
opts.ipv6 = false;
server_connection->Listen(opts);
opts.ipv6 = false;
m_server_connection->Listen(opts);
LogInfo("Loginserver now listening on port [{0}]", listen_port);
server_connection->OnConnectionIdentified(
m_server_connection->OnConnectionIdentified(
"World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> world_connection) {
LogInfo(
"New World Server connection from {0}:{1}",
@@ -49,8 +29,8 @@ ServerManager::ServerManager()
world_connection->Handle()->RemotePort()
);
auto iter = world_servers.begin();
while (iter != world_servers.end()) {
auto iter = m_world_servers.begin();
while (iter != m_world_servers.end()) {
if ((*iter)->GetConnection()->Handle()->RemoteIP().compare(world_connection->Handle()->RemoteIP()) ==
0 &&
(*iter)->GetConnection()->Handle()->RemotePort() == world_connection->Handle()->RemotePort()) {
@@ -61,27 +41,27 @@ ServerManager::ServerManager()
world_connection->Handle()->RemotePort()
);
world_servers.erase(iter);
m_world_servers.erase(iter);
break;
}
++iter;
}
world_servers.push_back(std::make_unique<WorldServer>(world_connection));
m_world_servers.push_back(std::make_unique<WorldServer>(world_connection));
}
);
server_connection->OnConnectionRemoved(
m_server_connection->OnConnectionRemoved(
"World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> c) {
auto iter = world_servers.begin();
while (iter != world_servers.end()) {
auto iter = m_world_servers.begin();
while (iter != m_world_servers.end()) {
if ((*iter)->GetConnection()->GetUUID() == c->GetUUID()) {
LogInfo(
"World server {0} has been disconnected, removing.",
(*iter)->GetServerLongName()
);
world_servers.erase(iter);
m_world_servers.erase(iter);
return;
}
@@ -100,8 +80,8 @@ ServerManager::~ServerManager() = default;
*/
WorldServer *ServerManager::GetServerByAddress(const std::string &ip_address, int port)
{
auto iter = world_servers.begin();
while (iter != world_servers.end()) {
auto iter = m_world_servers.begin();
while (iter != m_world_servers.end()) {
if ((*iter)->GetConnection()->Handle()->RemoteIP() == ip_address &&
(*iter)->GetConnection()->Handle()->RemotePort()) {
return (*iter).get();
@@ -117,9 +97,8 @@ WorldServer *ServerManager::GetServerByAddress(const std::string &ip_address, in
* @param sequence
* @return
*/
EQApplicationPacket *ServerManager::CreateServerListPacket(Client *client, uint32 sequence)
std::unique_ptr<EQApplicationPacket> ServerManager::CreateServerListPacket(Client *client, uint32 sequence)
{
unsigned int packet_size = sizeof(ServerListHeader_Struct);
unsigned int server_count = 0;
in_addr in{};
in.s_addr = client->GetConnection()->GetRemoteIP();
@@ -127,144 +106,60 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *client, uint3
LogDebug("ServerManager::CreateServerListPacket via client address [{0}]", client_ip);
auto iter = world_servers.begin();
while (iter != world_servers.end()) {
if (!(*iter)->IsAuthorized()) {
for (const auto& world_server : m_world_servers)
{
if (world_server->IsAuthorized()) {
++server_count;
}
}
SerializeBuffer buf;
// LoginBaseMessage_Struct header
buf.WriteInt32(sequence);
buf.WriteInt8(0);
buf.WriteInt8(0);
buf.WriteInt32(0);
// LoginBaseReplyMessage_Struct
buf.WriteInt8(true); // success (no error)
buf.WriteInt32(0x65); // 101 "No Error" eqlsstr
buf.WriteString("");
// ServerListReply_Struct
buf.WriteInt32(server_count);
for (const auto& world_server : m_world_servers)
{
if (!world_server->IsAuthorized()) {
LogDebug(
"ServerManager::CreateServerListPacket | Server [{0}] via IP [{1}] is not authorized to be listed",
(*iter)->GetServerLongName(),
(*iter)->GetConnection()->Handle()->RemoteIP()
"ServerManager::CreateServerListPacket | Server [{}] via IP [{}] is not authorized to be listed",
world_server->GetServerLongName(),
world_server->GetConnection()->Handle()->RemoteIP()
);
++iter;
continue;
}
std::string world_ip = (*iter)->GetConnection()->Handle()->RemoteIP();
if (world_ip == client_ip) {
packet_size += (*iter)->GetServerLongName().size() + (*iter)->GetLocalIP().size() + 24;
bool use_local_ip = false;
LogDebug(
"CreateServerListPacket | Building list entry | Client [{0}] IP [{1}] Server Long Name [{2}] Server IP [{3}] (Local)",
client->GetAccountName(),
client_ip,
(*iter)->GetServerLongName(),
(*iter)->GetLocalIP()
);
}
else if (IpUtil::IsIpInPrivateRfc1918(client_ip)) {
packet_size += (*iter)->GetServerLongName().size() + (*iter)->GetLocalIP().size() + 24;
LogDebug(
"CreateServerListPacket | Building list entry | Client [{0}] IP [{1}] Server Long Name [{2}] Server IP [{3}] (Local)",
client->GetAccountName(),
client_ip,
(*iter)->GetServerLongName(),
(*iter)->GetLocalIP()
);
}
else {
packet_size += (*iter)->GetServerLongName().size() + (*iter)->GetRemoteIP().size() + 24;
LogDebug(
"CreateServerListPacket | Building list entry | Client [{0}] IP [{1}] Server Long Name [{2}] Server IP [{3}] (Remote)",
client->GetAccountName(),
client_ip,
(*iter)->GetServerLongName(),
(*iter)->GetRemoteIP()
);
std::string world_ip = world_server->GetConnection()->Handle()->RemoteIP();
if (world_ip == client_ip || IpUtil::IsIpInPrivateRfc1918(client_ip)) {
use_local_ip = true;
}
server_count++;
++iter;
LogDebug(
"CreateServerListPacket | Building list entry | Client [{}] IP [{}] Server Long Name [{}] Server IP [{}] ({})",
client->GetAccountName(),
client_ip,
world_server->GetServerLongName(),
use_local_ip ? world_server->GetLocalIP() : world_server->GetRemoteIP(),
use_local_ip ? "Local" : "Remote"
);
world_server->SerializeForClientServerList(buf, use_local_ip);
}
auto *outapp = new EQApplicationPacket(OP_ServerListResponse, packet_size);
auto *server_list = (ServerListHeader_Struct *) outapp->pBuffer;
server_list->Unknown1 = sequence;
server_list->Unknown2 = 0x00000000;
server_list->Unknown3 = 0x01650000;
/**
* Not sure what this is but it should be noted setting it to
* 0xFFFFFFFF crashes the client so: don't do that.
*/
server_list->Unknown4 = 0x00000000;
server_list->NumberOfServers = server_count;
unsigned char *data_pointer = outapp->pBuffer;
data_pointer += sizeof(ServerListHeader_Struct);
iter = world_servers.begin();
while (iter != world_servers.end()) {
if (!(*iter)->IsAuthorized()) {
++iter;
continue;
}
std::string world_ip = (*iter)->GetConnection()->Handle()->RemoteIP();
if (world_ip == client_ip) {
memcpy(data_pointer, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size());
data_pointer += ((*iter)->GetLocalIP().size() + 1);
}
else if (IpUtil::IsIpInPrivateRfc1918(client_ip)) {
memcpy(data_pointer, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size());
data_pointer += ((*iter)->GetLocalIP().size() + 1);
}
else {
memcpy(data_pointer, (*iter)->GetRemoteIP().c_str(), (*iter)->GetRemoteIP().size());
data_pointer += ((*iter)->GetRemoteIP().size() + 1);
}
switch ((*iter)->GetServerListID()) {
case 1: {
*(unsigned int *) data_pointer = 0x00000030;
break;
}
case 2: {
*(unsigned int *) data_pointer = 0x00000009;
break;
}
default: {
*(unsigned int *) data_pointer = 0x00000001;
}
}
data_pointer += 4;
*(unsigned int *) data_pointer = (*iter)->GetServerId();
data_pointer += 4;
memcpy(data_pointer, (*iter)->GetServerLongName().c_str(), (*iter)->GetServerLongName().size());
data_pointer += ((*iter)->GetServerLongName().size() + 1);
memcpy(data_pointer, "EN", 2);
data_pointer += 3;
memcpy(data_pointer, "US", 2);
data_pointer += 3;
// 0 = Up, 1 = Down, 2 = Up, 3 = down, 4 = locked, 5 = locked(down)
if ((*iter)->GetStatus() < 0) {
if ((*iter)->GetZonesBooted() == 0) {
*(uint32 *) data_pointer = 0x01;
}
else {
*(uint32 *) data_pointer = 0x04;
}
}
else {
*(uint32 *) data_pointer = 0x02;
}
data_pointer += 4;
*(uint32 *) data_pointer = (*iter)->GetPlayersOnline();
data_pointer += 4;
++iter;
}
return outapp;
return std::make_unique<EQApplicationPacket>(OP_ServerListResponse, buf);
}
/**
@@ -278,9 +173,9 @@ void ServerManager::SendUserToWorldRequest(
const std::string &client_loginserver
)
{
auto iter = world_servers.begin();
auto iter = m_world_servers.begin();
bool found = false;
while (iter != world_servers.end()) {
while (iter != m_world_servers.end()) {
if ((*iter)->GetServerId() == server_id) {
EQ::Net::DynamicPacket outapp;
outapp.Resize(sizeof(UsertoWorldRequest_Struct));
@@ -316,8 +211,8 @@ bool ServerManager::ServerExists(
WorldServer *ignore
)
{
auto iter = world_servers.begin();
while (iter != world_servers.end()) {
auto iter = m_world_servers.begin();
while (iter != m_world_servers.end()) {
if ((*iter).get() == ignore) {
++iter;
continue;
@@ -343,8 +238,8 @@ void ServerManager::DestroyServerByName(
WorldServer *ignore
)
{
auto iter = world_servers.begin();
while (iter != world_servers.end()) {
auto iter = m_world_servers.begin();
while (iter != m_world_servers.end()) {
if ((*iter).get() == ignore) {
++iter;
continue;
@@ -353,7 +248,7 @@ void ServerManager::DestroyServerByName(
if ((*iter)->GetServerLongName().compare(server_long_name) == 0 &&
(*iter)->GetServerShortName().compare(server_short_name) == 0) {
(*iter)->GetConnection()->Handle()->Disconnect();
iter = world_servers.erase(iter);
iter = m_world_servers.erase(iter);
continue;
}
@@ -366,5 +261,5 @@ void ServerManager::DestroyServerByName(
*/
const std::list<std::unique_ptr<WorldServer>> &ServerManager::getWorldServers() const
{
return world_servers;
return m_world_servers;
}

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