From 694764f9ce4be26961753ad99d780d288bc9b15e Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 20 Apr 2024 14:45:53 -0500 Subject: [PATCH 1/6] Added AutoUnequippedCasting --- source/Changelog.txt | 3 +++ source/SEFunctions.cpp | 3 +++ source/cServerData.cpp | 23 ++++++++++++++++- source/cServerData.h | 5 +++- source/magic.cpp | 58 ++++++++++++++++++++++++++++++++---------- 5 files changed, 76 insertions(+), 16 deletions(-) diff --git a/source/Changelog.txt b/source/Changelog.txt index ec710f5d4..4cc50a0d4 100644 --- a/source/Changelog.txt +++ b/source/Changelog.txt @@ -1,3 +1,6 @@ + 20/04/2024 - Dragon Slayer/Xuri + Introduced a new INI setting, AutoUnequippedCasting, enhancing customization and control for users. + 22/03/2024 - Dragon Slayer/Xuri Leading/trailing whitespace is now trimmed from account names during login. diff --git a/source/SEFunctions.cpp b/source/SEFunctions.cpp index 17ffe76a4..bb54f0374 100644 --- a/source/SEFunctions.cpp +++ b/source/SEFunctions.cpp @@ -5080,6 +5080,9 @@ JSBool SE_GetServerSetting( JSContext *cx, [[maybe_unused]] JSObject *obj, uintN case 347: // MOONGATESFACETS *rval = INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->GetMoongateFacetStatus() )); break; + case 348: // AUTOUNEQUIPPEDCASTING + *rval = BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->AutoUnequippedCasting() ); + break; default: ScriptError( cx, "GetServerSetting: Invalid server setting name provided" ); return false; diff --git a/source/cServerData.cpp b/source/cServerData.cpp index 62d46868b..9b73d99f6 100644 --- a/source/cServerData.cpp +++ b/source/cServerData.cpp @@ -367,7 +367,8 @@ const std::map CServerData::uox3IniCaseValue {"YOUNGPLAYERSYSTEM"s, 344}, {"YOUNGLOCATION"s, 345}, {"SECRETSHARDKEY"s, 346}, - {"MOONGATEFACETS"s, 347} + {"MOONGATEFACETS"s, 347}, + {"AUTOUNEQUIPPEDCASTING"s, 348} }; constexpr auto MAX_TRACKINGTARGETS = 128; @@ -478,6 +479,7 @@ constexpr auto BIT_ENABLENPCGUILDDISCOUNTS = UI32( 100 ); constexpr auto BIT_ENABLENPCGUILDPREMIUMS = UI32( 101 ); constexpr auto BIT_SNOOPAWARENESS = UI32( 102 ); constexpr auto BIT_YOUNGPLAYERSYSTEM = UI32( 103 ); +constexpr auto BIT_AUTOUNEQUIPPEDCASTING = UI32( 104 ); // New uox3.ini format lookup @@ -803,6 +805,7 @@ auto CServerData::ResetDefaults() -> void TravelSpellsBetweenWorlds( false ); TravelSpellsWhileAggressor( false ); CastSpellsWhileMoving( false ); + AutoUnequippedCasting( false ); MaxControlSlots( 0 ); // Default to 0, which is equal to off MaxFollowers( 5 ); MaxPetOwners( 10 ); @@ -3868,6 +3871,20 @@ auto CServerData::TravelSpellsWhileAggressor( bool newVal ) -> void boolVals.set( BIT_TRAVELSPELLSWHILEAGGRESSOR, newVal ); } +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::AutoUnequippedCasting() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets whether spells will auto unequipe the hands that is not a spellbook or spellchanneling type. +//o------------------------------------------------------------------------------------------------o +auto CServerData::AutoUnequippedCasting() const -> bool +{ + return boolVals.test( BIT_AUTOUNEQUIPPEDCASTING ); +} +auto CServerData::AutoUnequippedCasting( bool newVal ) -> void +{ + boolVals.set( BIT_AUTOUNEQUIPPEDCASTING, newVal ); +} + //o------------------------------------------------------------------------------------------------o //| Function - CServerData::MaxControlSlots() //o------------------------------------------------------------------------------------------------o @@ -5173,6 +5190,7 @@ auto CServerData::SaveIni( const std::string &filename ) -> bool ofsOutput << "TRAVELSPELLSWHILEAGGRESSOR=" << ( TravelSpellsWhileAggressor() ? 1 : 0 ) << '\n'; ofsOutput << "HIDESTATSFORUNKNOWNMAGICITEMS=" << HideStatsForUnknownMagicItems() << '\n'; ofsOutput << "CASTSPELLSWHILEMOVING=" << ( CastSpellsWhileMoving() ? 1 : 0 ) << '\n'; + ofsOutput << "AUTOUNEQUIPPEDCASTING=" << ( AutoUnequippedCasting() ? 1 : 0 ) << '\n'; ofsOutput << "}" << '\n'; ofsOutput << '\n' << "[start locations]" << '\n' << "{" << '\n'; @@ -6524,6 +6542,9 @@ auto CServerData::HandleLine( const std::string& tag, const std::string& value ) case 347: // MOONGATEFACETS SetMoongateFacetStatus( static_cast( std::stoul( value, nullptr, 0 ))); break; + case 348: // AUTOUNEQUIPPEDCASTING + AutoUnequippedCasting(( static_cast( std::stoul( value, nullptr, 0 )) >= 1 ? true : false )); + break; default: rValue = false; break; diff --git a/source/cServerData.h b/source/cServerData.h index 5e8f09525..1bc7cddf2 100644 --- a/source/cServerData.h +++ b/source/cServerData.h @@ -212,7 +212,7 @@ class CServerData // Once over 62, bitsets are costly. std::vector has a special exception in the c++ specificaiton, to minimize wasted space for bools // These should be updated - std::bitset<104> boolVals; // Many values stored this way, rather than using bools. + std::bitset<105> boolVals; // Many values stored this way, rather than using bools. std::bitset<64> spawnRegionsFacets; // Used to determine which facets to enable spawn regions for, set in UOX>INI std::bitset<64> moongateFacets; // Used to determine which facets to enable moongates for, set in UOX>INI @@ -924,6 +924,9 @@ class CServerData auto TravelSpellsWhileAggressor( bool value ) -> void; auto TravelSpellsWhileAggressor() const -> bool; + auto AutoUnequippedCasting( bool value ) -> void; + auto AutoUnequippedCasting() const -> bool; + auto ToolUseLimit( bool value ) -> void; auto ToolUseLimit() const -> bool; diff --git a/source/magic.cpp b/source/magic.cpp index daf0bf3e4..12a39d517 100644 --- a/source/magic.cpp +++ b/source/magic.cpp @@ -4108,20 +4108,50 @@ bool CMagic::SelectSpell( CSocket *mSock, SI32 num ) } // The following loop checks to see if any item is currently equipped (if not a GM) - if( !mChar->IsGM() ) - { - if( type != 2 ) - { - CItem *itemRHand = mChar->GetItemAtLayer( IL_RIGHTHAND ); - CItem *itemLHand = mChar->GetItemAtLayer( IL_LEFTHAND ); - if(( itemLHand != nullptr && itemLHand->GetType() != IT_SPELLCHANNELING ) || ( itemRHand != nullptr && itemRHand->GetType() != IT_SPELLBOOK && itemRHand->GetType() != IT_SPELLCHANNELING )) - { - mSock->SysMessage( 708 ); // You cannot cast with a weapon equipped. - mChar->StopSpell(); - return false; - } - } - } + if( !mChar->IsGM() && type != 2 ) + { + bool autoUnequipEnabled = cwmWorldState->ServerData()->AutoUnequippedCasting(); + + CItem *itemRHand = mChar->GetItemAtLayer( IL_RIGHTHAND ); + CItem *itemLHand = mChar->GetItemAtLayer( IL_LEFTHAND ); + auto mCharPack = mChar->GetPackItem(); + + // Function to check and possibly unequip an item if it blocks spell casting + auto handleItem = [&]( CItem* item, auto itemCheck, bool& blockFlag = true ) + { + if( item && itemCheck( item )) + { + // If auto-unequip is enabled, make sure pack can hold another item before unequipping + if( autoUnequipEnabled && ValidateObject( mCharPack ) && mCharPack->GetContainsList()->Num() < mCharPack->GetMaxItems() ) + { + item->SetCont( mCharPack ); + blockFlag = false; + } + else + { + blockFlag = true; + } + } + else + { + blockFlag = false; + } + }; + + bool lHandBlocks = true; + bool rHandBlocks = true; + + // Evaluate blocking for left and right hand items + handleItem( itemLHand, []( CItem* item ) { return item->GetType() != IT_SPELLCHANNELING; }, lHandBlocks ); + handleItem( itemRHand, []( CItem* item ) { return item->GetType() != IT_SPELLBOOK && item->GetType() != IT_SPELLCHANNELING; }, rHandBlocks ); + + if( lHandBlocks || rHandBlocks ) + { + mSock->SysMessage( 708 ); // You cannot cast with a weapon equipped. + mChar->StopSpell(); + return false; + } + } if( mChar->GetVisible() == VT_TEMPHIDDEN || mChar->GetVisible() == VT_INVISIBLE ) { From f104e12813d8874f43d0bf44cd05e826554abb7a Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 20 Apr 2024 14:46:48 -0500 Subject: [PATCH 2/6] Update Changelog.txt --- source/Changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Changelog.txt b/source/Changelog.txt index 4cc50a0d4..41edae857 100644 --- a/source/Changelog.txt +++ b/source/Changelog.txt @@ -1,4 +1,4 @@ - 20/04/2024 - Dragon Slayer/Xuri +20/04/2024 - Dragon Slayer/Xuri Introduced a new INI setting, AutoUnequippedCasting, enhancing customization and control for users. 22/03/2024 - Dragon Slayer/Xuri From f1328d47b55a97ea8e615afa4631f9dd2572c26c Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 20 Apr 2024 16:23:56 -0500 Subject: [PATCH 3/6] Update clumsy.js --- data/js/magic/clumsy.js | 51 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/data/js/magic/clumsy.js b/data/js/magic/clumsy.js index ada3d3650..96181d2cc 100644 --- a/data/js/magic/clumsy.js +++ b/data/js/magic/clumsy.js @@ -106,22 +106,38 @@ function onSpellCast( mSock, mChar, directCast, spellNum ) // The following loop checks to see if any item is currently equipped (if not a GM) if( mChar.commandlevel < 2 ) { - if( spellType != 2 ) + if( spellType != 2 ) { var itemRHand = mChar.FindItemLayer( 0x01 ); var itemLHand = mChar.FindItemLayer( 0x02 ); - if(( itemLHand && itemLHand.type != 119 ) || ( itemRHand && ( itemRHand.type != 9 || itemRHand.type != 119 ))) // Spellbook + var lHandBlocks = false; + var rHandBlocks = false; + + // Evaluate blocking for left and right hand items + if( isSpellCastingAllowed( itemRHand ) || isSpellCastingAllowed( itemLHand )) + { + var result = handleItem( itemLHand, itemRHand, mChar ); + lHandBlocks = result.lHandBlocks; + rHandBlocks = result.rHandBlocks; + } + + if( lHandBlocks || rHandBlocks ) { if( mSock != null ) { mSock.SysMessage( GetDictionaryEntry( 708, mSock.language )); // You cannot cast with a weapon equipped. } - mChar.SetTimer( Timer.SPELLTIME, 0 ); - mChar.isCasting = false; - mChar.spellCast = -1; + + if( !mChar.isCasting ) + { + mChar.SetTimer( Timer.SPELLTIME, 0 ); + mChar.isCasting = false; + mChar.spellCast = -1; + } return true; } } + return false; } if( mChar.visible == 1 || mChar.visible == 2 ) @@ -389,4 +405,29 @@ function onSpellSuccess( mSock, mChar, ourTarg ) DoTempEffect( 0, sourceChar, ourTarg, 3, Math.round( mChar.skills.magery / 100 ), 0, 0 ); } +// Function to check if an equipped item allows casting +function isSpellCastingAllowed( item ) +{ + return item != null && ( item.type == 9 || item.type == 119 ); // Assuming type 9 is spellbook, and type 119 is spell channeling item +} + +// Function to handle items +function handleItem( itemLHand, itemRHand, mChar ) +{ + var lHandBlocks = false; // Default to false + var rHandBlocks = false; // Default to false + if( itemLHand != null && !isSpellCastingAllowed( itemLHand )) + { // Allow casting if item is spell channeling or type 9 spell book + itemLHand.container = mChar.pack; + lHandBlocks = true; // Set to true if item is blocking + } + + if( itemRHand != null && !isSpellCastingAllowed( itemRHand )) + { // Allow casting if item is spell channeling or type 9 spell book + itemRHand.container = mChar.pack; + rHandBlocks = true; // Set to true if item is blocking + } + return { lHandBlocks: lHandBlocks, rHandBlocks: rHandBlocks }; +} + function _restorecontext_() {} From e850c48da4df34891ab71461ebc7b24a6d0e3341 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 20 Apr 2024 16:53:56 -0500 Subject: [PATCH 4/6] Update clumsy.js --- data/js/magic/clumsy.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data/js/magic/clumsy.js b/data/js/magic/clumsy.js index 96181d2cc..0460b360e 100644 --- a/data/js/magic/clumsy.js +++ b/data/js/magic/clumsy.js @@ -414,15 +414,16 @@ function isSpellCastingAllowed( item ) // Function to handle items function handleItem( itemLHand, itemRHand, mChar ) { + const UnEquipEnabled = GetServerSetting("AutoUnequippedCasting"); var lHandBlocks = false; // Default to false var rHandBlocks = false; // Default to false - if( itemLHand != null && !isSpellCastingAllowed( itemLHand )) + if( UnEquipEnabled && itemLHand != null && !isSpellCastingAllowed( itemLHand )) { // Allow casting if item is spell channeling or type 9 spell book itemLHand.container = mChar.pack; lHandBlocks = true; // Set to true if item is blocking } - if( itemRHand != null && !isSpellCastingAllowed( itemRHand )) + if( UnEquipEnabled && itemRHand != null && !isSpellCastingAllowed( itemRHand )) { // Allow casting if item is spell channeling or type 9 spell book itemRHand.container = mChar.pack; rHandBlocks = true; // Set to true if item is blocking From 2c432ce7e9925c265113116443d02ad3de516252 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 20 Apr 2024 17:00:55 -0500 Subject: [PATCH 5/6] updated spells in js form --- data/js/magic/createfood.js | 54 ++++++++++++++++++++++++++++++++----- data/js/magic/level1targ.js | 53 +++++++++++++++++++++++++++++++----- 2 files changed, 95 insertions(+), 12 deletions(-) diff --git a/data/js/magic/createfood.js b/data/js/magic/createfood.js index 0349dfa29..8952e0944 100644 --- a/data/js/magic/createfood.js +++ b/data/js/magic/createfood.js @@ -83,18 +83,34 @@ function onSpellCast( mSock, mChar, directCast, spellNum ) { var itemRHand = mChar.FindItemLayer( 0x01 ); var itemLHand = mChar.FindItemLayer( 0x02 ); - if(( itemLHand && itemLHand.type != 119 ) || ( itemRHand && ( itemRHand.type != 9 || itemRHand.type != 119 ))) // Spellbook + var lHandBlocks = false; + var rHandBlocks = false; + + // Evaluate blocking for left and right hand items + if( isSpellCastingAllowed( itemRHand ) || isSpellCastingAllowed( itemLHand )) { - if( mSock ) + var result = handleItem( itemLHand, itemRHand, mChar ); + lHandBlocks = result.lHandBlocks; + rHandBlocks = result.rHandBlocks; + } + + if( lHandBlocks || rHandBlocks ) + { + if( mSock != null ) { - mSock.SysMessage( GetDictionaryEntry( 708, mSock.language )); // You cannot cast with a weapon equipped. + mSock.SysMessage(GetDictionaryEntry( 708, mSock.language )); // You cannot cast with a weapon equipped. + } + + if( !mChar.isCasting ) + { + mChar.SetTimer( Timer.SPELLTIME, 0 ); + mChar.isCasting = false; + mChar.spellCast = -1; } - mChar.SetTimer( Timer.SPELLTIME, 0 ); - mChar.isCasting = false; - mChar.spellCast = -1; return true; } } + return false; } // Turn character visible @@ -304,4 +320,30 @@ function onSpellSuccess( mSock, mChar, ourTarg ) } } +// Function to check if an equipped item allows casting +function isSpellCastingAllowed( item ) +{ + return item != null && ( item.type == 9 || item.type == 119 ); // Assuming type 9 is spellbook, and type 119 is spell channeling item +} + +// Function to handle items +function handleItem( itemLHand, itemRHand, mChar ) +{ + const UnEquipEnabled = GetServerSetting( "AutoUnequippedCasting" ); + var lHandBlocks = false; // Default to false + var rHandBlocks = false; // Default to false + if(UnEquipEnabled && itemLHand != null && !isSpellCastingAllowed( itemLHand )) + { // Allow casting if item is spell channeling or type 9 spell book + itemLHand.container = mChar.pack; + lHandBlocks = true; // Set to true if item is blocking + } + + if( UnEquipEnabled && itemRHand != null && !isSpellCastingAllowed( itemRHand )) + { // Allow casting if item is spell channeling or type 9 spell book + itemRHand.container = mChar.pack; + rHandBlocks = true; // Set to true if item is blocking + } + return { lHandBlocks: lHandBlocks, rHandBlocks: rHandBlocks }; +} + function _restorecontext_() {} diff --git a/data/js/magic/level1targ.js b/data/js/magic/level1targ.js index 1d35bd6eb..83d825df3 100644 --- a/data/js/magic/level1targ.js +++ b/data/js/magic/level1targ.js @@ -67,20 +67,35 @@ function ItemInHandCheck( mChar, mSock, spellType ) { var itemRHand = mChar.FindItemLayer( 0x01 ); var itemLHand = mChar.FindItemLayer( 0x02 ); - if(( itemLHand && itemLHand.type != 119 ) || ( itemRHand && ( itemRHand.type != 9 || itemRHand.type != 119 ))) // Spellbook + var lHandBlocks = false; + var rHandBlocks = false; + + // Evaluate blocking for left and right hand items + if( isSpellCastingAllowed( itemRHand ) || isSpellCastingAllowed( itemLHand )) { - if( mSock ) + var result = handleItem( itemLHand, itemRHand, mChar ); + lHandBlocks = result.lHandBlocks; + rHandBlocks = result.rHandBlocks; + } + + if( lHandBlocks || rHandBlocks ) + { + if( mSock != null ) { mSock.SysMessage( GetDictionaryEntry( 708, mSock.language )); // You cannot cast with a weapon equipped. } - mChar.SetTimer( Timer.SPELLTIME, 0 ); - mChar.isCasting = false; - mChar.spellCast = -1; + + if( !mChar.isCasting ) + { + mChar.SetTimer( Timer.SPELLTIME, 0 ); + mChar.isCasting = false; + mChar.spellCast = -1; + } return false; } } + return true; } - return true; } function onSpellCast( mSock, mChar, directCast, spellNum ) @@ -635,4 +650,30 @@ function DispatchSpell( spellNum, mSpell, sourceChar, ourTarg, caster ) } } +// Function to check if an equipped item allows casting +function isSpellCastingAllowed( item ) +{ + return item != null && ( item.type == 9 || item.type == 119 ); // Assuming type 9 is spellbook, and type 119 is spell channeling item +} + +// Function to handle items +function handleItem( itemLHand, itemRHand, mChar ) +{ + const UnEquipEnabled = GetServerSetting( "AutoUnequippedCasting" ); + var lHandBlocks = false; // Default to false + var rHandBlocks = false; // Default to false + if( UnEquipEnabled && itemLHand != null && !isSpellCastingAllowed( itemLHand )) + { // Allow casting if item is spell channeling or type 9 spell book + itemLHand.container = mChar.pack; + lHandBlocks = true; // Set to true if item is blocking + } + + if( UnEquipEnabled && itemRHand != null && !isSpellCastingAllowed( itemRHand )) + { // Allow casting if item is spell channeling or type 9 spell book + itemRHand.container = mChar.pack; + rHandBlocks = true; // Set to true if item is blocking + } + return { lHandBlocks: lHandBlocks, rHandBlocks: rHandBlocks }; +} + function _restorecontext_() {} From dd36c062cfad8004cab5ffc81daa6719e4837d3f Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 27 Apr 2024 02:05:07 -0500 Subject: [PATCH 6/6] Update magic.cpp --- source/magic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/magic.cpp b/source/magic.cpp index 12a39d517..d04ab3f97 100644 --- a/source/magic.cpp +++ b/source/magic.cpp @@ -4117,7 +4117,7 @@ bool CMagic::SelectSpell( CSocket *mSock, SI32 num ) auto mCharPack = mChar->GetPackItem(); // Function to check and possibly unequip an item if it blocks spell casting - auto handleItem = [&]( CItem* item, auto itemCheck, bool& blockFlag = true ) + auto handleItem = [&]( CItem* item, auto itemCheck, bool& blockFlag ) { if( item && itemCheck( item )) {