diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index bffd5163ae..906de62b06 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -6758,6 +6758,7 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto ObjectGuid victim_guid; uint32 victim_rank = 0; + uint32 rank_diff = 0; // need call before fields update to have chance move yesterday data to appropriate fields before today data change. UpdateHonorFields(); @@ -6795,6 +6796,30 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto // [29..38] Other title and player name // [39+] Nothing uint32 victim_title = victim->GetUInt32Value(PLAYER_CHOSEN_TITLE); + + // PLAYER__FIELD_KNOWN_TITLES describe which titles player can use, + // so we must find biggest pvp title , even for killer to find extra honor value + uint32 vtitle = victim->GetUInt32Value(PLAYER__FIELD_KNOWN_TITLES); + //uint32 victim_title = 0; + uint32 ktitle = GetUInt32Value(PLAYER__FIELD_KNOWN_TITLES); + uint32 killer_title = 0; + if (PLAYER_TITLE_MASK_ALL_PVP & ktitle) + { + for (int i = ((GetTeam() == ALLIANCE) ? 1:HKRANKMAX);i!=((GetTeam() == ALLIANCE) ? HKRANKMAX : (2*HKRANKMAX-1));i++) + { + if (ktitle & (1<GetTeam() == ALLIANCE) ? 1:HKRANKMAX);i!=((plrVictim->GetTeam() == ALLIANCE) ? HKRANKMAX : (2*HKRANKMAX-1));i++) + { + if (vtitle & (1< rank[5..18] @@ -6802,15 +6827,25 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto // title[other] -> 0 if (victim_title == 0) victim_guid.Clear(); // Don't show HK: message, only log. - else if (victim_title < 15) + else if (victim_title < HKRANKMAX) victim_rank = victim_title + 4; - else if (victim_title < 29) - victim_rank = victim_title - 14 + 4; + else if (victim_title < (2*HKRANKMAX-1)) + victim_rank = victim_title - (HKRANKMAX-1) + 4; else victim_guid.Clear(); // Don't show HK: message, only log. + // now find rank difference + if (killer_title == 0 && victim_rank>4) + rank_diff = victim_rank - 4; + else if (killer_title < HKRANKMAX) + rank_diff = (victim_rank>(killer_title + 4))? (victim_rank - (killer_title + 4)) : 0; + else if (killer_title < (2*HKRANKMAX-1)) + rank_diff = (victim_rank>(killer_title - (HKRANKMAX-1) +4))? (victim_rank - (killer_title - (HKRANKMAX-1) + 4)) : 0; + honor_f = std::ceil(Trinity::Honor::hk_honor_at_level_f(k_level) * (v_level - k_grey) / (k_level - k_grey)); + honor *= 1 + sWorld->getRate(RATE_PVP_RANK_EXTRA_HONOR)*(((float)rank_diff) / 10.0f); + // count the number of playerkills in one day ApplyModUInt32Value(PLAYER_FIELD_KILLS, 1, true); // and those in a lifetime @@ -6818,6 +6853,7 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS, victim->GetClass()); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_RACE, victim->GetRace()); + UpdateKnownTitles(); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, GetAreaId()); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, 1, 0, victim); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, victim); @@ -6912,6 +6948,30 @@ void Player::SetArenaPoints(uint32 value) AddKnownCurrency(ITEM_ARENA_POINTS_ID); } +void Player::UpdateKnownTitles() +{ + uint32 new_title = 0; + uint32 honor_kills = GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS); + uint32 old_title = GetUInt32Value(PLAYER_CHOSEN_TITLE); + RemoveFlag64(PLAYER__FIELD_KNOWN_TITLES,PLAYER_TITLE_MASK_ALL_PVP); + // if (honor_kills < 0) + // return; + bool max_rank = ((honor_kills >= sWorld->pvp_ranks[HKRANKMAX-1]) ? true : false); + for (int i = HKRANK01; i != HKRANKMAX; ++i) + { + if (honor_kills < sWorld->pvp_ranks[i] || (max_rank)) + { + new_title = ((max_rank) ? (HKRANKMAX-1) : (i-1)); + if (new_title > 0) + new_title += ((GetTeam() == ALLIANCE) ? 0 : (HKRANKMAX-1)); + break; + } + } + SetFlag64(PLAYER__FIELD_KNOWN_TITLES,uint64(1) << new_title); + if (old_title > 0 && old_title < (2*HKRANKMAX-1) && new_title > old_title) + SetUInt32Value(PLAYER_CHOSEN_TITLE,new_title); +} + void Player::ModifyHonorPoints(int32 value, CharacterDatabaseTransaction trans) { int32 newValue = int32(GetHonorPoints()) + value; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index b5ddaca836..586eb22b54 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -362,6 +362,72 @@ enum PlayerFlags PLAYER_FLAGS_UNK31 = 0x80000000 }; +#define PLAYER_TITLE_MASK_ALLIANCE_PVP \ + (PLAYER_TITLE_PRIVATE | PLAYER_TITLE_CORPORAL | \ + PLAYER_TITLE_SERGEANT_A | PLAYER_TITLE_MASTER_SERGEANT | \ + PLAYER_TITLE_SERGEANT_MAJOR | PLAYER_TITLE_KNIGHT | \ + PLAYER_TITLE_KNIGHT_LIEUTENANT | PLAYER_TITLE_KNIGHT_CAPTAIN | \ + PLAYER_TITLE_KNIGHT_CHAMPION | PLAYER_TITLE_LIEUTENANT_COMMANDER | \ + PLAYER_TITLE_COMMANDER | PLAYER_TITLE_MARSHAL | \ + PLAYER_TITLE_FIELD_MARSHAL | PLAYER_TITLE_GRAND_MARSHAL) + +#define PLAYER_TITLE_MASK_HORDE_PVP \ + (PLAYER_TITLE_SCOUT | PLAYER_TITLE_GRUNT | \ + PLAYER_TITLE_SERGEANT_H | PLAYER_TITLE_SENIOR_SERGEANT | \ + PLAYER_TITLE_FIRST_SERGEANT | PLAYER_TITLE_STONE_GUARD | \ + PLAYER_TITLE_BLOOD_GUARD | PLAYER_TITLE_LEGIONNAIRE | \ + PLAYER_TITLE_CENTURION | PLAYER_TITLE_CHAMPION | \ + PLAYER_TITLE_LIEUTENANT_GENERAL | PLAYER_TITLE_GENERAL | \ + PLAYER_TITLE_WARLORD | PLAYER_TITLE_HIGH_WARLORD) + +#define PLAYER_TITLE_MASK_ALL_PVP \ + (PLAYER_TITLE_MASK_ALLIANCE_PVP | PLAYER_TITLE_MASK_HORDE_PVP) + +// used for PLAYER__FIELD_KNOWN_TITLES field (uint64), (1< void ModifyHonorPoints(int32 value, CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr)); //! If trans is specified, honor save query will be added to trans void ModifyArenaPoints(int32 value, CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr)); //! If trans is specified, arena point save query will be added to trans uint32 GetMaxPersonalArenaRatingRequirement(uint32 minarenaslot) const; + void UpdateKnownTitles(); void SetHonorPoints(uint32 value); void SetArenaPoints(uint32 value); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 2d8882dcae..fbf30e9db1 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -999,6 +999,18 @@ void World::LoadConfigSettings(bool reload) TC_LOG_ERROR("server.loading", "MinPetitionSigns (%i) must be in range 0..9. Set to 9.", m_int_configs[CONFIG_MIN_PETITION_SIGNS]); m_int_configs[CONFIG_MIN_PETITION_SIGNS] = 9; } + rate_values[RATE_PVP_RANK_EXTRA_HONOR] = sConfigMgr->GetFloatDefault("PvPRank.Rate.ExtraHonor", 1); + std::string s_pvp_ranks = sConfigMgr->GetStringDefault("PvPRank.HKPerRank", "10,50,100,200,450,750,1300,2000,3500,6000,9500,15000,21000,30000"); + char *c_pvp_ranks = const_cast(s_pvp_ranks.c_str()); + for (int i = 0; i !=HKRANKMAX; i++) + { + if (i==0) + pvp_ranks[0] = 0; + else if (i==1) + pvp_ranks[1] = atoi(strtok (c_pvp_ranks, ",")); + else + pvp_ranks[i] = atoi(strtok (NULL, ",")); + } m_int_configs[CONFIG_GM_LOGIN_STATE] = sConfigMgr->GetIntDefault("GM.LoginState", 2); m_int_configs[CONFIG_GM_VISIBLE_STATE] = sConfigMgr->GetIntDefault("GM.Visible", 2); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index eeda8e6970..de25f6e2af 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -459,6 +459,7 @@ enum Rates RATE_TALENT, RATE_CORPSE_DECAY_LOOTED, RATE_INSTANCE_RESET_TIME, + RATE_PVP_RANK_EXTRA_HONOR, RATE_DURABILITY_LOSS_ON_DEATH, RATE_DURABILITY_LOSS_DAMAGE, RATE_DURABILITY_LOSS_PARRY, @@ -471,6 +472,26 @@ enum Rates MAX_RATES }; +enum HonorKillPvPRank +{ + HKRANK00, + HKRANK01, + HKRANK02, + HKRANK03, + HKRANK04, + HKRANK05, + HKRANK06, + HKRANK07, + HKRANK08, + HKRANK09, + HKRANK10, + HKRANK11, + HKRANK12, + HKRANK13, + HKRANK14, + HKRANKMAX +}; + /// Can be used in SMSG_AUTH_RESPONSE packet enum BillingPlanFlags { @@ -656,6 +677,8 @@ class TC_GAME_API World bool SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self = nullptr, uint32 team = 0); void SendZoneText(uint32 zone, const char *text, WorldSession* self = nullptr, uint32 team = 0); + uint32 pvp_ranks[HKRANKMAX]; + /// Are we in the middle of a shutdown? bool IsShuttingDown() const { return m_ShutdownTimer > 0; } uint32 GetShutDownTimeLeft() const { return m_ShutdownTimer; } diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index f475d0248e..915c1fac14 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3349,6 +3349,29 @@ PreventRenameCharacterOnCustomization = 0 # ################################################################################################### +################################################################################################### +# PVP RANK / TITLE SYSTEM +# +# PvPRank.Rate.ExtraHonor +# Description: Rate of honor bonus for killing higher pvp ranked players +# Default: 1 - 10% more honor per rank difference +# 2 - 20% +# 0 - off + +PvPRank.Rate.ExtraHonor = 1 + +# +# PvPRank.HKPerRank +# Description: Honor Kills needed for each rank, use "," between values. +# Whole string must be enclosed with " " +# Always specify 14 values, for 14 ranks +# Default: "100,500,1000,2500,4000,6500,9500,12000,15000,20000,35000,50000,75000,100000" + +PvPRank.HKPerRank = "100,500,1000,2500,4000,6500,9500,12000,15000,20000,35000,50000,75000,100000" + +# +#################################################################################################### + ################################################################################################### # AUCTION HOUSE BOT SETTINGS #