diff --git a/source/CPacketSend.cpp b/source/CPacketSend.cpp index 448966e33..b5ce6865a 100644 --- a/source/CPacketSend.cpp +++ b/source/CPacketSend.cpp @@ -7467,6 +7467,13 @@ void CPToolTip::CopyItemData( CItem& cItem, size_t &totalStringLen, bool addAmou FinalizeData( tempEntry, totalStringLen ); } + if( cItem.GetDurabilityHpBonus() > 0) + { + tempEntry.stringNum = 1151780; // durability +~1_VAL~% + tempEntry.ourText = oldstrutil::number( cItem.GetDurabilityHpBonus() ); + FinalizeData( tempEntry, totalStringLen ); + } + if( cItem.GetType() == IT_MAGICWAND && cItem.GetTempVar( CITV_MOREZ )) { tempEntry.stringNum = 1060584; // uses remaining: ~1_val~ diff --git a/source/Changelog.txt b/source/Changelog.txt index cb849397d..24707c1a3 100644 --- a/source/Changelog.txt +++ b/source/Changelog.txt @@ -113,6 +113,11 @@ 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/Xuri/Maarc + Added Support for new AOS property tag. + -DURABILITYHPBONUS = # - Add durability (aka Health) at percentage multiplier to hp. + .durabilityhpbonus (js) + 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 diff --git a/source/UOXJSPropertyEnums.h b/source/UOXJSPropertyEnums.h index 6e848e018..ff4b20da9 100644 --- a/source/UOXJSPropertyEnums.h +++ b/source/UOXJSPropertyEnums.h @@ -470,6 +470,7 @@ enum CI_Properties CIP_DEFENSECHANCE, CIP_ARTIFACTRARITY, + CIP_DURABILITYHPBONUS, CIP_NAME2, CIP_ISITEM, CIP_ISCHAR, diff --git a/source/UOXJSPropertyFuncs.cpp b/source/UOXJSPropertyFuncs.cpp index c0d23aa20..007a58bb7 100644 --- a/source/UOXJSPropertyFuncs.cpp +++ b/source/UOXJSPropertyFuncs.cpp @@ -677,6 +677,7 @@ JSBool CItemProps_getProperty( JSContext *cx, JSObject *obj, jsval id, jsval *vp case CIP_DAMAGESNOW: *vp = BOOLEAN_TO_JSVAL( gPriv->GetWeatherDamage( SNOW )); break; case CIP_SWINGSPEEDINCREASE: *vp = INT_TO_JSVAL( gPriv->GetSwingSpeedIncrease() ); break; case CIP_SPEED: *vp = INT_TO_JSVAL( gPriv->GetSpeed() ); break; + case CIP_DURABILITYHPBONUS: *vp = INT_TO_JSVAL( gPriv->GetDurabilityHpBonus() ); break; case CIP_LOWERSTATREQ: *vp = INT_TO_JSVAL( gPriv->GetLowerStatReq() ); break; case CIP_HEALTHLEECH: *vp = INT_TO_JSVAL( gPriv->GetHealthLeech() ); break; case CIP_STAMINALEECH: *vp = INT_TO_JSVAL( gPriv->GetStaminaLeech() ); break; @@ -1344,7 +1345,7 @@ JSBool CItemProps_setProperty( JSContext *cx, JSObject *obj, jsval id, jsval *vp 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_DURABILITYHPBONUS: gPriv->SetDurabilityHpBonus( 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; diff --git a/source/UOXJSPropertySpecs.h b/source/UOXJSPropertySpecs.h index eeb2dab04..560cdd83c 100644 --- a/source/UOXJSPropertySpecs.h +++ b/source/UOXJSPropertySpecs.h @@ -554,6 +554,8 @@ inline JSPropertySpec CItemProps[] = { "manaBonus", CIP_MANABONUS, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "artifactRarity", CIP_ARTIFACTRARITY, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "durabilityHpBonus", CIP_DURABILITYHPBONUS, 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/cItem.cpp b/source/cItem.cpp index b668ef29e..116f09aed 100644 --- a/source/cItem.cpp +++ b/source/cItem.cpp @@ -94,8 +94,12 @@ const UI16 DEFITEM_REGIONNUM = 255; const UI16 DEFITEM_TEMPLASTTRADED = 0; const SI08 DEFITEM_STEALABLE = 1; const SI16 DEFITEM_ARTIFACTRARITY = 0; + +const SI16 DEFITEM_DURABLITITYHPBONUS = 0; + const SI16 DEFITEM_LOWERSTATREQ = 0; + //o------------------------------------------------------------------------------------------------o //| Function - CItem() //o------------------------------------------------------------------------------------------------o @@ -109,7 +113,7 @@ spd( DEFITEM_SPEED ), maxHp( DEFITEM_MAXHP ), amount( DEFITEM_AMOUNT ), layer( DEFITEM_LAYER ), type( DEFITEM_TYPE ), offspell( DEFITEM_OFFSPELL ), entryMadeFrom( DEFITEM_ENTRYMADEFROM ), creator( DEFITEM_CREATOR ), gridLoc( DEFITEM_GRIDLOC ), weightMax( DEFITEM_WEIGHTMAX ), baseWeight( DEFITEM_BASEWEIGHT ), maxItems( DEFITEM_MAXITEMS ), maxRange( DEFITEM_MAXRANGE ), baseRange( DEFITEM_BASERANGE ), maxUses( DEFITEM_MAXUSES ), usesLeft( DEFITEM_USESLEFT ), regionNum( DEFITEM_REGIONNUM ), -tempLastTraded( DEFITEM_TEMPLASTTRADED ), stealable( DEFITEM_STEALABLE ), artifactRarity( DEFITEM_ARTIFACTRARITY ), lowerStatReq( DEFITEM_LOWERSTATREQ ) +tempLastTraded( DEFITEM_TEMPLASTTRADED ), stealable( DEFITEM_STEALABLE ), artifactRarity( DEFITEM_ARTIFACTRARITY ), lowerStatReq( DEFITEM_LOWERSTATREQ ), durabilityHpBonus( DEFITEM_DURABLITITYHPBONUS ) { spells[0] = spells[1] = spells[2] = 0; value[0] = value[1] = value[2] = 0; @@ -1392,6 +1396,23 @@ auto CItem::SetBaseWeight( SI32 newValue ) -> void UpdateRegion(); } +//o------------------------------------------------------------------------------------------------o +//| Function - CItem::GetDurabilityHpBonus() +//| CItem::SetDurabilityHpBonus() +//| Date - 5 May, 2024 +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Bonus hp on the object +//o------------------------------------------------------------------------------------------------o +SI16 CItem::GetDurabilityHpBonus(void) const +{ + return durabilityHpBonus; +} +void CItem::SetDurabilityHpBonus(SI16 newValue) +{ + durabilityHpBonus = newValue; + UpdateRegion(); +} + //o------------------------------------------------------------------------------------------------o //| Function - CItem::GetMaxItems() //| CItem::SetMaxItems() @@ -1677,6 +1698,8 @@ auto CItem::CopyData( CItem *target ) -> void target->SetArtifactRarity( GetArtifactRarity() ); + target->SetDurabilityHpBonus( GetDurabilityHpBonus() ); + target->SetSpell( 0, GetSpell( 0 )); target->SetSpell( 1, GetSpell( 1 )); target->SetSpell( 2, GetSpell( 2 )); @@ -1787,6 +1810,7 @@ bool CItem::DumpBody( std::ostream &outStream ) const 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 << "DurabilityHpBonus=" + std::to_string( GetDurabilityHpBonus() ) + newLine; outStream << "Movable=" + std::to_string( GetMovable() ) + newLine; outStream << "Priv=" + std::to_string( GetPriv() ) + newLine; outStream << "LowerStatReq=" + std::to_string( GetLowerStatReq() ) + newLine; @@ -1918,6 +1942,11 @@ bool CItem::HandleLine( std::string &UTag, std::string &data ) SetDir( static_cast( std::stoi(oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); rValue = true; } + else if( UTag == "DURABILITYHPBONUS" ) + { + SetDurabilityHpBonus( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } else if( UTag == "DYEABLE" ) { SetDye( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 ); diff --git a/source/cItem.h b/source/cItem.h index 62c7cb13a..c6fcd62d1 100644 --- a/source/cItem.h +++ b/source/cItem.h @@ -49,7 +49,11 @@ class CItem : public CBaseObject SERIAL creator; // Store the serial of the player made this item SI08 gridLoc; SI16 artifactRarity; + + SI16 durabilityHpBonus; + SI16 lowerStatReq; + SI32 weightMax; // Maximum weight a container can hold SI32 baseWeight; // Base weight of item. Applied when item is created for the first time, based on weight. Primarily used to determine base weight of containers UI16 maxItems; // Maximum amount of items a container can hold @@ -112,8 +116,11 @@ class CItem : public CBaseObject auto GetGridLocation() const -> SI08; auto SetGridLocation( SI08 newLoc ) -> void; - virtual SI16 GetArtifactRarity(void) const; - virtual void SetArtifactRarity(SI16 newValue); + SI16 GetArtifactRarity(void) const; + void SetArtifactRarity(SI16 newValue); + + SI16 GetDurabilityHpBonus(void) const; + void SetDurabilityHpBonus(SI16 newValue); SI16 GetLowerStatReq( void ) const; void SetLowerStatReq( SI16 newValue ); diff --git a/source/items.cpp b/source/items.cpp index 5951c4a36..fb35bb107 100644 --- a/source/items.cpp +++ b/source/items.cpp @@ -118,6 +118,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect Console.Warning( oldstrutil::format( "Invalid data found in AMOUNT tag inside item script [%s]", sectionId.c_str() )); } break; + case DFNTAG_DURABILITYHPBONUS: applyTo->SetDurabilityHpBonus( static_cast( ndata )); break; case DFNTAG_DAMAGE: case DFNTAG_ATT: if( ndata >= 0 ) @@ -1204,10 +1205,34 @@ CItem * cItem::CreateBaseScriptItem( CItem *mCont, std::string ourItem, const UI Console.Error( "Trying to apply an item section failed" ); } + // If the durabilityhpbonus tag is on the item, it will add to its Durability (aka Health). + auto durabilityHpBonus = iCreated->GetDurabilityHpBonus(); + // If maxHP has not been defined for a new item, set it to the same value as HP - if( !iCreated->GetMaxHP() && iCreated->GetHP() ) + if (!iCreated->GetMaxHP() && iCreated->GetHP()) { - iCreated->SetMaxHP( iCreated->GetHP() ); + iCreated->SetMaxHP(iCreated->GetHP()); + } + + if( durabilityHpBonus > 0 ) + { + // Calculate percentage increase + auto baseHP = iCreated->GetHP(); + auto baseMaxHP = iCreated->GetMaxHP(); + + // If maxHP has not been defined, default it to HP + if( baseMaxHP == 0 && baseHP > 0 ) + { + baseMaxHP = baseHP; + iCreated->SetMaxHP( baseMaxHP ); + } + + // Apply the percentage bonus to HP and MaxHP + auto hpBonus = static_cast( baseHP * ( durabilityHpBonus / 100.0 )); + auto maxHpBonus = static_cast( baseMaxHP * ( durabilityHpBonus / 100.0 )); + + iCreated->SetHP( baseHP + hpBonus ); + iCreated->SetMaxHP( baseMaxHP + maxHpBonus ); } // If maxUses is higher than usesLeft for a new item, randomize the amount of usesLeft the item should have! diff --git a/source/ssection.cpp b/source/ssection.cpp index 6d89e606f..c9875f8d0 100644 --- a/source/ssection.cpp +++ b/source/ssection.cpp @@ -65,6 +65,7 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_NODATA, // DFNTAG_DISPELLABLE, DFN_NUMERIC, // DFNTAG_DISABLED, DFN_NUMERIC, // DFNTAG_DOORFLAG, + DFN_NUMERIC, // DFNTAG_DURABILITYHPBONUS, DFN_NUMERIC, // DFNTAG_DYE, DFN_NUMERIC, // DFNTAG_DYEBEARD, DFN_NUMERIC, // DFNTAG_DEFENSECHANCE, @@ -332,6 +333,7 @@ const std::map strToDFNTag {"DISPELLABLE"s, DFNTAG_DISPELLABLE}, {"DISABLED"s, DFNTAG_DISABLED}, {"DOORFLAG"s, DFNTAG_DOORFLAG}, + {"DURABILITYHPBONUS"s, DFNTAG_DURABILITYHPBONUS}, {"DYE"s, DFNTAG_DYE}, {"DYEABLE"s, DFNTAG_DYE}, {"DYEHAIR"s, DFNTAG_DYEHAIR}, diff --git a/source/ssection.h b/source/ssection.h index 0c5bcfbbc..2cca1a2e8 100644 --- a/source/ssection.h +++ b/source/ssection.h @@ -60,6 +60,7 @@ enum DFNTAGS DFNTAG_CREATOR, DFNTAG_CUSTOMSTRINGTAG, DFNTAG_CUSTOMINTTAG, + DFNTAG_DURABILITYHPBONUS, DFNTAG_DAMAGE, DFNTAG_DAMAGEABLE, DFNTAG_DECAY,