diff --git a/changelog.txt b/changelog.txt index de7572176..c7421fc97 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,10 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 09/02/2014 == +Secrets: Identified OP_GuildPromote for RoF clients. +Secrets: Fixed promotion, demotion, transferring a leader and displaying of client ranks in the Rain of Fear client. The rain of fear client, as such, will only have 3 ranks like the other clients, but supports a theoretical 8 ranks later. +Secrets/Akkadius: Fixed an issue involving character name lookup in the new DB code. + == 08/31/2014 == KLS: Fixed a bug in fishing in S3D zones KLS: Fixed a bug in turnins with new any abstraction diff --git a/common/database.cpp b/common/database.cpp index b99eac2ea..d1845b82e 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -771,7 +771,9 @@ void Database::GetCharName(uint32 char_id, char* name) { } auto row = results.begin(); - strcpy(name, row[0]); + for (auto row = results.begin(); row != results.end(); ++row) { + strcpy(name, row[0]); + } } bool Database::LoadVariables() { diff --git a/common/emu_oplist.h b/common/emu_oplist.h index edee551a1..c1ceb3c80 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -540,3 +540,4 @@ N(OP_OpenInventory), N(OP_OpenContainer), N(OP_Marquee), N(OP_ClientTimeStamp), +N(OP_GuildPromote), diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index d2fbcbb76..027039122 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -4461,6 +4461,14 @@ struct GuildBankPromote_Struct /*12*/ uint32 Slot2; // Always appears to be the same as Slot for Action code 3 }; +struct GuildPromoteStruct { +/*000*/ char target[64]; +/*064*/ char name[64]; +/*128*/ uint32 rank; +/*132*/ uint32 myrank; +/*136*/ +}; + struct GuildBankPermissions_Struct { /*00*/ uint32 Action; // 6 diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index 61dc201be..8cb67e0e0 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -534,7 +534,7 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req) uint16 opcode = (*OpMgr)->EmuToEQ(pack->emu_opcode); - _log(NET__APP_TRACE, "Queueing %sacked packet with opcode 0x%x (%s) and length %d", ack_req?"":"non-", opcode, OpcodeManager::EmuToName(pack->emu_opcode), pack->size); + //_log(NET__APP_TRACE, "Queueing %sacked packet with opcode 0x%x (%s) and length %d", ack_req?"":"non-", opcode, OpcodeManager::EmuToName(pack->emu_opcode), pack->size); if (!ack_req) { NonSequencedPush(new EQProtocolPacket(opcode, pack->pBuffer, pack->size)); diff --git a/common/guild_base.cpp b/common/guild_base.cpp index 8f6144270..6546918d0 100644 --- a/common/guild_base.cpp +++ b/common/guild_base.cpp @@ -474,6 +474,11 @@ bool BaseGuildManager::SetBankerFlag(uint32 charid, bool is_banker) { return(true); } +bool BaseGuildManager::ForceRankUpdate(uint32 charid) { + SendRankUpdate(charid); + return(true); +} + bool BaseGuildManager::SetAltFlag(uint32 charid, bool is_alt) { if(!DBSetAltFlag(charid, is_alt)) diff --git a/common/guild_base.h b/common/guild_base.h index 652db0bc8..b59244480 100644 --- a/common/guild_base.h +++ b/common/guild_base.h @@ -54,6 +54,7 @@ public: bool SetGuild(uint32 charid, uint32 guild_id, uint8 rank); bool SetGuildRank(uint32 charid, uint8 rank); bool SetBankerFlag(uint32 charid, bool is_banker); + bool ForceRankUpdate(uint32 charid); bool GetAltFlag(uint32 CharID); bool SetAltFlag(uint32 charid, bool is_alt); bool GetBankerFlag(uint32 CharID); diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 90ff9ab9e..3a83cef93 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -1,4 +1,3 @@ - #include "../debug.h" #include "rof.h" #include "../opcodemgr.h" @@ -1974,7 +1973,14 @@ ENCODE(OP_ZoneSpawns) else { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildID); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); + + /* Translate older ranks to new values */ + switch (emu->guildrank) { + case 0: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 5); break; } // GUILD_MEMBER 0 + case 1: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 3); break; } // GUILD_OFFICER 1 + case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2 + default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } // + } } VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->class_); @@ -2406,7 +2412,15 @@ ENCODE(OP_GuildMemberList) { PutFieldN(level); PutFieldN(banker); PutFieldN(class_); - PutFieldN(rank); + + /* Translate older ranks to new values */ + switch (emu_e->rank) { + case 0: { e->rank = htonl(5); break; } // GUILD_MEMBER 0 + case 1: { e->rank = htonl(3); break; } // GUILD_OFFICER 1 + case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2 + default: { e->rank = htonl(emu_e->rank); break; } // GUILD_NONE + } + PutFieldN(time_last_on); PutFieldN(tribute_enable); e->unknown01 = 0; @@ -3330,7 +3344,15 @@ ENCODE(OP_SetGuildRank) ENCODE_LENGTH_EXACT(GuildSetRank_Struct); SETUP_DIRECT_ENCODE(GuildSetRank_Struct, structs::GuildSetRank_Struct); eq->GuildID = emu->Unknown00; - OUT(Rank); + + /* Translate older ranks to new values */ + switch (emu->Rank) { + case 0: { eq->Rank = 5; break; } // GUILD_MEMBER 0 + case 1: { eq->Rank = 3; break; } // GUILD_OFFICER 1 + case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2 + default: { eq->Rank = emu->Rank; break; } + } + memcpy(eq->MemberName, emu->MemberName, sizeof(eq->MemberName)); OUT(Banker); eq->Unknown76 = 1; diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index c4e0b7955..50bfd5580 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -125,6 +125,7 @@ OP_GuildLeader=0x7c6f OP_GuildDelete=0x241b OP_GuildInviteAccept=0x78a5 OP_GuildDemote=0x3100 +OP_GuildPromote=0x2945 OP_GuildPublicNote=0x3c2c OP_GuildManageBanker=0x096d # Was 0x0737 OP_GuildBank=0x2ab0 # Was 0x10c3 diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index d56d8386a..37c58d743 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -190,6 +190,7 @@ void MapOpcodes() { ConnectedOpcodes[OP_GuildWar] = &Client::Handle_OP_GuildWar; ConnectedOpcodes[OP_GuildLeader] = &Client::Handle_OP_GuildLeader; ConnectedOpcodes[OP_GuildDemote] = &Client::Handle_OP_GuildDemote; + ConnectedOpcodes[OP_GuildPromote] = &Client::Handle_OP_GuildPromote; ConnectedOpcodes[OP_GuildInvite] = &Client::Handle_OP_GuildInvite; ConnectedOpcodes[OP_GuildRemove] = &Client::Handle_OP_GuildRemove; ConnectedOpcodes[OP_GetGuildMOTD] = &Client::Handle_OP_GetGuildMOTD; @@ -4088,7 +4089,7 @@ void Client::Handle_OP_GuildLeader(const EQApplicationPacket *app) GuildMakeLeader* gml=(GuildMakeLeader*)app->pBuffer; if (!IsInAGuild()) Message(0, "Error: You arent in a guild!"); - else if (!guild_mgr.IsGuildLeader(GuildID(), CharacterID())) + else if (GuildRank() != GUILD_LEADER) Message(0, "Error: You arent the guild leader!"); else if (!worldserver.Connected()) Message(0, "Error: World server disconnected"); @@ -4169,6 +4170,57 @@ void Client::Handle_OP_GuildDemote(const EQApplicationPacket *app) return; } + +void Client::Handle_OP_GuildPromote(const EQApplicationPacket *app) +{ + mlog(GUILDS__IN_PACKETS, "Received OP_GuildPromote"); + mpkt(GUILDS__IN_PACKET_TRACE, app); + + if(app->size != sizeof(GuildPromoteStruct)) { + mlog(GUILDS__ERROR, "Error: app size of %i != size of GuildDemoteStruct of %i\n",app->size,sizeof(GuildPromoteStruct)); + return; + } + + if (!IsInAGuild()) + Message(0, "Error: You arent in a guild!"); + else if (!guild_mgr.CheckPermission(GuildID(), GuildRank(), GUILD_PROMOTE)) + Message(0, "You dont have permission to invite."); + else if (!worldserver.Connected()) + Message(0, "Error: World server disconnected"); + else { + GuildPromoteStruct* promote = (GuildPromoteStruct*)app->pBuffer; + + CharGuildInfo gci; + if(!guild_mgr.GetCharInfo(promote->target, gci)) { + Message(0, "Unable to find '%s'", promote->target); + return; + } + if(gci.guild_id != GuildID()) { + Message(0, "You aren't in the same guild, what do you think you are doing?"); + return; + } + + uint8 rank = gci.rank + 1; + + if(rank > GUILD_OFFICER) + return; + + + mlog(GUILDS__ACTIONS, "Promoting %s (%d) from rank %s (%d) to %s (%d) in %s (%d)", + promote->target, gci.char_id, + guild_mgr.GetRankName(GuildID(), gci.rank), gci.rank, + guild_mgr.GetRankName(GuildID(), rank), rank, + guild_mgr.GetGuildName(GuildID()), GuildID()); + + if(!guild_mgr.SetGuildRank(gci.char_id, rank)) { + Message(13, "Error while setting rank %d on '%s'.", rank, promote->target); + return; + } + Message(0, "Successfully promoted %s to rank %d", promote->target, rank); + } + return; +} + void Client::Handle_OP_GuildInvite(const EQApplicationPacket *app) { mlog(GUILDS__IN_PACKETS, "Received OP_GuildInvite"); @@ -4379,6 +4431,16 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app) GuildInviteAccept_Struct* gj = (GuildInviteAccept_Struct*) app->pBuffer; + if(GetClientVersion() >= EQClientRoF) + { + if(gj->response > 9) + { + //dont care if the check fails (since we dont know the rank), just want to clear the entry. + guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, gj->response); + worldserver.SendEmoteMessage(gj->inviter, 0, 0, "%s has declined to join the guild.", this->GetName()); + return; + } + } if (gj->response == 5 || gj->response == 4) { //dont care if the check fails (since we dont know the rank), just want to clear the entry. guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, gj->response); @@ -4424,15 +4486,24 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app) guild_mgr.GetGuildName(gj->guildeqid), gj->guildeqid, gj->response); - //change guild and rank. - if(!guild_mgr.SetGuild(CharacterID(), gj->guildeqid, gj->response)) { + //change guild and rank + + uint32 guildrank = gj->response; + + if(GetClientVersion() == EQClientRoF) + { + if(gj->response == 8) + { + guildrank = 0; + } + } + + if(!guild_mgr.SetGuild(CharacterID(), gj->guildeqid, guildrank)) { Message(13, "There was an error during the invite, DB may now be inconsistent."); return; } if(zone->GetZoneID() == RuleI(World, GuildBankZoneID) && GuildBanks) GuildBanks->SendGuildBank(this); - SendGuildRanks(); - } } } @@ -9301,8 +9372,18 @@ void Client::CompleteConnect() { UpdateAdmin(false); if (IsInAGuild()){ + uint8 rank = GuildRank(); + if(GetClientVersion() >= EQClientRoF) + { + switch (rank) { + case 0: { rank = 5; break; } // GUILD_MEMBER 0 + case 1: { rank = 3; break; } // GUILD_OFFICER 1 + case 2: { rank = 1; break; } // GUILD_LEADER 2 + default: { break; } // GUILD_NONE + } + } SendAppearancePacket(AT_GuildID, GuildID(), false); - SendAppearancePacket(AT_GuildRank, GuildRank(), false); + SendAppearancePacket(AT_GuildRank, rank, false); } for (uint32 spellInt = 0; spellInt < MAX_PP_SPELLBOOK; spellInt++) { diff --git a/zone/client_packet.h b/zone/client_packet.h index 1b687edb9..424a8f78f 100644 --- a/zone/client_packet.h +++ b/zone/client_packet.h @@ -90,6 +90,7 @@ void Handle_OP_GuildWar(const EQApplicationPacket *app); void Handle_OP_GuildLeader(const EQApplicationPacket *app); void Handle_OP_GuildDemote(const EQApplicationPacket *app); + void Handle_OP_GuildPromote(const EQApplicationPacket *app); void Handle_OP_GuildInvite(const EQApplicationPacket *app); void Handle_OP_GuildRemove(const EQApplicationPacket *app); void Handle_OP_GetGuildMOTD(const EQApplicationPacket *app); diff --git a/zone/effects.cpp b/zone/effects.cpp index a24a6b39b..671d010ae 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -175,8 +175,8 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmt, spell_id); - if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); + if(itembonuses.SpellDmg) + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); return value; } @@ -245,29 +245,15 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { value -= extra_dmg; + if(itembonuses.SpellDmg) + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value) / 6; + return value; } int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg) { - int total_cast_time = 0; - - if (spells[spell_id].recast_time >= spells[spell_id].recovery_time) - total_cast_time = spells[spell_id].recast_time + spells[spell_id].cast_time; - else - total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time; - - if (total_cast_time > 0 && total_cast_time <= 2500) - extra_spell_amt = extra_spell_amt*25/100; - else if (total_cast_time > 2500 && total_cast_time < 7000) - extra_spell_amt = extra_spell_amt*(0.167*((total_cast_time - 1000)/1000)); - else - extra_spell_amt = extra_spell_amt * total_cast_time / 7000; - - if(extra_spell_amt*2 < base_spell_dmg) - return 0; - - return extra_spell_amt; + return extra_spell_amt; } diff --git a/zone/guild.cpp b/zone/guild.cpp index 92635c185..6512bedec 100644 --- a/zone/guild.cpp +++ b/zone/guild.cpp @@ -160,9 +160,17 @@ void Client::SendGuildSpawnAppearance() { uint8 rank = guild_mgr.GetDisplayedRank(GuildID(), GuildRank(), CharacterID()); mlog(GUILDS__OUT_PACKETS, "Sending spawn appearance for guild %d at rank %d", GuildID(), rank); SendAppearancePacket(AT_GuildID, GuildID()); + if(GetClientVersion() >= EQClientRoF) + { + switch (rank) { + case 0: { rank = 5; break; } // GUILD_MEMBER 0 + case 1: { rank = 3; break; } // GUILD_OFFICER 1 + case 2: { rank = 1; break; } // GUILD_LEADER 2 + default: { break; } // GUILD_NONE + } + } SendAppearancePacket(AT_GuildRank, rank); } - UpdateWho(); } diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index 37cc7a3de..19a8c5a61 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -374,6 +374,10 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { else if(c != nullptr && s->guild_id != GUILD_NONE) { //char is in zone, and has changed into a new guild, send MOTD. c->SendGuildMOTD(); + if(c->GetClientVersion() >= EQClientRoF) + { + c->SendGuildRanks(); + } }