mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
Cleaned up an issue with last commit where wrong npclists were used in some spawn regions Made a few additional adjustments to the new spawn regions in Lost Lands/New Haven Included more changes related to poison updates that should've been in previous commit (like the complete UOX.INI support for POISONCORROSIONSYSTEM setting) Adjusted region setup for New Haven to set the individual "building" regions within as a sub-region of the main town (regions.dfn) Fixed an issue where the displayed HP of an equipped item would not update correctly Further updates to convert timers 32-bit to 64-bit. This affects and addresses some potential issues with: Character creation/NPC guild-join timestamps, NPC movement, combat timers, idle timeouts, item decay, spellcasting Added support for new JS Events that can trigger from global script, and can be used to store persistent custom entries in players' paperdoll profiles: onProfileRequest( socket, profileOwnerChar ) - Triggers when client requests data for a paperdoll profile onProfileUpdate( socket, updatedText ) - Triggers when client sends updated data from paperdoll profile Added two new helper functions in code that allows faster (but very slightly less accurate) distance checks between two points: GetApproxDist( Point3_st a, Point3_st b ) GetApproxDist( CBaseObject *a, CBaseObject *b ) Improved pathfinding for NPCs attempting to follow another character, by adopting a system of weighted variables to help the NPC determine when to recalculate the path vs when to stick with the old, combined with faster distance checks via GetApproxDist(). The end result of this is faster, smarter and more responsive NPC followers and NPC opponents in combat. The variables influencing this include: how far the target has moved from last pathfind target location, whether NPC is heading in the overall right direction or not, time since last path calculation and some small randomization to avoid edge case jitters. Updated default command levels in commands.dfn, code and scripts to support the Seer role and make space for some custom roles. These are the new defaults as listed in commands.dfn, which should not be changed as they are linked to specific enums in code. Do take note that this might invalidate command levels for existing GMs/Seers/Counselors, who might need another round of 'make gm/seer/cns from an admin: ADMIN - command level 10 GM - command level 9 SEER - command level 7 CNS - command level 4 PLAYER - command level 0 Updated how UOX3 makes use of the account-level flags 0x2000 (Seer) and 0x4000 (Counselor). If either of these flags are set on an account, all new characters created on the accounts will automatically receive the relevant command privileges. Fixed an issue with 'wholist command that prevented admin characters from seeing characters with lower privilege levels in the list (js/commands/wholist.js) Fixed an issue with hiding/GM hide that prevented admin characters from seeing hidden characters with lower privilege levels in the world UOX3 now includes the cross-platform, header-only utf8cpp library found at https://github.com/nemtrif/utfcpp and freely available under Boost Software License v1.0. The immediate use-case for this is in code right now is to better handle strings related to custom paperdoll profiles, but will also look to make more heavy use of this in future updates
254 lines
No EOL
8.8 KiB
C++
254 lines
No EOL
8.8 KiB
C++
// All funcs in this file are used for item/char distance related situations
|
|
// There's a chance that a number of these could become inline
|
|
#include "uox3.h"
|
|
#include "cRaces.h"
|
|
#include "regions.h"
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CheckItemRange()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Checks if an item is within reach
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CheckItemRange( CChar *mChar, CItem *i )
|
|
{
|
|
if( mChar->IsGM() || mChar->IsCounselor() )
|
|
return true;
|
|
|
|
CBaseObject *itemOwner = i;
|
|
bool checkRange = false;
|
|
|
|
if( i->GetCont() != nullptr ) // It's inside another container, we need root container to calculate distance
|
|
{
|
|
ObjectType objType = OT_CBO;
|
|
CBaseObject *iOwner = FindItemOwner( i, objType );
|
|
if( iOwner != nullptr )
|
|
{
|
|
itemOwner = iOwner;
|
|
}
|
|
}
|
|
if( itemOwner == mChar )
|
|
{
|
|
checkRange = true;
|
|
}
|
|
else
|
|
{
|
|
if( ValidateObject( itemOwner ))
|
|
{
|
|
if( mChar->GetInstanceId() != itemOwner->GetInstanceId() || mChar->WorldNumber() != itemOwner->WorldNumber() )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if( mChar->GetInstanceId() != i->GetInstanceId() || mChar->WorldNumber() != i->WorldNumber() )
|
|
return false;
|
|
}
|
|
|
|
checkRange = ObjInRange( mChar, itemOwner, DIST_NEARBY );
|
|
}
|
|
|
|
return checkRange;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - ObjInRange()
|
|
//| Date - 2/12/2003
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Check if BaseObject obj is within a certain distance
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool ObjInRange( CSocket *mSock, CBaseObject *obj, UI16 distance )
|
|
{
|
|
CChar *mChar = mSock->CurrcharObj();
|
|
return ObjInRange( mChar, obj, distance );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - ObjInRange()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Check if an object is within a certain distance of another object
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool ObjInRange( CBaseObject *a, CBaseObject *b, UI16 distance )
|
|
{
|
|
return ( GetDist( a, b ) <= distance );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - ObjInRangeSquare()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Check if an object's location is within a certain distance of another
|
|
//| object, but checking using a square instead of a radius
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool ObjInRangeSquare( CBaseObject *a, CBaseObject *b, UI16 distance )
|
|
{
|
|
if( !ValidateObject( a ) || !ValidateObject( b ))
|
|
return false;
|
|
|
|
if( a == b )
|
|
return true;
|
|
|
|
if( a->WorldNumber() != b->WorldNumber() || a->GetInstanceId() != b->GetInstanceId() )
|
|
return false;
|
|
|
|
auto aX = a->GetX();
|
|
auto aY = a->GetY();
|
|
auto bX = b->GetX();
|
|
auto bY = b->GetY();
|
|
return ( aX >= ( bX - distance ) && aX <= ( bX + distance )
|
|
&& aY >= ( bY - distance ) && aY <= ( bY + distance ));
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - ObjInOldRange()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Check if an object is within a certain distance of another object
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool ObjInOldRange( CBaseObject *a, CBaseObject *b, UI16 distance )
|
|
{
|
|
return ( GetOldDist( a, b ) <= distance );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - ObjInOldRangeSquare()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Check if an object's old location is within a certain distance of another
|
|
//| object, but checking using a square instead of a radius
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool ObjInOldRangeSquare( CBaseObject *a, CBaseObject *b, UI16 distance )
|
|
{
|
|
if( !ValidateObject( a ) || !ValidateObject( b ))
|
|
return false;
|
|
|
|
if( a == b )
|
|
return true;
|
|
|
|
if( a->WorldNumber() != b->WorldNumber() || a->GetInstanceId() != b->GetInstanceId() )
|
|
return false;
|
|
|
|
Point3_st aOldLoc = a->GetOldLocation();
|
|
auto aX = aOldLoc.x;
|
|
auto aY = aOldLoc.y;
|
|
auto bX = b->GetX();
|
|
auto bY = b->GetY();
|
|
return ( aX >= ( bX - distance ) && aX <= ( bX + distance )
|
|
&& aY >= ( bY - distance ) && aY <= ( bY + distance ));
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CharInRange()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Check if characters a and b are in visual range
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CharInRange( CChar *a, CChar *b )
|
|
{
|
|
if( !ValidateObject( a ))
|
|
return false;
|
|
|
|
SI16 visRange = MAX_VISRANGE;
|
|
if( a->GetSocket() != nullptr )
|
|
{
|
|
visRange = a->GetSocket()->Range() + Races->VisRange( a->GetRace() );
|
|
}
|
|
else
|
|
{
|
|
visRange += Races->VisRange( a->GetRace() );
|
|
}
|
|
return ObjInRangeSquare( a, b, static_cast<UI16>( visRange ));
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - GetDist()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Get the distance between two objects
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI16 GetDist( CBaseObject *a, CBaseObject *b )
|
|
{
|
|
if( !ValidateObject( a ) || !ValidateObject( b ))
|
|
return DIST_OUTOFRANGE;
|
|
|
|
if( a == b )
|
|
return DIST_SAMETILE;
|
|
|
|
if( a->WorldNumber() != b->WorldNumber() || a->GetInstanceId() != b->GetInstanceId() )
|
|
return DIST_OUTOFRANGE;
|
|
|
|
return GetDist( a->GetLocation(), b->GetLocation() );
|
|
}
|
|
|
|
UI16 GetDist( Point3_st a, Point3_st b )
|
|
{
|
|
Point3_st difference = a - b;
|
|
return static_cast<UI16>( difference.Mag() );
|
|
}
|
|
|
|
UI16 GetDist3D( Point3_st a, Point3_st b )
|
|
{
|
|
Point3_st difference = a - b;
|
|
return static_cast<UI16>( difference.Mag3D() );
|
|
}
|
|
|
|
UI16 GetOldDist( CBaseObject *a, CBaseObject *b )
|
|
{
|
|
if( !ValidateObject( a ) || !ValidateObject( b ))
|
|
return DIST_OUTOFRANGE;
|
|
|
|
if( a == b )
|
|
return DIST_SAMETILE;
|
|
|
|
if( a->WorldNumber() != b->WorldNumber() || a->GetInstanceId() != b->GetInstanceId() )
|
|
return DIST_OUTOFRANGE;
|
|
|
|
Point3_st distA;
|
|
Point3_st distB;
|
|
distA = a->GetOldLocation();
|
|
distB = b->GetLocation();
|
|
Point3_st difference = distA - distB;
|
|
return static_cast<UI16>( difference.Mag() );
|
|
}
|
|
|
|
UI16 GetDist3D( CBaseObject *a, CBaseObject *b )
|
|
{
|
|
if( !ValidateObject( a ) || !ValidateObject( b ))
|
|
return DIST_OUTOFRANGE;
|
|
|
|
if( a == b )
|
|
return DIST_SAMETILE;
|
|
|
|
if( a->WorldNumber() != b->WorldNumber() || a->GetInstanceId() != b->GetInstanceId() )
|
|
return DIST_OUTOFRANGE;
|
|
|
|
Point3_st difference = a->GetLocation() - b->GetLocation();
|
|
return static_cast<UI16>( difference.Mag3D() );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - GetApproxDist()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Calculates the shortest grid-path distance (Octile) between
|
|
//| - two points. Much faster than GetDist() as it avoids sqrt()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
R32 GetApproxDist( Point3_st a, Point3_st b )
|
|
{
|
|
const R32 dx = fabs( a.x - b.x );
|
|
const R32 dy = fabs( a.y - b.y );
|
|
|
|
// The constant 0.414f (sqrt(2) - 1) is chosen to approximate the cost of diagonal movement.
|
|
return ( dx > dy ) ? ( dx + 0.414f * dy ) : ( dy + 0.414f * dx );
|
|
}
|
|
|
|
R32 GetApproxDist( CBaseObject *a, CBaseObject *b )
|
|
{
|
|
if( !ValidateObject( a ) || !ValidateObject( b ))
|
|
return static_cast<R32>( DIST_OUTOFRANGE );
|
|
|
|
if( a == b )
|
|
return static_cast<R32>( DIST_SAMETILE );
|
|
|
|
if( a->WorldNumber() != b->WorldNumber() || a->GetInstanceId() != b->GetInstanceId() )
|
|
return static_cast<R32>( DIST_OUTOFRANGE );
|
|
|
|
|
|
const R32 dx = fabs( a->GetX() - b->GetX() );
|
|
const R32 dy = fabs( a->GetY() - b->GetY() );
|
|
|
|
// The constant 0.414f (sqrt(2) - 1) is chosen to approximate the cost of diagonal movement.
|
|
return ( dx > dy ) ? ( dx + 0.414f * dy ) : ( dy + 0.414f * dx );
|
|
} |