diff --git a/data/js/commands/targeting/get.js b/data/js/commands/targeting/get.js index 365d3a2b3..b07305bd5 100644 --- a/data/js/commands/targeting/get.js +++ b/data/js/commands/targeting/get.js @@ -294,30 +294,27 @@ function HandleGetItem( socket, ourItem, uKey ) case "DESC": socket.SysMessage( ourItem.desc ); break; - case "DEF": - socket.SysMessage( ourItem.Resist( 1 )); - break; case "DEF": case "RESISTARMOR": - socket.SysMessage( ourObj.Resist( 1 )); + socket.SysMessage( ourItem.Resist( 1 )); break; case "RESISTLIGHT": - socket.SysMessage( ourObj.Resist( 2 )); + socket.SysMessage( ourItem.Resist( 2 )); break; case "RESISTWATER": - socket.SysMessage( ourObj.Resist( 3 )); + socket.SysMessage( ourItem.Resist( 3 )); break; case "RESISTCOLD": - socket.SysMessage( ourObj.Resist( 4 )); + socket.SysMessage( ourItem.Resist( 4 )); break; case "RESISTFIRE": - socket.SysMessage( ourObj.Resist( 5 )); + socket.SysMessage( ourItem.Resist( 5 )); break; case "RESISTENERGY": - socket.SysMessage( ourObj.Resist( 6 )); + socket.SysMessage( ourItem.Resist( 6 )); break; case "RESISTPOISON": - socket.SysMessage( ourObj.Resist( 7 )); + socket.SysMessage( ourItem.Resist( 7 )); break; case "ARMORCLASS": case "ARMOURCLASS": @@ -598,8 +595,27 @@ function HandleGetChar( socket, ourChar, uKey ) break; case "ARMOUR": case "ARMOR": + case "RESISTARMOR": socket.SysMessage( ourChar.Resist( 1 )); break; + case "RESISTLIGHT": + socket.SysMessage( ourChar.Resist( 2 )); + break; + case "RESISTWATER": + socket.SysMessage( ourChar.Resist( 3 )); + break; + case "RESISTCOLD": + socket.SysMessage( ourChar.Resist( 4 )); + break; + case "RESISTFIRE": + socket.SysMessage( ourChar.Resist( 5 )); + break; + case "RESISTENERGY": + socket.SysMessage( ourChar.Resist( 6 )); + break; + case "RESISTPOISON": + socket.SysMessage( ourChar.Resist( 7 )); + break; case "MAXHP": socket.SysMessage( ourChar.maxhp ); break; diff --git a/data/js/npc/ai/vendor_bdo_dispenser.js b/data/js/npc/ai/vendor_bdo_dispenser.js index 0b5739539..9d069ea22 100644 --- a/data/js/npc/ai/vendor_bdo_dispenser.js +++ b/data/js/npc/ai/vendor_bdo_dispenser.js @@ -302,7 +302,7 @@ function onSpeech( myString, pUser, myNPC ) { if( CheckBodTimers( pUser, myNPC.GetTag( "bodType" ) )) { - if( EraStringToNum( GetServerSetting( "CoreShardEra" )) <= EraStringToNum( "lbr" )) + if( EraStringToNum( GetServerSetting( "CoreShardEra" )) >= EraStringToNum( "lbr" )) { myNPC.SetTimer( Timer.MOVETIME, 1000 ); // Pause NPC in their tracks for a second myNPC.TurnToward( pUser ); diff --git a/data/js/server/data/weapontypes.js b/data/js/server/data/weapontypes.js index 42fe15a2b..0a6940e56 100644 --- a/data/js/server/data/weapontypes.js +++ b/data/js/server/data/weapontypes.js @@ -208,6 +208,10 @@ function GetWeaponType( mChar, itemID ) case 0x48B3: //gargish axe - SA weaponType = "TWOHND_AXES"; break; // Default Maces + case 0x0DF2: // Wand + case 0x0DF3: // Wand + case 0x0DF4: // Wand + case 0x0DF5: // Wand case 0x0FB4: //sledge hammer case 0x0FB5: //sledge hammer case 0x0F5C: //mace diff --git a/data/js/server/house/houseCommands.js b/data/js/server/house/houseCommands.js index e27bef044..2c7afd3f3 100644 --- a/data/js/server/house/houseCommands.js +++ b/data/js/server/house/houseCommands.js @@ -1522,8 +1522,17 @@ function DemolishHouse( pSocket, iMulti ) iMulti.RemoveTrashCont( itemInHouse ); itemInHouse.Delete(); } - else if( itemInHouse.movable == 2 ) // items placed as part of the house itself like forge/anvil in smithy + else if( itemInHouse.movable == 2 || itemInHouse.GetTag( "deed" )) // items placed as part of the house itself like forge/anvil in smithy or the addon deed { + var addonDeed = itemInHouse.GetTag( "deed" ); + if( addonDeed ) + { + var newDeed = CreateDFNItem( pSocket, pSocket.currentChar, addonDeed, 1, "ITEM", true ); + if( newDeed ) + { + pSocket.SysMessage( GetDictionaryEntry( 1970, pSocket.language )); // A deed for the house add-on has been placed in your backpack. + } + } itemInHouse.Delete(); } else if( itemInHouse.isLockedDown ) diff --git a/source/CPacketSend.cpp b/source/CPacketSend.cpp index d088c87cb..961323651 100644 --- a/source/CPacketSend.cpp +++ b/source/CPacketSend.cpp @@ -70,7 +70,7 @@ using namespace std::string_literals; //| BYTE[2] unknown5 (0x0) //| BYTE[4] unknown6 (0x0) //| -//| Note: Only send once after login. It’s mandatory to send it once. +//| Note: Only send once after login. It’s mandatory to send it once. //o------------------------------------------------------------------------------------------------o void CPCharLocBody::Log( std::ostream &outStream, bool fullHeader ) { @@ -1411,7 +1411,7 @@ CPPaperdoll &CPPaperdoll::operator = ( CChar &toCopy ) //| //| Packet Build //| BYTE cmd -//| BYTE type (0x00 – “It starts to rain”, 0x01 – “A fierce storm approaches.”, 0x02 – “It begins to snow”, 0x03 - “A storm is brewing.”, 0xFF – None (turns off sound effects), 0xFE (no effect?? Set temperature?) +//| BYTE type (0x00 – “It starts to rain”, 0x01 – “A fierce storm approaches.”, 0x02 – “It begins to snow”, 0x03 - “A storm is brewing.”, 0xFF – None (turns off sound effects), 0xFE (no effect?? Set temperature?) //| BYTE num (number of weather effects on screen) //| BYTE temperature //| @@ -1422,8 +1422,8 @@ CPPaperdoll &CPPaperdoll::operator = ( CChar &toCopy ) //| Note: Weather messages are only displayed when weather starts. //| Note: Weather will end automatically after 6 minutes without any weather change packets. //| Note: You can totally end weather (to display a new message) by teleporting. -//| I think it’s either the 0x78 or 0x20 messages that reset it, though I -//| haven’t checked to be sure (other possibilities, 0x4F or 0x4E) +//| I think it’s either the 0x78 or 0x20 messages that reset it, though I +//| haven’t checked to be sure (other possibilities, 0x4F or 0x4E) //o------------------------------------------------------------------------------------------------o void CPWeather::InternalReset( void ) { @@ -2043,7 +2043,7 @@ void CPOpenGump::Serial( SERIAL toSet ) //| BYTE unknown (0x00) //| BYTE click zLoc //| BYTE[2] model # (if a static tile, 0 if a map/landscape tile) -//| Note: the model # shouldn’t be trusted. +//| Note: the model # shouldn’t be trusted. //o------------------------------------------------------------------------------------------------o CPTargetCursor::CPTargetCursor() { @@ -2601,7 +2601,7 @@ void CPStatWindow::TithingPoints( UI32 value ) //| 0x07 idle //| 0x05 another character is online //| "Another character from this account is currently online in this world. -//| You must either log in as that character or wait for it to time out.” +//| You must either log in as that character or wait for it to time out.” //o------------------------------------------------------------------------------------------------o void CPIdleWarning::InternalReset( void ) { @@ -3107,12 +3107,12 @@ CPMultiPlacementView::CPMultiPlacementView( SERIAL toSet ) //| 0 neither T2A NOR LBR, equal to not sending it at all, //| 1 is T2A, chatbutton, //| 2 is LBR without chatbutton, -//| 3 is LBR with chatbutton… +//| 3 is LBR with chatbutton… //| 8013 LBR + chatbutton + AOS enabled //| //| Note1: this message is send immediately after login. -//| Note2: on OSI servers this controls features OSI enables/disables via “upgrade codes.” -//| Note3: a 3 doesn’t seem to “hurt” older (NON LBR) clients. +//| Note2: on OSI servers this controls features OSI enables/disables via “upgrade codes.” +//| Note3: a 3 doesn’t seem to “hurt” older (NON LBR) clients. //o------------------------------------------------------------------------------------------------o CPEnableClientFeatures::CPEnableClientFeatures( CSocket *mSock ) { @@ -6118,7 +6118,7 @@ void CPObjectInfo::Objects( CItem& mItem, CChar& mChar ) //| BYTE[2] Font //| BYTE[4] Language //| BYTE[30] Name -//| BYTE[?][2] Msg – Null Terminated (blockSize - 48) +//| BYTE[?][2] Msg – Null Terminated (blockSize - 48) //| //| The various types of text is as follows: //| 0x00 - Normal @@ -6294,7 +6294,7 @@ void CPUnicodeSpeech::GhostIt( [[maybe_unused]] UI08 method ) //| BYTE[2] Font //| BYTE[4] Language //| BYTE[30] Name -//| BYTE[?][2] Msg – Null Terminated (blockSize - 48) +//| BYTE[?][2] Msg – Null Terminated (blockSize - 48) //| //| The various types of text is as follows: //| 0x00 - Normal @@ -6572,7 +6572,7 @@ void CPSecureTrading::Name( const std::string& nameFollowing ) //o------------------------------------------------------------------------------------------------o //| Purpose - Handles outgoing packet with server response to all names request //o------------------------------------------------------------------------------------------------o -//| Notes - Packet: 0x98 (All-names “3D”) +//| Notes - Packet: 0x98 (All-names “3D”) //| Size: Variable //| //| Packet Build @@ -6588,7 +6588,7 @@ void CPSecureTrading::Name( const std::string& nameFollowing ) //| Client asks for name of object with ID x. //| Server has to reply with ID + name //| Client automatically knows names of items. -//| Hence it only asks only for NPC/Player names nearby, but shows bars of items plus NPC’s. +//| Hence it only asks only for NPC/Player names nearby, but shows bars of items plus NPC’s. //| //| Client request has 7 bytes, server-reply 37 //| Triggered by Crtl + Shift. @@ -6641,7 +6641,7 @@ void CPAllNames3D::Object( CBaseObject& obj ) //| BYTE[var] null terminated line //| Note: //| server side: # of pages equals value given in 0x93/0xd4 -//| EACH page # given. If empty: # lines: 0 + terminator (=3 0’s) +//| EACH page # given. If empty: # lines: 0 + terminator (=3 0’s) //| client side: # of pages always 1. if 2 pages changed, client generates 2 packets. //o------------------------------------------------------------------------------------------------o void CPBookPage::IncLength( UI08 amount ) @@ -7009,7 +7009,7 @@ bool CPNewSpellBook::ClientCanReceive( CSocket *mSock ) //| BYTE[4] Serial //| BYTE Damage // how much damage was done ? //| -//| Note: displays damage above the npc/player’s head. +//| Note: displays damage above the npc/player’s head. //o------------------------------------------------------------------------------------------------o void CPDisplayDamage::InternalReset( void ) { @@ -7687,6 +7687,41 @@ void CPToolTip::CopyItemData( CItem& cItem, size_t &totalStringLen, bool addAmou FinalizeData( tempEntry, totalStringLen ); } + if( cItem.GetHitChance() > 0 ) + { + tempEntry.stringNum = 1060415; // hit chance increase ~1_val~% + tempEntry.ourText = oldstrutil::number( cItem.GetHitChance() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetDefenseChance() > 0 ) + { + tempEntry.stringNum = 1060408; // defense chance increase ~1_val~% + tempEntry.ourText = oldstrutil::number( cItem.GetDefenseChance() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetHealthBonus() > 0 ) + { + tempEntry.stringNum = 1060431; // hit point increase ~1_val~ + tempEntry.ourText = oldstrutil::number( cItem.GetHealthBonus() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetStaminaBonus() > 0 ) + { + tempEntry.stringNum = 1060484; // stamina increase ~1_val~ + tempEntry.ourText = oldstrutil::number( cItem.GetStaminaBonus() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetManaBonus() > 0 ) + { + tempEntry.stringNum = 1060439; // mana increase ~1_val~ + tempEntry.ourText = oldstrutil::number( cItem.GetManaBonus() ); + FinalizeData( tempEntry, totalStringLen ); + } + if( cItem.GetStrength() > 1 ) { tempEntry.stringNum = 1061170; // strength requirement ~1_val~ @@ -8058,9 +8093,9 @@ bool CPSellList::CanSellItems( CChar &mChar, CChar &vendor ) //| BYTE[2] len //| BYTE subcmd //| BYTE[ len - 4 ] submessage -//| Submessage 0 – Display Bulletin Board +//| Submessage 0 – Display Bulletin Board //| BYTE[4] Board serial -//| BYTE[22] board name (default is “bulletin board”, the rest nulls) +//| BYTE[22] board name (default is “bulletin board”, the rest nulls) //| BYTE[4] unknown/ID? //| BYTE[4] zero (0) //o------------------------------------------------------------------------------------------------o @@ -8140,7 +8175,7 @@ CPOpenMessageBoard::CPOpenMessageBoard( CSocket *mSock ) //| BYTE subjectLen //| BYTE[subjectLen] subject (null terminated string) //| BYTE timeLen -//| BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”) +//| BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”) //o------------------------------------------------------------------------------------------------o //| Subcommand: 0x2 (Message Summary) //| Size: Variable @@ -8157,7 +8192,7 @@ CPOpenMessageBoard::CPOpenMessageBoard( CSocket *mSock ) //| BYTE subjectLen //| BYTE[subjectLen] subject (null terminated string) //| BYTE timeLen -//| BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”) +//| BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”) //| BYTE[5] Unknown (01 90 03 F7 00) //| BYTE numlines //| For each line: diff --git a/source/Changelog.txt b/source/Changelog.txt index 1366bcc6a..ee8b02ae1 100644 --- a/source/Changelog.txt +++ b/source/Changelog.txt @@ -7,9 +7,35 @@ Added leechstats.js file that controls the combat for the properties. (script 7003) To add this script to a weapon only. add in SCRIPT=7003, HEALTHLEECH=# or STAMINALEECH=# or MANALEECH=# it can also be all three on the weapon. +14/06/2024 - Dragon Slayer + Added two new DFN tags for Items: + HITCHANCE=# // Increases the player's chance to hit a target with wrestling, melee and ranged weapons. + DEFENSECHANCE=# // Increases the wearer's chance that his opponents' swings (or arrows/bolts) will miss. + These are also available as JS Engine object properties: .hitChance, .defenseChance + +13/06/2024 - Dragon Slayer + Added three More AOS Props + -HEALTHBONUS=# + -MANABONUS=# + -STAMINABONUS=# + Add this properties to any weapon/armor/jewlery will give the player more hp/mana/stam why its equiped. depending on number you add with it + These are also available as JS Engine object properties: .healthBonus, .staminaBonus, .manaBonus + +6/06/2024 - Dragon Slayer + Fixed Accepting bods, When the expansion is to to lbr or later. + +29/05/2024 - Dragon Slayer + House add-on deeds are now returned when an add-on is present in the house on demolish. + +27/05/2024 - Dragon Slayer + Added Missing Wand ID's to combat weapon type in core and in js. + 13/05/2024 - Dragon Slayer Added New Shield Type 107 so shield ID's no longer have to be in hard code for shields to work properly +11/05/2024 - Dragon Slayer + Updated 'get command (js/commands/targeting/get.js) to use correct object reference when getting resist values for items, and added support for getting resist values for chars + 09/05/2024 - Dragon Slayer Added ArtifactRarity AOS Property for items -ARTIFACTRARITY=# diff --git a/source/UOXJSPropertyEnums.h b/source/UOXJSPropertyEnums.h index cd00a7706..2c2eb0a80 100644 --- a/source/UOXJSPropertyEnums.h +++ b/source/UOXJSPropertyEnums.h @@ -339,6 +339,8 @@ enum CC_Properties CCP_SPAWNSERIAL, CCP_SPATTACK, CCP_SPDELAY, + CCP_HITCHANCE, + CCP_DEFENSECHANCE, CCP_AITYPE, CCP_SPLIT, CCP_SPLITCHANCE, @@ -461,6 +463,9 @@ enum CI_Properties CIP_DAMAGEPOISON, CIP_DAMAGERAIN, CIP_DAMAGESNOW, + CIP_HITCHANCE, + CIP_DEFENSECHANCE, + CIP_ARTIFACTRARITY, CIP_NAME2, CIP_ISITEM, @@ -519,6 +524,9 @@ enum CI_Properties CIP_ISCONTTYPE, CIP_CARVESECTION, CIP_SPEED, + CIP_HEALTHBONUS, + CIP_STAMINABONUS, + CIP_MANABONUS, CIP_MULTI, CIP_AMMOID, CIP_AMMOHUE, diff --git a/source/UOXJSPropertyFuncs.cpp b/source/UOXJSPropertyFuncs.cpp index 4615406a4..3418eec20 100644 --- a/source/UOXJSPropertyFuncs.cpp +++ b/source/UOXJSPropertyFuncs.cpp @@ -679,7 +679,13 @@ JSBool CItemProps_getProperty( JSContext *cx, JSObject *obj, jsval id, jsval *vp case CIP_HEALTHLEECH: *vp = INT_TO_JSVAL( gPriv->GetHealthLeech() ); break; case CIP_STAMINALEECH: *vp = INT_TO_JSVAL( gPriv->GetStaminaLeech() ); break; case CIP_MANALEECH: *vp = INT_TO_JSVAL( gPriv->GetManaLeech() ); break; + case CIP_HITCHANCE: *vp = INT_TO_JSVAL( gPriv->GetHitChance() ); break; + case CIP_DEFENSECHANCE: *vp = INT_TO_JSVAL( gPriv->GetDefenseChance() ); break; + case CIP_HEALTHBONUS: *vp = INT_TO_JSVAL( gPriv->GetHealthBonus() ); break; + case CIP_STAMINABONUS: *vp = INT_TO_JSVAL( gPriv->GetStaminaBonus() ); break; + case CIP_MANABONUS: *vp = INT_TO_JSVAL( gPriv->GetManaBonus() ); break; case CIP_ARTIFACTRARITY: *vp = INT_TO_JSVAL( gPriv->GetArtifactRarity() ); break; + case CIP_NAME2: tString = JS_NewStringCopyZ( cx, gPriv->GetName2().c_str() ); *vp = STRING_TO_JSVAL( tString ); @@ -1328,7 +1334,13 @@ JSBool CItemProps_setProperty( JSContext *cx, JSObject *obj, jsval id, jsval *vp case CIP_HEALTHLEECH: gPriv->SetHealthLeech( static_cast( encaps.toInt() )); break; case CIP_STAMINALEECH: gPriv->SetStaminaLeech( static_cast( encaps.toInt() )); break; case CIP_MANALEECH: gPriv->SetManaLeech( static_cast( encaps.toInt() )); break; + case CIP_HITCHANCE: gPriv->SetHitChance( static_cast( encaps.toInt() )); break; + case CIP_DEFENSECHANCE: gPriv->SetDefenseChance( static_cast( encaps.toInt() )); break; + case CIP_HEALTHBONUS: gPriv->SetHealthBonus( static_cast( encaps.toInt() )); break; + case CIP_STAMINABONUS: gPriv->SetStaminaBonus( static_cast( encaps.toInt() )); break; + case CIP_MANABONUS: gPriv->SetManaBonus( static_cast( encaps.toInt() )); break; case CIP_ARTIFACTRARITY: gPriv->SetArtifactRarity( static_cast( encaps.toInt() )); break; + case CIP_NAME2: gPriv->SetName2( encaps.toString() ); break; case CIP_RACE: gPriv->SetRace( static_cast( encaps.toInt() )); break; case CIP_MAXHP: gPriv->SetMaxHP( static_cast( encaps.toInt() )); break; @@ -2002,6 +2014,8 @@ JSBool CCharacterProps_getProperty( JSContext *cx, JSObject *obj, jsval id, jsva case CCP_HOUSEICONS: *vp = BOOLEAN_TO_JSVAL( gPriv->ViewHouseAsIcon() ); break; case CCP_SPATTACK: *vp = INT_TO_JSVAL( gPriv->GetSpAttack() ); break; case CCP_SPDELAY: *vp = INT_TO_JSVAL( gPriv->GetSpDelay() ); break; + case CCP_HITCHANCE: *vp = INT_TO_JSVAL( gPriv->GetHitChance() ); break; + case CCP_DEFENSECHANCE: *vp = INT_TO_JSVAL( gPriv->GetDefenseChance() ); break; case CCP_AITYPE: *vp = INT_TO_JSVAL( gPriv->GetNpcAiType() ); break; case CCP_SPLIT: *vp = INT_TO_JSVAL( gPriv->GetSplit() ); break; case CCP_SPLITCHANCE: *vp = INT_TO_JSVAL( gPriv->GetSplitChance() ); break; @@ -2507,6 +2521,8 @@ JSBool CCharacterProps_setProperty( JSContext *cx, JSObject *obj, jsval id, jsva case CCP_HOUSEICONS: gPriv->SetViewHouseAsIcon( encaps.toBool() ); break; case CCP_SPATTACK: gPriv->SetSpAttack( static_cast( encaps.toInt() )); break; case CCP_SPDELAY: gPriv->SetSpDelay( static_cast( encaps.toInt() )); break; + case CCP_HITCHANCE: gPriv->SetHitChance( static_cast( encaps.toInt() )); break; + case CCP_DEFENSECHANCE: gPriv->SetDefenseChance( static_cast( encaps.toInt() )); break; case CCP_AITYPE: gPriv->SetNPCAiType( static_cast( encaps.toInt() )); break; case CCP_SPLIT: gPriv->SetSplit( static_cast( encaps.toInt() )); break; case CCP_SPLITCHANCE: gPriv->SetSplitChance( static_cast( encaps.toInt() ));break; diff --git a/source/UOXJSPropertySpecs.h b/source/UOXJSPropertySpecs.h index 5bc4c5006..a8ecac965 100644 --- a/source/UOXJSPropertySpecs.h +++ b/source/UOXJSPropertySpecs.h @@ -357,6 +357,8 @@ inline JSPropertySpec CCharacterProps[] = { "houseicons", CCP_HOUSEICONS, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "spattack", CCP_SPATTACK, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "spdelay", CCP_SPDELAY, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "hitChance", CCP_HITCHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "defenseChance", CCP_DEFENSECHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "aitype", CCP_AITYPE, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "split", CCP_SPLIT, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "splitchance", CCP_SPLITCHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, @@ -535,10 +537,19 @@ inline JSPropertySpec CItemProps[] = { "ammoFXHue", CIP_AMMOFXHUE, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "ammoFXRender", CIP_AMMOFXRENDER, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "speed", CIP_SPEED, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "healthLeech", CIP_HEALTHLEECH, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "staminaLeech", CIP_STAMINALEECH, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "manaLeech", CIP_MANALEECH, JSPROP_ENUMANDPERM, nullptr, nullptr }, + + { "hitChance", CIP_HITCHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "defenseChance", CIP_DEFENSECHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, + + { "healthBonus", CIP_HEALTHBONUS, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "staminaBonus", CIP_STAMINABONUS, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "manaBonus", CIP_MANABONUS, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "artifactRarity", CIP_ARTIFACTRARITY, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "multi", CIP_MULTI, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "maxRange", CIP_MAXRANGE, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "baseRange", CIP_BASERANGE, JSPROP_ENUMANDPERM, nullptr, nullptr }, diff --git a/source/cBaseObject.cpp b/source/cBaseObject.cpp index 2c5ce0b89..8ffa0e864 100644 --- a/source/cBaseObject.cpp +++ b/source/cBaseObject.cpp @@ -98,6 +98,13 @@ const SI16 DEFBASE_HEALTHLEECH = 0; const SI16 DEFBASE_STAMINALEECH = 0; const SI16 DEFBASE_MANALEECH = 0; +const SI16 DEFBASE_HITCHANCE = 0; +const SI16 DEFBASE_DEFENSECHANCE = 0; + +const SI16 DEFBASE_HEALTHBONUS = 0; +const SI16 DEFBASE_STAMINABONOS = 0; +const SI16 DEFBASE_MANABONUS = 0; + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject constructor //| Date - 26 July, 2000 @@ -114,6 +121,7 @@ mana( DEFBASE_MANA ), stamina( DEFBASE_STAMINA ), scriptTrig( DEFBASE_SCPTRIG ), in2( DEFBASE_INT2 ), FilePosition( DEFBASE_FP ), poisoned( DEFBASE_POISONED ), carve( DEFBASE_CARVE ), oldLocX( 0 ), oldLocY( 0 ), oldLocZ( 0 ), oldTargLocX( 0 ), oldTargLocY( 0 ), fame( DEFBASE_FAME ), karma( DEFBASE_KARMA ), kills( DEFBASE_KILLS ), subRegion( DEFBASE_SUBREGION ), nameRequestActive( DEFBASE_NAMEREQUESTACTIVE ), origin( DEFBASE_ORIGIN ), +healthBonus( DEFBASE_HEALTHBONUS ),staminaBonus( DEFBASE_STAMINABONOS ), manaBonus( DEFBASE_MANABONUS ), hitChance( DEFBASE_HITCHANCE ), defenseChance( DEFBASE_DEFENSECHANCE ), healthLeech( DEFBASE_HEALTHLEECH ), staminaLeech( DEFBASE_STAMINALEECH ), manaLeech( DEFBASE_MANALEECH ) { multis = nullptr; @@ -1040,6 +1048,46 @@ void CBaseObject::IncHP( SI16 amtToChange ) SetHP( hitpoints + amtToChange ); } +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::GetHitChance() +//| CBaseObject::SetHitChance() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Defense Chance of the Item(s) Equiped or Character +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetHitChance( void ) const +{ + return hitChance; +} +void CBaseObject::SetHitChance( SI16 newValue ) +{ + hitChance = newValue; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::GetDefenseChance() +//| CBaseObject::SetDefenseChance() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Defense Chance of the Item(s) Equiped or Character +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetDefenseChance( void ) const +{ + return defenseChance; +} +void CBaseObject::SetDefenseChance( SI16 newValue ) +{ + defenseChance = newValue; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject::GetDir() //| CBaseObject::SetDir() @@ -1655,6 +1703,26 @@ void CBaseObject::SetHealthLeech( SI16 nVal ) } } +//| Function - CBaseObject::GetHealthBonus() +//| CBaseObject::SetHealthBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the health max var associated with the object. For chars, it's the +//| bonuses (via armour and such) +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetHealthBonus( void ) const +{ + return healthBonus; +} +void CBaseObject::SetHealthBonus( SI16 nVal ) +{ + healthBonus = nVal; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject::GetStaminaLeech() //| CBaseObject::SetStaminaLeech() @@ -1675,6 +1743,26 @@ void CBaseObject::SetStaminaLeech( SI16 nVal ) } } +//| Function - CBaseObject::GetStaminaBonus() +//| CBaseObject::SetStaminaBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the stamina max var associated with the object. For chars, it's the +//| bonuses (via armour and such) +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetStaminaBonus( void ) const +{ + return staminaBonus; +} +void CBaseObject::SetStaminaBonus( SI16 nVal ) +{ + staminaBonus = nVal; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject::GetManaLeech() //| CBaseObject::SetManaLeech() @@ -1695,6 +1783,26 @@ void CBaseObject::SetManaLeech( SI16 nVal ) } } +//| Function - CBaseObject::GetManaBonus() +//| CBaseObject::SetManaBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Mana max var associated with the object. For chars, it's the +//| bonuses (via armour and such) +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetManaBonus( void ) const +{ + return manaBonus; +} +void CBaseObject::SetManaBonus( SI16 nVal ) +{ + manaBonus = nVal; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject::IncStrength() //o------------------------------------------------------------------------------------------------o @@ -1755,6 +1863,25 @@ void CBaseObject::IncManaLeech( SI16 toInc ) SetManaLeech( manaLeech + toInc ); } +//| Function - CBaseObject::IncHitChance() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments the object's Hit Chance value +//o------------------------------------------------------------------------------------------------o +void CBaseObject::IncHitChance( SI16 toInc ) +{ + SetHitChance( hitChance + toInc ); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::IncDefenseChance() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments the object's Hit Chance value +//o------------------------------------------------------------------------------------------------o +void CBaseObject::IncDefenseChance( SI16 toInc ) +{ + SetDefenseChance( defenseChance + toInc ); +} + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject::DumpFooter() //o------------------------------------------------------------------------------------------------o diff --git a/source/cBaseObject.h b/source/cBaseObject.h index 316cd2530..d19902995 100644 --- a/source/cBaseObject.h +++ b/source/cBaseObject.h @@ -69,6 +69,8 @@ class CBaseObject SI16 dexterity; SI16 intelligence; SI16 hitpoints; + SI16 hitChance; + SI16 defenseChance; VisibleTypes visible; SI16 hiDamage; SI16 loDamage; @@ -82,6 +84,9 @@ class CBaseObject SI16 st2; SI16 dx2; SI16 in2; + SI16 healthBonus; + SI16 staminaBonus; + SI16 manaBonus; mutable SI32 FilePosition; SERIAL tempMulti; std::string name; @@ -226,6 +231,12 @@ class CBaseObject virtual void SetHP( SI16 newValue ); void IncHP( SI16 amtToChange ); + virtual SI16 GetHitChance( void ) const; + virtual void SetHitChance( SI16 newValue ); + + virtual SI16 GetDefenseChance( void ) const; + virtual void SetDefenseChance( SI16 newValue ); + void SetDir( UI08 newDir, bool sendUpdate = true ); UI08 GetDir( void ) const; @@ -259,6 +270,7 @@ class CBaseObject void IncDexterity( SI16 toInc = 1 ); void IncIntelligence( SI16 toInc = 1 ); + SI16 GetHealthLeech( void ) const; virtual void SetHealthLeech( SI16 nVal ); @@ -272,6 +284,18 @@ class CBaseObject void IncStaminaLeech( SI16 toInc = 1 ); void IncManaLeech( SI16 toInc = 1 ); + void IncHitChance( SI16 toInc = 1 ); + void IncDefenseChance( SI16 toInc = 1 ); + + SI16 GetHealthBonus( void ) const; + virtual void SetHealthBonus( SI16 nVal ); + + SI16 GetStaminaBonus( void ) const; + virtual void SetStaminaBonus( SI16 nVal ); + + SI16 GetManaBonus( void ) const; + virtual void SetManaBonus( SI16 nVal ); + virtual void PostLoadProcessing( void ); virtual bool LoadRemnants( void ) = 0; diff --git a/source/cChar.cpp b/source/cChar.cpp index 439a72527..acd8011f4 100644 --- a/source/cChar.cpp +++ b/source/cChar.cpp @@ -2411,6 +2411,8 @@ void CChar::CopyData( CChar *target ) target->SetNextAct( nextAct ); target->SetSquelched( GetSquelched() ); target->SetMeditating( IsMeditating() ); + target->SetHitChance( GetHitChance() ); + target->SetDefenseChance( GetDefenseChance() ); target->SetStealth( stealth ); target->SetRunning( running ); target->SetRace( GetRace() ); @@ -2924,6 +2926,13 @@ bool CChar::WearItem( CItem *toWear ) IncStaminaLeech( itemLayers[tLayer]->GetStaminaLeech() ); IncManaLeech( itemLayers[tLayer]->GetManaLeech() ); + IncHitChance( itemLayers[tLayer]->GetHitChance() ); + IncDefenseChance( itemLayers[tLayer]->GetDefenseChance() ); + + IncHealthBonus( itemLayers[tLayer]->GetHealthBonus() ); + IncStaminaBonus( itemLayers[tLayer]->GetStaminaBonus() ); + IncManaBonus( itemLayers[tLayer]->GetManaBonus() ); + if( toWear->IsPostLoaded() ) { if( itemLayers[tLayer]->GetPoisoned() ) @@ -2987,6 +2996,14 @@ bool CChar::TakeOffItem( ItemLayers Layer ) IncHealthLeech( -itemLayers[Layer]->GetHealthLeech() ); IncStaminaLeech( -itemLayers[Layer]->GetStaminaLeech() ); IncManaLeech( -itemLayers[Layer]->GetManaLeech() ); + + IncHitChance( -itemLayers[Layer]->GetHitChance() ); + IncDefenseChance( -itemLayers[Layer]->GetDefenseChance() ); + + IncHealthBonus( -itemLayers[Layer]->GetHealthBonus() ); + IncStaminaBonus( -itemLayers[Layer]->GetStaminaBonus() ); + IncManaBonus( -itemLayers[Layer]->GetManaBonus() ); + if( itemLayers[Layer]->GetPoisoned() ) { if( itemLayers[Layer]->GetPoisoned() > GetPoisoned() ) @@ -3142,6 +3159,8 @@ bool CChar::DumpBody( std::ostream &outStream ) const //------------------------------------------------------------------------------------------- outStream << "CanRun=" + std::to_string((( CanRun() && IsNpc() ) ? 1 : 0 )) + newLine; outStream << "CanAttack=" + std::to_string(( GetCanAttack() ? 1 : 0 )) + newLine; + outStream << "HitChance=" + std::to_string( GetHitChance() ) + newLine; + outStream << "DefChance=" + std::to_string( GetDefenseChance() ) + newLine; outStream << "AllMove=" + std::to_string(( AllMove() ? 1 : 0 )) + newLine; outStream << "IsNpc=" + std::to_string(( IsNpc() ? 1 : 0 )) + newLine; outStream << "IsShop=" + std::to_string(( IsShop() ? 1 : 0 )) + newLine; @@ -3795,7 +3814,7 @@ UI16 CChar::GetMaxHP( void ) oldRace = GetRace(); } - return maxHP; + return maxHP + GetHealthBonus(); } void CChar::SetMaxHP( UI16 newmaxhp, UI16 newoldstr, RACEID newoldrace ) { @@ -3838,7 +3857,7 @@ void CChar::SetFixedMaxHP( SI16 newmaxhp ) SI16 CChar::GetMaxMana( void ) { if(( maxMana_oldint != GetIntelligence() || oldRace != GetRace() ) && !GetMaxManaFixed() ) - //if int/race changed since last calculation, recalculate maxHp + //if int/race changed since last calculation, recalculate maxMana { CRace *pRace = Races->Race( GetRace() ); @@ -3855,7 +3874,7 @@ SI16 CChar::GetMaxMana( void ) oldRace = GetRace(); } - return maxMana; + return maxMana + GetManaBonus(); } void CChar::SetMaxMana( SI16 newmaxmana, UI16 newoldint, RACEID newoldrace ) { @@ -3897,7 +3916,7 @@ void CChar::SetFixedMaxMana( SI16 newmaxmana ) //o------------------------------------------------------------------------------------------------o SI16 CChar::GetMaxStam( void ) { - // If dex/race changed since last calculation, recalculate maxHp + // If dex/race changed since last calculation, recalculate maxStam if(( maxStam_olddex != GetDexterity() || oldRace != GetRace() ) && !GetMaxStamFixed() ) { CRace *pRace = Races->Race( GetRace() ); @@ -3915,7 +3934,7 @@ SI16 CChar::GetMaxStam( void ) oldRace = GetRace(); } - return maxStam; + return maxStam + GetStaminaBonus(); } void CChar::SetMaxStam( SI16 newmaxstam, UI16 newolddex, RACEID newoldrace ) { @@ -4380,6 +4399,11 @@ bool CChar::HandleLine( std::string &UTag, std::string &data ) SetDead(( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 )); rValue = true; } + else if( UTag == "DEFCHANCE" ) + { + SetDefenseChance( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } break; case 'E': if( UTag == "EMOTION" ) @@ -4468,7 +4492,12 @@ bool CChar::HandleLine( std::string &UTag, std::string &data ) } break; case 'H': - if( UTag == "HUNGER" ) + if( UTag == "HITCHANCE" ) + { + SetHitChance( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } + else if( UTag == "HUNGER" ) { SetHunger( static_cast( std::stoi( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); rValue = true; @@ -5601,6 +5630,74 @@ void CChar::SetIntelligence2( SI16 nVal ) UpdateRegion(); } +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::SetHealthBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Sets bonus Hits stat for character +//o------------------------------------------------------------------------------------------------o +void CChar::SetHealthBonus( SI16 nVal ) +{ + CBaseObject::SetHealthBonus( nVal ); + Dirty( UT_HITPOINTS ); + UpdateRegion(); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::SetStaminaBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Sets bonus Stam stat for character +//o------------------------------------------------------------------------------------------------o +void CChar::SetStaminaBonus( SI16 nVal ) +{ + CBaseObject::SetStaminaBonus( nVal ); + Dirty( UT_STAMINA ); + UpdateRegion(); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::SetManaBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Sets bonus Mana stat for character +//o------------------------------------------------------------------------------------------------o +void CChar::SetManaBonus( SI16 nVal ) +{ + CBaseObject::SetManaBonus( nVal ); + Dirty( UT_MANA ); + UpdateRegion(); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::IncHealthBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments GetHealthBonus (modifications) by toAdd +//o------------------------------------------------------------------------------------------------o +void CChar::IncHealthBonus( SI16 toAdd ) +{ + SetHealthBonus( static_cast( GetHealthBonus() + toAdd )); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::IncStaminaBonus() +//| Date - 26 May 2024 +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments GetBonusStam (modifications) by toAdd +//o------------------------------------------------------------------------------------------------o +void CChar::IncStaminaBonus( SI16 toAdd ) +{ + SetStaminaBonus( static_cast( GetStaminaBonus() + toAdd )); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::IncManaBonus() +//| Date - 26 May 2024 +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments GetBonusMana (modifications) by toAdd +//o------------------------------------------------------------------------------------------------o +void CChar::IncManaBonus( SI16 toAdd ) +{ + SetManaBonus( static_cast( GetManaBonus() + toAdd )); +} + //o------------------------------------------------------------------------------------------------o //| Function - CChar::IncStamina() //o------------------------------------------------------------------------------------------------o diff --git a/source/cChar.h b/source/cChar.h index ed4cc90ba..ae387a58c 100644 --- a/source/cChar.h +++ b/source/cChar.h @@ -628,6 +628,15 @@ class CChar : public CBaseObject virtual void SetStrength2( SI16 newValue ) override; virtual void SetDexterity2( SI16 newValue ) override; virtual void SetIntelligence2( SI16 newValue ) override; + + virtual void SetHealthBonus( SI16 newValue ) override; + virtual void SetStaminaBonus( SI16 newValue ) override; + virtual void SetManaBonus( SI16 newValue ) override; + + void IncHealthBonus( SI16 toAdd = 1 ); + void IncStaminaBonus( SI16 toAdd = 1 ); + void IncManaBonus( SI16 toAdd = 1 ); + void IncStamina( SI16 toInc ); void IncMana( SI16 toInc ); void SetMaxLoyalty( UI16 newMaxLoyalty ); diff --git a/source/cItem.cpp b/source/cItem.cpp index c07822758..d692eaede 100644 --- a/source/cItem.cpp +++ b/source/cItem.cpp @@ -1654,7 +1654,11 @@ auto CItem::CopyData( CItem *target ) -> void target->SetRndValueRate( GetRndValueRate() ); target->SetSpawn( GetSpawn() ); target->SetSpeed( GetSpeed() ); + target->SetHitChance( GetHitChance() ); + target->SetDefenseChance( GetDefenseChance() ); + target->SetArtifactRarity( GetArtifactRarity() ); + target->SetSpell( 0, GetSpell( 0 )); target->SetSpell( 1, GetSpell( 1 )); target->SetSpell( 2, GetSpell( 2 )); @@ -1674,6 +1678,9 @@ auto CItem::CopyData( CItem *target ) -> void target->SetWeightMax( GetWeightMax() ); target->SetBaseWeight( GetBaseWeight() ); target->SetMaxItems( GetMaxItems() ); + target->SetHealthBonus( GetHealthBonus() ); + target->SetStaminaBonus( GetStaminaBonus() ); + target->SetManaBonus( GetManaBonus() ); //target->SetWipeable( IsWipeable() ); target->SetPriv( GetPriv() ); target->SetBaseRange( GetBaseRange() ); @@ -1756,7 +1763,10 @@ bool CItem::DumpBody( std::ostream &outStream ) const outStream << "BaseWeight=" + std::to_string( GetBaseWeight() ) + newLine; outStream << "MaxItems=" + std::to_string( GetMaxItems() ) + newLine; outStream << "MaxHP=" + std::to_string( GetMaxHP() ) + newLine; + outStream << "HitChance=" + std::to_string( GetHitChance() ) + newLine; + outStream << "DefenseChance=" + std::to_string( GetDefenseChance() ) + newLine; outStream << "Speed=" + std::to_string( GetSpeed() ) + newLine; + outStream << "BonusStats=" + std::to_string( GetHealthBonus() ) + "," + std::to_string( GetStaminaBonus() ) + "," + std::to_string( GetManaBonus() ) + newLine; outStream << "ArtifactRarity=" + std::to_string( GetArtifactRarity() ) + newLine; outStream << "Movable=" + std::to_string( GetMovable() ) + newLine; outStream << "Priv=" + std::to_string( GetPriv() ) + newLine; @@ -1847,6 +1857,13 @@ bool CItem::HandleLine( std::string &UTag, std::string &data ) bools = static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )); rValue = true; } + else if( UTag == "BONUSSTATS" ) + { + SetHealthBonus( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[0], "//" )), nullptr, 0 ))); + SetStaminaBonus( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[1], "//" )), nullptr, 0 ))); + SetManaBonus( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[2], "//" )), nullptr, 0 ))); + rValue = true; + } break; case 'C': if( UTag == "CONT" ) @@ -1886,6 +1903,11 @@ bool CItem::HandleLine( std::string &UTag, std::string &data ) SetDye( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 ); rValue = true; } + else if( UTag == "DEFENSECHANCE" ) + { + SetDefenseChance( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } break; case 'E': if( UTag == "ENTRYMADEFROM" ) @@ -1932,6 +1954,11 @@ bool CItem::HandleLine( std::string &UTag, std::string &data ) SetWeatherDamage( HEAT, static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 ); rValue = true; } + else if( UTag == "HITCHANCE" ) + { + SetHitChance( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } break; case 'L': if( UTag == "LAYER" ) diff --git a/source/combat.cpp b/source/combat.cpp index 8817d7b3d..181c7503c 100644 --- a/source/combat.cpp +++ b/source/combat.cpp @@ -801,6 +801,10 @@ UI08 CHandleCombat::GetWeaponType( CItem *i ) case 0x48B3: //gargish axe - SA return TWOHND_AXES; // Default Maces + case 0x0DF2: // Wand + case 0x0DF3: // Wand + case 0x0DF4: // Wand + case 0x0DF5: // Wand case 0x13E3: //smith's hammer case 0x13E4: //smith's hammer case 0x13B3: //club @@ -2877,18 +2881,24 @@ bool CHandleCombat::HandleCombat( CSocket *mSock, CChar& mChar, CChar *ourTarg ) R32 attHitChanceBonus = 0; R32 defDefenseChanceBonus = 0; R32 maxAttHitChanceBonus = 45; + if( cwmWorldState->ServerData()->ExpansionCombatHitChance() >= ER_SA && mChar.GetBodyType() == BT_GARGOYLE ) { // If attacker is a Gargoyle player, and ExpansionCombatHitChance is ER_SA or higher, use 50 as hitchance bonus cap instead of 45 maxAttHitChanceBonus = 50; } - // Fetch bonuses to hitChance/defenseChance from AoS item properties, when implemented - //attHitChanceBonus = GetAttackerHitChanceBonus(); - //defDefenseChanceBonus = GetDefenderDefenseChanceBonus(); + // Fetch bonuses to hitChance/defenseChance from AoS item properties or characters + attHitChanceBonus = mChar.GetHitChance(); + defDefenseChanceBonus = mChar.GetDefenseChance(); + + // Clamp to ensure valid bonus ranges (e.g., no multiplier below 1) + R32 effectiveAttHitChanceBonus = std::max(-99.0f, std::min( attHitChanceBonus, maxAttHitChanceBonus )); // Cap at -99 and maxAttHitChanceBonus + R32 effectiveDefDefenseChanceBonus = std::max(-99.0f, std::min( defDefenseChanceBonus, 45.0f )); // Cap at -99 and 45 - R32 attackerHitChance = ( static_cast( attackSkill / 10 ) + 20 ) * ( 100 + std::min( attHitChanceBonus, static_cast( maxAttHitChanceBonus ))); - R32 defenderDefenseChance = ( static_cast( defendSkill / 10 ) + 20 ) * ( 100 + std::min( defDefenseChanceBonus, static_cast( 45 ))); + // Calculate the attacker's hit chance and defender's defense chance + R32 attackerHitChance = ( static_cast( attackSkill / 10 ) + 20 ) * ( 100 + effectiveAttHitChanceBonus ); + R32 defenderDefenseChance = ( static_cast( defendSkill / 10 ) + 20 ) * ( 100 + effectiveDefDefenseChanceBonus ); hitChance = ( attackerHitChance / ( defenderDefenseChance * 2 )) * 100; // Always leave at least 2% chance to hit diff --git a/source/items.cpp b/source/items.cpp index df3fb88d8..9bb1e737e 100644 --- a/source/items.cpp +++ b/source/items.cpp @@ -143,6 +143,9 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect case DFNTAG_STAMINALEECH: applyTo->SetStaminaLeech( static_cast( ndata )); break; case DFNTAG_MANALEECH: applyTo->SetManaLeech( static_cast( ndata )); break; case DFNTAG_BASERANGE: applyTo->SetBaseRange( static_cast( ndata )); break; + case DFNTAG_HEALTHBONUS: applyTo->SetHealthBonus( static_cast( ndata )); break; + case DFNTAG_STAMINABONUS: applyTo->SetStaminaBonus( static_cast( ndata )); break; + case DFNTAG_MANABONUS: applyTo->SetManaBonus( static_cast( ndata )); break; case DFNTAG_CREATOR: applyTo->SetCreator( ndata ); break; case DFNTAG_COLOUR: applyTo->SetColour( static_cast( ndata )); break; case DFNTAG_COLOURLIST: applyTo->SetColour( AddRandomColor( cdata )); break; @@ -233,6 +236,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect case DFNTAG_DISPELLABLE: applyTo->SetDispellable( true ); break; case DFNTAG_DISABLED: applyTo->SetDisabled( ndata != 0 ); break; case DFNTAG_DOORFLAG: break; + case DFNTAG_DEFENSECHANCE: applyTo->SetDefenseChance( static_cast( ndata )); break; case DFNTAG_GOOD: applyTo->SetGood( static_cast( ndata )); break; case DFNTAG_GLOW: applyTo->SetGlow( ndata ); break; case DFNTAG_GLOWBC: applyTo->SetGlowColour( static_cast( ndata )); break; @@ -342,6 +346,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect } break; case DFNTAG_HIDAMAGE: applyTo->SetHiDamage( static_cast( ndata )); break; + case DFNTAG_HITCHANCE: applyTo->SetHitChance( static_cast( ndata )); break; case DFNTAG_HEAT: applyTo->SetWeatherDamage( HEAT, ndata != 0 ); break; case DFNTAG_ID: // applyTo->SetId( static_cast( ndata )); break; if( ssecs.size() == 1 ) diff --git a/source/npcs.cpp b/source/npcs.cpp index 36005b420..a749b95aa 100644 --- a/source/npcs.cpp +++ b/source/npcs.cpp @@ -1541,6 +1541,8 @@ auto CCharStuff::ApplyNpcSection( CChar *applyTo, CScriptSection *NpcCreation, s case DFNTAG_NAMELIST: SetRandomName( applyTo, cdata ); break; case DFNTAG_NECROMANCY: skillToSet = NECROMANCY; break; case DFNTAG_NINJITSU: skillToSet = NINJITSU; break; + case DFNTAG_HITCHANCE: applyTo->SetHitChance( static_cast( ndata )); break; + case DFNTAG_DEFENSECHANCE: applyTo->SetDefenseChance( static_cast( ndata )); break; case DFNTAG_NPCWANDER: if( !isGate ) { diff --git a/source/ssection.cpp b/source/ssection.cpp index 22713bbde..2c1285d37 100644 --- a/source/ssection.cpp +++ b/source/ssection.cpp @@ -67,6 +67,7 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_NUMERIC, // DFNTAG_DOORFLAG, DFN_NUMERIC, // DFNTAG_DYE, DFN_NUMERIC, // DFNTAG_DYEBEARD, + DFN_NUMERIC, // DFNTAG_DEFENSECHANCE, DFN_NUMERIC, // DFNTAG_DYEHAIR, DFN_STRING, // DFNTAG_ELEMENTRESIST, DFN_STRING, // DFNTAG_ERBONUS, @@ -112,6 +113,7 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_NUMERIC, // DFNTAG_HEAT, DFN_DOUBLENUMERIC, // DFNTAG_HERDING, DFN_NUMERIC, // DFNTAG_HIDAMAGE, + DFN_NUMERIC, // DFNTAG_HITCHANCE, DFN_DOUBLENUMERIC, // DFNTAG_HIDING, DFN_NODATA, // DFNTAG_HIRELING, DFN_DOUBLENUMERIC, // DFNTAG_HP, @@ -218,6 +220,9 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_STRING, // DFNTAG_SPAWNOBJ, DFN_STRING, // DFNTAG_SPAWNOBJLIST, DFN_NUMERIC, // DFNTAG_SPD, + DFN_NUMERIC, // DFNTAG_HEALTHBONUS, + DFN_NUMERIC, // DFNTAG_STAMINABONUS, + DFN_NUMERIC, // DFNTAG_MANABONUS, DFN_STRING, // DFNTAG_SPELLS, DFN_DOUBLENUMERIC, // DFNTAG_SPELLWEAVING, DFN_DOUBLENUMERIC, // DFNTAG_SPIRITSPEAK, @@ -288,6 +293,9 @@ const std::map strToDFNTag {"BLACKSMITHING"s, DFNTAG_BLACKSMITHING}, {"BOWCRAFT"s, DFNTAG_BOWCRAFT}, {"BUSHIDO"s, DFNTAG_BUSHIDO}, + {"HEALTHBONUS"s, DFNTAG_HEALTHBONUS}, + {"STAMINABONUS"s, DFNTAG_STAMINABONUS}, + {"MANABONUS"s, DFNTAG_MANABONUS}, {"CAMPING"s, DFNTAG_CAMPING}, {"CARPENTRY"s, DFNTAG_CARPENTRY}, {"CARTOGRAPHY"s, DFNTAG_CARTOGRAPHY}, @@ -326,6 +334,7 @@ const std::map strToDFNTag {"DYEABLE"s, DFNTAG_DYE}, {"DYEHAIR"s, DFNTAG_DYEHAIR}, {"DYEBEARD"s, DFNTAG_DYEBEARD}, + {"DEFENSECHANCE"s, DFNTAG_DEFENSECHANCE}, {"ELEMENTRESIST"s, DFNTAG_ELEMENTRESIST}, {"ERBONUS"s, DFNTAG_ERBONUS}, {"EMOTECOLOR"s, DFNTAG_EMOTECOLOUR}, @@ -371,6 +380,7 @@ const std::map strToDFNTag {"HEAT"s, DFNTAG_HEAT}, {"HERDING"s, DFNTAG_HERDING}, {"HIDAMAGE"s, DFNTAG_HIDAMAGE}, + {"HITCHANCE"s, DFNTAG_HITCHANCE}, {"HIDING"s, DFNTAG_HIDING}, {"HIRELING"s, DFNTAG_HIRELING}, {"HP"s, DFNTAG_HP}, diff --git a/source/ssection.h b/source/ssection.h index ab5bb27f8..dc5ab2f45 100644 --- a/source/ssection.h +++ b/source/ssection.h @@ -72,6 +72,7 @@ enum DFNTAGS DFNTAG_DISPELLABLE, DFNTAG_DISABLED, DFNTAG_DOORFLAG, + DFNTAG_DEFENSECHANCE, DFNTAG_DYE, DFNTAG_DYEBEARD, DFNTAG_DYEHAIR, @@ -119,6 +120,7 @@ enum DFNTAGS DFNTAG_HEAT, DFNTAG_HERDING, DFNTAG_HIDAMAGE, + DFNTAG_HITCHANCE, DFNTAG_HIDING, DFNTAG_HIRELING, DFNTAG_HP, @@ -225,6 +227,9 @@ enum DFNTAGS DFNTAG_SPAWNOBJ, DFNTAG_SPAWNOBJLIST, DFNTAG_SPD, + DFNTAG_HEALTHBONUS, + DFNTAG_STAMINABONUS, + DFNTAG_MANABONUS, DFNTAG_SPELLS, DFNTAG_SPELLWEAVING, DFNTAG_SPIRITSPEAK,