Fix #304 - quest sharing and delete restrictions, check DB sql for required updates
This commit is contained in:
parent
6f21dcd29d
commit
3ee4e5e105
11 changed files with 151 additions and 17 deletions
3
DB/updates/sharequest_feb_16_2023.sql
Normal file
3
DB/updates/sharequest_feb_16_2023.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
update commands set handler=533 where command='share_quest';
|
||||
alter table quests add column shareable_flag int(10) unsigned not null default 0;
|
||||
alter table quests add column deleteable tinyint(3) unsigned not null default 1;
|
|
@ -3127,11 +3127,12 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
if(quest_id > 0){
|
||||
if(lua_interface && client->GetPlayer()->player_quests.count(quest_id) > 0) {
|
||||
Quest* quest = client->GetPlayer()->player_quests[quest_id];
|
||||
if (quest)
|
||||
if (quest && quest->CanDeleteQuest()) {
|
||||
lua_interface->CallQuestFunction(quest, "Deleted", client->GetPlayer());
|
||||
client->RemovePlayerQuest(quest_id);
|
||||
client->GetCurrentZone()->SendQuestUpdates(client);
|
||||
}
|
||||
}
|
||||
client->RemovePlayerQuest(quest_id);
|
||||
client->GetCurrentZone()->SendQuestUpdates(client);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4752,7 +4753,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
client->Message(CHANNEL_COLOR_YELLOW, "Faction ID: %u, Merchant ID: %u, Transporter ID: %u", spawn->GetFactionID(), spawn->GetMerchantID(), spawn->GetTransporterID());
|
||||
client->Message(CHANNEL_COLOR_YELLOW, "Grid ID: %u", spawn->GetLocation());
|
||||
client->Message(CHANNEL_COLOR_YELLOW, "Race: %i, Class: %i, Gender: %i", spawn->GetRace(), spawn->GetAdventureClass(), spawn->GetGender());
|
||||
client->Message(CHANNEL_COLOR_YELLOW, "Level: %i, HP: %u, Power: %u", spawn->GetLevel(), spawn->GetHP(), spawn->GetPower());
|
||||
client->Message(CHANNEL_COLOR_YELLOW, "Level: %i, HP: %u / %u, Power: %u", spawn->GetLevel(), spawn->GetHP(), spawn->GetTotalHP(), spawn->GetPower());
|
||||
client->Message(CHANNEL_COLOR_YELLOW, "Respawn Time: %u (sec), X: %f, Y: %f, Z: %f Heading: %f", spawn->GetRespawnTime(), spawn->GetX(), spawn->GetY(), spawn->GetZ(), spawn->GetHeading());
|
||||
client->Message(CHANNEL_COLOR_YELLOW, "Collision Radius: %i, Size: %i, Difficulty: %i, Heroic: %i", spawn->GetCollisionRadius(), spawn->GetSize(), spawn->GetEncounterLevel(), spawn->GetHeroic());
|
||||
client->Message(CHANNEL_COLOR_YELLOW, "Targetable: %i, Show Name: %i, Attackable: %i, Show Level: %i", spawn->GetTargetable(), spawn->GetShowName(), spawn->GetAttackable(), spawn->GetShowLevel());
|
||||
|
@ -4790,7 +4791,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
details += "Class: " + to_string(spawn->GetAdventureClass()) + "\n";
|
||||
details += "Gender: " + to_string(spawn->GetGender()) + "\n";
|
||||
details += "Level: " + to_string(spawn->GetLevel()) + "\n";
|
||||
details += "HP: " + to_string(spawn->GetHP()) + "\n";
|
||||
details += "HP: " + to_string(spawn->GetHP()) + " / " + to_string(spawn->GetTotalHP()) + "\n";
|
||||
details += "Power: " + to_string(spawn->GetPower()) + "\n";
|
||||
details += "Difficulty: " + to_string(spawn->GetEncounterLevel()) + "\n";
|
||||
details += "Heroic: " + to_string(spawn->GetHeroic()) + "\n";
|
||||
|
@ -5712,6 +5713,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
}
|
||||
case COMMAND_CANCEL_EFFECT: { Command_CancelEffect(client, sep); break; }
|
||||
case COMMAND_CUREPLAYER: { Command_CurePlayer(client, sep); break; }
|
||||
case COMMAND_SHARE_QUEST: { Command_ShareQuest(client, sep); break; }
|
||||
default:
|
||||
{
|
||||
LogWrite(COMMAND__WARNING, 0, "Command", "Unhandled command: %s", command->command.data.c_str());
|
||||
|
@ -11934,3 +11936,36 @@ void Commands::Command_CurePlayer(Client* client, Seperator* sep)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Function: Command_ShareQuest()
|
||||
Purpose : Share quest with the group
|
||||
Example : /share_quest [quest_id]
|
||||
*/
|
||||
void Commands::Command_ShareQuest(Client* client, Seperator* sep)
|
||||
{
|
||||
Entity* target = nullptr;
|
||||
bool use_spells = true;
|
||||
bool use_potions = true;
|
||||
if (sep && sep->arg[0] && sep->IsNumber(0)) {
|
||||
int32 quest_id = atoul(sep->arg[0]);
|
||||
|
||||
Quest* playerQuest = client->GetPlayer()->GetQuest(quest_id);
|
||||
if(playerQuest) {
|
||||
Quest* quest = master_quest_list.GetQuest(playerQuest->GetQuestID(), false);
|
||||
if(quest) {
|
||||
GroupMemberInfo* gmi = client->GetPlayer()->GetGroupMemberInfo();
|
||||
if (gmi && gmi->group_id) {
|
||||
PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
|
||||
if (group) {
|
||||
group->ShareQuestWithGroup(client, quest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
client->SimpleMessage(CHANNEL_COLOR_RED, "Cannot find quest.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -447,6 +447,7 @@ public:
|
|||
|
||||
void Command_CancelEffect(Client* client, Seperator* sep);
|
||||
void Command_CurePlayer(Client* client, Seperator* sep);
|
||||
void Command_ShareQuest(Client* client, Seperator* sep);
|
||||
|
||||
// AA Commands
|
||||
void Get_AA_Xml(Client* client, Seperator* sep);
|
||||
|
@ -933,6 +934,7 @@ private:
|
|||
#define COMMAND_CUREPLAYER 531
|
||||
|
||||
#define COMMAND_RELOAD_VOICEOVERS 532
|
||||
#define COMMAND_SHARE_QUEST 533
|
||||
|
||||
|
||||
#define GET_AA_XML 750
|
||||
|
|
|
@ -4347,7 +4347,7 @@ PacketStruct* Player::GetQuestJournalPacket(bool all_quests, int16 version, int3
|
|||
packet->setArrayDataByName("name", quest->GetName(), i);
|
||||
packet->setArrayDataByName("quest_type", quest->GetType(), i);
|
||||
packet->setArrayDataByName("quest_zone", quest->GetZone(), i);
|
||||
int8 display_status = QUEST_DISPLAY_STATUS_NORMAL;
|
||||
int8 display_status = 0;
|
||||
if(itr->second->GetCompleted())
|
||||
packet->setArrayDataByName("completed", 1, i);
|
||||
if(itr->second->GetTurnedIn()){
|
||||
|
@ -4396,6 +4396,9 @@ PacketStruct* Player::GetQuestJournalPacket(bool all_quests, int16 version, int3
|
|||
|
||||
if (quest->IsHidden() && !quest->GetTurnedIn())
|
||||
display_status = QUEST_DISPLAY_STATUS_HIDDEN;
|
||||
else if(quest->CanShareQuestCriteria(GetClient(),false)) {
|
||||
display_status += QUEST_DISPLAY_STATUS_CAN_SHARE;
|
||||
}
|
||||
}
|
||||
else
|
||||
packet->setArrayDataByName("visible", quest->GetVisible(), i);
|
||||
|
@ -4443,7 +4446,7 @@ PacketStruct* Player::GetQuestJournalPacket(Quest* quest, int16 version, int32 c
|
|||
packet->setArrayDataByName("quest_type", quest->GetType());
|
||||
packet->setArrayDataByName("quest_zone", quest->GetZone());
|
||||
|
||||
int8 display_status = QUEST_DISPLAY_STATUS_NORMAL;
|
||||
int8 display_status = 0;
|
||||
if(quest->GetCompleted())
|
||||
packet->setArrayDataByName("completed", 1);
|
||||
if(quest->GetTurnedIn()) {
|
||||
|
@ -4489,12 +4492,15 @@ PacketStruct* Player::GetQuestJournalPacket(Quest* quest, int16 version, int32 c
|
|||
|
||||
if (quest->IsHidden() && !quest->GetTurnedIn())
|
||||
display_status = QUEST_DISPLAY_STATUS_HIDDEN;
|
||||
else if(quest->CanShareQuestCriteria(GetClient(),false)) {
|
||||
display_status += QUEST_DISPLAY_STATUS_CAN_SHARE;
|
||||
}
|
||||
}
|
||||
else
|
||||
packet->setArrayDataByName("visible", quest->GetVisible());
|
||||
if (quest->IsRepeatable())
|
||||
packet->setArrayDataByName("repeatable", 1);
|
||||
|
||||
|
||||
packet->setArrayDataByName("display_status", display_status);
|
||||
if (updated) {
|
||||
packet->setArrayDataByName("quest_updated", 1);
|
||||
|
|
|
@ -514,6 +514,7 @@ public:
|
|||
Quest* SetStepComplete(int32 quest_id, int32 step);
|
||||
Quest* AddStepProgress(int32 quest_id, int32 step, int32 progress);
|
||||
int32 GetStepProgress(int32 quest_id, int32 step_id);
|
||||
Quest* GetQuestByPositionID(int32 list_position_id);
|
||||
bool AddItem(Item* item, AddItemType type = AddItemType::NOT_SET);
|
||||
bool AddItemToBank(Item* item);
|
||||
int16 GetSpellSlotMappingCount();
|
||||
|
|
|
@ -193,6 +193,34 @@ bool PlayerGroup::MakeLeader(Entity* new_leader) {
|
|||
}
|
||||
|
||||
|
||||
bool PlayerGroup::ShareQuestWithGroup(Client* quest_sharer, Quest* quest) {
|
||||
if(!quest || !quest_sharer)
|
||||
return false;
|
||||
|
||||
bool canShare = quest->CanShareQuestCriteria(quest_sharer);
|
||||
|
||||
if(!canShare) {
|
||||
return false;
|
||||
}
|
||||
|
||||
deque<GroupMemberInfo*>::iterator itr;
|
||||
MGroupMembers.readlock(__FUNCTION__, __LINE__);
|
||||
for(itr = m_members.begin(); itr != m_members.end(); itr++) {
|
||||
GroupMemberInfo* info = *itr;
|
||||
if(info && info->client && info->client->GetCurrentZone()) {
|
||||
if( quest_sharer != info->client && info->client->GetPlayer()->GetCompletedQuest(quest->GetQuestID()) == 0 &&
|
||||
info->client->GetPlayer()->GetQuest(quest->GetQuestID()) == 0 ) {
|
||||
info->client->AddPendingQuest(new Quest(quest));
|
||||
info->client->Message(CHANNEL_COLOR_YELLOW, "%s has shared the quest %s with you.", quest_sharer->GetPlayer()->GetName(), quest->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************** PlayerGroupManager ********************************************************/
|
||||
|
||||
|
|
|
@ -96,7 +96,9 @@ public:
|
|||
void SimpleGroupMessage(const char* message);
|
||||
void GroupChatMessage(Spawn* from, int32 language, const char* message);
|
||||
bool MakeLeader(Entity* new_leader);
|
||||
|
||||
|
||||
bool ShareQuestWithGroup(Client* quest_sharer, Quest* quest);
|
||||
|
||||
void RemoveClientReference(Client* remove);
|
||||
void UpdateGroupMemberInfo(Entity* ent, bool groupMembersLocked=false);
|
||||
Entity* GetGroupMemberByPosition(Entity* seeker, int32 mapped_position);
|
||||
|
|
|
@ -315,6 +315,8 @@ Quest::Quest(int32 in_id){
|
|||
tmp_reward_coins = 0;
|
||||
completed_description = string("");
|
||||
quest_temporary_description = string("");
|
||||
quest_shareable_flag = 0;
|
||||
can_delete_quest = false;
|
||||
}
|
||||
|
||||
Quest::Quest(Quest* old_quest){
|
||||
|
@ -389,6 +391,8 @@ Quest::Quest(Quest* old_quest){
|
|||
tmp_reward_status = 0;
|
||||
tmp_reward_coins = 0;
|
||||
quest_temporary_description = string("");
|
||||
quest_shareable_flag = old_quest->GetQuestShareableFlag();
|
||||
can_delete_quest = old_quest->CanDeleteQuest();
|
||||
}
|
||||
|
||||
Quest::~Quest(){
|
||||
|
@ -978,12 +982,12 @@ EQ2Packet* Quest::QuestJournalReply(int16 version, int32 player_crc, Player* pla
|
|||
packet->setDataByName("unknown8b", 255);
|
||||
|
||||
if (version >= 1096) {
|
||||
packet->setDataByName("deletable", 1);
|
||||
packet->setDataByName("shareable", 1);
|
||||
packet->setDataByName("deletable", (int8)CanDeleteQuest());
|
||||
packet->setDataByName("shareable", (int8)CanShareQuestCriteria(player->GetClient(),false));
|
||||
}
|
||||
else {
|
||||
packet->setDataByName("unknown3", 1, 5);
|
||||
packet->setDataByName("unknown3", 1, 6);
|
||||
packet->setDataByName("unknown3", 1, 5); // this supposed to be CanDeleteQuest?
|
||||
packet->setDataByName("unknown3", 1, 6); // this supposed to be CanShareQuestCriteria?
|
||||
}
|
||||
|
||||
int8 map_data_count = 0;
|
||||
|
@ -1805,4 +1809,40 @@ void Quest::SetQuestTemporaryState(bool tempState, std::string customDescription
|
|||
|
||||
quest_state_temporary = tempState;
|
||||
quest_temporary_description = customDescription;
|
||||
}
|
||||
|
||||
bool Quest::CanShareQuestCriteria(Client* quest_sharer, bool display_client_msg) {
|
||||
Quest* clientQuest = quest_sharer->GetPlayer()->GetQuest(GetQuestID()); // gets active quest if available
|
||||
if(((GetQuestShareableFlag() & QUEST_SHAREABLE_COMPLETED) == 0) && quest_sharer->GetPlayer()->GetCompletedQuest(GetQuestID())) {
|
||||
if(display_client_msg)
|
||||
quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You cannot share this quest after it is already completed.");
|
||||
return false;
|
||||
}
|
||||
else if((GetQuestShareableFlag() == QUEST_SHAREABLE_COMPLETED) && !quest_sharer->GetPlayer()->GetCompletedQuest(GetQuestID())) {
|
||||
if(display_client_msg)
|
||||
quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You cannot share this quest until it is completed.");
|
||||
return false;
|
||||
}
|
||||
else if(((GetQuestShareableFlag() & QUEST_SHAREABLE_DURING) == 0) && clientQuest && clientQuest->GetQuestStep() > 1) {
|
||||
if(display_client_msg)
|
||||
quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You cannot share this quest after already completing a step.");
|
||||
return false;
|
||||
}
|
||||
else if(((GetQuestShareableFlag() & QUEST_SHAREABLE_ACTIVE) == 0) && clientQuest) {
|
||||
if(display_client_msg)
|
||||
quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You cannot share this quest while it is active.");
|
||||
return false;
|
||||
}
|
||||
else if(!GetQuestShareableFlag()) {
|
||||
if(display_client_msg)
|
||||
quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You cannot share this quest.");
|
||||
return false;
|
||||
}
|
||||
else if(((GetQuestShareableFlag() & QUEST_SHAREABLE_COMPLETED) == 0) && clientQuest == nullptr) {
|
||||
if(display_client_msg)
|
||||
quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You do not have this quest.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -39,13 +39,16 @@
|
|||
#define QUEST_DISPLAY_STATUS_YELLOW 2
|
||||
#define QUEST_DISPLAY_STATUS_COMPLETED 4
|
||||
#define QUEST_DISPLAY_STATUS_REPEATABLE 8
|
||||
#define QUEST_DISPLAY_STATUS_UNKNOWN1 16
|
||||
#define QUEST_DISPLAY_STATUS_CAN_SHARE 16
|
||||
#define QUEST_DISPLAY_STATUS_COMPLETE_FLAG 32
|
||||
#define QUEST_DISPLAY_STATUS_UNKNOWN2 64
|
||||
#define QUEST_DISPLAY_STATUS_CHECK 128
|
||||
|
||||
// Almost all quests have these values, but they don't see to effect anything
|
||||
#define QUEST_DISPLAY_STATUS_NORMAL QUEST_DISPLAY_STATUS_UNKNOWN1 + QUEST_DISPLAY_STATUS_UNKNOWN2
|
||||
|
||||
#define QUEST_SHAREABLE_NONE 0
|
||||
#define QUEST_SHAREABLE_ACTIVE 1
|
||||
#define QUEST_SHAREABLE_DURING 2
|
||||
#define QUEST_SHAREABLE_COMPLETED 4
|
||||
|
||||
struct QuestFactionPrereq{
|
||||
int32 faction_id;
|
||||
|
@ -317,6 +320,14 @@ public:
|
|||
void SetQuestTemporaryState(bool tempState, std::string customDescription = string(""));
|
||||
bool GetQuestTemporaryState() { return quest_state_temporary; }
|
||||
std::string GetQuestTemporaryDescription() { return quest_temporary_description; }
|
||||
|
||||
void SetQuestShareableFlag(int32 flag) { quest_shareable_flag = flag; }
|
||||
void SetCanDeleteQuest(bool newval) { can_delete_quest = newval; }
|
||||
|
||||
int32 GetQuestShareableFlag() { return quest_shareable_flag; }
|
||||
bool CanDeleteQuest() { return can_delete_quest; }
|
||||
|
||||
bool CanShareQuestCriteria(Client* quest_sharer, bool display_client_msg = true);
|
||||
protected:
|
||||
bool needs_save;
|
||||
Mutex MQuestSteps;
|
||||
|
@ -397,6 +408,8 @@ protected:
|
|||
|
||||
bool quest_state_temporary;
|
||||
std::string quest_temporary_description;
|
||||
int32 quest_shareable_flag;
|
||||
bool can_delete_quest;
|
||||
};
|
||||
|
||||
class MasterQuestList{
|
||||
|
|
|
@ -5018,7 +5018,8 @@ void WorldDatabase::FixBugReport(){
|
|||
int32 WorldDatabase::LoadQuests(){
|
||||
Query query;
|
||||
MYSQL_ROW row;
|
||||
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `quest_id`, `name`, `type`, `zone`, `level`, `enc_level`, `description`, `lua_script`, `completed_text`, `spawn_id` FROM `quests`");
|
||||
std::string querystr = std::string("SELECT `quest_id`, `name`, `type`, `zone`, `level`, `enc_level`, `description`, `lua_script`, `completed_text`, `spawn_id`, `shareable_flag`, `deleteable` FROM `quests`");
|
||||
MYSQL_RES* result = query.RunQuery2(Q_SELECT, querystr.c_str());
|
||||
Quest* quest = 0;
|
||||
char* name = 0;
|
||||
char* type = 0;
|
||||
|
@ -5063,6 +5064,8 @@ int32 WorldDatabase::LoadQuests(){
|
|||
quest->SetCompletedDescription(string(compDescription));
|
||||
quest->SetQuestReturnNPC(return_npc_id);
|
||||
quest->SetEncounterLevel(enc_level);
|
||||
quest->SetQuestShareableFlag(atoul(row[10]));
|
||||
quest->SetCanDeleteQuest(atoul(row[11]));
|
||||
total++;
|
||||
master_quest_list.AddQuest(id, quest);
|
||||
}
|
||||
|
|
|
@ -10521,6 +10521,7 @@ bool Client::HandleNewLogin(int32 account_id, int32 access_code)
|
|||
delayTimer.Disable();
|
||||
|
||||
firstlogin = zar->isFirstLogin();
|
||||
SetReadyForSpawns(false);
|
||||
ready_for_updates = false;
|
||||
LogWrite(ZONE__INFO, 0, "ZoneAuth", "Access Key: %u, Character Name: %s, Account ID: %u, Client Data Version: %u", zar->GetAccessKey(), zar->GetCharacterName(), zar->GetAccountID(), version);
|
||||
if (database.loadCharacter(zar->GetCharacterName(), zar->GetAccountID(), this)) {
|
||||
|
|
Loading…
Reference in a new issue