Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Expert PvP #5

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ maintainModeMessage = ""
-- NOTE: valid values for worldType are: "pvp", "no-pvp" and "pvp-enforced"
-- NOTE: removeBeginningWeaponAmmunition: spears, arrows, bolt have endless ammo (allows training for paladins)
-- NOTE: refundManaOnBeginningWeapons: wand of vortex and snakebite refund mana used (allows training for mages)
-- NOTE: toggleExpertPvp enables the PvP frames, similar to Tibia RL.
worldType = "pvp"
hotkeyAimbotEnabled = true
protectionLevel = 7
Expand All @@ -50,6 +51,7 @@ blackSkulledDeathHealth = 40
blackSkulledDeathMana = 0
fieldOwnershipDuration = 5 * 1000
loginProtectionPeriod = 10 * 1000
toggleExpertPvp = true

cleanProtectionZones = false

Expand Down
1 change: 1 addition & 0 deletions src/config/config_enums.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,5 +350,6 @@ enum ConfigKey_t : uint16_t {
FIELD_OWNERSHIP,
BEDS_ONLY_PREMIUM,
LOGIN_PROTECTION,
TOGGLE_EXPERT_PVP,
SPELL_NAME_INSTEAD_WORDS,
};
1 change: 1 addition & 0 deletions src/config/configmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ bool ConfigManager::load() {
loadBoolConfig(L, HALF_LOSS_MAGIC, "halfLossMagicLevel", true);
loadBoolConfig(L, CHAIN_SYSTEM_VIP_ONLY, "chainSystemVipOnly", false);
loadBoolConfig(L, BEDS_ONLY_PREMIUM, "bedsOnlyPremium", true);
loadBoolConfig(L, TOGGLE_EXPERT_PVP, "toggleExpertPvp", false);
loadBoolConfig(L, SPELL_NAME_INSTEAD_WORDS, "spellNameInsteadOfWords", false);

loadFloatConfig(L, BESTIARY_RATE_CHARM_SHOP_PRICE, "bestiaryRateCharmShopPrice", 1.0);
Expand Down
3 changes: 1 addition & 2 deletions src/creatures/combat/spells.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ TalkActionResult_t Spells::playerSaySpell(const std::shared_ptr<Player> &player,
if (instantSpell->playerCastInstant(player, param)) {
if (!player->checkSpellNameInsteadOfWords()) {
words = instantSpell->getWords();
}
else {
} else {
words = instantSpell->getName();
}

Expand Down
98 changes: 94 additions & 4 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3339,7 +3339,8 @@ bool Player::isPzLocked() const {

BlockType_t Player::blockHit(const std::shared_ptr<Creature> &attacker, const CombatType_t &combatType, int32_t &damage, bool checkDefense, bool checkArmor, bool field) {
BlockType_t blockType = Creature::blockHit(attacker, combatType, damage, checkDefense, checkArmor, field);
if (attacker) {

if (!g_game().isExpertPvpEnabled() && attacker) {
sendCreatureSquare(attacker, SQ_COLOR_BLACK);
}

Expand Down Expand Up @@ -5482,6 +5483,10 @@ void Player::setFightMode(FightMode_t mode) {
fightMode = mode;
}

void Player::setPvpMode(PvpMode_t mode) {
pvpMode = mode;
}

void Player::setSecureMode(bool mode) {
secureMode = mode;
}
Expand Down Expand Up @@ -5629,6 +5634,10 @@ void Player::onEndCondition(ConditionType_t type) {
pzLocked = false;
clearAttacked();

if (g_game().isExpertPvpEnabled()) {
g_game().updateSpectatorsPvp(std::const_pointer_cast<Player>(getPlayer()));
}

if (getSkull() != SKULL_RED && getSkull() != SKULL_BLACK) {
setSkull(SKULL_NONE);
}
Expand Down Expand Up @@ -5694,7 +5703,12 @@ void Player::onAttackedCreature(const std::shared_ptr<Creature> &target) {
}

const auto &targetPlayer = target->getPlayer();
if (targetPlayer && !isPartner(targetPlayer) && !isGuildMate(targetPlayer)) {
if (targetPlayer) {
if (!g_game().isExpertPvpEnabled() && (isPartner(targetPlayer) || isGuildMate(targetPlayer))) {
addInFightTicks();
return;
}

if (!pzLocked && g_game().getWorldType() == WORLD_TYPE_PVP_ENFORCED) {
pzLocked = true;
sendIcons();
Expand Down Expand Up @@ -5723,6 +5737,11 @@ void Player::onAttackedCreature(const std::shared_ptr<Creature> &target) {
}
}

if (g_game().isExpertPvpEnabled()) {
g_game().updateSpectatorsPvp(std::const_pointer_cast<Player>(getPlayer()));
g_game().updateSpectatorsPvp(targetPlayer);
}

addInFightTicks();
}

Expand Down Expand Up @@ -7623,6 +7642,10 @@ void Player::onThink(uint32_t interval) {
// Wheel of destiny major spells
wheel()->onThink();

if (g_game().isExpertPvpEnabled()) {
g_game().updateSpectatorsPvp(std::const_pointer_cast<Player>(getPlayer()));
}

g_callbacks().executeCallback(EventCallback_t::playerOnThink, &EventCallback::playerOnThink, getPlayer(), interval);
}

Expand Down Expand Up @@ -7829,9 +7852,9 @@ void Player::sendPrivateMessage(const std::shared_ptr<Player> &speaker, SpeakCla
}
}

void Player::sendCreatureSquare(const std::shared_ptr<Creature> &creature, SquareColor_t color) const {
void Player::sendCreatureSquare(const std::shared_ptr<Creature> &creature, SquareColor_t color, uint8_t length) const {
if (client) {
client->sendCreatureSquare(creature, color);
client->sendCreatureSquare(creature, color, length);
}
}

Expand Down Expand Up @@ -9872,6 +9895,11 @@ void Player::onRemoveTileItem(const std::shared_ptr<Tile> &fromTile, const Posit
void Player::onCreatureAppear(const std::shared_ptr<Creature> &creature, bool isLogin) {
Creature::onCreatureAppear(creature, isLogin);

if (g_game().isExpertPvpEnabled()) {
g_game().updateSpectatorsPvp(getPlayer());
g_game().updateSpectatorsPvp(creature);
}

if (isLogin && creature == getPlayer()) {
onEquipInventory();

Expand Down Expand Up @@ -10590,3 +10618,65 @@ uint16_t Player::getPlayerVocationEnum() const {

return Vocation_t::VOCATION_NONE;
}

bool Player::hasPvpActivity(const std::shared_ptr<Player> &player, bool guildAndParty /* = false*/) const {
if (!g_game().isExpertPvpEnabled() || !player || player.get() == this) {
return false;
}

if (hasAttacked(player) || player->hasAttacked(std::const_pointer_cast<Player>(getPlayer()))) {
return true;
}

if (guildAndParty) {
if (guild) {
for (auto it : guild->getMembersOnline()) {
if (it->hasPvpActivity(player)) {
return true;
}
}
}

const auto &party = getParty();
if (party) {
for (auto it : party->getMembers()) {
if (it->hasPvpActivity(player)) {
return true;
}
}
}
}

return false;
}

bool Player::isInPvpSituation() {
if (!isPvpSituation) {
return false;
}

if (pzLocked || attackedSet.size() > 0) {
return true;
}

for (auto it : g_game().getPlayers()) {
std::shared_ptr<Player> itPlayer = it.second;
if (!itPlayer || itPlayer->isRemoved()) {
continue;
}

if (itPlayer->hasAttacked(getPlayer())) {
return true;
}
}

return false;
}

void Player::sendPvpSquare(const std::shared_ptr<Creature> &creature, SquareColor_t squareColor) {
sendCreatureSquare(creature, squareColor, 2);

if (squareColor == SQ_COLOR_YELLOW) {
sendCreatureSquare(creature, squareColor, 2);
}
}
16 changes: 15 additions & 1 deletion src/creatures/players/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@ class Player final : public Creature, public Cylinder, public Bankable {
void setChaseMode(bool mode);
void setFightMode(FightMode_t mode);
void setSecureMode(bool mode);
void setPvpMode(PvpMode_t mode);

Faction_t getFaction() const override;

Expand Down Expand Up @@ -765,7 +766,7 @@ class Player final : public Creature, public Cylinder, public Bankable {
void sendCreatureSay(const std::shared_ptr<Creature> &creature, SpeakClasses type, const std::string &text, const Position* pos = nullptr) const;
void sendCreatureReload(const std::shared_ptr<Creature> &creature) const;
void sendPrivateMessage(const std::shared_ptr<Player> &speaker, SpeakClasses type, const std::string &text) const;
void sendCreatureSquare(const std::shared_ptr<Creature> &creature, SquareColor_t color) const;
void sendCreatureSquare(const std::shared_ptr<Creature> &creature, SquareColor_t color, uint8_t length = 1) const;
void sendCreatureChangeOutfit(const std::shared_ptr<Creature> &creature, const Outfit_t &outfit) const;
void sendCreatureChangeVisible(const std::shared_ptr<Creature> &creature, bool visible);
void sendCreatureLight(const std::shared_ptr<Creature> &creature) const;
Expand Down Expand Up @@ -979,6 +980,17 @@ class Player final : public Creature, public Cylinder, public Bankable {

void setWalkExhaust(int64_t value);

bool hasPvpActivity(const std::shared_ptr<Player> &player, bool guildAndParty = false) const;
bool isInPvpSituation();

void sendPvpSquare(const std::shared_ptr<Creature> &creature, SquareColor_t squareColor);
void setPvpSituation(bool situation) {
isPvpSituation = situation;
}
PvpMode_t getPvPMode() const {
return pvpMode;
}

const std::map<uint8_t, OpenContainer> &getOpenContainers() const;

uint16_t getBaseXpGain() const;
Expand Down Expand Up @@ -1542,6 +1554,7 @@ class Player final : public Creature, public Cylinder, public Bankable {
BlockType_t lastAttackBlockType = BLOCK_NONE;
TradeState_t tradeState = TRADE_NONE;
FightMode_t fightMode = FIGHTMODE_ATTACK;
PvpMode_t pvpMode = PVP_MODE_DOVE;
Faction_t faction = FACTION_PLAYER;
QuickLootFilter_t quickLootFilter {};
PlayerPronoun_t pronoun = PLAYERPRONOUN_THEY;
Expand All @@ -1565,6 +1578,7 @@ class Player final : public Creature, public Cylinder, public Bankable {
bool moved = false;
bool m_isDead = false;
bool imbuementTrackerWindowOpen = false;
bool isPvpSituation = false;

// Hazard system
int64_t lastHazardSystemCriticalHit = 0;
Expand Down
81 changes: 79 additions & 2 deletions src/game/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5946,15 +5946,46 @@ void Game::playerFollowCreature(uint32_t playerId, uint32_t creatureId) {
player->setFollowCreature(getCreatureByID(creatureId));
}

void Game::playerSetFightModes(uint32_t playerId, FightMode_t fightMode, bool chaseMode, bool secureMode) {
void Game::playerSetFightModes(uint32_t playerId, FightMode_t fightMode, PvpMode_t pvpMode, bool chaseMode, bool secureMode) {
const auto &player = getPlayerByID(playerId);
if (!player) {
return;
}

PvpMode_t oldPvpMode = player->getPvPMode();
bool expertPvp = isExpertPvpEnabled();

player->setFightMode(fightMode);
player->setChaseMode(chaseMode);
player->setSecureMode(secureMode);

if (expertPvp) {
WorldType_t worldType = getWorldType();
if (worldType == WORLD_TYPE_NO_PVP && pvpMode == PVP_MODE_RED_FIST) {
player->setPvpMode(player->pvpMode);
} else if (worldType == WORLD_TYPE_PVP_ENFORCED && pvpMode != PVP_MODE_RED_FIST) {
player->setPvpMode(PVP_MODE_RED_FIST);
} else {
player->setPvpMode(pvpMode);
}

if ((worldType == WORLD_TYPE_NO_PVP && !secureMode) || (worldType == WORLD_TYPE_PVP_ENFORCED && secureMode)) {
player->setSecureMode(!secureMode);
} else {
if (player->getPvPMode() == PVP_MODE_RED_FIST) {
player->setSecureMode(false);
} else {
player->setSecureMode(secureMode);
}

if (oldPvpMode == PVP_MODE_RED_FIST) {
player->setSecureMode(true);
}
}

player->sendFightModes();
} else {
player->setSecureMode(secureMode);
}
}

void Game::playerRequestAddVip(uint32_t playerId, const std::string &name) {
Expand Down Expand Up @@ -10911,3 +10942,49 @@ void Game::updatePlayersOnline() const {
g_logger().error("[Game::updatePlayersOnline] Failed to update players online.");
}
}

bool Game::isExpertPvpEnabled() {
return g_configManager().getBoolean(TOGGLE_EXPERT_PVP);
}

void Game::updateSpectatorsPvp(const std::shared_ptr<Thing> &thing) {
if (!thing) {
return;
}

if (std::shared_ptr<Creature> creature = thing->getCreature()) {
std::shared_ptr<Player> player = creature->getPlayer();
if (!player) {
return;
}

for (const auto &spectator : Spectators().find<Player>(player->getPosition(), true)) {
std::shared_ptr<Player> itPlayer = spectator->getPlayer();
if (!itPlayer) {
continue;
}

SquareColor_t sqColor = SQ_COLOR_NONE;
if (player->hasPvpActivity(itPlayer)) {
sqColor = SQ_COLOR_YELLOW;
} else if (itPlayer->isInPvpSituation()) {
if (itPlayer == player) {
sqColor = SQ_COLOR_YELLOW;
} else if (player->hasPvpActivity(itPlayer, true)) {
// if this player attacked anyone of players's guild/party
sqColor = SQ_COLOR_ORANGE;
} else {
// meaning that the fight you are not involved.
sqColor = SQ_COLOR_BROWN;
}
} else {
// player isn't enganged at any pvp situation! ( even if self)
player->sendCreatureSquare(itPlayer, SQ_COLOR_NONE, 0);
}

if (sqColor != SQ_COLOR_NONE) {
player->sendPvpSquare(itPlayer, sqColor);
}
}
}
}
5 changes: 4 additions & 1 deletion src/game/game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ class Game {
void playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId);
void playerFollowCreature(uint32_t playerId, uint32_t creatureId);
void playerCancelAttackAndFollow(uint32_t playerId);
void playerSetFightModes(uint32_t playerId, FightMode_t fightMode, bool chaseMode, bool secureMode);
void playerSetFightModes(uint32_t playerId, FightMode_t fightMode, PvpMode_t pvpMode, bool chaseMode, bool secureMode);
void playerLookAt(uint32_t playerId, uint16_t itemId, const Position &pos, uint8_t stackPos);
void playerLookInBattleList(uint32_t playerId, uint32_t creatureId);
void playerQuickLootCorpse(const std::shared_ptr<Player> &player, const std::shared_ptr<Container> &corpse, const Position &position);
Expand Down Expand Up @@ -560,6 +560,9 @@ class Game {
bool addUniqueItem(uint16_t uniqueId, std::shared_ptr<Item> item);
void removeUniqueItem(uint16_t uniqueId);

bool isExpertPvpEnabled();
void updateSpectatorsPvp(const std::shared_ptr<Thing> &thing);

bool hasEffect(uint16_t effectId);
bool hasDistanceEffect(uint16_t effectId);

Expand Down
Loading