mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
341 lines
10 KiB
C++
341 lines
10 KiB
C++
#include "PartySystem.h"
|
|
#include "uox3.h"
|
|
#include "network.h"
|
|
#include "CPacketSend.h"
|
|
#include <mutex>
|
|
// PartyEntry code goes here
|
|
const size_t BIT_LEADER = 0;
|
|
const size_t BIT_LOOTABLE = 1;
|
|
|
|
CChar * PartyEntry::Member( void ) const { return member; }
|
|
bool PartyEntry::IsLeader( void ) const { return settings.test( BIT_LEADER ); }
|
|
bool PartyEntry::IsLootable( void ) const { return settings.test( BIT_LOOTABLE ); }
|
|
void PartyEntry::Member( CChar *valid ) { member = valid; }
|
|
void PartyEntry::IsLeader( bool value ) { settings.set( BIT_LEADER, true ); }
|
|
void PartyEntry::IsLootable( bool value ) { settings.set( BIT_LOOTABLE, true ); }
|
|
PartyEntry::PartyEntry() : member( NULL ) { settings.reset(); }
|
|
PartyEntry::PartyEntry( CChar *m, bool isLeader, bool isLootable ) : member( m )
|
|
{
|
|
settings.set( BIT_LEADER, isLeader );
|
|
settings.set( BIT_LOOTABLE, isLootable );
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - bool AddMember( CChar *i )
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Add new member to party
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
bool Party::AddMember( CChar *i )
|
|
{
|
|
bool retVal = false;
|
|
if( ValidateObject( i ) )
|
|
{
|
|
if( !HasMember( i ) )
|
|
{
|
|
PartyEntry *toAdd = new PartyEntry( i );
|
|
PartyFactory::getSingleton().AddLookup( this, i );
|
|
members.push_back( toAdd );
|
|
SendList( NULL );
|
|
retVal = true;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - PartyEntry *Find( CChar *i, SI32 *location )
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Check if character is a member of party
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
PartyEntry *Party::Find( CChar *i, SI32 *location )
|
|
{
|
|
if( ValidateObject( i ) )
|
|
{
|
|
for( size_t j = 0; j < members.size(); ++j )
|
|
{
|
|
PartyEntry *toFind = members[j];
|
|
if( toFind->Member() == i )
|
|
{
|
|
if( location != NULL )
|
|
(*location) = j;
|
|
return toFind;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
bool Party::HasMember( CChar *find )
|
|
{
|
|
return ( Find( find ) != NULL );
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - bool RemoveMember( CChar *i )
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Remove a character from the party
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
bool Party::RemoveMember( CChar *i )
|
|
{
|
|
bool retVal = false;
|
|
if( ValidateObject( i ) )
|
|
{
|
|
SI32 removeSpot;
|
|
PartyEntry *toFind = Find( i, &removeSpot );
|
|
if( toFind != NULL )
|
|
{
|
|
delete members[removeSpot];
|
|
members.erase( members.begin() + removeSpot );
|
|
PartyFactory::getSingleton().RemoveLookup( i );
|
|
|
|
CPPartyMemberRemove toSend( i );
|
|
for( size_t j = 0; j < members.size(); ++j )
|
|
{
|
|
PartyEntry *toFind = members[j];
|
|
toSend.AddMember( toFind->Member() );
|
|
}
|
|
|
|
SendPacket( &toSend, NULL );
|
|
if( i->GetSocket() != NULL )
|
|
SendPacket( &toSend, i->GetSocket() );
|
|
retVal = true;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void Leader( CChar *member )
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Set a party member as party leader
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void Party::Leader( CChar *member )
|
|
{
|
|
SI32 newLeaderPos;
|
|
PartyEntry *newLeader = Find( member, &newLeaderPos );
|
|
if( newLeader != NULL )
|
|
{
|
|
if( leader != NULL )
|
|
{
|
|
SI32 oldLeaderPos;
|
|
PartyEntry *mFind = Find( leader, &oldLeaderPos );
|
|
if( mFind != NULL )
|
|
{
|
|
mFind->IsLeader( false );
|
|
// We need to swap their position in the array, because the first cab
|
|
// off the rank is the leader, and the client makes assumptions about
|
|
// this
|
|
members[oldLeaderPos] = newLeader;
|
|
members[newLeaderPos] = mFind;
|
|
}
|
|
}
|
|
leader = newLeader->Member();
|
|
newLeader->IsLeader( true );
|
|
}
|
|
}
|
|
CChar *Party::Leader( void ) { return leader; }
|
|
Party::Party( bool npc ) : leader( NULL ), isNPC( npc ) { }
|
|
Party::Party( CChar *ldr, bool npc ) : leader( NULL ), isNPC( npc )
|
|
{
|
|
if( ValidateObject( ldr ) )
|
|
{
|
|
AddMember( ldr );
|
|
Leader( ldr );
|
|
}
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void SendPacket( CPUOXBuffer *toSend, CSocket *toSendTo )
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Send list of party members to client
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void Party::SendPacket( CPUOXBuffer *toSend, CSocket *toSendTo )
|
|
{
|
|
if( toSendTo != NULL )
|
|
toSendTo->Send( toSend );
|
|
else
|
|
{
|
|
for( size_t k = 0; k < members.size(); ++k )
|
|
{
|
|
PartyEntry *toFind = members[k];
|
|
CSocket *tSock = toFind->Member()->GetSocket();
|
|
if( tSock != NULL )
|
|
tSock->Send( toSend );
|
|
}
|
|
}
|
|
}
|
|
void Party::SendList( CSocket *toSendTo )
|
|
{
|
|
CPPartyMemberList toSend;
|
|
for( size_t j = 0; j < members.size(); ++j )
|
|
{
|
|
PartyEntry *toFind = members[j];
|
|
toSend.AddMember( toFind->Member() );
|
|
}
|
|
SendPacket( &toSend, toSendTo );
|
|
}
|
|
bool Party::IsNPC( void ) const
|
|
{
|
|
return isNPC;
|
|
}
|
|
void Party::IsNPC( bool value )
|
|
{
|
|
isNPC = value;
|
|
}
|
|
|
|
/** This class is responsible for the creation and destruction of parties
|
|
*/
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
PartyFactory& PartyFactory::getSingleton( void )
|
|
{
|
|
std::mutex lock;
|
|
std::scoped_lock scope(lock) ;
|
|
static PartyFactory instance ;
|
|
return instance ;
|
|
}
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
void PartyFactory::AddLookup( Party *toQuickLook, CChar *toSave )
|
|
{
|
|
if( ValidateObject( toSave ) )
|
|
partyQuickLook[toSave->GetSerial()] = toQuickLook;
|
|
}
|
|
void PartyFactory::RemoveLookup( CChar *toRemove )
|
|
{
|
|
if( ValidateObject( toRemove ) )
|
|
{
|
|
std::map< SERIAL, Party * >::iterator toFind = partyQuickLook.find( toRemove->GetSerial() );
|
|
if( toFind != partyQuickLook.end() )
|
|
partyQuickLook.erase( toFind );
|
|
}
|
|
}
|
|
PartyFactory::PartyFactory()
|
|
{
|
|
partyQuickLook.clear();
|
|
}
|
|
PartyFactory::~PartyFactory()
|
|
{
|
|
for( Party *obj = parties.First(); !parties.Finished(); obj = parties.Next() )
|
|
{
|
|
delete obj;
|
|
obj = NULL;
|
|
}
|
|
}
|
|
Party *PartyFactory::Create( CChar *leader )
|
|
{
|
|
Party *toAdd = NULL;
|
|
if( ValidateObject( leader ) )
|
|
{
|
|
toAdd = new Party( leader );
|
|
parties.Add( toAdd );
|
|
}
|
|
return toAdd;
|
|
}
|
|
void PartyFactory::Destroy( CChar *member )
|
|
{
|
|
Party *toRemove = Get( member );
|
|
Destroy( toRemove );
|
|
}
|
|
void PartyFactory::Destroy( Party *toRemove )
|
|
{
|
|
if( toRemove != NULL )
|
|
{
|
|
std::vector< PartyEntry * > *mList = toRemove->MemberList();
|
|
if( mList != NULL )
|
|
{
|
|
for( size_t j = 0; j < mList->size(); ++j )
|
|
{
|
|
PartyEntry *mEntry = (*mList)[j];
|
|
RemoveLookup( mEntry->Member() );
|
|
}
|
|
}
|
|
parties.Remove( toRemove );
|
|
delete toRemove;
|
|
}
|
|
}
|
|
Party *PartyFactory::Get( CChar *member )
|
|
{
|
|
if( ValidateObject( member ) )
|
|
{
|
|
std::map< SERIAL, Party * >::iterator toFind = partyQuickLook.find( member->GetSerial() );
|
|
if( toFind != partyQuickLook.end() )
|
|
return toFind->second;
|
|
else
|
|
return NULL;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void CreateInvite( CSocket *inviter )
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Invite a player to the party
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void PartyFactory::CreateInvite( CSocket *inviter )
|
|
{
|
|
SERIAL serial = inviter->GetDWord( 7 );
|
|
CChar *toInvite = calcCharObjFromSer( serial );
|
|
if( !ValidateObject( toInvite ) || toInvite->IsNpc() )
|
|
{
|
|
inviter->sysmessage( "You cannot invite an npc or unknown player" );
|
|
return;
|
|
}
|
|
CChar *inviterChar = inviter->CurrcharObj();
|
|
if( ValidateObject( inviterChar ) && inviterChar == toInvite )
|
|
{
|
|
inviter->sysmessage( "You cannot invite yourself to a party" );
|
|
return;
|
|
}
|
|
Party *ourParty = Get( inviterChar );
|
|
if( ourParty == NULL )
|
|
{
|
|
//Party *tParty = Create( inviterChar );
|
|
Create( inviterChar);
|
|
}
|
|
CSocket *targSock = toInvite->GetSocket();
|
|
if( targSock != NULL )
|
|
{
|
|
CPPartyInvitation toSend;
|
|
toSend.Leader( inviterChar );
|
|
targSock->Send( &toSend );
|
|
targSock->sysmessage( "You have been invited to join a party, type /accept or /decline to deal with the invitation" );
|
|
}
|
|
else
|
|
{
|
|
inviter->sysmessage( "That player is not online" );
|
|
}
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void Kick( CSocket *inviter )
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Kick a member from the party
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void PartyFactory::Kick( CSocket *inviter )
|
|
{
|
|
SERIAL serial = inviter->GetDWord( 7 );
|
|
CChar *toRemove = calcCharObjFromSer( serial );
|
|
if( !ValidateObject( toRemove ) || toRemove->IsNpc() )
|
|
{
|
|
inviter->sysmessage( "You cannot kick an npc or unknown player" );
|
|
return;
|
|
}
|
|
Party *ourParty = Get( inviter->CurrcharObj() );
|
|
if( ourParty == NULL )
|
|
{
|
|
inviter->sysmessage( "You are not in a party and cannot kick them out" );
|
|
return;
|
|
}
|
|
if( ( ourParty->Leader() != inviter->CurrcharObj() ) && ( inviter->CurrcharObj() != toRemove ) )
|
|
{
|
|
inviter->sysmessage( "Only the leader can kick someone out" );
|
|
return;
|
|
}
|
|
if( ourParty->HasMember( toRemove ) )
|
|
{ // even if they're offline, we can kick them out
|
|
ourParty->RemoveMember( toRemove );
|
|
inviter->sysmessage( "The player has been removed" );
|
|
}
|
|
}
|
|
|