Skip to content

Commit

Permalink
Modify crits, spells direct at players
Browse files Browse the repository at this point in the history
  • Loading branch information
kphoenix137 committed Feb 25, 2024
1 parent 2bbd28d commit 64f49c5
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 18 deletions.
95 changes: 79 additions & 16 deletions Source/missiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,23 @@ Monster *FindClosest(Point source, int rad)
return nullptr;
}

Player *FindClosestPlayer(Point source, int rad)
{
std::optional<Point> playerPosition = FindClosestValidPosition(
[&source](Point target) {
// search for a player with clear line of sight
return InDungeonBounds(target) && dPlayer[target.x][target.y] > 0 && !CheckBlock(source, target);
},
source, 1, rad);

if (playerPosition) {
int pid = dPlayer[playerPosition->x][playerPosition->y];
return &Players[pid - 1];
}

return nullptr;
}

constexpr Direction16 Direction16Flip(Direction16 x, Direction16 pivot)
{
std::underlying_type_t<Direction16> ret = (2 * static_cast<std::underlying_type_t<Direction16>>(pivot) + 16 - static_cast<std::underlying_type_t<Direction16>>(x)) % 16;
Expand Down Expand Up @@ -409,13 +426,14 @@ bool Plr2PlrMHit(const Player &player, Player &target, int mindam, int maxdam, i
int charLevel = player.getCharacterLevel();
bool isSpell = !missileData.isArrow();
int critChance = (charLevel * 2 + (isSpell ? player._pMagic : player._pDexterity)) / 10;
bool forcehit = false;

// PVP REBALANCE: Crit chance for arrows and spells in arenas.
// PVP REBALANCE: Crit chance for arrows and spells in arenas. Crits force hit recovery.
if (isOnArena && GenerateRnd(100) < critChance) {
dam = isSpell ? dam * 5 / 4 : dam * 3 / 2; // Arrow: +50% damage, Spell: +25% damage
forcehit = true;
}


if (resper > 0) {
dam -= (dam * resper) / 100;
if (&player == MyPlayer)
Expand All @@ -430,7 +448,7 @@ bool Plr2PlrMHit(const Player &player, Player &target, int mindam, int maxdam, i
} else {
if (&player == MyPlayer)
NetSendCmdDamage(true, target, dam, damageType);
StartPlrHit(target, dam, false);
StartPlrHit(target, dam, forcehit);
}

return true;
Expand Down Expand Up @@ -3584,13 +3602,18 @@ void ProcessChainLightning(Missile &missile)
Point position = missile.position.tile;
Point dst { missile.var1, missile.var2 };
Direction dir = GetDirection(position, dst);
AddMissile(position, dst, dir, MissileID::LightningControl, TARGET_MONSTERS, id, 1, missile._mispllvl);
const Player &player = Players[missile._misource];
mienemy_type targetType = TARGET_MONSTERS;
if (player.isOnArenaLevel()) {
targetType = TARGET_PLAYERS;
}
AddMissile(position, dst, dir, MissileID::LightningControl, targetType, id, 1, missile._mispllvl);
int rad = std::min<int>(missile._mispllvl + 3, MaxCrawlRadius);
Crawl(1, rad, [&](Displacement displacement) {
Point target = position + displacement;
if (InDungeonBounds(target) && dMonster[target.x][target.y] > 0) {
if (InDungeonBounds(target) && (missile.sourcePlayer()->isOnArenaLevel() ? dPlayer[target.x][target.y] : dMonster[target.x][target.y]) > 0) {
dir = GetDirection(position, target);
AddMissile(position, target, dir, MissileID::LightningControl, TARGET_MONSTERS, id, 1, missile._mispllvl);
AddMissile(position, target, dir, MissileID::LightningControl, targetType, id, 1, missile._mispllvl);
}
return false;
});
Expand Down Expand Up @@ -4085,11 +4108,30 @@ void ProcessElemental(Missile &missile)
if (missile.var3 == 1) {
missile.var3 = 2;
missile._mirange = 255;
auto *nextMonster = FindClosest(missilePosition, 19);
if (nextMonster != nullptr) {
Direction sd = GetDirection(missilePosition, nextMonster->position.tile);
SetMissDir(missile, sd);
UpdateMissileVelocity(missile, nextMonster->position.tile, 16);

std::function<void()> targetAction;
if (missile.sourcePlayer()->isOnArenaLevel()) {
auto *nextPlayer = FindClosestPlayer(missilePosition, 19);
if (nextPlayer != nullptr) {
targetAction = [&]() {
Direction sd = GetDirection(missilePosition, nextPlayer->position.tile);
SetMissDir(missile, sd);
UpdateMissileVelocity(missile, nextPlayer->position.tile, 16);
};
}
} else {
auto *nextMonster = FindClosest(missilePosition, 19);
if (nextMonster != nullptr) {
targetAction = [&]() {
Direction sd = GetDirection(missilePosition, nextMonster->position.tile);
SetMissDir(missile, sd);
UpdateMissileVelocity(missile, nextMonster->position.tile, 16);
};
}
}

if (targetAction) {
targetAction();
} else {
Direction sd = Players[missile._misource]._pdir;
SetMissDir(missile, sd);
Expand Down Expand Up @@ -4130,17 +4172,38 @@ void ProcessBoneSpirit(Missile &missile)
if (missile.var3 == 1) {
missile.var3 = 2;
missile._mirange = 255;
auto *monster = FindClosest(c, 19);
if (monster != nullptr) {
missile._midam = monster->hitPoints >> 7;
SetMissDir(missile, GetDirection(c, monster->position.tile));
UpdateMissileVelocity(missile, monster->position.tile, 16);

std::function<void()> targetAction;

if (missile.sourcePlayer()->isOnArenaLevel()) {
auto *player = FindClosestPlayer(c, 19);
if (player != nullptr) {
targetAction = [&]() {
missile._midam = player->_pHitPoints >> 7;
SetMissDir(missile, GetDirection(c, player->position.tile));
UpdateMissileVelocity(missile, player->position.tile, 16);
};
}
} else {
auto *monster = FindClosest(c, 19);
if (monster != nullptr) {
targetAction = [&]() {
missile._midam = monster->hitPoints >> 7;
SetMissDir(missile, GetDirection(c, monster->position.tile));
UpdateMissileVelocity(missile, monster->position.tile, 16);
};
}
}

if (targetAction) {
targetAction();
} else {
Direction sd = Players[missile._misource]._pdir;
SetMissDir(missile, sd);
UpdateMissileVelocity(missile, c + sd, 16);
}
}

if (c != Point { missile.var1, missile.var2 }) {
missile.var1 = c.x;
missile.var2 = c.y;
Expand Down
7 changes: 5 additions & 2 deletions Source/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -815,10 +815,13 @@ bool PlrHitPlr(Player &attacker, Player &target)
int charLevel = attacker.getCharacterLevel();
HeroClass charClass = attacker._pClass;
int critChance = isOnArena ? (charLevel * 2 + attacker._pStrength) / 10 : charLevel;
bool forcehit = false;

// PVP REBALANCE: New formula for crit chance in arenas.
// PVP REBALANCE: New crit chance formula for arenas. Crits always cause hit recovery.
if ((isOnArena || charClass == HeroClass::Warrior || charClass == HeroClass::Barbarian) && GenerateRnd(100) < critChance) {
dam *= 2;
if (isOnArena)
forcehit = true;
}

int skdam = dam << 6;
Expand All @@ -837,7 +840,7 @@ bool PlrHitPlr(Player &attacker, Player &target)
if (&attacker == MyPlayer) {
NetSendCmdDamage(true, target, skdam, DamageType::Physical);
}
StartPlrHit(target, skdam, false);
StartPlrHit(target, skdam, forcehit);

return true;
}
Expand Down
1 change: 1 addition & 0 deletions Source/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

namespace devilution {

extern Player *MyPlayer;
constexpr int InventoryGridCells = 40;
constexpr int MaxBeltItems = 8;
constexpr int MaxResistance = 75;
Expand Down

0 comments on commit 64f49c5

Please sign in to comment.