Skip to content

Commit

Permalink
Moved Imbuement Combat logic to Combat::doTargetCombat() (#43) Fixes #41
Browse files Browse the repository at this point in the history


- Rewrote some of the math and logic involving the math
- Used more consts and refs
- Added defaults, and unlikely attribute, for switches
- Checking for only melee and ranged attacks
- Excluded all healing and manadrain combat types
  • Loading branch information
Codinablack authored Jan 4, 2025
1 parent 04fb74b commit 54631e8
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 112 deletions.
138 changes: 137 additions & 1 deletion src/combat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,8 @@ void Combat::doTargetCombat(Creature* caster, Creature* target, CombatDamage& da
g_game.addMagicEffect(target->getPosition(), CONST_ME_CRITICAL_DAMAGE);
}

for (const auto& condition : params.conditionList) {
for (const auto& condition : params.conditionList)
{
if (!target->isImmune(condition->getType())) {
Condition* conditionCopy = condition->clone();
if (caster) {
Expand All @@ -985,6 +986,141 @@ void Combat::doTargetCombat(Creature* caster, Creature* target, CombatDamage& da
target->addCombatCondition(conditionCopy);
}
}
// hopefully runes are counted as spells and not ranged
if (casterPlayer.has_value()
&& (damage.origin == ORIGIN_MELEE || damage.origin == ORIGIN_RANGED)
&& (damage.primary.type != COMBAT_HEALING && damage.primary.type != COMBAT_MANADRAIN )) {
for (int32_t slot = CONST_SLOT_FIRST; slot <= CONST_SLOT_LAST; ++slot) {

Item* item = casterPlayer.value()->getInventoryItem(static_cast<slots_t>(slot));
if (!item) {
continue;
}
if (item->hasImbuements()) {

for (auto& imbuement : item->getImbuements()) {
if (!imbuement->value) {
continue;
}
const auto& originalDamage = abs(damage.primary.value);
const auto& conversionAmount = (originalDamage * imbuement->value) / 100;
const int32_t& difference = (originalDamage - conversionAmount);

CombatDamage imbueDamage;
imbueDamage.blockType = BLOCK_NONE;
imbueDamage.origin = ORIGIN_IMBUEMENT;

switch (imbuement->imbuetype) {
case IMBUEMENT_TYPE_FIRE_DAMAGE:
imbueDamage.primary.type = COMBAT_FIREDAMAGE;
break;
case IMBUEMENT_TYPE_ENERGY_DAMAGE:
imbueDamage.primary.type = COMBAT_ENERGYDAMAGE;
break;
case IMBUEMENT_TYPE_EARTH_DAMAGE:
imbueDamage.primary.type = COMBAT_EARTHDAMAGE;
break;
case IMBUEMENT_TYPE_ICE_DAMAGE:
imbueDamage.primary.type = COMBAT_ICEDAMAGE;
break;
case IMBUEMENT_TYPE_HOLY_DAMAGE:
imbueDamage.primary.type = COMBAT_HOLYDAMAGE;
break;
case IMBUEMENT_TYPE_DEATH_DAMAGE:
imbueDamage.primary.type = COMBAT_DEATHDAMAGE;
break;
default: [[unlikely]]
break;
}

if (difference < 0) {
imbueDamage.primary.value -= originalDamage;
g_game.combatChangeHealth(caster, target, imbueDamage);
break;
} // else
imbueDamage.primary.value -= conversionAmount;
g_game.combatChangeHealth(caster, target, imbueDamage);
}
}
}
}

if (targetPlayer.has_value() && damage.primary.type != COMBAT_HEALING && damage.primary.type != COMBAT_MANADRAIN ) {
for (int32_t slot = CONST_SLOT_FIRST; slot <= CONST_SLOT_LAST; ++slot)
{
Item* item = targetPlayer.value()->getInventoryItem(static_cast<slots_t>(slot));
if (!item) {
continue;
}

if (item->hasImbuements()) {
for (const auto& imbuement : item->getImbuements()) {
const auto combatType = damage.primary.type;
const auto& originalDamage = abs(damage.primary.value);
const auto& resistance = (originalDamage * imbuement->value) / 100;
const int32_t& difference = (originalDamage - resistance);
switch (imbuement->imbuetype) {
case ImbuementType::IMBUEMENT_TYPE_FIRE_RESIST:
if (combatType == COMBAT_FIREDAMAGE) {
if (difference < 0) {
damage.primary.value = 0;
return;
}
damage.primary.value += difference;
}
break;
case ImbuementType::IMBUEMENT_TYPE_EARTH_RESIST:
if (combatType == COMBAT_EARTHDAMAGE) {
if (difference < 0) {
damage.primary.value = 0;
return;
}
damage.primary.value += difference;
}
break;
case ImbuementType::IMBUEMENT_TYPE_ICE_RESIST:
if (combatType == COMBAT_ICEDAMAGE) {
if (difference < 0) {
damage.primary.value = 0;
return;
}
damage.primary.value += difference;
}
break;
case ImbuementType::IMBUEMENT_TYPE_ENERGY_RESIST:
if (combatType == COMBAT_ENERGYDAMAGE) {
if (difference < 0) {
damage.primary.value = 0;
return;
}
damage.primary.value += difference;
}
break;
case ImbuementType::IMBUEMENT_TYPE_DEATH_RESIST:
if (combatType == COMBAT_DEATHDAMAGE) {
if (difference < 0) {
damage.primary.value = 0;
return;
}
damage.primary.value += difference;
}
break;
case ImbuementType::IMBUEMENT_TYPE_HOLY_RESIST:
if (combatType == COMBAT_HOLYDAMAGE) {
if (difference < 0) {
damage.primary.value = 0;
return;
}
damage.primary.value += difference;
}
break;
default: [[unlikely]]
break;
}
}
}
}
}

if (!damage.leeched && damage.primary.type != COMBAT_HEALING
&& casterPlayer
Expand Down
72 changes: 0 additions & 72 deletions src/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -875,78 +875,6 @@ BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int3
}
}

if (attacker && combatType != COMBAT_HEALING && blockType == BLOCK_NONE)
{
Player* attackerPlayer = attacker->getPlayer();
if (attackerPlayer) {
for (int32_t slot = CONST_SLOT_FIRST; slot <= CONST_SLOT_LAST; ++slot) {

Item* item = attackerPlayer->getInventoryItem(static_cast<slots_t>(slot));
if (!item) {
continue;
}

if (item->hasImbuements()) {

for (auto& imbuement : item->getImbuements()) {

auto conversionAmount = std::abs(std::round(damage * (imbuement->value / 100.)));

if (conversionAmount > 0) {
auto trueDamage = std::abs(damage);
auto difference = (trueDamage - conversionAmount);

CombatDamage imbueDamage;
imbueDamage.blockType = BLOCK_NONE;
imbueDamage.origin = ORIGIN_IMBUEMENT;

switch (imbuement->imbuetype) {
case IMBUEMENT_TYPE_FIRE_DAMAGE:
imbueDamage.primary.type = COMBAT_FIREDAMAGE;
break;
case IMBUEMENT_TYPE_ENERGY_DAMAGE:
imbueDamage.primary.type = COMBAT_ENERGYDAMAGE;
break;
case IMBUEMENT_TYPE_EARTH_DAMAGE:
imbueDamage.primary.type = COMBAT_EARTHDAMAGE;
break;
case IMBUEMENT_TYPE_ICE_DAMAGE:
imbueDamage.primary.type = COMBAT_ICEDAMAGE;
break;
case IMBUEMENT_TYPE_HOLY_DAMAGE:
imbueDamage.primary.type = COMBAT_HOLYDAMAGE;
break;
case IMBUEMENT_TYPE_DEATH_DAMAGE:
imbueDamage.primary.type = COMBAT_DEATHDAMAGE;
break;
default:
break;
}

// Here we keep the damage from being reduced so much it becomes healing,
// while also considering the damage the imbuement does, and limiting it
// to only do as much as actually convertable.
if (difference <= 0) {
if (difference < 0) {
imbueDamage.primary.value = (0 - trueDamage);
} else {
imbueDamage.primary.value = (0 - conversionAmount);
}
damage = 0;
} else {
imbueDamage.primary.value = (0 - conversionAmount);
// this might be confusing, but since we know damage is a negative number
// and we know that the conversion is positive, we can add them to reduce the damage.
damage += conversionAmount;
}
g_game.combatChangeHealth(attacker, this, imbueDamage);
}
}
}
}
}
}

if (damage <= 0) {
damage = 0;
blockType = BLOCK_ARMOR;
Expand Down
40 changes: 1 addition & 39 deletions src/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2661,43 +2661,6 @@ BlockType_t Player::blockHit(Creature* attacker, CombatType_t combatType, int32_
if (charges != 0) {
g_game.transformItem(item, item->getID(), charges - 1);
}

if (item->hasImbuements() && combatType != COMBAT_HEALING) {
for (auto imbuement : item->getImbuements()) {
switch (imbuement->imbuetype) {
case ImbuementType::IMBUEMENT_TYPE_FIRE_RESIST:
if (combatType == COMBAT_FIREDAMAGE) {
damage -= std::round(damage * (imbuement->value / 100.));
}
break;
case ImbuementType::IMBUEMENT_TYPE_EARTH_RESIST:
if (combatType == COMBAT_EARTHDAMAGE) {
damage -= std::round(damage * (imbuement->value / 100.));
}
break;
case ImbuementType::IMBUEMENT_TYPE_ICE_RESIST:
if (combatType == COMBAT_ICEDAMAGE) {
damage -= std::round(damage * (imbuement->value / 100.));
}
break;
case ImbuementType::IMBUEMENT_TYPE_ENERGY_RESIST:
if (combatType == COMBAT_ENERGYDAMAGE) {
damage -= std::round(damage * (imbuement->value / 100.));
}
break;
case ImbuementType::IMBUEMENT_TYPE_DEATH_RESIST:
if (combatType == COMBAT_DEATHDAMAGE) {
damage -= std::round(damage * (imbuement->value / 100.));
}
break;
case ImbuementType::IMBUEMENT_TYPE_HOLY_RESIST:
if (combatType == COMBAT_HOLYDAMAGE) {
damage -= std::round(damage * (imbuement->value / 100.));
}
break;
}
}
}
}
}

Expand Down Expand Up @@ -5667,8 +5630,7 @@ void Player::removeItemImbuements(Item* item) {


void Player::removeImbuementEffect(std::shared_ptr<Imbuement> imbue) {



if (imbue->isSkill()) {
switch (imbue->imbuetype) {
case ImbuementType::IMBUEMENT_TYPE_FIST_SKILL:
Expand Down

0 comments on commit 54631e8

Please sign in to comment.