Compare commits

...

202 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
460 changed files with 31273 additions and 20616 deletions
+2
View File
@@ -54,3 +54,5 @@ bin/
/Win32
/x64
/client_files/**/CMakeFiles/
.idea
+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)
+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;
+1 -1
View File
@@ -716,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);
}
+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",
};
+142 -2
View File
@@ -19,6 +19,8 @@
#include "emu_constants.h"
#include "languages.h"
#include "data_verification.h"
#include "bodytypes.h"
int16 EQ::invtype::GetInvTypeSize(int16 inv_type) {
@@ -148,8 +150,9 @@ 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;
}
@@ -191,9 +194,146 @@ const std::map<int, std::string>& EQ::constants::GetLanguageMap()
std::string EQ::constants::GetLanguageName(int language_id)
{
if (language_id >= LANG_COMMON_TONGUE && language_id <= LANG_UNKNOWN) {
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;
}
+61 -7
View File
@@ -22,6 +22,7 @@
#include "eq_limits.h"
#include "emu_versions.h"
#include "bodytypes.h"
#include <string.h>
@@ -220,12 +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;
@@ -328,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),
+1
View File
@@ -448,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
+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;
+63 -1
View File
@@ -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);
+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 {
+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";
-14
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
-14
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
-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)
-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)
-14
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
-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)
-14
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);
-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)
+13
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);
+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)
-14
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
-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)
@@ -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
);
+27 -1
View File
@@ -174,6 +174,24 @@ RULE_INT(Character, ResurrectionSicknessSpellID, 756, "756 is Default Resurrecti
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)
@@ -263,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")
@@ -491,6 +510,7 @@ RULE_INT(Combat, SneakPullAssistRange, 400, "Modified range of assist for sneak
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)
@@ -726,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)
@@ -764,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)
@@ -806,6 +828,10 @@ 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
+1
View File
@@ -226,6 +226,7 @@
#define ServerOP_UCSServerStatusReply 0x4010
#define ServerOP_HotReloadQuests 0x4011
#define ServerOP_UpdateSchedulerEvents 0x4012
#define ServerOP_ReloadContentFlags 0x4013
#define ServerOP_CZDialogueWindow 0x4500
#define ServerOP_CZLDoNUpdate 0x4501
+79 -12
View File
@@ -1239,10 +1239,10 @@ bool IsEffectIgnoredInStacking(int spa)
case SE_GravityEffect:
case 425:
//Spell effects implemented after ROF2, following same pattern, lets assume these should go here.
case SE_Fc_Spell_Damage_Pct_IncomingPC:
case SE_Fc_Spell_Damage_Pct_IncomingPC:
case SE_Fc_Spell_Damage_Amt_IncomingPC:
case SE_Ff_CasterClass:
case SE_Ff_Same_Caster:
case SE_Ff_Same_Caster:
case SE_Proc_Timer_Modifier:
case SE_Weapon_Stance:
case SE_TwinCastBlocker:
@@ -1417,8 +1417,8 @@ bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect)
case SE_MinDamageModifier:
case SE_ProcChance:
case SE_PetFlurry: // ? Need verified
case SE_DiseaseCounter:
case SE_PoisonCounter:
case SE_DiseaseCounter:
case SE_PoisonCounter:
case SE_CurseCounter:
case SE_CorruptionCounter:
return true;
@@ -1462,6 +1462,23 @@ bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect)
//Allowing anything not confirmed to be restricted / allowed to receive modifiers, as to not inhbit anyone making custom bard songs.
}
bool IsPulsingBardSong(int32 spell_id)
{
if (!IsValidSpell(spell_id)) {
return false;
}
if (spells[spell_id].buff_duration == 0xFFFF ||
spells[spell_id].recast_time> 0 ||
spells[spell_id].mana > 0 ||
IsEffectInSpell(spell_id, SE_TemporaryPets) ||
IsEffectInSpell(spell_id, SE_Familiar)) {
return false;
}
return true;
}
int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot)
{
if (!IsValidSpell(spell_id))
@@ -1576,7 +1593,7 @@ int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot)
return 0;
}
bool IsVirusSpell(int32 spell_id)
bool IsVirusSpell(int32 spell_id)
{
if (GetViralMinSpreadTime(spell_id) && GetViralMaxSpreadTime(spell_id) && GetViralSpreadRange(spell_id)){
return true;
@@ -1584,17 +1601,17 @@ bool IsVirusSpell(int32 spell_id)
return false;
}
int32 GetViralMinSpreadTime(int32 spell_id)
int32 GetViralMinSpreadTime(int32 spell_id)
{
return spells[spell_id].viral_targets;
}
int32 GetViralMaxSpreadTime(int32 spell_id)
int32 GetViralMaxSpreadTime(int32 spell_id)
{
return spells[spell_id].viral_timer;
}
int32 GetViralSpreadRange(int32 spell_id)
int32 GetViralSpreadRange(int32 spell_id)
{
return spells[spell_id].viral_range;
}
@@ -1605,23 +1622,23 @@ uint32 GetProcLimitTimer(int32 spell_id, int proc_type) {
if (!IsValidSpell(spell_id)) {
return 0;
}
bool use_next_timer = false;
for (int i = 0; i < EFFECT_COUNT; ++i) {
if (proc_type == SE_WeaponProc) {
if (proc_type == ProcType::MELEE_PROC) {
if (spells[spell_id].effect_id[i] == SE_WeaponProc || spells[spell_id].effect_id[i] == SE_AddMeleeProc) {
use_next_timer = true;
}
}
if (proc_type == SE_RangedProc) {
if (proc_type == ProcType::RANGED_PROC) {
if (spells[spell_id].effect_id[i] == SE_RangedProc) {
use_next_timer = true;
}
}
if (proc_type == SE_DefensiveProc) {
if (proc_type == ProcType::DEFENSIVE_PROC) {
if (spells[spell_id].effect_id[i] == SE_DefensiveProc) {
use_next_timer = true;
}
@@ -1633,3 +1650,53 @@ uint32 GetProcLimitTimer(int32 spell_id, int proc_type) {
}
return 0;
}
bool CastRestrictedSpell(int spellid)
{
switch (spellid) {
case SPELL_TOUCH_OF_VINITRAS:
case SPELL_DESPERATE_HOPE:
case SPELL_CHARM:
case SPELL_METAMORPHOSIS65:
case SPELL_JT_BUFF:
case SPELL_CAN_O_WHOOP_ASS:
case SPELL_PHOENIX_CHARM:
case SPELL_CAZIC_TOUCH:
case SPELL_AVATAR_KNOCKBACK:
case SPELL_SHAPECHANGE65:
case SPELL_SUNSET_HOME1218:
case SPELL_SUNSET_HOME819:
case SPELL_SHAPECHANGE75:
case SPELL_SHAPECHANGE80:
case SPELL_SHAPECHANGE85:
case SPELL_SHAPECHANGE90:
case SPELL_SHAPECHANGE95:
case SPELL_SHAPECHANGE100:
case SPELL_SHAPECHANGE25:
case SPELL_SHAPECHANGE30:
case SPELL_SHAPECHANGE35:
case SPELL_SHAPECHANGE40:
case SPELL_SHAPECHANGE45:
case SPELL_SHAPECHANGE50:
case SPELL_NPC_AEGOLISM:
case SPELL_SHAPECHANGE55:
case SPELL_SHAPECHANGE60:
case SPELL_COMMAND_OF_DRUZZIL:
case SPELL_SHAPECHANGE70:
return true;
default:
return false;
}
}
bool IgnoreCastingRestriction(int32 spell_id) {
/*
field 'cast_not_standing' allows casting when sitting, stunned, mezed, Divine Aura, through SPA 343 Interrupt casting
Likely also allows for casting while feared, but need to confirm. Possibly also while charmed.
This field also allows for damage to ignore DA immunity.
*/
if (spells[spell_id].cast_not_standing) {
return true;
}
return false;
}
+306 -283
View File
@@ -26,6 +26,7 @@
#define SPELLBOOK_UNKNOWN 0xFFFFFFFF //player profile spells are 32 bit
//some spell IDs which will prolly change, but are needed
#define SPELL_LIFEBURN 2755
#define SPELL_LEECH_TOUCH 2766
#define SPELL_LAY_ON_HANDS 87
#define SPELL_HARM_TOUCH 88
@@ -162,6 +163,12 @@
#define SPELL_RESURRECTION_SICKNESS3 37624
#define SPELL_PACT_OF_HATE_RECOURSE 40375
#define SPELL_INCENDIARY_OOZE_BUFF 32513
#define SPELL_EYE_OF_ZOMM 323
#define SPELL_MINOR_ILLUSION 287
#define SPELL_ILLUSION_TREE 601
#define SPELL_ILLUSION_FEMALE 1731
#define SPELL_ILLUSION_MALE 1732
#define SPELL_UNSUMMON_SELF 892
//spellgroup ids
#define SPELLGROUP_FRENZIED_BURNOUT 2754
@@ -172,8 +179,6 @@
#define SPELLGROUP_FURIOUS_RAMPAGE 38106
#define SPELLGROUP_SHROUD_OF_PRAYER 41050
#define EFFECT_COUNT 12
#define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2)
#define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists.
@@ -183,7 +188,14 @@
#define MAX_SYMPATHETIC_PROCS 10 // Number of sympathetic procs a client can have (This is arbitrary)
#define MAX_FOCUS_PROC_LIMIT_TIMERS 20 //Number of focus recast timers that can be going at same time (This is arbitrary)
#define MAX_PROC_LIMIT_TIMERS 8 //Number of proc delay timers that can be going at same time, different proc types get their own timer array. (This is arbitrary)
#define MAX_APPEARANCE_EFFECTS 20 //Up to 20 Appearance Effects can be saved to a mobs appearance effect array, these will be sent to other clients when they enter a zone (This is arbitrary)
#define MAX_CAST_ON_SKILL_USE 36 //Actual amount is MAX/3
//instrument item id's used as song components
#define INSTRUMENT_HAND_DRUM 13000
#define INSTRUMENT_WOODEN_FLUTE 13001
#define INSTRUMENT_LUTE 13011
#define INSTRUMENT_HORN 13012
const int Z_AGGRO=10;
@@ -219,292 +231,292 @@ enum SpellRestriction
{
UNKNOWN_3 = 3, // | caster restriction | seen in spell 30183 Mind Spiral
IS_NOT_ON_HORSE = 5, // | caster restriction |
IS_ANIMAL_OR_HUMANOID = 100, // This spell will only work on animals or humanoid creatures.
IS_DRAGON = 101, // This spell will only work on dragons.
IS_ANIMAL_OR_INSECT = 102, // This spell will only work on animals or insects.
IS_BODY_TYPE_MISC = 103, // This spell will only work on humanoids, lycanthropes, giants, Kael Drakkel giants, Coldain, animals, insects, constructs, dragons, Skyshrine dragons, Muramites, or creatures constructed from magic.
IS_BODY_TYPE_MISC2 = 104, // This spell will only work on humanoids, lycanthropes, giants, Kael Drakkel giants, Coldain, animals, or insects.
IS_PLANT = 105, // This spell will only work on plants.
IS_ANIMAL_OR_HUMANOID = 100, // This spell will only work on animals or humanoid creatures.
IS_DRAGON = 101, // This spell will only work on dragons.
IS_ANIMAL_OR_INSECT = 102, // This spell will only work on animals or insects.
IS_BODY_TYPE_MISC = 103, // This spell will only work on humanoids, lycanthropes, giants, Kael Drakkel giants, Coldain, animals, insects, constructs, dragons, Skyshrine dragons, Muramites, or creatures constructed from magic.
IS_BODY_TYPE_MISC2 = 104, // This spell will only work on humanoids, lycanthropes, giants, Kael Drakkel giants, Coldain, animals, or insects.
IS_PLANT = 105, // This spell will only work on plants.
IS_GIANT = 106, // This spell will only work on animals. | Live used to have this on spells restricted to Giants, but those spells were removed... We still have them
IS_NOT_ANIMAL_OR_HUMANOID = 108, // This spell will only work on targets that are neither animals or humanoid.
IS_BIXIE = 109, // This spell will only work on bixies.
IS_HARPY = 110, // This spell will only work on harpies.
IS_GNOLL = 111, // This spell will only work on gnolls.
IS_SPORALI = 112, // This spell will only work on fungusoids.
IS_KOBOLD = 113, // This spell will only work on kobolds.
IS_FROSTCRYPT_SHADE = 114, // This spell will only work on undead creatures or the Shades of Frostcrypt.
IS_DRAKKIN = 115, // This spell will only work on Drakkin.
IS_UNDEAD_OR_VALDEHOLM_GIANT = 116, // This spell will only work on undead creatures or the inhabitants of Valdeholm.
IS_ANIMAL_OR_PLANT = 117, // This spell will only work on plants or animals.
IS_SUMMONED = 118, // This spell will only work on constructs, elementals, or summoned elemental minions.
IS_WIZARD_USED_ON_MAGE_FIRE_PET = 119, // This spell will only work on wizards. | Live uses this on high level mage fire pets, which are wizard class
IS_UNDEAD = 120, //
IS_NOT_UNDEAD_OR_SUMMONED_OR_VAMPIRE = 121, // This spell will only work on creatures that are not undead, constructs, elementals, or vampires.
IS_FAE_OR_PIXIE = 122, // This spell will only work on Fae or pixies.
IS_HUMANOID = 123, //
IS_UNDEAD_AND_HP_LESS_THAN_10_PCT = 124, // The Essence Extractor whirrs but does not light up.
IS_CLOCKWORK_AND_HP_LESS_THAN_45_PCT = 125, // This spell will only work on clockwork gnomes.
IS_WISP_AND_HP_LESS_THAN_10_PCT = 126, // This spell will only work on wisps at or below 10% of their maximum HP.
IS_CLASS_MELEE_THAT_CAN_BASH_OR_KICK_EXCEPT_BARD = 127, // This spell will only work on non-bard targets that can bash or kick.
IS_CLASS_PURE_MELEE = 128, // This spell will only affect melee classes (warriors, monks, rogues, and berserkers).
IS_CLASS_PURE_CASTER = 129, // This spell will only affect pure caster classes (necromancers, wizards, magicians, and enchanters).
IS_CLASS_HYBRID_CLASS = 130, // This spell will only affect hybrid classes (paladins, rangers, shadow knights, bards, and beastlords).
IS_CLASS_WARRIOR = 131, // This spell will only affect Warriors.
IS_CLASS_CLERIC = 132, // This spell will only affect Clerics.
IS_CLASS_PALADIN = 133, // This spell will only affect Paladins.
IS_CLASS_RANGER = 134, // This spell will only affect Rangers.
IS_CLASS_SHADOWKNIGHT = 135, // This spell will only affect Shadow Knights.
IS_CLASS_DRUID = 136, // This spell will only affect Druids.
IS_CLASS_MONK = 137, // This spell will only affect Monks.
IS_CLASS_BARD = 138, // This spell will only affect Bards.
IS_CLASS_ROGUE = 139, // This spell will only affect Rogues.
IS_CLASS_SHAMAN = 140, // This spell will only affect Shamans.
IS_CLASS_NECRO = 141, // This spell will only affect Necromancers.
IS_CLASS_WIZARD = 142, // This spell will only affect Wizards.
IS_CLASS_MAGE = 143, // This spell will only affect Magicians.
IS_CLASS_ENCHANTER = 144, // This spell will only affect Enchanters.
IS_CLASS_BEASTLORD = 145, // This spell will only affect Beastlords.
IS_CLASS_BERSERKER = 146, // This spell will only affect Berserkers.
IS_CLASS_CLR_SHM_DRU = 147, // This spell will only affect priest classes (clerics, druids, and shaman).
IS_CLASS_NOT_WAR_PAL_SK = 148, // This spell will not affect Warriors, Paladins, or Shadow Knights.
IS_LEVEL_UNDER_100 = 150, // This spell will not affect any target over level 100.
IS_NOT_RAID_BOSS = 190, // This spell will not affect raid bosses.
IS_RAID_BOSS = 191, // This spell will only affect raid bosses.
FRENZIED_BURNOUT_ACTIVE = 192, // This spell will only cast if you have Frenzied Burnout active.
FRENZIED_BURNOUT_NOT_ACTIVE = 193, // This spell will only cast if you do not have Frenzied Burnout active.
IS_NOT_ANIMAL_OR_HUMANOID = 108, // This spell will only work on targets that are neither animals or humanoid.
IS_BIXIE = 109, // This spell will only work on bixies.
IS_HARPY = 110, // This spell will only work on harpies.
IS_GNOLL = 111, // This spell will only work on gnolls.
IS_SPORALI = 112, // This spell will only work on fungusoids.
IS_KOBOLD = 113, // This spell will only work on kobolds.
IS_FROSTCRYPT_SHADE = 114, // This spell will only work on undead creatures or the Shades of Frostcrypt.
IS_DRAKKIN = 115, // This spell will only work on Drakkin.
IS_UNDEAD_OR_VALDEHOLM_GIANT = 116, // This spell will only work on undead creatures or the inhabitants of Valdeholm.
IS_ANIMAL_OR_PLANT = 117, // This spell will only work on plants or animals.
IS_SUMMONED = 118, // This spell will only work on constructs, elementals, or summoned elemental minions.
IS_WIZARD_USED_ON_MAGE_FIRE_PET = 119, // This spell will only work on wizards. | Live uses this on high level mage fire pets, which are wizard class
IS_UNDEAD = 120, //
IS_NOT_UNDEAD_OR_SUMMONED_OR_VAMPIRE = 121, // This spell will only work on creatures that are not undead, constructs, elementals, or vampires.
IS_FAE_OR_PIXIE = 122, // This spell will only work on Fae or pixies.
IS_HUMANOID = 123, //
IS_UNDEAD_AND_HP_LESS_THAN_10_PCT = 124, // The Essence Extractor whirrs but does not light up.
IS_CLOCKWORK_AND_HP_LESS_THAN_45_PCT = 125, // This spell will only work on clockwork gnomes.
IS_WISP_AND_HP_LESS_THAN_10_PCT = 126, // This spell will only work on wisps at or below 10% of their maximum HP.
IS_CLASS_MELEE_THAT_CAN_BASH_OR_KICK_EXCEPT_BARD = 127, // This spell will only work on non-bard targets that can bash or kick.
IS_CLASS_PURE_MELEE = 128, // This spell will only affect melee classes (warriors, monks, rogues, and berserkers).
IS_CLASS_PURE_CASTER = 129, // This spell will only affect pure caster classes (necromancers, wizards, magicians, and enchanters).
IS_CLASS_HYBRID_CLASS = 130, // This spell will only affect hybrid classes (paladins, rangers, shadow knights, bards, and beastlords).
IS_CLASS_WARRIOR = 131, // This spell will only affect Warriors.
IS_CLASS_CLERIC = 132, // This spell will only affect Clerics.
IS_CLASS_PALADIN = 133, // This spell will only affect Paladins.
IS_CLASS_RANGER = 134, // This spell will only affect Rangers.
IS_CLASS_SHADOWKNIGHT = 135, // This spell will only affect Shadow Knights.
IS_CLASS_DRUID = 136, // This spell will only affect Druids.
IS_CLASS_MONK = 137, // This spell will only affect Monks.
IS_CLASS_BARD = 138, // This spell will only affect Bards.
IS_CLASS_ROGUE = 139, // This spell will only affect Rogues.
IS_CLASS_SHAMAN = 140, // This spell will only affect Shamans.
IS_CLASS_NECRO = 141, // This spell will only affect Necromancers.
IS_CLASS_WIZARD = 142, // This spell will only affect Wizards.
IS_CLASS_MAGE = 143, // This spell will only affect Magicians.
IS_CLASS_ENCHANTER = 144, // This spell will only affect Enchanters.
IS_CLASS_BEASTLORD = 145, // This spell will only affect Beastlords.
IS_CLASS_BERSERKER = 146, // This spell will only affect Berserkers.
IS_CLASS_CLR_SHM_DRU = 147, // This spell will only affect priest classes (clerics, druids, and shaman).
IS_CLASS_NOT_WAR_PAL_SK = 148, // This spell will not affect Warriors, Paladins, or Shadow Knights.
IS_LEVEL_UNDER_100 = 150, // This spell will not affect any target over level 100.
IS_NOT_RAID_BOSS = 190, // This spell will not affect raid bosses.
IS_RAID_BOSS = 191, // This spell will only affect raid bosses.
FRENZIED_BURNOUT_ACTIVE = 192, // This spell will only cast if you have Frenzied Burnout active.
FRENZIED_BURNOUT_NOT_ACTIVE = 193, // This spell will only cast if you do not have Frenzied Burnout active.
UNKNOWN_199 = 199, //
IS_HP_ABOVE_75_PCT = 201, //
IS_HP_ABOVE_75_PCT = 201, //
IS_HP_LESS_THAN_20_PCT = 203, // Your target's HP must be at 20% of its maximum or below. | caster restriction |
IS_HP_LESS_THAN_50_PCT = 204, // Your target's HP must be at 50% of its maximum or below. | caster restriction |
IS_HP_LESS_THAN_75_PCT = 205, // Your target's HP must be at 75% of its maximum or below.
IS_NOT_IN_COMBAT = 216, // This spell will only affect creatures that are not in combat.
HAS_AT_LEAST_1_PET_ON_HATELIST = 221, //
HAS_AT_LEAST_2_PETS_ON_HATELIST = 222, //
HAS_AT_LEAST_3_PETS_ON_HATELIST = 223, //
HAS_AT_LEAST_4_PETS_ON_HATELIST = 224, //
HAS_AT_LEAST_5_PETS_ON_HATELIST = 225, //
HAS_AT_LEAST_6_PETS_ON_HATELIST = 226, //
HAS_AT_LEAST_7_PETS_ON_HATELIST = 227, //
HAS_AT_LEAST_8_PETS_ON_HATELIST = 228, //
HAS_AT_LEAST_9_PETS_ON_HATELIST = 229, //
HAS_AT_LEAST_10_PETS_ON_HATELIST = 230, //
HAS_AT_LEAST_11_PETS_ON_HATELIST = 231, //
HAS_AT_LEAST_12_PETS_ON_HATELIST = 232, //
HAS_AT_LEAST_13_PETS_ON_HATELIST = 233, //
HAS_AT_LEAST_14_PETS_ON_HATELIST = 234, //
HAS_AT_LEAST_15_PETS_ON_HATELIST = 235, //
HAS_AT_LEAST_16_PETS_ON_HATELIST = 236, //
HAS_AT_LEAST_17_PETS_ON_HATELIST = 237, //
HAS_AT_LEAST_18_PETS_ON_HATELIST = 238, //
HAS_AT_LEAST_19_PETS_ON_HATELIST = 239, //
HAS_AT_LEAST_20_PETS_ON_HATELIST = 240, //
IS_HP_LESS_THAN_75_PCT = 205, // Your target's HP must be at 75% of its maximum or below.
IS_NOT_IN_COMBAT = 216, // This spell will only affect creatures that are not in combat.
HAS_AT_LEAST_1_PET_ON_HATELIST = 221, //
HAS_AT_LEAST_2_PETS_ON_HATELIST = 222, //
HAS_AT_LEAST_3_PETS_ON_HATELIST = 223, //
HAS_AT_LEAST_4_PETS_ON_HATELIST = 224, //
HAS_AT_LEAST_5_PETS_ON_HATELIST = 225, //
HAS_AT_LEAST_6_PETS_ON_HATELIST = 226, //
HAS_AT_LEAST_7_PETS_ON_HATELIST = 227, //
HAS_AT_LEAST_8_PETS_ON_HATELIST = 228, //
HAS_AT_LEAST_9_PETS_ON_HATELIST = 229, //
HAS_AT_LEAST_10_PETS_ON_HATELIST = 230, //
HAS_AT_LEAST_11_PETS_ON_HATELIST = 231, //
HAS_AT_LEAST_12_PETS_ON_HATELIST = 232, //
HAS_AT_LEAST_13_PETS_ON_HATELIST = 233, //
HAS_AT_LEAST_14_PETS_ON_HATELIST = 234, //
HAS_AT_LEAST_15_PETS_ON_HATELIST = 235, //
HAS_AT_LEAST_16_PETS_ON_HATELIST = 236, //
HAS_AT_LEAST_17_PETS_ON_HATELIST = 237, //
HAS_AT_LEAST_18_PETS_ON_HATELIST = 238, //
HAS_AT_LEAST_19_PETS_ON_HATELIST = 239, //
HAS_AT_LEAST_20_PETS_ON_HATELIST = 240, //
IS_HP_LESS_THAN_35_PCT = 250, // Your target's HP must be at 35% of its maximum or below.
HAS_BETWEEN_1_TO_2_PETS_ON_HATELIST = 260, // between 1 and 2 pets
HAS_BETWEEN_3_TO_5_PETS_ON_HATELIST = 261, // between 3 and 5 pets
HAS_BETWEEN_6_TO_9_PETS_ON_HATELIST = 262, // between 6 and 9 pets
HAS_BETWEEN_10_TO_14_PETS_ON_HATELIST = 263, // between 10 and 14 pets
HAS_MORE_THAN_14_PETS_ON_HATELIST = 264, // 15 or more pets
IS_CLASS_CHAIN_OR_PLATE = 304, // This spell will only affect plate or chain wearing classes.
IS_HP_BETWEEN_5_AND_9_PCT = 350, // Your target's HP must be between 5% and 9% of its maximum.
IS_HP_BETWEEN_10_AND_14_PCT = 351, // Your target's HP must be between 10% and 14% of its maximum.
IS_HP_BETWEEN_15_AND_19_PCT = 352, // Your target's HP must be between 15% and 19% of its maximum.
IS_HP_BETWEEN_20_AND_24_PCT = 353, // Your target's HP must be between 20% and 24% of its maximum.
IS_HP_BETWEEN_25_AND_29_PCT = 354, // Your target's HP must be between 25% and 29% of its maximum.
IS_HP_BETWEEN_30_AND_34_PCT = 355, // Your target's HP must be between 30% and 34% of its maximum.
IS_HP_BETWEEN_35_AND_39_PCT = 356, // Your target's HP must be between 35% and 39% of its maximum.
IS_HP_BETWEEN_40_AND_44_PCT = 357, // Your target's HP must be between 40% and 44% of its maximum.
IS_HP_BETWEEN_45_AND_49_PCT = 358, // Your target's HP must be between 45% and 49% of its maximum.
IS_HP_BETWEEN_50_AND_54_PCT = 359, // Your target's HP must be between 50% and 54% of its maximum.
IS_HP_BETWEEN_55_AND_59_PCT = 360, // Your target's HP must be between 55% and 59% of its maximum.
IS_HP_BETWEEN_5_AND_15_PCT = 398, // Your target's HP must be between 5% and 15% of its maximum.
IS_HP_BETWEEN_15_AND_25_PCT = 399, // Your target's HP must be between 15% and 25% of its maximum.
IS_HP_BETWEEN_1_AND_25_PCT = 400, // Your target's HP must be at 25% of its maximum or below.
IS_HP_BETWEEN_25_AND_35_PCT = 401, // Your target's HP must be between 25% and 35% of its maximum.
IS_HP_BETWEEN_35_AND_45_PCT = 402, // Your target's HP must be between 35% and 45% of its maximum.
IS_HP_BETWEEN_45_AND_55_PCT = 403, // Your target's HP must be between 45% and 55% of its maximum.
IS_HP_BETWEEN_55_AND_65_PCT = 404, // Your target's HP must be between 55% and 65% of its maximum.
IS_HP_BETWEEN_65_AND_75_PCT = 405, // Your target's HP must be between 65% and 75% of its maximum.
IS_HP_BETWEEN_75_AND_85_PCT = 406, // Your target's HP must be between 75% and 85% of its maximum.
IS_HP_BETWEEN_85_AND_95_PCT = 407, // Your target's HP must be between 85% and 95% of its maximum.
IS_HP_ABOVE_45_PCT = 408, // Your target's HP must be at least 45% of its maximum.
IS_HP_ABOVE_55_PCT = 409, // Your target's HP must be at least 55% of its maximum.
UNKNOWN_TOO_MUCH_HP_410 = 410, // Your target has too much HP to be affected by this spell.
UNKNOWN_TOO_MUCH_HP_411 = 411, // Your target has too much HP to be affected by this spell.
IS_HP_ABOVE_99_PCT = 412, //
IS_MANA_ABOVE_10_PCT = 429, // You must have at least 10% of your maximum mana available to cast this spell. | caster restriction |
IS_HP_BELOW_5_PCT = 501, //
IS_HP_BELOW_10_PCT = 502, //
IS_HP_BELOW_15_PCT = 503, //
IS_HP_BELOW_20_PCT = 504, // Your target's HP must be at 20% of its maximum or below.
IS_HP_BELOW_25_PCT = 505, //
IS_HP_BELOW_30_PCT = 506, //
IS_HP_BELOW_35_PCT = 507, //
IS_HP_BELOW_40_PCT = 508, //
IS_HP_BELOW_45_PCT = 509, // Your target's HP must be at 45% of its maximum or below.
IS_HP_BELOW_50_PCT = 510, //
IS_HP_BELOW_55_PCT = 511, //
IS_HP_BELOW_60_PCT = 512, //
IS_HP_BELOW_65_PCT = 513, //
IS_HP_BELOW_70_PCT = 514, //
IS_HP_BELOW_75_PCT = 515, //
IS_HP_BELOW_80_PCT = 516, //
IS_HP_BELOW_85_PCT = 517, //
HAS_BETWEEN_1_TO_2_PETS_ON_HATELIST = 260, // between 1 and 2 pets
HAS_BETWEEN_3_TO_5_PETS_ON_HATELIST = 261, // between 3 and 5 pets
HAS_BETWEEN_6_TO_9_PETS_ON_HATELIST = 262, // between 6 and 9 pets
HAS_BETWEEN_10_TO_14_PETS_ON_HATELIST = 263, // between 10 and 14 pets
HAS_MORE_THAN_14_PETS_ON_HATELIST = 264, // 15 or more pets
IS_CLASS_CHAIN_OR_PLATE = 304, // This spell will only affect plate or chain wearing classes.
IS_HP_BETWEEN_5_AND_9_PCT = 350, // Your target's HP must be between 5% and 9% of its maximum.
IS_HP_BETWEEN_10_AND_14_PCT = 351, // Your target's HP must be between 10% and 14% of its maximum.
IS_HP_BETWEEN_15_AND_19_PCT = 352, // Your target's HP must be between 15% and 19% of its maximum.
IS_HP_BETWEEN_20_AND_24_PCT = 353, // Your target's HP must be between 20% and 24% of its maximum.
IS_HP_BETWEEN_25_AND_29_PCT = 354, // Your target's HP must be between 25% and 29% of its maximum.
IS_HP_BETWEEN_30_AND_34_PCT = 355, // Your target's HP must be between 30% and 34% of its maximum.
IS_HP_BETWEEN_35_AND_39_PCT = 356, // Your target's HP must be between 35% and 39% of its maximum.
IS_HP_BETWEEN_40_AND_44_PCT = 357, // Your target's HP must be between 40% and 44% of its maximum.
IS_HP_BETWEEN_45_AND_49_PCT = 358, // Your target's HP must be between 45% and 49% of its maximum.
IS_HP_BETWEEN_50_AND_54_PCT = 359, // Your target's HP must be between 50% and 54% of its maximum.
IS_HP_BETWEEN_55_AND_59_PCT = 360, // Your target's HP must be between 55% and 59% of its maximum.
IS_HP_BETWEEN_5_AND_15_PCT = 398, // Your target's HP must be between 5% and 15% of its maximum.
IS_HP_BETWEEN_15_AND_25_PCT = 399, // Your target's HP must be between 15% and 25% of its maximum.
IS_HP_BETWEEN_1_AND_25_PCT = 400, // Your target's HP must be at 25% of its maximum or below.
IS_HP_BETWEEN_25_AND_35_PCT = 401, // Your target's HP must be between 25% and 35% of its maximum.
IS_HP_BETWEEN_35_AND_45_PCT = 402, // Your target's HP must be between 35% and 45% of its maximum.
IS_HP_BETWEEN_45_AND_55_PCT = 403, // Your target's HP must be between 45% and 55% of its maximum.
IS_HP_BETWEEN_55_AND_65_PCT = 404, // Your target's HP must be between 55% and 65% of its maximum.
IS_HP_BETWEEN_65_AND_75_PCT = 405, // Your target's HP must be between 65% and 75% of its maximum.
IS_HP_BETWEEN_75_AND_85_PCT = 406, // Your target's HP must be between 75% and 85% of its maximum.
IS_HP_BETWEEN_85_AND_95_PCT = 407, // Your target's HP must be between 85% and 95% of its maximum.
IS_HP_ABOVE_45_PCT = 408, // Your target's HP must be at least 45% of its maximum.
IS_HP_ABOVE_55_PCT = 409, // Your target's HP must be at least 55% of its maximum.
UNKNOWN_TOO_MUCH_HP_410 = 410, // Your target has too much HP to be affected by this spell.
UNKNOWN_TOO_MUCH_HP_411 = 411, // Your target has too much HP to be affected by this spell.
IS_HP_ABOVE_99_PCT = 412, //
IS_MANA_ABOVE_10_PCT = 429, // You must have at least 10% of your maximum mana available to cast this spell. | caster restriction |
IS_HP_BELOW_5_PCT = 501, //
IS_HP_BELOW_10_PCT = 502, //
IS_HP_BELOW_15_PCT = 503, //
IS_HP_BELOW_20_PCT = 504, // Your target's HP must be at 20% of its maximum or below.
IS_HP_BELOW_25_PCT = 505, //
IS_HP_BELOW_30_PCT = 506, //
IS_HP_BELOW_35_PCT = 507, //
IS_HP_BELOW_40_PCT = 508, //
IS_HP_BELOW_45_PCT = 509, // Your target's HP must be at 45% of its maximum or below.
IS_HP_BELOW_50_PCT = 510, //
IS_HP_BELOW_55_PCT = 511, //
IS_HP_BELOW_60_PCT = 512, //
IS_HP_BELOW_65_PCT = 513, //
IS_HP_BELOW_70_PCT = 514, //
IS_HP_BELOW_75_PCT = 515, //
IS_HP_BELOW_80_PCT = 516, //
IS_HP_BELOW_85_PCT = 517, //
IS_HP_BELOW_90_PCT = 518, // This ability requires you to be at or below 90% of your maximum HP. | caster restriction |
IS_HP_BELOW_95_PCT = 519, //
IS_HP_BELOW_95_PCT = 519, //
IS_MANA_BELOW_UNKNOWN_PCT = 521, //
IS_ENDURANCE_BELOW_40_PCT = 522, //
IS_MANA_BELOW_40_PCT = 523, //
IS_HP_ABOVE_20_PCT = 524, // Your target's HP must be at least 21% of its maximum.
IS_ENDURANCE_BELOW_40_PCT = 522, //
IS_MANA_BELOW_40_PCT = 523, //
IS_HP_ABOVE_20_PCT = 524, // Your target's HP must be at least 21% of its maximum.
IS_BODY_TYPE_UNDEFINED = 600, // This spell will only work on creatures with an undefined body type.
IS_BODY_TYPE_HUMANOID = 601, // This spell will only work on humanoid creatures.
IS_BODY_TYPE_WEREWOLF = 602, // This spell will only work on lycanthrope creatures.
IS_BODY_TYPE_UNDEAD = 603, // This spell will only work on undead creatures.
IS_BODY_TYPE_GIANTS = 604, // This spell will only work on giants.
IS_BODY_TYPE_CONSTRUCTS = 605, // This spell will only work on constructs.
IS_BODY_TYPE_EXTRAPLANAR = 606, // This spell will only work on extraplanar creatures.
IS_BODY_TYPE_MAGICAL_CREATURE = 607, // This spell will only work on creatures constructed from magic.
IS_BODY_TYPE_UNDEADPET = 608, // This spell will only work on animated undead servants.
IS_BODY_TYPE_KAELGIANT = 609, // This spell will only work on the Giants of Kael Drakkal.
IS_BODY_TYPE_COLDAIN = 610, // This spell will only work on Coldain Dwarves.
IS_BODY_TYPE_VAMPIRE = 612, // This spell will only work on vampires.
IS_BODY_TYPE_ATEN_HA_RA = 613, // This spell will only work on Aten Ha Ra.
IS_BODY_TYPE_GREATER_AHKEVANS = 614, // This spell will only work on Greater Ahkevans.
IS_BODY_TYPE_KHATI_SHA = 615, // This spell will only work on Khati Sha.
IS_BODY_TYPE_LORD_INQUISITOR_SERU = 616, // This spell will only work on Lord Inquisitor Seru.
IS_BODY_TYPE_GRIEG_VENEFICUS = 617, // This spell will only work on Grieg Veneficus.
IS_BODY_TYPE_HUMANOID = 601, // This spell will only work on humanoid creatures.
IS_BODY_TYPE_WEREWOLF = 602, // This spell will only work on lycanthrope creatures.
IS_BODY_TYPE_UNDEAD = 603, // This spell will only work on undead creatures.
IS_BODY_TYPE_GIANTS = 604, // This spell will only work on giants.
IS_BODY_TYPE_CONSTRUCTS = 605, // This spell will only work on constructs.
IS_BODY_TYPE_EXTRAPLANAR = 606, // This spell will only work on extraplanar creatures.
IS_BODY_TYPE_MAGICAL_CREATURE = 607, // This spell will only work on creatures constructed from magic.
IS_BODY_TYPE_UNDEADPET = 608, // This spell will only work on animated undead servants.
IS_BODY_TYPE_KAELGIANT = 609, // This spell will only work on the Giants of Kael Drakkal.
IS_BODY_TYPE_COLDAIN = 610, // This spell will only work on Coldain Dwarves.
IS_BODY_TYPE_VAMPIRE = 612, // This spell will only work on vampires.
IS_BODY_TYPE_ATEN_HA_RA = 613, // This spell will only work on Aten Ha Ra.
IS_BODY_TYPE_GREATER_AHKEVANS = 614, // This spell will only work on Greater Ahkevans.
IS_BODY_TYPE_KHATI_SHA = 615, // This spell will only work on Khati Sha.
IS_BODY_TYPE_LORD_INQUISITOR_SERU = 616, // This spell will only work on Lord Inquisitor Seru.
IS_BODY_TYPE_GRIEG_VENEFICUS = 617, // This spell will only work on Grieg Veneficus.
IS_BODY_TYPE_FROM_PLANE_OF_WAR = 619, // This spell will only work on creatures from the Plane of War.
IS_BODY_TYPE_LUGGALD = 620, // This spell will only work on Luggalds.
IS_BODY_TYPE_ANIMAL = 621, // This spell will only work on animals.
IS_BODY_TYPE_INSECT = 622, // This spell will only work on insects.
IS_BODY_TYPE_MONSTER = 623, // This spell will only work on monsters.
IS_BODY_TYPE_ELEMENTAL = 624, // This spell will only work on elemental creatures.
IS_BODY_TYPE_PLANT = 625, // This spell will only work on plants.
IS_BODY_TYPE_DRAGON2 = 626, // This spell will only work on dragons.
IS_BODY_TYPE_SUMMONED_ELEMENTAL = 627, // This spell will only work on summoned elementals.
IS_BODY_TYPE_WARDER = 628, //
IS_BODY_TYPE_DRAGON_OF_TOV = 630, // This spell will only work on Dragons of Veeshan's Temple.
IS_BODY_TYPE_FAMILIAR = 631, // This spell will only work on familiars.
IS_BODY_TYPE_MURAMITE = 634, // This spell will only work on Muramites.
IS_NOT_UNDEAD_OR_SUMMONED = 635, //
IS_NOT_PLANT = 636, // This spell will not affect plants.
IS_NOT_CLIENT = 700, // This spell will not work on adventurers.
IS_CLIENT = 701, // This spell will only work on adventurers.
IS_BODY_TYPE_LUGGALD = 620, // This spell will only work on Luggalds.
IS_BODY_TYPE_ANIMAL = 621, // This spell will only work on animals.
IS_BODY_TYPE_INSECT = 622, // This spell will only work on insects.
IS_BODY_TYPE_MONSTER = 623, // This spell will only work on monsters.
IS_BODY_TYPE_ELEMENTAL = 624, // This spell will only work on elemental creatures.
IS_BODY_TYPE_PLANT = 625, // This spell will only work on plants.
IS_BODY_TYPE_DRAGON2 = 626, // This spell will only work on dragons.
IS_BODY_TYPE_SUMMONED_ELEMENTAL = 627, // This spell will only work on summoned elementals.
IS_BODY_TYPE_WARDER = 628, //
IS_BODY_TYPE_DRAGON_OF_TOV = 630, // This spell will only work on Dragons of Veeshan's Temple.
IS_BODY_TYPE_FAMILIAR = 631, // This spell will only work on familiars.
IS_BODY_TYPE_MURAMITE = 634, // This spell will only work on Muramites.
IS_NOT_UNDEAD_OR_SUMMONED = 635, //
IS_NOT_PLANT = 636, // This spell will not affect plants.
IS_NOT_CLIENT = 700, // This spell will not work on adventurers.
IS_CLIENT = 701, // This spell will only work on adventurers.
IS_LEVEL_ABOVE_42_AND_IS_CLIENT = 800, // This spell will only work on level 43 or higher adventurers.
UNKNOWN_812 = 812, // | seen in spell 22616 Thaumatize Pet Mana Regen Base |
UNKNOWN_814 = 814, // | seen in spell 22704 Vegetentacles I |
IS_TREANT = 815, // This spell will only work on treants.
IS_BIXIE2 = 816, // This spell will only work on bixies.
IS_SCARECROW = 817, // This spell will only work on scarecrows.
IS_VAMPIRE_OR_UNDEAD_OR_UNDEADPET = 818, // This spell will only work on vampires, undead, or animated undead creatures.
IS_NOT_VAMPIRE_OR_UNDEAD = 819, // This spell will not work on vampires or undead creatures.
IS_CLASS_KNIGHT_HYBRID_MELEE = 820, // This spell will only work on knights, hybrids, or melee classes.
IS_CLASS_WARRIOR_CASTER_PRIEST = 821, // This spell will only work on warriors, casters, or priests.
IS_TREANT = 815, // This spell will only work on treants.
IS_BIXIE2 = 816, // This spell will only work on bixies.
IS_SCARECROW = 817, // This spell will only work on scarecrows.
IS_VAMPIRE_OR_UNDEAD_OR_UNDEADPET = 818, // This spell will only work on vampires, undead, or animated undead creatures.
IS_NOT_VAMPIRE_OR_UNDEAD = 819, // This spell will not work on vampires or undead creatures.
IS_CLASS_KNIGHT_HYBRID_MELEE = 820, // This spell will only work on knights, hybrids, or melee classes.
IS_CLASS_WARRIOR_CASTER_PRIEST = 821, // This spell will only work on warriors, casters, or priests.
UNKNOWN_822 = 822, // | seen in spell 22870 Morell's Distraction 822 |
IS_END_BELOW_21_PCT = 825, // This ability requires you to be at or below 21% of your maximum endurance.
IS_END_BELOW_25_PCT = 826, // This ability requires you to be at or below 25% of your maximum endurance.
IS_END_BELOW_29_PCT = 827, // This ability requires you to be at or below 29% of your maximum endurance.
IS_REGULAR_SERVER = 836, //
IS_PROGRESSION_SERVER = 837, //
IS_END_BELOW_21_PCT = 825, // This ability requires you to be at or below 21% of your maximum endurance.
IS_END_BELOW_25_PCT = 826, // This ability requires you to be at or below 25% of your maximum endurance.
IS_END_BELOW_29_PCT = 827, // This ability requires you to be at or below 29% of your maximum endurance.
IS_REGULAR_SERVER = 836, //
IS_PROGRESSION_SERVER = 837, //
IS_GOD_EXPANSION_UNLOCKED = 839, //
UNKNOWN_840 = 840, // | caster restriction | seen in spell 6883 Expedient Recovery
UNKNOWN_841 = 841, // | caster restriction | seen in spell 32192 Merciless Blow
IS_HUMANOID_LEVEL_84_MAX = 842, //
IS_HUMANOID_LEVEL_86_MAX = 843, //
IS_HUMANOID_LEVEL_88_MAX = 844, //
IS_HUMANOID_LEVEL_84_MAX = 842, //
IS_HUMANOID_LEVEL_86_MAX = 843, //
IS_HUMANOID_LEVEL_88_MAX = 844, //
HAS_CRYSTALLIZED_FLAME_BUFF = 845, // This spell will only work on targets afflicted by Crystallized Flame. | On live spell does not appear to be a buff
HAS_INCENDIARY_OOZE_BUFF = 847, // This spell will only work on targets afflicted by Incendiary Ooze.
IS_LEVEL_90_MAX = 860, //
IS_LEVEL_92_MAX = 861, //
IS_LEVEL_94_MAX = 862, //
IS_LEVEL_95_MAX = 863, //
IS_LEVEL_97_MAX = 864, //
IS_LEVEL_99_MAX = 865, //
HAS_INCENDIARY_OOZE_BUFF = 847, // This spell will only work on targets afflicted by Incendiary Ooze.
IS_LEVEL_90_MAX = 860, //
IS_LEVEL_92_MAX = 861, //
IS_LEVEL_94_MAX = 862, //
IS_LEVEL_95_MAX = 863, //
IS_LEVEL_97_MAX = 864, //
IS_LEVEL_99_MAX = 865, //
HAS_WEAPONSTANCE_DEFENSIVE_PROFICIENCY = 866, // | caster restriction |
HAS_WEAPONSTANCE_TWO_HAND_PROFICIENCY = 867, // | caster restriction |
HAS_WEAPONSTANCE_TWO_HAND_PROFICIENCY = 867, // | caster restriction |
HAS_WEAPONSTANCE_DUAL_WEILD_PROFICIENCY = 868, // | caster restriction |
IS_LEVEL_100_MAX = 869, //
IS_LEVEL_102_MAX = 870, //
IS_LEVEL_104_MAX = 871, //
IS_LEVEL_105_MAX = 872, //
IS_LEVEL_107_MAX = 873, //
IS_LEVEL_109_MAX = 874, //
IS_LEVEL_110_MAX = 875, //
IS_LEVEL_112_MAX = 876, //
IS_LEVEL_114_MAX = 877, //
IS_LEVEL_100_MAX = 869, //
IS_LEVEL_102_MAX = 870, //
IS_LEVEL_104_MAX = 871, //
IS_LEVEL_105_MAX = 872, //
IS_LEVEL_107_MAX = 873, //
IS_LEVEL_109_MAX = 874, //
IS_LEVEL_110_MAX = 875, //
IS_LEVEL_112_MAX = 876, //
IS_LEVEL_114_MAX = 877, //
HAS_TBL_ESIANTI_ACCESS = 997, // This spell will only transport adventurers who have gained access to Esianti: Palace of the Winds. | not implemented
HAS_ITEM_CLOCKWORK_SCRAPS = 999, //
IS_BETWEEN_LEVEL_1_AND_75 = 1000, //
IS_BETWEEN_LEVEL_76_AND_85 = 1001, //
IS_BETWEEN_LEVEL_86_AND_95 = 1002, //
IS_BETWEEN_LEVEL_96_AND_105 = 1003, //
IS_HP_LESS_THAN_80_PCT = 1004, //
IS_LEVEL_ABOVE_34 = 1474, // Your target must be level 35 or higher.
IN_TWO_HANDED_STANCE = 2000, // You must be in your two-handed stance to use this ability.
IN_DUAL_WIELD_HANDED_STANCE = 2001, // You must be in your dual-wielding stance to use this ability.
IN_SHIELD_STANCE = 2002, // You must be in your shield stance to use this ability.
NOT_IN_TWO_HANDED_STANCE = 2010, // You may not use this ability if you are in your two-handed stance.
NOT_IN_DUAL_WIELD_HANDED_STANCE = 2011, // You may not use this ability if you are in your dual-wielding stance.
NOT_IN_SHIELD_STANCE = 2012, // You may not use this ability if you are in your shield stance.
LEVEL_46_MAX = 2761, //
DISABLED_UNTIL_EXPANSION_ROK = 7000, // This ability is disabled until Ruins of Kunark.
DISABLED_UNTIL_EXPANSION_SOV = 7001, // This ability is disabled until Scars of Velious.
DISABLED_UNTIL_EXPANSION_SOL = 7002, // This ability is disabled until Shadows of Luclin.
DISABLED_UNTIL_EXPANSION_POP = 7003, // This ability is disabled until Planes of Power.
DISABLED_UNTIL_EXPANSION_LOY = 7004, // This ability is disabled until Legacy of Ykesha.
DISABLED_UNTIL_EXPANSION_LDON = 7005, // This ability is disabled until Lost Dungeons of Norrath.
DISABLED_UNTIL_EXPANSION_GOD = 7006, // This ability is disabled until Gates of Discord.
DISABLED_UNTIL_EXPANSION_OOW = 7007, // This ability is disabled until Omens of War.
DISABLED_UNTIL_EXPANSION_DON = 7008, // This ability is disabled until Dragons of Norrath.
DISABLED_UNTIL_EXPANSION_DOD = 7009, // This ability is disabled until Depths of Darkhollow.
DISABLED_UNTIL_EXPANSION_POR = 7010, // This ability is disabled until Prophecy of Ro.
DISABLED_UNTIL_EXPANSION_TSS = 7011, // This ability is disabled until Serpent's Spine.
DISABLED_UNTIL_EXPANSION_TBS = 7012, // This ability is disabled until Buried Sea.
DISABLED_UNTIL_EXPANSION_SOF = 7013, // This ability is disabled until Secrets of Faydwer.
DISABLED_UNTIL_EXPANSION_SOD = 7014, // This ability is disabled until Seeds of Destruction.
DISABLED_UNTIL_EXPANSION_UF = 7015, // This ability is disabled until Underfoot.
DISABLED_UNTIL_EXPANSION_HOT = 7016, // This ability is disabled until House of Thule.
DISABLED_UNTIL_EXPANSION_VOA = 7017, // This ability is disabled until Veil of Alaris.
DISABLED_UNTIL_EXPANSION_ROF = 7018, // This ability is disabled until Rain of Fear.
DISABLED_UNTIL_EXPANSION_COF = 7019, // This ability is disabled until Call of the Forsaken.
DISABLED_UNTIL_EXPANSION_TDS = 7020, // This ability is disabled until Darkened Sea.
DISABLED_UNTIL_EXPANSION_TBM = 7021, // This ability is disabled until Broken Mirror.
DISABLED_UNTIL_EXPANSION_EOK = 7022, // This ability is disabled until Empires of Kunark.
DISABLED_UNTIL_EXPANSION_ROS = 7023, // This ability is disabled until Ring of Scale.
DISABLED_UNTIL_EXPANSION_TBL = 7024, // This ability is disabled until The Burning Lands.
DISABLED_UNTIL_EXPANSION_TOV = 7025, // This ability is disabled until Torment of Velious.
DISABLED_UNTIL_EXPANSION_COV = 7026, // This ability is disabled until Claws of Veeshan.
HAS_NO_MANA_BURN_BUFF = 8450, // This spell will not take hold until the effects of the previous Mana Burn have expired.
HAS_ITEM_CLOCKWORK_SCRAPS = 999, //
IS_BETWEEN_LEVEL_1_AND_75 = 1000, //
IS_BETWEEN_LEVEL_76_AND_85 = 1001, //
IS_BETWEEN_LEVEL_86_AND_95 = 1002, //
IS_BETWEEN_LEVEL_96_AND_105 = 1003, //
IS_HP_LESS_THAN_80_PCT = 1004, //
IS_LEVEL_ABOVE_34 = 1474, // Your target must be level 35 or higher.
IN_TWO_HANDED_STANCE = 2000, // You must be in your two-handed stance to use this ability.
IN_DUAL_WIELD_HANDED_STANCE = 2001, // You must be in your dual-wielding stance to use this ability.
IN_SHIELD_STANCE = 2002, // You must be in your shield stance to use this ability.
NOT_IN_TWO_HANDED_STANCE = 2010, // You may not use this ability if you are in your two-handed stance.
NOT_IN_DUAL_WIELD_HANDED_STANCE = 2011, // You may not use this ability if you are in your dual-wielding stance.
NOT_IN_SHIELD_STANCE = 2012, // You may not use this ability if you are in your shield stance.
LEVEL_46_MAX = 2761, //
DISABLED_UNTIL_EXPANSION_ROK = 7000, // This ability is disabled until Ruins of Kunark.
DISABLED_UNTIL_EXPANSION_SOV = 7001, // This ability is disabled until Scars of Velious.
DISABLED_UNTIL_EXPANSION_SOL = 7002, // This ability is disabled until Shadows of Luclin.
DISABLED_UNTIL_EXPANSION_POP = 7003, // This ability is disabled until Planes of Power.
DISABLED_UNTIL_EXPANSION_LOY = 7004, // This ability is disabled until Legacy of Ykesha.
DISABLED_UNTIL_EXPANSION_LDON = 7005, // This ability is disabled until Lost Dungeons of Norrath.
DISABLED_UNTIL_EXPANSION_GOD = 7006, // This ability is disabled until Gates of Discord.
DISABLED_UNTIL_EXPANSION_OOW = 7007, // This ability is disabled until Omens of War.
DISABLED_UNTIL_EXPANSION_DON = 7008, // This ability is disabled until Dragons of Norrath.
DISABLED_UNTIL_EXPANSION_DOD = 7009, // This ability is disabled until Depths of Darkhollow.
DISABLED_UNTIL_EXPANSION_POR = 7010, // This ability is disabled until Prophecy of Ro.
DISABLED_UNTIL_EXPANSION_TSS = 7011, // This ability is disabled until Serpent's Spine.
DISABLED_UNTIL_EXPANSION_TBS = 7012, // This ability is disabled until Buried Sea.
DISABLED_UNTIL_EXPANSION_SOF = 7013, // This ability is disabled until Secrets of Faydwer.
DISABLED_UNTIL_EXPANSION_SOD = 7014, // This ability is disabled until Seeds of Destruction.
DISABLED_UNTIL_EXPANSION_UF = 7015, // This ability is disabled until Underfoot.
DISABLED_UNTIL_EXPANSION_HOT = 7016, // This ability is disabled until House of Thule.
DISABLED_UNTIL_EXPANSION_VOA = 7017, // This ability is disabled until Veil of Alaris.
DISABLED_UNTIL_EXPANSION_ROF = 7018, // This ability is disabled until Rain of Fear.
DISABLED_UNTIL_EXPANSION_COF = 7019, // This ability is disabled until Call of the Forsaken.
DISABLED_UNTIL_EXPANSION_TDS = 7020, // This ability is disabled until Darkened Sea.
DISABLED_UNTIL_EXPANSION_TBM = 7021, // This ability is disabled until Broken Mirror.
DISABLED_UNTIL_EXPANSION_EOK = 7022, // This ability is disabled until Empires of Kunark.
DISABLED_UNTIL_EXPANSION_ROS = 7023, // This ability is disabled until Ring of Scale.
DISABLED_UNTIL_EXPANSION_TBL = 7024, // This ability is disabled until The Burning Lands.
DISABLED_UNTIL_EXPANSION_TOV = 7025, // This ability is disabled until Torment of Velious.
DISABLED_UNTIL_EXPANSION_COV = 7026, // This ability is disabled until Claws of Veeshan.
HAS_NO_MANA_BURN_BUFF = 8450, // This spell will not take hold until the effects of the previous Mana Burn have expired.
IS_RACE_FIRST_CUSTOM = 10000, // | custom range to restrict targets or casters by race *not on live* |
IS_RACE_LAST_CUSTOM = 11000, // | custom range to restrict targets or casters by race *not on live* |
IS_CLIENT_AND_MALE_PLATE_USER = 11044, // Your target wouldn't look right as that Jann.
IS_CLEINT_AND_MALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD = 11090, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_MALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE = 11209, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_PLATE_USER = 11210, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD = 11211, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE = 11248, // Your target wouldn't look right as that Jann.
HAS_TRAVELED_TO_STRATOS = 11260, // You must travel to Stratos at least once before wishing to go there.
HAS_TRAVELED_TO_AALISHAI = 11261, // You must travel to Aalishai at least once before wishing to go there.
HAS_TRAVELED_TO_MEARATS = 11268, // You must travel to Mearatas at least once before wishing to go there.
HAS_NO_ILLUSIONS_OF_GRANDEUR_BUFF = 12519, //
IS_HP_ABOVE_50_PCT = 16010, //
IS_HP_UNDER_50_PCT = 16031, //
IS_OFF_HAND_EQUIPED = 27672, // You must be wielding a weapon or shield in your offhand to use this ability.
IS_CLIENT_AND_MALE_PLATE_USER = 11044, // Your target wouldn't look right as that Jann.
IS_CLEINT_AND_MALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD = 11090, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_MALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE = 11209, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_PLATE_USER = 11210, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_DRUID_ENCHANTER_MAGICIAN_NECROANCER_SHAMAN_OR_WIZARD = 11211, // Your target wouldn't look right as that Jann.
IS_CLIENT_AND_FEMALE_BEASTLORD_BERSERKER_MONK_RANGER_OR_ROGUE = 11248, // Your target wouldn't look right as that Jann.
HAS_TRAVELED_TO_STRATOS = 11260, // You must travel to Stratos at least once before wishing to go there.
HAS_TRAVELED_TO_AALISHAI = 11261, // You must travel to Aalishai at least once before wishing to go there.
HAS_TRAVELED_TO_MEARATS = 11268, // You must travel to Mearatas at least once before wishing to go there.
HAS_NO_ILLUSIONS_OF_GRANDEUR_BUFF = 12519, //
IS_HP_ABOVE_50_PCT = 16010, //
IS_HP_UNDER_50_PCT = 16031, //
IS_OFF_HAND_EQUIPED = 27672, // You must be wielding a weapon or shield in your offhand to use this ability.
HAS_NO_PACT_OF_FATE_RECOURSE_BUFF = 29556, // This spell will not work while Pact of Fate Recourse is active. | caster restriction |
HAS_NO_SHROUD_OF_PRAYER_BUFF = 32339, // Your target cannot receive another Quiet Prayer this soon.
IS_MANA_BELOW_20_PCT = 38311, // This ability requires you to be at or below 20% of your maximum mana.
IS_MANA_ABOVE_50_PCT = 38312, // This ability requires you to be at or above 50% of your maximum mana.
COMPLETED_ACHIEVEMENT_LEGENDARY_ANSWERER = 39281, // You have completed Legendary Answerer.
HAS_NO_SHROUD_OF_PRAYER_BUFF = 32339, // Your target cannot receive another Quiet Prayer this soon.
IS_MANA_BELOW_20_PCT = 38311, // This ability requires you to be at or below 20% of your maximum mana.
IS_MANA_ABOVE_50_PCT = 38312, // This ability requires you to be at or above 50% of your maximum mana.
COMPLETED_ACHIEVEMENT_LEGENDARY_ANSWERER = 39281, // You have completed Legendary Answerer.
HAS_NO_ROGUES_FURY_BUFF = 40297, // This spell will not affect anyone that currently has Rogue's Fury active. | caster restriction |
NOT_COMPLETED_ACHIEVEMENT_LEGENDARY_ANSWERER = 42280, // You must complete Legendary Answerer.
IS_SUMMONED_OR_UNDEAD = 49326, //
IS_CLASS_CASTER_PRIEST = 49529, //
NOT_COMPLETED_ACHIEVEMENT_LEGENDARY_ANSWERER = 42280, // You must complete Legendary Answerer.
IS_SUMMONED_OR_UNDEAD = 49326, //
IS_CLASS_CASTER_PRIEST = 49529, //
IS_END_OR_MANA_ABOVE_20_PCT = 49543, // You must have at least 20% of your maximum mana and endurance to use this ability. //pure melee class check end, other check mana
IS_END_OR_MANA_BELOW_30_PCT = 49573, // Your target already has 30% or more of their maximum mana or endurance. //pure melee class check the, other check more
IS_CLASS_BARD2 = 49574, //
IS_NOT_CLASS_BARD = 49575, //
HAS_NO_FURIOUS_RAMPAGE_BUFF = 49612, // This ability cannot be activated while Furious Rampage is active.
IS_END_OR_MANA_BELOW_30_PCT2 = 49809, // You can only perform this solo if you have less than 30% mana or endurance.
HAS_NO_HARMONIOUS_PRECISION_BUFF = 50003, // This spell will not work if you have the Harmonious Precision line active.
IS_CLASS_BARD2 = 49574, //
IS_NOT_CLASS_BARD = 49575, //
HAS_NO_FURIOUS_RAMPAGE_BUFF = 49612, // This ability cannot be activated while Furious Rampage is active.
IS_END_OR_MANA_BELOW_30_PCT2 = 49809, // You can only perform this solo if you have less than 30% mana or endurance.
HAS_NO_HARMONIOUS_PRECISION_BUFF = 50003, // This spell will not work if you have the Harmonious Precision line active.
HAS_NO_HARMONIOUS_EXPANSE_BUFF = 50009, // This spell will not work if you have the Harmonious Expanse line active.
UNKNOWN_99999 = 99999, // | caster restriction | works will spell 27672 Strike of Ire
};
@@ -528,6 +540,15 @@ enum ReflectSpellType
RELFECT_ALL_SINGLE_TARGET_SPELLS = 3,
REFLECT_ALL_SPELLS = 4,
};
//For better organizing in proc effects, not used in spells.
enum ProcType
{
MELEE_PROC = 1,
RANGED_PROC = 2,
DEFENSIVE_PROC = 3,
SKILL_PROC = 4,
SKILL_PROC_SUCCESS = 5,
};
enum SpellTypes : uint32
{
@@ -775,7 +796,7 @@ typedef enum {
//#define SE_CorpseBomb 70 // not used
#define SE_NecPet 71 // implemented
//#define SE_PreserveCorpse 72 // not used
#define SE_BindSight 73 // implemented
#define SE_BindSight 73 // implemented, @Vision, see through the eyes of your target, click off buff to end effect, base: 1, limit: none, max: none
#define SE_FeignDeath 74 // implemented
#define SE_VoiceGraft 75 // implemented
#define SE_Sentinel 76 // *not implemented?(just seems to send a message)
@@ -863,7 +884,7 @@ typedef enum {
#define SE_Reflect 158 // implemented, @SpellMisc, reflect casted detrimental spell back at caster, base: chance pct, limit: resist modifier (positive value reduces resists), max: pct of base dmg mod (50=50pct of base)
#define SE_AllStats 159 // implemented
//#define SE_MakeDrunk 160 // *not implemented - Effect works entirely client side (Should check against tolerance)
#define SE_MitigateSpellDamage 161 // implemented - rune with max value
#define SE_MitigateSpellDamage 161 // implemented, @Runes, mitigate incoming spell damage by percentage until rune fades, base: percent mitigation, limit: max dmg absorbed per hit, max: rune amt, Note: If placed on item or AA, will provide stackable percent mitigation.
#define SE_MitigateMeleeDamage 162 // implemented - rune with max value
#define SE_NegateAttacks 163 // implemented
#define SE_AppraiseLDonChest 164 // implemented
@@ -907,12 +928,12 @@ typedef enum {
#define SE_IllusionOther 202 // implemented - Project Illusion
#define SE_MassGroupBuff 203 // implemented
#define SE_GroupFearImmunity 204 // implemented - (Does not use bonus)
#define SE_Rampage 205 // implemented
#define SE_Rampage 205 // implemented, @Combat Instant, Perform a primary slot combat rounds on all creatures within a 40 foot radius, base: number of attack rounds, limit: max entities hit per round, max: none, Note: AE range is 40 by default. Custom: Set field 'aoe_range' to override default. Adding additional attacks and hit count limit.
#define SE_AETaunt 206 // implemented
#define SE_FleshToBone 207 // implemented
//#define SE_PurgePoison 208 // not used
#define SE_DispelBeneficial 209 // implemented, @Dispel, removes only beneficial effects on a target, base: pct chance (950=95%), limit: none, max: none
#define SE_PetShield 210 // implmented, @ShieldAbility, allows pet to 'shield' owner for 50 pct of damage taken for a duration, base: Time multiplier 1=12 seconds, 2=24 ect, limit: mitigation on pet owner override (not on live), max: mitigation on pet overide (not on live)
#define SE_PetShield 210 // implmented, @ShieldAbility, allows pet to 'shield' owner for 50 pct of damage taken for a duration, base: Time multiplier 1=12 seconds, 2=24 ect, limit: mitigation on pet owner override (not on live), max: mitigation on pet overide (not on live)
#define SE_AEMelee 211 // implemented TO DO: Implement to allow NPC use (client only atm).
#define SE_FrenziedDevastation 212 // implemented - increase spell criticals + all DD spells cast 2x mana.
#define SE_PetMaxHP 213 // implemented[AA] - increases the maximum hit points of your pet
@@ -947,7 +968,7 @@ typedef enum {
#define SE_IncreaseChanceMemwipe 242 // implemented - @Memblur, increases the chance to wipe hate with memory blurr, base: chance pct, limit: none, max: none, Note: Mods final blur chance after other bonuses added.
#define SE_CharmBreakChance 243 // implemented - Total Domination
#define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break.
#define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest
#define SE_TrapCircumvention 245 // implemented, @Traps, decreases the chance that you will set off a trap when opening a chest or other similar container by percentage, base: chance modifer, limit: none, max: none
#define SE_SetBreathLevel 246 // *not implemented as bonus
#define SE_RaiseSkillCap 247 // implemented[AA] - adds skill over the skill cap.
#define SE_SecondaryForte 248 // not implemented as bonus(gives you a 2nd specialize skill that can go past 50 to 100)
@@ -983,17 +1004,17 @@ typedef enum {
#define SE_FinishingBlow 278 // implemented[AA] - chance to do massive damage under 10% HP (base1 = chance, base2 = damage)
#define SE_Flurry 279 // implemented
#define SE_PetFlurry 280 // implemented[AA]
#define SE_FeignedMinion 281 // *not implemented[AA] ability allows you to instruct your pet to feign death via the '/pet feign' command. value = succeed chance
#define SE_FeignedMinion 281 // implemented, ability allows you to instruct your pet to feign death via the '/pet feign' command, base: succeed chance, limit: none, max: none, Note: Only implemented as an AA.
#define SE_ImprovedBindWound 282 // implemented[AA] - increase bind wound amount by percent.
#define SE_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk
//#define SE_LoHSetHeal 284 // not used
#define SE_NimbleEvasion 285 // *not implemented - base1 = 100 for max
#define SE_FcDamageAmt 286 // implemented, @Fc, On Caster, spell damage mod flat amt, base: amt
#define SE_SpellDurationIncByTic 287 // implemented, @Fc, SPA: 287, SE_SpellDurationIncByTic, On Caster, spell buff duration mod, base: tics
#define SE_SkillAttackProc 288 // implemented[AA] - Chance to proc spell on skill attack usage (ex. Dragon Punch)
#define SE_SkillAttackProc 288 // implemented, @Procs, chance to cast a spell when using a skill, base: chance, limit: skill, max: spellid, note: if used in AA the spell id is set in aa_ranks spell field, chance is calculated as 100% = value 1000.
#define SE_CastOnFadeEffect 289 // implemented - Triggers only if fades after natural duration.
#define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap
#define SE_Purify 291 // implemented, @Dispel, remove up specified amount of detiremental spells, base: amt removed, limit: none, max: none, Note: excluding charm, fear, resurrection, and revival sickness
#define SE_Purify 291 // implemented, @Dispel, remove up specified amount of detiremental spells, base: amt removed, limit: none, max: none, Note: excluding charm, fear, resurrection, and revival sickness
#define SE_StrikeThrough2 292 // implemented[AA] - increasing chance of bypassing an opponent's special defenses, such as dodge, block, parry, and riposte.
#define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front. -- live descriptions sounds like this isn't limited to frontal anymore
#define SE_CriticalSpellChance 294 // implemented - increase chance to critical hit and critical damage modifier.
@@ -1001,19 +1022,19 @@ typedef enum {
#define SE_FcSpellVulnerability 296 // implemented, @Fc, On Target, spell damage taken mod pct, base: min pct, limit: max pct
#define SE_FcDamageAmtIncoming 297 // implemetned, @Fc, On Target, damage taken flat amt, base: amt
#define SE_ChangeHeight 298 // implemented
#define SE_WakeTheDead 299 // implemented
#define SE_WakeTheDead 299 // implemented, @Pets, summon one temporary pet from nearby corpses that last a set duration, base: none, limit: none, max: duration (seconds). Note: max range of corpse is 250.
#define SE_Doppelganger 300 // implemented
#define SE_ArcheryDamageModifier 301 // implemented[AA] - increase archery damage by percent
#define SE_FcDamagePctCrit 302 // implemented, @Fc, On Caster, spell damage mod pct, base: min pct, limit: max pct, Note: applied after critical hits has been calculated.
#define SE_FcDamageAmtCrit 303 // implemented, @Fc, On Caster, spell damage mod flat amt, base: amt
#define SE_OffhandRiposteFail 304 // implemented as bonus - enemy cannot riposte offhand attacks
#define SE_MitigateDamageShield 305 // implemented - off hand attacks only (Shielding Resistance)
//#define SE_ArmyOfTheDead 306 // *not implemented NecroAA - This ability calls up to five shades of nearby corpses back to life to serve the necromancer. The soulless abominations will mindlessly fight the target until called back to the afterlife some time later. The first rank summons up to three shades that serve for 60 seconds, and each additional rank adds one more possible shade and increases their duration by 15 seconds
#define SE_ArmyOfTheDead 306 // implemented, @Pets, summon multiple temporary pets from nearby corpses that last a set duration, base: amount of corpses that a pet can summon from, limit: none, max: duration (seconds). Note: max range of corpse is 250.
//#define SE_Appraisal 307 // *not implemented Rogue AA - This ability allows you to estimate the selling price of an item you are holding on your cursor.
#define SE_ZoneSuspendMinion 308 // implemented, @Pet, allow suspended pets to be resummoned upon zoning, base: 1, limit: none, max: none, Calc: Bool
#define SE_GateCastersBindpoint 309 // implemented - Gate to casters bind point
#define SE_ReduceReuseTimer 310 // implemented, @Fc, On Caster, disc reuse time mod, base: milliseconds
#define SE_LimitCombatSkills 311 // implemented, @Ff, Include or exclude combat skills or procs (non-memorizable spells) from being focused, base1: 0=Exclude if proc 1=Allow only if proc
#define SE_ReduceReuseTimer 310 // implemented, @Fc, On Caster, spell and disc reuse time mod by amount, base: milliseconds
#define SE_LimitCombatSkills 311 // implemented, @Ff, Include or exclude combat skills or procs from being focused, base1: 0=Exclude if proc 1=Allow only if proc.
#define SE_Sanctuary 312 // implemented - Places caster at bottom hate list, effect fades if cast cast spell on targets other than self.
#define SE_ForageAdditionalItems 313 // implemented[AA] - chance to forage additional items
#define SE_Invisibility2 314 // implemented - fixed duration invisible
@@ -1041,7 +1062,7 @@ typedef enum {
//#define SE_IllusionaryTarget 336 // not used
#define SE_PercentXPIncrease 337 // implemented
#define SE_SummonAndResAllCorpses 338 // implemented
#define SE_TriggerOnCast 339 // implemented, @Fc, On Caster, cast on spell use, base: chance pct limit: spellid
#define SE_TriggerOnCast 339 // implemented, @Fc, On Caster, cast on spell use, base: chance pct limit: spellid
#define SE_SpellTrigger 340 // implemented - chance to trigger spell [Share rolls with 469] All base2 spells share roll chance, only 1 cast.
#define SE_ItemAttackCapIncrease 341 // implemented[AA] - increases the maximum amount of attack you can gain from items.
#define SE_ImmuneFleeing 342 // implemented - stop mob from fleeing
@@ -1129,8 +1150,8 @@ typedef enum {
#define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace
//#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626)
#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window
#define SE_SkillProc 427 // implemented - chance to proc when using a skill(ie taunt)
#define SE_LimitToSkill 428 // implemented - limits what skills will effect a skill proc
#define SE_SkillProcAttempt 427 // implemented - chance to proc when using a skill(ie taunt)
#define SE_LimitToSkill 428 // implemented, @Procs, limits what combat skills will effect a skill proc, base: skill value, limit: none, max: none
#define SE_SkillProcSuccess 429 // implemented - chance to proc when tje skill in use successfully fires.
//#define SE_PostEffect 430 // *not implemented - Fear of the Dark(27641) - Alters vision
//#define SE_PostEffectData 431 // *not implemented - Fear of the Dark(27641) - Alters vision
@@ -1152,7 +1173,7 @@ typedef enum {
#define SE_BStacker 447 // implemented
#define SE_CStacker 448 // implemented
#define SE_DStacker 449 // implemented
#define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value
#define SE_MitigateDotDamage 450 // implemented, @Runes, mitigate incoming dot damage by percentage until rune fades, base: percent mitigation, limit: max dmg absorbed per hit, max: rune amt, Note: If placed on item or AA, will provide stackable percent mitigation.
#define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage
#define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage
#define SE_TriggerMeleeThreshold 453 // implemented Trigger effect on X amount of melee damage taken in a single hit
@@ -1186,14 +1207,14 @@ typedef enum {
#define SE_Fc_Cast_Spell_On_Land 481 // implemented, @Fc, On Target, cast spell if hit by spell, base: chance pct, limit: spellid
#define SE_Skill_Base_Damage_Mod 482 // implemented, @OffBonus, modify base melee damage by percent, base: pct, limit: skill(-1=ALL), max: none
#define SE_Fc_Spell_Damage_Pct_IncomingPC 483 // implemented, @Fc, On Target, spell damage taken mod pct, base: min pct, limit: max pct
#define SE_Fc_Spell_Damage_Amt_IncomingPC 484 // implemented, @Fc, On Target, damage taken flat amt, base: amt
#define SE_Fc_Spell_Damage_Amt_IncomingPC 484 // implemented, @Fc, On Target, damage taken flat amt, base: amt
#define SE_Ff_CasterClass 485 // implemented, @Ff, Caster of spell on target with a focus effect that is checked by incoming spells must be specified class(es). base1: class(es), Note: Set multiple classes same as would for items
#define SE_Ff_Same_Caster 486 // implemented, @Ff, Caster of spell on target with a focus effect that is checked by incoming spells, base1: 0=Must be different caster 1=Must be same caster
//#define SE_Extend_Tradeskill_Cap 487 //
//#define SE_Defender_Melee_Force_Pct_PC 488 //
#define SE_Worn_Endurance_Regen_Cap 489 // implemented, modify worn regen cap, base: amt, limit: none, max: none
#define SE_Ff_ReuseTimeMin 490 // implemented, @Ff, Minimum recast time of a spell that can be focused, base: recast time
#define SE_Ff_ReuseTimeMax 491 // implemented, @Ff, Max recast time of a spell that can be focused, base: recast time
#define SE_Ff_ReuseTimeMax 491 // implemented, @Ff, Max recast time of a spell that can be focused, base: recast time
#define SE_Ff_Endurance_Min 492 // implemented, @Ff, Minimum endurance cost of a spell that can be focused, base: endurance cost
#define SE_Ff_Endurance_Max 493 // implemented, @Ff, Max endurance cost of a spell that can be focused, base: endurance cost
#define SE_Pet_Add_Atk 494 // implemented - Bonus on pet owner which gives their pet increased attack stat
@@ -1213,7 +1234,7 @@ typedef enum {
#define SE_Fc_Amplify_Amt 508 // implemented, @Fc, On Caster, damage-heal-dot mod flat amt, base: amt
#define SE_Health_Transfer 509 // implemented - exchange health for damage or healing on a target. ie Lifeburn/Act of Valor
#define SE_Fc_ResistIncoming 510 // implemented, @Fc, On Target, resist modifier, base: amt
#define SE_Ff_FocusTimerMin 511 // implemented, @Ff, sets a recast time until focus can be used again, base: 1, limit: time ms, Note: ie. limit to 1 trigger every 1.5 seconds
#define SE_Ff_FocusTimerMin 511 // implemented, @Ff, sets a recast time until focus can be used again, base: 1, limit: time ms, Note: ie. limit to 1 trigger every 1.5 seconds
#define SE_Proc_Timer_Modifier 512 // implemented - limits procs per amount of a time based on timer value, base: 1, limit: time ms, Note:, ie limit to 1 proc every 55 seconds)
//#define SE_Mana_Max_Percent 513 //
//#define SE_Endurance_Max_Percent 514 //
@@ -1340,7 +1361,7 @@ struct SPDat_Spell_Struct
/* 181 */ int pvp_duration; // buffdurationformula for PvP -- PVP_DURATION
/* 182 */ int pvp_duration_cap; // buffduration for PvP -- PVP_DURATION_CAP
/* 183 */ int pcnpc_only_flag; // valid values are 0, 1 = PCs (and mercs), and 2 = NPCs (and not mercs) -- PCNPC_ONLY_FLAG
/* 184 */ bool cast_not_standing; // this is checked in the client's EQ_Spell::IsCastWhileInvisSpell, this also blocks SE_InterruptCasting from affecting this spell -- CAST_NOT_STANDING
/* 184 */ bool cast_not_standing; // this is checked in the client's EQ_Spell::IsCastWhileInvisSpell, this also blocks SE_InterruptCasting from affecting this spell -- CAST_NOT_STANDING (Allows casting if DA, stun, mezed, charm? fear?, damage to invul targets)
/* 185 */ bool can_mgb; // 0=no, -1 or 1 = yes -- CAN_MGB
/* 186 */ int dispel_flag; // -- NO_DISPELL
/* 187 */ //int npc_category; // -- NPC_MEM_CATEGORY
@@ -1519,8 +1540,9 @@ int GetViralMinSpreadTime(int32 spell_id);
int GetViralMaxSpreadTime(int32 spell_id);
int GetViralSpreadRange(int32 spell_id);
bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect);
bool IsPulsingBardSong(int32 spell_id);
uint32 GetProcLimitTimer(int32 spell_id, int proc_type);
bool IgnoreCastingRestriction(int32 spell_id);
int CalcPetHp(int levelb, int classb, int STA = 75);
int GetSpellEffectDescNum(uint16 spell_id);
DmgShieldType GetDamageShieldType(uint16 spell_id, int32 DSType = 0);
@@ -1531,5 +1553,6 @@ bool IsShortDurationBuff(uint16 spell_id);
bool IsSpellUsableThisZoneType(uint16 spell_id, uint8 zone_type);
const char *GetSpellName(uint16 spell_id);
int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot = 0);
bool CastRestrictedSpell(int spellid);
#endif
+241
View File
@@ -15,6 +15,7 @@
*/
#include "string_util.h"
#include <fmt/format.h>
#include <algorithm>
#include <cctype>
@@ -1019,3 +1020,243 @@ std::vector<std::string> GetBadWords()
"zoophilia"
};
}
std::string ConvertSecondsToTime(int duration, bool is_milliseconds)
{
if (duration <= 0) {
return "Unknown";
}
if (is_milliseconds && duration < 1000) {
return fmt::format(
"{} Millisecond{}",
duration,
duration != 1 ? "s" : ""
);
}
int timer_length = (
is_milliseconds ?
static_cast<int>(std::ceil(static_cast<float>(duration) / 1000.0f)) :
duration
);
int days = int(timer_length / 86400);
timer_length %= 86400;
int hours = int(timer_length / 3600);
timer_length %= 3600;
int minutes = int(timer_length / 60);
timer_length %= 60;
int seconds = timer_length;
std::string time_string = "Unknown";
std::string day_string = (days == 1 ? "Day" : "Days");
std::string hour_string = (hours == 1 ? "Hour" : "Hours");
std::string minute_string = (minutes == 1 ? "Minute" : "Minutes");
std::string second_string = (seconds == 1 ? "Second" : "Seconds");
if (days && hours && minutes && seconds) { // DHMS
time_string = fmt::format(
"{} {}, {} {}, {} {}, and {} {}",
days,
day_string,
hours,
hour_string,
minutes,
minute_string,
seconds,
second_string
);
} else if (days && hours && minutes && !seconds) { // DHM
time_string = fmt::format(
"{} {}, {} {}, and {} {}",
days,
day_string,
hours,
hour_string,
minutes,
minute_string
);
} else if (days && hours && !minutes && seconds) { // DHS
time_string = fmt::format(
"{} {}, {} {}, and {} {}",
days,
day_string,
hours,
hour_string,
seconds,
second_string
);
} else if (days && hours && !minutes && !seconds) { // DH
time_string = fmt::format(
"{} {} and {} {}",
days,
day_string,
hours,
hour_string
);
} else if (days && !hours && minutes && seconds) { // DMS
time_string = fmt::format(
"{} {}, {} {}, and {} {}",
days,
day_string,
minutes,
minute_string,
seconds,
second_string
);
} else if (days && !hours && minutes && !seconds) { // DM
time_string = fmt::format(
"{} {} and {} {}",
days,
day_string,
minutes,
minute_string
);
} else if (days && !hours && !minutes && seconds) { // DS
time_string = fmt::format(
"{} {} and {} {}",
days,
day_string,
seconds,
second_string
);
} else if (days && !hours && !minutes && !seconds) { // D
time_string = fmt::format(
"{} {}",
days,
day_string
);
} else if (!days && hours && minutes && seconds) { // HMS
time_string = fmt::format(
"{} {}, {} {}, and {} {}",
hours,
hour_string,
minutes,
minute_string,
seconds,
second_string
);
} else if (!days && hours && minutes && !seconds) { // HM
time_string = fmt::format(
"{} {} and {} {}",
hours,
hour_string,
minutes,
minute_string
);
} else if (!days && hours && !minutes && seconds) { // HS
time_string = fmt::format(
"{} {} and {} {}",
hours,
hour_string,
seconds,
second_string
);
} else if (!days && hours && !minutes && !seconds) { // H
time_string = fmt::format(
"{} {}",
hours,
hour_string
);
} else if (!days && !hours && minutes && seconds) { // MS
time_string = fmt::format(
"{} {} and {} {}",
minutes,
minute_string,
seconds,
second_string
);
} else if (!days && !hours && minutes && !seconds) { // M
time_string = fmt::format(
"{} {}",
minutes,
minute_string
);
} else if (!days && !hours && !minutes && seconds) { // S
time_string = fmt::format(
"{} {}",
seconds,
second_string
);
}
return time_string;
}
std::string ConvertMoneyToString(uint32 platinum, uint32 gold, uint32 silver, uint32 copper)
{
std::string money_string = "Unknown";
if (copper && silver && gold && platinum) { // CSGP
money_string = fmt::format(
"{} Platinum, {} Gold, {} Silver, and {} Copper",
platinum,
gold,
silver,
copper
);
} else if (copper && silver && gold && !platinum) { // CSG
money_string = fmt::format(
"{} Gold, {} Silver, and {} Copper",
gold,
silver,
copper
);
} else if (copper && silver && !gold && !platinum) { // CS
money_string = fmt::format(
"{} Silver and {} Copper",
silver,
copper
);
} else if (!copper && silver && gold && platinum) { // SGP
money_string = fmt::format(
"{} Platinum, {} Gold, and {} Silver",
platinum,
gold,
silver
);
} else if (!copper && silver && gold && !platinum) { // SG
money_string = fmt::format(
"{} Gold and {} Silver",
gold,
silver
);
} else if (copper && !silver && gold && platinum) { // CGP
money_string = fmt::format(
"{} Platinum, {} Gold, and {} Copper",
platinum,
gold,
copper
);
} else if (copper && !silver && gold && !platinum) { // CG
money_string = fmt::format(
"{} Gold and {} Copper",
gold,
copper
);
} else if (!copper && !silver && gold && platinum) { // GP
money_string = fmt::format(
"{} Platinum and {} Gold",
platinum,
gold
);
} else if (!copper && !silver && !gold && platinum) { // P
money_string = fmt::format(
"{} Platinum",
platinum
);
} else if (!copper && !silver && gold && !platinum) { // G
money_string = fmt::format(
"{} Gold",
gold
);
} else if (!copper && silver && !gold && !platinum) { // S
money_string = fmt::format(
"{} Silver",
silver
);
} else if (copper && !silver && !gold && !platinum) { // C
money_string = fmt::format(
"{} Copper",
copper
);
}
return money_string;
}
+5
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.
+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 9174
#define CURRENT_BINARY_DATABASE_VERSION 9175
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9028
+3 -3
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(30) 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(30) 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(30) 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,
+3
View File
@@ -167,6 +167,9 @@ int main(int argc, char **argv)
content_service.SetCurrentExpansion(RuleI(Expansion, CurrentExpansion));
content_service.SetDatabase(&database)
->SetExpansionContext()
->ReloadContentFlags();
LogInfo(
"Current expansion is [{}] ({})",
+1 -1
View File
@@ -20,7 +20,7 @@ SET(tests_headers
ADD_EXECUTABLE(tests ${tests_sources} ${tests_headers})
TARGET_LINK_LIBRARIES(tests common cppunit)
TARGET_LINK_LIBRARIES(tests common cppunit fmt)
INSTALL(TARGETS tests RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
-8
View File
@@ -1,8 +0,0 @@
{
"server": {
"world": {
"shortname": "setme",
"longname": "I Forgot To Edit My Config"
}
}
}
-54
View File
@@ -1,54 +0,0 @@
{
"server": {
"zones": {
"defaultstatus": "20",
"ports": {
"low": "7000",
"high": "7100"
}
},
"database": {
"password": "eq",
"db": "eq",
"host": "127.0.0.1",
"port": "3306",
"username": "eq"
},
"world": {
"shortname": "setme",
"longname": "I Forgot To Edit My Config",
"loginserver": {
"password": "",
"host": "login.eqemulator.net",
"port": "5998",
"account": ""
},
"tcp": {
"port": "9000",
"telnet": "disable",
"ip": "127.0.0.1"
},
"key": "some long random string",
"http": {
"mimefile": "mime.types",
"port": "9080",
"enabled": "false"
}
},
"mailserver": {
"host": "channels.eqemulator.net",
"port": "7778"
},
"chatserver": {
"host": "channels.eqemulator.net",
"port": "7778"
},
"qsdatabase": {
"host": "127.0.0.1",
"port": "3306",
"username": "eq",
"password": "eq",
"db": "eq"
}
}
}
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0"?>
<server>
<world>
<shortname>setme</shortname>
<longname>I Forgot To Edit My Config</longname>
</world>
</server>
-95
View File
@@ -1,95 +0,0 @@
<?xml version="1.0"?>
<server>
<world>
<shortname>setme</shortname>
<longname>I Forgot To Edit My Config</longname>
<!-- Only specify these two if you really think you need to. (read: You don't) -->
<!-- <address>some.server.com</address> -->
<!-- <localaddress>192.168.0.5</localaddress> -->
<!-- Loginserver information. Defaults shown -->
<loginserver>
<host>login.eqemulator.net</host>
<port>5998</port>
<account></account>
<password></password>
</loginserver>
<!-- Server status. Default is unlocked -->
<!--<locked/>-->
<!-- <unlocked/> -->
<!-- Sets the ip/port for the tcp connections. Both zones and console (if enabled). Defaults are shown -->
<tcp ip="127.0.0.1" port="9000" telnet="disable"/>
<!-- Sets the shared key used by zone/launcher to connect to world -->
<key>some long random string</key>
<!-- Enable and set the port for the HTTP service. Defaults are shown -->
<http port="9080" enabled="false" mimefile="mime.types" />
</world>
<!-- Chatserver (channels) information. Defaults shown -->
<chatserver>
<host>channels.eqemulator.net</host>
<port>7778</port>
</chatserver>
<!-- Mailserver (in-game mail) information. Defaults shown -->
<mailserver>
<host>channels.eqemulator.net</host>
<port>7778</port>
</mailserver>
<zones>
<defaultstatus>20</defaultstatus>
<!-- Sets port range for world to use to auto configure zones -->
<ports low="7000" high="7100"/>
</zones>
<!-- Database configuration, replaces db.ini. Defaults shown -->
<database>
<host>127.0.0.1</host>
<port>3306</port>
<username>eq</username>
<password>eq</password>
<db>eq</db>
</database>
<qsdatabase>
<host>127.0.0.1</host>
<port>3306</port>
<username>eq</username>
<password>eq</password>
<db>eq</db>
</qsdatabase>
<!-- Launcher Configuration -->
<launcher>
<!-- <logprefix>zone-</logprefix> -->
<!-- <logsuffix>.log</logsuffix> -->
<!-- <exe>zone.exe or ./zone</exe> -->
<!-- <timers restart="10000" reterminate="10000"> -->
</launcher>
<!-- File locations. Defaults shown -->
<files>
<!-- <spells>spells_us.txt</spells> -->
<!-- <opcodes>opcodes.conf</opcodes> -->
<!-- <logsettings>log.ini</logsettings> -->
<!-- <eqtime>eqtime.cfg</eqtime> -->
<!-- <plugin.pl>plugin.pl</plugin.pl> -->
</files>
<!-- Directory locations. Defaults shown -->
<directories>
<!-- <maps>Maps/</maps> -->
<!-- <quests>quests/</quests> -->
<!-- <plugins>plugins/</plugins> -->
<!-- <lua_modules>lua_modules/</lua_modules> -->
<!-- <patches>./</patches> -->
<!-- <shared_memory>shared/</shared_memory> -->
<!-- <logs>logs/</logs> -->
</directories>
</server>
+183
View File
@@ -0,0 +1,183 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"sort"
"strings"
)
func main() {
// zone/command.cpp
commands, err := os.ReadFile("./zone/command.cpp")
if err != nil {
log.Fatal(err)
}
commandsString := string(commands)
s := strings.Split(commandsString, "void command_")
commandFiles := []string{}
if len(s) > 1 {
startListing := false
for i, chunk := range s {
if strings.Contains(chunk, "logcommand(Client *c") {
startListing = true
}
// get function name
functionName := ""
nameSplit := strings.Split(chunk, "(Client")
if len(nameSplit) > 0 {
functionName = strings.TrimSpace(nameSplit[0])
}
if startListing &&
len(s[i-1]) > 0 &&
!strings.Contains(s[i-1], "#ifdef") &&
!strings.Contains(chunk, "#ifdef") &&
!strings.Contains(chunk, "#ifdef BOTS") &&
!strings.Contains(chunk, "#ifdef EQPROFILE") &&
!strings.Contains(functionName, "bot") &&
!strings.Contains(functionName, "help") &&
!strings.Contains(functionName, "findaliases") {
fmt.Println(functionName)
// build command file name
commandFile := fmt.Sprintf("zone/gm_commands/%v.cpp", functionName)
// append command file nam eto list
commandFiles = append(commandFiles, commandFile)
includes := ""
if strings.Contains(chunk, "Client") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../client.h\"")
}
if strings.Contains(chunk, "parse->") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../quest_parser_collection.h\"")
}
if strings.Contains(chunk, "worldserver.") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../worldserver.h\"")
includes = fmt.Sprintf("%v%v\n", includes, "extern WorldServer worldserver;")
}
if strings.Contains(chunk, "RegionType") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../water_map.h\"")
}
if strings.Contains(chunk, "Corpse") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../corpse.h\"")
}
if strings.Contains(chunk, "Object") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../object.h\"")
}
if strings.Contains(chunk, "DoorManipulation") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"door_manipulation.h\"")
}
if strings.Contains(chunk, "Group") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../groups.h\"")
}
if strings.Contains(chunk, "httplib") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/http/httplib.h\"")
}
if strings.Contains(chunk, "guild_mgr") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../guild_mgr.h\"")
}
if strings.Contains(chunk, "expedition") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../expedition.h\"")
}
if strings.Contains(chunk, "DataBucket::") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../data_bucket.h\"")
}
if strings.Contains(chunk, "file_exists") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/file_util.h\"")
}
if strings.Contains(chunk, "std::thread") {
includes = fmt.Sprintf("%v%v\n", includes, "#include <thread>")
}
if strings.Contains(chunk, "Door") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../doors.h\"")
}
if strings.Contains(chunk, "NOW_INVISIBLE") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../string_ids.h\"")
}
if strings.Contains(chunk, "Expansion::") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/content/world_content_service.h\"")
}
if strings.Contains(chunk, "MobMovementManager::") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../mob_movement_manager.h\"")
}
if strings.Contains(chunk, "MobStuckBehavior::") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../mob_movement_manager.h\"")
}
if strings.Contains(chunk, "ReloadAllPatches") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/patches/patches.h\"")
}
if strings.Contains(chunk, "ProfanityManager") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/profanity_manager.h\"")
}
if strings.Contains(chunk, "npc_scale_manager") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../npc_scale_manager.h\"")
}
if strings.Contains(chunk, "g_Math") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../fastmath.h\"")
includes = fmt.Sprintf("%v%v\n", includes, "extern FastMath g_Math;")
}
if strings.Contains(chunk, "raid") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../raids.h\"")
}
if strings.Contains(chunk, "Raid") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../raids.h\"")
}
if strings.Contains(chunk, "GetOS") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/serverinfo.h\"")
}
if strings.Contains(chunk, "LANG_") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/languages.h\"")
}
if strings.Contains(chunk, "ServerOP_Shared") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../common/shared_tasks.h\"")
}
if strings.Contains(chunk, "title_manager") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../titles.h\"")
}
if strings.Contains(chunk, "CatchSignal") {
includes = fmt.Sprintf("%v%v\n", includes, "#include \"../../world/main.h\"")
}
// build the contents of the command file
commandString := fmt.Sprintf("%v\nvoid command_%v", includes, chunk)
//write file contents
err := ioutil.WriteFile(commandFile, []byte(commandString), 0777)
if err != nil {
fmt.Println(err)
}
commandOnly := fmt.Sprintf("void command_%v", chunk)
commandsString = strings.ReplaceAll(commandsString, commandOnly, "")
}
}
// rewrite commands.cpp with functions removed
err := ioutil.WriteFile("zone/command.cpp", []byte(commandsString), 0777)
if err != nil {
fmt.Println(err)
}
fmt.Println("# CmakeLists")
// sort a-z
sort.Slice(commandFiles, func(i, j int) bool {
return commandFiles[i] < commandFiles[j]
})
for _, file := range commandFiles {
file = strings.ReplaceAll(file, "zone/", "")
fmt.Println(file)
}
}
//fmt.Print(string(commands))
}
+4 -5
View File
@@ -962,15 +962,14 @@ function CommonOutgoingHitSuccess(e)
)
);
e.hit.damage_done = e.hit.damage_done + (e.hit.damage_done * e.other:GetSkillDmgTaken(e.hit.skill) / 100) + (e.self:GetSkillDmgAmt(e.hit.skill) + e.other:GetFcDamageAmtIncoming(e.self, 0, true, e.hit.skill));
e.hit.damage_done = e.hit.damage_done + (e.hit.damage_done * e.other:GetSkillDmgTaken(e.hit.skill) / 100) + e.self:GetSkillDmgAmt(e.hit.skill);
eq.log_combat(
string.format("[%s] [Mob::CommonOutgoingHitSuccess] Dmg [%i] SkillDmgTaken [%i] SkillDmgtAmt [%i] FcDmgAmtIncoming [%i] Post DmgCalcs",
string.format("[%s] [Mob::CommonOutgoingHitSuccess] Dmg [%i] SkillDmgTaken [%i] SkillDmgtAmt [%i] Post DmgCalcs",
e.self:GetCleanName(),
e.hit.damage_done,
e.other:GetSkillDmgTaken(e.hit.skill),
e.self:GetSkillDmgAmt(e.hit.skill),
e.other:GetFcDamageAmtIncoming(e.self, 0, true, e.hit.skill)
e.self:GetSkillDmgAmt(e.hit.skill)
)
);
@@ -997,4 +996,4 @@ function ApplyMeleeDamageBonus(e)
e.hit.damage_done = e.hit.damage_done + (e.hit.damage_done * dmgbonusmod / 100);
return e;
end
end
+2 -2
View File
@@ -307,8 +307,8 @@ OP_RecipeAutoCombine=0x0353
OP_TradeSkillCombine=0x0b40
OP_RequestDuel=0x0000
OP_DuelResponse=0x0000
OP_DuelResponse2=0x0000 #when accepted
OP_DuelDecline=0x0000
OP_DuelAccept=0x0000 #when accepted
OP_RezzComplete=0x0000 #packet wrong on this
OP_RezzRequest=0x0000 #packet wrong on this
+2 -2
View File
@@ -288,8 +288,8 @@ OP_YellForHelp=0x0017
OP_LoadSpellSet=0x38b4
OP_Bandolier=0x2b6f
OP_PotionBelt=0x2d1b # Was 0x4d3b
OP_DuelResponse=0x0dee
OP_DuelResponse2=0x5e04
OP_DuelDecline=0x0dee
OP_DuelAccept=0x5e04
OP_SaveOnZoneReq=0x36b1
OP_ReadBook=0x383c
OP_Dye=0x62d8
+2 -2
View File
@@ -287,8 +287,8 @@ OP_YellForHelp=0x4e56
OP_LoadSpellSet=0x261d
OP_Bandolier=0x7677
OP_PotionBelt=0x1a3e
OP_DuelResponse=0x6a46
OP_DuelResponse2=0x68d3
OP_DuelDecline=0x6a46
OP_DuelAccept=0x68d3
OP_SaveOnZoneReq=0x600d
OP_ReadBook=0x72df
OP_Dye=0x23b9
+2 -2
View File
@@ -281,7 +281,7 @@ OP_YellForHelp=0x6f79 # C
OP_LoadSpellSet=0x7113 # C
OP_Bandolier=0x441c # C
OP_PotionBelt=0x5db5 # C
OP_DuelResponse=0x1ebb # C
OP_DuelDecline=0x1ebb # C
OP_SaveOnZoneReq=0x6eff # C
OP_ReadBook=0x2444 # C
OP_Dye=0x3672 # C
@@ -299,7 +299,7 @@ OP_DoGroupLeadershipAbility=0x540b # C
OP_GroupLeadershipAAUpdate=0x0c33
OP_DelegateAbility=0x0322 # C
OP_SetGroupTarget=0x521c # C
OP_DuelResponse2=0x52b5 # C
OP_DuelAccept=0x52b5 # C
OP_Charm=0x7108 # C
OP_Stun=0x2a6d # C
OP_SendFindableNPCs=0x5360
+2 -2
View File
@@ -275,7 +275,7 @@ OP_YellForHelp=0x4F4A #Trevius 03/19/09
OP_LoadSpellSet=0x05B5 #Trevius 03/19/09
OP_Bandolier=0x3FD4 #Trevius 03/19/09
OP_PotionBelt=0x16F3 #Trevius 03/19/09
OP_DuelResponse=0x5E59 #Derision 2009
OP_DuelDecline=0x5E59 #Derision 2009
OP_SaveOnZoneReq=0x1103 #Trevius 03/20/09
OP_ReadBook=0x424a #Xinu 03/19/09
OP_Dye=0x3611 #Xinu 03/19/09
@@ -292,7 +292,7 @@ OP_ClearRaidNPCMarks=0x56a9 #
OP_DoGroupLeadershipAbility=0x5a64 #Derision 2009
OP_DelegateAbility=0x57e3 #Derision 2009
OP_SetGroupTarget=0x1651 #Derision 2009
OP_DuelResponse2=0x2A85 #Derision 2009
OP_DuelAccept=0x2A85 #Derision 2009
OP_Charm=0x2F32 #Derision 2009
OP_Stun=0x55BF #Derision 2009
OP_FindPersonRequest=0x07F0 #Derision 2009
+2 -2
View File
@@ -356,8 +356,8 @@ OP_RecipeAutoCombine=0x0353
OP_TradeSkillCombine=0x0b40
OP_RequestDuel=0x28e1
OP_DuelResponse=0x3bad
OP_DuelResponse2=0x1b09 #when accepted
OP_DuelDecline=0x3bad
OP_DuelAccept=0x1b09 #when accepted
OP_RezzComplete=0x4b05
OP_RezzRequest=0x1035
+2 -2
View File
@@ -290,8 +290,8 @@ OP_YellForHelp=0x55a8 # C
OP_LoadSpellSet=0x6617 # C
OP_Bandolier=0x510c # C
OP_PotionBelt=0x0651 # C
OP_DuelResponse=0x41a6 # C
OP_DuelResponse2=0x6d60 # C
OP_DuelDecline=0x41a6 # C
OP_DuelAccept=0x6d60 # C
OP_SaveOnZoneReq=0x2913 # C
OP_ReadBook=0x465e # C
OP_Dye=0x2137 # C
+1 -1
View File
@@ -1911,7 +1911,7 @@ sub fetch_peq_db_full
sub map_files_fetch_bulk
{
print "[Install] Fetching Latest Maps... (This could take a few minutes...)\n";
get_remote_file("http://github.com/Akkadius/EQEmuMaps/archive/master.zip", "maps/maps.zip", 1);
get_remote_file("http://analytics.akkadius.com/maps.zip", "maps/maps.zip", 1);
unzip('maps/maps.zip', 'maps/');
my @files;
my $start_dir = "maps/EQEmuMaps-master/";
+1
View File
@@ -428,6 +428,7 @@
9172|2021_05_21_shared_tasks.sql|SHOW TABLES LIKE 'shared_tasks'|empty|
9173|2021_09_14_zone_lava_damage.sql|SHOW COLUMNS FROM `zone` LIKE 'lava_damage'|empty|
9174|2021_10_09_not_null_door_columns.sql|SELECT * FROM db_version WHERE version >= 9174|empty|
9175|2022_01_02_expansion_default_value_all.sql|SHOW COLUMNS FROM `forage` LIKE 'min_expansion'|contains|unsigned
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not
@@ -1,3 +1,3 @@
ALTER TABLE login_accounts MODIFY COLUMN last_ip_address VARCHAR(30) NOT NULL;
ALTER TABLE login_server_admins MODIFY COLUMN registration_ip_address VARCHAR(30) NOT NULL;
ALTER TABLE login_world_servers MODIFY COLUMN last_ip_address VARCHAR(30) DEFAULT NULL;
ALTER TABLE login_accounts MODIFY COLUMN last_ip_address VARCHAR(80) NOT NULL;
ALTER TABLE login_server_admins MODIFY COLUMN registration_ip_address VARCHAR(80) NOT NULL;
ALTER TABLE login_world_servers MODIFY COLUMN last_ip_address VARCHAR(80) DEFAULT NULL;
@@ -0,0 +1 @@
UPDATE doors SET lockpick=1 WHERE doorid=46 AND zone="potranquility";
@@ -0,0 +1,117 @@
-- forage
ALTER TABLE `forage` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `forage` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE forage set min_expansion = -1 where min_expansion = 0;
UPDATE forage set max_expansion = -1 where max_expansion = 0;
-- tradeskill_recipe
ALTER TABLE `tradeskill_recipe` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `tradeskill_recipe` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE tradeskill_recipe set min_expansion = -1 where min_expansion = 0;
UPDATE tradeskill_recipe set max_expansion = -1 where max_expansion = 0;
-- fishing
ALTER TABLE `fishing` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `fishing` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE fishing set min_expansion = -1 where min_expansion = 0;
UPDATE fishing set max_expansion = -1 where max_expansion = 0;
-- zone
ALTER TABLE `zone` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `zone` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE zone set min_expansion = -1 where min_expansion = 0;
UPDATE zone set max_expansion = -1 where max_expansion = 0;
-- traps
ALTER TABLE `traps` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `traps` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE traps set min_expansion = -1 where min_expansion = 0;
UPDATE traps set max_expansion = -1 where max_expansion = 0;
-- loottable
ALTER TABLE `loottable` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `loottable` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE loottable set min_expansion = -1 where min_expansion = 0;
UPDATE loottable set max_expansion = -1 where max_expansion = 0;
-- ground_spawns
ALTER TABLE `ground_spawns` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `ground_spawns` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE ground_spawns set min_expansion = -1 where min_expansion = 0;
UPDATE ground_spawns set max_expansion = -1 where max_expansion = 0;
-- starting_items
ALTER TABLE `starting_items` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `starting_items` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE starting_items set min_expansion = -1 where min_expansion = 0;
UPDATE starting_items set max_expansion = -1 where max_expansion = 0;
-- spawn2
ALTER TABLE `spawn2` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `spawn2` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE spawn2 set min_expansion = -1 where min_expansion = 0;
UPDATE spawn2 set max_expansion = -1 where max_expansion = 0;
-- zone_points
ALTER TABLE `zone_points` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `zone_points` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE zone_points set min_expansion = -1 where min_expansion = 0;
UPDATE zone_points set max_expansion = -1 where max_expansion = 0;
-- lootdrop
ALTER TABLE `lootdrop` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `lootdrop` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE lootdrop set min_expansion = -1 where min_expansion = 0;
UPDATE lootdrop set max_expansion = -1 where max_expansion = 0;
-- global_loot
ALTER TABLE `global_loot` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `global_loot` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE global_loot set min_expansion = -1 where min_expansion = 0;
UPDATE global_loot set max_expansion = -1 where max_expansion = 0;
-- doors
ALTER TABLE `doors` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `doors` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE doors set min_expansion = -1 where min_expansion = 0;
UPDATE doors set max_expansion = -1 where max_expansion = 0;
-- object
ALTER TABLE `object` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `object` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE object set min_expansion = -1 where min_expansion = 0;
UPDATE object set max_expansion = -1 where max_expansion = 0;
-- start_zones
ALTER TABLE `start_zones` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `start_zones` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE start_zones set min_expansion = -1 where min_expansion = 0;
UPDATE start_zones set max_expansion = -1 where max_expansion = 0;
-- merchantlist
ALTER TABLE `merchantlist` CHANGE `max_expansion` `max_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
ALTER TABLE `merchantlist` CHANGE `min_expansion` `min_expansion` tinyint(4) NOT NULL DEFAULT -1 COMMENT '';
UPDATE merchantlist set min_expansion = -1 where min_expansion = 0;
UPDATE merchantlist set max_expansion = -1 where max_expansion = 0;
-- spawnentry
ALTER TABLE `spawnentry` ADD `min_expansion` tinyint(4) NOT NULL DEFAULT -1;
ALTER TABLE `spawnentry` ADD `max_expansion` tinyint(4) NOT NULL DEFAULT -1;
ALTER TABLE `spawnentry` ADD `content_flags` varchar(100) NULL;
ALTER TABLE `spawnentry` ADD `content_flags_disabled` varchar(100) NULL;
+2 -2
View File
@@ -274,7 +274,7 @@ void ClientListEntry::ClearVars(bool iAll)
paccountid = 0;
memset(paccountname, 0, sizeof(paccountname));
padmin = 0;
padmin = AccountStatus::Player;
}
pzoneserver = 0;
pzone = 0;
@@ -365,7 +365,7 @@ bool ClientListEntry::CheckAuth(uint32 loginserver_account_id, const char *key_p
}
std::string lsworldadmin;
if (database.GetVariable("honorlsworldadmin", lsworldadmin)) {
if (atoi(lsworldadmin.c_str()) == 1 && pworldadmin != 0 && (padmin < pworldadmin || padmin == 0)) {
if (atoi(lsworldadmin.c_str()) == 1 && pworldadmin != 0 && (padmin < pworldadmin || padmin == AccountStatus::Player)) {
padmin = pworldadmin;
}
}
+1 -1
View File
@@ -60,7 +60,7 @@ public:
* @param scl
* @param iOnline
*/
ClientListEntry(uint32 id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin = 0);
ClientListEntry(uint32 id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin = AccountStatus::Player);
ClientListEntry(uint32 id, ZoneServer* iZS, ServerClientList_Struct* scl, CLE_Status iOnline);
~ClientListEntry();
bool CheckStale();
+103 -79
View File
@@ -296,7 +296,13 @@ void ClientList::SendCLEList(const int16& admin, const char* to, WorldTCPConnect
fmt:format_to(out, "{} CharID: {} CharName: {} Zone: {} ({})", newline, cle->CharID(), cle->name(), ZoneName(cle->zone()), cle->zone());
if (out.size() >= 3072) {
auto output = fmt::to_string(out);
connection->SendEmoteMessageRaw(to, 0, 0, 10, output.c_str());
connection->SendEmoteMessageRaw(
to,
0,
AccountStatus::Player,
Chat::NPCQuestSay,
output.c_str()
);
addnewline = false;
out.clear();
} else {
@@ -309,7 +315,13 @@ void ClientList::SendCLEList(const int16& admin, const char* to, WorldTCPConnect
}
fmt::format_to(out, "{}{} CLEs in memory. {} CLEs listed. numplayers = {}.", newline, x, y, numplayers);
auto output = fmt::to_string(out);
connection->SendEmoteMessageRaw(to, 0, 0, 10, output.c_str());
connection->SendEmoteMessageRaw(
to,
0,
AccountStatus::Player,
Chat::NPCQuestSay,
output.c_str()
);
}
@@ -558,7 +570,7 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
(countcle->Online() >= CLE_Status::Zoning) &&
(!countcle->GetGM() || countcle->Anon() != 1 || admin >= countcle->Admin()) &&
(whom == 0 || (
((countcle->Admin() >= 80 && countcle->GetGM()) || whom->gmlookup == 0xFFFF) &&
((countcle->Admin() >= AccountStatus::QuestTroupe && countcle->GetGM()) || whom->gmlookup == 0xFFFF) &&
(whom->lvllow == 0xFFFF || (countcle->level() >= whom->lvllow && countcle->level() <= whom->lvlhigh && (countcle->Anon()==0 || admin > countcle->Admin()))) &&
(whom->wclass == 0xFFFF || (countcle->class_() == whom->wclass && (countcle->Anon()==0 || admin > countcle->Admin()))) &&
(whom->wrace == 0xFFFF || (countcle->race() == whom->wrace && (countcle->Anon()==0 || admin > countcle->Admin()))) &&
@@ -566,18 +578,18 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
(tmpZone != 0 && strncasecmp(tmpZone, whom->whom, whomlen) == 0) ||
strncasecmp(countcle->name(),whom->whom, whomlen) == 0 ||
(strncasecmp(guild_mgr.GetGuildName(countcle->GuildID()), whom->whom, whomlen) == 0) ||
(admin >= 100 && strncasecmp(countcle->AccountName(), whom->whom, whomlen) == 0)
(admin >= AccountStatus::GMAdmin && strncasecmp(countcle->AccountName(), whom->whom, whomlen) == 0)
))
))
) {
if((countcle->Anon()>0 && admin>=countcle->Admin() && admin>0) || countcle->Anon()==0 ){
if((countcle->Anon()>0 && admin >= countcle->Admin() && admin > AccountStatus::Player) || countcle->Anon()==0 ){
totalusers++;
if(totalusers<=20 || admin>=100)
if(totalusers<=20 || admin >= AccountStatus::GMAdmin)
totallength=totallength+strlen(countcle->name())+strlen(countcle->AccountName())+strlen(guild_mgr.GetGuildName(countcle->GuildID()))+5;
}
else if((countcle->Anon()>0 && admin<=countcle->Admin()) || (countcle->Anon()==0 && !countcle->GetGM())) {
totalusers++;
if(totalusers<=20 || admin>=100)
if(totalusers<=20 || admin >= AccountStatus::GMAdmin)
totallength=totallength+strlen(countcle->name())+strlen(guild_mgr.GetGuildName(countcle->GuildID()))+5;
}
}
@@ -589,7 +601,7 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
uint8 unknown35=0x0A;
uint32 unknown36=0;
uint32 playersinzonestring=5028;
if(totalusers>20 && admin<100){
if(totalusers>20 && admin<AccountStatus::GMAdmin){
totalusers=20;
playersinzonestring=5033;
}
@@ -638,7 +650,7 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
(cle->Online() >= CLE_Status::Zoning) &&
(!cle->GetGM() || cle->Anon() != 1 || admin >= cle->Admin()) &&
(whom == 0 || (
((cle->Admin() >= 80 && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
((cle->Admin() >= AccountStatus::QuestTroupe && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
(whom->lvllow == 0xFFFF || (cle->level() >= whom->lvllow && cle->level() <= whom->lvlhigh && (cle->Anon()==0 || admin>cle->Admin()))) &&
(whom->wclass == 0xFFFF || (cle->class_() == whom->wclass && (cle->Anon()==0 || admin>cle->Admin()))) &&
(whom->wrace == 0xFFFF || (cle->race() == whom->wrace && (cle->Anon()==0 || admin>cle->Admin()))) &&
@@ -646,60 +658,60 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
(tmpZone != 0 && strncasecmp(tmpZone, whom->whom, whomlen) == 0) ||
strncasecmp(cle->name(),whom->whom, whomlen) == 0 ||
(strncasecmp(guild_mgr.GetGuildName(cle->GuildID()), whom->whom, whomlen) == 0) ||
(admin >= 100 && strncasecmp(cle->AccountName(), whom->whom, whomlen) == 0)
(admin >= AccountStatus::GMAdmin && strncasecmp(cle->AccountName(), whom->whom, whomlen) == 0)
))
))
) {
line[0] = 0;
uint32 rankstring=0xFFFFFFFF;
if((cle->Anon()==1 && cle->GetGM() && cle->Admin()>admin) || (idx>=20 && admin<100)){ //hide gms that are anon from lesser gms and normal players, cut off at 20
rankstring=0;
uint32 rankstring = 0xFFFFFFFF;
if((cle->Anon()==1 && cle->GetGM() && cle->Admin()>admin) || (idx>=20 && admin < AccountStatus::GMAdmin)){ //hide gms that are anon from lesser gms and normal players, cut off at 20
rankstring = 0;
iterator.Advance();
continue;
} else if (cle->GetGM()) {
if (cle->Admin() >=250)
rankstring=5021;
else if (cle->Admin() >= 200)
rankstring=5020;
else if (cle->Admin() >= 180)
rankstring=5019;
else if (cle->Admin() >= 170)
rankstring=5018;
else if (cle->Admin() >= 160)
rankstring=5017;
else if (cle->Admin() >= 150)
rankstring=5016;
else if (cle->Admin() >= 100)
rankstring=5015;
else if (cle->Admin() >= 95)
rankstring=5014;
else if (cle->Admin() >= 90)
rankstring=5013;
else if (cle->Admin() >= 85)
rankstring=5012;
else if (cle->Admin() >= 81)
rankstring=5011;
else if (cle->Admin() >= 80)
rankstring=5010;
else if (cle->Admin() >= 50)
rankstring=5009;
else if (cle->Admin() >= 20)
rankstring=5008;
else if (cle->Admin() >= 10)
rankstring=5007;
if (cle->Admin() >= AccountStatus::GMImpossible)
rankstring = 5021;
else if (cle->Admin() >= AccountStatus::GMMgmt)
rankstring = 5020;
else if (cle->Admin() >= AccountStatus::GMCoder)
rankstring = 5019;
else if (cle->Admin() >= AccountStatus::GMAreas)
rankstring = 5018;
else if (cle->Admin() >= AccountStatus::QuestMaster)
rankstring = 5017;
else if (cle->Admin() >= AccountStatus::GMLeadAdmin)
rankstring = 5016;
else if (cle->Admin() >= AccountStatus::GMAdmin)
rankstring = 5015;
else if (cle->Admin() >= AccountStatus::GMStaff)
rankstring = 5014;
else if (cle->Admin() >= AccountStatus::EQSupport)
rankstring = 5013;
else if (cle->Admin() >= AccountStatus::GMTester)
rankstring = 5012;
else if (cle->Admin() >= AccountStatus::SeniorGuide)
rankstring = 5011;
else if (cle->Admin() >= AccountStatus::QuestTroupe)
rankstring = 5010;
else if (cle->Admin() >= AccountStatus::Guide)
rankstring = 5009;
else if (cle->Admin() >= AccountStatus::ApprenticeGuide)
rankstring = 5008;
else if (cle->Admin() >= AccountStatus::Steward)
rankstring = 5007;
}
idx++;
char guildbuffer[67]={0};
if (cle->GuildID() != GUILD_NONE && cle->GuildID()>0)
sprintf(guildbuffer,"<%s>", guild_mgr.GetGuildName(cle->GuildID()));
uint32 formatstring=5025;
if(cle->Anon()==1 && (admin<cle->Admin() || admin==0))
if(cle->Anon()==1 && (admin<cle->Admin() || admin == AccountStatus::Player))
formatstring=5024;
else if(cle->Anon()==1 && admin>=cle->Admin() && admin>0)
else if(cle->Anon()==1 && admin>=cle->Admin() && admin > AccountStatus::Player)
formatstring=5022;
else if(cle->Anon()==2 && (admin<cle->Admin() || admin==0))
else if(cle->Anon()==2 && (admin<cle->Admin() || admin == AccountStatus::Player))
formatstring=5023;//display guild
else if(cle->Anon()==2 && admin>=cle->Admin() && admin>0)
else if(cle->Anon()==2 && admin>=cle->Admin() && admin > AccountStatus::Player)
formatstring=5022;//display everything
//war* wars2 = (war*)pack2->pBuffer;
@@ -711,10 +723,10 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
uint32 zonestring=0xFFFFFFFF;
uint32 plzone=0;
uint32 unknown80[2];
if(cle->Anon()==0 || (admin>=cle->Admin() && admin>0)){
if(cle->Anon()==0 || (admin>=cle->Admin() && admin> AccountStatus::Player)){
plclass_=cle->class_();
pllevel=cle->level();
if(admin>=100)
if(admin>=AccountStatus::GMAdmin)
pidstring=5003;
plrace=cle->race();
zonestring=5006;
@@ -722,7 +734,7 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
}
if(admin>=cle->Admin() && admin>0)
if(admin>=cle->Admin() && admin > AccountStatus::Player)
unknown80[0]=cle->Admin();
else
unknown80[0]=0xFFFFFFFF;
@@ -735,7 +747,7 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
strcpy(plname,cle->name());
char placcount[30]={0};
if(admin>=cle->Admin() && admin>0)
if(admin>=cle->Admin() && admin > AccountStatus::Player)
strcpy(placcount,cle->AccountName());
memcpy(bufptr,&formatstring, sizeof(uint32));
@@ -1020,7 +1032,7 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
if (
(cle->Online() >= CLE_Status::Zoning)
&& (whom == 0 || (
((cle->Admin() >= 80 && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
((cle->Admin() >= AccountStatus::QuestTroupe && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
(whom->lvllow == 0xFFFF || (cle->level() >= whom->lvllow && cle->level() <= whom->lvlhigh)) &&
(whom->wclass == 0xFFFF || cle->class_() == whom->wclass) &&
(whom->wrace == 0xFFFF || cle->race() == whom->wrace) &&
@@ -1028,41 +1040,41 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
(tmpZone != 0 && strncasecmp(tmpZone, whom->whom, whomlen) == 0) ||
strncasecmp(cle->name(), whom->whom, whomlen) == 0 ||
(strncasecmp(guild_mgr.GetGuildName(cle->GuildID()), whom->whom, whomlen) == 0) ||
(admin >= 100 && strncasecmp(cle->AccountName(), whom->whom, whomlen) == 0)
(admin >= AccountStatus::GMAdmin && strncasecmp(cle->AccountName(), whom->whom, whomlen) == 0)
))
))
) {
line[0] = 0;
// MYRA - use new (5.x) Status labels in who for telnet connection
if (cle->Admin() >= 250)
if (cle->Admin() >= AccountStatus::GMImpossible)
strcpy(tmpgm, "* GM-Impossible * ");
else if (cle->Admin() >= 200)
else if (cle->Admin() >= AccountStatus::GMMgmt)
strcpy(tmpgm, "* GM-Mgmt * ");
else if (cle->Admin() >= 180)
else if (cle->Admin() >= AccountStatus::GMCoder)
strcpy(tmpgm, "* GM-Coder * ");
else if (cle->Admin() >= 170)
else if (cle->Admin() >= AccountStatus::GMAreas)
strcpy(tmpgm, "* GM-Areas * ");
else if (cle->Admin() >= 160)
else if (cle->Admin() >= AccountStatus::QuestMaster)
strcpy(tmpgm, "* QuestMaster * ");
else if (cle->Admin() >= 150)
else if (cle->Admin() >= AccountStatus::GMLeadAdmin)
strcpy(tmpgm, "* GM-Lead Admin * ");
else if (cle->Admin() >= 100)
else if (cle->Admin() >= AccountStatus::GMAdmin)
strcpy(tmpgm, "* GM-Admin * ");
else if (cle->Admin() >= 95)
else if (cle->Admin() >= AccountStatus::GMStaff)
strcpy(tmpgm, "* GM-Staff * ");
else if (cle->Admin() >= 90)
else if (cle->Admin() >= AccountStatus::EQSupport)
strcpy(tmpgm, "* EQ Support * ");
else if (cle->Admin() >= 85)
else if (cle->Admin() >= AccountStatus::GMTester)
strcpy(tmpgm, "* GM-Tester * ");
else if (cle->Admin() >= 81)
else if (cle->Admin() >= AccountStatus::SeniorGuide)
strcpy(tmpgm, "* Senior Guide * ");
else if (cle->Admin() >= 80)
else if (cle->Admin() >= AccountStatus::QuestTroupe)
strcpy(tmpgm, "* QuestTroupe * ");
else if (cle->Admin() >= 50)
else if (cle->Admin() >= AccountStatus::Guide)
strcpy(tmpgm, "* Guide * ");
else if (cle->Admin() >= 20)
else if (cle->Admin() >= AccountStatus::ApprenticeGuide)
strcpy(tmpgm, "* Apprentice Guide * ");
else if (cle->Admin() >= 10)
else if (cle->Admin() >= AccountStatus::Steward)
strcpy(tmpgm, "* Steward * ");
else
tmpgm[0] = 0;
@@ -1079,16 +1091,16 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
else
LFG[0] = 0;
if (admin >= 150 && admin >= cle->Admin()) {
if (admin >= AccountStatus::GMLeadAdmin && admin >= cle->Admin()) {
sprintf(accinfo, " AccID: %i AccName: %s LSID: %i Status: %i", cle->AccountID(), cle->AccountName(), cle->LSAccountID(), cle->Admin());
}
else
accinfo[0] = 0;
if (cle->Anon() == 2) { // Roleplay
if (admin >= 100 && admin >= cle->Admin())
if (admin >= AccountStatus::GMAdmin && admin >= cle->Admin())
sprintf(line, " %s[RolePlay %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetClassIDName(cle->class_(), cle->level()), cle->name(), GetRaceIDName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
else if (cle->Admin() >= 80 && admin < 80 && cle->GetGM()) {
else if (cle->Admin() >= AccountStatus::QuestTroupe && admin < AccountStatus::QuestTroupe && cle->GetGM()) {
iterator.Advance();
continue;
}
@@ -1096,9 +1108,9 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
sprintf(line, " %s[ANONYMOUS] %s%s%s%s", tmpgm, cle->name(), tmpguild, LFG, accinfo);
}
else if (cle->Anon() == 1) { // Anon
if (admin >= 100 && admin >= cle->Admin())
if (admin >= AccountStatus::GMAdmin && admin >= cle->Admin())
sprintf(line, " %s[ANON %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetClassIDName(cle->class_(), cle->level()), cle->name(), GetRaceIDName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
else if (cle->Admin() >= 80 && cle->GetGM()) {
else if (cle->Admin() >= AccountStatus::QuestTroupe && cle->GetGM()) {
iterator.Advance();
continue;
}
@@ -1111,7 +1123,13 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
fmt::format_to(out, line);
if (out.size() >= 3584) {
auto output = fmt::to_string(out);
connection->SendEmoteMessageRaw(to, 0, 0, 10, output.c_str());
connection->SendEmoteMessageRaw(
to,
0,
AccountStatus::Player,
Chat::NPCQuestSay,
output.c_str()
);
out.clear();
}
else {
@@ -1121,17 +1139,17 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
fmt::format_to(out, "\n");
}
x++;
if (x >= 20 && admin < 80)
if (x >= 20 && admin < AccountStatus::QuestTroupe)
break;
}
iterator.Advance();
}
if (x >= 20 && admin < 80)
if (x >= 20 && admin < AccountStatus::QuestTroupe)
fmt::format_to(out, "too many results...20 players shown");
else
fmt::format_to(out, "{} players online", x);
if (admin >= 150 && (whom == 0 || whom->gmlookup != 0xFFFF)) {
if (admin >= AccountStatus::GMAdmin && (whom == 0 || whom->gmlookup != 0xFFFF)) {
if (connection->IsConsole())
fmt::format_to(out, "\r\n");
else
@@ -1140,7 +1158,13 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
//console_list.SendConsoleWho(connection, to, admin, &output, &outsize, &outlen);
}
auto output = fmt::to_string(out);
connection->SendEmoteMessageRaw(to, 0, 0, 10, output.c_str());
connection->SendEmoteMessageRaw(
to,
0,
AccountStatus::Player,
Chat::NPCQuestSay,
output.c_str()
);
}
void ClientList::Add(Client* client) {
@@ -1386,7 +1410,7 @@ void ClientList::SendClientVersionSummary(const char *Name)
zoneserver_list.SendEmoteMessage(
Name,
0,
0,
AccountStatus::Player,
Chat::White,
fmt::format(
"There {} {} Titanium, {} SoF, {} SoD, {} UF, {} RoF, and {} RoF2 Client{} currently connected for a total of {} Client{} and {} Unique IP{} connected.",
+1 -1
View File
@@ -62,7 +62,7 @@ public:
void DisconnectByIP(uint32 iIP);
void CLCheckStale();
void CLEKeepAlive(uint32 numupdates, uint32* wid);
void CLEAdd(uint32 iLSID, const char* iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0);
void CLEAdd(uint32 iLSID, const char* iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = AccountStatus::Player, uint32 ip = 0, uint8 local=0);
void UpdateClientGuild(uint32 char_id, uint32 guild_id);
void RemoveCLEByLSID(uint32 iLSID);
bool IsAccountInGame(uint32 iLSID);
+38 -7
View File
@@ -280,20 +280,33 @@ void ConsoleEmote(
join_args.erase(join_args.begin(), join_args.begin() + 2);
if (strcasecmp(args[0].c_str(), "world") == 0) {
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, atoi(args[1].c_str()), JoinString(join_args, " ").c_str());
zoneserver_list.SendEmoteMessageRaw(
0,
0,
AccountStatus::Player,
atoi(args[1].c_str()),
JoinString(join_args, " ").c_str()
);
}
else {
ZoneServer *zs = zoneserver_list.FindByName(args[0].c_str());
if (zs != 0) {
zs->SendEmoteMessageRaw(0, 0, 0, atoi(args[1].c_str()), JoinString(join_args, " ").c_str());
zs->SendEmoteMessageRaw(
0,
0,
AccountStatus::Player,
atoi(args[1].c_str()),
JoinString(join_args, " ").c_str()
);
}
else {
zoneserver_list.SendEmoteMessageRaw(
args[0].c_str(),
0,
0,
AccountStatus::Player,
atoi(args[1].c_str()),
JoinString(join_args, " ").c_str());
JoinString(join_args, " ").c_str()
);
}
}
}
@@ -637,7 +650,16 @@ void ConsoleZoneLock(
uint16 tmp = ZoneID(args[1].c_str());
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, true)) {
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone locked: %s", ZoneName(tmp));
zoneserver_list.SendEmoteMessage(
0,
0,
AccountStatus::QuestTroupe,
Chat::Yellow,
fmt::format(
"Zone locked: {}",
ZoneName(tmp)
).c_str()
);
}
else {
connection->SendLine("Failed to change lock");
@@ -655,7 +677,16 @@ void ConsoleZoneLock(
uint16 tmp = ZoneID(args[1].c_str());
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, false)) {
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone unlocked: %s", ZoneName(tmp));
zoneserver_list.SendEmoteMessage(
0,
0,
AccountStatus::QuestTroupe,
Chat::Yellow,
fmt::format(
"Zone unlocked: {}",
ZoneName(tmp)
).c_str()
);
}
else {
connection->SendLine("Failed to change lock");
@@ -782,7 +813,7 @@ void ConsoleWorldShutdown(
zoneserver_list.SendEmoteMessage(
0,
0,
0,
AccountStatus::Player,
Chat::Yellow,
"[SYSTEM] World shutdown has been aborted."
);
+9 -9
View File
@@ -481,10 +481,10 @@ void Console::ProcessCommand(const char* command) {
SendMessage(1, " version");
SendMessage(1, " worldshutdown");
}
if (admin >= 201) {
if (admin >= AccountStatus::GMMgmt) {
SendMessage(1, " IPLookup [name]");
}
if (admin >= 100) {
if (admin >= AccountStatus::GMAdmin) {
SendMessage(1, " LSReconnect");
SendMessage(1, " signalcharbyname charname ID");
SendMessage(1, " reloadworld");
@@ -799,7 +799,7 @@ void Console::ProcessCommand(const char* command) {
SendMessage(1, " Compiled on: %s at %s", COMPILE_DATE, COMPILE_TIME);
SendMessage(1, " Last modified on: %s", LAST_MODIFIED);
}
else if (strcasecmp(sep.arg[0], "serverinfo") == 0 && admin >= 200) {
else if (strcasecmp(sep.arg[0], "serverinfo") == 0 && admin >= AccountStatus::GMMgmt) {
if (strcasecmp(sep.arg[1], "os") == 0) {
#ifdef _WINDOWS
GetOS();
@@ -821,10 +821,10 @@ void Console::ProcessCommand(const char* command) {
SendMessage(1, " OS - Operating system version information.");
}
}
else if (strcasecmp(sep.arg[0], "IPLookup") == 0 && admin >= 201) {
else if (strcasecmp(sep.arg[0], "IPLookup") == 0 && admin >= AccountStatus::GMMgmt) {
client_list.SendCLEList(admin, 0, this, sep.argplus[1]);
}
else if (strcasecmp(sep.arg[0], "LSReconnect") == 0 && admin >= 100) {
else if (strcasecmp(sep.arg[0], "LSReconnect") == 0 && admin >= AccountStatus::GMAdmin) {
#ifdef _WINDOWS
_beginthread(AutoInitLoginServer, 0, nullptr);
#else
@@ -839,7 +839,7 @@ void Console::ProcessCommand(const char* command) {
if (strcasecmp(sep.arg[1], "list") == 0) {
zoneserver_list.ListLockedZones(0, this);
}
else if (strcasecmp(sep.arg[1], "lock") == 0 && admin >= 101) {
else if (strcasecmp(sep.arg[1], "lock") == 0 && admin >= AccountStatus::GMAdmin) {
uint16 tmp = ZoneID(sep.arg[2]);
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, true))
@@ -850,7 +850,7 @@ void Console::ProcessCommand(const char* command) {
else
SendMessage(1, "Usage: #zonelock lock [zonename]");
}
else if (strcasecmp(sep.arg[1], "unlock") == 0 && admin >= 101) {
else if (strcasecmp(sep.arg[1], "unlock") == 0 && admin >= AccountStatus::GMAdmin) {
uint16 tmp = ZoneID(sep.arg[2]);
if (tmp) {
if (zoneserver_list.SetLockedZone(tmp, false))
@@ -864,13 +864,13 @@ void Console::ProcessCommand(const char* command) {
else {
SendMessage(1, "#zonelock sub-commands");
SendMessage(1, " list");
if (admin >= 101) {
if (admin >= AccountStatus::GMAdmin) {
SendMessage(1, " lock [zonename]");
SendMessage(1, " unlock [zonename]");
}
}
}
else if (strcasecmp(sep.arg[0], "reloadworld") == 0 && admin > 101)
else if (strcasecmp(sep.arg[0], "reloadworld") == 0 && admin > AccountStatus::GMAdmin)
{
SendEmoteMessage(0,0,0,15,"Reloading World...");
auto pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct));
+8 -1
View File
@@ -37,6 +37,7 @@
#include "launcher_list.h"
#include "launcher_link.h"
#include "wguild_mgr.h"
#include "../common/emu_constants.h"
#ifdef seed
#undef seed
@@ -360,7 +361,13 @@ void EQW::ResolveBug(const char *id) {
}
void EQW::SendMessage(uint32 type, const char *msg) {
zoneserver_list.SendEmoteMessage(0, 0, 0, type, msg);
zoneserver_list.SendEmoteMessage(
0,
0,
AccountStatus::Player,
type,
msg
);
}
void EQW::WorldShutDown(uint32 time, uint32 interval) {
+7 -1
View File
@@ -306,7 +306,13 @@ void LoginServer::ProcessSystemwideMessage(uint16_t opcode, EQ::Net::Packet &p)
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
ServerSystemwideMessage *swm = (ServerSystemwideMessage *) p.Data();
zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
zoneserver_list.SendEmoteMessageRaw(
0,
0,
AccountStatus::Player,
swm->type,
swm->message
);
}
void LoginServer::ProcessLSRemoteAddr(uint16_t opcode, EQ::Net::Packet &p)
+14 -8
View File
@@ -119,7 +119,6 @@ EQ::Random emu_random;
volatile bool RunLoops = true;
uint32 numclients = 0;
uint32 numzones = 0;
bool holdzones = false;
const WorldConfig *Config;
EQEmuLogSys LogSys;
WorldContentService content_service;
@@ -252,13 +251,15 @@ static void GMSayHookCallBackProcessWorld(uint16 log_category, std::string messa
for (size_t iter = 0; iter < message_split.size(); ++iter) {
zoneserver_list.SendEmoteMessage(
nullptr,
0,
80,
0,
AccountStatus::QuestTroupe,
LogSys.GetGMSayColorFromCategory(log_category),
" %s%s",
(iter == 0 ? " ---" : ""),
message_split[iter].c_str()
fmt::format(
" {}{}",
(iter == 0 ? " ---" : ""),
message_split[iter]
).c_str()
);
}
@@ -266,9 +267,9 @@ static void GMSayHookCallBackProcessWorld(uint16 log_category, std::string messa
}
zoneserver_list.SendEmoteMessage(
nullptr,
0,
80,
0,
AccountStatus::QuestTroupe,
LogSys.GetGMSayColorFromCategory(log_category),
"%s",
message.c_str()
@@ -502,6 +503,11 @@ int main(int argc, char **argv)
LogInfo("Initializing [EventScheduler]");
event_scheduler.SetDatabase(&database)->LoadScheduledEvents();
LogInfo("Initializing [WorldContentService]");
content_service.SetDatabase(&database)
->SetExpansionContext()
->ReloadContentFlags();
LogInfo("Initializing [SharedTaskManager]");
shared_task_manager.SetDatabase(&database)
->SetContentDatabase(&content_db)
+7 -1
View File
@@ -45,7 +45,13 @@ void WorldEventScheduler::Process(ZSList *zs_list)
if (ValidateEventReadyToActivate(e)) {
if (e.event_type == ServerEvents::EVENT_TYPE_BROADCAST) {
LogScheduler("Sending broadcast [{}]", e.event_data.c_str());
zs_list->SendEmoteMessage(nullptr, 0, 0, 15, e.event_data.c_str());
zs_list->SendEmoteMessage(
0,
0,
AccountStatus::Player,
Chat::Yellow,
e.event_data.c_str()
);
}
if (e.event_type == ServerEvents::EVENT_TYPE_RELOAD_WORLD) {
+16 -7
View File
@@ -165,37 +165,37 @@ namespace WorldserverCommandHandler {
Json::Value player_tables_json;
std::vector<std::string> player_tables = DatabaseSchema::GetPlayerTables();
for (const auto &table : player_tables) {
for (const auto &table: player_tables) {
player_tables_json.append(table);
}
Json::Value content_tables_json;
std::vector<std::string> content_tables = DatabaseSchema::GetContentTables();
for (const auto &table : content_tables) {
for (const auto &table: content_tables) {
content_tables_json.append(table);
}
Json::Value server_tables_json;
std::vector<std::string> server_tables = DatabaseSchema::GetServerTables();
for (const auto &table : server_tables) {
for (const auto &table: server_tables) {
server_tables_json.append(table);
}
Json::Value login_tables_json;
std::vector<std::string> login_tables = DatabaseSchema::GetLoginTables();
for (const auto &table : login_tables) {
for (const auto &table: login_tables) {
login_tables_json.append(table);
}
Json::Value state_tables_json;
std::vector<std::string> state_tables = DatabaseSchema::GetStateTables();
for (const auto &table : state_tables) {
for (const auto &table: state_tables) {
state_tables_json.append(table);
}
Json::Value version_tables_json;
std::vector<std::string> version_tables = DatabaseSchema::GetVersionTables();
for (const auto &table : version_tables) {
for (const auto &table: version_tables) {
version_tables_json.append(table);
}
@@ -313,11 +313,20 @@ namespace WorldserverCommandHandler {
content_service.SetCurrentExpansion(RuleI(Expansion, CurrentExpansion));
std::vector<std::string> flags = {
std::vector<ContentFlagsRepository::ContentFlags> flags = {};
auto f = ContentFlagsRepository::NewEntity();
f.enabled = 1;
std::vector<std::string> flag_names = {
"hateplane_enabled",
"patch_nerf_7077",
};
for (auto &name: flag_names) {
f.flag_name = name;
flags.push_back(f);
}
content_service.SetContentFlags(flags);
LogInfo(
+20
View File
@@ -85,6 +85,26 @@ std::string WorldStore::GetZoneName(uint32 zone_id)
return std::string();
}
/**
* @param zone_id
* @param error_unknown
* @return
*/
const char *WorldStore::GetZoneLongName(uint32 zone_id, bool error_unknown)
{
for (auto &z: zones) {
if (z.zoneidnumber == zone_id) {
return z.long_name.c_str();
}
}
if (error_unknown) {
return "UNKNOWN";
}
return nullptr;
}
/**
* @param zone_id
* @return
+8 -2
View File
@@ -40,7 +40,7 @@ public:
std::string GetZoneName(uint32 zone_id);
std::string GetZoneLongName(uint32 zone_id);
const char *GetZoneName(uint32 zone_id, bool error_unknown = false);
const char *GetZoneLongName(uint32 zone_id, bool error_unknown = false);
};
extern WorldStore world_store;
@@ -57,7 +57,13 @@ inline const char *ZoneName(uint32 zone_id, bool error_unknown = false)
error_unknown
);
}
inline const char *ZoneLongName(uint32 zone_id) { return world_store.GetZoneLongName(zone_id).c_str(); }
inline const char *ZoneLongName(uint32 zone_id, bool error_unknown = false)
{
return world_store.GetZoneLongName(
zone_id,
error_unknown
);
}
inline ZoneRepository::Zone GetZone(uint32 zone_id, int version = 0) { return world_store.GetZone(zone_id, version); };
inline ZoneRepository::Zone GetZone(const char *in_zone_name) { return world_store.GetZone(in_zone_name); };
+115 -37
View File
@@ -30,7 +30,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "world_store.h"
extern uint32 numzones;
extern bool holdzones;
extern EQ::Random emu_random;
extern WebInterfaceList web_interface;
volatile bool UCSServerAvailable_ = false;
@@ -51,19 +50,17 @@ ZSList::~ZSList() {
void ZSList::ShowUpTime(WorldTCPConnection* con, const char* adminname) {
uint32 ms = Timer::GetCurrentTime();
uint32 d = ms / 86400000;
ms -= d * 86400000;
uint32 h = ms / 3600000;
ms -= h * 3600000;
uint32 m = ms / 60000;
ms -= m * 60000;
uint32 s = ms / 1000;
if (d)
con->SendEmoteMessage(adminname, 0, 0, 0, "Worldserver Uptime: %02id %02ih %02im %02is", d, h, m, s);
else if (h)
con->SendEmoteMessage(adminname, 0, 0, 0, "Worldserver Uptime: %02ih %02im %02is", h, m, s);
else
con->SendEmoteMessage(adminname, 0, 0, 0, "Worldserver Uptime: %02im %02is", m, s);
std::string time_string = ConvertMillisecondsToTime(ms);
con->SendEmoteMessage(
adminname,
0,
AccountStatus::Player,
Chat::White,
fmt::format(
"Worldserver Uptime | {}",
time_string
).c_str()
);
}
void ZSList::Add(ZoneServer* zoneserver) {
@@ -113,7 +110,7 @@ void ZSList::Process() {
SendEmoteMessage(
0,
0,
0,
AccountStatus::Player,
Chat::Yellow,
fmt::format(
"[SYSTEM] World will be shutting down in {} minutes.",
@@ -270,14 +267,39 @@ bool ZSList::IsZoneLocked(uint16 iZoneID) {
}
void ZSList::ListLockedZones(const char* to, WorldTCPConnection* connection) {
int x = 0;
for (auto &zone : pLockedZones) {
if (zone) {
connection->SendEmoteMessageRaw(to, 0, 0, 0, ZoneName(zone, true));
x++;
int zone_count = 0;
for (const auto& zone_id : pLockedZones) {
if (zone_id) {
int zone_number = (zone_count + 1);
connection->SendEmoteMessageRaw(
to,
0,
AccountStatus::Player,
Chat::White,
fmt::format(
"Zone {} | Name: {} ({}) ID: {}",
zone_number,
ZoneLongName(zone_id),
ZoneName(zone_id),
zone_id
).c_str()
);
zone_count++;
}
}
connection->SendEmoteMessage(to, 0, 0, 0, "%i zones locked.", x);
std::string zone_message = (
zone_count ?
fmt::format("{} Zones are locked.", zone_count) :
"There are no zones locked."
);
connection->SendEmoteMessage(
to,
0,
AccountStatus::Player,
Chat::White,
zone_message.c_str()
);
}
void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* connection) {
@@ -330,7 +352,7 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con
else
is_static_string[0] = 'D';
if (admin >= 150) {
if (admin >= AccountStatus::GMLeadAdmin) {
if (zone_server_data->GetZoneID()) {
snprintf(zone_data_string, sizeof(zone_data_string), "%s (%i)", zone_server_data->GetZoneName(), zone_server_data->GetZoneID());
}
@@ -356,7 +378,13 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con
if (out.size() >= 3584) {
auto output = fmt::to_string(out);
connection->SendEmoteMessageRaw(to, 0, 0, 10, output.c_str());
connection->SendEmoteMessageRaw(
to,
0,
AccountStatus::Player,
Chat::NPCQuestSay,
output.c_str()
);
out.clear();
}
else {
@@ -375,7 +403,13 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con
fmt::format_to(out, " #{} {} {}", zone_server_data->GetID(), is_static_string, zone_data_string);
if (out.size() >= 3584) {
auto output = fmt::to_string(out);
connection->SendEmoteMessageRaw(to, 0, 0, 10, output.c_str());
connection->SendEmoteMessageRaw(
to,
0,
AccountStatus::Player,
Chat::NPCQuestSay,
output.c_str()
);
out.clear();
}
else {
@@ -402,7 +436,13 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con
fmt::format_to(out, "{} zones are static zones, {} zones are booted zones, {} zones available.", z, w, v);
auto output = fmt::to_string(out);
connection->SendEmoteMessageRaw(to, 0, 0, 10, output.c_str());
connection->SendEmoteMessageRaw(
to,
0,
AccountStatus::Player,
Chat::NPCQuestSay,
output.c_str()
);
}
void ZSList::SendChannelMessage(const char* from, const char* to, uint8 chan_num, uint8 language, const char* message, ...) {
@@ -533,20 +573,52 @@ void ZSList::SOPZoneBootup(const char* adminname, uint32 ZoneServerID, const cha
ZoneServer* zs = 0;
ZoneServer* zs2 = 0;
uint32 zoneid;
if (!(zoneid = ZoneID(zonename)))
SendEmoteMessage(adminname, 0, 0, 0, "Error: SOP_ZoneBootup: zone '%s' not found in 'zone' table. Typo protection=ON.", zonename);
else {
if (ZoneServerID != 0)
if (!(zoneid = ZoneID(zonename))) {
SendEmoteMessage(
adminname,
0,
AccountStatus::Player,
Chat::White,
fmt::format(
"Error: SOP_ZoneBootup: Zone '{}' not found in 'zone' table.",
zonename
).c_str()
);
} else {
if (ZoneServerID != 0) {
zs = FindByID(ZoneServerID);
else
SendEmoteMessage(adminname, 0, 0, 0, "Error: SOP_ZoneBootup: ServerID must be specified");
} else {
SendEmoteMessage(
adminname,
0,
AccountStatus::Player,
Chat::White,
"Error: SOP_ZoneBootup: Server ID must be specified."
);
}
if (zs == 0)
SendEmoteMessage(adminname, 0, 0, 0, "Error: SOP_ZoneBootup: zoneserver not found");
else {
if (!zs) {
SendEmoteMessage(
adminname,
0,
AccountStatus::Player,
Chat::White,
"Error: SOP_ZoneBootup: Zoneserver not found."
);
} else {
zs2 = FindByName(zonename);
if (zs2 != 0)
SendEmoteMessage(adminname, 0, 0, 0, "Error: SOP_ZoneBootup: zone '%s' already being hosted by ZoneServer #%i", zonename, zs2->GetID());
SendEmoteMessage(
adminname,
0,
AccountStatus::Player,
Chat::White,
fmt::format(
"Error: SOP_ZoneBootup: Zone '{}' already being hosted by Zoneserver ID {}.",
zonename,
zs2->GetID()
).c_str()
);
else {
zs->TriggerBootup(zoneid, 0, adminname, iMakeStatic);
}
@@ -689,7 +761,7 @@ void ZSList::WorldShutDown(uint32 time, uint32 interval)
SendEmoteMessage(
0,
0,
0,
AccountStatus::Player,
Chat::Yellow,
fmt::format(
"[SYSTEM] World will be shutting down in {} minutes.",
@@ -708,7 +780,13 @@ void ZSList::WorldShutDown(uint32 time, uint32 interval)
reminder->Start();
}
else {
SendEmoteMessage(0, 0, 0, 15, "[SYSTEM] World is shutting down.");
SendEmoteMessage(
0,
0,
AccountStatus::Player,
Chat::Yellow,
"[SYSTEM] World is shutting down."
);
auto pack = new ServerPacket;
pack->opcode = ServerOP_ShutdownAll;
pack->size = 0;
+167 -54
View File
@@ -41,6 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "shared_task_world_messaging.h"
#include "../common/shared_tasks.h"
#include "shared_task_manager.h"
#include "../common/content/world_content_service.h"
extern ClientList client_list;
extern GroupLFPList LFPGroupList;
@@ -438,7 +439,16 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
safe_delete(pack);
}))) && (!scm->noreply))
{
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "%s is not online at this time.", scm->to);
zoneserver_list.SendEmoteMessage(
scm->from,
0,
AccountStatus::Player,
Chat::White,
fmt::format(
"{} is not online at this time.",
scm->to
).c_str()
);
}
}
break;
@@ -446,7 +456,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
ClientListEntry* cle = client_list.FindCharacter(scm->deliverto);
if (cle == 0 || cle->Online() < CLE_Status::Zoning ||
(cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
(cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < AccountStatus::QuestTroupe))) {
if (!scm->noreply) {
ClientListEntry* sender = client_list.FindCharacter(scm->from);
if (!sender || !sender->Server())
@@ -491,7 +501,17 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
else if (cle->Server() == 0) {
if (!scm->noreply)
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not contactable at this time'", scm->to, scm->to);
zoneserver_list.SendEmoteMessage(
scm->from,
0,
AccountStatus::Player,
Chat::White,
fmt::format(
"You told {}, '{} is not contactable at this time'",
scm->to,
scm->to
).c_str()
);
}
else
cle->Server()->SendPacket(pack);
@@ -518,29 +538,36 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
case ServerOP_EmoteMessage: {
ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*)pack->pBuffer;
zoneserver_list.SendEmoteMessageRaw(sem->to, sem->guilddbid, sem->minstatus, sem->type, sem->message);
zoneserver_list.SendEmoteMessageRaw(
sem->to,
sem->guilddbid,
sem->minstatus,
sem->type,
sem->message
);
break;
}
case ServerOP_VoiceMacro: {
ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*)pack->pBuffer;
if (svm->Type == VoiceMacroTell) {
ClientListEntry* cle = client_list.FindCharacter(svm->To);
if (!cle || (cle->Online() < CLE_Status::Zoning) || !cle->Server()) {
zoneserver_list.SendEmoteMessage(svm->From, 0, 0, 0, "'%s is not online at this time'", svm->To);
zoneserver_list.SendEmoteMessage(
svm->From,
0,
AccountStatus::Player,
Chat::White,
fmt::format(
"'{} is not online at this time'",
svm->To
).c_str()
);
break;
}
cle->Server()->SendPacket(pack);
}
else
} else {
zoneserver_list.SendPacket(pack);
}
break;
}
@@ -656,17 +683,31 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
case ServerOP_ZoneShutdown: {
ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *)pack->pBuffer;
ZoneServer* zs = 0;
if (s->ZoneServerID != 0)
if (s->ZoneServerID != 0) {
zs = zoneserver_list.FindByID(s->ZoneServerID);
else if (s->zoneid != 0)
} else if (s->zoneid != 0) {
zs = zoneserver_list.FindByName(ZoneName(s->zoneid));
else
zoneserver_list.SendEmoteMessage(s->adminname, 0, 0, 0, "Error: SOP_ZoneShutdown: neither ID nor name specified");
} else {
zoneserver_list.SendEmoteMessage(
s->adminname,
0,
AccountStatus::Player,
Chat::White,
"Error: SOP_ZoneShutdown: neither ID nor name specified"
);
}
if (zs == 0)
zoneserver_list.SendEmoteMessage(s->adminname, 0, 0, 0, "Error: SOP_ZoneShutdown: zoneserver not found");
else
if (!zs) {
zoneserver_list.SendEmoteMessage(
s->adminname,
0,
AccountStatus::Player,
Chat::White,
"Error: SOP_ZoneShutdown: zoneserver not found"
);
} else {
zs->SendPacket(pack);
}
break;
}
case ServerOP_ZoneBootup: {
@@ -717,7 +758,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
if (GetZoneID() == ztz->current_zone_id && GetInstanceID() == ztz->current_instance_id) {
LogInfo("Processing ZTZ for egress from zone for client [{}]", ztz->name);
if (ztz->admin < 80 && ztz->ignorerestrictions < 2 && zoneserver_list.IsZoneLocked(ztz->requested_zone_id)) {
if (ztz->admin < AccountStatus::QuestTroupe && ztz->ignorerestrictions < 2 && zoneserver_list.IsZoneLocked(ztz->requested_zone_id)) {
ztz->response = 0;
SendPacket(pack);
break;
@@ -828,6 +869,11 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
RuleManager::Instance()->LoadRules(&database, "default", true);
break;
}
case ServerOP_ReloadContentFlags: {
zoneserver_list.SendPacket(pack);
content_service.SetExpansionContext()->ReloadContentFlags();
break;
}
case ServerOP_ReloadRulesWorld:
{
RuleManager::Instance()->LoadRules(&database, "default", true);
@@ -909,15 +955,43 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
ServerGMGoto_Struct* gmg = (ServerGMGoto_Struct*)pack->pBuffer;
ClientListEntry* cle = client_list.FindCharacter(gmg->gotoname);
if (cle != 0) {
if (cle->Server() == 0)
this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: Cannot identify %s's zoneserver.", gmg->gotoname);
else if (cle->Anon() == 1 && cle->Admin() > gmg->admin) // no snooping for anon GMs
this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: %s not found", gmg->gotoname);
else
if (!cle->Server()) {
SendEmoteMessage(
gmg->myname,
0,
AccountStatus::Player,
Chat::Red,
fmt::format(
"Error: Cannot identify {}'s zoneserver.",
gmg->gotoname
).c_str()
);
} else if (cle->Anon() == 1 && cle->Admin() > gmg->admin) { // no snooping for anon GMs
SendEmoteMessage(
gmg->myname,
0,
AccountStatus::Player,
Chat::Red,
fmt::format(
"Error: {} not found.",
gmg->gotoname
).c_str()
);
} else {
cle->Server()->SendPacket(pack);
}
}
else {
this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: %s not found", gmg->gotoname);
SendEmoteMessage(
gmg->myname,
0,
AccountStatus::Player,
Chat::Red,
fmt::format(
"Error: {} not found",
gmg->gotoname
).c_str()
);
}
break;
}
@@ -933,16 +1007,28 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
WorldConfig::UnlockWorld();
if (loginserverlist.Connected()) {
loginserverlist.SendStatus();
if (slock->mode >= 1)
this->SendEmoteMessage(slock->myname, 0, 0, 13, "World locked");
else
this->SendEmoteMessage(slock->myname, 0, 0, 13, "World unlocked");
SendEmoteMessage(
slock->myname,
0,
AccountStatus::Player,
Chat::Red,
fmt::format(
"World {}.",
slock->mode ? "locked" : "unlocked"
).c_str()
);
}
else {
if (slock->mode >= 1)
this->SendEmoteMessage(slock->myname, 0, 0, 13, "World locked, but login server not connected.");
else
this->SendEmoteMessage(slock->myname, 0, 0, 13, "World unlocked, but login server not conencted.");
SendEmoteMessage(
slock->myname,
0,
AccountStatus::Player,
Chat::Red,
fmt::format(
"World {}, but login server not connected.",
slock->mode ? "locked" : "unlocked"
).c_str()
);
}
break;
}
@@ -953,7 +1039,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
ServerMotd_Struct* smotd = (ServerMotd_Struct*)pack->pBuffer;
database.SetVariable("MOTD", smotd->motd);
//this->SendEmoteMessage(smotd->myname, 0, 0, 13, "Updated Motd.");
zoneserver_list.SendPacket(pack);
break;
}
@@ -1022,22 +1107,44 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
LogInfo("Wrong size on ServerOP_LockZone. Got: [{}], Expected: [{}]", pack->size, sizeof(ServerLockZone_Struct));
break;
}
ServerLockZone_Struct* s = (ServerLockZone_Struct*)pack->pBuffer;
switch (s->op) {
case 0:
zoneserver_list.ListLockedZones(s->adminname, this);
ServerLockZone_Struct* lock_zone = (ServerLockZone_Struct*) pack->pBuffer;
if (lock_zone->op == ServerLockType::List) {
zoneserver_list.ListLockedZones(lock_zone->adminname, this);
break;
case 1:
if (zoneserver_list.SetLockedZone(s->zoneID, true))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone locked: %s", ZoneName(s->zoneID));
else
this->SendEmoteMessageRaw(s->adminname, 0, 0, 0, "Failed to change lock");
break;
case 2:
if (zoneserver_list.SetLockedZone(s->zoneID, false))
zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone unlocked: %s", ZoneName(s->zoneID));
else
this->SendEmoteMessageRaw(s->adminname, 0, 0, 0, "Failed to change lock");
} else if (
lock_zone->op == ServerLockType::Lock ||
lock_zone->op == ServerLockType::Unlock
) {
if (zoneserver_list.SetLockedZone(lock_zone->zoneID, lock_zone->op == ServerLockType::Lock)) {
zoneserver_list.SendEmoteMessage(
0,
0,
AccountStatus::QuestTroupe,
Chat::White,
fmt::format(
"Zone {} | Name: {} ({}) ID: {}",
lock_zone->op == ServerLockType::Lock ? "Locked" : "Unlocked",
ZoneLongName(lock_zone->zoneID),
ZoneName(lock_zone->zoneID),
lock_zone->zoneID
).c_str()
);
} else {
SendEmoteMessageRaw(
lock_zone->adminname,
0,
AccountStatus::Player,
Chat::White,
fmt::format(
"Zone Failed to {} | Name: {} ({}) ID: {}",
lock_zone->op == ServerLockType::Lock ? "Lock" : "Unlock",
ZoneLongName(lock_zone->zoneID),
ZoneName(lock_zone->zoneID),
lock_zone->zoneID
).c_str()
);
}
break;
}
break;
@@ -1382,7 +1489,13 @@ void ZoneServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_
va_start(argptr, message);
vsnprintf(buffer, sizeof(buffer), message, argptr);
va_end(argptr);
SendEmoteMessageRaw(to, to_guilddbid, to_minstatus, type, buffer);
SendEmoteMessageRaw(
to,
to_guilddbid,
to_minstatus,
type,
buffer
);
}
void ZoneServer::SendEmoteMessageRaw(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message) {
+1 -1
View File
@@ -22,6 +22,7 @@
#include "../common/net/servertalk_server.h"
#include "../common/event/timer.h"
#include "../common/timer.h"
#include "../common/emu_constants.h"
#include "console.h"
#include <string.h>
#include <string>
@@ -29,7 +30,6 @@
class Client;
class ServerPacket;
class ZoneServer : public WorldTCPConnection {
public:
ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console);
+576 -283
View File
@@ -1,293 +1,586 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
SET(zone_sources
aa.cpp
aa_ability.cpp
aggro.cpp
aggromanager.cpp
api_service.cpp
attack.cpp
aura.cpp
beacon.cpp
bonuses.cpp
bot.cpp
bot_command.cpp
bot_database.cpp
botspellsai.cpp
cheat_manager.cpp
client.cpp
client_mods.cpp
client_packet.cpp
client_process.cpp
command.cpp
corpse.cpp
data_bucket.cpp
doors.cpp
dialogue_window.cpp
dynamic_zone.cpp
effects.cpp
embparser.cpp
embparser_api.cpp
embperl.cpp
embxs.cpp
encounter.cpp
entity.cpp
exp.cpp
expedition.cpp
expedition_database.cpp
expedition_request.cpp
fastmath.cpp
fearpath.cpp
forage.cpp
groups.cpp
guild.cpp
guild_mgr.cpp
hate_list.cpp
heal_rotation.cpp
horse.cpp
inventory.cpp
loottables.cpp
lua_bot.cpp
lua_bit.cpp
lua_corpse.cpp
lua_client.cpp
lua_door.cpp
lua_encounter.cpp
lua_entity.cpp
lua_entity_list.cpp
lua_expedition.cpp
lua_general.cpp
lua_group.cpp
lua_hate_list.cpp
lua_inventory.cpp
lua_item.cpp
lua_iteminst.cpp
lua_mob.cpp
lua_mod.cpp
lua_npc.cpp
lua_object.cpp
lua_packet.cpp
lua_parser.cpp
lua_parser_events.cpp
lua_raid.cpp
lua_spawn.cpp
lua_spell.cpp
lua_stat_bonuses.cpp
embperl.cpp
embxs.cpp
entity.cpp
exp.cpp
fearpath.cpp
forage.cpp
global_loot_manager.cpp
gm_commands/door_manipulation.cpp
groups.cpp
guild.cpp
guild_mgr.cpp
hate_list.cpp
horse.cpp
inventory.cpp
loottables.cpp
main.cpp
map.cpp
merc.cpp
mob.cpp
mob_ai.cpp
mob_appearance.cpp
mob_movement_manager.cpp
mob_info.cpp
mod_functions.cpp
npc.cpp
npc_ai.cpp
npc_scale_manager.cpp
object.cpp
oriented_bounding_box.cpp
pathfinder_interface.cpp
pathfinder_nav_mesh.cpp
pathfinder_null.cpp
pathing.cpp
perl_bot.cpp
perl_client.cpp
perl_doors.cpp
perl_entity.cpp
perl_expedition.cpp
perl_groups.cpp
perl_hateentry.cpp
perl_inventory.cpp
perl_mob.cpp
perl_npc.cpp
perl_object.cpp
perl_perlpacket.cpp
perl_player_corpse.cpp
perl_questitem.cpp
perl_raids.cpp
perl_spell.cpp
perlpacket.cpp
petitions.cpp
pets.cpp
position.cpp
qglobals.cpp
queryserv.cpp
questmgr.cpp
quest_parser_collection.cpp
raids.cpp
raycast_mesh.cpp
shared_task_zone_messaging.cpp
spawn2.cpp
spawn2.h
spawngroup.cpp
special_attacks.cpp
spell_effects.cpp
spells.cpp
task_client_state.cpp
task_goal_list_manager.cpp
task_manager.cpp
task_proximity_manager.cpp
tasks.cpp
titles.cpp
tradeskills.cpp
trading.cpp
trap.cpp
tribute.cpp
tune.cpp
water_map.cpp
water_map_v1.cpp
water_map_v2.cpp
waypoints.cpp
worldserver.cpp
xtargetautohaters.cpp
zone.cpp
zone_config.cpp
zonedb.cpp
zone_event_scheduler.cpp
zone_reload.cpp
zone_store.cpp
zoning.cpp
)
aa.cpp
aa_ability.cpp
aggro.cpp
aggromanager.cpp
api_service.cpp
attack.cpp
aura.cpp
beacon.cpp
bonuses.cpp
bot.cpp
bot_command.cpp
bot_database.cpp
botspellsai.cpp
cheat_manager.cpp
client.cpp
client_mods.cpp
client_packet.cpp
client_process.cpp
command.cpp
corpse.cpp
data_bucket.cpp
doors.cpp
dialogue_window.cpp
dynamic_zone.cpp
effects.cpp
embparser.cpp
embparser_api.cpp
embperl.cpp
embxs.cpp
encounter.cpp
entity.cpp
exp.cpp
expedition.cpp
expedition_database.cpp
expedition_request.cpp
fastmath.cpp
fearpath.cpp
forage.cpp
groups.cpp
guild.cpp
guild_mgr.cpp
hate_list.cpp
heal_rotation.cpp
horse.cpp
inventory.cpp
loottables.cpp
lua_bot.cpp
lua_bit.cpp
lua_corpse.cpp
lua_client.cpp
lua_door.cpp
lua_encounter.cpp
lua_entity.cpp
lua_entity_list.cpp
lua_expedition.cpp
lua_general.cpp
lua_group.cpp
lua_hate_list.cpp
lua_inventory.cpp
lua_item.cpp
lua_iteminst.cpp
lua_mob.cpp
lua_mod.cpp
lua_npc.cpp
lua_object.cpp
lua_packet.cpp
lua_parser.cpp
lua_parser_events.cpp
lua_raid.cpp
lua_spawn.cpp
lua_spell.cpp
lua_stat_bonuses.cpp
embperl.cpp
embxs.cpp
entity.cpp
exp.cpp
fearpath.cpp
forage.cpp
global_loot_manager.cpp
gm_commands/door_manipulation.cpp
groups.cpp
guild.cpp
guild_mgr.cpp
hate_list.cpp
horse.cpp
inventory.cpp
loottables.cpp
main.cpp
map.cpp
merc.cpp
mob.cpp
mob_ai.cpp
mob_appearance.cpp
mob_movement_manager.cpp
mob_info.cpp
mod_functions.cpp
npc.cpp
npc_ai.cpp
npc_scale_manager.cpp
object.cpp
oriented_bounding_box.cpp
pathfinder_interface.cpp
pathfinder_nav_mesh.cpp
pathfinder_null.cpp
pathing.cpp
perl_bot.cpp
perl_client.cpp
perl_doors.cpp
perl_entity.cpp
perl_expedition.cpp
perl_groups.cpp
perl_hateentry.cpp
perl_inventory.cpp
perl_mob.cpp
perl_npc.cpp
perl_object.cpp
perl_perlpacket.cpp
perl_player_corpse.cpp
perl_questitem.cpp
perl_raids.cpp
perl_spell.cpp
perlpacket.cpp
petitions.cpp
pets.cpp
position.cpp
qglobals.cpp
queryserv.cpp
questmgr.cpp
quest_parser_collection.cpp
raids.cpp
raycast_mesh.cpp
shared_task_zone_messaging.cpp
spawn2.cpp
spawn2.h
spawngroup.cpp
special_attacks.cpp
spell_effects.cpp
spells.cpp
task_client_state.cpp
task_goal_list_manager.cpp
task_manager.cpp
task_proximity_manager.cpp
tasks.cpp
titles.cpp
tradeskills.cpp
trading.cpp
trap.cpp
tribute.cpp
tune.cpp
water_map.cpp
water_map_v1.cpp
water_map_v2.cpp
waypoints.cpp
worldserver.cpp
xtargetautohaters.cpp
zone.cpp
zone_config.cpp
zonedb.cpp
zone_event_scheduler.cpp
zone_reload.cpp
zone_store.cpp
zoning.cpp
)
SET(zone_headers
aa.h
aa_ability.h
aggromanager.h
api_service.h
aura.h
basic_functions.h
beacon.h
bot.h
bot_command.h
bot_database.h
bot_structs.h
cheat_manager.h
client.h
client_packet.h
command.h
common.h
corpse.h
data_bucket.h
doors.h
dialogue_window.h
dynamic_zone.h
embparser.h
embperl.h
embxs.h
encounter.h
entity.h
errmsg.h
event_codes.h
expedition.h
expedition_database.h
expedition_request.h
fastmath.h
forage.h
global_loot_manager.h
gm_commands/door_manipulation.h
groups.h
guild_mgr.h
hate_list.h
heal_rotation.h
horse.h
lua_bot.h
lua_bit.h
lua_client.h
lua_corpse.h
lua_door.h
lua_encounter.h
lua_entity.h
lua_entity_list.h
lua_expedition.h
lua_general.h
lua_group.h
lua_hate_list.h
lua_inventory.h
lua_item.h
lua_iteminst.h
lua_mob.h
lua_mod.h
lua_npc.h
lua_object.h
lua_packet.h
lua_parser.h
lua_parser_events.h
lua_ptr.h
lua_raid.h
lua_spawn.h
lua_spell.h
lua_stat_bonuses.h
map.h
masterentity.h
maxskill.h
message.h
merc.h
mob.h
mob_movement_manager.h
npc.h
npc_ai.h
npc_scale_manager.h
object.h
oriented_bounding_box.h
pathfinder_interface.h
pathfinder_nav_mesh.h
pathfinder_null.h
perlpacket.h
petitions.h
pets.h
position.h
qglobals.h
quest_interface.h
queryserv.h
quest_interface.h
questmgr.h
quest_parser_collection.h
raids.h
raycast_mesh.h
skills.h
shared_task_zone_messaging.h
spawn2.cpp
spawn2.h
spawngroup.h
string_ids.h
task_client_state.h
task_goal_list_manager.h
task_manager.h
task_proximity_manager.h
tasks.h
titles.h
trap.h
water_map.h
water_map_v1.h
water_map_v2.h
worldserver.h
xtargetautohaters.h
zone.h
zone_event_scheduler.h
zone_config.h
zonedb.h
zonedump.h
zone_reload.h
zone_store.h
aa.h
aa_ability.h
aggromanager.h
api_service.h
aura.h
basic_functions.h
beacon.h
bot.h
bot_command.h
bot_database.h
bot_structs.h
cheat_manager.h
client.h
client_packet.h
command.h
common.h
corpse.h
data_bucket.h
doors.h
dialogue_window.h
dynamic_zone.h
embparser.h
embperl.h
embxs.h
encounter.h
entity.h
errmsg.h
event_codes.h
expedition.h
expedition_database.h
expedition_request.h
fastmath.h
forage.h
global_loot_manager.h
gm_commands/door_manipulation.h
groups.h
guild_mgr.h
hate_list.h
heal_rotation.h
horse.h
lua_bot.h
lua_bit.h
lua_client.h
lua_corpse.h
lua_door.h
lua_encounter.h
lua_entity.h
lua_entity_list.h
lua_expedition.h
lua_general.h
lua_group.h
lua_hate_list.h
lua_inventory.h
lua_item.h
lua_iteminst.h
lua_mob.h
lua_mod.h
lua_npc.h
lua_object.h
lua_packet.h
lua_parser.h
lua_parser_events.h
lua_ptr.h
lua_raid.h
lua_spawn.h
lua_spell.h
lua_stat_bonuses.h
map.h
masterentity.h
maxskill.h
message.h
merc.h
mob.h
mob_movement_manager.h
npc.h
npc_ai.h
npc_scale_manager.h
object.h
oriented_bounding_box.h
pathfinder_interface.h
pathfinder_nav_mesh.h
pathfinder_null.h
perlpacket.h
petitions.h
pets.h
position.h
qglobals.h
quest_interface.h
queryserv.h
quest_interface.h
questmgr.h
quest_parser_collection.h
raids.h
raycast_mesh.h
skills.h
shared_task_zone_messaging.h
spawn2.cpp
spawn2.h
spawngroup.h
string_ids.h
task_client_state.h
task_goal_list_manager.h
task_manager.h
task_proximity_manager.h
tasks.h
titles.h
trap.h
water_map.h
water_map_v1.h
water_map_v2.h
worldserver.h
xtargetautohaters.h
zone.h
zone_event_scheduler.h
zone_config.h
zonedb.h
zonedump.h
zone_reload.h
zone_store.h
)
SET(gm_commands
gm_commands/acceptrules.cpp
gm_commands/advnpcspawn.cpp
gm_commands/aggro.cpp
gm_commands/aggrozone.cpp
gm_commands/ai.cpp
gm_commands/appearance.cpp
gm_commands/appearanceeffects.cpp
gm_commands/attack.cpp
gm_commands/augmentitem.cpp
gm_commands/ban.cpp
gm_commands/beard.cpp
gm_commands/beardcolor.cpp
gm_commands/bestz.cpp
gm_commands/bind.cpp
gm_commands/camerashake.cpp
gm_commands/castspell.cpp
gm_commands/chat.cpp
gm_commands/checklos.cpp
gm_commands/copycharacter.cpp
gm_commands/corpse.cpp
gm_commands/corpsefix.cpp
gm_commands/countitem.cpp
gm_commands/cvs.cpp
gm_commands/damage.cpp
gm_commands/databuckets.cpp
gm_commands/date.cpp
gm_commands/dbspawn2.cpp
gm_commands/delacct.cpp
gm_commands/deletegraveyard.cpp
gm_commands/delpetition.cpp
gm_commands/depop.cpp
gm_commands/depopzone.cpp
gm_commands/details.cpp
gm_commands/devtools.cpp
gm_commands/disablerecipe.cpp
gm_commands/disarmtrap.cpp
gm_commands/distance.cpp
gm_commands/doanim.cpp
gm_commands/door.cpp
gm_commands/dye.cpp
gm_commands/dz.cpp
gm_commands/dzkickplayers.cpp
gm_commands/editmassrespawn.cpp
gm_commands/emote.cpp
gm_commands/emotesearch.cpp
gm_commands/emoteview.cpp
gm_commands/enablerecipe.cpp
gm_commands/endurance.cpp
gm_commands/equipitem.cpp
gm_commands/face.cpp
gm_commands/faction.cpp
gm_commands/findclass.cpp
gm_commands/findfaction.cpp
gm_commands/findnpctype.cpp
gm_commands/findrace.cpp
gm_commands/findskill.cpp
gm_commands/findspell.cpp
gm_commands/findtask.cpp
gm_commands/findzone.cpp
gm_commands/fixmob.cpp
gm_commands/flag.cpp
gm_commands/flagedit.cpp
gm_commands/flags.cpp
gm_commands/flymode.cpp
gm_commands/fov.cpp
gm_commands/freeze.cpp
gm_commands/gassign.cpp
gm_commands/gearup.cpp
gm_commands/gender.cpp
gm_commands/getplayerburiedcorpsecount.cpp
gm_commands/getvariable.cpp
gm_commands/ginfo.cpp
gm_commands/giveitem.cpp
gm_commands/givemoney.cpp
gm_commands/globalview.cpp
gm_commands/gm.cpp
gm_commands/gmspeed.cpp
gm_commands/gmzone.cpp
gm_commands/goto.cpp
gm_commands/grid.cpp
gm_commands/guild.cpp
gm_commands/guildapprove.cpp
gm_commands/guildcreate.cpp
gm_commands/guildlist.cpp
gm_commands/hair.cpp
gm_commands/haircolor.cpp
gm_commands/haste.cpp
gm_commands/hatelist.cpp
gm_commands/heal.cpp
gm_commands/helm.cpp
gm_commands/heritage.cpp
gm_commands/heromodel.cpp
gm_commands/hideme.cpp
gm_commands/hp.cpp
gm_commands/incstat.cpp
gm_commands/instance.cpp
gm_commands/interrogateinv.cpp
gm_commands/interrupt.cpp
gm_commands/invsnapshot.cpp
gm_commands/invul.cpp
gm_commands/ipban.cpp
gm_commands/iplookup.cpp
gm_commands/iteminfo.cpp
gm_commands/itemsearch.cpp
gm_commands/kick.cpp
gm_commands/kill.cpp
gm_commands/killallnpcs.cpp
gm_commands/lastname.cpp
gm_commands/list.cpp
gm_commands/listpetition.cpp
gm_commands/loc.cpp
gm_commands/lock.cpp
gm_commands/logcommand.cpp
gm_commands/logs.cpp
gm_commands/makepet.cpp
gm_commands/mana.cpp
gm_commands/max_all_skills.cpp
gm_commands/memspell.cpp
gm_commands/merchantcloseshop.cpp
gm_commands/merchantopenshop.cpp
gm_commands/modifynpcstat.cpp
gm_commands/motd.cpp
gm_commands/movechar.cpp
gm_commands/movement.cpp
gm_commands/myskills.cpp
gm_commands/mysql.cpp
gm_commands/mystats.cpp
gm_commands/name.cpp
gm_commands/netstats.cpp
gm_commands/network.cpp
gm_commands/npccast.cpp
gm_commands/npcedit.cpp
gm_commands/npceditmass.cpp
gm_commands/npcemote.cpp
gm_commands/npcloot.cpp
gm_commands/npcsay.cpp
gm_commands/npcshout.cpp
gm_commands/npcspawn.cpp
gm_commands/npcspecialattk.cpp
gm_commands/npcstats.cpp
gm_commands/npctype_cache.cpp
gm_commands/npctypespawn.cpp
gm_commands/nudge.cpp
gm_commands/nukebuffs.cpp
gm_commands/nukeitem.cpp
gm_commands/object.cpp
gm_commands/oocmute.cpp
gm_commands/opcode.cpp
gm_commands/path.cpp
gm_commands/peekinv.cpp
gm_commands/peqzone.cpp
gm_commands/permaclass.cpp
gm_commands/permagender.cpp
gm_commands/permarace.cpp
gm_commands/petitems.cpp
gm_commands/petitioninfo.cpp
gm_commands/petname.cpp
gm_commands/pf.cpp
gm_commands/picklock.cpp
gm_commands/profanity.cpp
gm_commands/proximity.cpp
gm_commands/push.cpp
gm_commands/pvp.cpp
gm_commands/qglobal.cpp
gm_commands/questerrors.cpp
gm_commands/race.cpp
gm_commands/raidloot.cpp
gm_commands/randomfeatures.cpp
gm_commands/refreshgroup.cpp
gm_commands/reloadaa.cpp
gm_commands/reloadallrules.cpp
gm_commands/reloadcontentflags.cpp
gm_commands/reloademote.cpp
gm_commands/reloadlevelmods.cpp
gm_commands/reloadmerchants.cpp
gm_commands/reloadperlexportsettings.cpp
gm_commands/reloadqst.cpp
gm_commands/reloadstatic.cpp
gm_commands/reloadtitles.cpp
gm_commands/reloadtraps.cpp
gm_commands/reloadworld.cpp
gm_commands/reloadworldrules.cpp
gm_commands/reloadzps.cpp
gm_commands/removeitem.cpp
gm_commands/repop.cpp
gm_commands/resetaa.cpp
gm_commands/resetaa_timer.cpp
gm_commands/resetdisc_timer.cpp
gm_commands/revoke.cpp
gm_commands/roambox.cpp
gm_commands/rules.cpp
gm_commands/save.cpp
gm_commands/scale.cpp
gm_commands/scribespell.cpp
gm_commands/scribespells.cpp
gm_commands/sendzonespawns.cpp
gm_commands/sensetrap.cpp
gm_commands/serverinfo.cpp
gm_commands/serverrules.cpp
gm_commands/set_adventure_points.cpp
gm_commands/setaapts.cpp
gm_commands/setaaxp.cpp
gm_commands/setaltcurrency.cpp
gm_commands/setanim.cpp
gm_commands/setcrystals.cpp
gm_commands/setendurance.cpp
gm_commands/setfaction.cpp
gm_commands/setgraveyard.cpp
gm_commands/sethp.cpp
gm_commands/setlanguage.cpp
gm_commands/setlsinfo.cpp
gm_commands/setmana.cpp
gm_commands/setpass.cpp
gm_commands/setpvppoints.cpp
gm_commands/setskill.cpp
gm_commands/setskillall.cpp
gm_commands/setstartzone.cpp
gm_commands/setstat.cpp
gm_commands/setxp.cpp
gm_commands/showbonusstats.cpp
gm_commands/showbuffs.cpp
gm_commands/shownpcgloballoot.cpp
gm_commands/shownumhits.cpp
gm_commands/showskills.cpp
gm_commands/showspellslist.cpp
gm_commands/showstats.cpp
gm_commands/showzonegloballoot.cpp
gm_commands/showzonepoints.cpp
gm_commands/shutdown.cpp
gm_commands/size.cpp
gm_commands/spawn.cpp
gm_commands/spawnfix.cpp
gm_commands/spawnstatus.cpp
gm_commands/spellinfo.cpp
gm_commands/stun.cpp
gm_commands/summon.cpp
gm_commands/summonburiedplayercorpse.cpp
gm_commands/summonitem.cpp
gm_commands/suspend.cpp
gm_commands/task.cpp
gm_commands/tattoo.cpp
gm_commands/tempname.cpp
gm_commands/texture.cpp
gm_commands/time.cpp
gm_commands/timers.cpp
gm_commands/timezone.cpp
gm_commands/title.cpp
gm_commands/titlesuffix.cpp
gm_commands/traindisc.cpp
gm_commands/trapinfo.cpp
gm_commands/tune.cpp
gm_commands/ucs.cpp
gm_commands/undye.cpp
gm_commands/undyeme.cpp
gm_commands/unfreeze.cpp
gm_commands/unlock.cpp
gm_commands/unmemspell.cpp
gm_commands/unmemspells.cpp
gm_commands/unscribespell.cpp
gm_commands/unscribespells.cpp
gm_commands/untraindisc.cpp
gm_commands/untraindiscs.cpp
gm_commands/uptime.cpp
gm_commands/version.cpp
gm_commands/viewcurrencies.cpp
gm_commands/viewnpctype.cpp
gm_commands/viewpetition.cpp
gm_commands/viewzoneloot.cpp
gm_commands/wc.cpp
gm_commands/weather.cpp
gm_commands/who.cpp
gm_commands/worldshutdown.cpp
gm_commands/worldwide.cpp
gm_commands/wp.cpp
gm_commands/wpadd.cpp
gm_commands/wpinfo.cpp
gm_commands/xtargets.cpp
gm_commands/zclip.cpp
gm_commands/zcolor.cpp
gm_commands/zheader.cpp
gm_commands/zonebootup.cpp
gm_commands/zonelock.cpp
gm_commands/zoneshutdown.cpp
gm_commands/zonestatus.cpp
gm_commands/zopp.cpp
gm_commands/zsafecoords.cpp
gm_commands/zsave.cpp
gm_commands/zsky.cpp
gm_commands/zstats.cpp
gm_commands/zunderworld.cpp
)
ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers})
ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers} ${gm_commands})
INSTALL(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
+256 -168
View File
@@ -151,10 +151,14 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
//give the pets somebody to "love"
if (targ != nullptr) {
swarm_pet_npc->AddToHateList(targ, 1000, 1000);
if (RuleB(Spells, SwarmPetTargetLock) || sticktarg)
if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) {
swarm_pet_npc->GetSwarmInfo()->target = targ->GetID();
else
swarm_pet_npc->SetPetTargetLockID(targ->GetID());
swarm_pet_npc->SetSpecialAbility(IMMUNE_AGGRO, 1);
}
else {
swarm_pet_npc->GetSwarmInfo()->target = 0;
}
}
//we allocated a new NPC type object, give the NPC ownership of that memory
@@ -213,7 +217,7 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
glm::vec2(5, 5), glm::vec2(-5, 5), glm::vec2(5, -5), glm::vec2(-5, -5),
glm::vec2(10, 10), glm::vec2(-10, 10), glm::vec2(10, -10), glm::vec2(-10, -10),
glm::vec2(8, 8), glm::vec2(-8, 8), glm::vec2(8, -8), glm::vec2(-8, -8)
};;
};
while(summon_count > 0) {
int pet_duration = pet.duration;
@@ -255,10 +259,14 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
if(targ != nullptr){
swarm_pet_npc->AddToHateList(targ, 1000, 1000);
if (RuleB(Spells, SwarmPetTargetLock) || sticktarg)
if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) {
swarm_pet_npc->GetSwarmInfo()->target = targ->GetID();
else
swarm_pet_npc->SetPetTargetLockID(targ->GetID());
swarm_pet_npc->SetSpecialAbility(IMMUNE_AGGRO, 1);
}
else {
swarm_pet_npc->GetSwarmInfo()->target = 0;
}
}
//we allocated a new NPC type object, give the NPC ownership of that memory
@@ -273,63 +281,94 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
delete made_npc;
}
void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
{
Corpse *CorpseToUse = nullptr;
CorpseToUse = entity_list.GetClosestCorpse(this, nullptr);
void Mob::WakeTheDead(uint16 spell_id, Corpse *corpse_to_use, Mob *target, uint32 duration) {
if(!CorpseToUse)
/*
SPA 299 Wake The Dead, 'animateDead' should be temp pet, always spawns 1 pet from corpse, max value is duration
SPA 306 Wake The Dead, 'animateDead#' should be temp pet, base is amount of pets from indivual corpses, max value is duration
Max range for closet corpse is 250 units.
TODO: Should use temp pets
*/
if (!corpse_to_use) {
return;
}
//assuming we have pets in our table; we take the first pet as a base type.
const NPCType *base_type = content_db.LoadNPCTypesData(500);
auto make_npc = new NPCType;
memcpy(make_npc, base_type, sizeof(NPCType));
/* TODO: Does WTD use pet focus?
int act_power = 0;
//combat stats
make_npc->AC = ((GetLevel() * 7) + 550);
make_npc->ATK = GetLevel();
make_npc->max_dmg = (GetLevel() * 4) + 2;
make_npc->min_dmg = 1;
if (IsClient()) {
act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);
act_power = CastToClient()->mod_pet_power(act_power, spell_id);
}
*/
//base stats
make_npc->current_hp = (GetLevel() * 55);
make_npc->max_hp = (GetLevel() * 55);
make_npc->STR = 85 + (GetLevel() * 3);
make_npc->STA = 85 + (GetLevel() * 3);
make_npc->DEX = 85 + (GetLevel() * 3);
make_npc->AGI = 85 + (GetLevel() * 3);
make_npc->INT = 85 + (GetLevel() * 3);
make_npc->WIS = 85 + (GetLevel() * 3);
make_npc->CHA = 85 + (GetLevel() * 3);
make_npc->MR = 25;
make_npc->FR = 25;
make_npc->CR = 25;
make_npc->DR = 25;
make_npc->PR = 25;
SwarmPet_Struct pet;
pet.count = 1;
pet.duration = 1;
//pet.duration += GetFocusEffect(focusSwarmPetDuration, spell_id) / 1000; //TODO: Does WTD use pet focus?
pet.npc_id = WAKE_THE_DEAD_NPCTYPEID;
NPCType *made_npc = nullptr;
const NPCType *npc_type = content_db.LoadNPCTypesData(WAKE_THE_DEAD_NPCTYPEID);
if (npc_type == nullptr) {
//log write
LogError("Unknown npc type for 'Wake the Dead' swarm pet spell id: [{}]", spell_id);
Message(0, "Unable to find pet!");
return;
}
made_npc = new NPCType;
memcpy(made_npc, npc_type, sizeof(NPCType));
//level class and gender
make_npc->level = GetLevel();
make_npc->class_ = CorpseToUse->class_;
make_npc->race = CorpseToUse->race;
make_npc->gender = CorpseToUse->gender;
make_npc->loottable_id = 0;
//name
char NewName[64];
sprintf(NewName, "%s`s Animated Corpse", GetCleanName());
strcpy(make_npc->name, NewName);
strcpy(made_npc->name, NewName);
npc_type = made_npc;
//combat stats
made_npc->AC = ((GetLevel() * 7) + 550);
made_npc->ATK = GetLevel();
made_npc->max_dmg = (GetLevel() * 4) + 2;
made_npc->min_dmg = 1;
//base stats
made_npc->current_hp = (GetLevel() * 55);
made_npc->max_hp = (GetLevel() * 55);
made_npc->STR = 85 + (GetLevel() * 3);
made_npc->STA = 85 + (GetLevel() * 3);
made_npc->DEX = 85 + (GetLevel() * 3);
made_npc->AGI = 85 + (GetLevel() * 3);
made_npc->INT = 85 + (GetLevel() * 3);
made_npc->WIS = 85 + (GetLevel() * 3);
made_npc->CHA = 85 + (GetLevel() * 3);
made_npc->MR = 25;
made_npc->FR = 25;
made_npc->CR = 25;
made_npc->DR = 25;
made_npc->PR = 25;
//level class and gender
made_npc->level = GetLevel();
made_npc->class_ = corpse_to_use->class_;
made_npc->race = corpse_to_use->race;
made_npc->gender = corpse_to_use->gender;
made_npc->loottable_id = 0;
//appearance
make_npc->beard = CorpseToUse->beard;
make_npc->beardcolor = CorpseToUse->beardcolor;
make_npc->eyecolor1 = CorpseToUse->eyecolor1;
make_npc->eyecolor2 = CorpseToUse->eyecolor2;
make_npc->haircolor = CorpseToUse->haircolor;
make_npc->hairstyle = CorpseToUse->hairstyle;
make_npc->helmtexture = CorpseToUse->helmtexture;
make_npc->luclinface = CorpseToUse->luclinface;
make_npc->size = CorpseToUse->size;
make_npc->texture = CorpseToUse->texture;
made_npc->beard = corpse_to_use->beard;
made_npc->beardcolor = corpse_to_use->beardcolor;
made_npc->eyecolor1 = corpse_to_use->eyecolor1;
made_npc->eyecolor2 = corpse_to_use->eyecolor2;
made_npc->haircolor = corpse_to_use->haircolor;
made_npc->hairstyle = corpse_to_use->hairstyle;
made_npc->helmtexture = corpse_to_use->helmtexture;
made_npc->luclinface = corpse_to_use->luclinface;
made_npc->size = corpse_to_use->size;
made_npc->texture = corpse_to_use->texture;
//cast stuff.. based off of PEQ's if you want to change
//it you'll have to mod this code, but most likely
@@ -337,130 +376,144 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
//part of their spell list; can't think of any smooth
//way to do this
//some basic combat mods here too since it's convienent
switch(CorpseToUse->class_)
switch (corpse_to_use->class_)
{
case CLERIC:
make_npc->npc_spells_id = 1;
made_npc->npc_spells_id = 1;
break;
case WIZARD:
make_npc->npc_spells_id = 2;
made_npc->npc_spells_id = 2;
break;
case NECROMANCER:
make_npc->npc_spells_id = 3;
made_npc->npc_spells_id = 3;
break;
case MAGICIAN:
make_npc->npc_spells_id = 4;
made_npc->npc_spells_id = 4;
break;
case ENCHANTER:
make_npc->npc_spells_id = 5;
made_npc->npc_spells_id = 5;
break;
case SHAMAN:
make_npc->npc_spells_id = 6;
made_npc->npc_spells_id = 6;
break;
case DRUID:
make_npc->npc_spells_id = 7;
made_npc->npc_spells_id = 7;
break;
case PALADIN:
//SPECATK_TRIPLE
strcpy(make_npc->special_abilities, "6,1");
make_npc->current_hp = make_npc->current_hp * 150 / 100;
make_npc->max_hp = make_npc->max_hp * 150 / 100;
make_npc->npc_spells_id = 8;
strcpy(made_npc->special_abilities, "6,1");
made_npc->current_hp = made_npc->current_hp * 150 / 100;
made_npc->max_hp = made_npc->max_hp * 150 / 100;
made_npc->npc_spells_id = 8;
break;
case SHADOWKNIGHT:
strcpy(make_npc->special_abilities, "6,1");
make_npc->current_hp = make_npc->current_hp * 150 / 100;
make_npc->max_hp = make_npc->max_hp * 150 / 100;
make_npc->npc_spells_id = 9;
strcpy(made_npc->special_abilities, "6,1");
made_npc->current_hp = made_npc->current_hp * 150 / 100;
made_npc->max_hp = made_npc->max_hp * 150 / 100;
made_npc->npc_spells_id = 9;
break;
case RANGER:
strcpy(make_npc->special_abilities, "7,1");
make_npc->current_hp = make_npc->current_hp * 135 / 100;
make_npc->max_hp = make_npc->max_hp * 135 / 100;
make_npc->npc_spells_id = 10;
strcpy(made_npc->special_abilities, "7,1");
made_npc->current_hp = made_npc->current_hp * 135 / 100;
made_npc->max_hp = made_npc->max_hp * 135 / 100;
made_npc->npc_spells_id = 10;
break;
case BARD:
strcpy(make_npc->special_abilities, "6,1");
make_npc->current_hp = make_npc->current_hp * 110 / 100;
make_npc->max_hp = make_npc->max_hp * 110 / 100;
make_npc->npc_spells_id = 11;
strcpy(made_npc->special_abilities, "6,1");
made_npc->current_hp = made_npc->current_hp * 110 / 100;
made_npc->max_hp = made_npc->max_hp * 110 / 100;
made_npc->npc_spells_id = 11;
break;
case BEASTLORD:
strcpy(make_npc->special_abilities, "7,1");
make_npc->current_hp = make_npc->current_hp * 110 / 100;
make_npc->max_hp = make_npc->max_hp * 110 / 100;
make_npc->npc_spells_id = 12;
strcpy(made_npc->special_abilities, "7,1");
made_npc->current_hp = made_npc->current_hp * 110 / 100;
made_npc->max_hp = made_npc->max_hp * 110 / 100;
made_npc->npc_spells_id = 12;
break;
case ROGUE:
strcpy(make_npc->special_abilities, "7,1");
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
make_npc->current_hp = make_npc->current_hp * 110 / 100;
make_npc->max_hp = make_npc->max_hp * 110 / 100;
strcpy(made_npc->special_abilities, "7,1");
made_npc->max_dmg = made_npc->max_dmg * 150 / 100;
made_npc->current_hp = made_npc->current_hp * 110 / 100;
made_npc->max_hp = made_npc->max_hp * 110 / 100;
break;
case MONK:
strcpy(make_npc->special_abilities, "7,1");
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
make_npc->current_hp = make_npc->current_hp * 135 / 100;
make_npc->max_hp = make_npc->max_hp * 135 / 100;
strcpy(made_npc->special_abilities, "7,1");
made_npc->max_dmg = made_npc->max_dmg * 150 / 100;
made_npc->current_hp = made_npc->current_hp * 135 / 100;
made_npc->max_hp = made_npc->max_hp * 135 / 100;
break;
case WARRIOR:
case BERSERKER:
strcpy(make_npc->special_abilities, "7,1");
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
make_npc->current_hp = make_npc->current_hp * 175 / 100;
make_npc->max_hp = make_npc->max_hp * 175 / 100;
strcpy(made_npc->special_abilities, "7,1");
made_npc->max_dmg = made_npc->max_dmg * 150 / 100;
made_npc->current_hp = made_npc->current_hp * 175 / 100;
made_npc->max_hp = made_npc->max_hp * 175 / 100;
break;
default:
make_npc->npc_spells_id = 0;
made_npc->npc_spells_id = 0;
break;
}
make_npc->loottable_id = 0;
make_npc->merchanttype = 0;
make_npc->d_melee_texture1 = 0;
make_npc->d_melee_texture2 = 0;
made_npc->loottable_id = 0;
made_npc->merchanttype = 0;
made_npc->d_melee_texture1 = 0;
made_npc->d_melee_texture2 = 0;
auto npca = new NPC(make_npc, 0, GetPosition(), GravityBehavior::Water);
if(!npca->GetSwarmInfo()){
auto nSI = new SwarmPet;
npca->SetSwarmInfo(nSI);
npca->GetSwarmInfo()->duration = new Timer(duration*1000);
}
else{
npca->GetSwarmInfo()->duration->Start(duration*1000);
}
int summon_count = 0;
summon_count = pet.count;
npca->StartSwarmTimer(duration * 1000);
npca->GetSwarmInfo()->owner_id = GetID();
NPC* swarm_pet_npc = nullptr;
//TODO: potenitally add support for multiple pets per corpse
while (summon_count > 0) {
int pet_duration = duration;
//give the pet somebody to "love"
if(target != nullptr){
npca->AddToHateList(target, 100000);
npca->GetSwarmInfo()->target = target->GetID();
}
//gear stuff, need to make sure there's
//no situation where this stuff can be duped
for (int x = EQ::invslot::EQUIPMENT_BEGIN; x <= EQ::invslot::EQUIPMENT_END; x++)
{
uint32 sitem = 0;
sitem = CorpseToUse->GetWornItem(x);
if(sitem){
const EQ::ItemData * itm = database.GetItem(sitem);
npca->AddLootDrop(itm, &npca->itemlist, NPC::NewLootDropEntry(), true);
NPCType *npc_dup = nullptr;
if (made_npc != nullptr) {
npc_dup = new NPCType;
memcpy(npc_dup, made_npc, sizeof(NPCType));
}
swarm_pet_npc = new NPC(
(npc_dup != nullptr) ? npc_dup : npc_type,
0, corpse_to_use->GetPosition(),GravityBehavior::Water);
swarm_pet_npc->SetFollowID(GetID());
if (!swarm_pet_npc->GetSwarmInfo()) {
auto nSI = new SwarmPet;
swarm_pet_npc->SetSwarmInfo(nSI);
swarm_pet_npc->GetSwarmInfo()->duration = new Timer(pet_duration * 1000);
}
else {
swarm_pet_npc->GetSwarmInfo()->duration->Start(pet_duration * 1000);
}
swarm_pet_npc->StartSwarmTimer(pet_duration * 1000);
//removing this prevents the pet from attacking
swarm_pet_npc->GetSwarmInfo()->owner_id = GetID();
//give the pets somebody to "love"
if (target != nullptr) {
swarm_pet_npc->AddToHateList(target, 10000, 1000);
swarm_pet_npc->GetSwarmInfo()->target = 0;
}
//we allocated a new NPC type object, give the NPC ownership of that memory
if (npc_dup != nullptr)
swarm_pet_npc->GiveNPCTypeData(npc_dup);
entity_list.AddNPC(swarm_pet_npc, true, true);
summon_count--;
}
//we allocated a new NPC type object, give the NPC ownership of that memory
if(make_npc != nullptr)
npca->GiveNPCTypeData(make_npc);
entity_list.AddNPC(npca, true, true);
//the target of these swarm pets will take offense to being cast on...
if(target != nullptr)
if (target != nullptr)
target->AddToHateList(this, 1, 0);
// The other pointers we make are handled elsewhere.
delete made_npc;
}
void Client::ResetAA() {
@@ -499,9 +552,19 @@ void Client::ResetAA() {
void Client::SendClearAA()
{
auto outapp = new EQApplicationPacket(OP_ClearLeadershipAbilities, 0);
SendClearLeadershipAA();
SendClearPlayerAA();
}
void Client::SendClearPlayerAA()
{
auto outapp = new EQApplicationPacket(OP_ClearAA, 0);
FastQueuePacket(&outapp);
outapp = new EQApplicationPacket(OP_ClearAA, 0);
}
void Client::SendClearLeadershipAA()
{
auto outapp = new EQApplicationPacket(OP_ClearLeadershipAbilities, 0);
FastQueuePacket(&outapp);
}
@@ -1164,65 +1227,65 @@ void Client::IncrementAlternateAdvancementRank(int rank_id) {
void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id);
if(!rank) {
if (!rank) {
return;
}
AA::Ability *ability = rank->base_ability;
if(!ability) {
if (!ability) {
return;
}
if(!IsValidSpell(rank->spell)) {
if (!IsValidSpell(rank->spell)) {
return;
}
//do not allow AA to cast if your actively casting another AA.
if (rank->spell == casting_spell_id && rank->id == casting_spell_aa_id) {
return;
}
if(!CanUseAlternateAdvancementRank(rank)) {
if (!CanUseAlternateAdvancementRank(rank)) {
return;
}
bool use_toggle_passive_hotkey = UseTogglePassiveHotkey(*rank);
//make sure it is not a passive
if(!rank->effects.empty() && !use_toggle_passive_hotkey) {
if (!rank->effects.empty() && !use_toggle_passive_hotkey) {
return;
}
uint32 charges = 0;
// We don't have the AA
if (!GetAA(rank_id, &charges))
if (!GetAA(rank_id, &charges)) {
return;
}
//if expendable make sure we have charges
if(ability->charges > 0 && charges < 1)
if (ability->charges > 0 && charges < 1) {
return;
}
//check cooldown
if(!p_timers.Expired(&database, rank->spell_type + pTimerAAStart, false)) {
if (!p_timers.Expired(&database, rank->spell_type + pTimerAAStart, false)) {
uint32 aaremain = p_timers.GetRemainingTime(rank->spell_type + pTimerAAStart);
uint32 aaremain_hr = aaremain / (60 * 60);
uint32 aaremain_min = (aaremain / 60) % 60;
uint32 aaremain_sec = aaremain % 60;
if(aaremain_hr >= 1) {
if (aaremain_hr >= 1) {
Message(Chat::Red, "You can use this ability again in %u hour(s) %u minute(s) %u seconds",
aaremain_hr, aaremain_min, aaremain_sec);
aaremain_hr, aaremain_min, aaremain_sec);
}
else {
Message(Chat::Red, "You can use this ability again in %u minute(s) %u seconds",
aaremain_min, aaremain_sec);
aaremain_min, aaremain_sec);
}
return;
}
//calculate cooldown
int cooldown = rank->recast_time - GetAlternateAdvancementCooldownReduction(rank);
if(cooldown < 0) {
cooldown = 0;
}
if (!IsCastWhileInvis(rank->spell))
if (!IsCastWhileInvis(rank->spell)) {
CommonBreakInvisible();
}
if (spells[rank->spell].sneak && (!hidden || (hidden && (Timer::GetCurrentTime() - tmHidden) < 4000))) {
MessageString(Chat::SpellFailure, SNEAK_RESTRICT);
@@ -1230,13 +1293,15 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
}
//
// Modern clients don't require pet targeted for AA casts that are ST_Pet
if (spells[rank->spell].target_type == ST_Pet || spells[rank->spell].target_type == ST_SummonedPet)
if (spells[rank->spell].target_type == ST_Pet || spells[rank->spell].target_type == ST_SummonedPet) {
target_id = GetPetID();
}
// extra handling for cast_not_standing spells
if (!spells[rank->spell].cast_not_standing) {
if (GetAppearance() == eaSitting) // we need to stand!
if (!IgnoreCastingRestriction(rank->spell)) {
if (GetAppearance() == eaSitting) { // we need to stand!
SetAppearance(eaStanding, false);
}
if (GetAppearance() != eaStanding) {
MessageString(Chat::SpellFailure, STAND_TO_CAST);
@@ -1248,22 +1313,36 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
TogglePassiveAlternativeAdvancement(*rank, ability->id);
}
else {
// Bards can cast instant cast AAs while they are casting another song
if (spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
if (!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQ::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].resist_difficulty, false)) {
// Bards can cast instant cast AAs while they are casting or channeling item cast.
if (GetClass() == BARD && IsCasting() && spells[rank->spell].cast_time == 0) {
if (!DoCastingChecksOnCaster(rank->spell)) {
return;
}
ExpendAlternateAdvancementCharge(ability->id);
SpellFinished(rank->spell, entity_list.GetMob(target_id), EQ::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].resist_difficulty, false, -1, false, rank->id);
}
//Known issue: If you attempt to give a Bard an AA with a cast time, the cast timer will not display on the client (no live bard AA have cast time).
else {
if (!CastSpell(rank->spell, target_id, EQ::spells::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
return;
}
CastSpell(rank->spell, target_id, EQ::spells::CastingSlot::AltAbility, -1, -1, 0, -1, 0xFFFFFFFF, 0, nullptr, rank->id);
}
}
}
CastToClient()->GetPTimers().Start(rank->spell_type + pTimerAAStart, cooldown);
SendAlternateAdvancementTimer(rank->spell_type, 0, 0);
void Client::SetAARecastTimer(AA::Rank *rank_in, int32 spell_id) {
if (!rank_in) {
return;
}
//calculate AA cooldown
int timer_duration = rank_in->recast_time - GetAlternateAdvancementCooldownReduction(rank_in);
if (timer_duration <= 0) {
return;
}
CastToClient()->GetPTimers().Start(rank_in->spell_type + pTimerAAStart, timer_duration);
CastToClient()->SendAlternateAdvancementTimer(rank_in->spell_type, 0, 0);
LogSpells("Spell [{}]: Setting AA reuse timer [{}] to [{}]", spell_id, rank_in->spell_type + pTimerAAStart, timer_duration);
}
int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) {
@@ -1276,6 +1355,7 @@ int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) {
return 0;
}
int total_reduction = 0;
for(auto &aa : aa_ranks) {
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
auto ability = ability_rank.first;
@@ -1287,15 +1367,16 @@ int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) {
for(auto &effect : rank->effects) {
if(effect.effect_id == SE_HastenedAASkill && effect.limit_value == ability_in->id) {
return effect.base_value;
total_reduction += effect.base_value;
}
}
}
return 0;
return total_reduction;
}
void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) {
for (auto &iter : aa_ranks) {
AA::Ability *ability = zone->GetAlternateAdvancementAbility(iter.first);
if (ability && aa_id == ability->id) {
@@ -1700,11 +1781,18 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_map<int, std
}
LogInfo("Loaded [{}] Alternate Advancement Abilities", (int)abilities.size());
int expansion = RuleI(Expansion, CurrentExpansion);
bool use_expansion_aa = RuleB(Expansion, UseCurrentExpansionAAOnly);
LogInfo("Loading Alternate Advancement Ability Ranks");
ranks.clear();
query = "SELECT id, upper_hotkey_sid, lower_hotkey_sid, title_sid, desc_sid, cost, level_req, spell, spell_type, recast_time, "
if (use_expansion_aa && expansion >= 0) {
query = fmt::format("SELECT id, upper_hotkey_sid, lower_hotkey_sid, title_sid, desc_sid, cost, level_req, spell, spell_type, recast_time, "
"next_id, expansion FROM aa_ranks WHERE expansion <= {}", expansion);
} else {
query = "SELECT id, upper_hotkey_sid, lower_hotkey_sid, title_sid, desc_sid, cost, level_req, spell, spell_type, recast_time, "
"next_id, expansion FROM aa_ranks";
}
results = QueryDatabase(query);
if(results.Success()) {
for(auto row = results.begin(); row != results.end(); ++row) {
+1
View File
@@ -2,6 +2,7 @@
#define AA_H
#define MAX_SWARM_PETS 12 //this can change as long as you make more coords (swarm_pet_x/swarm_pet_y)
#define WAKE_THE_DEAD_NPCTYPEID 500 //We use first pet in pets table as a template
typedef enum {
aaActionNone = 0,
+437 -231
View File
@@ -38,190 +38,359 @@ extern Zone* zone;
//#define LOSDEBUG 6
void EntityList::DescribeAggro(Client *towho, NPC *from_who, float d, bool verbose) {
float d2 = d*d;
float distance_squared = (d * d);
towho->Message(Chat::White, "Describing aggro for %s", from_who->GetName());
towho->Message(
Chat::White,
fmt::format(
"Describing aggro for {} ({}).",
from_who->GetCleanName(),
from_who->GetID()
).c_str()
);
bool engaged = from_who->IsEngaged();
if(engaged) {
bool is_engaged = from_who->IsEngaged();
bool will_aggro_npcs = from_who->WillAggroNPCs();
if (is_engaged) {
Mob *top = from_who->GetHateTop();
towho->Message(Chat::White, ".. I am currently fighting with %s", top == nullptr?"(nullptr)":top->GetName());
towho->Message(
Chat::White,
fmt::format(
"I am currently engaged with {}.",
(
!top ?
"nothing" :
fmt::format(
"{} ({})",
top->GetCleanName(),
top->GetID()
)
)
).c_str()
);
}
bool check_npcs = from_who->WillAggroNPCs();
if(verbose) {
char namebuf[256];
int my_primary = from_who->GetPrimaryFaction();
Mob *own = from_who->GetOwner();
if(own != nullptr)
my_primary = own->GetPrimaryFaction();
if(my_primary == 0) {
strcpy(namebuf, "(No faction)");
} else if(my_primary < 0) {
strcpy(namebuf, "(Special faction)");
} else {
if(!content_db.GetFactionName(my_primary, namebuf, sizeof(namebuf)))
strcpy(namebuf, "(Unknown)");
if (verbose) {
int faction_id = from_who->GetPrimaryFaction();
Mob *owner = from_who->GetOwner();
if(owner) {
faction_id = owner->GetPrimaryFaction();
}
towho->Message(Chat::White, ".. I am on faction %s (%d)\n", namebuf, my_primary);
std::string faction_name = (
faction_id > 0 ?
content_db.GetFactionName(faction_id) :
(
faction_id == 0 ?
"None" :
fmt::format(
"Special Faction {}",
faction_id
)
)
);
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is on Faction {} ({}).",
from_who->GetCleanName(),
from_who->GetID(),
faction_name,
faction_id
).c_str()
);
}
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
Mob *mob = it->second;
if (mob->IsClient()) //also ensures that mob != around
for (const auto& npc_entity : entity_list.GetNPCList()) {
auto entity_id = npc_entity.first;
auto npc = npc_entity.second;
if (npc == from_who) {
continue;
}
if (DistanceSquared(mob->GetPosition(), from_who->GetPosition()) > d2)
if (DistanceSquared(npc->GetPosition(), from_who->GetPosition()) > distance_squared) {
continue;
}
if (engaged) {
uint32 amm = from_who->GetHateAmount(mob);
if (amm == 0)
towho->Message(Chat::White, "... %s is not on my hate list.", mob->GetName());
else
towho->Message(Chat::White, "... %s is on my hate list with value %lu", mob->GetName(), (unsigned long)amm);
} else if (!check_npcs && mob->IsNPC()) {
towho->Message(Chat::White, "... %s is an NPC and my npc_aggro is disabled.", mob->GetName());
if (is_engaged) {
uint32 hate_amount = from_who->GetHateAmount(npc);
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is {}on my hate list{}.",
npc->GetCleanName(),
npc->GetID(),
!hate_amount ? "not " : "",
(
!hate_amount ?
"" :
fmt::format(
" with a hate amount of {}.",
hate_amount
)
)
).c_str()
);
} else if (!will_aggro_npcs) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is an NPC and I cannot aggro NPCs.",
npc->GetCleanName(),
npc->GetID()
).c_str()
);
} else {
from_who->DescribeAggro(towho, mob, verbose);
from_who->DescribeAggro(towho, npc, verbose);
}
}
}
void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
//this logic is duplicated from below, try to keep it up to date.
float iAggroRange = GetAggroRange();
float t1, t2, t3;
t1 = std::abs(mob->GetX() - GetX());
t2 = std::abs(mob->GetY() - GetY());
t3 = std::abs(mob->GetZ() - GetZ());
if(( t1 > iAggroRange)
|| ( t2 > iAggroRange)
|| ( t3 > iAggroRange) ) {
towho->Message(Chat::White, "...%s is out of range (fast). distances (%.3f,%.3f,%.3f), range %.3f", mob->GetName(),
t1, t2, t3, iAggroRange);
float aggro_range = GetAggroRange();
float x_range = std::abs(mob->GetX() - GetX());
float y_range = std::abs(mob->GetY() - GetY());
float z_range = std::abs(mob->GetZ() - GetZ());
if (
x_range > aggro_range ||
y_range > aggro_range ||
z_range > aggro_range
) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is out of range. X Range: {} Y Range: {} Z Range: {} Aggro Range: {}",
mob->GetCleanName(),
mob->GetID(),
x_range,
y_range,
z_range,
aggro_range
).c_str()
);
return;
}
if(mob->IsInvisible(this)) {
towho->Message(Chat::White, "...%s is invisible to me. ", mob->GetName());
if (mob->IsInvisible(this)) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is invisible to me. ",
mob->GetCleanName(),
mob->GetID()
).c_str()
);
return;
}
if((mob->IsClient() &&
(!mob->CastToClient()->Connected()
|| mob->CastToClient()->IsLD()
|| mob->CastToClient()->IsBecomeNPC()
|| mob->CastToClient()->GetGM()
if (
mob->IsClient() &&
(
!mob->CastToClient()->Connected() ||
mob->CastToClient()->IsLD() ||
mob->CastToClient()->IsBecomeNPC() ||
mob->CastToClient()->GetGM()
)
))
{
towho->Message(Chat::White, "...%s is my owner. ", mob->GetName());
) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is a GM or is not connected. ",
mob->GetCleanName(),
mob->GetID()
).c_str()
);
return;
}
if(mob == GetOwner()) {
towho->Message(Chat::White, "...%s a GM or is not connected. ", mob->GetName());
if (mob == GetOwner()) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is my owner. ",
mob->GetCleanName(),
mob->GetID()
).c_str()
);
return;
}
float dist2 = DistanceSquared(mob->GetPosition(), m_Position);
float iAggroRange2 = iAggroRange*iAggroRange;
if( dist2 > iAggroRange2 ) {
towho->Message(Chat::White, "...%s is out of range. %.3f > %.3f ", mob->GetName(),
dist2, iAggroRange2);
float distance_squared = DistanceSquared(mob->GetPosition(), m_Position);
float aggro_range_squared = (aggro_range * aggro_range);
if (distance_squared > aggro_range_squared) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is out of range. Distance: {:.2f} Aggro Range: {:.2f}",
mob->GetCleanName(),
mob->GetID(),
distance_squared,
aggro_range_squared
).c_str()
);
return;
}
if (RuleB(Aggro, UseLevelAggro))
{
if (GetLevel() < RuleI(Aggro, MinAggroLevel) && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3 && !AlwaysAggro())
{
towho->Message(Chat::White, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2);
if (RuleB(Aggro, UseLevelAggro)) {
if (
GetLevel() < RuleI(Aggro, MinAggroLevel) &&
mob->GetLevelCon(GetLevel()) == CON_GRAY &&
GetBodyType() != BT_Undead &&
!AlwaysAggro()
) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) considers Red to me.",
mob->GetCleanName(),
mob->GetID()
).c_str()
);
return;
}
}
else
{
if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GRAY && !AlwaysAggro()) {
towho->Message(Chat::White, "...%s is red to me (basically)", mob->GetName(),
dist2, iAggroRange2);
} else {
if (
GetINT() > RuleI(Aggro, IntAggroThreshold) &&
mob->GetLevelCon(GetLevel()) == CON_GRAY &&
!AlwaysAggro()
) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) considers Red to me.",
mob->GetCleanName(),
mob->GetID()
).c_str()
);
return;
}
}
if(verbose) {
int my_primary = GetPrimaryFaction();
int mob_primary = mob->GetPrimaryFaction();
Mob *own = GetOwner();
if(own != nullptr)
my_primary = own->GetPrimaryFaction();
own = mob->GetOwner();
if(mob_primary > 0 && own != nullptr)
mob_primary = own->GetPrimaryFaction();
if (verbose) {
int faction_id = GetPrimaryFaction();
int mob_faction_id = mob->GetPrimaryFaction();
Mob *owner = GetOwner();
if (owner) {
faction_id = owner->GetPrimaryFaction();
}
if(mob_primary == 0) {
towho->Message(Chat::White, "...%s has no primary faction", mob->GetName());
} else if(mob_primary < 0) {
towho->Message(Chat::White, "...%s is on special faction %d", mob->GetName(), mob_primary);
owner = mob->GetOwner();
if (mob_faction_id && owner) {
mob_faction_id = owner->GetPrimaryFaction();
}
if (!mob_faction_id) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) has no primary Faction.",
mob->GetCleanName(),
mob->GetID()
).c_str()
);
} else if (mob_faction_id < 0) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is on special Faction {}.",
mob->GetCleanName(),
mob->GetID(),
mob_faction_id
).c_str()
);
} else {
char namebuf[256];
if(!content_db.GetFactionName(mob_primary, namebuf, sizeof(namebuf)))
strcpy(namebuf, "(Unknown)");
std::list<struct NPCFaction*>::iterator cur,end;
cur = faction_list.begin();
end = faction_list.end();
bool res = false;
for(; cur != end; ++cur) {
struct NPCFaction* fac = *cur;
if ((int32)fac->factionID == mob_primary) {
if (fac->npc_value > 0) {
towho->Message(Chat::White, "...%s is on ALLY faction %s (%d) with %d", mob->GetName(), namebuf, mob_primary, fac->npc_value);
res = true;
break;
} else if (fac->npc_value < 0) {
towho->Message(Chat::White, "...%s is on ENEMY faction %s (%d) with %d", mob->GetName(), namebuf, mob_primary, fac->npc_value);
res = true;
break;
} else {
towho->Message(Chat::White, "...%s is on NEUTRAL faction %s (%d) with 0", mob->GetName(), namebuf, mob_primary);
res = true;
break;
}
auto faction_name = content_db.GetFactionName(mob_faction_id);
bool has_entry = false;
for (auto faction : faction_list) {
if (static_cast<int>(faction->factionID) == mob_faction_id) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) has {} standing with Faction {} ({}) with their Faction Level of {}",
mob->GetCleanName(),
mob->GetID(),
(
faction->npc_value != 0 ?
(
faction->npc_value > 0 ?
"positive" :
"negative"
) :
"neutral"
),
faction_name,
faction->factionID,
faction->npc_value
).c_str()
);
has_entry = true;
break;
}
}
if(!res) {
towho->Message(Chat::White, "...%s is on faction %s (%d), which I have no entry for.", mob->GetName(), namebuf, mob_primary);
if (!has_entry) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is on Faction {} ({}), for which I do not have an entry.",
mob->GetCleanName(),
mob->GetID(),
faction_name,
mob_faction_id
).c_str()
);
}
}
}
FACTION_VALUE fv = mob->GetReverseFactionCon(this);
auto faction_value = mob->GetReverseFactionCon(this);
if(!(
fv == FACTION_SCOWLS
||
(mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr)
||
fv == FACTION_THREATENLY
)) {
towho->Message(Chat::White, "...%s faction not low enough. value='%s'", mob->GetName(), FactionValueToString(fv));
if(
!(
faction_value == FACTION_THREATENINGLY ||
faction_value == FACTION_SCOWLS ||
(
mob->GetPrimaryFaction() != GetPrimaryFaction() &&
mob->GetPrimaryFaction() == -4 &&
!GetOwner()
)
)
) {
towho->Message(
Chat::White,
fmt::format(
"{} ({}) does not have low enough faction, their Faction Level is {} ({}).",
mob->GetCleanName(),
mob->GetID(),
FactionValueToString(faction_value),
faction_value
).c_str()
);
return;
}
if(fv == FACTION_THREATENLY) {
towho->Message(Chat::White, "...%s threatening to me, so they only have a %d chance per check of attacking.", mob->GetName());
}
if(!CheckLosFN(mob)) {
towho->Message(Chat::White, "...%s is out of sight.", mob->GetName());
towho->Message(
Chat::White,
fmt::format(
"{} ({}) is out of sight.",
mob->GetCleanName(),
mob->GetID()
).c_str()
);
}
towho->Message(Chat::White, "...%s meets all conditions, I should be attacking them.", mob->GetName());
towho->Message(
Chat::White,
fmt::format(
"{} ({}) meets all conditions, I should be attacking them.",
mob->GetCleanName(),
mob->GetID()
).c_str()
);
}
/*
@@ -229,65 +398,87 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
to keep the #aggro command accurate.
*/
bool Mob::CheckWillAggro(Mob *mob) {
if(!mob)
if(!mob) {
return false;
}
//sometimes if a client has some lag while zoning into a dangerous place while either invis or a GM
//they will aggro mobs even though it's supposed to be impossible, to lets make sure we've finished connecting
if (mob->IsClient()) {
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->bZoning)
if (
!mob->CastToClient()->ClientFinishedLoading() ||
mob->CastToClient()->IsHoveringForRespawn() ||
mob->CastToClient()->bZoning
) {
return false;
}
}
// We don't want to aggro clients outside of water if we're water only.
if (mob->IsClient() && mob->CastToClient()->GetLastRegion() != RegionTypeWater && IsUnderwaterOnly()) {
if (
mob->IsClient() &&
mob->CastToClient()->GetLastRegion() != RegionTypeWater &&
IsUnderwaterOnly()
) {
return false;
}
/**
* Pets shouldn't scan for aggro
*/
if (this->GetOwner()) {
if (GetOwner()) {
return false;
}
Mob *pet_owner = mob->GetOwner();
if (pet_owner && pet_owner->IsClient() && (!RuleB(Aggro, AggroPlayerPets) || pet_owner->CastToClient()->GetGM())) {
if (
pet_owner &&
pet_owner->IsClient() &&
(
!RuleB(Aggro, AggroPlayerPets) ||
pet_owner->CastToClient()->GetGM()
)
) {
return false;
}
float iAggroRange = GetAggroRange();
// Check If it's invisible and if we can see invis
// Check if it's a client, and that the client is connected and not linkdead,
// and that the client isn't Playing an NPC, with thier gm flag on
// Check if it's not a Interactive NPC
// Trumpcard: The 1st 3 checks are low cost calcs to filter out unnessecary distance checks. Leave them at the beginning, they are the most likely occurence.
// Image: I moved this up by itself above faction and distance checks because if one of these return true, theres no reason to go through the other information
float aggro_range = GetAggroRange();
float x_range = std::abs(mob->GetX() - GetX());
float y_range = std::abs(mob->GetY() - GetY());
float z_range = std::abs(mob->GetZ() - GetZ());
float t1, t2, t3;
t1 = std::abs(mob->GetX() - GetX());
t2 = std::abs(mob->GetY() - GetY());
t3 = std::abs(mob->GetZ() - GetZ());
if(( t1 > iAggroRange)
|| ( t2 > iAggroRange)
|| ( t3 > iAggroRange)
|| (mob->IsInvisible(this))
|| (mob->IsClient() &&
(!mob->CastToClient()->Connected()
if (
x_range > aggro_range ||
y_range > aggro_range ||
z_range > aggro_range ||
mob->IsInvisible(this) ||
(
mob->IsClient() &&
(
!mob->CastToClient()->Connected()
|| mob->CastToClient()->IsLD()
|| mob->CastToClient()->IsBecomeNPC()
|| mob->CastToClient()->GetGM()
)
))
{
return(false);
)
) {
return false;
}
// Don't aggro new clients if we are already engaged unless PROX_AGGRO is set
if (IsEngaged() && (!GetSpecialAbility(PROX_AGGRO) || (GetSpecialAbility(PROX_AGGRO) && !CombatRange(mob)))) {
LogAggro("[{}] is in combat, and does not have prox_aggro, or does and is out of combat range with [{}]", GetName(), mob->GetName());
LogAggro(
"[{}] is in combat, and does not have prox_aggro, or does and is out of combat range with [{}]",
GetName(),
mob->GetName()
);
return false;
}
@@ -296,105 +487,100 @@ bool Mob::CheckWillAggro(Mob *mob) {
//aggro this mob...???
//changed to be 'if I have an owner and this is it'
if(mob == GetOwner()) {
return(false);
return false;
}
float dist2 = DistanceSquared(mob->GetPosition(), m_Position);
float iAggroRange2 = iAggroRange*iAggroRange;
float distance_squared = DistanceSquared(mob->GetPosition(), m_Position);
float aggro_range_squared = (aggro_range * aggro_range);
if( dist2 > iAggroRange2 ) {
if (distance_squared > aggro_range_squared ) {
// Skip it, out of range
return(false);
return false;
}
//Image: Get their current target and faction value now that its required
//this function call should seem backwards
FACTION_VALUE fv = mob->GetReverseFactionCon(this);
FACTION_VALUE faction_value = mob->GetReverseFactionCon(this);
// Make sure they're still in the zone
// Are they in range?
// Are they kos?
// Are we stupid or are they green
// and they don't have their gm flag on
int heroicCHA_mod = mob->itembonuses.HeroicCHA/25; // 800 Heroic CHA cap
if(heroicCHA_mod > THREATENLY_ARRGO_CHANCE)
heroicCHA_mod = THREATENLY_ARRGO_CHANCE;
if (RuleB(Aggro, UseLevelAggro) &&
(
//old InZone check taken care of above by !mob->CastToClient()->Connected()
(
( GetLevel() >= RuleI(Aggro, MinAggroLevel))
||(GetBodyType() == 3) || AlwaysAggro()
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
int heroic_cha_mod = (mob->itembonuses.HeroicCHA / 25); // 800 Heroic CHA cap
if(heroic_cha_mod > THREATENINGLY_AGGRO_CHANCE) {
heroic_cha_mod = THREATENINGLY_AGGRO_CHANCE;
}
)
&&
(
if (
RuleB(Aggro, UseLevelAggro) &&
(
fv == FACTION_SCOWLS
||
(mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr)
||
GetLevel() >= RuleI(Aggro, MinAggroLevel) ||
GetBodyType() == BT_Undead ||
AlwaysAggro() ||
(
fv == FACTION_THREATENLY
&& zone->random.Roll(THREATENLY_ARRGO_CHANCE - heroicCHA_mod)
mob->IsClient() &&
mob->CastToClient()->IsSitting()
) ||
mob->GetLevelCon(GetLevel()) != CON_GRAY
) &&
(
faction_value == FACTION_SCOWLS ||
(
mob->GetPrimaryFaction() != GetPrimaryFaction() &&
mob->GetPrimaryFaction() == -4 &&
!GetOwner()
) ||
(
faction_value == FACTION_THREATENINGLY &&
zone->random.Roll(THREATENINGLY_AGGRO_CHANCE - heroic_cha_mod)
)
)
)
)
)
{
//FatherNiwtit: make sure we can see them. last since it is very expensive
) {
if(CheckLosFN(mob)) {
LogAggro("Check aggro for [{}] target [{}]", GetName(), mob->GetName());
return( mod_will_aggro(mob, this) );
return mod_will_aggro(mob, this);
}
}
else
{
if
(
//old InZone check taken care of above by !mob->CastToClient()->Connected()
(
( GetINT() <= RuleI(Aggro, IntAggroThreshold) )
|| AlwaysAggro()
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
)
&&
(
} else {
if (
(
fv == FACTION_SCOWLS
||
(mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr)
||
GetINT() <= RuleI(Aggro, IntAggroThreshold) ||
AlwaysAggro() ||
(
fv == FACTION_THREATENLY
&& zone->random.Roll(THREATENLY_ARRGO_CHANCE - heroicCHA_mod)
mob->IsClient() &&
mob->CastToClient()->IsSitting()
) ||
mob->GetLevelCon(GetLevel()) != CON_GRAY
) &&
(
faction_value == FACTION_SCOWLS ||
(
mob->GetPrimaryFaction() != GetPrimaryFaction() &&
mob->GetPrimaryFaction() == -4 &&
!GetOwner()
) ||
(
faction_value == FACTION_THREATENINGLY
&& zone->random.Roll(THREATENINGLY_AGGRO_CHANCE - heroic_cha_mod)
)
)
)
)
{
//FatherNiwtit: make sure we can see them. last since it is very expensive
) {
if(CheckLosFN(mob)) {
LogAggro("Check aggro for [{}] target [{}]", GetName(), mob->GetName());
return( mod_will_aggro(mob, this) );
return mod_will_aggro(mob, this);
}
}
}
LogAggro("Is In zone?:[{}]\n", mob->InZone());
LogAggro("Dist^2: [{}]\n", dist2);
LogAggro("Range^2: [{}]\n", iAggroRange2);
LogAggro("Faction: [{}]\n", fv);
LogAggro("Dist^2: [{}]\n", distance_squared);
LogAggro("Range^2: [{}]\n", aggro_range_squared);
LogAggro("Faction: [{}]\n", faction_value);
LogAggro("AlwaysAggroFlag: [{}]\n", AlwaysAggro());
LogAggro("Int: [{}]\n", GetINT());
LogAggro("Con: [{}]\n", GetLevelCon(mob->GetLevel()));
return(false);
return false;
}
int EntityList::GetHatedCount(Mob *attacker, Mob *exclude, bool inc_gray_con)
@@ -474,6 +660,9 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
if (target->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
return false;
if (target->IsHorse())
return false;
// can't damage own pet (applies to everthing)
Mob *target_owner = target->GetOwner();
Mob *our_owner = GetOwner();
@@ -1133,10 +1322,10 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
if (dispel && target && target->GetHateAmount(this) < 100)
AggroAmount += 50;
if (spells[spell_id].hate_added > 0) // overrides the hate (ex. tash)
if (spells[spell_id].hate_added != 0) // overrides the hate (ex. tash), can be negative.
AggroAmount = spells[spell_id].hate_added;
if (GetOwner() && IsPet())
if (GetOwner() && IsPet() && AggroAmount > 0)
AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;
// hate focus ignored on first action for some reason
@@ -1216,45 +1405,62 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib
return std::max(0, AggroAmount);
}
void Mob::AddFeignMemory(Client* attacker) {
if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr)
void Mob::AddFeignMemory(Mob* attacker) {
if (feign_memory_list.empty() && AI_feign_remember_timer != nullptr) {
AI_feign_remember_timer->Start(AIfeignremember_delay);
feign_memory_list.insert(attacker->CharacterID());
}
if (attacker) {
feign_memory_list.insert(attacker->GetID());
}
}
void Mob::RemoveFromFeignMemory(Client* attacker) {
feign_memory_list.erase(attacker->CharacterID());
if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr)
void Mob::RemoveFromFeignMemory(Mob* attacker) {
if (!attacker) {
return;
}
feign_memory_list.erase(attacker->GetID());
if (feign_memory_list.empty() && AI_feign_remember_timer != nullptr) {
AI_feign_remember_timer->Disable();
}
if(feign_memory_list.empty())
{
minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin);
maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax);
if(AI_feign_remember_timer != nullptr)
if (AI_feign_remember_timer != nullptr) {
AI_feign_remember_timer->Disable();
}
}
}
void Mob::ClearFeignMemory() {
auto RememberedCharID = feign_memory_list.begin();
while (RememberedCharID != feign_memory_list.end())
auto remembered_feigned_mobid = feign_memory_list.begin();
while (remembered_feigned_mobid != feign_memory_list.end())
{
Client* remember_client = entity_list.GetClientByCharID(*RememberedCharID);
if(remember_client != nullptr) //Still in zone
remember_client->RemoveXTarget(this, false);
++RememberedCharID;
Mob* remembered_mob = entity_list.GetMob(*remembered_feigned_mobid);
if (remembered_mob->IsClient() && remembered_mob != nullptr) { //Still in zone
remembered_mob->CastToClient()->RemoveXTarget(this, false);
}
++remembered_feigned_mobid;
}
feign_memory_list.clear();
minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin);
maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax);
if(AI_feign_remember_timer != nullptr)
if (AI_feign_remember_timer != nullptr) {
AI_feign_remember_timer->Disable();
}
}
bool Mob::IsOnFeignMemory(Client *attacker) const
bool Mob::IsOnFeignMemory(Mob *attacker) const
{
return feign_memory_list.find(attacker->CharacterID()) != feign_memory_list.end();
if (!attacker) {
return 0;
}
return feign_memory_list.find(attacker->GetID()) != feign_memory_list.end();
}
bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
-1
View File
@@ -436,7 +436,6 @@ Json::Value ApiGetMobListDetail(EQ::Net::WebsocketServerConnection *connection,
row["cwp"] = mob->GetCWP();
row["cwpp"] = mob->GetCWPP();
row["divine_aura"] = mob->DivineAura();
row["do_casting_checks"] = mob->DoCastingChecks();
row["dont_buff_me_before"] = mob->DontBuffMeBefore();
row["dont_cure_me_before"] = mob->DontCureMeBefore();
row["dont_dot_me_before"] = mob->DontDotMeBefore();
+230 -113
View File
@@ -432,7 +432,22 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
}
// riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo
bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance || attacker->IsEnraged();
bool ImmuneRipo = false;
if (!RuleB(Combat, UseLiveRiposteMechanics)) {
ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance || attacker->IsEnraged();
}
/*
Live Riposte Mechanics (~Kayen updated 1/22)
-Ripostes can not trigger another riposte. (Ie. Riposte from defender can't then trigger the attacker to riposte)
-Ripostes can not be 'avoided', only hit or miss.
-Attacker with SPA 173 is not immune to riposte. The defender can riposte against the attackers melee hits.
Legacy Riposte Mechanics
-Ripostes can trigger another riposte
-Attacker with SPA 173 is immune to riposte
-Attacker that is enraged is immune to riposte
*/
// Need to check if we have something in MainHand to actually attack with (or fists)
if (hit.hand != EQ::invslot::slotRange && (CanThisClassRiposte() || IsEnraged()) && InFront && !ImmuneRipo) {
if (IsEnraged()) {
@@ -1369,25 +1384,27 @@ int Client::DoDamageCaps(int base_damage)
// other is the defender, this is the attacker
//SYNC WITH: tune.cpp, mob.h TuneDoAttack
void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts)
void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts, bool FromRiposte)
{
if (!other)
return;
LogCombat("[{}]::DoAttack vs [{}] base [{}] min [{}] offense [{}] tohit [{}] skill [{}]", GetName(),
other->GetName(), hit.base_damage, hit.min_damage, hit.offense, hit.tohit, hit.skill);
// check to see if we hit..
if (other->AvoidDamage(this, hit)) {
if (!RuleB(Combat, UseLiveRiposteMechanics)) {
FromRiposte = false;
}
// check to see if we hit..
if (!FromRiposte && other->AvoidDamage(this, hit)) {
int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
if (strike_through && zone->random.Roll(strike_through)) {
MessageString(Chat::StrikeThrough,
STRIKETHROUGH_STRING); // You strike through your opponents defenses!
hit.damage_done = 1; // set to one, we will check this to continue
}
// I'm pretty sure you can riposte a riposte
if (hit.damage_done == DMG_RIPOSTED) {
DoRiposte(other);
//if (IsDead())
return;
}
LogCombat("Avoided/strikethrough damage with code [{}]", hit.damage_done);
@@ -1570,7 +1587,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
my_hit.tohit = GetTotalToHit(my_hit.skill, hit_chance_bonus);
DoAttack(other, my_hit, opts);
DoAttack(other, my_hit, opts, bRiposte);
}
else {
my_hit.damage_done = DMG_INVULNERABLE;
@@ -1603,32 +1620,26 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
///////////////////////////////////////////////////////////
////// Send Attack Damage
///////////////////////////////////////////////////////////
if (my_hit.damage_done > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SKILL] == my_hit.skill &&
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID])) {
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] / 1000.0f;
if (zone->random.Roll(chance))
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
spells[aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID]].resist_difficulty);
}
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill, true, -1, false, m_specialattacks);
if (IsDead()) return false;
if (IsDead()) {
return false;
}
MeleeLifeTap(my_hit.damage_done);
if (my_hit.damage_done > 0 && HasSkillProcSuccess() && other && other->GetHP() > 0)
TrySkillProc(other, my_hit.skill, 0, true, Hand);
CommonBreakInvisibleFromCombat();
if (GetTarget())
if (GetTarget()) {
TriggerDefensiveProcs(other, Hand, true, my_hit.damage_done);
}
if (my_hit.damage_done > 0)
if (my_hit.damage_done > 0) {
return true;
else
}
else {
return false;
}
}
//used by complete heal and #heal
@@ -1880,6 +1891,8 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill
//m_epp.perAA = 0; //reset to no AA exp on death.
}
int32 illusion_spell_id = spellbonuses.Illusion;
//this generates a lot of 'updates' to the client that the client does not need
BuffFadeNonPersistDeath();
if (RuleB(Character, UnmemSpellsOnDeath)) {
@@ -1925,13 +1938,12 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill
}
}
}
entity_list.AddCorpse(new_corpse, GetID());
SetID(0);
//send the become corpse packet to everybody else in the zone.
entity_list.QueueClients(this, &app2, true);
ApplyIllusionToCorpse(illusion_spell_id, new_corpse);
LeftCorpse = true;
}
}
@@ -2168,7 +2180,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
my_hit.offense = offense(my_hit.skill);
my_hit.tohit = GetTotalToHit(my_hit.skill, hit_chance_bonus);
DoAttack(other, my_hit, opts);
DoAttack(other, my_hit, opts, bRiposte);
other->AddToHateList(this, hate);
@@ -2329,6 +2341,8 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
if (p_depop == true)
return false;
int32 illusion_spell_id = spellbonuses.Illusion;
HasAISpellEffects = false;
BuffFadeAll();
uint8 killed_level = GetLevel();
@@ -2400,7 +2414,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
give_exp_client = give_exp->CastToClient();
//do faction hits even if we are a merchant, so long as a player killed us
if (give_exp_client && !RuleB(NPC, EnableMeritBasedFaction))
if (!IsCharmed() && give_exp_client && !RuleB(NPC, EnableMeritBasedFaction))
hate_list.DoFactionHits(GetNPCFactionID());
bool IsLdonTreasure = (this->GetClass() == LDON_TREASURE);
@@ -2571,6 +2585,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
}
entity_list.RemoveFromAutoXTargets(this);
uint16 emoteid = this->GetEmoteID();
auto corpse = new Corpse(this, &itemlist, GetNPCTypeID(), &NPCTypedata,
level > 54 ? RuleI(NPC, MajorNPCCorpseDecayTimeMS)
@@ -2583,8 +2598,8 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
// entity_list.RemoveMobFromCloseLists(this);
close_mobs.clear();
this->SetID(0);
ApplyIllusionToCorpse(illusion_spell_id, corpse);
if (killer != 0 && emoteid != 0)
corpse->CastToNPC()->DoNPCEmote(AFTERDEATH, emoteid);
@@ -2815,7 +2830,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other->CastToClient()))
if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other))
other->CastToClient()->AddAutoXTarget(this);
#ifdef BOTS
@@ -2857,7 +2872,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
}
} //MERC
// then add pet owner if there's one
//if I am a pet, then add pet owner if there's one
if (owner) { // Other is a pet, add him and it
// EverHood 6/12/06
// Can't add a feigned owner to hate list
@@ -2872,8 +2887,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
!(this->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && owner->IsClient()) &&
!(this->GetSpecialAbility(IMMUNE_AGGRO_NPC) && owner->IsNPC())
) {
if (owner->IsClient() && !CheckAggro(owner))
if (owner->IsClient() && !CheckAggro(owner)) {
owner->CastToClient()->AddAutoXTarget(this);
}
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
}
}
@@ -2900,8 +2916,10 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
}
}
if (other->GetTempPetCount())
entity_list.AddTempPetsToHateList(other, this, bFrenzy);
//I have a swarm pet, add other to it.
if (GetTempPetCount()) {
entity_list.AddTempPetsToHateList(this, other, bFrenzy);
}
if (!wasengaged) {
if (IsNPC() && other->IsClient() && other->CastToClient())
@@ -3298,7 +3316,8 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi
// If this is a DoT, use DoT Shielding...
if (iBuffTic) {
damage -= (damage * itembonuses.DoTShielding / 100);
int total_dotshielding = itembonuses.DoTShielding + itembonuses.MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] + aabonuses.MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT];
damage -= (damage * total_dotshielding / 100);
if (spellbonuses.MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT]) {
slot = spellbonuses.MitigateDotRune[SBIndex::MITIGATION_RUNE_BUFFSLOT];
@@ -3330,8 +3349,9 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi
else
{
// Reduce damage by the Spell Shielding first so that the runes don't take the raw damage.
damage -= (damage * itembonuses.SpellShield / 100);
int total_spellshielding = itembonuses.SpellShield + itembonuses.MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] + aabonuses.MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT];
damage -= (damage * total_spellshielding / 100);
//Only mitigate if damage is above the minimium specified.
if (spellbonuses.SpellThresholdGuard[SBIndex::THRESHOLDGUARD_MITIGATION_PERCENT]) {
slot = spellbonuses.SpellThresholdGuard[SBIndex::THRESHOLDGUARD_BUFFSLOT];
@@ -3469,7 +3489,6 @@ bool Mob::HasDefensiveProcs() const
bool Mob::HasSkillProcs() const
{
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
if (spellbonuses.SkillProc[i] || itembonuses.SkillProc[i] || aabonuses.SkillProc[i])
return true;
@@ -3683,6 +3702,10 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
}
}
if (GetTempPetCount()) {
entity_list.AddTempPetsToHateListOnOwnerDamage(this, attacker, spell_id);
}
//see if any runes want to reduce this damage
if (spell_id == SPELL_UNKNOWN) {
damage = ReduceDamage(damage);
@@ -4162,12 +4185,12 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
//Spell Procs and Quest added procs
for (int i = 0; i < MAX_PROCS; i++) {
if (IsValidSpell(DefensiveProcs[i].spellID)) {
if (!IsProcLimitTimerActive(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, SE_DefensiveProc)) {
if (!IsProcLimitTimerActive(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, ProcType::DEFENSIVE_PROC)) {
float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0, DefensiveProcs[i].base_spellID);
SetProcLimitTimer(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, SE_DefensiveProc);
SetProcLimitTimer(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, ProcType::DEFENSIVE_PROC);
}
}
}
@@ -4176,17 +4199,17 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
//AA Procs
if (IsClient()){
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
int32 aa_rank_id = aabonuses.DefensiveProc[i];
int32 aa_spell_id = aabonuses.DefensiveProc[i + 1];
int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + 2];
uint32 aa_proc_reuse_timer = aabonuses.DefensiveProc[i + 3];
int32 aa_rank_id = aabonuses.DefensiveProc[i + +SBIndex::COMBAT_PROC_ORIGIN_ID];
int32 aa_spell_id = aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_SPELL_ID];
int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
uint32 aa_proc_reuse_timer = aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER];
if (aa_rank_id) {
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, SE_DefensiveProc)) {
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, ProcType::DEFENSIVE_PROC)) {
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
ExecWeaponProc(nullptr, aa_spell_id, on);
SetProcLimitTimer(-aa_rank_id, aa_proc_reuse_timer, SE_DefensiveProc);
SetProcLimitTimer(-aa_rank_id, aa_proc_reuse_timer, ProcType::DEFENSIVE_PROC);
}
}
}
@@ -4195,7 +4218,8 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
}
}
void Mob::TryWeaponProc(const EQ::ItemInstance* weapon_g, Mob *on, uint16 hand) {
void Mob::TryCombatProcs(const EQ::ItemInstance* weapon_g, Mob *on, uint16 hand, const EQ::ItemData* weapon_data) {
if (!on) {
SetTarget(nullptr);
LogError("A null Mob object was passed to Mob::TryWeaponProc for evaluation!");
@@ -4212,6 +4236,13 @@ void Mob::TryWeaponProc(const EQ::ItemInstance* weapon_g, Mob *on, uint16 hand)
return;
}
//used for special case when checking last ammo item on projectile hit.
if (!weapon_g && weapon_data) {
TryWeaponProc(nullptr, weapon_data, on, hand);
TrySpellProc(nullptr, weapon_data, on, hand);
return;
}
if (!weapon_g) {
TrySpellProc(nullptr, (const EQ::ItemData*)nullptr, on);
return;
@@ -4251,7 +4282,7 @@ void Mob::TryWeaponProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon
// Try innate proc on weapon
// We can proc once here, either weapon or one aug
bool proced = false; // silly bool to prevent augs from going if weapon does
skillinuse = GetSkillByItemType(weapon->ItemType);
if (weapon->Proc.Type == EQ::item::ItemEffectCombatProc && IsValidSpell(weapon->Proc.Effect)) {
float WPC = ProcChance * (100.0f + // Proc chance for this weapon
static_cast<float>(weapon->ProcRate)) / 100.0f;
@@ -4328,8 +4359,16 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
float ProcChance = 0.0f;
ProcChance = GetProcChances(ProcBonus, hand);
if (hand == EQ::invslot::slotSecondary)
bool passed_skill_limit_check = true;
EQ::skills::SkillType skillinuse = EQ::skills::SkillHandtoHand;
if (weapon){
skillinuse = GetSkillByItemType(weapon->ItemType);
}
if (hand == EQ::invslot::slotSecondary) {
ProcChance /= 2;
}
bool rangedattk = false;
if (weapon && hand == EQ::invslot::slotRange) {
@@ -4341,8 +4380,9 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
}
}
if (!weapon && hand == EQ::invslot::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK))
if (!weapon && hand == EQ::invslot::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK)) {
rangedattk = true;
}
int16 poison_slot=-1;
@@ -4351,8 +4391,9 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
continue; // If pets ever can proc from off hand, this will need to change
if (SpellProcs[i].base_spellID == POISON_PROC &&
(!weapon || weapon->ItemType != EQ::item::ItemType1HPiercing))
(!weapon || weapon->ItemType != EQ::item::ItemType1HPiercing)) {
continue; // Old school poison will only proc with 1HP equipped.
}
// Not ranged
if (!rangedattk) {
@@ -4373,14 +4414,16 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
poison_slot=i;
continue; // Process the poison proc last per @mackal
}
if (!IsProcLimitTimerActive(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, SE_WeaponProc)) {
passed_skill_limit_check = PassLimitToSkill(skillinuse, SpellProcs[i].base_spellID, ProcType::MELEE_PROC);
if (passed_skill_limit_check && !IsProcLimitTimerActive(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, ProcType::MELEE_PROC)) {
float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
SendBeginCast(SpellProcs[i].spellID, 0);
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
SetProcLimitTimer(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, SE_WeaponProc);
SetProcLimitTimer(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, ProcType::MELEE_PROC);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, SpellProcs[i].base_spellID);
}
else {
@@ -4393,13 +4436,15 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
// ranged spell procs (buffs)
if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
if (!IsProcLimitTimerActive(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, SE_RangedProc)) {
passed_skill_limit_check = PassLimitToSkill(skillinuse, RangedProcs[i].base_spellID, ProcType::RANGED_PROC);
if (passed_skill_limit_check && !IsProcLimitTimerActive(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, ProcType::RANGED_PROC)) {
float chance = ProcChance * (static_cast<float>(RangedProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
LogCombat("Ranged proc [{}] procing spell [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, RangedProcs[i].base_spellID);
SetProcLimitTimer(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, SE_RangedProc);
SetProcLimitTimer(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, ProcType::RANGED_PROC);
}
else {
LogCombat("Ranged proc [{}] failed to proc [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
@@ -4409,7 +4454,7 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
}
}
//AA Procs
//AA Melee and Ranged Procs
if (IsClient()) {
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
@@ -4421,22 +4466,25 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
if (!rangedattk) {
aa_rank_id = aabonuses.SpellProc[i];
aa_spell_id = aabonuses.SpellProc[i + 1];
aa_proc_chance += aabonuses.SpellProc[i + 2];
aa_proc_reuse_timer = aabonuses.SpellProc[i + 3];
proc_type = SE_WeaponProc;
aa_rank_id = aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID];
aa_spell_id = aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_SPELL_ID];
aa_proc_chance += aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
aa_proc_reuse_timer = aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
proc_type = ProcType::MELEE_PROC;
}
else {
aa_rank_id = aabonuses.RangedProc[i];
aa_spell_id = aabonuses.RangedProc[i + 1];
aa_proc_chance += aabonuses.RangedProc[i + 2];
aa_proc_reuse_timer = aabonuses.RangedProc[i + 3];
proc_type = SE_RangedProc;
aa_rank_id = aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID];
aa_spell_id = aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_SPELL_ID];
aa_proc_chance += aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
aa_proc_reuse_timer = aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
proc_type = ProcType::RANGED_PROC;
}
if (aa_rank_id) {
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, proc_type)) {
passed_skill_limit_check = PassLimitToSkill(skillinuse, 0, proc_type, aa_rank_id);
if (passed_skill_limit_check && !IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, proc_type)) {
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
LogCombat("AA proc [{}] procing spell [{}] ([{}] percent chance)", aa_rank_id, aa_spell_id, chance);
@@ -4466,14 +4514,15 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
}
}
if (HasSkillProcs() && hand != EQ::invslot::slotRange) { //We check ranged skill procs within the attack functions.
uint16 skillinuse = 28;
if (weapon)
skillinuse = GetSkillByItemType(weapon->ItemType);
TryCastOnSkillUse(on, skillinuse);
if (HasSkillProcs() && hand != EQ::invslot::slotRange) { //We check ranged skill procs within the attack functions.
TrySkillProc(on, skillinuse, 0, false, hand);
}
if (HasSkillProcSuccess() && hand != EQ::invslot::slotRange) { //We check ranged skill procs within the attack functions.
TrySkillProc(on, skillinuse, 0, true, hand);
}
return;
}
@@ -4736,8 +4785,13 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
bool Mob::TryFinishingBlow(Mob *defender, int &damage)
{
// base2 of FinishingBlowLvl is the HP limit (cur / max) * 1000, 10% is listed as 100
if (defender && !defender->IsClient() && defender->GetHPRatio() < 10) {
float hp_limit = 10.0f;
auto fb_hp_limit = std::max({ aabonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO], spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO], itembonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] });
if (fb_hp_limit) {
hp_limit = fb_hp_limit/10.0f;
}
if (defender && !defender->IsClient() && defender->GetHPRatio() < hp_limit) {
uint32 FB_Dmg =
aabonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] + spellbonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_DMG] + itembonuses.FinishingBlow[SBIndex::FINISHING_EFFECT_DMG];
@@ -4788,6 +4842,7 @@ void Mob::DoRiposte(Mob *defender)
}
defender->Attack(this, EQ::invslot::slotPrimary, true);
if (HasDied())
return;
@@ -5038,7 +5093,7 @@ void Mob::ApplyDamageTable(DamageHitInfo &hit)
Log(Logs::Detail, Logs::Attack, "Damage table applied %d (max %d)", percent, damage_table.max_extra);
}
void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, uint16 hand, bool IsDefensive)
void Mob::TrySkillProc(Mob *on, EQ::skills::SkillType skill, uint16 ReuseTime, bool Success, uint16 hand, bool IsDefensive)
{
if (!on) {
@@ -5047,12 +5102,19 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
return;
}
if (!spellbonuses.LimitToSkill[skill] && !itembonuses.LimitToSkill[skill] && !aabonuses.LimitToSkill[skill])
if (on->HasDied()) {
return;
}
/*Allow one proc from each (Spell/Item/AA)
Kayen: Due to limited avialability of effects on live it is too difficult
to confirm how they stack at this time, will adjust formula when more data is avialablle to test.*/
if (!spellbonuses.LimitToSkill[skill] && !itembonuses.LimitToSkill[skill] && !aabonuses.LimitToSkill[skill]) {
return;
}
/*
Allow one proc from each (Spell/Item/AA)
Kayen: Due to limited avialability of effects on live it is too difficult
to confirm how they stack at this time, will adjust formula when more data is avialablle to test.
*/
bool CanProc = true;
uint16 base_spell_id = 0;
@@ -5067,22 +5129,24 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
if (spellbonuses.LimitToSkill[skill]) {
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
if (CanProc &&
((!Success && spellbonuses.SkillProc[e] && IsValidSpell(spellbonuses.SkillProc[e]))
|| (Success && spellbonuses.SkillProcSuccess[e] && IsValidSpell(spellbonuses.SkillProcSuccess[e])))) {
((!Success && spellbonuses.SkillProc[i] && IsValidSpell(spellbonuses.SkillProc[i]))
|| (Success && spellbonuses.SkillProcSuccess[i] && IsValidSpell(spellbonuses.SkillProcSuccess[i])))) {
if (Success)
base_spell_id = spellbonuses.SkillProcSuccess[e];
else
base_spell_id = spellbonuses.SkillProc[e];
if (Success) {
base_spell_id = spellbonuses.SkillProcSuccess[i];
}
else {
base_spell_id = spellbonuses.SkillProc[i];
}
proc_spell_id = 0;
ProcMod = 0;
for (int i = 0; i < EFFECT_COUNT; i++) {
if (spells[base_spell_id].effect_id[i] == SE_SkillProc || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) {
if (spells[base_spell_id].effect_id[i] == SE_SkillProcAttempt || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) {
proc_spell_id = spells[base_spell_id].base_value[i];
ProcMod = static_cast<float>(spells[base_spell_id].limit_value[i]);
}
@@ -5093,8 +5157,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
float final_chance = chance * (ProcMod / 100.0f);
if (zone->random.Roll(final_chance)) {
ExecWeaponProc(nullptr, proc_spell_id, on);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
base_spell_id);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, base_spell_id);
CanProc = false;
break;
}
@@ -5112,21 +5175,23 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
if (itembonuses.LimitToSkill[skill]) {
CanProc = true;
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
if (CanProc &&
((!Success && itembonuses.SkillProc[e] && IsValidSpell(itembonuses.SkillProc[e]))
|| (Success && itembonuses.SkillProcSuccess[e] && IsValidSpell(itembonuses.SkillProcSuccess[e])))) {
((!Success && itembonuses.SkillProc[i] && IsValidSpell(itembonuses.SkillProc[i]))
|| (Success && itembonuses.SkillProcSuccess[i] && IsValidSpell(itembonuses.SkillProcSuccess[i])))) {
if (Success)
base_spell_id = itembonuses.SkillProcSuccess[e];
else
base_spell_id = itembonuses.SkillProc[e];
if (Success) {
base_spell_id = itembonuses.SkillProcSuccess[i];
}
else {
base_spell_id = itembonuses.SkillProc[i];
}
proc_spell_id = 0;
ProcMod = 0;
for (int i = 0; i < EFFECT_COUNT; i++) {
if (spells[base_spell_id].effect_id[i] == SE_SkillProc || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) {
if (spells[base_spell_id].effect_id[i] == SE_SkillProcAttempt || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) {
proc_spell_id = spells[base_spell_id].base_value[i];
ProcMod = static_cast<float>(spells[base_spell_id].limit_value[i]);
}
@@ -5159,16 +5224,16 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
int32 limit_value = 0;
uint32 slot = 0;
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
if (CanProc &&
((!Success && aabonuses.SkillProc[e])
|| (Success && aabonuses.SkillProcSuccess[e]))) {
((!Success && aabonuses.SkillProc[i])
|| (Success && aabonuses.SkillProcSuccess[i]))) {
int aaid = 0;
if (Success)
base_spell_id = aabonuses.SkillProcSuccess[e];
base_spell_id = aabonuses.SkillProcSuccess[i];
else
base_spell_id = aabonuses.SkillProc[e];
base_spell_id = aabonuses.SkillProc[i];
proc_spell_id = 0;
ProcMod = 0;
@@ -5188,7 +5253,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
limit_value = effect.limit_value;
slot = effect.slot;
if (effect_id == SE_SkillProc || effect_id == SE_SkillProcSuccess) {
if (effect_id == SE_SkillProcAttempt || effect_id == SE_SkillProcSuccess) {
proc_spell_id = base_value;
ProcMod = static_cast<float>(limit_value);
}
@@ -5223,16 +5288,65 @@ float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) {
if (!ReuseTime && hand) {
weapon_speed = GetWeaponSpeedbyHand(hand);
ProcChance = static_cast<float>(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
if (hand == EQ::invslot::slotSecondary)
if (hand == EQ::invslot::slotSecondary) {
ProcChance /= 2;
}
}
else
else {
ProcChance = static_cast<float>(ReuseTime) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
}
return ProcChance;
}
void Mob::TryCastOnSkillUse(Mob *on, EQ::skills::SkillType skill) {
if (!spellbonuses.HasSkillAttackProc[skill] && !itembonuses.HasSkillAttackProc[skill] && !aabonuses.HasSkillAttackProc[skill]) {
return;
}
if (!on) {
SetTarget(nullptr);
LogError("A null Mob object was passed to Mob::TryCastOnSkillUse for evaluation!");
return;
}
if (on->HasDied()) {
return;
}
if (spellbonuses.HasSkillAttackProc[skill]) {
for (int i = 0; i < MAX_CAST_ON_SKILL_USE; i += 3) {
if (spellbonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID] && skill == spellbonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SKILL]) {
if (IsValidSpell(spellbonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]) && zone->random.Int(1, 1000) <= spellbonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_CHANCE]) {
SpellFinished(spellbonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID], on, EQ::spells::CastingSlot::Item, 0, -1, spells[spellbonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]].resist_difficulty);
}
}
}
}
if (itembonuses.HasSkillAttackProc[skill]) {
for (int i = 0; i < MAX_CAST_ON_SKILL_USE; i += 3) {
if (itembonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID] && skill == itembonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SKILL]) {
if (IsValidSpell(itembonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]) && zone->random.Int(1, 1000) <= spellbonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_CHANCE]) {
SpellFinished(itembonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID], on, EQ::spells::CastingSlot::Item, 0, -1, spells[itembonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]].resist_difficulty);
}
}
}
}
if (aabonuses.HasSkillAttackProc[skill]) {
for (int i = 0; i < MAX_CAST_ON_SKILL_USE; i += 3) {
if (IsValidSpell(aabonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]) && aabonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID] && skill == aabonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SKILL]) {
if (zone->random.Int(1, 1000) <= aabonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_CHANCE]) {
SpellFinished(aabonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID], on, EQ::spells::CastingSlot::Item, 0, -1, spells[aabonuses.SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]].resist_difficulty);
}
}
}
}
}
bool Mob::TryRootFadeByDamage(int buffslot, Mob* attacker) {
/*Dev Quote 2010: http://forums.station.sony.com/eq/posts/list.m?topic_id=161443
@@ -5247,28 +5361,31 @@ bool Mob::TryRootFadeByDamage(int buffslot, Mob* attacker) {
- Root break chance values obtained from live parses.
*/
if (!attacker || !spellbonuses.Root[SBIndex::ROOT_EXISTS] || spellbonuses.Root[SBIndex::ROOT_BUFFSLOT] < 0)
if (!attacker || !spellbonuses.Root[SBIndex::ROOT_EXISTS] || spellbonuses.Root[SBIndex::ROOT_BUFFSLOT] < 0) {
return false;
}
if (IsDetrimentalSpell(buffs[spellbonuses.Root[SBIndex::ROOT_BUFFSLOT]].spellid) && spellbonuses.Root[SBIndex::ROOT_BUFFSLOT] != buffslot) {
if (IsDetrimentalSpell(spellbonuses.Root[SBIndex::ROOT_BUFFSLOT]) && spellbonuses.Root[SBIndex::ROOT_BUFFSLOT] != buffslot) {
int BreakChance = RuleI(Spells, RootBreakFromSpells);
BreakChance -= BreakChance * buffs[spellbonuses.Root[SBIndex::ROOT_BUFFSLOT]].RootBreakChance / 100;
int level_diff = attacker->GetLevel() - GetLevel();
//Use baseline if level difference <= 1 (ie. If target is (1) level less than you, or equal or greater level)
if (level_diff == 2)
if (level_diff == 2) {
BreakChance = (BreakChance * 80) / 100; //Decrease by 20%;
else if (level_diff >= 3 && level_diff <= 20)
}
else if (level_diff >= 3 && level_diff <= 20) {
BreakChance = (BreakChance * 60) / 100; //Decrease by 40%;
else if (level_diff > 21)
}
else if (level_diff > 21) {
BreakChance = (BreakChance * 20) / 100; //Decrease by 80%;
}
if (BreakChance < 1)
if (BreakChance < 1) {
BreakChance = 1;
}
if (zone->random.Roll(BreakChance)) {
@@ -5456,7 +5573,7 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
int pct_damage_reduction = defender->GetSkillDmgTaken(hit.skill, opts) + defender->GetPositionalDmgTaken(this);
hit.damage_done += (hit.damage_done * pct_damage_reduction / 100) + (defender->GetFcDamageAmtIncoming(this, 0, true, hit.skill)) + defender->GetPositionalDmgTakenAmt(this);
hit.damage_done += (hit.damage_done * pct_damage_reduction / 100) + defender->GetPositionalDmgTakenAmt(this);
if (defender->GetShielderID()) {
DoShieldDamageOnShielder(defender, hit.damage_done, hit.skill);
+117 -55
View File
@@ -674,7 +674,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
uint8 focus = IsFocusEffect(0, 0, true, effect);
if (focus) {
newbon->FocusEffects[focus] = static_cast<uint8>(effect);
newbon->FocusEffects[focus] = effect;
continue;
}
@@ -1074,11 +1074,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
case SE_WeaponProc:
case SE_AddMeleeProc:
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (!newbon->SpellProc[i]) {
newbon->SpellProc[i] = rank.id; //aa rank id
newbon->SpellProc[i + 1] = base_value; //proc spell id
newbon->SpellProc[i + 2] = limit_value; //proc rate modifer
newbon->SpellProc[i + 3] = 0; //Lock out Timer
if (!newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
newbon->SpellProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
newbon->SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
break;
}
}
@@ -1086,11 +1086,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
case SE_RangedProc:
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (!newbon->RangedProc[i]) {
newbon->RangedProc[i] = rank.id; //aa rank id
newbon->RangedProc[i + 1] = base_value; //proc spell id
newbon->RangedProc[i + 2] = limit_value; //proc rate modifer
newbon->RangedProc[i + 3] = 0; //Lock out Timer
if (!newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
newbon->RangedProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
newbon->RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
break;
}
}
@@ -1098,11 +1098,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
case SE_DefensiveProc:
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (!newbon->DefensiveProc[i]) {
newbon->DefensiveProc[i] = rank.id; //aa rank id
newbon->DefensiveProc[i + 1] = base_value; //proc spell id
newbon->DefensiveProc[i + 2] = limit_value; //proc rate modifer
newbon->DefensiveProc[i + 3] = 0; //Lock out Timer
if (!newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
break;
}
}
@@ -1118,23 +1118,23 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
newbon->Proc_Timer_Modifier = true;
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (newbon->SpellProc[i] == rank.id) {
if (!newbon->SpellProc[i + 3]) {
newbon->SpellProc[i + 3] = limit_value;//Lock out Timer
if (newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
if (!newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
break;
}
}
if (newbon->RangedProc[i] == rank.id) {
if (!newbon->RangedProc[i + 3]) {
newbon->RangedProc[i + 3] = limit_value;//Lock out Timer
if (newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
if (!newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
break;
}
}
if (newbon->DefensiveProc[i] == rank.id) {
if (!newbon->DefensiveProc[i + 3]) {
newbon->DefensiveProc[i + 3] = limit_value;//Lock out Timer
if (newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
if (!newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
break;
}
}
@@ -1207,11 +1207,18 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
case SE_SkillAttackProc: {
// You can only have one of these per client. [AA Dragon Punch]
newbon->SkillAttackProc[SBIndex::SKILLPROC_CHANCE] = base_value; // Chance base 1000 = 100% proc rate
newbon->SkillAttackProc[SBIndex::SKILLPROC_SKILL] = limit_value; // Skill to Proc Off
newbon->SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID] = rank.spell; // spell to proc
break;
for (int i = 0; i < MAX_CAST_ON_SKILL_USE; i += 3) {
if (!newbon->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]) { // spell id
newbon->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID] = rank.spell; // spell to proc
newbon->SkillAttackProc[i + SBIndex::SKILLATK_PROC_CHANCE] = base_value; // Chance base 1000 = 100% proc rate
newbon->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SKILL] = limit_value; // Skill to Proc Offr
if (limit_value < EQ::skills::HIGHEST_SKILL) {
newbon->HasSkillAttackProc[limit_value] = true; //check first before looking for any effects.
}
break;
}
}
}
case SE_DamageModifier: {
@@ -1349,7 +1356,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
// base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?)
if (newbon->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] < base_value) {
newbon->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = base_value;
newbon->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = limit_value;
newbon->FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = limit_value;
}
break;
}
@@ -1453,20 +1460,28 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
break;
}
case SE_Illusion:
newbon->Illusion = true;
break;
case SE_IllusionPersistence:
newbon->IllusionPersistence = true;
newbon->IllusionPersistence = base_value;
break;
case SE_LimitToSkill: {
// Bad data or unsupported new skill
if (limit_value > EQ::skills::HIGHEST_SKILL)
if (base_value > EQ::skills::HIGHEST_SKILL) {
break;
if (base_value <= EQ::skills::HIGHEST_SKILL)
}
if (base_value <= EQ::skills::HIGHEST_SKILL) {
newbon->LimitToSkill[base_value] = true;
newbon->LimitToSkill[EQ::skills::HIGHEST_SKILL + 3] = true; //Used as a general exists check
}
break;
}
case SE_SkillProc: {
case SE_SkillProcAttempt: {
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
if (newbon->SkillProc[e] && newbon->SkillProc[e] == rank.id)
break; // Do not use the same aa id more than once.
@@ -1560,8 +1575,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
break;
case SE_FeignedMinion:
if (newbon->FeignedMinionChance < base_value)
if (newbon->FeignedMinionChance < base_value) {
newbon->FeignedMinionChance = base_value;
}
newbon->PetCommands[PET_FEIGN] = true;
break;
case SE_AdditionalAura:
@@ -1761,6 +1778,22 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
newbon->Amplification += base_value;
break;
case SE_MitigateSpellDamage:
{
newbon->MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] += base_value;
break;
}
case SE_MitigateDotDamage:
{
newbon->MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] += base_value;
break;
}
case SE_TrapCircumvention:
newbon->TrapCircumvention += base_value;
break;
// to do
case SE_PetDiscipline:
break;
@@ -1772,9 +1805,6 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
break;
case SE_NimbleEvasion:
break;
case SE_TrapCircumvention:
break;
// not handled here
case SE_HastenedAASkill:
@@ -1874,7 +1904,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
}
}
else {
new_bonus->FocusEffects[focus] = static_cast<uint8>(spells[spell_id].effect_id[i]);
new_bonus->FocusEffects[focus] = spells[spell_id].effect_id[i];
}
continue;
}
@@ -3019,6 +3049,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_MitigateSpellDamage:
{
if (WornType) {
new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] += effect_value;
}
if (new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] < effect_value){
new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_PERCENT] = effect_value;
new_bonus->MitigateSpellRune[SBIndex::MITIGATION_RUNE_BUFFSLOT] = buffslot;
@@ -3030,6 +3064,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_MitigateDotDamage:
{
if (WornType) {
new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] += effect_value;
}
if (new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] < effect_value){
new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_PERCENT] = effect_value;
new_bonus->MitigateDotRune[SBIndex::MITIGATION_RUNE_BUFFSLOT] = buffslot;
@@ -3482,10 +3520,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_FinishingBlowLvl:
{
//base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?)
if (new_bonus->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] < effect_value){
new_bonus->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
new_bonus->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = limit_value;
new_bonus->FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value;
new_bonus->FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = limit_value;
}
break;
}
@@ -3508,21 +3545,27 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
break;
}
case SE_Illusion:
new_bonus->Illusion = spell_id;
break;
case SE_IllusionPersistence:
new_bonus->IllusionPersistence = true;
new_bonus->IllusionPersistence = effect_value;
break;
case SE_LimitToSkill:{
// Bad data or unsupported new skill
if (limit_value > EQ::skills::HIGHEST_SKILL)
if (effect_value > EQ::skills::HIGHEST_SKILL) {
break;
}
if (effect_value <= EQ::skills::HIGHEST_SKILL){
new_bonus->LimitToSkill[effect_value] = true;
new_bonus->LimitToSkill[EQ::skills::HIGHEST_SKILL + 3] = true; //Used as a general exists check
}
break;
}
case SE_SkillProc:{
case SE_SkillProcAttempt:{
for(int e = 0; e < MAX_SKILL_PROCS; e++)
{
@@ -3552,6 +3595,21 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
break;
}
case SE_SkillAttackProc: {
for (int i = 0; i < MAX_CAST_ON_SKILL_USE; i += 3) {
if (!new_bonus->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID]) { // spell id
new_bonus->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SPELL_ID] = max_value; // spell to proc
new_bonus->SkillAttackProc[i + SBIndex::SKILLATK_PROC_CHANCE] = effect_value; // Chance base 1000 = 100% proc rate
new_bonus->SkillAttackProc[i + SBIndex::SKILLATK_PROC_SKILL] = limit_value; // Skill to Proc Offr
if (limit_value < EQ::skills::HIGHEST_SKILL) {
new_bonus->HasSkillAttackProc[limit_value] = true; //check first before looking for any effects.
}
break;
}
}
}
case SE_PC_Pet_Rampage: {
new_bonus->PC_Pet_Rampage[SBIndex::PET_RAMPAGE_CHANCE] += effect_value; //Chance to rampage
if (new_bonus->PC_Pet_Rampage[SBIndex::PET_RAMPAGE_DMG_MOD] < limit_value)
@@ -3774,6 +3832,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
new_bonus->CompleteHealBuffBlocker = true;
break;
case SE_TrapCircumvention:
new_bonus->TrapCircumvention += effect_value;
break;
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
if (IsAISpellEffect) {
@@ -4088,9 +4150,9 @@ uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_eff
case SE_Fc_ResistIncoming:
focusFcResistIncoming;
case SE_Fc_Amplify_Mod:
focusFcResistIncoming;
focusFcAmplifyMod;
case SE_Fc_Amplify_Amt:
focusFcResistIncoming;
focusFcAmplifyAmt;
case SE_SpellHateMod:
return focusSpellHateMod;
case SE_ReduceReuseTimer:
@@ -5374,9 +5436,9 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
if (negate_spellbonus) { spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value; }
if (negate_aabonus) { aabonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value; }
if (negate_itembonus) { itembonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_MAX] = effect_value; }
if (negate_spellbonus) { spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = effect_value; }
if (negate_aabonus) { aabonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = effect_value; }
if (negate_itembonus) { itembonuses.FinishingBlowLvl[SBIndex::FINISHING_EFFECT_LEVEL_CHANCE_BONUS] = effect_value; }
if (negate_spellbonus) { spellbonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = effect_value; }
if (negate_aabonus) { aabonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = effect_value; }
if (negate_itembonus) { itembonuses.FinishingBlowLvl[SBIndex::FINISHING_BLOW_LEVEL_HP_RATIO] = effect_value; }
break;
case SE_Sanctuary:
@@ -5390,9 +5452,9 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
break;
case SE_IllusionPersistence:
if (negate_spellbonus) { spellbonuses.IllusionPersistence = false; }
if (negate_itembonus) { itembonuses.IllusionPersistence = false; }
if (negate_aabonus) { aabonuses.IllusionPersistence = false; }
if (negate_spellbonus) { spellbonuses.IllusionPersistence = effect_value; }
if (negate_itembonus) { itembonuses.IllusionPersistence = effect_value; }
if (negate_aabonus) { aabonuses.IllusionPersistence = effect_value; }
break;
case SE_Attack_Accuracy_Max_Percent:
@@ -5503,7 +5565,7 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
}
}
case SE_SkillProc: {
case SE_SkillProcAttempt: {
for (int e = 0; e < MAX_SKILL_PROCS; e++)
{
if (negate_spellbonus) { spellbonuses.SkillProc[e] = effect_value; }
+13 -6
View File
@@ -3248,7 +3248,7 @@ void Bot::AI_Process()
TriggerDefensiveProcs(tar, EQ::invslot::slotPrimary, false);
TEST_COMBATANTS();
TryWeaponProc(p_item, tar, EQ::invslot::slotPrimary);
TryCombatProcs(p_item, tar, EQ::invslot::slotPrimary);
// bool tripleSuccess = false;
@@ -3337,7 +3337,7 @@ void Bot::AI_Process()
Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand
TEST_COMBATANTS();
TryWeaponProc(s_item, tar, EQ::invslot::slotSecondary);
TryCombatProcs(s_item, tar, EQ::invslot::slotSecondary);
TEST_COMBATANTS();
if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) {
@@ -4906,7 +4906,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
my_hit.tohit = GetTotalToHit(my_hit.skill, hit_chance_bonus);
DoAttack(other, my_hit, opts);
DoAttack(other, my_hit, opts, FromRiposte);
LogCombat("Final damage after all reductions: [{}]", my_hit.damage_done);
} else {
@@ -7349,7 +7349,7 @@ void Bot::GenerateSpecialAttacks() {
bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQ::spells::CastingSlot slot, bool& stopLogic) {
if(GetClass() == BARD) {
if(!ApplyNextBardPulse(bardsong, this, bardsong_slot))
if(!ApplyBardPulse(bardsong, this, bardsong_slot))
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
stopLogic = true;
@@ -9549,8 +9549,15 @@ bool Bot::UseDiscipline(uint32 spell_id, uint32 target) {
if(spells[spell_id].timer_id > 0 && spells[spell_id].timer_id < MAX_DISCIPLINE_TIMERS)
SetDisciplineRecastTimer(spells[spell_id].timer_id, spell.recast_time);
} else {
uint32 remain = (GetDisciplineRemainingTime(this, spells[spell_id].timer_id) / 1000);
GetOwner()->Message(Chat::White, "%s can use this discipline in %d minutes %d seconds.", GetCleanName(), (remain / 60), (remain % 60));
uint32 remaining_time = (GetDisciplineRemainingTime(this, spells[spell_id].timer_id) / 1000);
GetOwner()->Message(
Chat::White,
fmt::format(
"{} can use this discipline in {}.",
GetCleanName(),
ConvertSecondsToTime(remaining_time)
).c_str()
);
return false;
}
}
+60 -39
View File
@@ -1652,47 +1652,68 @@ int bot_command_real_dispatch(Client *c, const char *message)
void bot_command_log_command(Client *c, const char *message)
{
int admin = c->Admin();
int admin = c->Admin();
bool continueevents = false;
switch (zone->loglevelvar) { //catch failsafe
case 9: // log only LeadGM
if ((admin >= 150) && (admin <200))
switch (zone->loglevelvar){ //catch failsafe
case 9: { // log only LeadGM
if (
admin >= AccountStatus::GMLeadAdmin &&
admin < AccountStatus::GMMgmt
) {
continueevents = true;
}
break;
}
case 8: { // log only GM
if (
admin >= AccountStatus::GMAdmin &&
admin < AccountStatus::GMLeadAdmin
) {
continueevents = true;
}
break;
}
case 1: {
if (admin >= AccountStatus::GMMgmt) {
continueevents = true;
}
break;
}
case 2: {
if (admin >= AccountStatus::GMLeadAdmin) {
continueevents = true;
}
break;
}
case 3: {
if (admin >= AccountStatus::GMAdmin) {
continueevents = true;
}
break;
}
case 4: {
if (admin >= AccountStatus::QuestTroupe) {
continueevents = true;
}
break;
}
case 5: {
if (admin >= AccountStatus::ApprenticeGuide) {
continueevents = true;
}
break;
}
case 6: {
if (admin >= AccountStatus::Steward) {
continueevents = true;
}
break;
}
case 7: {
continueevents = true;
break;
case 8: // log only GM
if ((admin >= 100) && (admin <150))
continueevents = true;
break;
case 1:
if ((admin >= 200))
continueevents = true;
break;
case 2:
if ((admin >= 150))
continueevents = true;
break;
case 3:
if ((admin >= 100))
continueevents = true;
break;
case 4:
if ((admin >= 80))
continueevents = true;
break;
case 5:
if ((admin >= 20))
continueevents = true;
break;
case 6:
if ((admin >= 10))
continueevents = true;
break;
case 7:
continueevents = true;
break;
default:
break;
break;
}
}
if (continueevents)
@@ -3382,7 +3403,7 @@ void bot_command_heal_rotation(Client *c, const Seperator *sep)
return;
#if (EQDEBUG >= 12)
while (c->Admin() >= 250) {
while (c->Admin() >= AccountStatus::GMImpossible) {
if (strcasecmp(sep->arg[1], "shone")) { break; }
Bot* my_bot = ActionableBots::AsTarget_ByBot(c);
if (!my_bot || !(my_bot->IsHealRotationMember())) { break; }
+236 -147
View File
@@ -145,7 +145,6 @@ Client::Client(EQStreamInterface* ieqs)
global_channel_timer(1000),
fishing_timer(8000),
endupkeep_timer(1000),
forget_timer(0),
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)),
client_zone_wide_full_position_update_timer(5 * 60 * 1000),
@@ -154,6 +153,7 @@ Client::Client(EQStreamInterface* ieqs)
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),
charm_update_timer(6000),
rest_timer(1),
pick_lock_timer(1000),
charm_class_attacks_timer(3000),
charm_cast_timer(3500),
qglobal_purge_timer(30000),
@@ -185,7 +185,6 @@ Client::Client(EQStreamInterface* ieqs)
character_id = 0;
conn_state = NoPacketsReceived;
client_data_loaded = false;
feigned = false;
berserk = false;
dead = false;
eqs = ieqs;
@@ -200,7 +199,7 @@ Client::Client(EQStreamInterface* ieqs)
TrackingID = 0;
WID = 0;
account_id = 0;
admin = 0;
admin = AccountStatus::Player;
lsaccountid = 0;
guild_id = GUILD_NONE;
guildrank = 0;
@@ -270,6 +269,8 @@ Client::Client(EQStreamInterface* ieqs)
if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true, false);
dynamiczone_removal_timer.Disable();
heroforge_wearchange_timer.Disable();
//for good measure:
memset(&m_pp, 0, sizeof(m_pp));
memset(&m_epp, 0, sizeof(m_epp));
@@ -1013,7 +1014,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
else
return;
}
if(worldserver.IsOOCMuted() && admin < 100)
if(worldserver.IsOOCMuted() && admin < AccountStatus::GMAdmin)
{
Message(0,"OOC has been muted. Try again later.");
return;
@@ -1052,7 +1053,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
}
case ChatChannel_Broadcast: /* Broadcast */
case ChatChannel_GMSAY: { /* GM Say */
if (!(admin >= 80))
if (!(admin >= AccountStatus::QuestTroupe))
Message(0, "Error: Only GMs can use this channel");
else if (!worldserver.SendChannelMessage(this, targetname, chan_num, 0, language, lang_skill, message))
Message(0, "Error: World server disconnected");
@@ -1230,7 +1231,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
}
void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...) {
if ((chan_num==11 && !(this->GetGM())) || (chan_num==10 && this->Admin()<80)) // dont need to send /pr & /petition to everybody
if ((chan_num==11 && !(this->GetGM())) || (chan_num==10 && this->Admin() < AccountStatus::QuestTroupe)) // dont need to send /pr & /petition to everybody
return;
va_list argptr;
char buffer[4096];
@@ -1869,9 +1870,7 @@ void Client::CheckManaEndUpdate() {
mana_change->stamina = current_endurance;
mana_change->spell_id = casting_spell_id;
mana_change->keepcasting = 1;
mana_change->padding[0] = 0;
mana_change->padding[1] = 0;
mana_change->padding[2] = 0;
mana_change->slot = -1;
outapp->priority = 6;
QueuePacket(outapp);
safe_delete(outapp);
@@ -2076,7 +2075,13 @@ bool Client::ChangeFirstName(const char* in_firstname, const char* gmname)
void Client::SetGM(bool toggle) {
m_pp.gm = toggle ? 1 : 0;
m_inv.SetGMInventory((bool)m_pp.gm);
Message(Chat::Red, "You are %s a GM.", m_pp.gm ? "now" : "no longer");
Message(
Chat::White,
fmt::format(
"You are {} flagged as a GM.",
m_pp.gm ? "now" : "no longer"
).c_str()
);
SendAppearancePacket(AT_GM, m_pp.gm);
Save();
UpdateWho();
@@ -2417,7 +2422,7 @@ bool Client::CheckIncreaseSkill(EQ::skills::SkillType skillid, Mob *against_who,
return false;
if (skillid > EQ::skills::HIGHEST_SKILL)
return false;
int skillval = GetRawSkill(skillid);
int skillval = GetRawSkill(skillid);
int maxskill = GetMaxSkillAfterSpecializationRules(skillid, MaxSkill(skillid));
std::string export_string = fmt::format(
"{} {}",
@@ -2442,23 +2447,26 @@ bool Client::CheckIncreaseSkill(EQ::skills::SkillType skillid, Mob *against_who,
// Make sure we're not already at skill cap
if (skillval < maxskill)
{
// the higher your current skill level, the harder it is
int32 Chance = 10 + chancemodi + ((252 - skillval) / 20);
Chance = (Chance * RuleI(Character, SkillUpModifier) / 100);
Chance = mod_increase_skill_chance(Chance, against_who);
if(Chance < 1)
Chance = 1; // Make it always possible
double Chance = 0;
if (RuleI(Character, SkillUpMaximumChancePercentage) + chancemodi - RuleI(Character, SkillUpMinimumChancePercentage) <= RuleI(Character, SkillUpMinimumChancePercentage)) {
Chance = RuleI(Character, SkillUpMinimumChancePercentage);
}
else {
// f(x) = (max - min + modification) * .99^skillval + min
// This results in a exponential decay where as you skill up, you lose a slight chance to skill up, ranging from your modified maximum to approaching your minimum
// This result is increased by the existing SkillUpModifier rule
double working_chance = (((RuleI(Character, SkillUpMaximumChancePercentage) - RuleI(Character, SkillUpMinimumChancePercentage) + chancemodi) * (pow(0.99, skillval))) + RuleI(Character, SkillUpMinimumChancePercentage));
Chance = (working_chance * RuleI(Character, SkillUpModifier) / 100);
Chance = mod_increase_skill_chance(Chance, against_who);
}
if(zone->random.Real(0, 99) < Chance)
{
SetSkill(skillid, GetRawSkill(skillid) + 1);
LogSkills("Skill [{}] at value [{}] successfully gain with [{}]% chance (mod [{}])", skillid, skillval, Chance, chancemodi);
LogSkills("Skill [{}] at value [{}] successfully gain with [{}] chance (mod [{}])", skillid, skillval, Chance, chancemodi);
return true;
} else {
LogSkills("Skill [{}] at value [{}] failed to gain with [{}]% chance (mod [{}])", skillid, skillval, Chance, chancemodi);
LogSkills("Skill [{}] at value [{}] failed to gain with [{}] chance (mod [{}])", skillid, skillval, Chance, chancemodi);
}
} else {
LogSkills("Skill [{}] at value [{}] cannot increase due to maxmum [{}]", skillid, skillval, maxskill);
@@ -2613,10 +2621,11 @@ void Client::SetPVP(bool toggle, bool message) {
m_pp.pvp = toggle ? 1 : 0;
if (message) {
if(GetPVP())
this->MessageString(Chat::Shout,PVP_ON);
else
Message(Chat::Red, "You no longer follow the ways of discord.");
if(GetPVP()) {
MessageString(Chat::Shout, PVP_ON);
} else {
Message(Chat::Shout, "You now follow the ways of Order.");
}
}
SendAppearancePacket(AT_PVP, GetPVP());
@@ -2647,44 +2656,28 @@ void Client::GMKill() {
}
bool Client::CheckAccess(int16 iDBLevel, int16 iDefaultLevel) {
if ((admin >= iDBLevel) || (iDBLevel == 255 && admin >= iDefaultLevel))
if ((admin >= iDBLevel) || (iDBLevel == AccountStatus::Max && admin >= iDefaultLevel))
return true;
else
return false;
}
void Client::MemorizeSpell(uint32 slot,uint32 spellid,uint32 scribing){
void Client::MemorizeSpell(uint32 slot,uint32 spellid,uint32 scribing, uint32 reduction){
if (slot < 0 || slot >= EQ::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize)
return;
if ((spellid < 3 || spellid > EQ::spells::DynamicLookup(ClientVersion(), GetGM())->SpellIdMax) && spellid != 0xFFFFFFFF)
return;
auto outapp = new EQApplicationPacket(OP_MemorizeSpell, sizeof(MemorizeSpell_Struct));
MemorizeSpell_Struct* mss=(MemorizeSpell_Struct*)outapp->pBuffer;
mss->scribing=scribing;
mss->slot=slot;
mss->spell_id=spellid;
mss->reduction = reduction;
outapp->priority = 5;
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::SetFeigned(bool in_feigned) {
if (in_feigned)
{
if(RuleB(Character, FeignKillsPet))
{
SetPet(0);
}
SetHorseId(0);
entity_list.ClearFeignAggro(this);
forget_timer.Start(FeignMemoryDuration);
} else {
forget_timer.Disable();
}
feigned=in_feigned;
}
void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQ::ItemData* item, bool buying)
{
if(!player || !merchant || !item)
@@ -3460,7 +3453,7 @@ uint8 Client::SlotConvert2(uint8 slot){
void Client::Escape()
{
entity_list.RemoveFromTargets(this, true);
SetInvisible(1);
SetInvisible(Invisibility::Invisible);
MessageString(Chat::Skills, ESCAPE);
}
@@ -3471,7 +3464,7 @@ float Client::CalcPriceMod(Mob* other, bool reverse)
if (other)
{
int factionlvl = GetFactionLevel(CharacterID(), other->CastToNPC()->GetNPCTypeID(), GetFactionRace(), GetClass(), GetDeity(), other->CastToNPC()->GetPrimaryFaction(), other);
if (factionlvl >= FACTION_APPREHENSIVE) // Apprehensive or worse.
if (factionlvl >= FACTION_APPREHENSIVELY) // Apprehensive or worse.
{
if (GetCHA() > 103)
{
@@ -3486,7 +3479,7 @@ float Client::CalcPriceMod(Mob* other, bool reverse)
chaformula = 1*(RuleI(Merchant, PricePenaltyPct));
}
}
if (factionlvl <= FACTION_INDIFFERENT) // Indifferent or better.
if (factionlvl <= FACTION_INDIFFERENTLY) // Indifferent or better.
{
if (GetCHA() > 75)
{
@@ -5321,31 +5314,72 @@ uint32 Client::GetStartZone()
void Client::ShowSkillsWindow()
{
const char *WindowTitle = "Skills";
std::string WindowText;
std::map<EQ::skills::SkillType, std::string> Skills = EQ::skills::GetSkillTypeMap();
std::string popup_text;
std::map<EQ::skills::SkillType, std::string> skills_map = EQ::skills::GetSkillTypeMap();
if (ClientVersion() < EQ::versions::ClientVersion::RoF2)
Skills[EQ::skills::Skill1HPiercing] = "Piercing";
// print out all available skills
for (auto skills_iter : Skills) {
if (skills_iter.first == EQ::skills::Skill2HPiercing && ClientVersion() < EQ::versions::ClientVersion::RoF2)
continue;
if (!GetSkill(skills_iter.first) && !MaxSkill(skills_iter.first))
continue;
WindowText += skills_iter.second;
// line up the values
WindowText += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
WindowText += itoa(this->GetSkill(skills_iter.first));
if (MaxSkill(skills_iter.first) > 0) {
WindowText += "/";
WindowText += itoa(this->GetMaxSkillAfterSpecializationRules(skills_iter.first, this->MaxSkill(skills_iter.first)));
}
WindowText += "<br>";
if (ClientVersion() < EQ::versions::ClientVersion::RoF2) {
skills_map[EQ::skills::Skill1HPiercing] = "Piercing";
}
this->SendPopupToClient(WindowTitle, WindowText.c_str());
// Table Start
popup_text += "<table>";
for (const auto& skill : skills_map) {
auto skill_id = skill.first;
auto skill_name = skill.second;
auto can_have_skill = CanHaveSkill(skill_id);
auto current_skill = GetSkill(skill_id);
auto max_skill = MaxSkill(skill_id);
auto skill_maxed = current_skill >= max_skill;
if (
skill_id == EQ::skills::Skill2HPiercing &&
ClientVersion() < EQ::versions::ClientVersion::RoF2
) {
continue;
}
if (
!can_have_skill ||
!current_skill ||
!max_skill
) {
continue;
}
// Row Start
popup_text += "<tr>";
// Skill Name
popup_text += fmt::format(
"<td>{}</td>",
skill_name
);
// Current Skill Level out of Max Skill Level or a Check Mark for Maxed
popup_text += fmt::format(
"<td>{}</td>",
(
skill_maxed ?
"<c \"#00FF00\">✔</c>" :
fmt::format(
"{}/{}",
current_skill,
max_skill
)
)
);
// Row End
popup_text += "</tr>";
}
// Table End
popup_text += "</table>";
SendPopupToClient(
"Skills",
popup_text.c_str()
);
}
void Client::Signal(uint32 data)
@@ -6228,36 +6262,44 @@ void Client::LocateCorpse()
void Client::NPCSpawn(NPC *target_npc, const char *identifier, uint32 extra)
{
if (!target_npc || !identifier)
if (!target_npc || !identifier) {
return;
std::string id = identifier;
for(int i = 0; i < id.length(); ++i)
{
id[i] = tolower(id[i]);
}
if (id == "create") {
// extra tries to create the npc_type ID within the range for the current zone (zone_id * 1000)
content_db.NPCSpawnDB(0, zone->GetShortName(), zone->GetInstanceVersion(), this, target_npc->CastToNPC(), extra);
}
else if (id == "add") {
// extra sets the respawn timer for add
content_db.NPCSpawnDB(1, zone->GetShortName(), zone->GetInstanceVersion(), this, target_npc->CastToNPC(), extra);
}
else if (id == "update") {
content_db.NPCSpawnDB(2, zone->GetShortName(), zone->GetInstanceVersion(), this, target_npc->CastToNPC());
}
else if (id == "remove") {
content_db.NPCSpawnDB(3, zone->GetShortName(), zone->GetInstanceVersion(), this, target_npc->CastToNPC());
target_npc->Depop(false);
}
else if (id == "delete") {
content_db.NPCSpawnDB(4, zone->GetShortName(), zone->GetInstanceVersion(), this, target_npc->CastToNPC());
target_npc->Depop(false);
}
else {
return;
std::string spawn_type = str_tolower(identifier);
bool is_add = spawn_type.find("add") != std::string::npos;
bool is_create = spawn_type.find("create") != std::string::npos;
bool is_delete = spawn_type.find("delete") != std::string::npos;
bool is_remove = spawn_type.find("remove") != std::string::npos;
bool is_update = spawn_type.find("update") != std::string::npos;
if (is_add || is_create) {
// Add: extra tries to create the NPC ID within the range for the current Zone (Zone ID * 1000)
// Create: extra sets the Respawn Timer for add
content_db.NPCSpawnDB(
is_add ? NPCSpawnTypes::AddNewSpawngroup : NPCSpawnTypes::CreateNewSpawn,
zone->GetShortName(),
zone->GetInstanceVersion(),
this,
target_npc->CastToNPC(),
extra
);
} else if (is_delete || is_remove || is_update) {
uint8 spawn_update_type = (
is_delete ?
NPCSpawnTypes::DeleteSpawn :
(
is_remove ?
NPCSpawnTypes::RemoveSpawn :
NPCSpawnTypes::UpdateAppearance
)
);
content_db.NPCSpawnDB(
spawn_update_type,
zone->GetShortName(),
zone->GetInstanceVersion(),
this,
target_npc->CastToNPC()
);
}
}
@@ -6443,11 +6485,12 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
swarm_pet_npc->StartSwarmTimer(pet_duration * 1000);
swarm_pet_npc->GetSwarmInfo()->owner_id = GetID();
swarm_pet_npc->SetFollowID(GetID());
// Give the pets alittle more agro than the caster and then agro them on the target
target->AddToHateList(swarm_pet_npc, (target->GetHateAmount(this) + 100), (target->GetDamageAmount(this) + 100));
swarm_pet_npc->AddToHateList(target, 1000, 1000);
swarm_pet_npc->GetSwarmInfo()->target = target->GetID();
swarm_pet_npc->GetSwarmInfo()->target = 0;
//we allocated a new NPC type object, give the NPC ownership of that memory
if(npc_dup != nullptr)
@@ -6882,7 +6925,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
for (auto iter = item_faction_bonuses.begin(); iter != item_faction_bonuses.end(); ++iter) {
memset(&faction_buf, 0, sizeof(faction_buf));
if(!content_db.GetFactionName((int32)((*iter).first), faction_buf, sizeof(faction_buf)))
if(!content_db.GetFactionName((int)((*iter).first), faction_buf, sizeof(faction_buf)))
strcpy(faction_buf, "Not in DB");
if((*iter).second > 0) {
@@ -6999,7 +7042,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
Extra_Info:
client->Message(Chat::White, " BaseRace: %i Gender: %i BaseGender: %i Texture: %i HelmTexture: %i", GetBaseRace(), GetGender(), GetBaseGender(), GetTexture(), GetHelmTexture());
if (client->Admin() >= 100) {
if (client->Admin() >= AccountStatus::GMAdmin) {
client->Message(Chat::White, " CharID: %i EntityID: %i PetID: %i OwnerID: %i AIControlled: %i Targetted: %i", CharacterID(), GetID(), GetPetID(), GetOwnerID(), IsAIControlled(), targeted);
}
}
@@ -7018,23 +7061,16 @@ void Client::SendAltCurrencies() {
altc->opcode = ALT_CURRENCY_OP_POPULATE;
altc->count = count;
uint32 i = 0;
auto iter = zone->AlternateCurrencies.begin();
while(iter != zone->AlternateCurrencies.end()) {
const EQ::ItemData* item = database.GetItem((*iter).item_id);
altc->entries[i].currency_number = (*iter).id;
altc->entries[i].unknown00 = 1;
altc->entries[i].currency_number2 = (*iter).id;
altc->entries[i].item_id = (*iter).item_id;
if(item) {
altc->entries[i].item_icon = item->Icon;
altc->entries[i].stack_size = item->StackSize;
} else {
altc->entries[i].item_icon = 1000;
altc->entries[i].stack_size = 1000;
}
i++;
++iter;
uint32 currency_id = 0;
for (const auto& alternate_currency : zone->AlternateCurrencies) {
const EQ::ItemData* item = database.GetItem(alternate_currency.item_id);
altc->entries[currency_id].currency_number = alternate_currency.id;
altc->entries[currency_id].unknown00 = 1;
altc->entries[currency_id].currency_number2 = alternate_currency.id;
altc->entries[currency_id].item_id = alternate_currency.item_id;
altc->entries[currency_id].item_icon = item ? item->Icon : 1000;
altc->entries[currency_id].stack_size = item ? item->StackSize : 1000;
currency_id++;
}
FastQueuePacket(&outapp);
@@ -7089,10 +7125,8 @@ void Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 me
void Client::SendAlternateCurrencyValues()
{
auto iter = zone->AlternateCurrencies.begin();
while(iter != zone->AlternateCurrencies.end()) {
SendAlternateCurrencyValue((*iter).id, false);
++iter;
for (const auto& alternate_currency : zone->AlternateCurrencies) {
SendAlternateCurrencyValue(alternate_currency.id, false);
}
}
@@ -7396,7 +7430,7 @@ void Client::ProcessXTargetAutoHaters()
std::queue<int> empty_slots;
for (int i = 0; i < GetMaxXTargets(); ++i) {
if (XTargets[i].Type != Auto)
continue;
continue;
if (XTargets[i].ID != 0 && !GetXTargetAutoMgr()->contains_mob(XTargets[i].ID)) {
XTargets[i].ID = 0;
@@ -7435,6 +7469,7 @@ void Client::ProcessXTargetAutoHaters()
break;
}
}
m_dirtyautohaters = false;
SendXTargetUpdates();
}
@@ -7801,7 +7836,7 @@ FACTION_VALUE Client::GetReverseFactionCon(Mob* iOther) {
return GetSpecialFactionCon(iOther);
if (iOther->GetPrimaryFaction() == 0)
return FACTION_INDIFFERENT;
return FACTION_INDIFFERENTLY;
return GetFactionLevel(CharacterID(), 0, GetFactionRace(), GetClass(), GetDeity(), iOther->GetPrimaryFaction(), iOther);
}
@@ -7824,25 +7859,25 @@ FACTION_VALUE Client::GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_ra
{
if (pFaction < 0)
return GetSpecialFactionCon(tnpc);
FACTION_VALUE fac = FACTION_INDIFFERENT;
FACTION_VALUE fac = FACTION_INDIFFERENTLY;
int32 tmpFactionValue;
FactionMods fmods;
// few optimizations
if (GetFeigned())
return FACTION_INDIFFERENT;
return FACTION_INDIFFERENTLY;
if(!zone->CanDoCombat())
return FACTION_INDIFFERENT;
return FACTION_INDIFFERENTLY;
if (invisible_undead && tnpc && !tnpc->SeeInvisibleUndead())
return FACTION_INDIFFERENT;
return FACTION_INDIFFERENTLY;
if (IsInvisible(tnpc))
return FACTION_INDIFFERENT;
return FACTION_INDIFFERENTLY;
if (tnpc && tnpc->GetOwnerID() != 0) // pets con amiably to owner and indiff to rest
{
if (char_id == tnpc->GetOwner()->CastToClient()->CharacterID())
return FACTION_AMIABLE;
return FACTION_AMIABLY;
else
return FACTION_INDIFFERENT;
return FACTION_INDIFFERENTLY;
}
//First get the NPC's Primary faction
@@ -7862,15 +7897,15 @@ FACTION_VALUE Client::GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_ra
}
else
{
return(FACTION_INDIFFERENT);
return(FACTION_INDIFFERENTLY);
}
// merchant fix
if (tnpc && tnpc->IsNPC() && tnpc->CastToNPC()->MerchantType && (fac == FACTION_THREATENLY || fac == FACTION_SCOWLS))
fac = FACTION_DUBIOUS;
if (tnpc && tnpc->IsNPC() && tnpc->CastToNPC()->MerchantType && (fac == FACTION_THREATENINGLY || fac == FACTION_SCOWLS))
fac = FACTION_DUBIOUSLY;
if (tnpc != 0 && fac != FACTION_SCOWLS && tnpc->CastToNPC()->CheckAggro(this))
fac = FACTION_THREATENLY;
fac = FACTION_THREATENINGLY;
return fac;
}
@@ -8493,7 +8528,7 @@ void Client::Consume(const EQ::ItemData *item, uint8 type, int16 slot, bool auto
LogFood("Consuming food, points added to hunger_level: [{}] - current_hunger: [{}]", increase, m_pp.hunger_level);
DeleteItemInInventory(slot, 1, false);
DeleteItemInInventory(slot, 1);
if (!auto_consume) // no message if the client consumed for us
entity_list.MessageCloseString(this, true, 50, 0, EATING_MESSAGE, GetName(), item->Name);
@@ -8508,7 +8543,7 @@ void Client::Consume(const EQ::ItemData *item, uint8 type, int16 slot, bool auto
m_pp.thirst_level += increase;
DeleteItemInInventory(slot, 1, false);
DeleteItemInInventory(slot, 1);
LogFood("Consuming drink, points added to thirst_level: [{}] current_thirst: [{}]", increase, m_pp.thirst_level);
@@ -8558,14 +8593,25 @@ void Client::ExpeditionSay(const char *str, int ExpID) {
return;
if(results.RowCount() == 0) {
this->Message(Chat::Lime, "You say to the expedition, '%s'", str);
Message(Chat::Lime, "You say to the expedition, '%s'", str);
return;
}
for(auto row = results.begin(); row != results.end(); ++row) {
const char* charName = row[0];
if(strcmp(charName, this->GetCleanName()) != 0)
worldserver.SendEmoteMessage(charName, 0, 0, 14, "%s says to the expedition, '%s'", this->GetCleanName(), str);
if(strcmp(charName, GetCleanName()) != 0) {
worldserver.SendEmoteMessage(
charName,
0,
AccountStatus::Player,
Chat::Lime,
fmt::format(
"{} says to the expedition, '{}'",
GetCleanName(),
str
).c_str()
);
}
// ChannelList->CreateChannel(ChannelName, ChannelOwner, ChannelPassword, true, atoi(row[3]));
}
@@ -8635,7 +8681,7 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold,
if (faction)
{
if (target && target->IsNPC())
if (target && target->IsNPC() && !target->IsCharmed())
{
int32 nfl_id = target->CastToNPC()->GetNPCFactionID();
SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true);
@@ -8671,7 +8717,7 @@ void Client::QuestReward(Mob* target, const QuestReward_Struct &reward, bool fac
if (faction)
{
if (target && target->IsNPC())
if (target && target->IsNPC() && !target->IsCharmed())
{
int32 nfl_id = target->CastToNPC()->GetNPCFactionID();
SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true);
@@ -9388,7 +9434,7 @@ void Client::CheckVirtualZoneLines()
LogZonePoints(
"Virtual Zone Box Sending player [{}] to [{}]",
GetCleanName(),
zone_store.GetZoneLongName(virtual_zone_point.target_zone_id)
ZoneLongName(virtual_zone_point.target_zone_id)
);
}
}
@@ -10266,7 +10312,7 @@ void Client::RemoveItem(uint32 item_id, uint32 quantity)
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
};
int removed_count = 0;
int16 removed_count = 0;
const size_t size = sizeof(slots) / sizeof(slots[0]);
for (int slot_index = 0; slot_index < size; ++slot_index) {
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
@@ -10276,13 +10322,13 @@ void Client::RemoveItem(uint32 item_id, uint32 quantity)
item = GetInv().GetItem(slot_id);
if (item && item->GetID() == item_id) {
int charges = item->IsStackable() ? item->GetCharges() : 0;
int stack_size = std::max(charges, 1);
int16 charges = item->IsStackable() ? item->GetCharges() : 0;
int16 stack_size = std::max(charges, static_cast<int16>(1));
if ((removed_count + stack_size) <= quantity) {
removed_count += stack_size;
DeleteItemInInventory(slot_id, charges, true);
} else {
int amount_left = (quantity - removed_count);
int16 amount_left = (quantity - removed_count);
if (amount_left > 0 && stack_size >= amount_left) {
removed_count += amount_left;
DeleteItemInInventory(slot_id, amount_left, true);
@@ -10810,3 +10856,46 @@ uint16 Client::LearnDisciplines(uint8 min_level, uint8 max_level)
return learned_disciplines;
}
uint16 Client::GetClassTrackingDistanceMultiplier(uint16 class_) {
switch (class_) {
case WARRIOR:
return RuleI(Character, WarriorTrackingDistanceMultiplier);
case CLERIC:
return RuleI(Character, ClericTrackingDistanceMultiplier);
case PALADIN:
return RuleI(Character, PaladinTrackingDistanceMultiplier);
case RANGER:
return RuleI(Character, RangerTrackingDistanceMultiplier);
case SHADOWKNIGHT:
return RuleI(Character, ShadowKnightTrackingDistanceMultiplier);
case DRUID:
return RuleI(Character, DruidTrackingDistanceMultiplier);
case MONK:
return RuleI(Character, MonkTrackingDistanceMultiplier);
case BARD:
return RuleI(Character, BardTrackingDistanceMultiplier);
case ROGUE:
return RuleI(Character, RogueTrackingDistanceMultiplier);
case SHAMAN:
return RuleI(Character, ShamanTrackingDistanceMultiplier);
case NECROMANCER:
return RuleI(Character, NecromancerTrackingDistanceMultiplier);
case WIZARD:
return RuleI(Character, WizardTrackingDistanceMultiplier);
case MAGICIAN:
return RuleI(Character, MagicianTrackingDistanceMultiplier);
case ENCHANTER:
return RuleI(Character, EnchanterTrackingDistanceMultiplier);
case BEASTLORD:
return RuleI(Character, BeastlordTrackingDistanceMultiplier);
case BERSERKER:
return RuleI(Character, BerserkerTrackingDistanceMultiplier);
default:
return 0;
}
}
bool Client::CanThisClassTrack() {
return (GetClassTrackingDistanceMultiplier(GetClass()) > 0) ? true : false;
}
+33 -14
View File
@@ -301,8 +301,8 @@ public:
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
uint32 FindTraderItemSerialNumber(int32 ItemID);
EQ::ItemInstance* FindTraderItemBySerialNumber(int32 SerialNumber);
void FindAndNukeTraderItem(int32 item_id,uint16 quantity,Client* customer,uint16 traderslot);
void NukeTraderItem(uint16 slot, int16 charges, uint16 quantity, Client* customer, uint16 traderslot, int32 uniqueid, int32 itemid = 0);
void FindAndNukeTraderItem(int32 item_id,int16 quantity,Client* customer,uint16 traderslot);
void NukeTraderItem(uint16 slot, int16 charges, int16 quantity, Client* customer, uint16 traderslot, int32 uniqueid, int32 itemid = 0);
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
void TradeRequestFailed(const EQApplicationPacket* app);
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
@@ -783,16 +783,18 @@ public:
void GMKill();
inline bool IsMedding() const {return medding;}
inline uint16 GetDuelTarget() const { return duel_target; }
inline uint32 GetDuelTarget() const { return duel_target; }
inline bool IsDueling() const { return duelaccepted; }
inline void SetDuelTarget(uint16 set_id) { duel_target=set_id; }
inline void SetDuelTarget(uint32 set_id) { duel_target = set_id; }
inline void SetDueling(bool duel) { duelaccepted = duel; }
// use this one instead
void MemSpell(uint16 spell_id, int slot, bool update_client = true);
void UnmemSpell(int slot, bool update_client = true);
void UnmemSpellBySpellID(int32 spell_id);
void UnmemSpellAll(bool update_client = true);
int FindEmptyMemSlot();
uint16 FindMemmedSpellBySlot(int slot);
int FindMemmedSpellBySpellID(uint16 spell_id);
int MemmedCount();
std::vector<int> GetLearnableDisciplines(uint8 min_level = 1, uint8 max_level = 0);
std::vector<int> GetLearnedDisciplines();
@@ -808,6 +810,11 @@ public:
uint16 ScribeSpells(uint8 min_level, uint8 max_level);
uint16 LearnDisciplines(uint8 min_level, uint8 max_level);
// Configurable Tracking Skill
uint16 GetClassTrackingDistanceMultiplier(uint16 class_);
bool CanThisClassTrack();
// defer save used when bulk saving
void UnscribeSpell(int slot, bool update_client = true, bool defer_save = false);
void UnscribeSpellAll(bool update_client = true);
@@ -828,9 +835,6 @@ public:
inline uint8 GetBecomeNPCLevel() const { return npclevel; }
inline void SetBecomeNPC(bool flag) { npcflag = flag; }
inline void SetBecomeNPCLevel(uint8 level) { npclevel = level; }
void SetFeigned(bool in_feigned);
/// this cures timing issues cuz dead animation isn't done but server side feigning is?
inline bool GetFeigned() const { return(feigned); }
EQStreamInterface* Connection() { return eqs; }
#ifdef PACKET_PROFILER
void DumpPacketProfile() { if(eqs) eqs->DumpPacketProfile(); }
@@ -847,6 +851,7 @@ public:
void SummonHorse(uint16 spell_id);
void SetHorseId(uint16 horseid_in);
inline void SetControlledMobId(uint16 mob_id_in) { controlled_mob_id = mob_id_in; }
uint16 GetControlledMobId() const{ return controlled_mob_id; }
uint16 GetHorseId() const { return horseId; }
bool CanMedOnHorse();
@@ -897,12 +902,14 @@ public:
void ResetAA();
void RefundAA();
void SendClearAA();
void SendClearLeadershipAA();
void SendClearPlayerAA();
inline uint32 GetAAXP() const { return m_pp.expAA; }
inline uint32 GetAAPercent() const { return m_epp.perAA; }
int32 CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id);
void SetAATitle(const char *Title);
void SetTitleSuffix(const char *txt);
void MemorizeSpell(uint32 slot, uint32 spellid, uint32 scribing);
void MemorizeSpell(uint32 slot, uint32 spellid, uint32 scribing, uint32 reduction = 0);
// Item methods
void EVENT_ITEM_ScriptStopReturn();
@@ -917,7 +924,7 @@ public:
bool PutItemInInventory(int16 slot_id, const EQ::ItemInstance& inst, bool client_update = false);
bool PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update = false);
void SendCursorBuffer();
void DeleteItemInInventory(int16 slot_id, int8 quantity = 0, bool client_update = false, bool update_db = true);
void DeleteItemInInventory(int16 slot_id, int16 quantity = 0, bool client_update = false, bool update_db = true);
int CountItem(uint32 item_id);
void RemoveItem(uint32 item_id, uint32 quantity = 1);
bool SwapItem(MoveItem_Struct* move_in);
@@ -971,7 +978,7 @@ public:
//remove charges/multiple objects from inventory:
//bool DecreaseByType(uint32 type, uint8 amt);
bool DecreaseByID(uint32 type, uint8 amt);
bool DecreaseByID(uint32 type, int16 quantity);
uint8 SlotConvert2(uint8 slot); //Maybe not needed.
void Escape(); //AA Escape
void DisenchantSummonedBags(bool client_update = true);
@@ -1009,6 +1016,10 @@ public:
void SetLinkedSpellReuseTimer(uint32 timer_id, uint32 duration);
bool IsLinkedSpellReuseTimerReady(uint32 timer_id);
void ResetCastbarCooldownBySlot(int slot);
void ResetAllCastbarCooldowns();
void ResetCastbarCooldownBySpellID(uint32 spell_id);
bool CheckTitle(int titleset);
void EnableTitle(int titleset);
@@ -1481,6 +1492,12 @@ public:
bool GroupFollow(Client* inviter);
inline bool GetRunMode() const { return runmode; }
void SendItemRecastTimer(int32 recast_type, uint32 recast_delay = 0);
void SetItemRecastTimer(int32 spell_id, uint32 inventory_slot);
bool HasItemRecastTimer(int32 spell_id, uint32 inventory_slot);
void SetDisciplineRecastTimer(int32 spell_id);
void SetAARecastTimer(AA::Rank *rank_in, int32 spell_id);
inline bool AggroMeterAvailable() const { return ((m_ClientVersionBit & EQ::versions::maskRoF2AndLater)) && RuleB(Character, EnableAggroMeter); } // RoF untested
inline void SetAggroMeterLock(int in) { m_aggrometer.set_lock_id(in); }
@@ -1519,6 +1536,7 @@ public:
void UpdateMercLevel();
void CheckMercSuspendTimer();
Timer* GetMercTimer() { return &merc_timer; };
Timer* GetPickLockTimer() { return &pick_lock_timer; };
const char* GetRacePlural(Client* client);
const char* GetClassPlural(Client* client);
@@ -1553,7 +1571,7 @@ public:
int mod_client_damage(int damage, EQ::skills::SkillType skillinuse, int hand, const EQ::ItemInstance* weapon, Mob* other);
bool mod_client_message(char* message, uint8 chan_num);
bool mod_can_increase_skill(EQ::skills::SkillType skillid, Mob* against_who);
int16 mod_increase_skill_chance(int16 chance, Mob* against_who);
double mod_increase_skill_chance(double chance, Mob* against_who);
int mod_bindwound_percent(int max_percent, Mob* bindmob);
int mod_bindwound_hp(int bindhps, Mob* bindmob);
int mod_client_haste(int h);
@@ -1631,7 +1649,7 @@ protected:
void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true);
bool client_data_loaded;
int32 GetFocusEffect(focusType type, uint16 spell_id);
int32 GetFocusEffect(focusType type, uint16 spell_id, Mob *caster = nullptr);
uint16 GetSympatheticFocusEffect(focusType type, uint16 spell_id);
void FinishAlternateAdvancementPurchase(AA::Rank *rank, bool ignore_cost);
@@ -1835,7 +1853,6 @@ private:
Timer global_channel_timer;
Timer fishing_timer;
Timer endupkeep_timer;
Timer forget_timer; // our 2 min everybody forgets you timer
Timer autosave_timer;
Timer client_scan_npc_aggro_timer;
Timer client_zone_wide_full_position_update_timer;
@@ -1860,7 +1877,10 @@ private:
Timer consent_throttle_timer;
Timer dynamiczone_removal_timer;
Timer task_request_timer;
Timer pick_lock_timer;
Timer heroforge_wearchange_timer;
glm::vec3 m_Proximity;
glm::vec4 last_position_before_bulk_update;
@@ -1872,7 +1892,6 @@ private:
bool npcflag;
uint8 npclevel;
bool feigned;
bool bZoning;
bool tgb;
bool instalog;
+5
View File
@@ -1517,6 +1517,11 @@ uint32 Mob::GetInstrumentMod(uint16 spell_id)
}
return 10;
}
//AA's click effects that use instrument/singing skills don't apply modifiers (Confirmed on live 11/24/21 ~Kayen)
if (casting_spell_aa_id) {
return 10;
}
uint32 effectmod = 10;
int effectmodcap = 0;
+561 -595
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -97,8 +97,8 @@
void Handle_OP_Disarm(const EQApplicationPacket *app);
void Handle_OP_DisarmTraps(const EQApplicationPacket *app);
void Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app);
void Handle_OP_DuelResponse(const EQApplicationPacket *app);
void Handle_OP_DuelResponse2(const EQApplicationPacket *app);
void Handle_OP_DuelDecline(const EQApplicationPacket *app);
void Handle_OP_DuelAccept(const EQApplicationPacket *app);
void Handle_OP_DumpName(const EQApplicationPacket *app);
void Handle_OP_Dye(const EQApplicationPacket *app);
void Handle_OP_DzAddPlayer(const EQApplicationPacket *app);
+30 -7
View File
@@ -199,6 +199,25 @@ bool Client::Process() {
instalog = true;
}
if (heroforge_wearchange_timer.Check()) {
/*
This addresses bug where on zone in heroforge models would not be sent to other clients when this was
in Client::CompleteConnect(). Sending after a small 250 ms delay after that function resolves the issue.
Unclear the underlying reason for this, if a better solution can be found then can move this back.
*/
if (queue_wearchange_slot >= 0) { //Resend slot from Client::SwapItem if heroforge item is swapped.
SendWearChange(static_cast<uint8>(queue_wearchange_slot));
}
else { //Send from Client::CompleteConnect()
SendWearChangeAndLighting(EQ::textures::LastTexture);
Mob *pet = GetPet();
if (pet) {
pet->SendWearChangeAndLighting(EQ::textures::LastTexture);
}
}
heroforge_wearchange_timer.Disable();
}
if (IsStunned() && stunned_timer.Check())
Mob::UnStun();
@@ -219,9 +238,9 @@ bool Client::Process() {
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
}
else {
if (!ApplyNextBardPulse(bardsong, song_target, bardsong_slot))
if (!ApplyBardPulse(bardsong, song_target, bardsong_slot)) {
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
//SpellFinished(bardsong, bardsong_target, bardsong_slot, spells[bardsong].mana);
}
}
}
@@ -302,6 +321,10 @@ bool Client::Process() {
}
if (AutoFireEnabled()) {
if (GetTarget() == this) {
MessageString(Chat::TooFarAway, TRY_ATTACKING_SOMEONE);
auto_fire = false;
}
EQ::ItemInstance *ranged = GetInv().GetItem(EQ::invslot::slotRange);
if (ranged)
{
@@ -391,7 +414,7 @@ bool Client::Process() {
else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP
{
EQ::ItemInstance *wpn = GetInv().GetItem(EQ::invslot::slotPrimary);
TryWeaponProc(wpn, auto_attack_target, EQ::invslot::slotPrimary);
TryCombatProcs(wpn, auto_attack_target, EQ::invslot::slotPrimary);
TriggerDefensiveProcs(auto_attack_target, EQ::invslot::slotPrimary, false);
DoAttackRounds(auto_attack_target, EQ::invslot::slotPrimary);
@@ -401,7 +424,7 @@ bool Client::Process() {
}
if (CheckAATimer(aaTimerRampage)) {
entity_list.AEAttack(this, 30);
entity_list.AEAttack(this, 40);
}
}
}
@@ -437,7 +460,7 @@ bool Client::Process() {
CheckIncreaseSkill(EQ::skills::SkillDualWield, auto_attack_target, -10);
if (CheckDualWield()) {
EQ::ItemInstance *wpn = GetInv().GetItem(EQ::invslot::slotSecondary);
TryWeaponProc(wpn, auto_attack_target, EQ::invslot::slotSecondary);
TryCombatProcs(wpn, auto_attack_target, EQ::invslot::slotSecondary);
DoAttackRounds(auto_attack_target, EQ::invslot::slotSecondary);
}
@@ -533,7 +556,7 @@ bool Client::Process() {
OnDisconnect(true);
LogInfo("Client linkdead: {}", name);
if (Admin() > 100) {
if (Admin() > AccountStatus::GMAdmin) {
if (GetMerc()) {
GetMerc()->Save();
GetMerc()->Depop();
@@ -1729,7 +1752,7 @@ void Client::OPGMSummon(const EQApplicationPacket *app)
}
else
{
if(admin < 80)
if(admin < AccountStatus::QuestTroupe)
{
return;
}
+333 -15087
View File
File diff suppressed because it is too large Load Diff
+36 -43
View File
@@ -1,22 +1,3 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
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 COMMAND_H
#define COMMAND_H
@@ -25,18 +6,18 @@ class Seperator;
#include "../common/types.h"
#define COMMAND_CHAR '#'
#define COMMAND_CHAR '#'
typedef void (*CmdFuncPtr)(Client *,const Seperator *);
typedef void (*CmdFuncPtr)(Client *, const Seperator *);
typedef struct {
int access;
const char *desc; // description of command
CmdFuncPtr function; // null means perl function
} CommandRecord;
int access;
const char *desc; // description of command
CmdFuncPtr function; // null means perl function
} CommandRecord;
extern int (*command_dispatch)(Client *,char const*);
extern int commandcount; // number of commands loaded
extern int (*command_dispatch)(Client *, char const *);
extern int commandcount; // number of commands loaded
// the command system:
int command_init(void);
@@ -53,13 +34,14 @@ void command_aggro(Client *c, const Seperator *sep);
void command_aggrozone(Client *c, const Seperator *sep);
void command_ai(Client *c, const Seperator *sep);
void command_appearance(Client *c, const Seperator *sep);
void command_appearanceeffects(Client *c, const Seperator *sep);
void command_apply_shared_memory(Client *c, const Seperator *sep);
void command_attack(Client *c, const Seperator *sep);
void command_augmentitem(Client *c, const Seperator *sep);
void command_ban(Client *c, const Seperator *sep);
void command_beard(Client *c, const Seperator *sep);
void command_beardcolor(Client *c, const Seperator *sep);
void command_bind(Client* c, const Seperator *sep);
void command_bind(Client *c, const Seperator *sep);
void command_camerashake(Client *c, const Seperator *sep);
void command_castspell(Client *c, const Seperator *sep);
void command_chat(Client *c, const Seperator *sep);
@@ -67,6 +49,7 @@ void command_checklos(Client *c, const Seperator *sep);
void command_copycharacter(Client *c, const Seperator *sep);
void command_corpse(Client *c, const Seperator *sep);
void command_corpsefix(Client *c, const Seperator *sep);
void command_countitem(Client *c, const Seperator *sep);
void command_cvs(Client *c, const Seperator *sep);
void command_damage(Client *c, const Seperator *sep);
void command_databuckets(Client *c, const Seperator *sep);
@@ -87,10 +70,10 @@ void command_doanim(Client *c, const Seperator *sep);
void command_dye(Client *c, const Seperator *sep);
void command_dz(Client *c, const Seperator *sep);
void command_dzkickplayers(Client *c, const Seperator *sep);
void command_editmassrespawn(Client* c, const Seperator* sep);
void command_editmassrespawn(Client *c, const Seperator *sep);
void command_emote(Client *c, const Seperator *sep);
void command_emotesearch(Client* c, const Seperator *sep);
void command_emoteview(Client* c, const Seperator *sep);
void command_emotesearch(Client *c, const Seperator *sep);
void command_emoteview(Client *c, const Seperator *sep);
void command_emptyinventory(Client *c, const Seperator *sep);
void command_enablerecipe(Client *c, const Seperator *sep);
void command_endurance(Client *c, const Seperator *sep);
@@ -121,14 +104,14 @@ void command_getvariable(Client *c, const Seperator *sep);
void command_ginfo(Client *c, const Seperator *sep);
void command_giveitem(Client *c, const Seperator *sep);
void command_givemoney(Client *c, const Seperator *sep);
void command_globalview(Client* c, const Seperator *sep);
void command_globalview(Client *c, const Seperator *sep);
void command_gm(Client *c, const Seperator *sep);
void command_gmspeed(Client *c, const Seperator *sep);
void command_gmzone(Client *c, const Seperator *sep);
void command_goto(Client *c, const Seperator *sep);
void command_grid(Client *c, const Seperator *sep);
void command_guild(Client *c, const Seperator *sep);
bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char* what, const char* value);
bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char *what, const char *value);
void command_guildapprove(Client *c, const Seperator *sep);
void command_guildcreate(Client *c, const Seperator *sep);
void command_guildlist(Client *c, const Seperator *sep);
@@ -193,12 +176,14 @@ void command_npcspecialattk(Client *c, const Seperator *sep);
void command_npcstats(Client *c, const Seperator *sep);
void command_npctype_cache(Client *c, const Seperator *sep);
void command_npctypespawn(Client *c, const Seperator *sep);
void command_nudge(Client* c, const Seperator* sep);
void command_nudge(Client *c, const Seperator *sep);
void command_nukebuffs(Client *c, const Seperator *sep);
void command_nukeitem(Client *c, const Seperator *sep);
void command_object(Client* c, const Seperator *sep);
void command_object(Client *c, const Seperator *sep);
void command_oocmute(Client *c, const Seperator *sep);
void command_opcode(Client *c, const Seperator *sep);
void command_bestz(Client *c, const Seperator *message);
void command_pf(Client *c, const Seperator *message);
#ifdef PACKET_PROFILER
void command_packetprofile(Client *c, const Seperator *sep);
@@ -210,6 +195,7 @@ void command_peqzone(Client *c, const Seperator *sep);
void command_permaclass(Client *c, const Seperator *sep);
void command_permagender(Client *c, const Seperator *sep);
void command_permarace(Client *c, const Seperator *sep);
void command_petitems(Client *c, const Seperator *sep);
void command_petitioninfo(Client *c, const Seperator *sep);
void command_picklock(Client *c, const Seperator *sep);
void command_profanity(Client *c, const Seperator *sep);
@@ -225,24 +211,26 @@ void command_pvp(Client *c, const Seperator *sep);
void command_qglobal(Client *c, const Seperator *sep);
void command_questerrors(Client *c, const Seperator *sep);
void command_race(Client *c, const Seperator *sep);
void command_raidloot(Client* c, const Seperator *sep);
void command_raidloot(Client *c, const Seperator *sep);
void command_randomfeatures(Client *c, const Seperator *sep);
void command_refreshgroup(Client *c, const Seperator *sep);
void command_reloadaa(Client *c, const Seperator *sep);
void command_reloadallrules(Client *c, const Seperator *sep);
void command_reloademote(Client* c, const Seperator *sep);
void command_reloadcontentflags(Client *c, const Seperator *sep);
void command_reloademote(Client *c, const Seperator *sep);
void command_reloadlevelmods(Client *c, const Seperator *sep);
void command_reloadmerchants(Client *c, const Seperator *sep);
void command_reloadperlexportsettings(Client *c, const Seperator *sep);
void command_reloadqst(Client *c, const Seperator *sep);
void command_reloadstatic(Client *c, const Seperator *sep);
void command_reloadtitles(Client *c, const Seperator *sep);
void command_reloadtraps(Client* c, const Seperator *sep);
void command_reloadtraps(Client *c, const Seperator *sep);
void command_reloadworld(Client *c, const Seperator *sep);
void command_reloadworldrules(Client *c, const Seperator *sep);
void command_reloadzps(Client *c, const Seperator *sep);
void command_removeitem(Client *c, const Seperator *sep);
void command_repop(Client *c, const Seperator *sep);
void command_resetaa(Client* c,const Seperator *sep);
void command_resetaa(Client *c, const Seperator *sep);
void command_resetaa_timer(Client *c, const Seperator *sep);
void command_resetdisc_timer(Client *c, const Seperator *sep);
void command_revoke(Client *c, const Seperator *sep);
@@ -259,12 +247,16 @@ void command_serverrules(Client *c, const Seperator *sep);
void command_set_adventure_points(Client *c, const Seperator *sep);
void command_setaapts(Client *c, const Seperator *sep);
void command_setaaxp(Client *c, const Seperator *sep);
void command_setaltcurrency(Client *c, const Seperator *sep);
void command_setanim(Client *c, const Seperator *sep);
void command_setcrystals(Client *c, const Seperator *sep);
void command_setendurance(Client *c, const Seperator *sep);
void command_setfaction(Client *c, const Seperator *sep);
void command_setgraveyard(Client *c, const Seperator *sep);
void command_sethp(Client *c, const Seperator *sep);
void command_setlanguage(Client *c, const Seperator *sep);
void command_setlsinfo(Client *c, const Seperator *sep);
void command_setmana(Client *c, const Seperator *sep);
void command_setpass(Client *c, const Seperator *sep);
void command_setpvppoints(Client *c, const Seperator *sep);
void command_setskill(Client *c, const Seperator *sep);
@@ -305,21 +297,25 @@ void command_timezone(Client *c, const Seperator *sep);
void command_title(Client *c, const Seperator *sep);
void command_titlesuffix(Client *c, const Seperator *sep);
void command_traindisc(Client *c, const Seperator *sep);
void command_trapinfo(Client* c, const Seperator *sep);
void command_trapinfo(Client *c, const Seperator *sep);
void command_tune(Client *c, const Seperator *sep);
void command_ucs(Client *c, const Seperator *sep);
void command_undye(Client *c, const Seperator *sep);
void command_undyeme(Client *c, const Seperator *sep);
void command_unfreeze(Client *c, const Seperator *sep);
void command_unlock(Client *c, const Seperator *sep);
void command_unmemspell(Client *c, const Seperator *sep);
void command_unmemspells(Client *c, const Seperator *sep);
void command_unscribespell(Client *c, const Seperator *sep);
void command_unscribespells(Client *c, const Seperator *sep);
void command_untraindisc(Client *c, const Seperator *sep);
void command_untraindiscs(Client *c, const Seperator *sep);
void command_uptime(Client *c, const Seperator *sep);
void command_version(Client *c, const Seperator *sep);
void command_viewcurrencies(Client *c, const Seperator *sep);
void command_viewnpctype(Client *c, const Seperator *sep);
void command_viewpetition(Client *c, const Seperator *sep);
void command_viewzoneloot(Client *c, const Seperator *sep);
void command_wc(Client *c, const Seperator *sep);
void command_weather(Client *c, const Seperator *sep);
void command_who(Client *c, const Seperator *sep);
@@ -336,9 +332,7 @@ void command_zone(Client *c, const Seperator *sep);
void command_zone_instance(Client *c, const Seperator *sep);
void command_zonebootup(Client *c, const Seperator *sep);
void command_zonelock(Client *c, const Seperator *sep);
void command_viewzoneloot(Client *c, const Seperator *sep);
void command_zoneshutdown(Client *c, const Seperator *sep);
void command_zonespawn(Client *c, const Seperator *sep);
void command_zonestatus(Client *c, const Seperator *sep);
void command_zopp(Client *c, const Seperator *sep);
void command_zsafecoords(Client *c, const Seperator *sep);
@@ -346,7 +340,6 @@ void command_zsave(Client *c, const Seperator *sep);
void command_zsky(Client *c, const Seperator *sep);
void command_zstats(Client *c, const Seperator *sep);
void command_zunderworld(Client *c, const Seperator *sep);
void command_zuwcoords(Client *c, const Seperator *sep);
#ifdef BOTS
#include "bot.h"

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