2013-09-10 11:45:59 +02:00
/*
2020-01-02 06:44:10 +01:00
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
2013-09-10 11:45:59 +02:00
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2017-05-20 00:09:37 +02:00
#include "ScriptMgr.h"
2017-02-05 23:14:19 +01:00
#include "CharacterCache.h"
2013-09-10 11:45:59 +02:00
#include "Chat.h"
2017-05-18 23:52:58 +02:00
#include "DatabaseEnv.h"
2017-06-04 01:00:45 +02:00
#include "DB2Stores.h"
2017-05-18 23:52:58 +02:00
#include "GroupMgr.h"
2013-09-10 11:45:59 +02:00
#include "Language.h"
#include "LFG.h"
2017-06-04 01:00:45 +02:00
#include "Map.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
2013-09-10 11:45:59 +02:00
#include "ObjectMgr.h"
2018-01-28 11:37:20 +01:00
#include "PhasingHandler.h"
2017-05-18 23:52:58 +02:00
#include "Player.h"
2017-05-20 00:09:37 +02:00
#include "RBAC.h"
2017-06-04 01:00:45 +02:00
#include "WorldSession.h"
2013-09-10 11:45:59 +02:00
class group_commandscript : public CommandScript
{
public :
group_commandscript () : CommandScript ( "group_commandscript" ) { }
2015-10-22 20:26:56 +02:00
std :: vector < ChatCommand > GetCommands () const override
2013-09-10 11:45:59 +02:00
{
2017-06-12 17:01:47 +02:00
static std :: vector < ChatCommand > groupSetCommandTable =
{
{ "leader" , rbac :: RBAC_PERM_COMMAND_GROUP_LEADER , false , & HandleGroupLeaderCommand , "" },
{ "assistant" , rbac :: RBAC_PERM_COMMAND_GROUP_ASSISTANT , false , & HandleGroupAssistantCommand , "" },
{ "maintank" , rbac :: RBAC_PERM_COMMAND_GROUP_MAINTANK , false , & HandleGroupMainTankCommand , "" },
{ "mainassist" , rbac :: RBAC_PERM_COMMAND_GROUP_MAINASSIST , false , & HandleGroupMainAssistCommand , "" },
};
2015-10-22 20:26:56 +02:00
static std :: vector < ChatCommand > groupCommandTable =
2013-09-10 11:45:59 +02:00
{
2017-06-12 17:01:47 +02:00
{ "set" , rbac :: RBAC_PERM_COMMAND_GROUP_SET , false , nullptr , "" , groupSetCommandTable },
2015-10-22 20:26:56 +02:00
{ "leader" , rbac :: RBAC_PERM_COMMAND_GROUP_LEADER , false , & HandleGroupLeaderCommand , "" },
{ "disband" , rbac :: RBAC_PERM_COMMAND_GROUP_DISBAND , false , & HandleGroupDisbandCommand , "" },
{ "remove" , rbac :: RBAC_PERM_COMMAND_GROUP_REMOVE , false , & HandleGroupRemoveCommand , "" },
{ "join" , rbac :: RBAC_PERM_COMMAND_GROUP_JOIN , false , & HandleGroupJoinCommand , "" },
{ "list" , rbac :: RBAC_PERM_COMMAND_GROUP_LIST , false , & HandleGroupListCommand , "" },
{ "summon" , rbac :: RBAC_PERM_COMMAND_GROUP_SUMMON , false , & HandleGroupSummonCommand , "" },
2013-09-10 11:45:59 +02:00
};
2015-10-22 20:26:56 +02:00
static std :: vector < ChatCommand > commandTable =
2013-09-10 11:45:59 +02:00
{
2017-06-12 17:01:47 +02:00
{ "group" , rbac :: RBAC_PERM_COMMAND_GROUP , false , nullptr , "" , groupCommandTable },
2013-09-10 11:45:59 +02:00
};
return commandTable ;
}
// Summon group of player
static bool HandleGroupSummonCommand ( ChatHandler * handler , char const * args )
{
Player * target ;
if ( ! handler -> extractPlayerTarget (( char * ) args , & target ))
return false ;
// check online security
2014-09-14 16:54:21 +02:00
if ( handler -> HasLowerSecurity ( target , ObjectGuid :: Empty ))
2013-09-10 11:45:59 +02:00
return false ;
Group * group = target -> GetGroup ();
std :: string nameLink = handler -> GetNameLink ( target );
if ( ! group )
{
handler -> PSendSysMessage ( LANG_NOT_IN_GROUP , nameLink . c_str ());
return false ;
}
Player * gmPlayer = handler -> GetSession () -> GetPlayer ();
Map * gmMap = gmPlayer -> GetMap ();
bool toInstance = gmMap -> Instanceable ();
2017-06-12 13:08:07 +02:00
bool onlyLocalSummon = false ;
2013-09-10 11:45:59 +02:00
2017-06-12 13:08:07 +02:00
// make sure people end up on our instance of the map, disallow far summon if intended destination is different from actual destination
// note: we could probably relax this further by checking permanent saves and the like, but eh
// :close enough:
if ( toInstance )
2013-09-10 11:45:59 +02:00
{
2017-06-12 13:08:07 +02:00
Player * groupLeader = ObjectAccessor :: GetPlayer ( gmMap , group -> GetLeaderGUID ());
if ( ! groupLeader || ( groupLeader -> GetMapId () != gmMap -> GetId ()) || ( groupLeader -> GetInstanceId () != gmMap -> GetInstanceId ()))
{
handler -> SendSysMessage ( LANG_PARTIAL_GROUP_SUMMON );
onlyLocalSummon = true ;
}
2013-09-10 11:45:59 +02:00
}
2017-06-12 13:08:07 +02:00
for ( GroupReference * itr = group -> GetFirstMember (); itr != nullptr ; itr = itr -> next ())
2013-09-10 11:45:59 +02:00
{
Player * player = itr -> GetSource ();
if ( ! player || player == gmPlayer || ! player -> GetSession ())
continue ;
// check online security
2014-09-14 16:54:21 +02:00
if ( handler -> HasLowerSecurity ( player , ObjectGuid :: Empty ))
2017-06-12 13:08:07 +02:00
continue ;
2013-09-10 11:45:59 +02:00
std :: string plNameLink = handler -> GetNameLink ( player );
if ( player -> IsBeingTeleported ())
{
handler -> PSendSysMessage ( LANG_IS_TELEPORTED , plNameLink . c_str ());
2017-06-12 13:08:07 +02:00
continue ;
2013-09-10 11:45:59 +02:00
}
if ( toInstance )
{
Map * playerMap = player -> GetMap ();
2017-06-12 13:08:07 +02:00
if (
( onlyLocalSummon || ( playerMap -> Instanceable () && playerMap -> GetId () == gmMap -> GetId ())) && // either no far summon allowed or we're in the same map as player (no map switch)
(( playerMap -> GetId () != gmMap -> GetId ()) || ( playerMap -> GetInstanceId () != gmMap -> GetInstanceId ())) // so we need to be in the same map and instance of the map, otherwise skip
)
2013-09-10 11:45:59 +02:00
{
// cannot summon from instance to instance
2017-06-12 13:08:07 +02:00
handler -> PSendSysMessage ( LANG_CANNOT_SUMMON_INST_INST , plNameLink . c_str ());
continue ;
2013-09-10 11:45:59 +02:00
}
}
handler -> PSendSysMessage ( LANG_SUMMONING , plNameLink . c_str (), "" );
if ( handler -> needReportToTarget ( player ))
ChatHandler ( player -> GetSession ()). PSendSysMessage ( LANG_SUMMONED_BY , handler -> GetNameLink (). c_str ());
// stop flight if need
if ( player -> IsInFlight ())
{
player -> GetMotionMaster () -> MovementExpired ();
player -> CleanupAfterTaxiFlight ();
}
// save only in non-flight case
else
player -> SaveRecallPosition ();
// before GM
float x , y , z ;
2017-03-23 00:43:04 +01:00
gmPlayer -> GetClosePoint ( x , y , z , player -> GetCombatReach ());
2013-09-10 11:45:59 +02:00
player -> TeleportTo ( gmPlayer -> GetMapId (), x , y , z , player -> GetOrientation ());
}
return true ;
}
static bool HandleGroupLeaderCommand ( ChatHandler * handler , char const * args )
{
2017-06-12 17:01:47 +02:00
Player * player = nullptr ;
Group * group = nullptr ;
2014-09-14 16:54:21 +02:00
ObjectGuid guid ;
2013-09-10 11:45:59 +02:00
char * nameStr = strtok (( char * ) args , " " );
if ( ! handler -> GetPlayerGroupAndGUIDByName ( nameStr , player , group , guid ))
return false ;
if ( ! group )
{
handler -> PSendSysMessage ( LANG_GROUP_NOT_IN_GROUP , player -> GetName (). c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
if ( group -> GetLeaderGUID () != guid )
{
group -> ChangeLeader ( guid );
group -> SendUpdate ();
}
return true ;
}
2017-06-12 17:01:47 +02:00
static bool GroupFlagCommand ( ChatHandler * handler , char const * args , GroupMemberFlags flag , const char * what )
{
Player * player = nullptr ;
Group * group = nullptr ;
ObjectGuid guid ;
char * nameStr = strtok (( char * ) args , " " );
if ( ! handler -> GetPlayerGroupAndGUIDByName ( nameStr , player , group , guid ))
return false ;
if ( ! group )
{
handler -> PSendSysMessage ( LANG_GROUP_NOT_IN_GROUP , player -> GetName (). c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
if ( ! group -> isRaidGroup ())
{
handler -> PSendSysMessage ( LANG_GROUP_NOT_IN_RAID_GROUP , player -> GetName (). c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
if ( flag == MEMBER_FLAG_ASSISTANT && group -> IsLeader ( guid ))
{
handler -> PSendSysMessage ( LANG_LEADER_CANNOT_BE_ASSISTANT , player -> GetName (). c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
if ( group -> GetMemberFlags ( guid ) & flag )
{
group -> SetGroupMemberFlag ( guid , false , flag );
handler -> PSendSysMessage ( LANG_GROUP_ROLE_CHANGED , player -> GetName (). c_str (), "no longer" , what );
}
else
{
group -> SetGroupMemberFlag ( guid , true , flag );
handler -> PSendSysMessage ( LANG_GROUP_ROLE_CHANGED , player -> GetName (). c_str (), "now" , what );
}
return true ;
}
static bool HandleGroupAssistantCommand ( ChatHandler * handler , char const * args )
{
return GroupFlagCommand ( handler , args , MEMBER_FLAG_ASSISTANT , "Assistant" );
}
static bool HandleGroupMainTankCommand ( ChatHandler * handler , char const * args )
{
return GroupFlagCommand ( handler , args , MEMBER_FLAG_MAINTANK , "Main Tank" );
}
static bool HandleGroupMainAssistCommand ( ChatHandler * handler , char const * args )
{
return GroupFlagCommand ( handler , args , MEMBER_FLAG_MAINASSIST , "Main Assist" );
}
2013-09-10 11:45:59 +02:00
static bool HandleGroupDisbandCommand ( ChatHandler * handler , char const * args )
{
2017-06-12 17:01:47 +02:00
Player * player = nullptr ;
Group * group = nullptr ;
2014-09-14 16:54:21 +02:00
ObjectGuid guid ;
2013-09-10 11:45:59 +02:00
char * nameStr = strtok (( char * ) args , " " );
if ( ! handler -> GetPlayerGroupAndGUIDByName ( nameStr , player , group , guid ))
return false ;
if ( ! group )
{
handler -> PSendSysMessage ( LANG_GROUP_NOT_IN_GROUP , player -> GetName (). c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
group -> Disband ();
return true ;
}
static bool HandleGroupRemoveCommand ( ChatHandler * handler , char const * args )
{
2017-06-12 17:01:47 +02:00
Player * player = nullptr ;
Group * group = nullptr ;
2014-09-14 16:54:21 +02:00
ObjectGuid guid ;
2013-09-10 11:45:59 +02:00
char * nameStr = strtok (( char * ) args , " " );
if ( ! handler -> GetPlayerGroupAndGUIDByName ( nameStr , player , group , guid ))
return false ;
if ( ! group )
{
handler -> PSendSysMessage ( LANG_GROUP_NOT_IN_GROUP , player -> GetName (). c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
group -> RemoveMember ( guid );
return true ;
}
static bool HandleGroupJoinCommand ( ChatHandler * handler , char const * args )
{
if ( !* args )
return false ;
2017-06-12 17:01:47 +02:00
Player * playerSource = nullptr ;
Player * playerTarget = nullptr ;
Group * groupSource = nullptr ;
Group * groupTarget = nullptr ;
2014-09-14 16:54:21 +02:00
ObjectGuid guidSource ;
ObjectGuid guidTarget ;
2013-09-10 11:45:59 +02:00
char * nameplgrStr = strtok (( char * ) args , " " );
char * nameplStr = strtok ( NULL , " " );
if ( ! handler -> GetPlayerGroupAndGUIDByName ( nameplgrStr , playerSource , groupSource , guidSource , true ))
return false ;
if ( ! groupSource )
{
handler -> PSendSysMessage ( LANG_GROUP_NOT_IN_GROUP , playerSource -> GetName (). c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
if ( ! handler -> GetPlayerGroupAndGUIDByName ( nameplStr , playerTarget , groupTarget , guidTarget , true ))
return false ;
if ( groupTarget || playerTarget -> GetGroup () == groupSource )
{
handler -> PSendSysMessage ( LANG_GROUP_ALREADY_IN_GROUP , playerTarget -> GetName (). c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
2014-08-31 23:43:36 -03:00
if ( groupSource -> IsFull ())
2013-09-10 11:45:59 +02:00
{
handler -> PSendSysMessage ( LANG_GROUP_FULL );
handler -> SetSentErrorMessage ( true );
return false ;
}
groupSource -> AddMember ( playerTarget );
groupSource -> BroadcastGroupUpdate ();
handler -> PSendSysMessage ( LANG_GROUP_PLAYER_JOINED , playerTarget -> GetName (). c_str (), playerSource -> GetName (). c_str ());
return true ;
}
static bool HandleGroupListCommand ( ChatHandler * handler , char const * args )
{
2013-10-15 23:13:49 +02:00
// Get ALL the variables!
2013-09-10 11:45:59 +02:00
Player * playerTarget ;
2014-09-14 16:14:12 +02:00
ObjectGuid guidTarget ;
2013-09-10 11:45:59 +02:00
std :: string nameTarget ;
2013-10-15 23:13:49 +02:00
std :: string zoneName ;
const char * onlineState = "" ;
2013-09-10 11:45:59 +02:00
2013-10-15 23:13:49 +02:00
// Parse the guid to uint32...
2014-10-29 21:13:21 +01:00
ObjectGuid parseGUID = ObjectGuid :: Create < HighGuid :: Player > ( strtoull ( args , nullptr , 10 ));
2013-09-10 11:45:59 +02:00
2013-10-15 23:13:49 +02:00
// ... and try to extract a player out of it.
2017-02-05 23:14:19 +01:00
if ( sCharacterCache -> GetCharacterNameByGuid ( parseGUID , nameTarget ))
2013-09-10 11:45:59 +02:00
{
2014-09-14 16:14:12 +02:00
playerTarget = ObjectAccessor :: FindPlayer ( parseGUID );
2013-09-10 11:45:59 +02:00
guidTarget = parseGUID ;
}
2013-10-15 23:13:49 +02:00
// If not, we return false and end right away.
2013-09-10 11:45:59 +02:00
else if ( ! handler -> extractPlayerTarget (( char * ) args , & playerTarget , & guidTarget , & nameTarget ))
return false ;
2013-10-15 23:13:49 +02:00
// Next, we need a group. So we define a group variable.
2017-06-12 17:01:47 +02:00
Group * groupTarget = nullptr ;
2013-10-15 23:13:49 +02:00
// We try to extract a group from an online player.
2013-09-10 11:45:59 +02:00
if ( playerTarget )
groupTarget = playerTarget -> GetGroup ();
2013-10-15 23:13:49 +02:00
// If not, we extract it from the SQL.
2013-09-10 11:45:59 +02:00
if ( ! groupTarget )
{
2019-07-27 01:00:37 +02:00
CharacterDatabasePreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_GROUP_MEMBER );
2014-10-25 15:04:38 +02:00
stmt -> setUInt64 ( 0 , guidTarget . GetCounter ());
2013-09-10 11:45:59 +02:00
PreparedQueryResult resultGroup = CharacterDatabase . Query ( stmt );
if ( resultGroup )
groupTarget = sGroupMgr -> GetGroupByDbStoreId (( * resultGroup )[ 0 ]. GetUInt32 ());
}
2013-10-15 23:13:49 +02:00
// If both fails, players simply has no party. Return false.
2013-09-10 11:45:59 +02:00
if ( ! groupTarget )
{
handler -> PSendSysMessage ( LANG_GROUP_NOT_IN_GROUP , nameTarget . c_str ());
handler -> SetSentErrorMessage ( true );
return false ;
}
2013-10-15 23:13:49 +02:00
// We get the group members after successfully detecting a group.
2013-09-10 11:45:59 +02:00
Group :: MemberSlotList const & members = groupTarget -> GetMemberSlots ();
2013-10-15 23:13:49 +02:00
// To avoid a cluster fuck, namely trying multiple queries to simply get a group member count...
2017-07-22 10:22:17 +03:00
handler -> PSendSysMessage ( LANG_GROUP_TYPE , ( groupTarget -> isRaidGroup () ? "raid" : "party" ), std :: to_string ( members . size ()). c_str ());
2013-10-15 23:13:49 +02:00
// ... we simply move the group type and member count print after retrieving the slots and simply output it's size.
// While rather dirty codestyle-wise, it saves space (if only a little). For each member, we look several informations up.
2013-09-10 11:45:59 +02:00
for ( Group :: MemberSlotList :: const_iterator itr = members . begin (); itr != members . end (); ++ itr )
{
2013-10-15 23:13:49 +02:00
// Define temporary variable slot to iterator.
2013-09-10 11:45:59 +02:00
Group :: MemberSlot const & slot = * itr ;
2013-10-15 23:13:49 +02:00
// Check for given flag and assign it to that iterator
2013-09-10 11:45:59 +02:00
std :: string flags ;
if ( slot . flags & MEMBER_FLAG_ASSISTANT )
flags = "Assistant" ;
if ( slot . flags & MEMBER_FLAG_MAINTANK )
{
if ( ! flags . empty ())
flags . append ( ", " );
flags . append ( "MainTank" );
}
if ( slot . flags & MEMBER_FLAG_MAINASSIST )
{
if ( ! flags . empty ())
flags . append ( ", " );
flags . append ( "MainAssist" );
}
if ( flags . empty ())
flags = "None" ;
2013-10-15 23:13:49 +02:00
// Check if iterator is online. If is...
2013-09-10 11:45:59 +02:00
Player * p = ObjectAccessor :: FindPlayer (( * itr ). guid );
2018-01-10 22:01:40 +01:00
std :: string phases ;
2014-10-16 22:47:02 +02:00
if ( p )
2013-10-15 23:13:49 +02:00
{
// ... than, it prints information like "is online", where he is, etc...
onlineState = "online" ;
2018-01-28 11:37:20 +01:00
phases = PhasingHandler :: FormatPhases ( p -> GetPhaseShift ());
2013-10-15 23:13:49 +02:00
2016-02-02 19:13:04 +01:00
AreaTableEntry const * area = sAreaTableStore . LookupEntry ( p -> GetAreaId ());
2013-10-15 23:13:49 +02:00
if ( area )
{
2016-02-02 19:13:04 +01:00
AreaTableEntry const * zone = sAreaTableStore . LookupEntry ( area -> ParentAreaID );
2013-10-15 23:13:49 +02:00
if ( zone )
2020-06-27 13:33:17 +02:00
zoneName = zone -> AreaName [ handler -> GetSessionDbcLocale ()];
2013-10-15 23:13:49 +02:00
}
}
else
{
// ... else, everything is set to offline or neutral values.
zoneName = "<ERROR>" ;
onlineState = "Offline" ;
}
2013-09-10 11:45:59 +02:00
2013-10-15 23:13:49 +02:00
// Now we can print those informations for every single member of each group!
2013-09-10 11:45:59 +02:00
handler -> PSendSysMessage ( LANG_GROUP_PLAYER_NAME_GUID , slot . name . c_str (), onlineState ,
2018-01-10 22:01:40 +01:00
zoneName . c_str (), phases . c_str (), slot . guid . ToString (). c_str (), flags . c_str (),
2013-10-15 23:13:49 +02:00
lfg :: GetRolesString ( slot . roles ). c_str ());
2013-09-10 11:45:59 +02:00
}
2013-10-15 23:13:49 +02:00
// And finish after every iterator is done.
2013-09-10 11:45:59 +02:00
return true ;
}
};
void AddSC_group_commandscript ()
{
new group_commandscript ();
}