mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-25 02:42:27 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e4767269e | |||
| e0eb145081 | |||
| a6dd65435f | |||
| 26dc05c0dc | |||
| da20a6ab67 | |||
| 3949a31246 | |||
| e898be1ce9 | |||
| 2962575dda | |||
| 6a6045a21c | |||
| 717fe7dc8c | |||
| df69d12c0c | |||
| 99e49cb2ec | |||
| 5ee2856133 | |||
| 4a64048744 | |||
| 2ae795fd61 | |||
| 0829bc08b8 | |||
| 903a385229 | |||
| fafa33e190 | |||
| 90a01f7c53 | |||
| 19434197d4 | |||
| 18b62667f0 | |||
| 8ed7ca977f | |||
| 665e336946 | |||
| ccf8504dec | |||
| d107213fe1 | |||
| c115cbcd6a | |||
| 064ae7ba89 | |||
| 02302802b8 | |||
| 536e248424 | |||
| 5b56a23a8a | |||
| 97edb09fba | |||
| 85f7b10f90 | |||
| 0f49fbcfcd | |||
| e57979c3a8 |
+163
@@ -1,3 +1,166 @@
|
||||
## [22.4.1] - 02/17/2023
|
||||
|
||||
### Bots
|
||||
|
||||
* Set Taunt to enabled for SK/Paladin Bots by Default. ([#2941](https://github.com/EQEmu/Server/pull/2941)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-17
|
||||
|
||||
### DevTools
|
||||
|
||||
* Fix NPC targetting dev tools display window ([#2943](https://github.com/EQEmu/Server/pull/2943)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
|
||||
### Fixes
|
||||
|
||||
* Issue with AssignRaidToInstance that was using the groups repository instead of raid ([#2947](https://github.com/EQEmu/Server/pull/2947)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
* Missing comma in schema list breaking dumps ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
|
||||
### Player Events
|
||||
|
||||
* Fix issue with item instances not being validated properly before accessing causing crashes on handin ([#2945](https://github.com/EQEmu/Server/pull/2945)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
* Fix rare out of bound issue when loading event types ([#2946](https://github.com/EQEmu/Server/pull/2946)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
* Turn off KILLED_NPC (trash) off by default ([#2948](https://github.com/EQEmu/Server/pull/2948)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
|
||||
|
||||
## [22.4.0] - 02/17/2023
|
||||
|
||||
### Bots
|
||||
|
||||
* Add Additional HeroicAgi/Dex Modifiers. ([#2838](https://github.com/EQEmu/Server/pull/2838)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
|
||||
* Add Additional HeroicStr modifiers. ([#2837](https://github.com/EQEmu/Server/pull/2837)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
|
||||
* Add IsBot() to methods in attack.cpp where applicable. ([#2840](https://github.com/EQEmu/Server/pull/2840)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
|
||||
* Add Lore Check for Augments. ([#2874](https://github.com/EQEmu/Server/pull/2874)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-12
|
||||
* Add Pet Power Support for Temp Pets. ([#2853](https://github.com/EQEmu/Server/pull/2853)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-11
|
||||
* Add Support for TryTriggerOnCastFocusEffect ([#2864](https://github.com/EQEmu/Server/pull/2864)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-13
|
||||
* Add TotalDominationBonus modifiers. ([#2852](https://github.com/EQEmu/Server/pull/2852)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
|
||||
* ST_AreaClientOnly spells to land on Bots ([#2849](https://github.com/EQEmu/Server/pull/2849)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
|
||||
* Update ResistSpell to use temp_level_diff client formula ([#2851](https://github.com/EQEmu/Server/pull/2851)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
|
||||
|
||||
### Bots & Mercenaries
|
||||
|
||||
* Add 100% Hit chance if sitting while attacked. ([#2839](https://github.com/EQEmu/Server/pull/2839)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
|
||||
* Add Support for TrySympatheticProc ([#2866](https://github.com/EQEmu/Server/pull/2866)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-13
|
||||
|
||||
### CI
|
||||
|
||||
* Fix Windows stderr not bubbling properly ([#2925](https://github.com/EQEmu/Server/pull/2925)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
|
||||
|
||||
### Code
|
||||
|
||||
* Add IsOfClientBot() virtual method. ([#2845](https://github.com/EQEmu/Server/pull/2845)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
|
||||
* Doors EVENT_CLICK_DOOR syntax adjustment ([Akkadius](https://github.com/Akkadius)) 2023-02-14
|
||||
* Remove Unused Mod Hooks ([#2856](https://github.com/EQEmu/Server/pull/2856)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
|
||||
### Crash
|
||||
|
||||
* Crash fix where invalid input to #heromodel would crash zone ([#2937](https://github.com/EQEmu/Server/pull/2937)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
|
||||
* Fix Bot Crash in Bot::Bot Constructor. ([#2868](https://github.com/EQEmu/Server/pull/2868)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-12
|
||||
* Fix Crash in FindType ([#2867](https://github.com/EQEmu/Server/pull/2867)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-13
|
||||
* Fix crash in Mob::CommonDamage when attacker was null ([#2872](https://github.com/EQEmu/Server/pull/2872)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-13
|
||||
* Fix crash issue with dropping items and order of operations ([#2939](https://github.com/EQEmu/Server/pull/2939)) ([joligario](https://github.com/joligario)) 2023-02-16
|
||||
* Fix issue where long short names overflow file_name ([Akkadius](https://github.com/Akkadius)) 2023-02-09
|
||||
* Fix potential crash in Mob::CommonDamage ([#2848](https://github.com/EQEmu/Server/pull/2848)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
|
||||
|
||||
### Doors
|
||||
|
||||
* Fix issue where NPC's wouldn't open doors because door param overflow ([#2934](https://github.com/EQEmu/Server/pull/2934)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
|
||||
|
||||
### Feature
|
||||
|
||||
* Add IsOfClientBotMerc() virtual method. ([#2843](https://github.com/EQEmu/Server/pull/2843)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
|
||||
|
||||
### Fixes
|
||||
|
||||
* Another doors fix ([Akkadius](https://github.com/Akkadius)) 2023-02-14
|
||||
* Fix CheckNumHitsRemaining() with 1H Blunt ([#2846](https://github.com/EQEmu/Server/pull/2846)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-07
|
||||
* Fix Door opening regression caused by #2880 ([Akkadius](https://github.com/Akkadius)) 2023-02-14
|
||||
* Fix EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE regression caused by #2897 ([#2928](https://github.com/EQEmu/Server/pull/2928)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
|
||||
* Fix HP_EVENT regression ([#2927](https://github.com/EQEmu/Server/pull/2927)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
|
||||
* Fix crash in EVENT_DISCOVER_ITEM ([#2933](https://github.com/EQEmu/Server/pull/2933)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-15
|
||||
* Fix crash where dropped items crash Lua logic ([#2936](https://github.com/EQEmu/Server/pull/2936)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
|
||||
* Fix for interrupting item casts to no longer lock the client if cast time of item greater than 0 ([#2921](https://github.com/EQEmu/Server/pull/2921)) ([Natedog2012](https://github.com/Natedog2012)) 2023-02-13
|
||||
* Fix issue where Lore groundspawn pickups will desync ROF2+ ([#2929](https://github.com/EQEmu/Server/pull/2929)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
|
||||
* Fix issue with EVENT_HP firing regression from #2904 ([#2924](https://github.com/EQEmu/Server/pull/2924)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
|
||||
* Replace uses of SPELL_UNKNOWN with IsValidSpell() ([#2938](https://github.com/EQEmu/Server/pull/2938)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-16
|
||||
* Self Only Spells will no longer check target level or buff restrictions ([#2931](https://github.com/EQEmu/Server/pull/2931)) ([noudess](https://github.com/noudess)) 2023-02-15
|
||||
|
||||
### Groundspawns
|
||||
|
||||
* Fix issue where groundspawns appear floating high off the ground ([#2930](https://github.com/EQEmu/Server/pull/2930)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
|
||||
|
||||
### Logging
|
||||
|
||||
* Add raw opcode when emu translated opcode is not found (OP_Unknown) via (C->S) ([#2847](https://github.com/EQEmu/Server/pull/2847)) ([Akkadius](https://github.com/Akkadius)) 2023-02-08
|
||||
* Implement Player Event Logging system ([#2833](https://github.com/EQEmu/Server/pull/2833)) ([Akkadius](https://github.com/Akkadius)) 2023-02-13
|
||||
|
||||
### Quest API
|
||||
|
||||
* (Performance) Check equip or scale item events exist before export and execute ([#2898](https://github.com/EQEmu/Server/pull/2898)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_AA_BUY or EVENT_AA_GAIN exist before export and execute ([#2892](https://github.com/EQEmu/Server/pull/2892)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_AGGRO, EVENT_ATTACK, or EVENT_COMBAT exist before export and execute ([#2901](https://github.com/EQEmu/Server/pull/2901)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_COMBINE, EVENT_COMBINE_SUCCESS, EVENT_COMBINE_FAILURE, or EVENT_COMBINE_VALIDATE exist before export and execute ([#2896](https://github.com/EQEmu/Server/pull/2896)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_DEATH, EVENT_DEATH_COMPLETE, or EVENT_DEATH_ZONE exist before export and execute ([#2909](https://github.com/EQEmu/Server/pull/2909)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_ENVIRONMENTAL_DAMAGE exists before export and execute ([#2899](https://github.com/EQEmu/Server/pull/2899)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_FEIGN_DEATH exists before export and execute ([#2916](https://github.com/EQEmu/Server/pull/2916)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_ITEM_TICK or EVENT_WEAPON_PROC exist before export and execute ([#2914](https://github.com/EQEmu/Server/pull/2914)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_LANGUAGE_SKILL_UP, EVENT_SKILL_UP, or EVENT_USE_SKILL exist before export and execute ([#2894](https://github.com/EQEmu/Server/pull/2894)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_PAYLOAD or EVENT_SIGNAL exist before export and execute ([#2902](https://github.com/EQEmu/Server/pull/2902)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_SLAY exists before export and execute ([#2910](https://github.com/EQEmu/Server/pull/2910)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event EVENT_WAYPOINT_ARRIVE or EVENT_WAYPOINT_DEPART exist before export and execute ([#2905](https://github.com/EQEmu/Server/pull/2905)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_AGGRO_SAY, EVENT_SAY, and EVENT_PROXIMITY_SAY ([#2882](https://github.com/EQEmu/Server/pull/2882)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_BOT_CREATE ([#2886](https://github.com/EQEmu/Server/pull/2886)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_CLICK_DOOR and EVENT_CLICK_OBJECT ([#2880](https://github.com/EQEmu/Server/pull/2880)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_DESPAWN and EVENT_DESPAWN_ZONE ([#2887](https://github.com/EQEmu/Server/pull/2887)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_DISCOVER_ITEM ([#2912](https://github.com/EQEmu/Server/pull/2912)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_DUEL_LOSE and EVENT_DUEL_WIN ([#2915](https://github.com/EQEmu/Server/pull/2915)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_ENTER_ZONE and EVENT_ZONE ([#2900](https://github.com/EQEmu/Server/pull/2900)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_GM_COMMAND ([#2890](https://github.com/EQEmu/Server/pull/2890)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_GROUP_CHANGE ([#2884](https://github.com/EQEmu/Server/pull/2884)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_HP ([#2904](https://github.com/EQEmu/Server/pull/2904)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_KILLED_MERIT ([#2911](https://github.com/EQEmu/Server/pull/2911)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_LEVEL_UP and EVENT_LEVEL_DOWN ([#2889](https://github.com/EQEmu/Server/pull/2889)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_POPUP_RESPONSE ([#2881](https://github.com/EQEmu/Server/pull/2881)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_RESPAWN ([#2917](https://github.com/EQEmu/Server/pull/2917)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_TICK ([#2919](https://github.com/EQEmu/Server/pull/2919)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_TIMER ([#2903](https://github.com/EQEmu/Server/pull/2903)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_TRADE ([#2906](https://github.com/EQEmu/Server/pull/2906)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_UNHANDLED_OPCODE ([#2918](https://github.com/EQEmu/Server/pull/2918)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_WARP ([#2907](https://github.com/EQEmu/Server/pull/2907)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute area events ([#2888](https://github.com/EQEmu/Server/pull/2888)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check merchant events exist before export and execute ([#2893](https://github.com/EQEmu/Server/pull/2893)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check spell or cast events exist before export and execute ([#2897](https://github.com/EQEmu/Server/pull/2897)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check task events exist before export and execute ([#2883](https://github.com/EQEmu/Server/pull/2883)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_CONNECT and EVENT_DISCONNECT ([#2913](https://github.com/EQEmu/Server/pull/2913)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* (Performance) Check event exists before export and execute EVENT_TEST_BUFF ([#2920](https://github.com/EQEmu/Server/pull/2920)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Add $target export to EVENT_INSPECT in Perl ([#2891](https://github.com/EQEmu/Server/pull/2891)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Add Additional XP Events EVENT_AA_EXP_GAIN, EVENT_EXP_GAIN ([#2865](https://github.com/EQEmu/Server/pull/2865)) ([Valorith](https://github.com/Valorith)) 2023-02-13
|
||||
* Add EVENT_DESTROY_ITEM_CLIENT to Perl/Lua. ([#2871](https://github.com/EQEmu/Server/pull/2871)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Add EVENT_DROP_ITEM_CLIENT to Perl/Lua ([#2869](https://github.com/EQEmu/Server/pull/2869)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Add Recipe-based methods to Perl/Lua. ([#2844](https://github.com/EQEmu/Server/pull/2844)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-08
|
||||
* Export $door to EVENT_CLICKDOOR in Perl ([#2861](https://github.com/EQEmu/Server/pull/2861)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-11
|
||||
* Export $hate_entity to EVENT_HATE_LIST in Perl ([#2885](https://github.com/EQEmu/Server/pull/2885)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Export $item and $augment to augment events in Perl ([#2895](https://github.com/EQEmu/Server/pull/2895)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Export $item and $corpse to EVENT_LOOT and EVENT_LOOT_ZONE in Perl ([#2878](https://github.com/EQEmu/Server/pull/2878)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Export $item to Client/Bot Equip Events in Perl ([#2860](https://github.com/EQEmu/Server/pull/2860)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-11
|
||||
* Export $item to EVENT_DISCOVER_ITEM in Perl ([#2863](https://github.com/EQEmu/Server/pull/2863)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-11
|
||||
* Export $item to EVENT_PLAYER_PICKUP in Perl. ([#2875](https://github.com/EQEmu/Server/pull/2875)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Export $item to Fishing and Forage Events in Perl ([#2876](https://github.com/EQEmu/Server/pull/2876)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Export $killed_npc to EVENT_NPC_SLAY to Perl ([#2879](https://github.com/EQEmu/Server/pull/2879)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Export $object to EVENT_CLICK_OBJECT in Perl ([#2862](https://github.com/EQEmu/Server/pull/2862)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-11
|
||||
* Export $spawned to EVENT_SPAWN_ZONE in Perl ([#2877](https://github.com/EQEmu/Server/pull/2877)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Export target to EVENT_TARGET_CHANGE in Perl/Lua. ([#2870](https://github.com/EQEmu/Server/pull/2870)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Export targets to EVENT_CONSIDER and EVENT_CONSIDER_CORPSE ([#2908](https://github.com/EQEmu/Server/pull/2908)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
* Fix SetSimpleRoamBox in Perl to have optional params again ([#2935](https://github.com/EQEmu/Server/pull/2935)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
|
||||
|
||||
### Rules
|
||||
|
||||
* Add Group/Raid Experience Rules ([#2850](https://github.com/EQEmu/Server/pull/2850)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
|
||||
|
||||
### Tradeskills
|
||||
|
||||
* Check if combine would result in lore conflict ([#2932](https://github.com/EQEmu/Server/pull/2932)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-16
|
||||
|
||||
### Windows
|
||||
|
||||
* Fix MSVC compilation bug via workaround ([#2926](https://github.com/EQEmu/Server/pull/2926)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
|
||||
|
||||
## [22.3.0] - 02/06/2023
|
||||
|
||||
### Bots
|
||||
|
||||
@@ -409,7 +409,7 @@ void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
|
||||
auto zone_id = GetInstanceZoneID(instance_id);
|
||||
auto version = GetInstanceVersion(instance_id);
|
||||
|
||||
auto l = GroupIdRepository::GetWhere(
|
||||
auto l = RaidMembersRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"raidid = {}",
|
||||
|
||||
@@ -342,7 +342,7 @@ namespace DatabaseSchema {
|
||||
"saylink",
|
||||
"server_scheduled_events",
|
||||
"player_event_log_settings",
|
||||
"player_event_logs"
|
||||
"player_event_logs",
|
||||
"shared_task_activity_state",
|
||||
"shared_task_dynamic_zones",
|
||||
"shared_task_members",
|
||||
|
||||
@@ -30,6 +30,9 @@ void PlayerEventLogs::Init()
|
||||
std::vector<int> db{};
|
||||
db.reserve(s.size());
|
||||
for (auto &e: s) {
|
||||
if (e.id >= PlayerEvent::MAX) {
|
||||
continue;
|
||||
}
|
||||
m_settings[e.id] = e;
|
||||
db.emplace_back(e.id);
|
||||
}
|
||||
@@ -693,7 +696,7 @@ void PlayerEventLogs::SetSettingsDefaults()
|
||||
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
|
||||
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
|
||||
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
|
||||
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace cereal
|
||||
@param indentChar The type of character to indent with
|
||||
@param indentLength The number of indentChar to use for indentation
|
||||
(0 corresponds to no indentation) */
|
||||
explicit Options( int precision = JSONWriterSL::Writer::kDefaultMaxDecimalPlaces,
|
||||
explicit Options( int precision = 324,
|
||||
IndentChar indentChar = IndentChar::space,
|
||||
unsigned int indentLength = 4,
|
||||
bool singleLine = false) :
|
||||
|
||||
+4
-1
@@ -197,10 +197,13 @@ RULE_BOOL(Character, PetZoneWithOwner, true, "Should Pets Zone with Owner")
|
||||
RULE_BOOL(Character, FullManaOnDeath, true, "On death set mana to full")
|
||||
RULE_BOOL(Character, FullEndurOnDeath, true, "On death set endurance to full")
|
||||
RULE_INT(Character, ExperiencePercentCapPerKill, -1, "Caps the percentage of experience that can be gained per kill. -1 disables the cap; 0 blocks all (non-aa) xp.")
|
||||
RULE_BOOL(Character, EnableGroupEXPModifier, true, "Enable or disable the group experience modifier based on number of players in group, default is true")
|
||||
RULE_BOOL(Character, EnableGroupEXPModifier, true, "Enable or disable the group experience modifier in group, default is true")
|
||||
RULE_BOOL(Character, EnableGroupMemberEXPModifier, true, "Enable or disable the group member experience modifier based on number of players in group, default is true")
|
||||
RULE_REAL(Character, GroupMemberEXPModifier, 0.2, "Sets the group experience modifier per members between 2 and 5, default is 0.2")
|
||||
RULE_REAL(Character, FullGroupEXPModifier, 2.16, "Sets the group experience modifier for a full group, default is 2.16")
|
||||
RULE_BOOL(Character, IgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
|
||||
RULE_BOOL(Character, EnableRaidEXPModifier, true, "Enable or disable the raid experience modifier, default is true")
|
||||
RULE_BOOL(Character, EnableRaidMemberEXPModifier, true, "Enable or disable the raid experience modifier based on members in raid, default is true")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.3.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.4.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define LOGIN_VERSION "0.8.0"
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.3.0",
|
||||
"version": "22.4.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
@@ -72,13 +72,7 @@ func main() {
|
||||
}
|
||||
|
||||
if len(os.Getenv("RCLONE_FTP_PASS")) == 0 {
|
||||
fmt.Printf("Missing RCLONE_FTP_PASS no need to deploy\n")
|
||||
fmt.Printf("Exiting code 78 to halt pipeline steps gracefully\n")
|
||||
os.Exit(78)
|
||||
}
|
||||
|
||||
if len(os.Getenv("GH_RELEASE_GITHUB_API_TOKEN")) == 0 {
|
||||
fmt.Printf("Missing GH_RELEASE_GITHUB_API_TOKEN no need to deploy\n")
|
||||
fmt.Printf("Missing RCLONE_FTP_PASS no need to release\n")
|
||||
fmt.Printf("Exiting code 78 to halt pipeline steps gracefully\n")
|
||||
os.Exit(78)
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,49 +1,42 @@
|
||||
try
|
||||
$cwd = Get-Location
|
||||
|
||||
Set-Location -Path "$cwd"
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
if (![System.IO.Directory]::Exists("$cwd\win-build-x64"))
|
||||
{
|
||||
$cwd = Get-Location
|
||||
|
||||
Set-Location -Path "$cwd"
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
if (![System.IO.Directory]::Exists("$cwd\win-build-x64"))
|
||||
{
|
||||
Write-Information -MessageData "Creating build x64 folder" -InformationAction Continue
|
||||
New-Item -Path "$cwd\win-build-x64" -ItemType Directory
|
||||
}
|
||||
|
||||
perl .\utils\scripts\build\tag-version.pl
|
||||
|
||||
Write-Information -MessageData "Creating build x64" -InformationAction Continue
|
||||
Set-Location -Path "$cwd\win-build-x64"
|
||||
cmake -Wno-dev -G "Visual Studio 17 2022" -A x64 -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON "$cwd"
|
||||
cmake --build . --config RelWithDebInfo --clean-first
|
||||
Set-Location -Path "$cwd"
|
||||
|
||||
.\utils\scripts\build\should-release\should-release.exe; if ($LASTEXITCODE -ne 0) { exit }
|
||||
|
||||
# trim some fat
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\export_client_files.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\import_client_files.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\shared_memory.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\queryserv.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\eqlaunch.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\cppunit.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\tests.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\tests.exe
|
||||
|
||||
7z a eqemu-server-windows-x64.zip $cwd\win-build-x64\bin\RelWithDebInfo\*.exe $cwd\win-build-x64\bin\RelWithDebInfo\*.dll $cwd\win-build-x64\bin\RelWithDebInfo\*.pdb $cwd\win-build-x64\libs\zlibng\RelWithDebInfo\*.dll $cwd\win-build-x64\libs\zlibng\RelWithDebInfo\*.pdb
|
||||
|
||||
dir *.zip
|
||||
rclone config create remote ftp env_auth true
|
||||
rclone copy eqemu-server-windows-x64.zip remote: 2>&1
|
||||
rclone ls remote: 2>&1
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Host ("Caught signal to end")
|
||||
Write-Host $_
|
||||
Write-Information -MessageData "Creating build x64 folder" -InformationAction Continue
|
||||
New-Item -Path "$cwd\win-build-x64" -ItemType Directory
|
||||
}
|
||||
|
||||
perl .\utils\scripts\build\tag-version.pl
|
||||
|
||||
Write-Information -MessageData "Creating build x64" -InformationAction Continue
|
||||
Set-Location -Path "$cwd\win-build-x64"
|
||||
cmake -Wno-dev -G "Visual Studio 17 2022" -A x64 -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_ZLIB=ON "$cwd"
|
||||
cmake --build . --config RelWithDebInfo --clean-first
|
||||
Set-Location -Path "$cwd"
|
||||
|
||||
if ($LASTEXITCODE -ne 0) { echo "Build emitted error"; exit 1 }
|
||||
|
||||
.\utils\scripts\build\should-release\should-release.exe; if ($LASTEXITCODE -ne 0) { exit }
|
||||
|
||||
# trim some fat
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\export_client_files.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\import_client_files.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\shared_memory.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\queryserv.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\eqlaunch.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\cppunit.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\tests.pdb
|
||||
del $cwd\win-build-x64\bin\RelWithDebInfo\tests.exe
|
||||
|
||||
7z a eqemu-server-windows-x64.zip $cwd\win-build-x64\bin\RelWithDebInfo\*.exe $cwd\win-build-x64\bin\RelWithDebInfo\*.dll $cwd\win-build-x64\bin\RelWithDebInfo\*.pdb $cwd\win-build-x64\libs\zlibng\RelWithDebInfo\*.dll $cwd\win-build-x64\libs\zlibng\RelWithDebInfo\*.pdb
|
||||
|
||||
dir *.zip
|
||||
rclone config create remote ftp env_auth true
|
||||
rclone copy eqemu-server-windows-x64.zip remote: 2>&1
|
||||
rclone ls remote: 2>&1
|
||||
|
||||
|
||||
@@ -97,7 +97,6 @@ SET(zone_sources
|
||||
mob_appearance.cpp
|
||||
mob_movement_manager.cpp
|
||||
mob_info.cpp
|
||||
mod_functions.cpp
|
||||
npc.cpp
|
||||
npc_ai.cpp
|
||||
npc_scale_manager.cpp
|
||||
|
||||
+2
-11
@@ -59,7 +59,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
|
||||
if (IsOfClientBot()) {
|
||||
act_power = GetFocusEffect(focusPetPower, spell_id);
|
||||
if (IsClient()) {
|
||||
act_power = CastToClient()->mod_pet_power(act_power, spell_id);
|
||||
act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,15 +302,6 @@ void Mob::WakeTheDead(uint16 spell_id, Corpse *corpse_to_use, Mob *target, uint3
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Does WTD use pet focus?
|
||||
int act_power = 0;
|
||||
|
||||
if (IsClient()) {
|
||||
act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);
|
||||
act_power = CastToClient()->mod_pet_power(act_power, spell_id);
|
||||
}
|
||||
*/
|
||||
|
||||
SwarmPet_Struct pet;
|
||||
pet.count = 1;
|
||||
pet.duration = 1;
|
||||
@@ -832,7 +823,7 @@ void Client::InspectBuffs(Client* Inspector, int Rank)
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
uint32 packet_index = 0;
|
||||
for (uint32 i = 0; i < buff_count; i++) {
|
||||
if (buffs[i].spellid == SPELL_UNKNOWN)
|
||||
if (!IsValidSpell(buffs[i].spellid))
|
||||
continue;
|
||||
ib->spell_id[packet_index] = buffs[i].spellid;
|
||||
if (Rank > 1)
|
||||
|
||||
+2
-2
@@ -520,7 +520,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
) {
|
||||
if(CheckLosFN(mob)) {
|
||||
LogAggro("Check aggro for [{}] target [{}]", GetName(), mob->GetName());
|
||||
return mod_will_aggro(mob, this);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
@@ -548,7 +548,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
) {
|
||||
if(CheckLosFN(mob)) {
|
||||
LogAggro("Check aggro for [{}] target [{}]", GetName(), mob->GetName());
|
||||
return mod_will_aggro(mob, this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+42
-49
@@ -1694,8 +1694,9 @@ void Client::Damage(Mob* other, int64 damage, uint16 spell_id, EQ::skills::Skill
|
||||
if (dead || IsCorpse())
|
||||
return;
|
||||
|
||||
if (spell_id == 0)
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
spell_id = SPELL_UNKNOWN;
|
||||
}
|
||||
|
||||
// cut all PVP spell damage to 2/3
|
||||
// Blasting ourselfs is considered PvP
|
||||
@@ -1719,8 +1720,9 @@ void Client::Damage(Mob* other, int64 damage, uint16 spell_id, EQ::skills::Skill
|
||||
|
||||
if (damage > 0) {
|
||||
|
||||
if (spell_id == SPELL_UNKNOWN)
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
CheckIncreaseSkill(EQ::skills::SkillDefense, other, -15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1755,7 +1757,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
|
||||
}
|
||||
}
|
||||
|
||||
if (killerMob && (killerMob->IsClient() || killerMob->IsBot()) && (spell != SPELL_UNKNOWN) && damage > 0) {
|
||||
if (killerMob && killerMob->IsOfClientBot() && IsValidSpell(spell) && damage > 0) {
|
||||
char val1[20] = { 0 };
|
||||
|
||||
entity_list.MessageCloseString(
|
||||
@@ -1794,8 +1796,8 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
|
||||
d->killer_id = killerMob ? killerMob->GetID() : 0;
|
||||
d->corpseid = GetID();
|
||||
d->bindzoneid = m_pp.binds[0].zone_id;
|
||||
d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell;
|
||||
d->attack_skill = spell != SPELL_UNKNOWN ? 0xe7 : attack_skill;
|
||||
d->spell_id = IsValidSpell(spell) ? spell : 0xffffffff;
|
||||
d->attack_skill = IsValidSpell(spell) ? 0xe7 : attack_skill;
|
||||
d->damage = damage;
|
||||
app.priority = 6;
|
||||
entity_list.QueueClients(this, &app);
|
||||
@@ -1824,8 +1826,6 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
|
||||
parse->EventNPC(EVENT_SLAY, killerMob->CastToNPC(), this, "", 0);
|
||||
}
|
||||
|
||||
mod_client_death_npc(killerMob);
|
||||
|
||||
auto emote_id = killerMob->GetEmoteID();
|
||||
if (emote_id) {
|
||||
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid);
|
||||
@@ -1855,9 +1855,6 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
|
||||
killerMob->CastToClient()->SetDueling(false);
|
||||
killerMob->CastToClient()->SetDuelTarget(0);
|
||||
entity_list.DuelMessage(killerMob, this, false);
|
||||
|
||||
mod_client_death_duel(killerMob);
|
||||
|
||||
}
|
||||
else {
|
||||
//otherwise, we just died, end the duel.
|
||||
@@ -1928,7 +1925,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
|
||||
}
|
||||
}
|
||||
|
||||
if (spell != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(spell)) {
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (uint16 buffIt = 0; buffIt < buff_count; buffIt++) {
|
||||
if (buffs[buffIt].spellid == spell && buffs[buffIt].client) {
|
||||
@@ -2260,8 +2257,6 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
otherlevel = otherlevel ? otherlevel : 1;
|
||||
mylevel = mylevel ? mylevel : 1;
|
||||
|
||||
//damage = mod_npc_damage(damage, skillinuse, Hand, weapon, other);
|
||||
|
||||
my_hit.base_damage = GetBaseDamage() + eleBane;
|
||||
my_hit.min_damage = GetMinDamage();
|
||||
int32 hate = my_hit.base_damage + my_hit.min_damage;
|
||||
@@ -2423,7 +2418,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
}
|
||||
}
|
||||
|
||||
if (killer_mob && (killer_mob->IsClient() || killer_mob->IsBot()) && (spell != SPELL_UNKNOWN) && damage > 0) {
|
||||
if (killer_mob && killer_mob->IsOfClientBot() && IsValidSpell(spell) && damage > 0) {
|
||||
char val1[20] = { 0 };
|
||||
|
||||
entity_list.MessageCloseString(
|
||||
@@ -2545,7 +2540,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
Raid *kr = entity_list.GetRaidByClient(give_exp_client);
|
||||
|
||||
int64 finalxp = give_exp_client->GetExperienceForKill(this);
|
||||
finalxp = give_exp_client->mod_client_xp(finalxp, this);
|
||||
|
||||
// handle task credit on behalf of the killer
|
||||
if (RuleB(TaskSystem, EnableTaskSystem)) {
|
||||
@@ -2577,8 +2571,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
if (RuleB(NPC, EnableMeritBasedFaction))
|
||||
c->SetFactionLevel(c->CharacterID(), GetNPCFactionID(), c->GetBaseClass(), c->GetBaseRace(), c->GetDeity());
|
||||
|
||||
mod_npc_killed_merit(kr->members[i].member);
|
||||
|
||||
PlayerCount++;
|
||||
}
|
||||
}
|
||||
@@ -2629,8 +2621,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
if (RuleB(NPC, EnableMeritBasedFaction))
|
||||
c->SetFactionLevel(c->CharacterID(), GetNPCFactionID(), c->GetBaseClass(), c->GetBaseRace(), c->GetDeity());
|
||||
|
||||
mod_npc_killed_merit(c);
|
||||
|
||||
PlayerCount++;
|
||||
}
|
||||
}
|
||||
@@ -2680,8 +2670,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
give_exp_client->SetFactionLevel(give_exp_client->CharacterID(), GetNPCFactionID(), give_exp_client->GetBaseClass(),
|
||||
give_exp_client->GetBaseRace(), give_exp_client->GetDeity());
|
||||
|
||||
mod_npc_killed_merit(give_exp_client);
|
||||
|
||||
// QueryServ Logging - Solo
|
||||
if (RuleB(QueryServ, PlayerLogNPCKills)) {
|
||||
auto pack = new ServerPacket(ServerOP_QSPlayerLogNPCKills,
|
||||
@@ -2817,8 +2805,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
// Parse quests even if we're killed by an NPC
|
||||
if (oos) {
|
||||
mod_npc_killed(oos);
|
||||
|
||||
if (IsNPC()) {
|
||||
auto emote_id = GetEmoteID();
|
||||
if (emote_id) {
|
||||
@@ -2962,7 +2948,7 @@ void Mob::AddToHateList(Mob* other, int64 hate /*= 0*/, int64 damage /*= 0*/, bo
|
||||
if (GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && other->IsClient())
|
||||
return;
|
||||
|
||||
if (spell_id != SPELL_UNKNOWN && NoDetrimentalSpellAggro(spell_id))
|
||||
if (IsValidSpell(spell_id) && NoDetrimentalSpellAggro(spell_id))
|
||||
return;
|
||||
|
||||
if (other == myowner)
|
||||
@@ -3126,8 +3112,9 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) {
|
||||
DS = spellbonuses.DamageShield;
|
||||
rev_ds = attacker->spellbonuses.ReverseDamageShield;
|
||||
|
||||
if (spellbonuses.DamageShieldSpellID != 0 && spellbonuses.DamageShieldSpellID != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(spellbonuses.DamageShieldSpellID)) {
|
||||
spellid = spellbonuses.DamageShieldSpellID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DS = spellbonuses.SpellDamageShield + itembonuses.SpellDamageShield + aabonuses.SpellDamageShield;
|
||||
@@ -3196,8 +3183,9 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) {
|
||||
//if we've gotten to this point, we know we know "attacker" hit "this" (us) for damage & we aren't invulnerable
|
||||
uint16 rev_ds_spell_id = SPELL_UNKNOWN;
|
||||
|
||||
if (spellbonuses.ReverseDamageShieldSpellID != 0 && spellbonuses.ReverseDamageShieldSpellID != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(spellbonuses.ReverseDamageShieldSpellID)) {
|
||||
rev_ds_spell_id = spellbonuses.ReverseDamageShieldSpellID;
|
||||
}
|
||||
|
||||
if (rev_ds < 0) {
|
||||
LogCombat("Applying Reverse Damage Shield of value [{}] to [{}]", rev_ds, attacker->GetName());
|
||||
@@ -3630,7 +3618,7 @@ int64 Mob::ReduceAllDamage(int64 damage)
|
||||
bool Mob::HasProcs() const
|
||||
{
|
||||
for (int i = 0; i < MAX_PROCS; i++) {
|
||||
if (PermaProcs[i].spellID != SPELL_UNKNOWN || SpellProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(PermaProcs[i].spellID) || IsValidSpell(SpellProcs[i].spellID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3648,7 +3636,7 @@ bool Mob::HasProcs() const
|
||||
bool Mob::HasDefensiveProcs() const
|
||||
{
|
||||
for (int i = 0; i < MAX_PROCS; i++) {
|
||||
if (DefensiveProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(DefensiveProcs[i].spellID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3684,7 +3672,7 @@ bool Mob::HasSkillProcSuccess() const
|
||||
bool Mob::HasRangedProcs() const
|
||||
{
|
||||
for (int i = 0; i < MAX_PROCS; i++){
|
||||
if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(RangedProcs[i].spellID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3776,16 +3764,16 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
damage = DMG_INVULNERABLE;
|
||||
}
|
||||
|
||||
if (spell_id != SPELL_UNKNOWN || attacker == nullptr)
|
||||
if (IsValidSpell(spell_id) || attacker == nullptr)
|
||||
avoidable = false;
|
||||
|
||||
// only apply DS if physical damage (no spell damage)
|
||||
// damage shield calls this function with spell_id set, so its unavoidable
|
||||
if (attacker && damage > 0 && spell_id == SPELL_UNKNOWN && skill_used != EQ::skills::SkillArchery && skill_used != EQ::skills::SkillThrowing) {
|
||||
if (attacker && damage > 0 && !IsValidSpell(spell_id) && skill_used != EQ::skills::SkillArchery && skill_used != EQ::skills::SkillThrowing) {
|
||||
DamageShield(attacker);
|
||||
}
|
||||
|
||||
if (spell_id == SPELL_UNKNOWN && skill_used >= EQ::skills::Skill1HBlunt) {
|
||||
if (!IsValidSpell(spell_id) && skill_used >= EQ::skills::Skill1HBlunt) {
|
||||
CheckNumHitsRemaining(NumHit::IncomingHitAttempts);
|
||||
|
||||
if (attacker)
|
||||
@@ -3812,7 +3800,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
//if there is some damage being done and theres an attacker involved
|
||||
if (attacker) {
|
||||
// if spell is lifetap add hp to the caster
|
||||
if (spell_id != SPELL_UNKNOWN && IsLifetapSpell(spell_id)) {
|
||||
if (IsValidSpell(spell_id) && IsLifetapSpell(spell_id)) {
|
||||
int64 healed = damage;
|
||||
|
||||
healed = RuleB(Spells, CompoundLifetapHeals) ? attacker->GetActSpellHealing(spell_id, healed) : healed;
|
||||
@@ -3883,7 +3871,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
}
|
||||
|
||||
//see if any runes want to reduce this damage
|
||||
if (spell_id == SPELL_UNKNOWN) {
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
damage = ReduceDamage(damage);
|
||||
LogCombat("Melee Damage reduced to [{}]", damage);
|
||||
damage = ReduceAllDamage(damage);
|
||||
@@ -4163,12 +4151,12 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
}
|
||||
}
|
||||
|
||||
if (spell_id != SPELL_UNKNOWN && !iBuffTic) {
|
||||
if (IsValidSpell(spell_id) && !iBuffTic) {
|
||||
//see if root will break
|
||||
if (IsRooted() && !FromDamageShield) // neotoyko: only spells cancel root
|
||||
TryRootFadeByDamage(buffslot, attacker);
|
||||
}
|
||||
else if (spell_id == SPELL_UNKNOWN)
|
||||
else if (!IsValidSpell(spell_id))
|
||||
{
|
||||
//increment chances of interrupting
|
||||
if (IsCasting()) { //shouldnt interrupt on regular spell damage
|
||||
@@ -4229,17 +4217,18 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
//attacker is a pet, let pet owners see their pet's damage
|
||||
Mob* owner = attacker->GetOwner();
|
||||
if (owner && owner->IsClient()) {
|
||||
if (((spell_id != SPELL_UNKNOWN) || (FromDamageShield)) && damage>0) {
|
||||
if ((IsValidSpell(spell_id) || (FromDamageShield)) && damage > 0) {
|
||||
//special crap for spell damage, looks hackish to me
|
||||
char val1[20] = { 0 };
|
||||
owner->MessageString(Chat::NonMelee, OTHER_HIT_NONMELEE, GetCleanName(), ConvertArray(damage, val1));
|
||||
}
|
||||
else {
|
||||
if (damage > 0) {
|
||||
if (spell_id != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(spell_id)) {
|
||||
filter = iBuffTic ? FilterDOT : FilterSpellDamage;
|
||||
else
|
||||
} else {
|
||||
filter = FilterPetHits;
|
||||
}
|
||||
}
|
||||
else if (damage == -5)
|
||||
filter = FilterNone; //cant filter invulnerable
|
||||
@@ -4256,7 +4245,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
//attacker is not a pet, send to the attacker
|
||||
//if the attacker is a client, try them with the correct filter
|
||||
if (attacker && (attacker->IsClient() || attacker->IsBot())) {
|
||||
if ((spell_id != SPELL_UNKNOWN || FromDamageShield) && damage > 0) {
|
||||
if ((IsValidSpell(spell_id) || FromDamageShield) && damage > 0) {
|
||||
//special crap for spell damage, looks hackish to me
|
||||
char val1[20] = { 0 };
|
||||
if (FromDamageShield) {
|
||||
@@ -4281,10 +4270,12 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
// Only try to queue these packets to a client
|
||||
else if (attacker && (attacker->IsClient())) {
|
||||
if (damage > 0) {
|
||||
if (spell_id != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(spell_id)) {
|
||||
filter = iBuffTic ? FilterDOT : FilterSpellDamage;
|
||||
else
|
||||
filter = FilterNone; //cant filter our own hits
|
||||
}
|
||||
else {
|
||||
filter = FilterNone; //cant filter our own hits
|
||||
}
|
||||
}
|
||||
else if (damage == -5)
|
||||
filter = FilterNone; //cant filter invulnerable
|
||||
@@ -4299,10 +4290,12 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
|
||||
//send damage to all clients around except the specified skip mob (attacker or the attacker's owner) and ourself
|
||||
if (damage > 0) {
|
||||
if (spell_id != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(spell_id)) {
|
||||
filter = iBuffTic ? FilterDOT : FilterSpellDamage;
|
||||
else
|
||||
}
|
||||
else {
|
||||
filter = FilterOthersHit;
|
||||
}
|
||||
}
|
||||
else if (damage == -5)
|
||||
filter = FilterNone; //cant filter invulnerable
|
||||
@@ -4363,7 +4356,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
else {
|
||||
//else, it is a buff tic...
|
||||
// So we can see our dot dmg like live shows it.
|
||||
if (spell_id != SPELL_UNKNOWN && damage > 0 && attacker && attacker != this && !attacker->IsCorpse()) {
|
||||
if (IsValidSpell(spell_id) && damage > 0 && attacker && attacker != this && !attacker->IsCorpse()) {
|
||||
//might filter on (attack_skill>200 && attack_skill<250), but I dont think we need it
|
||||
if (attacker->IsClient()) {
|
||||
attacker->FilteredMessageString(attacker, Chat::DotDamage,
|
||||
@@ -4756,7 +4749,7 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
// Not ranged
|
||||
if (!rangedattk) {
|
||||
// Perma procs (Not used for AA, they are handled below)
|
||||
if (PermaProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(PermaProcs[i].spellID)) {
|
||||
if (zone->random.Roll(PermaProcs[i].chance)) { // TODO: Do these get spell bonus?
|
||||
LogCombat("Permanent proc [{}] procing spell [{}] ([{}] percent chance)", i, PermaProcs[i].spellID, PermaProcs[i].chance);
|
||||
ExecWeaponProc(nullptr, PermaProcs[i].spellID, on);
|
||||
@@ -4767,7 +4760,7 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
}
|
||||
|
||||
// Spell procs (buffs)
|
||||
if (SpellProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(SpellProcs[i].spellID)) {
|
||||
if (SpellProcs[i].base_spellID == POISON_PROC) {
|
||||
poison_slot=i;
|
||||
continue; // Process the poison proc last per @mackal
|
||||
@@ -4792,7 +4785,7 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
}
|
||||
else if (rangedattk) { // ranged only
|
||||
// ranged spell procs (buffs)
|
||||
if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(RangedProcs[i].spellID)) {
|
||||
|
||||
passed_skill_limit_check = PassLimitToSkill(skillinuse, RangedProcs[i].base_spellID, ProcType::RANGED_PROC);
|
||||
|
||||
|
||||
+5
-4
@@ -1858,12 +1858,13 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
newbon->AssistRange = -1;
|
||||
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(i = 0; i < buff_count; i++) {
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN){
|
||||
for (i = 0; i < buff_count; i++) {
|
||||
if (IsValidSpell(buffs[i].spellid)) {
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining, i, buffs[i].instrument_mod);
|
||||
|
||||
if (buffs[i].hit_number > 0)
|
||||
if (buffs[i].hit_number > 0) {
|
||||
Numhits(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1874,7 +1875,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
//Disables a specific spell effect bonus completely, can also be limited to negate only item, AA or spell bonuses.
|
||||
if (spellbonuses.NegateEffects){
|
||||
for(i = 0; i < buff_count; i++) {
|
||||
if( (buffs[i].spellid != SPELL_UNKNOWN) && (IsEffectInSpell(buffs[i].spellid, SE_NegateSpellEffect)) )
|
||||
if(IsValidSpell(buffs[i].spellid) && (IsEffectInSpell(buffs[i].spellid, SE_NegateSpellEffect)) )
|
||||
NegateSpellEffectBonuses(buffs[i].spellid);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -77,7 +77,7 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
|
||||
SetBotCharmer(false);
|
||||
SetPetChooser(false);
|
||||
SetRangerAutoWeaponSelect(false);
|
||||
SetTaunting(GetClass() == WARRIOR);
|
||||
SetTaunting(GetClass() == WARRIOR || GetClass() == PALADIN || GetClass() == SHADOWKNIGHT);
|
||||
SetDefaultBotStance();
|
||||
|
||||
SetAltOutOfCombatBehavior(GetClass() == BARD); // will need to be updated if more classes make use of this flag
|
||||
@@ -5352,7 +5352,7 @@ void Bot::Damage(Mob *from, int64 damage, uint16 spell_id, EQ::skills::SkillType
|
||||
|
||||
attacked_timer.Start(CombatEventTimer_expire);
|
||||
// if spell is lifetap add hp to the caster
|
||||
if (spell_id != SPELL_UNKNOWN && IsLifetapSpell(spell_id)) {
|
||||
if (IsValidSpell(spell_id) && IsLifetapSpell(spell_id)) {
|
||||
int64 healed = GetActSpellHealing(spell_id, damage);
|
||||
LogCombatDetail("Applying lifetap heal of [{}] to [{}]", healed, GetCleanName());
|
||||
HealDamage(healed);
|
||||
@@ -7043,7 +7043,7 @@ void Bot::CalcRestState() {
|
||||
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (unsigned int j = 0; j < buff_count; j++) {
|
||||
if(buffs[j].spellid != SPELL_UNKNOWN) {
|
||||
if(IsValidSpell(buffs[j].spellid)) {
|
||||
if(IsDetrimentalSpell(buffs[j].spellid) && (buffs[j].ticsremaining > 0))
|
||||
if(!DetrimentalSpellAllowsRest(buffs[j].spellid))
|
||||
return;
|
||||
@@ -7294,7 +7294,7 @@ void Bot::DoEnduranceUpkeep() {
|
||||
uint32 buffs_i;
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (buffs_i = 0; buffs_i < buff_count; buffs_i++) {
|
||||
if (buffs[buffs_i].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[buffs_i].spellid)) {
|
||||
int upkeep = spells[buffs[buffs_i].spellid].endurance_upkeep;
|
||||
if(upkeep > 0) {
|
||||
if(cost_redux > 0) {
|
||||
@@ -8716,7 +8716,7 @@ bool Bot::GetNeedsCured(Mob *tar) {
|
||||
int buffsWithCounters = 0;
|
||||
needCured = true;
|
||||
for (unsigned int j = 0; j < buff_count; j++) {
|
||||
if(tar->GetBuffs()[j].spellid != SPELL_UNKNOWN) {
|
||||
if(IsValidSpell(tar->GetBuffs()[j].spellid)) {
|
||||
if(CalculateCounters(tar->GetBuffs()[j].spellid) > 0) {
|
||||
buffsWithCounters++;
|
||||
if(buffsWithCounters == 1 && (tar->GetBuffs()[j].ticsremaining < 2 || (int32)((tar->GetBuffs()[j].ticsremaining * 6) / tar->GetBuffs()[j].counters) < 2)) {
|
||||
|
||||
@@ -1514,8 +1514,9 @@ bool BotDatabase::SavePetBuffs(const uint32 bot_id, const SpellBuff_Struct* pet_
|
||||
return true;
|
||||
|
||||
for (int buff_index = 0; buff_index < PET_BUFF_COUNT; ++buff_index) {
|
||||
if (!pet_buffs[buff_index].spellid || pet_buffs[buff_index].spellid == SPELL_UNKNOWN)
|
||||
if (!IsValidSpell(pet_buffs[buff_index].spellid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
query = StringFormat(
|
||||
"INSERT INTO `bot_pet_buffs` ("
|
||||
|
||||
+5
-24
@@ -922,9 +922,6 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
//Return true to proceed, false to return
|
||||
if(!mod_client_message(message, chan_num)) { return; }
|
||||
|
||||
// Garble the message based on drunkness
|
||||
if (m_pp.intoxication > 0 && !(RuleB(Chat, ServerWideOOC) && chan_num == ChatChannel_OOC) && !GetGM()) {
|
||||
GarbleMessage(message, (int)(m_pp.intoxication / 3));
|
||||
@@ -2544,10 +2541,7 @@ bool Client::CheckIncreaseSkill(EQ::skills::SkillType skillid, Mob *against_who,
|
||||
against_who->IsClient() ||
|
||||
GetLevelCon(against_who->GetLevel()) == CON_GRAY
|
||||
) {
|
||||
//false by default
|
||||
if (!mod_can_increase_skill(skillid, against_who)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2564,7 +2558,6 @@ bool Client::CheckIncreaseSkill(EQ::skills::SkillType skillid, Mob *against_who,
|
||||
// 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)
|
||||
@@ -2961,8 +2954,6 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
|
||||
max_percent = 70 + maxHPBonus;
|
||||
}
|
||||
|
||||
max_percent = mod_bindwound_percent(max_percent, bindmob);
|
||||
|
||||
int64 max_hp = bindmob->GetMaxHP() * max_percent / 100;
|
||||
|
||||
// send bindmob new hp's
|
||||
@@ -2983,8 +2974,6 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
|
||||
|
||||
bindhps += bindhps * bindBonus / 100;
|
||||
|
||||
bindhps = mod_bindwound_hp(bindhps, bindmob);
|
||||
|
||||
// if the bind takes them above the max bindable
|
||||
// cap it at that value. Dont know if live does it this way
|
||||
// but it makes sense to me.
|
||||
@@ -3026,8 +3015,6 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
|
||||
if (max_percent > 100)
|
||||
max_percent = 100;
|
||||
|
||||
max_percent = mod_bindwound_percent(max_percent, bindmob);
|
||||
|
||||
int max_hp = (bindmob->GetMaxHP() * max_percent) / 100;
|
||||
if (max_hp > bindmob->GetMaxHP())
|
||||
max_hp = bindmob->GetMaxHP();
|
||||
@@ -3048,8 +3035,6 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
|
||||
if (bindhps < 3)
|
||||
bindhps = 3;
|
||||
|
||||
bindhps = mod_bindwound_hp(bindhps, bindmob);
|
||||
|
||||
bindhps += bindmob->GetHP();
|
||||
if (bindhps > max_hp)
|
||||
bindhps = max_hp;
|
||||
@@ -4108,8 +4093,8 @@ void Client::DiscoverItem(uint32 item_id) {
|
||||
}
|
||||
|
||||
if (parse->PlayerHasQuestSub(EVENT_DISCOVER_ITEM)) {
|
||||
const auto* item = database.GetItem(item_id);
|
||||
std::vector<std::any> args = {item};
|
||||
auto* item = database.CreateItem(item_id);
|
||||
std::vector<std::any> args = { item };
|
||||
|
||||
parse->EventPlayer(EVENT_DISCOVER_ITEM, this, "", item_id, &args);
|
||||
}
|
||||
@@ -6702,7 +6687,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
uint32 magic_rune_number = 0;
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (int i=0; i < buff_count; i++) {
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[i].spellid)) {
|
||||
if (buffs[i].melee_rune > 0) { rune_number += buffs[i].melee_rune; }
|
||||
|
||||
if (buffs[i].magic_rune > 0) { magic_rune_number += buffs[i].magic_rune; }
|
||||
@@ -8387,8 +8372,6 @@ void Client::Consume(const EQ::ItemData *item, uint8 type, int16 slot, bool auto
|
||||
return;
|
||||
|
||||
if (type == EQ::item::ItemTypeFood) {
|
||||
increase = mod_food_value(item, increase);
|
||||
|
||||
if (increase < 0)
|
||||
return;
|
||||
|
||||
@@ -8404,8 +8387,6 @@ void Client::Consume(const EQ::ItemData *item, uint8 type, int16 slot, bool auto
|
||||
LogFood("Eating from slot: [{}]", (int)slot);
|
||||
|
||||
} else {
|
||||
increase = mod_drink_value(item, increase);
|
||||
|
||||
if (increase < 0)
|
||||
return;
|
||||
|
||||
@@ -8513,7 +8494,7 @@ void Client::ShowNumHits()
|
||||
uint32 buffcount = GetMaxTotalSlots();
|
||||
for (uint32 buffslot = 0; buffslot < buffcount; buffslot++) {
|
||||
const Buffs_Struct &curbuff = buffs[buffslot];
|
||||
if (curbuff.spellid != SPELL_UNKNOWN && curbuff.hit_number)
|
||||
if (IsValidSpell(curbuff.spellid) && curbuff.hit_number)
|
||||
Message(0, "You have %d hits left on %s", curbuff.hit_number, GetSpellName(curbuff.spellid));
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -1598,28 +1598,6 @@ public:
|
||||
void Consume(const EQ::ItemData *item, uint8 type, int16 slot, bool auto_consume);
|
||||
void PlayMP3(const char* fname);
|
||||
void ExpeditionSay(const char *str, int ExpID);
|
||||
int mod_client_damage(int64 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);
|
||||
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);
|
||||
void mod_consider(Mob* tmob, Consider_Struct* con);
|
||||
bool mod_saylink(const std::string&, bool silentsaylink);
|
||||
int16 mod_pet_power(int16 act_power, uint16 spell_id);
|
||||
float mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spec);
|
||||
float mod_tradeskill_skillup(float chance_stage2);
|
||||
int32 mod_tribute_item_value(int32 pts, const EQ::ItemInstance* item);
|
||||
void mod_client_death_npc(Mob* killerMob);
|
||||
void mod_client_death_duel(Mob* killerMob);
|
||||
void mod_client_death_env();
|
||||
int64 mod_client_xp(int64 in_exp, NPC *npc);
|
||||
uint32 mod_client_xp_for_level(uint32 xp, uint16 check_level);
|
||||
int mod_client_haste_cap(int cap);
|
||||
int mod_consume(EQ::ItemData *item, EQ::item::ItemType type, int change);
|
||||
int mod_food_value(const EQ::ItemData *item, int change);
|
||||
int mod_drink_value(const EQ::ItemData *item, int change);
|
||||
|
||||
inline int32 GetEnvironmentDamageModifier() const { return environment_damage_modifier; }
|
||||
void SetEnvironmentDamageModifier(int32 val) { environment_damage_modifier = val; }
|
||||
|
||||
@@ -1047,7 +1047,6 @@ int Client::CalcHaste()
|
||||
else { // 1-50
|
||||
cap = level + 25;
|
||||
}
|
||||
cap = mod_client_haste_cap(cap);
|
||||
if (h > cap) {
|
||||
h = cap;
|
||||
}
|
||||
@@ -1064,7 +1063,6 @@ int Client::CalcHaste()
|
||||
h += spellbonuses.hastetype3 > 10 ? 10 : spellbonuses.hastetype3;
|
||||
}
|
||||
h += ExtraHaste; //GM granted haste.
|
||||
h = mod_client_haste(h);
|
||||
Haste = 100 + h;
|
||||
return Haste;
|
||||
}
|
||||
|
||||
+37
-37
@@ -1456,7 +1456,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
database.LoadBuffs(this);
|
||||
uint32 max_slots = GetMaxBuffSlots();
|
||||
for (int i = 0; i < BUFF_COUNT; i++) {
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[i].spellid)) {
|
||||
m_pp.buffs[i].spellid = buffs[i].spellid;
|
||||
m_pp.buffs[i].bard_modifier = buffs[i].instrument_mod;
|
||||
m_pp.buffs[i].effect_type = 2;
|
||||
@@ -4560,11 +4560,15 @@ void Client::Handle_OP_ClickDoor(const EQApplicationPacket *app)
|
||||
|
||||
// don't spam scripts with client controlled doors if not within distance
|
||||
if (within_distance) {
|
||||
int quest_return = 0;
|
||||
if (parse->PlayerHasQuestSub(EVENT_CLICK_DOOR)) {
|
||||
std::vector<std::any> args = { currentdoor };
|
||||
if (parse->EventPlayer(EVENT_CLICK_DOOR, this, std::to_string(cd->doorid), 0, &args) == 0) {
|
||||
currentdoor->HandleClick(this, 0);
|
||||
}
|
||||
std::vector<std::any> args = {currentdoor};
|
||||
|
||||
quest_return = parse->EventPlayer(EVENT_CLICK_DOOR, this, std::to_string(cd->doorid), 0, &args);
|
||||
}
|
||||
|
||||
if (quest_return == 0) {
|
||||
currentdoor->HandleClick(this, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -5115,8 +5119,6 @@ void Client::Handle_OP_Consider(const EQApplicationPacket *app)
|
||||
con->faction = FACTION_DUBIOUSLY;
|
||||
}
|
||||
|
||||
mod_consider(t, con);
|
||||
|
||||
QueuePacket(outapp);
|
||||
// only wanted to check raid target once
|
||||
// and need con to still be around so, do it here!
|
||||
@@ -6204,7 +6206,6 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (GetHP() <= 0) {
|
||||
mod_client_death_env();
|
||||
Death(0, 32000, SPELL_UNKNOWN, EQ::skills::SkillHandtoHand);
|
||||
}
|
||||
SendHPUpdate();
|
||||
@@ -8736,10 +8737,6 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (!response.empty()) {
|
||||
if (!mod_saylink(response, silentsaylink)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelMessageReceived(ChatChannel_Say, 0, 100, response.c_str(), nullptr, true);
|
||||
|
||||
if (!silentsaylink) {
|
||||
@@ -15242,34 +15239,37 @@ void Client::Handle_OP_Translocate(const EQApplicationPacket *app)
|
||||
zone->GetInstanceID() == PendingTranslocateData.instance_id
|
||||
);
|
||||
|
||||
int quest_return = 0;
|
||||
if (parse->SpellHasQuestSub(spell_id, EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE)) {
|
||||
if (parse->EventSpell(EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE, nullptr, this, spell_id, "", 0) == 0) {
|
||||
// If the spell has a translocate to bind effect, AND we are already in the zone the client
|
||||
// is bound in, use the GoToBind method. If we send OP_Translocate in this case, the client moves itself
|
||||
// to the bind coords it has from the PlayerProfile, but with the X and Y reversed. I suspect they are
|
||||
// reversed in the pp, and since spells like Gate are handled serverside, this has not mattered before.
|
||||
if (
|
||||
IsTranslocateSpell(spell_id) &&
|
||||
in_translocate_zone
|
||||
) {
|
||||
PendingTranslocate = false;
|
||||
GoToBind();
|
||||
return;
|
||||
}
|
||||
quest_return = parse->EventSpell(EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE, nullptr, this, spell_id, "", 0);
|
||||
}
|
||||
|
||||
////Was sending the packet back to initiate client zone...
|
||||
////but that could be abusable, so lets go through proper channels
|
||||
MovePC(
|
||||
PendingTranslocateData.zone_id,
|
||||
PendingTranslocateData.instance_id,
|
||||
PendingTranslocateData.x,
|
||||
PendingTranslocateData.y,
|
||||
PendingTranslocateData.z,
|
||||
PendingTranslocateData.heading,
|
||||
0,
|
||||
ZoneSolicited
|
||||
);
|
||||
if (quest_return == 0) {
|
||||
// If the spell has a translocate to bind effect, AND we are already in the zone the client
|
||||
// is bound in, use the GoToBind method. If we send OP_Translocate in this case, the client moves itself
|
||||
// to the bind coords it has from the PlayerProfile, but with the X and Y reversed. I suspect they are
|
||||
// reversed in the pp, and since spells like Gate are handled serverside, this has not mattered before.
|
||||
if (
|
||||
IsTranslocateSpell(spell_id) &&
|
||||
in_translocate_zone
|
||||
) {
|
||||
PendingTranslocate = false;
|
||||
GoToBind();
|
||||
return;
|
||||
}
|
||||
|
||||
////Was sending the packet back to initiate client zone...
|
||||
////but that could be abusable, so lets go through proper channels
|
||||
MovePC(
|
||||
PendingTranslocateData.zone_id,
|
||||
PendingTranslocateData.instance_id,
|
||||
PendingTranslocateData.x,
|
||||
PendingTranslocateData.y,
|
||||
PendingTranslocateData.z,
|
||||
PendingTranslocateData.heading,
|
||||
0,
|
||||
ZoneSolicited
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1917,7 +1917,7 @@ void Client::DoEnduranceUpkeep() {
|
||||
uint32 buffs_i;
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (buffs_i = 0; buffs_i < buff_count; buffs_i++) {
|
||||
if (buffs[buffs_i].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[buffs_i].spellid)) {
|
||||
int upkeep = spells[buffs[buffs_i].spellid].endurance_upkeep;
|
||||
if(upkeep > 0) {
|
||||
has_effect = true;
|
||||
@@ -1966,7 +1966,7 @@ void Client::CalcRestState()
|
||||
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (unsigned int j = 0; j < buff_count; j++) {
|
||||
if(buffs[j].spellid != SPELL_UNKNOWN) {
|
||||
if(IsValidSpell(buffs[j].spellid)) {
|
||||
if(IsDetrimentalSpell(buffs[j].spellid) && (buffs[j].ticsremaining > 0))
|
||||
if(!DetrimentalSpellAllowsRest(buffs[j].spellid))
|
||||
return;
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ public:
|
||||
uint16 GetSize() { return m_size; }
|
||||
uint32 GetClientVersionMask() { return m_client_version_mask; }
|
||||
uint32 GetDoorDBID() { return m_database_id; }
|
||||
uint32 GetDoorParam() { return m_door_param; }
|
||||
int32 GetDoorParam() { return m_door_param; }
|
||||
uint32 GetEntityID() { return m_entity_id; }
|
||||
uint32 GetGuildID() { return m_guild_id; }
|
||||
uint32 GetKeyItem() { return m_key_item_id; }
|
||||
@@ -82,7 +82,7 @@ private:
|
||||
uint8 m_no_key_ring;
|
||||
uint8 m_trigger_door;
|
||||
uint8 m_trigger_type;
|
||||
uint32 m_door_param;
|
||||
int32 m_door_param;
|
||||
uint16 m_size;
|
||||
int m_invert_state;
|
||||
uint32 m_entity_id;
|
||||
|
||||
@@ -161,6 +161,8 @@ const char *QuestEventSubroutines[_LargestEventID] = {
|
||||
"EVENT_TASK_BEFORE_UPDATE",
|
||||
"EVENT_AA_BUY",
|
||||
"EVENT_AA_GAIN",
|
||||
"EVENT_AA_EXP_GAIN",
|
||||
"EVENT_EXP_GAIN",
|
||||
"EVENT_PAYLOAD",
|
||||
"EVENT_LEVEL_DOWN",
|
||||
"EVENT_GM_COMMAND",
|
||||
@@ -2084,6 +2086,16 @@ void PerlembParser::ExportEventVariables(
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_AA_EXP_GAIN: {
|
||||
ExportVar(package_name.c_str(), "aa_exp_gained", data);
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_EXP_GAIN: {
|
||||
ExportVar(package_name.c_str(), "exp_gained", data);
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_INSPECT: {
|
||||
ExportVar(package_name.c_str(), "target_id", extradata);
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
|
||||
@@ -106,6 +106,8 @@ typedef enum {
|
||||
EVENT_TASK_BEFORE_UPDATE,
|
||||
EVENT_AA_BUY,
|
||||
EVENT_AA_GAIN,
|
||||
EVENT_AA_EXP_GAIN,
|
||||
EVENT_EXP_GAIN,
|
||||
EVENT_PAYLOAD,
|
||||
EVENT_LEVEL_DOWN,
|
||||
EVENT_GM_COMMAND,
|
||||
|
||||
+41
-20
@@ -804,14 +804,23 @@ void Client::SetEXP(uint64 set_exp, uint64 set_aaxp, bool isrezzexp) {
|
||||
}
|
||||
}
|
||||
|
||||
if (parse->PlayerHasQuestSub(EVENT_EXP_GAIN) && m_pp.exp != set_exp) {
|
||||
parse->EventPlayer(EVENT_EXP_GAIN, this, std::to_string(set_exp - m_pp.exp), 0);
|
||||
}
|
||||
|
||||
if (parse->PlayerHasQuestSub(EVENT_AA_EXP_GAIN) && m_pp.expAA != set_aaxp) {
|
||||
parse->EventPlayer(EVENT_AA_EXP_GAIN, this, std::to_string(set_aaxp - m_pp.expAA), 0);
|
||||
}
|
||||
|
||||
//set the client's EXP and AAEXP
|
||||
m_pp.exp = set_exp;
|
||||
m_pp.expAA = set_aaxp;
|
||||
|
||||
if (GetLevel() < 51) {
|
||||
m_epp.perAA = 0; // turn off aa exp if they drop below 51
|
||||
} else
|
||||
SendAlternateAdvancementStats(); //otherwise, send them an AA update
|
||||
} else {
|
||||
SendAlternateAdvancementStats(); //otherwise, send them an AA update
|
||||
}
|
||||
|
||||
//send the expdata in any case so the xp bar isnt stuck after leveling
|
||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel()+1);
|
||||
@@ -1057,8 +1066,6 @@ uint32 Client::GetEXPForLevel(uint16 check_level)
|
||||
finalxp = uint64(finalxp * classmod);
|
||||
}
|
||||
|
||||
finalxp = mod_client_xp_for_level(finalxp, check_level);
|
||||
|
||||
return finalxp;
|
||||
}
|
||||
|
||||
@@ -1108,11 +1115,11 @@ void Group::SplitExp(const uint64 exp, Mob* other) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto group_experience = exp;
|
||||
auto group_experience = exp;
|
||||
const auto highest_level = GetHighestLevel();
|
||||
|
||||
auto group_modifier = 1.0f;
|
||||
if (RuleB(Character, EnableGroupEXPModifier)) {
|
||||
if (RuleB(Character, EnableGroupMemberEXPModifier)) {
|
||||
if (EQ::ValueWithin(member_count, 2, 5)) {
|
||||
group_modifier = 1 + RuleR(Character, GroupMemberEXPModifier) * (member_count - 1); // 2 = 1.2x, 3 = 1.4x, 4 = 1.6x, 5 = 1.8x
|
||||
} else if (member_count == 6) {
|
||||
@@ -1121,11 +1128,18 @@ void Group::SplitExp(const uint64 exp, Mob* other) {
|
||||
}
|
||||
|
||||
if (EQ::ValueWithin(member_count, 2, 6)) {
|
||||
group_experience += static_cast<uint64>(
|
||||
static_cast<float>(exp) *
|
||||
group_modifier *
|
||||
RuleR(Character, GroupExpMultiplier)
|
||||
);
|
||||
if (RuleB(Character, EnableGroupEXPModifier)) {
|
||||
group_experience += static_cast<uint64>(
|
||||
static_cast<float>(exp) *
|
||||
group_modifier *
|
||||
RuleR(Character, GroupExpMultiplier)
|
||||
);
|
||||
} else {
|
||||
group_experience += static_cast<uint64>(
|
||||
static_cast<float>(exp) *
|
||||
group_modifier
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8 consider_level = Mob::GetLevelCon(highest_level, other->GetLevel());
|
||||
@@ -1135,8 +1149,8 @@ void Group::SplitExp(const uint64 exp, Mob* other) {
|
||||
|
||||
for (const auto& m : members) {
|
||||
if (m && m->IsClient()) {
|
||||
const int32 diff = m->GetLevel() - highest_level;
|
||||
int32 max_diff = -(m->GetLevel() * 15 / 10 - m->GetLevel());
|
||||
const int32 diff = m->GetLevel() - highest_level;
|
||||
int32 max_diff = -(m->GetLevel() * 15 / 10 - m->GetLevel());
|
||||
|
||||
if (max_diff > -5) {
|
||||
max_diff = -5;
|
||||
@@ -1165,23 +1179,30 @@ void Raid::SplitExp(const uint64 exp, Mob* other) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto raid_experience = exp;
|
||||
auto raid_experience = exp;
|
||||
const auto highest_level = GetHighestLevel();
|
||||
|
||||
raid_experience = static_cast<uint64>(
|
||||
static_cast<float>(raid_experience) *
|
||||
(1.0f - RuleR(Character, RaidExpMultiplier))
|
||||
);
|
||||
if (RuleB(Character, EnableRaidEXPModifier)) {
|
||||
raid_experience = static_cast<uint64>(
|
||||
static_cast<float>(raid_experience) *
|
||||
(1.0f - RuleR(Character, RaidExpMultiplier))
|
||||
);
|
||||
}
|
||||
|
||||
const auto consider_level = Mob::GetLevelCon(highest_level, other->GetLevel());
|
||||
if (consider_level == CON_GRAY) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 member_modifier = 1;
|
||||
if (RuleB(Character, EnableRaidMemberEXPModifier)) {
|
||||
member_modifier = member_count;
|
||||
}
|
||||
|
||||
for (const auto& m : members) {
|
||||
if (m.member) {
|
||||
const int32 diff = m.member->GetLevel() - highest_level;
|
||||
int32 max_diff = -(m.member->GetLevel() * 15 / 10 - m.member->GetLevel());
|
||||
int32 max_diff = -(m.member->GetLevel() * 15 / 10 - m.member->GetLevel());
|
||||
|
||||
if (max_diff > -5) {
|
||||
max_diff = -5;
|
||||
@@ -1189,7 +1210,7 @@ void Raid::SplitExp(const uint64 exp, Mob* other) {
|
||||
|
||||
if (diff >= max_diff) {
|
||||
const uint64 tmp = (m.member->GetLevel() + 3) * (m.member->GetLevel() + 3) * 75 * 35 / 10;
|
||||
const uint64 tmp2 = (raid_experience / member_count) + 1;
|
||||
const uint64 tmp2 = (raid_experience / member_modifier) + 1;
|
||||
m.member->AddEXP(tmp < tmp2 ? tmp : tmp2, consider_level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ void command_heromodel(Client *c, const Seperator *sep)
|
||||
t = c->GetTarget();
|
||||
}
|
||||
|
||||
auto hero_forge_model = std::stoul(sep->arg[1]);
|
||||
auto hero_forge_model = Strings::IsNumber(sep->arg[1]) ? std::stoul(sep->arg[1]) : 0;
|
||||
|
||||
if (arguments > 1) {
|
||||
auto slot = static_cast<uint8>(std::stoul(sep->arg[2]));
|
||||
|
||||
+3
-2
@@ -848,13 +848,14 @@ void Client::DropItem(int16 slot_id, bool recurse)
|
||||
}
|
||||
}
|
||||
}
|
||||
invalid_drop = nullptr;
|
||||
|
||||
|
||||
std::string message = fmt::format(
|
||||
"Tried to drop an item on the ground that was no-drop! item_name [{}] item_id ({})",
|
||||
invalid_drop->GetItem()->Name,
|
||||
invalid_drop->GetItem()->ID
|
||||
);
|
||||
|
||||
invalid_drop = nullptr;
|
||||
RecordPlayerEventLog(PlayerEvent::POSSIBLE_HACK, PlayerEvent::PossibleHackEvent{.message = message});
|
||||
GetInv().DeleteItem(slot_id);
|
||||
return;
|
||||
|
||||
@@ -4736,7 +4736,9 @@ luabind::scope lua_register_events() {
|
||||
luabind::value("inspect", static_cast<int>(EVENT_INSPECT)),
|
||||
luabind::value("task_before_update", static_cast<int>(EVENT_TASK_BEFORE_UPDATE)),
|
||||
luabind::value("aa_buy", static_cast<int>(EVENT_AA_BUY)),
|
||||
luabind::value("aa_gain", static_cast<int>(EVENT_AA_GAIN)),
|
||||
luabind::value("aa_gained", static_cast<int>(EVENT_AA_GAIN)),
|
||||
luabind::value("aa_exp_gained", static_cast<int>(EVENT_AA_EXP_GAIN)),
|
||||
luabind::value("exp_gain", static_cast<int>(EVENT_EXP_GAIN)),
|
||||
luabind::value("payload", static_cast<int>(EVENT_PAYLOAD)),
|
||||
luabind::value("level_down", static_cast<int>(EVENT_LEVEL_DOWN)),
|
||||
luabind::value("gm_command", static_cast<int>(EVENT_GM_COMMAND)),
|
||||
|
||||
+5
-1
@@ -148,6 +148,8 @@ const char *LuaEvents[_LargestEventID] = {
|
||||
"event_task_before_update",
|
||||
"event_aa_buy",
|
||||
"event_aa_gain",
|
||||
"event_aa_exp_gain",
|
||||
"event_exp_gain",
|
||||
"event_payload",
|
||||
"event_level_down",
|
||||
"event_gm_command",
|
||||
@@ -162,7 +164,7 @@ const char *LuaEvents[_LargestEventID] = {
|
||||
"event_damage_taken",
|
||||
"event_item_click_client",
|
||||
"event_item_click_cast_client",
|
||||
"event_destroy_item_client"
|
||||
"event_destroy_item_client",
|
||||
"event_drop_item_client"
|
||||
};
|
||||
|
||||
@@ -275,6 +277,8 @@ LuaParser::LuaParser() {
|
||||
PlayerArgumentDispatch[EVENT_INSPECT] = handle_player_inspect;
|
||||
PlayerArgumentDispatch[EVENT_AA_BUY] = handle_player_aa_buy;
|
||||
PlayerArgumentDispatch[EVENT_AA_GAIN] = handle_player_aa_gain;
|
||||
PlayerArgumentDispatch[EVENT_AA_EXP_GAIN] = handle_player_aa_exp_gain;
|
||||
PlayerArgumentDispatch[EVENT_EXP_GAIN] = handle_player_exp_gain;
|
||||
PlayerArgumentDispatch[EVENT_PAYLOAD] = handle_player_payload;
|
||||
PlayerArgumentDispatch[EVENT_LEVEL_UP] = handle_player_level_up;
|
||||
PlayerArgumentDispatch[EVENT_LEVEL_DOWN] = handle_player_level_down;
|
||||
|
||||
@@ -1181,6 +1181,30 @@ void handle_player_aa_gain(
|
||||
lua_setfield(L, -2, "aa_gained");
|
||||
}
|
||||
|
||||
void handle_player_aa_exp_gain(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
Client* client,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
) {
|
||||
lua_pushinteger(L, std::stoull(data));
|
||||
lua_setfield(L, -2, "aa_exp_gained");
|
||||
}
|
||||
|
||||
void handle_player_exp_gain(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
Client* client,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
) {
|
||||
lua_pushinteger(L, std::stoull(data));
|
||||
lua_setfield(L, -2, "exp_gained");
|
||||
}
|
||||
|
||||
void handle_player_level_up(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
|
||||
@@ -608,6 +608,24 @@ void handle_player_aa_gain(
|
||||
std::vector<std::any> *extra_pointers
|
||||
);
|
||||
|
||||
void handle_player_aa_exp_gain(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
Client* client,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
);
|
||||
|
||||
void handle_player_exp_gain(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
Client* client,
|
||||
std::string data,
|
||||
uint32 extra_data,
|
||||
std::vector<std::any> *extra_pointers
|
||||
);
|
||||
|
||||
void handle_player_payload(
|
||||
QuestInterface *parse,
|
||||
lua_State* L,
|
||||
|
||||
+4
-4
@@ -1113,7 +1113,7 @@ void Merc::DoEnduranceUpkeep() {
|
||||
uint32 buffs_i;
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (buffs_i = 0; buffs_i < buff_count; buffs_i++) {
|
||||
if (buffs[buffs_i].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[buffs_i].spellid)) {
|
||||
int upkeep = spells[buffs[buffs_i].spellid].endurance_upkeep;
|
||||
if(upkeep > 0) {
|
||||
has_effect = true;
|
||||
@@ -1158,7 +1158,7 @@ void Merc::CalcRestState() {
|
||||
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (unsigned int j = 0; j < buff_count; j++) {
|
||||
if(buffs[j].spellid != SPELL_UNKNOWN) {
|
||||
if(IsValidSpell(buffs[j].spellid)) {
|
||||
if(IsDetrimentalSpell(buffs[j].spellid) && (buffs[j].ticsremaining > 0))
|
||||
if(!DetrimentalSpellAllowsRest(buffs[j].spellid))
|
||||
return;
|
||||
@@ -2579,7 +2579,7 @@ int64 Merc::GetFocusEffect(focusType type, uint16 spell_id, bool from_buff_tic)
|
||||
if (equipment[x] == 0)
|
||||
continue;
|
||||
TempItem = database.GetItem(equipment[x]);
|
||||
if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) {
|
||||
if (TempItem && IsValidSpell(TempItem->Focus.Effect)) {
|
||||
if(rand_effectiveness) {
|
||||
focus_max = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id, true);
|
||||
if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) {
|
||||
@@ -3895,7 +3895,7 @@ bool Merc::GetNeedsCured(Mob *tar) {
|
||||
needCured = true;
|
||||
|
||||
for (unsigned int j = 0; j < buff_count; j++) {
|
||||
if(tar->GetBuffs()[j].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(tar->GetBuffs()[j].spellid)) {
|
||||
if(CalculateCounters(tar->GetBuffs()[j].spellid) > 0) {
|
||||
buffsWithCounters++;
|
||||
|
||||
|
||||
+35
-37
@@ -1378,26 +1378,22 @@ void Mob::CreateHPPacket(EQApplicationPacket* app)
|
||||
ds->hp = (int)GetHPRatio();
|
||||
|
||||
// hp event
|
||||
if (IsNPC() && (GetNextHPEvent() > 0))
|
||||
{
|
||||
if (ds->hp < GetNextHPEvent())
|
||||
{
|
||||
if (IsNPC() && (GetNextHPEvent() > 0)) {
|
||||
if (ds->hp < GetNextHPEvent()) {
|
||||
std::string export_string = fmt::format("{}", GetNextHPEvent());
|
||||
SetNextHPEvent(-1);
|
||||
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_HP)) {
|
||||
parse->EventNPC(EVENT_HP, CastToNPC(), nullptr, std::to_string(GetNextHPEvent()), 0);
|
||||
if (parse->HasQuestSub(CastToNPC()->GetNPCTypeID(), EVENT_HP)) {
|
||||
parse->EventNPC(EVENT_HP, CastToNPC(), nullptr, export_string, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsNPC() && (GetNextIncHPEvent() > 0))
|
||||
{
|
||||
if (ds->hp > GetNextIncHPEvent())
|
||||
{
|
||||
if (IsNPC() && (GetNextIncHPEvent() > 0)) {
|
||||
if (ds->hp > GetNextIncHPEvent()) {
|
||||
std::string export_string = fmt::format("{}", GetNextIncHPEvent());
|
||||
SetNextIncHPEvent(-1);
|
||||
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_HP)) {
|
||||
parse->EventNPC(EVENT_HP, CastToNPC(), nullptr, std::to_string(GetNextIncHPEvent()), 1);
|
||||
if (parse->HasQuestSub(CastToNPC()->GetNPCTypeID(), EVENT_HP)) {
|
||||
parse->EventNPC(EVENT_HP, CastToNPC(), nullptr, export_string, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2335,7 +2331,7 @@ void Mob::ShowBuffs(Client* client) {
|
||||
uint32 i;
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (i=0; i < buff_count; i++) {
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[i].spellid)) {
|
||||
if (spells[buffs[i].spellid].buff_duration_formula == DF_Permanent)
|
||||
client->Message(Chat::White, " %i: %s: Permanent", i, spells[buffs[i].spellid].name);
|
||||
else
|
||||
@@ -2369,7 +2365,7 @@ void Mob::ShowBuffList(Client* client) {
|
||||
uint32 i;
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (i = 0; i < buff_count; i++) {
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[i].spellid)) {
|
||||
if (spells[buffs[i].spellid].buff_duration_formula == DF_Permanent)
|
||||
client->Message(Chat::White, " %i: %s: Permanent", i, spells[buffs[i].spellid].name);
|
||||
else
|
||||
@@ -4107,7 +4103,7 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on,
|
||||
return;
|
||||
}
|
||||
|
||||
if(spell_id == SPELL_UNKNOWN || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
||||
if(!IsValidSpell(spell_id) || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
||||
//This is so 65535 doesn't get passed to the client message and to logs because it is not relavant information for debugging.
|
||||
return;
|
||||
}
|
||||
@@ -4265,6 +4261,10 @@ void Mob::SetTarget(Mob *mob)
|
||||
parse->BotHasQuestSub(EVENT_TARGET_CHANGE)
|
||||
);
|
||||
|
||||
if (IsClient() && CastToClient()->admin > AccountStatus::GMMgmt) {
|
||||
DisplayInfo(mob);
|
||||
}
|
||||
|
||||
if (has_target_change_event) {
|
||||
std::vector<std::any> args;
|
||||
|
||||
@@ -4279,10 +4279,6 @@ void Mob::SetTarget(Mob *mob)
|
||||
parse->EventPlayer(EVENT_TARGET_CHANGE, CastToClient(), "", 0, &args);
|
||||
}
|
||||
|
||||
if (CastToClient()->admin > AccountStatus::GMMgmt) {
|
||||
DisplayInfo(mob);
|
||||
}
|
||||
|
||||
CastToClient()->SetBotPrecombat(false); // Any change in target will nullify this flag (target == mob checked above)
|
||||
} else if (IsBot()) {
|
||||
if (parse->BotHasQuestSub(EVENT_TARGET_CHANGE)) {
|
||||
@@ -4368,8 +4364,9 @@ int Mob::CountDispellableBuffs()
|
||||
if(spells[buffs[x].spellid].good_effect == 0)
|
||||
continue;
|
||||
|
||||
if(buffs[x].spellid != SPELL_UNKNOWN && spells[buffs[x].spellid].buff_duration_formula != DF_Permanent)
|
||||
if(IsValidSpell(buffs[x].spellid) && spells[buffs[x].spellid].buff_duration_formula != DF_Permanent) {
|
||||
val++;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@@ -4930,9 +4927,9 @@ bool Mob::TryFadeEffect(int slot)
|
||||
if(spell_id)
|
||||
{
|
||||
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
return false;
|
||||
|
||||
}
|
||||
if(IsValidSpell(spell_id))
|
||||
{
|
||||
if (IsBeneficialSpell(spell_id)) {
|
||||
@@ -5289,7 +5286,7 @@ void Mob::DoKnockback(Mob *caster, uint32 push_back, uint32 push_up)
|
||||
|
||||
void Mob::TrySpellOnKill(uint8 level, uint16 spell_id)
|
||||
{
|
||||
if (spell_id != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(spell_id))
|
||||
{
|
||||
if(IsEffectInSpell(spell_id, SE_ProcOnSpellKillShot)) {
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
@@ -5603,7 +5600,7 @@ void Mob::DoGravityEffect()
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for (int slot = 0; slot < buff_count; slot++)
|
||||
{
|
||||
if (buffs[slot].spellid != SPELL_UNKNOWN && IsEffectInSpell(buffs[slot].spellid, SE_GravityEffect))
|
||||
if (IsValidSpell(buffs[slot].spellid) && IsEffectInSpell(buffs[slot].spellid, SE_GravityEffect))
|
||||
{
|
||||
for (int i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
@@ -6174,19 +6171,20 @@ FACTION_VALUE Mob::GetSpecialFactionCon(Mob* iOther) {
|
||||
|
||||
bool Mob::HasSpellEffect(int effect_id)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(i = 0; i < buff_count; i++)
|
||||
{
|
||||
if(buffs[i].spellid == SPELL_UNKNOWN) { continue; }
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(i = 0; i < buff_count; i++)
|
||||
{
|
||||
if (!IsValidSpell(buffs[i].spellid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(IsEffectInSpell(buffs[i].spellid, effect_id))
|
||||
{
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
if (IsEffectInSpell(buffs[i].spellid, effect_id)) {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int Mob::GetSpecialAbility(int ability)
|
||||
|
||||
-39
@@ -1323,45 +1323,6 @@ public:
|
||||
inline uint32 GetEmoteID() { return emoteid; }
|
||||
|
||||
bool HasSpellEffect(int effect_id);
|
||||
int mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob *caster, uint16 caster_id);
|
||||
float mod_hit_chance(float chancetohit, EQ::skills::SkillType skillinuse, Mob *attacker);
|
||||
float mod_riposte_chance(float ripostchance, Mob *attacker);
|
||||
float mod_block_chance(float blockchance, Mob *attacker);
|
||||
float mod_parry_chance(float parrychance, Mob *attacker);
|
||||
float mod_dodge_chance(float dodgechance, Mob *attacker);
|
||||
float mod_monk_weight(float monkweight, Mob *attacker);
|
||||
float mod_mitigation_rating(float mitigation_rating, Mob *attacker);
|
||||
float mod_attack_rating(float attack_rating, Mob *defender);
|
||||
int64 mod_kick_damage(int64 dmg);
|
||||
int64 mod_bash_damage(int64 dmg);
|
||||
int64 mod_frenzy_damage(int64 dmg);
|
||||
int64 mod_monk_special_damage(int64 ndamage, EQ::skills::SkillType skill_type);
|
||||
int64 mod_backstab_damage(int64 ndamage);
|
||||
int64 mod_archery_bonus_chance(int bonuschance, const EQ::ItemInstance *RangeWeapon);
|
||||
uint64 mod_archery_bonus_damage(uint64 MaxDmg, const EQ::ItemInstance *RangeWeapon);
|
||||
int64 mod_archery_damage(int64 TotalDmg, bool hasbonus, const EQ::ItemInstance *RangeWeapon);
|
||||
uint64 mod_throwing_damage(uint64 MaxDmg);
|
||||
int32 mod_cast_time(int32 cast_time);
|
||||
int mod_buff_duration(int res, Mob *caster, Mob *target, uint16 spell_id);
|
||||
int mod_spell_stack(uint16 spellid1, int caster_level1, Mob *caster1, uint16 spellid2, int caster_level2, Mob *caster2);
|
||||
int mod_spell_resist(
|
||||
int resist_chance,
|
||||
int level_mod,
|
||||
int resist_modifier,
|
||||
int target_resist,
|
||||
uint8 resist_type,
|
||||
uint16 spell_id,
|
||||
Mob *caster
|
||||
);
|
||||
void mod_spell_cast(
|
||||
uint16 spell_id,
|
||||
Mob *spelltar,
|
||||
bool reflect,
|
||||
bool use_resist_adjust,
|
||||
int16 resist_adjust,
|
||||
bool isproc
|
||||
);
|
||||
bool mod_will_aggro(Mob *attacker, Mob *on);
|
||||
|
||||
//Command #Tune functions
|
||||
void TuneGetStats(Mob* defender, Mob *attacker);
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
#include "mob.h"
|
||||
#include "npc.h"
|
||||
#include "worldserver.h"
|
||||
#include "zone.h"
|
||||
|
||||
class Spawn2;
|
||||
struct Consider_Struct;
|
||||
struct DBTradeskillRecipe_Struct;
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
class ItemInstance;
|
||||
}
|
||||
|
||||
extern EntityList entity_list;
|
||||
extern Zone* zone;
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
//All functions that modify a value are passed the value as it was computed by default formulas and bonuses. In most cases this should be the final value that will be used.
|
||||
|
||||
//These are called when a zone boots or is repopped
|
||||
void Zone::mod_init() { return; }
|
||||
void Zone::mod_repop() { return; }
|
||||
|
||||
//Pre-spawn hook called from the NPC object to be spawned
|
||||
void NPC::mod_prespawn(Spawn2 *sp) { return; }
|
||||
|
||||
//Base damage from NPC::Attack
|
||||
int NPC::mod_npc_damage(int64 damage, EQ::skills::SkillType skillinuse, int hand, const EQ::ItemData* weapon, Mob* other) { return(damage); }
|
||||
|
||||
//Mob c has been given credit for a kill. This is called after the regular EVENT_KILLED_MERIT event.
|
||||
void NPC::mod_npc_killed_merit(Mob* c) { return; }
|
||||
|
||||
//Mob oos has been given credit for a kill. This is called after the regular EVENT_DEATH event.
|
||||
void NPC::mod_npc_killed(Mob* oos) { return; }
|
||||
|
||||
//Base damage from Client::Attack - can cover myriad skill types
|
||||
int Client::mod_client_damage(int64 damage, EQ::skills::SkillType skillinuse, int hand, const EQ::ItemInstance* weapon, Mob* other) { return(damage); }
|
||||
|
||||
//message is char[4096], don't screw it up. Return true for normal behavior, false to return immediately.
|
||||
// Channels:
|
||||
// 0 - Guild Chat
|
||||
// 2 - Group Chat
|
||||
// 3 - Shout
|
||||
// 4 - Auction
|
||||
// 5 - Out of Character
|
||||
// 6 - Broadcast
|
||||
// 7 - Tell
|
||||
// 8 - Say
|
||||
// 11 - GMSay
|
||||
// 15 - Raid Chat
|
||||
// 20 - UCS Relay for UF client and later
|
||||
// 22 - Emotes for UF and later
|
||||
bool Client::mod_client_message(char* message, uint8 chan_num) { return(true); }
|
||||
|
||||
//Skillup override. When this is called the regular skillup check has failed. Return false to proceed with default behavior.
|
||||
//This will NOT allow a client to increase skill past a cap.
|
||||
bool Client::mod_can_increase_skill(EQ::skills::SkillType skillid, Mob* against_who) { return(false); }
|
||||
|
||||
//chance of general skill increase, rolled against 0-99 where higher chance is better.
|
||||
double Client::mod_increase_skill_chance(double chance, Mob* against_who) { return(chance); }
|
||||
|
||||
//Max percent of health you can bind wound starting with default value for class, item, and AA bonuses
|
||||
int Client::mod_bindwound_percent(int max_percent, Mob* bindmob) { return(max_percent); }
|
||||
|
||||
//Final bind HP value after bonuses
|
||||
int Client::mod_bindwound_hp(int bindhps, Mob* bindmob) { return(bindhps); }
|
||||
|
||||
//Client haste as calculated by default formulas - In percent from 0-100
|
||||
int Client::mod_client_haste(int h) { return(h); }
|
||||
|
||||
//Haste cap override
|
||||
int Client::mod_client_haste_cap(int cap) { return(cap); }
|
||||
|
||||
//This is called when a client cons a mob
|
||||
void Client::mod_consider(Mob* tmob, Consider_Struct* con) { return; }
|
||||
|
||||
//Return true to continue with normal behavior, false returns in the parent function
|
||||
bool Client::mod_saylink(const std::string& response, bool silentsaylink) { return(true); }
|
||||
|
||||
//Client pet power as calculated by default formulas and bonuses
|
||||
int16 Client::mod_pet_power(int16 act_power, uint16 spell_id) { return(act_power); }
|
||||
|
||||
//Chance to combine rolled against a random 0-99 where higher is better.
|
||||
float Client::mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spec) { return(chance); }
|
||||
|
||||
//Chance to skillup rolled against a random 0-99 where higher is better.
|
||||
float Client::mod_tradeskill_skillup(float chance_stage2) { return(chance_stage2); }
|
||||
|
||||
//Tribute value override
|
||||
int32 Client::mod_tribute_item_value(int32 pts, const EQ::ItemInstance* item) { return(pts); }
|
||||
|
||||
//Death reporting
|
||||
void Client::mod_client_death_npc(Mob* killerMob) { return; }
|
||||
void Client::mod_client_death_duel(Mob* killerMob) { return; }
|
||||
void Client::mod_client_death_env() { return; }
|
||||
|
||||
//Calculated xp before consider modifier, called whenever a client gets XP for killing a mob.
|
||||
int64 Client::mod_client_xp(int64 in_xp, NPC *npc) { return(in_xp); }
|
||||
|
||||
//Client XP formula. Changes here will cause clients to change level after gaining or losing xp.
|
||||
//Either modify this before your server goes live, or be prepared to write a quest script that fixes levels.
|
||||
//To adjust how much XP is given per kill, use mod_client_xp
|
||||
uint32 Client::mod_client_xp_for_level(uint32 xp, uint16 check_level) { return(xp); }
|
||||
|
||||
//Food and drink values as computed by consume requests. Return < 0 to abort the request.
|
||||
int Client::mod_food_value(const EQ::ItemData *item, int change) { return(change); }
|
||||
int Client::mod_drink_value(const EQ::ItemData *item, int change) { return(change); }
|
||||
|
||||
//effect_vallue - Spell effect value as calculated by default formulas. You will want to ignore effects that don't lend themselves to scaling - pet ID's, gate coords, etc.
|
||||
int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster, uint16 caster_id) { return(effect_value); }
|
||||
|
||||
//chancetohit - 0 to 100 percent - set over 1000 for a guaranteed hit
|
||||
float Mob::mod_hit_chance(float chancetohit, EQ::skills::SkillType skillinuse, Mob* attacker) { return(chancetohit); }
|
||||
|
||||
//Final riposte chance
|
||||
float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { return(ripostechance); }
|
||||
|
||||
//Final block chance
|
||||
float Mob::mod_block_chance(float blockchance, Mob* attacker) { return(blockchance); }
|
||||
|
||||
//Final parry chance
|
||||
float Mob::mod_parry_chance(float parrychance, Mob* attacker) { return(parrychance); }
|
||||
|
||||
//Final dodge chance
|
||||
float Mob::mod_dodge_chance(float dodgechance, Mob* attacker) { return(dodgechance); }
|
||||
|
||||
//Usually 15, a monk under this weight threshold gets an AC bonus
|
||||
float Mob::mod_monk_weight(float monkweight, Mob* attacker) { return(monkweight); }
|
||||
|
||||
//Mitigation rating is compared to incoming attack rating. Higher is better.
|
||||
float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { return(mitigation_rating); }
|
||||
float Mob::mod_attack_rating(float attack_rating, Mob* defender) { return(attack_rating); }
|
||||
|
||||
//Kick damage after all other bonuses are applied
|
||||
int64 Mob::mod_kick_damage(int64 dmg) { return(dmg); }
|
||||
|
||||
//Slam and bash damage after all other bonuses are applied
|
||||
int64 Mob::mod_bash_damage(int64 dmg) { return(dmg); }
|
||||
|
||||
//Frenzy damage after all other bonuses are applied
|
||||
int64 Mob::mod_frenzy_damage(int64 dmg) { return(dmg); }
|
||||
|
||||
//Special attack damage after all other bonuses are applied.
|
||||
int64 Mob::mod_monk_special_damage(int64 ndamage, EQ::skills::SkillType skill_type) { return(ndamage); }
|
||||
|
||||
//ndamage - Backstab damage as calculated by default formulas
|
||||
int64 Mob::mod_backstab_damage(int64 ndamage) { return(ndamage); }
|
||||
|
||||
//Chance for 50+ archery bonus damage if Combat:UseArcheryBonusRoll is true.
|
||||
int64 Mob::mod_archery_bonus_chance(int bonuschance, const EQ::ItemInstance* RangeWeapon) { return(bonuschance); }
|
||||
|
||||
//Archery bonus damage
|
||||
uint64 Mob::mod_archery_bonus_damage(uint64 MaxDmg, const EQ::ItemInstance* RangeWeapon) { return(MaxDmg); }
|
||||
|
||||
//Final archery damage including bonus if it was applied.
|
||||
int64 Mob::mod_archery_damage(int64 TotalDmg, bool hasbonus, const EQ::ItemInstance* RangeWeapon) { return(TotalDmg); }
|
||||
|
||||
//Thrown weapon damage after all other calcs
|
||||
uint64 Mob::mod_throwing_damage(uint64 MaxDmg) { return(MaxDmg); }
|
||||
|
||||
//Spell cast time in milliseconds - will not sync with client cast time bar, but does work.
|
||||
int32 Mob::mod_cast_time(int32 cast_time) { return(cast_time); }
|
||||
|
||||
//res - Default buff duration formula
|
||||
int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { return(res); }
|
||||
|
||||
//Spell stack override - If this returns anything < 2, it will ignore all other stacking rules.
|
||||
// See spells.cpp: Mob::CheckStackConflict
|
||||
// 0 - No conflict
|
||||
// 1 - Overwrite, spellid1 is replaced by spellid2
|
||||
// -1 - Blocked, spellid2 will not land
|
||||
// 2 - Default stacking behavior
|
||||
int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint16 spellid2, int caster_level2, Mob* caster2) { return(2); }
|
||||
|
||||
//Sum of various resists rolled against a value of 200.
|
||||
int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) {
|
||||
return(resist_chance);
|
||||
}
|
||||
|
||||
//Spell is cast by this on spelltar, called from spellontarget after the event_cast_on NPC event
|
||||
void Mob::mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc) { return; }
|
||||
|
||||
//At this point all applicable aggro checks have succeeded. Attacker should aggro unless we return false.
|
||||
bool Mob::mod_will_aggro(Mob *attacker, Mob *on) { return(true); }
|
||||
@@ -1,187 +0,0 @@
|
||||
#include "../common/debug.h"
|
||||
#include "../common/timer.h"
|
||||
#include <cmath>
|
||||
#include <stdlib.h>
|
||||
#include "spawn2.h"
|
||||
#include "entity.h"
|
||||
#include "masterentity.h"
|
||||
#include "zone.h"
|
||||
#include "spawngroup.h"
|
||||
#include "zonedb.h"
|
||||
#include "../common/zone_store.h"
|
||||
#include "npc.h"
|
||||
#include "mob.h"
|
||||
#include "client.h"
|
||||
#include "worldserver.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "event_codes.h"
|
||||
#include "embparser.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
extern EntityList entity_list;
|
||||
extern Zone* zone;
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
//All functions that modify a value are passed the value as it was computed by default formulas and bonuses. In most cases this should be the final value that will be used.
|
||||
|
||||
//These are called when a zone boots or is repopped
|
||||
void Zone::mod_init() { return; }
|
||||
void Zone::mod_repop() { return; }
|
||||
|
||||
//Pre-spawn hook called from the NPC object to be spawned
|
||||
void NPC::mod_prespawn(Spawn2 *sp) { return; }
|
||||
|
||||
//Base damage from NPC::Attack
|
||||
int NPC::mod_npc_damage(int64 damage, SkillType skillinuse, int hand, const Item_Struct* weapon, Mob* other) { return(damage); }
|
||||
|
||||
//Mob c has been given credit for a kill. This is called after the regular EVENT_KILLED_MERIT event.
|
||||
void NPC::mod_npc_killed_merit(Mob* c) { return; }
|
||||
|
||||
//Mob oos has been given credit for a kill. This is called after the regular EVENT_DEATH event.
|
||||
void NPC::mod_npc_killed(Mob* oos) { return; }
|
||||
|
||||
//Base damage from Client::Attack - can cover myriad skill types
|
||||
int Client::mod_client_damage(int64 damage, SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other) { return(damage); }
|
||||
|
||||
//message is char[4096], don't screw it up. Return true for normal behavior, false to return immediately.
|
||||
// Channels:
|
||||
// 0 - Guild Chat
|
||||
// 2 - Group Chat
|
||||
// 3 - Shout
|
||||
// 4 - Auction
|
||||
// 5 - Out of Character
|
||||
// 6 - Broadcast
|
||||
// 7 - Tell
|
||||
// 8 - Say
|
||||
// 11 - GMSay
|
||||
// 15 - Raid Chat
|
||||
// 20 - UCS Relay for UF client and later
|
||||
// 22 - Emotes for UF and later
|
||||
bool Client::mod_client_message(char* message, uint8 chan_num) { return(true); }
|
||||
|
||||
//Skillup override. When this is called the regular skillup check has failed. Return false to proceed with default behavior.
|
||||
//This will NOT allow a client to increase skill past a cap.
|
||||
bool Client::mod_can_increase_skill(SkillType skillid, Mob* against_who) { return(false); }
|
||||
|
||||
//chance of general skill increase, rolled against 0-99 where higher chance is better.
|
||||
int16 Client::mod_increase_skill_chance(int16 chance, Mob* against_who) { return(chance); }
|
||||
|
||||
//Max percent of health you can bind wound starting with default value for class, item, and AA bonuses
|
||||
int Client::mod_bindwound_percent(int max_percent, Mob* bindmob) { return(max_percent); }
|
||||
|
||||
//Final bind HP value after bonuses
|
||||
int Client::mod_bindwound_hp(int bindhps, Mob* bindmob) { return(bindhps); }
|
||||
|
||||
//Client haste as calculated by default formulas - In percent from 0-100
|
||||
int Client::mod_client_haste(int h) { return(h); }
|
||||
|
||||
//Haste cap override
|
||||
int Client::mod_client_haste_cap(int cap) { return(cap); }
|
||||
|
||||
//This is called when a client cons a mob
|
||||
void Client::mod_consider(Mob* tmob, Consider_Struct* con) { return; }
|
||||
|
||||
//Return true to continue with normal behavior, false returns in the parent function
|
||||
bool Client::mod_saylink(const std::string& response, bool silentsaylink) { return(true); }
|
||||
|
||||
//Client pet power as calculated by default formulas and bonuses
|
||||
int16 Client::mod_pet_power(int16 act_power, uint16 spell_id) { return(act_power); }
|
||||
|
||||
//Chance to combine rolled against a random 0-99 where higher is better.
|
||||
float Client::mod_tradeskill_chance(float chance, DBTradeskillRecipe_Struct *spec) { return(chance); }
|
||||
|
||||
//Chance to skillup rolled against a random 0-99 where higher is better.
|
||||
float Client::mod_tradeskill_skillup(float chance_stage2) { return(chance_stage2); }
|
||||
|
||||
//Tribute value override
|
||||
int32 Client::mod_tribute_item_value(int32 pts, const ItemInst* item) { return(pts); }
|
||||
|
||||
//Death reporting
|
||||
void Client::mod_client_death_npc(Mob* killerMob) { return; }
|
||||
void Client::mod_client_death_duel(Mob* killerMob) { return; }
|
||||
void Client::mod_client_death_env() { return; }
|
||||
|
||||
//Calculated xp before consider modifier, called whenever a client gets XP for killing a mob.
|
||||
int64 Client::mod_client_xp(int64 in_xp, NPC *npc) { return(in_xp); }
|
||||
|
||||
//Client XP formula. Changes here will cause clients to change level after gaining or losing xp.
|
||||
//Either modify this before your server goes live, or be prepared to write a quest script that fixes levels.
|
||||
//To adjust how much XP is given per kill, use mod_client_xp
|
||||
uint32 Client::mod_client_xp_for_level(uint32 xp, uint16 check_level) { return(xp); }
|
||||
|
||||
//effect_vallue - Spell effect value as calculated by default formulas. You will want to ignore effects that don't lend themselves to scaling - pet ID's, gate coords, etc.
|
||||
int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster) { return(effect_value); }
|
||||
|
||||
//chancetohit - 0 to 100 percent - set over 1000 for a guaranteed hit
|
||||
float Mob::mod_hit_chance(float chancetohit, SkillType skillinuse, Mob* attacker) { return(chancetohit); }
|
||||
|
||||
//Final riposte chance
|
||||
float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { return(ripostechance); }
|
||||
|
||||
//Final block chance
|
||||
float Mob::mod_block_chance(float blockchance, Mob* attacker) { return(blockchance); }
|
||||
|
||||
//Final parry chance
|
||||
float Mob::mod_parry_chance(float parrychance, Mob* attacker) { return(parrychance); }
|
||||
|
||||
//Final dodge chance
|
||||
float Mob::mod_dodge_chance(float dodgechance, Mob* attacker) { return(dodgechance); }
|
||||
|
||||
//Usually 15, a monk under this weight threshold gets an AC bonus
|
||||
float Mob::mod_monk_weight(float monkweight, Mob* attacker) { return(monkweight); }
|
||||
|
||||
//Mitigation rating is compared to incoming attack rating. Higher is better.
|
||||
float Mob::mod_mitigation_rating(float mitigation_rating, Mob* attacker) { return(mitigation_rating); }
|
||||
float Mob::mod_attack_rating(float attack_rating, Mob* defender) { return(attack_rating); }
|
||||
|
||||
//Kick damage after all other bonuses are applied
|
||||
int64 Mob::mod_kick_damage(int64 dmg) { return(dmg); }
|
||||
|
||||
//Slam and bash damage after all other bonuses are applied
|
||||
int64 Mob::mod_bash_damage(int64 dmg) { return(dmg); }
|
||||
|
||||
//Frenzy damage after all other bonuses are applied
|
||||
int64 Mob::mod_frenzy_damage(int64 dmg) { return(dmg); }
|
||||
|
||||
//Special attack damage after all other bonuses are applied.
|
||||
int64 Mob::mod_monk_special_damage(int64 ndamage, EQ::skills::SkillType skill_type) { return(ndamage); }
|
||||
|
||||
//ndamage - Backstab damage as calculated by default formulas
|
||||
int64 Mob::mod_backstab_damage(int64 ndamage) { return(ndamage); }
|
||||
|
||||
//Chance for 50+ archery bonus damage if Combat:UseArcheryBonusRoll is true.
|
||||
int64 Mob::mod_archery_bonus_chance(int bonuschance, const ItemInst* RangeWeapon) { return(bonuschance); }
|
||||
|
||||
//Archery bonus damage
|
||||
uint64 Mob::mod_archery_bonus_damage(uint64 MaxDmg, const ItemInst* RangeWeapon) { return(MaxDmg); }
|
||||
|
||||
//Final archery damage including bonus if it was applied.
|
||||
int64 Mob::mod_archery_damage(int64 TotalDmg, bool hasbonus, const ItemInst* RangeWeapon) { return(TotalDmg); }
|
||||
|
||||
//Thrown weapon damage after all other calcs
|
||||
uint64 Mob::mod_throwing_damage(uint64 MaxDmg) { return(MaxDmg); }
|
||||
|
||||
//Spell cast time in milliseconds - will not sync with client cast time bar, but does work.
|
||||
int32 Mob::mod_cast_time(int32 cast_time) { return(cast_time); }
|
||||
|
||||
//res - Default buff duration formula
|
||||
int Mob::mod_buff_duration(int res, Mob* caster, Mob* target, uint16 spell_id) { return(res); }
|
||||
|
||||
//Spell stack override - If this returns anything < 2, it will ignore all other stacking rules.
|
||||
// See spells.cpp: Mob::CheckStackConflict
|
||||
// 0 - No conflict
|
||||
// 1 - Overwrite, spellid1 is replaced by spellid2
|
||||
// -1 - Blocked, spellid2 will not land
|
||||
// 2 - Default stacking behavior
|
||||
int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint16 spellid2, int caster_level2, Mob* caster2) { return(2); }
|
||||
|
||||
//Sum of various resists rolled against a value of 200.
|
||||
int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) {
|
||||
int final = resist_chance + level_mod + resist_modifier + target_resist;
|
||||
return(final);
|
||||
}
|
||||
|
||||
//Spell is cast by this on spelltar, called from spellontarget after the event_cast_on NPC event
|
||||
void Mob::mod_spell_cast(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc) { return; }
|
||||
@@ -477,10 +477,6 @@ public:
|
||||
|
||||
uint32 GetSpawnKillCount();
|
||||
int GetScore();
|
||||
void mod_prespawn(Spawn2 *sp);
|
||||
int mod_npc_damage(int64 damage, EQ::skills::SkillType skillinuse, int hand, const EQ::ItemData* weapon, Mob* other);
|
||||
void mod_npc_killed_merit(Mob* c);
|
||||
void mod_npc_killed(Mob* oos);
|
||||
void AISpellsList(Client *c);
|
||||
uint16 GetInnateProcSpellID() const { return innate_proc_spell_id; }
|
||||
|
||||
|
||||
+45
-8
@@ -71,6 +71,8 @@ Object::Object(uint32 id, uint32 type, uint32 icon, const Object_Struct& object,
|
||||
m_data.size = object.size;
|
||||
m_data.tilt_x = object.tilt_x;
|
||||
m_data.tilt_y = object.tilt_y;
|
||||
|
||||
FixZ();
|
||||
}
|
||||
|
||||
//creating a re-ocurring ground spawn.
|
||||
@@ -100,6 +102,8 @@ Object::Object(const EQ::ItemInstance* inst, char* name,float max_x,float min_x,
|
||||
strcpy(m_data.object_name, name);
|
||||
RandomSpawn(false);
|
||||
|
||||
FixZ();
|
||||
|
||||
// Hardcoded portion for unknown members
|
||||
m_data.unknown024 = 0x7f001194;
|
||||
m_data.unknown076 = 0x0000d5fe;
|
||||
@@ -167,6 +171,8 @@ Object::Object(Client* client, const EQ::ItemInstance* inst)
|
||||
strcpy(m_data.object_name, DEFAULT_OBJECT_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
FixZ();
|
||||
}
|
||||
|
||||
Object::Object(const EQ::ItemInstance *inst, float x, float y, float z, float heading, uint32 decay_time)
|
||||
@@ -223,6 +229,8 @@ Object::Object(const EQ::ItemInstance *inst, float x, float y, float z, float he
|
||||
strcpy(m_data.object_name, DEFAULT_OBJECT_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
FixZ();
|
||||
}
|
||||
|
||||
Object::Object(const char *model, float x, float y, float z, float heading, uint8 type, uint32 decay_time)
|
||||
@@ -247,6 +255,8 @@ Object::Object(const char *model, float x, float y, float z, float heading, uint
|
||||
m_data.z = z;
|
||||
m_data.zone_id = zone->GetZoneID();
|
||||
|
||||
FixZ();
|
||||
|
||||
if (decay_time)
|
||||
decay_timer.Start();
|
||||
|
||||
@@ -493,21 +503,25 @@ void Object::RandomSpawn(bool send_packet) {
|
||||
|
||||
bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
|
||||
{
|
||||
if(m_ground_spawn){//This is a Cool Groundspawn
|
||||
if(m_ground_spawn) {//This is a Cool Groundspawn
|
||||
respawn_timer.Start();
|
||||
}
|
||||
if (m_type == OT_DROPPEDITEM) {
|
||||
bool cursordelete = false;
|
||||
bool duplicate_lore = false;
|
||||
if (m_inst && sender) {
|
||||
// if there is a lore conflict, delete the offending item from the server inventory
|
||||
// the client updates itself and takes care of sending "duplicate lore item" messages
|
||||
auto item = m_inst->GetItem();
|
||||
if(sender->CheckLoreConflict(item)) {
|
||||
if (sender->CheckLoreConflict(item)) {
|
||||
duplicate_lore = true;
|
||||
int16 loreslot = sender->GetInv().HasItem(item->ID, 0, invWhereBank);
|
||||
if (loreslot != INVALID_INDEX) // if the duplicate is in the bank, delete it.
|
||||
if (loreslot != INVALID_INDEX) { // if the duplicate is in the bank, delete it.
|
||||
sender->DeleteItemInInventory(loreslot);
|
||||
else
|
||||
cursordelete = true; // otherwise, we delete the new one
|
||||
}
|
||||
else {
|
||||
cursordelete = true;
|
||||
} // otherwise, we delete the new one
|
||||
}
|
||||
|
||||
if (item->RecastDelay) {
|
||||
@@ -560,8 +574,9 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
|
||||
sender->DiscoverItem(item->ID);
|
||||
}
|
||||
|
||||
if(cursordelete) // delete the item if it's a duplicate lore. We have to do this because the client expects the item packet
|
||||
sender->DeleteItemInInventory(EQ::invslot::slotCursor);
|
||||
if (cursordelete) { // delete the item if it's a duplicate lore. We have to do this because the client expects the item packet
|
||||
sender->DeleteItemInInventory(EQ::invslot::slotCursor, 1, true);
|
||||
}
|
||||
|
||||
sender->DropItemQS(m_inst, true);
|
||||
|
||||
@@ -581,8 +596,18 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
|
||||
|
||||
// Remove object
|
||||
content_db.DeleteObject(m_id);
|
||||
if(!m_ground_spawn)
|
||||
if (!m_ground_spawn) {
|
||||
entity_list.RemoveEntity(GetID());
|
||||
}
|
||||
|
||||
// we have to delete the entity on click or the client desyncs
|
||||
// this is a way to immediately respawn the groundspawn after killing it and
|
||||
// deleting the item from the player
|
||||
// I believe older clients somehow sent this automatically but we are no longer with ROF2+
|
||||
if (duplicate_lore) {
|
||||
sender->Message(Chat::Yellow, "Duplicate lore item detected");
|
||||
respawn_timer.Trigger();
|
||||
}
|
||||
} else {
|
||||
// Tradeskill item
|
||||
auto outapp = new EQApplicationPacket(OP_ClickObjectAction, sizeof(ClickObjectAction_Struct));
|
||||
@@ -1157,3 +1182,15 @@ void Object::SetEntityVariable(std::string variable_name, std::string variable_v
|
||||
|
||||
o_EntityVariables[variable_name] = variable_value;
|
||||
}
|
||||
|
||||
void Object::FixZ()
|
||||
{
|
||||
float best_z = BEST_Z_INVALID;
|
||||
if (zone->zonemap != nullptr) {
|
||||
auto dest = glm::vec3(m_data.x, m_data.y, m_data.z + 5);
|
||||
best_z = zone->zonemap->FindBestZ(dest, nullptr);
|
||||
if (best_z != BEST_Z_INVALID) {
|
||||
m_data.z = best_z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,6 +204,7 @@ protected:
|
||||
|
||||
Timer respawn_timer;
|
||||
Timer decay_timer;
|
||||
void FixZ();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -898,7 +898,9 @@ void perl_register_npc()
|
||||
package.add("SetSaveWaypoint", &Perl_NPC_SetSaveWaypoint);
|
||||
package.add("SetSecSkill", &Perl_NPC_SetSecSkill);
|
||||
package.add("SetSilver", &Perl_NPC_SetSilver);
|
||||
package.add("SetSimpleRoamBox", &Perl_NPC_SetSimpleRoamBox);
|
||||
package.add("SetSimpleRoamBox", (void(*)(NPC*, float))&Perl_NPC_SetSimpleRoamBox);
|
||||
package.add("SetSimpleRoamBox", (void(*)(NPC*, float, float))&Perl_NPC_SetSimpleRoamBox);
|
||||
package.add("SetSimpleRoamBox", (void(*)(NPC*, float, float, int))&Perl_NPC_SetSimpleRoamBox);
|
||||
package.add("SetSp2", &Perl_NPC_SetSp2);
|
||||
package.add("SetSpellFocusDMG", &Perl_NPC_SetSpellFocusDMG);
|
||||
package.add("SetSpellFocusHeal", &Perl_NPC_SetSpellFocusHeal);
|
||||
|
||||
+2
-3
@@ -194,7 +194,6 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
if (petpower == -1) {
|
||||
if (IsClient()) {
|
||||
act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);//Client only
|
||||
act_power = CastToClient()->mod_pet_power(act_power, spell_id);
|
||||
}
|
||||
else if (IsBot())
|
||||
act_power = CastToBot()->GetFocusEffect(focusPetPower, spell_id);
|
||||
@@ -575,7 +574,7 @@ void NPC::GetPetState(SpellBuff_Struct *pet_buffs, uint32 *items, char *name) {
|
||||
|
||||
//save their buffs.
|
||||
for (int i=EQ::invslot::EQUIPMENT_BEGIN; i < GetPetMaxTotalSlots(); i++) {
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[i].spellid)) {
|
||||
pet_buffs[i].spellid = buffs[i].spellid;
|
||||
pet_buffs[i].effect_type = i+1;
|
||||
pet_buffs[i].duration = buffs[i].ticsremaining;
|
||||
@@ -601,7 +600,7 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) {
|
||||
for (i = 0; i < GetPetMaxTotalSlots(); i++) {
|
||||
for(int z = 0; z < GetPetMaxTotalSlots(); z++) {
|
||||
// check for duplicates
|
||||
if(buffs[z].spellid != SPELL_UNKNOWN && buffs[z].spellid == pet_buffs[i].spellid) {
|
||||
if(IsValidSpell(buffs[z].spellid) && buffs[z].spellid == pet_buffs[i].spellid) {
|
||||
buffs[z].spellid = SPELL_UNKNOWN;
|
||||
pet_buffs[i].spellid = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
+48
-42
@@ -4024,10 +4024,8 @@ void QuestManager::SendPlayerHandinEvent() {
|
||||
if (!handin_items.empty()) {
|
||||
if (Strings::Contains(handin_items, ",")) {
|
||||
const auto handin_data = Strings::Split(handin_items, ",");
|
||||
|
||||
for (const auto &h: handin_data) {
|
||||
const auto item_data = Strings::Split(h, "-");
|
||||
|
||||
const auto item_data = Strings::Split(h, "|");
|
||||
if (
|
||||
item_data.size() == 3 &&
|
||||
Strings::IsNumber(item_data[0]) &&
|
||||
@@ -4037,22 +4035,22 @@ void QuestManager::SendPlayerHandinEvent() {
|
||||
const auto item_id = static_cast<uint32>(std::stoul(item_data[0]));
|
||||
if (item_id != 0) {
|
||||
const auto *item = database.GetItem(item_id);
|
||||
|
||||
hi.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(std::stoul(item_data[1])),
|
||||
.attuned = std::stoi(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
if (item) {
|
||||
hi.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(std::stoul(item_data[1])),
|
||||
.attuned = std::stoi(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Strings::Contains(handin_items, "|")) {
|
||||
const auto item_data = Strings::Split(handin_items, "|");
|
||||
|
||||
if (
|
||||
item_data.size() == 3 &&
|
||||
Strings::IsNumber(item_data[0]) &&
|
||||
@@ -4061,15 +4059,16 @@ void QuestManager::SendPlayerHandinEvent() {
|
||||
) {
|
||||
const auto item_id = static_cast<uint32>(std::stoul(item_data[0]));
|
||||
const auto *item = database.GetItem(item_id);
|
||||
|
||||
hi.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(std::stoul(item_data[1])),
|
||||
.attuned = std::stoi(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
if (item) {
|
||||
hi.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(std::stoul(item_data[1])),
|
||||
.attuned = std::stoi(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4087,10 +4086,8 @@ void QuestManager::SendPlayerHandinEvent() {
|
||||
if (!return_items.empty()) {
|
||||
if (Strings::Contains(return_items, ",")) {
|
||||
const auto return_data = Strings::Split(return_items, ",");
|
||||
|
||||
for (const auto &r: return_data) {
|
||||
const auto item_data = Strings::Split(r, "|");
|
||||
|
||||
if (
|
||||
item_data.size() == 3 &&
|
||||
Strings::IsNumber(item_data[0]) &&
|
||||
@@ -4100,20 +4097,21 @@ void QuestManager::SendPlayerHandinEvent() {
|
||||
const auto item_id = static_cast<uint32>(std::stoul(item_data[0]));
|
||||
const auto *item = database.GetItem(item_id);
|
||||
|
||||
ri.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(std::stoul(item_data[1])),
|
||||
.attuned = std::stoi(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
if (item) {
|
||||
ri.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(std::stoul(item_data[1])),
|
||||
.attuned = std::stoi(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Strings::Contains(return_items, "|")) {
|
||||
const auto item_data = Strings::Split(return_items, "|");
|
||||
|
||||
if (
|
||||
item_data.size() == 3 &&
|
||||
Strings::IsNumber(item_data[0]) &&
|
||||
@@ -4123,14 +4121,16 @@ void QuestManager::SendPlayerHandinEvent() {
|
||||
const auto item_id = static_cast<uint32>(std::stoul(item_data[0]));
|
||||
const auto *item = database.GetItem(item_id);
|
||||
|
||||
ri.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(std::stoul(item_data[1])),
|
||||
.attuned = std::stoi(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
if (item) {
|
||||
ri.emplace_back(
|
||||
PlayerEvent::HandinEntry{
|
||||
.item_id = item_id,
|
||||
.item_name = item->Name,
|
||||
.charges = static_cast<uint16>(std::stoul(item_data[1])),
|
||||
.attuned = std::stoi(item_data[2]) ? true : false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4149,7 +4149,13 @@ void QuestManager::SendPlayerHandinEvent() {
|
||||
initiator->DeleteEntityVariable("RETURN_ITEMS");
|
||||
initiator->DeleteEntityVariable("RETURN_MONEY");
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::NPC_HANDIN)) {
|
||||
bool handed_in_money = hm.platinum > 0 || hm.gold > 0 || hm.silver > 0 || hm.copper > 0;
|
||||
|
||||
bool event_has_data_to_record = (
|
||||
!hi.empty() || handed_in_money
|
||||
);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::NPC_HANDIN) && event_has_data_to_record) {
|
||||
auto e = PlayerEvent::HandinEvent{
|
||||
.npc_id = owner->CastToNPC()->GetNPCTypeID(),
|
||||
.npc_name = owner->GetCleanName(),
|
||||
|
||||
@@ -260,8 +260,6 @@ bool Spawn2::Process() {
|
||||
|
||||
NPC *npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), GravityBehavior::Water);
|
||||
|
||||
npc->mod_prespawn(this);
|
||||
|
||||
npcthis = npc;
|
||||
npc->AddLootTable();
|
||||
if (npc->DropsGlobalLoot()) {
|
||||
|
||||
@@ -332,8 +332,6 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
|
||||
int32 max_dmg = GetBaseSkillDamage(EQ::skills::SkillFrenzy, GetTarget());
|
||||
DoAnim(anim1HWeapon, 0, false);
|
||||
|
||||
max_dmg = mod_frenzy_damage(max_dmg);
|
||||
|
||||
if (GetClass() == BERSERKER) {
|
||||
int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy);
|
||||
if (zone->random.Roll0(450) < chance)
|
||||
@@ -528,9 +526,6 @@ int Mob::MonkSpecialAttack(Mob *other, uint8 unchecked_type)
|
||||
if (max_dmg > 0)
|
||||
ht = max_dmg;
|
||||
|
||||
// This can potentially stack with changes to kick damage
|
||||
ht = ndamage = mod_monk_special_damage(ndamage, skill_type);
|
||||
|
||||
DoSpecialAttackDamage(other, skill_type, max_dmg, min_dmg, ht, reuse);
|
||||
|
||||
return reuse;
|
||||
|
||||
+20
-20
@@ -27,6 +27,7 @@
|
||||
#include "../common/data_verification.h"
|
||||
#include "../common/misc_functions.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "lua_parser.h"
|
||||
#include "string_ids.h"
|
||||
@@ -1078,7 +1079,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
}
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(int slot = 0; slot < buff_count; slot++) {
|
||||
if( buffs[slot].spellid != SPELL_UNKNOWN &&
|
||||
if(IsValidSpell(buffs[slot].spellid) &&
|
||||
spells[buffs[slot].spellid].dispel_flag == 0 &&
|
||||
!IsDiscipline(buffs[slot].spellid))
|
||||
{
|
||||
@@ -1109,7 +1110,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
int chance = spells[spell_id].base_value[i];
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(int slot = 0; slot < buff_count; slot++) {
|
||||
if (buffs[slot].spellid != SPELL_UNKNOWN &&
|
||||
if (IsValidSpell(buffs[slot].spellid) &&
|
||||
IsDetrimentalSpell(buffs[slot].spellid) &&
|
||||
spells[buffs[slot].spellid].dispel_flag == 0)
|
||||
{
|
||||
@@ -1136,7 +1137,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
int chance = spells[spell_id].base_value[i];
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(int slot = 0; slot < buff_count; slot++) {
|
||||
if (buffs[slot].spellid != SPELL_UNKNOWN &&
|
||||
if (IsValidSpell(buffs[slot].spellid) &&
|
||||
IsBeneficialSpell(buffs[slot].spellid) &&
|
||||
spells[buffs[slot].spellid].dispel_flag == 0)
|
||||
{
|
||||
@@ -1335,7 +1336,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
if (BeneficialSpell(spell_id) && spells[spell_id].buff_duration == 0) {
|
||||
int buff_count = GetMaxBuffSlots();
|
||||
for (int slot = 0; slot < buff_count; slot++) {
|
||||
if (buffs[slot].spellid != SPELL_UNKNOWN && IsEffectInSpell(buffs[slot].spellid, SE_Blind)) {
|
||||
if (IsValidSpell(buffs[slot].spellid) && IsEffectInSpell(buffs[slot].spellid, SE_Blind)) {
|
||||
if (caster && TryDispel(caster->GetCasterLevel(spell_id), buffs[slot].casterlevel, 1)) {
|
||||
BuffFadeBySlot(slot);
|
||||
slot = buff_count;
|
||||
@@ -3427,8 +3428,6 @@ int64 Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level
|
||||
}
|
||||
}
|
||||
|
||||
effect_value = mod_effect_value(effect_value, spell_id, spells[spell_id].effect_id[effect_id], caster, caster_id);
|
||||
|
||||
return effect_value;
|
||||
}
|
||||
|
||||
@@ -3756,12 +3755,13 @@ void Mob::BuffProcess()
|
||||
|
||||
for (int buffs_i = 0; buffs_i < buff_count; ++buffs_i)
|
||||
{
|
||||
if (buffs[buffs_i].spellid != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(buffs[buffs_i].spellid))
|
||||
{
|
||||
DoBuffTic(buffs[buffs_i], buffs_i, entity_list.GetMob(buffs[buffs_i].casterid));
|
||||
// If the Mob died during DoBuffTic, then the buff we are currently processing will have been removed
|
||||
if(buffs[buffs_i].spellid == SPELL_UNKNOWN)
|
||||
if(!IsValidSpell(buffs[buffs_i].spellid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// DF_Permanent uses -1 DF_Aura uses -4 but we need to check negatives for some spells for some reason?
|
||||
if (spells[buffs[buffs_i].spellid].buff_duration_formula != DF_Permanent &&
|
||||
@@ -6165,12 +6165,12 @@ void Mob::TryTriggerOnCastFocusEffect(focusType type, uint16 spell_id)
|
||||
int32 proc_spellid = 0;
|
||||
|
||||
// item focus
|
||||
if (IsClient() && itembonuses.FocusEffects[type]) {
|
||||
if (IsOfClientBot() && itembonuses.FocusEffects[type]) {
|
||||
const EQ::ItemData *temp_item = nullptr;
|
||||
|
||||
for (int x = EQ::invslot::EQUIPMENT_BEGIN; x <= EQ::invslot::EQUIPMENT_END; x++) {
|
||||
temp_item = nullptr;
|
||||
EQ::ItemInstance *ins = CastToClient()->GetInv().GetItem(x);
|
||||
EQ::ItemInstance const *ins = (IsClient()) ? CastToClient()->GetInv().GetItem(x) : CastToBot()->GetBotItem(x);
|
||||
if (!ins) {
|
||||
continue;
|
||||
}
|
||||
@@ -6230,7 +6230,7 @@ void Mob::TryTriggerOnCastFocusEffect(focusType type, uint16 spell_id)
|
||||
}
|
||||
|
||||
// Only use one of this focus per AA effect.
|
||||
if (IsClient() && aabonuses.FocusEffects[type]) {
|
||||
if (IsOfClientBot() && aabonuses.FocusEffects[type]) {
|
||||
for (const auto &aa : aa_ranks) {
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
|
||||
auto ability = ability_rank.first;
|
||||
@@ -6244,7 +6244,7 @@ void Mob::TryTriggerOnCastFocusEffect(focusType type, uint16 spell_id)
|
||||
continue;
|
||||
}
|
||||
|
||||
proc_spellid = CastToClient()->CalcAAFocus(type, *rank, spell_id);
|
||||
proc_spellid = CalcAAFocus(type, *rank, spell_id);
|
||||
if (proc_spellid) {
|
||||
TryTriggerOnCastProc(0, spell_id, proc_spellid);
|
||||
}
|
||||
@@ -6430,7 +6430,7 @@ int64 Mob::GetFocusEffect(focusType type, uint16 spell_id, Mob *caster, bool fro
|
||||
}
|
||||
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) {
|
||||
if (TempItem && IsValidSpell(TempItem->Focus.Effect)) {
|
||||
if(rand_effectiveness) {
|
||||
focus_max = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id, true);
|
||||
if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) {
|
||||
@@ -6462,7 +6462,7 @@ int64 Mob::GetFocusEffect(focusType type, uint16 spell_id, Mob *caster, bool fro
|
||||
aug = ins->GetAugment(y);
|
||||
if (aug) {
|
||||
const EQ::ItemData* TempItemAug = aug->GetItem();
|
||||
if (TempItemAug && TempItemAug->Focus.Effect > 0 && TempItemAug->Focus.Effect != SPELL_UNKNOWN) {
|
||||
if (TempItemAug && IsValidSpell(TempItemAug->Focus.Effect)) {
|
||||
if(rand_effectiveness) {
|
||||
focus_max = CalcFocusEffect(type, TempItemAug->Focus.Effect, spell_id, true);
|
||||
if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) {
|
||||
@@ -6502,7 +6502,7 @@ int64 Mob::GetFocusEffect(focusType type, uint16 spell_id, Mob *caster, bool fro
|
||||
}
|
||||
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) {
|
||||
if (TempItem && IsValidSpell(TempItem->Focus.Effect)) {
|
||||
if (rand_effectiveness) {
|
||||
focus_max = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id, true);
|
||||
if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) {
|
||||
@@ -6712,7 +6712,7 @@ int64 NPC::GetFocusEffect(focusType type, uint16 spell_id, Mob* caster, bool fro
|
||||
|
||||
TempItem = cur;
|
||||
|
||||
if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) {
|
||||
if (TempItem && IsValidSpell(TempItem->Focus.Effect)) {
|
||||
if(rand_effectiveness) {
|
||||
focus_max = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id, true);
|
||||
if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) {
|
||||
@@ -9755,7 +9755,7 @@ bool Mob::PassLimitToSkill(EQ::skills::SkillType skill, int32 spell_id, int proc
|
||||
|
||||
if (!aa_id && spellbonuses.LimitToSkill[EQ::skills::HIGHEST_SKILL + 2]) {
|
||||
|
||||
if (spell_id == SPELL_UNKNOWN) {
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -10362,13 +10362,13 @@ void Mob::SetBuffDuration(int spell_id, int duration) {
|
||||
for (int slot = 0; slot < buff_count; slot++) {
|
||||
|
||||
if (!adjust_all_buffs) {
|
||||
if (buffs[slot].spellid != SPELL_UNKNOWN && buffs[slot].spellid == spell_id) {
|
||||
if (IsValidSpell(buffs[slot].spellid) && buffs[slot].spellid == spell_id) {
|
||||
SpellOnTarget(buffs[slot].spellid, this, 0, false, 0, false, -1, duration, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (buffs[slot].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[slot].spellid)) {
|
||||
SpellOnTarget(buffs[slot].spellid, this, 0, false, 0, false, -1, duration, true);
|
||||
}
|
||||
}
|
||||
@@ -10410,7 +10410,7 @@ int Mob::GetBuffStatValueBySpell(int32 spell_id, const char* stat_identifier)
|
||||
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for (int slot = 0; slot < buff_count; slot++) {
|
||||
if (buffs[slot].spellid != SPELL_UNKNOWN && buffs[slot].spellid == spell_id) {
|
||||
if (IsValidSpell(buffs[slot].spellid) && buffs[slot].spellid == spell_id) {
|
||||
return GetBuffStatValueBySlot(slot, stat_identifier);
|
||||
}
|
||||
}
|
||||
|
||||
+32
-38
@@ -478,8 +478,6 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
return(true);
|
||||
}
|
||||
|
||||
cast_time = mod_cast_time(cast_time);
|
||||
|
||||
// ok we know it has a cast time so we can start the timer now
|
||||
spellend_timer.Start(cast_time);
|
||||
|
||||
@@ -1146,8 +1144,9 @@ void Mob::ZeroBardPulseVars()
|
||||
|
||||
void Mob::InterruptSpell(uint16 spellid)
|
||||
{
|
||||
if (spellid == SPELL_UNKNOWN)
|
||||
if (!IsValidSpell(spellid)) {
|
||||
spellid = casting_spell_id;
|
||||
}
|
||||
|
||||
InterruptSpell(0, 0x121, spellid);
|
||||
}
|
||||
@@ -1158,7 +1157,7 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
|
||||
EQApplicationPacket *outapp = nullptr;
|
||||
uint16 message_other;
|
||||
bool bard_song_mode = false; //has the bard song gone to auto repeat mode
|
||||
if (spellid == SPELL_UNKNOWN) {
|
||||
if (!IsValidSpell(spellid)) {
|
||||
if(bardsong) {
|
||||
spellid = bardsong;
|
||||
bard_song_mode = true;
|
||||
@@ -2819,9 +2818,6 @@ int Mob::CalcBuffDuration(Mob *caster, Mob *target, uint16 spell_id, int32 caste
|
||||
res = 10000; // ~16h override
|
||||
}
|
||||
|
||||
|
||||
res = mod_buff_duration(res, caster, target, spell_id);
|
||||
|
||||
LogSpells("Spell [{}]: Casting level [{}], formula [{}], base_duration [{}]: result [{}]",
|
||||
spell_id, castlevel, formula, duration, res);
|
||||
|
||||
@@ -2946,9 +2942,6 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
}
|
||||
}
|
||||
|
||||
int modval = mod_spell_stack(spellid1, caster_level1, caster1, spellid2, caster_level2, caster2);
|
||||
if(modval < 2) { return(modval); }
|
||||
|
||||
/*
|
||||
One of these is a bard song and one isn't and they're both beneficial so they should stack.
|
||||
*/
|
||||
@@ -3200,8 +3193,10 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
// 66+ Group Spells 62, Single Target 61
|
||||
bool Mob::CheckSpellLevelRestriction(Mob *caster, uint16 spell_id)
|
||||
{
|
||||
bool check_for_restrictions = false;
|
||||
bool can_cast = true;
|
||||
if (spells[spell_id].target_type == ST_Self) {
|
||||
LogSpells("[CheckSpellLevelRestriction] Self Only spell - no restrictions");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!caster) {
|
||||
LogSpells("[CheckSpellLevelRestriction] No caster");
|
||||
@@ -3213,6 +3208,9 @@ bool Mob::CheckSpellLevelRestriction(Mob *caster, uint16 spell_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check_for_restrictions = false;
|
||||
bool can_cast = true;
|
||||
|
||||
// NON GM clients might be restricted by rule setting
|
||||
if (caster->IsClient()) {
|
||||
if (IsClient()) { // Only restrict client on client for this rule
|
||||
@@ -3287,7 +3285,7 @@ uint32 Client::GetLastBuffSlot(bool disc, bool song)
|
||||
bool Mob::HasDiscBuff()
|
||||
{
|
||||
int slot = GetFirstBuffSlot(true, false);
|
||||
return buffs[slot].spellid != SPELL_UNKNOWN;
|
||||
return IsValidSpell(buffs[slot].spellid);
|
||||
}
|
||||
|
||||
// returns the slot the buff was added to, -1 if it wasn't added due to
|
||||
@@ -3332,7 +3330,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
for (buffslot = 0; buffslot < buff_count; buffslot++) {
|
||||
const Buffs_Struct &curbuf = buffs[buffslot];
|
||||
|
||||
if (curbuf.spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(curbuf.spellid)) {
|
||||
// there's a buff in this slot
|
||||
ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spell_id,
|
||||
caster_level, entity_list.GetMobID(curbuf.casterid), caster, buffslot);
|
||||
@@ -3483,7 +3481,7 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite)
|
||||
const Buffs_Struct &curbuf = buffs[i];
|
||||
|
||||
// no buff in this slot
|
||||
if (curbuf.spellid == SPELL_UNKNOWN)
|
||||
if (!IsValidSpell(curbuf.spellid))
|
||||
{
|
||||
// if we haven't found a free slot, this is the first one so save it
|
||||
if(firstfree == -2)
|
||||
@@ -3697,8 +3695,6 @@ bool Mob::SpellOnTarget(
|
||||
}
|
||||
}
|
||||
|
||||
mod_spell_cast(spell_id, spelltar, reflect_effectiveness, use_resist_adjust, resist_adjust, isproc);
|
||||
|
||||
if (!DoCastingChecksOnTarget(false, spell_id, spelltar)) {
|
||||
safe_delete(action_packet);
|
||||
return false;
|
||||
@@ -5067,8 +5063,6 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
resist_chance += resist_modifier;
|
||||
resist_chance += target_resist;
|
||||
|
||||
resist_chance = mod_spell_resist(resist_chance, level_mod, resist_modifier, target_resist, resist_type, spell_id, caster);
|
||||
|
||||
//Do our min and max resist checks.
|
||||
if(resist_chance > spells[spell_id].max_resist && spells[spell_id].max_resist != 0)
|
||||
{
|
||||
@@ -5872,7 +5866,7 @@ bool Client::SpellBucketCheck(uint16 spell_id, uint32 character_id) {
|
||||
int16 Mob::GetBuffSlotFromType(uint16 type) {
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (int i = 0; i < buff_count; i++) {
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[i].spellid)) {
|
||||
for (int j = 0; j < EFFECT_COUNT; j++) {
|
||||
if (spells[buffs[i].spellid].effect_id[j] == type )
|
||||
return i;
|
||||
@@ -5884,8 +5878,9 @@ int16 Mob::GetBuffSlotFromType(uint16 type) {
|
||||
|
||||
uint16 Mob::GetSpellIDFromSlot(uint8 slot)
|
||||
{
|
||||
if (buffs[slot].spellid != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(buffs[slot].spellid)) {
|
||||
return buffs[slot].spellid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5927,7 +5922,7 @@ bool Mob::IsCombatProc(uint16 spell_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spell_id == SPELL_UNKNOWN) {
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
return(false);
|
||||
}
|
||||
/*
|
||||
@@ -5955,13 +5950,13 @@ bool Mob::IsCombatProc(uint16 spell_id) {
|
||||
}
|
||||
|
||||
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id, int level_override, uint32 proc_reuse_time) {
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
if(!IsValidSpell(spell_id))
|
||||
return(false);
|
||||
|
||||
int i;
|
||||
if (bPerma) {
|
||||
for (i = 0; i < MAX_PROCS; i++) {
|
||||
if (PermaProcs[i].spellID == SPELL_UNKNOWN) {
|
||||
if (!IsValidSpell(PermaProcs[i].spellID)) {
|
||||
PermaProcs[i].spellID = spell_id;
|
||||
PermaProcs[i].chance = iChance;
|
||||
PermaProcs[i].base_spellID = base_spell_id;
|
||||
@@ -5993,7 +5988,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b
|
||||
// Find a slot and use it as normal.
|
||||
|
||||
for (i = 0; i < MAX_PROCS; i++) {
|
||||
if (SpellProcs[i].spellID == SPELL_UNKNOWN) {
|
||||
if (!IsValidSpell(SpellProcs[i].spellID)) {
|
||||
SpellProcs[i].spellID = spell_id;
|
||||
SpellProcs[i].chance = iChance;
|
||||
SpellProcs[i].base_spellID = base_spell_id;;
|
||||
@@ -6024,12 +6019,12 @@ bool Mob::RemoveProcFromWeapon(uint16 spell_id, bool bAll) {
|
||||
|
||||
bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id, uint32 proc_reuse_time)
|
||||
{
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
if(!IsValidSpell(spell_id))
|
||||
return(false);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_PROCS; i++) {
|
||||
if (DefensiveProcs[i].spellID == SPELL_UNKNOWN) {
|
||||
if (!IsValidSpell(DefensiveProcs[i].spellID)) {
|
||||
DefensiveProcs[i].spellID = spell_id;
|
||||
DefensiveProcs[i].chance = iChance;
|
||||
DefensiveProcs[i].base_spellID = base_spell_id;
|
||||
@@ -6058,12 +6053,12 @@ bool Mob::RemoveDefensiveProc(uint16 spell_id, bool bAll)
|
||||
|
||||
bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id, uint32 proc_reuse_time)
|
||||
{
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
if(!IsValidSpell(spell_id))
|
||||
return(false);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_PROCS; i++) {
|
||||
if (RangedProcs[i].spellID == SPELL_UNKNOWN) {
|
||||
if (!IsValidSpell(RangedProcs[i].spellID)) {
|
||||
RangedProcs[i].spellID = spell_id;
|
||||
RangedProcs[i].chance = iChance;
|
||||
RangedProcs[i].base_spellID = base_spell_id;
|
||||
@@ -6094,17 +6089,16 @@ bool Mob::RemoveRangedProc(uint16 spell_id, bool bAll)
|
||||
// behavior should be used.
|
||||
bool Mob::UseBardSpellLogic(uint16 spell_id, int slot)
|
||||
{
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
spell_id = casting_spell_id;
|
||||
|
||||
if(slot == -1)
|
||||
}
|
||||
if (slot == -1) {
|
||||
slot = static_cast<int>(casting_spell_slot);
|
||||
|
||||
}
|
||||
// should we treat this as a bard singing?
|
||||
return
|
||||
(
|
||||
spell_id != 0 &&
|
||||
spell_id != SPELL_UNKNOWN &&
|
||||
IsValidSpell(spell_id) &&
|
||||
slot != -1 &&
|
||||
GetClass() == BARD &&
|
||||
slot <= EQ::spells::SPELL_GEM_COUNT &&
|
||||
@@ -6200,7 +6194,7 @@ void Mob::SendPetBuffsToClient()
|
||||
|
||||
for(int buffslot = 0; buffslot < MaxSlots; buffslot++)
|
||||
{
|
||||
if(buffs[buffslot].spellid != SPELL_UNKNOWN) {
|
||||
if (IsValidSpell(buffs[buffslot].spellid)) {
|
||||
pbs->spellid[buffslot] = buffs[buffslot].spellid;
|
||||
pbs->ticsremaining[buffslot] = buffs[buffslot].ticsremaining;
|
||||
PetBuffCount++;
|
||||
@@ -6232,7 +6226,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
|
||||
uint32 buff_count = for_target ? GetMaxBuffSlots() : GetMaxTotalSlots();
|
||||
for(int i = 0; i < buff_count; ++i)
|
||||
{
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(buffs[i].spellid))
|
||||
{
|
||||
++count;
|
||||
}
|
||||
@@ -6265,7 +6259,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
|
||||
uint32 index = 0;
|
||||
for(int i = 0; i < buff_count; ++i)
|
||||
{
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN)
|
||||
if (IsValidSpell(buffs[i].spellid))
|
||||
{
|
||||
buff->entries[index].buff_slot = i;
|
||||
buff->entries[index].spell_id = buffs[i].spellid;
|
||||
|
||||
+3
-2
@@ -383,8 +383,9 @@
|
||||
#define FORAGE_MASTERY 6012 //Your forage mastery has enabled you to find something else!
|
||||
#define GUILD_BANK_CANNOT_DEPOSIT 6097 // Cannot deposit this item. Containers must be empty, and only one of each LORE and no NO TRADE or TEMPORARY items may be deposited.
|
||||
#define GUILD_BANK_FULL 6098 // There is no more room in the Guild Bank.
|
||||
#define GUILD_BANK_TRANSFERRED 6100 // '%1' transferred to Guild Bank from Deposits.
|
||||
#define GUILD_BANK_EMPTY_HANDS 6108 // You must empty your hands to withdraw from the Guild Bank.
|
||||
#define GUILD_BANK_TRANSFERRED 6100 // '%1' transferred to Guild Bank from Deposits.
|
||||
#define GUILD_BANK_EMPTY_HANDS 6108 // You must empty your hands to withdraw from the Guild Bank.
|
||||
#define TRADESKILL_COMBINE_LORE 6199 // Combine would result in a LORE item (%1) you already possess.
|
||||
#define TRANSFORM_FAILED 6326 //This mold cannot be applied to your %1.
|
||||
#define TRANSFORM_COMPLETE 6327 //You have successfully transformed your %1.
|
||||
#define DETRANSFORM_FAILED 6341 //%1 has no transformation that can be removed.
|
||||
|
||||
+53
-4
@@ -253,6 +253,9 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob
|
||||
{
|
||||
if (!user || !in_combine) {
|
||||
LogError("Client or NewCombine_Struct not set in Object::HandleCombine");
|
||||
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -278,6 +281,9 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob
|
||||
Chat::Red,
|
||||
"Error: Server is not aware of the tradeskill container you are attempting to use"
|
||||
);
|
||||
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
c_type = worldo->m_type;
|
||||
@@ -304,6 +310,9 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob
|
||||
|
||||
if (!inst || !inst->IsType(EQ::item::ItemClassBag)) {
|
||||
user->Message(Chat::Red, "Error: Server does not recognize specified tradeskill container");
|
||||
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -427,22 +436,50 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob
|
||||
if (spec.tradeskill == EQ::skills::SkillAlchemy) {
|
||||
if (user_pp.class_ != SHAMAN) {
|
||||
user->Message(Chat::Red, "This tradeskill can only be performed by a shaman.");
|
||||
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
else if (user_pp.level < MIN_LEVEL_ALCHEMY) {
|
||||
user->Message(Chat::Red, "You cannot perform alchemy until you reach level %i.", MIN_LEVEL_ALCHEMY);
|
||||
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (spec.tradeskill == EQ::skills::SkillTinkering) {
|
||||
if (user_pp.race != GNOME) {
|
||||
user->Message(Chat::Red, "Only gnomes can tinker.");
|
||||
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (spec.tradeskill == EQ::skills::SkillMakePoison) {
|
||||
if (user_pp.class_ != ROGUE) {
|
||||
user->Message(Chat::Red, "Only rogues can mix poisons.");
|
||||
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if Combine would result in Lore conflict
|
||||
for (const auto& e : spec.onsuccess) {
|
||||
auto success_item_inst = database.GetItem(e.first);
|
||||
if (user->CheckLoreConflict(success_item_inst)) {
|
||||
EQ::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQ::saylink::SayLinkItemData);
|
||||
linker.SetItemData(success_item_inst);
|
||||
auto item_link = linker.GenerateLink();
|
||||
user->MessageString(Chat::Red, TRADESKILL_COMBINE_LORE, item_link.c_str());
|
||||
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -687,6 +724,22 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac
|
||||
}
|
||||
}
|
||||
|
||||
DBTradeskillRecipe_Struct recipe_struct;
|
||||
|
||||
// Check if Combine would result in Lore conflict
|
||||
for (const auto& e : recipe_struct.onsuccess) {
|
||||
auto success_item_inst = database.GetItem(e.first);
|
||||
if (user->CheckLoreConflict(success_item_inst)) {
|
||||
EQ::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQ::saylink::SayLinkItemData);
|
||||
linker.SetItemData(success_item_inst);
|
||||
auto item_link = linker.GenerateLink();
|
||||
user->MessageString(Chat::Red, TRADESKILL_COMBINE_LORE, item_link.c_str());
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//otherwise, we found it all...
|
||||
outp->reply_code = 0x00000000; //success for finding it...
|
||||
user->QueuePacket(outapp);
|
||||
@@ -1110,8 +1163,6 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
|
||||
const EQ::ItemData* item = nullptr;
|
||||
|
||||
chance = mod_tradeskill_chance(chance, spec);
|
||||
|
||||
if (((spec->tradeskill==75) || GetGM() || (chance > res)) || zone->random.Roll(aa_chance)) {
|
||||
|
||||
success_modifier = 1;
|
||||
@@ -1248,8 +1299,6 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float
|
||||
}
|
||||
}
|
||||
|
||||
chance_stage2 = mod_tradeskill_skillup(chance_stage2);
|
||||
|
||||
if (chance_stage2 > zone->random.Real(0, 99)) {
|
||||
//Only if stage1 and stage2 succeeded you get a skillup.
|
||||
SetSkill(tradeskill, current_raw_skill + 1);
|
||||
|
||||
@@ -247,8 +247,6 @@ int32 Client::TributeItem(uint32 slot, uint32 quantity) {
|
||||
//figure out what its worth
|
||||
int32 pts = inst->GetItem()->Favor;
|
||||
|
||||
pts = mod_tribute_item_value(pts, m_inv[slot]);
|
||||
|
||||
if(pts < 1) {
|
||||
Message(Chat::Red, "This item is worthless for favor.");
|
||||
return(0);
|
||||
|
||||
@@ -1218,9 +1218,6 @@ bool Zone::Init(bool is_static) {
|
||||
LoadGrids();
|
||||
LoadTickItems();
|
||||
|
||||
//MODDING HOOK FOR ZONE INIT
|
||||
mod_init();
|
||||
|
||||
// logging origination information
|
||||
LogSys.origination_info.zone_short_name = zone->short_name;
|
||||
LogSys.origination_info.zone_long_name = zone->long_name;
|
||||
@@ -1927,9 +1924,6 @@ void Zone::Repop()
|
||||
initgrids_timer.Start();
|
||||
|
||||
entity_list.UpdateAllTraps(true, true);
|
||||
|
||||
//MODDING HOOK FOR REPOP
|
||||
mod_repop();
|
||||
}
|
||||
|
||||
void Zone::GetTimeSync()
|
||||
|
||||
@@ -395,11 +395,6 @@ public:
|
||||
|
||||
double GetMaxMovementUpdateRange() const { return max_movement_update_range; }
|
||||
|
||||
/**
|
||||
* Modding hooks
|
||||
*/
|
||||
void mod_init();
|
||||
void mod_repop();
|
||||
void SetIsHotzone(bool is_hotzone);
|
||||
|
||||
private:
|
||||
|
||||
+8
-5
@@ -2535,8 +2535,9 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) {
|
||||
}
|
||||
|
||||
for (int buffCount = 0; buffCount <= BUFF_COUNT; buffCount++) {
|
||||
if(buffs[buffCount].spellid == 0 || buffs[buffCount].spellid == SPELL_UNKNOWN)
|
||||
continue;
|
||||
if (!IsValidSpell(buffs[buffCount].spellid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int IsPersistent = buffs[buffCount].persistant_buff? 1: 0;
|
||||
|
||||
@@ -3079,8 +3080,9 @@ void ZoneDatabase::SaveBuffs(Client *client) {
|
||||
Buffs_Struct *buffs = client->GetBuffs();
|
||||
|
||||
for (int index = 0; index < buff_count; index++) {
|
||||
if(buffs[index].spellid == SPELL_UNKNOWN)
|
||||
continue;
|
||||
if (!IsValidSpell(buffs[index].spellid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
query = StringFormat("INSERT INTO `character_buffs` (character_id, slot_id, spell_id, "
|
||||
"caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, "
|
||||
@@ -3261,8 +3263,9 @@ void ZoneDatabase::SavePetInfo(Client *client)
|
||||
// pet buffs!
|
||||
int max_slots = RuleI(Spells, MaxTotalSlotsPET);
|
||||
for (int index = 0; index < max_slots; index++) {
|
||||
if (petinfo->Buffs[index].spellid == SPELL_UNKNOWN || petinfo->Buffs[index].spellid == 0)
|
||||
if (!IsValidSpell(petinfo->Buffs[index].spellid)) {
|
||||
continue;
|
||||
}
|
||||
if (query.length() == 0)
|
||||
query = StringFormat("INSERT INTO `character_pet_buffs` "
|
||||
"(`char_id`, `pet`, `slot`, `spell_id`, `caster_level`, "
|
||||
|
||||
Reference in New Issue
Block a user