Skip to content
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 changes/armor-rating-rounding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Full armor ratings (with the fractional part) are now displayed in item descriptions.
Fix armor ratings that end in 0.25 and 0.75 being equivalent to that armor rating minus 0.25.
8 changes: 4 additions & 4 deletions src/brogue/IO.c
Original file line number Diff line number Diff line change
Expand Up @@ -4476,8 +4476,8 @@ void highlightScreenCell(short x, short y, const color *highlightColor, short st

// Like `armorValueIfUnenchanted` for the currently-equipped armor, but takes the penalty from
// donning into account.
static short estimatedArmorValue() {
short retVal = armorValueIfUnenchanted(rogue.armor) - player.status[STATUS_DONNING];
static float estimatedArmorValue() {
float retVal = armorValueIfUnenchanted(rogue.armor) - player.status[STATUS_DONNING];
return max(0, retVal);
}

Expand Down Expand Up @@ -4683,13 +4683,13 @@ short printMonsterInfo(creature *monst, short y, boolean dim, boolean highlight)
tempColorEscape,
rogue.strength - player.weaknessAmount,
grayColorEscape,
displayedArmorValue());
(int) displayedArmorValue());
} else {
sprintf(buf, "Str: %s%i%s Armor: %i?",
tempColorEscape,
rogue.strength - player.weaknessAmount,
grayColorEscape,
estimatedArmorValue());
(int) estimatedArmorValue());
}
//buf[20] = '\0';
printString(" ", 0, y, &white, &black, 0);
Expand Down
117 changes: 65 additions & 52 deletions src/brogue/Items.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <math.h>

#include "Rogue.h"
#include "GlobalsBase.h"
Expand Down Expand Up @@ -2086,62 +2087,74 @@ void itemDetails(char *buf, item *theItem) {
}

// Display the known percentage by which the armor/weapon will increase/decrease accuracy/damage/defense if not already equipped.
if (!(theItem->flags & ITEM_EQUIPPED)) {
if (theItem->category & WEAPON) {
current = player.info.accuracy;
if (rogue.weapon) {
currentDamage = (rogue.weapon->damage.lowerBound + rogue.weapon->damage.upperBound) * FP_FACTOR / 2;
if ((rogue.weapon->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) {
current = current * accuracyFraction(netEnchant(rogue.weapon)) / FP_FACTOR;
currentDamage = currentDamage * damageFraction(netEnchant(rogue.weapon)) / FP_FACTOR;
} else {
current = current * accuracyFraction(strengthModifier(rogue.weapon)) / FP_FACTOR;
currentDamage = currentDamage * damageFraction(strengthModifier(rogue.weapon)) / FP_FACTOR;
}
if (!(theItem->flags & ITEM_EQUIPPED) && (theItem->category & WEAPON)) {
current = player.info.accuracy;
if (rogue.weapon) {
currentDamage = (rogue.weapon->damage.lowerBound + rogue.weapon->damage.upperBound) * FP_FACTOR / 2;
if ((rogue.weapon->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) {
current = current * accuracyFraction(netEnchant(rogue.weapon)) / FP_FACTOR;
currentDamage = currentDamage * damageFraction(netEnchant(rogue.weapon)) / FP_FACTOR;
} else {
currentDamage = (player.info.damage.lowerBound + player.info.damage.upperBound) * FP_FACTOR / 2;
current = current * accuracyFraction(strengthModifier(rogue.weapon)) / FP_FACTOR;
currentDamage = currentDamage * damageFraction(strengthModifier(rogue.weapon)) / FP_FACTOR;
}
} else {
currentDamage = (player.info.damage.lowerBound + player.info.damage.upperBound) * FP_FACTOR / 2;
}

new = player.info.accuracy;
newDamage = (theItem->damage.lowerBound + theItem->damage.upperBound) * FP_FACTOR / 2;
if ((theItem->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) {
new = new * accuracyFraction(netEnchant(theItem)) / FP_FACTOR;
newDamage = newDamage * damageFraction(netEnchant(theItem)) / FP_FACTOR;
} else {
new = new * accuracyFraction(strengthModifier(theItem)) / FP_FACTOR;
newDamage = newDamage * damageFraction(strengthModifier(theItem)) / FP_FACTOR;
}
accuracyChange = (new * 100 / current) - 100;
damageChange = (newDamage * 100 / currentDamage) - 100;
sprintf(buf2, "Wielding the %s%s will %s your current accuracy by %s%i%%%s, and will %s your current damage by %s%i%%%s. ",
theName,
((theItem->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) ? "" : ", assuming it has no hidden properties,",
(((short) accuracyChange) < 0) ? "decrease" : "increase",
(((short) accuracyChange) < 0) ? badColorEscape : (accuracyChange > 0 ? goodColorEscape : ""),
abs((short) accuracyChange),
whiteColorEscape,
(((short) damageChange) < 0) ? "decrease" : "increase",
(((short) damageChange) < 0) ? badColorEscape : (damageChange > 0 ? goodColorEscape : ""),
abs((short) damageChange),
whiteColorEscape);
new = player.info.accuracy;
newDamage = (theItem->damage.lowerBound + theItem->damage.upperBound) * FP_FACTOR / 2;
if ((theItem->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) {
new = new * accuracyFraction(netEnchant(theItem)) / FP_FACTOR;
newDamage = newDamage * damageFraction(netEnchant(theItem)) / FP_FACTOR;
} else {
new = 0;
new = new * accuracyFraction(strengthModifier(theItem)) / FP_FACTOR;
newDamage = newDamage * damageFraction(strengthModifier(theItem)) / FP_FACTOR;
}
accuracyChange = (new * 100 / current) - 100;
damageChange = (newDamage * 100 / currentDamage) - 100;
sprintf(buf2, "Wielding the %s%s will %s your current accuracy by %s%i%%%s, and will %s your current damage by %s%i%%%s. ",
theName,
((theItem->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) ? "" : ", assuming it has no hidden properties,",
(((short) accuracyChange) < 0) ? "decrease" : "increase",
(((short) accuracyChange) < 0) ? badColorEscape : (accuracyChange > 0 ? goodColorEscape : ""),
abs((short) accuracyChange),
whiteColorEscape,
(((short) damageChange) < 0) ? "decrease" : "increase",
(((short) damageChange) < 0) ? badColorEscape : (damageChange > 0 ? goodColorEscape : ""),
abs((short) damageChange),
whiteColorEscape);
strcat(buf, buf2);
} else if (theItem->category & ARMOR) {
float armorValue;

if ((theItem->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) {
new = theItem->armor;
new += 10 * netEnchant(theItem) / FP_FACTOR;
new /= 10;
} else {
new = armorValueIfUnenchanted(theItem);
}
if ((theItem->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) {
armorValue = theItem->armor;
armorValue += 10 * netEnchant(theItem) / FP_FACTOR;
armorValue /= 10;
} else {
armorValue = armorValueIfUnenchanted(theItem);
}

new = max(0, new);
armorValue = max(0, armorValue);
// If `armorValue` should end in 0.25 or 0.75, the last digit is truncated, so re-add it here.
float armorValueFractionalPart = armorValue - floor(armorValue);
if (fabs(armorValueFractionalPart - 0.2) < 1.0e-5 || fabs(armorValueFractionalPart - 0.7) < 1.0e-5) {
armorValue += 0.05;
}

sprintf(buf2, "Wearing the %s%s will result in an armor rating of %s%i%s. ",
if (theItem->flags & ITEM_EQUIPPED) {
sprintf(buf2, "%s has an armor rating of %s%g%s. ",
((theItem->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) ? "It" : "If it has no hidden properties, it",
armorValue > 0 ? goodColorEscape : badColorEscape,
armorValue,
whiteColorEscape);
} else {
sprintf(buf2, "Wearing the %s%s will result in an armor rating of %s%g%s. ",
theName,
((theItem->flags & ITEM_IDENTIFIED) || rogue.playbackOmniscience) ? "" : ", assuming it has no hidden properties,",
(new > displayedArmorValue() ? goodColorEscape : (new < displayedArmorValue() ? badColorEscape : whiteColorEscape)),
new, whiteColorEscape);
(armorValue > displayedArmorValue() ? goodColorEscape : (armorValue < displayedArmorValue() ? badColorEscape : whiteColorEscape)),
armorValue, whiteColorEscape);
}
strcat(buf, buf2);
}
Expand Down Expand Up @@ -3185,16 +3198,16 @@ void updateEncumbrance() {
}

// Estimates the armor value of the given item, assuming the item is unenchanted.
short armorValueIfUnenchanted(item *theItem) {
short averageValue = (armorTable[theItem->kind].range.upperBound + armorTable[theItem->kind].range.lowerBound) / 2;
short strengthAdjusted = averageValue + 10 * strengthModifier(theItem) / FP_FACTOR;
float armorValueIfUnenchanted(item *theItem) {
float averageValue = (armorTable[theItem->kind].range.upperBound + armorTable[theItem->kind].range.lowerBound) / 2;
float strengthAdjusted = averageValue + 10 * strengthModifier(theItem) / FP_FACTOR;
return max(0, strengthAdjusted / 10);
}

// Calculates the armor value to display to the player (estimated if the item is unidentified).
short displayedArmorValue() {
float displayedArmorValue() {
if (!rogue.armor || (rogue.armor->flags & ITEM_IDENTIFIED)) {
return player.info.defense / 10;
return ((float) player.info.defense) / 10;
} else {
return armorValueIfUnenchanted(rogue.armor);
}
Expand Down
16 changes: 15 additions & 1 deletion src/brogue/PowerTables.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,21 @@ fixpt defenseFraction(fixpt netDefense) {
469, 453, 439, 425, 411, 398, 385, 373, 361, 349, 338, 327, 316, 306, 296, 287, 277, 268, 260, 251, 243, 235, 228, 221, 213, 207,
200, 193, 187, 181, 175, 170, 164, 159, 154, 149, 144, 139, 135, 130, 126, 122, 118, 114, 111, 107, 104, 100, 97, 94};

short idx = clamp(netDefense * 4 / 10 / FP_FACTOR + 80, 0, LAST_INDEX(POW_DEFENSE_FRACTION));
/* Examples of what this code does for different armor values:
(Using floating point instead of fixed point, and using small armor values, for clarity)
An armor value of 1.5 results in a netDefense is 15.0.
An armor value of 1.75 results in a netDefense of 17.0 (the 0.5 is lost before this function is called).
It multiplies by 4, so the last decimal place would be zero if it weren't for the 0.5 being lost (as above).
15.0 -> 60.0; 17.0 -> 68.0 (this would be 70 if not for the truncation)
It divides by 10: 60.0 -> 6.0, 68.0 -> 6.8
It adds 0.5 to compensate for the truncation: 6.0 -> 6.5; 6.8 -> 7.3
This could add anywhere from 0.2 to 0.99, but 0.5 seems like the least arbitrary choice.
Without this, the step below would round both 6.0 and 6.8 down to 6.
It converts to an integer (which rounds towards zero): 6.5 -> 6; 7.3 -> 7
It adds 80 (because some of the entries are for negative armor values) and clamps to the size of the table
This is the index into the table above.
*/
short idx = clamp((netDefense * 4 / 10 + FP_FACTOR / 2) / FP_FACTOR + 80, 0, LAST_INDEX(POW_DEFENSE_FRACTION));
return POW_DEFENSE_FRACTION[idx];
}

Expand Down
4 changes: 2 additions & 2 deletions src/brogue/Rogue.h
Original file line number Diff line number Diff line change
Expand Up @@ -3314,8 +3314,8 @@ extern "C" {
boolean itemIsHeavyWeapon(const item *theItem);
boolean itemIsPositivelyEnchanted(const item *theItem);
void updateEncumbrance(void);
short displayedArmorValue(void);
short armorValueIfUnenchanted(item *theItem);
float displayedArmorValue();
float armorValueIfUnenchanted(item *theItem);
void strengthCheck(item *theItem, boolean noisy);
void recalculateEquipmentBonuses(void);
boolean equipItem(item *theItem, boolean force, item *unequipHint);
Expand Down