Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add some utility functions, and use them.

clamp*() functions, percentChance() and randBetween().
  • Loading branch information...
commit 5e9c0f47e8b80b36f15bc60cee47b7c717e7789f 1 parent f4d0105
@piotrrak piotrrak authored
View
61 src/Avatar.cpp
@@ -35,6 +35,7 @@ FLARE. If not, see http://www.gnu.org/licenses/
#include "PowerManager.h"
#include "SharedResources.h"
#include "UtilsParsing.h"
+#include "UtilsMath.h"
#include <sstream>
@@ -694,20 +695,17 @@ bool Avatar::takeHit(const Hazard &h) {
// check miss
int avoidance = stats.avoidance;
if (stats.effects.triggered_block) avoidance *= 2;
- if (MAX_AVOIDANCE < avoidance) avoidance = MAX_AVOIDANCE;
- if (rand() % 100 > (h.accuracy - avoidance + 25)) {
+ clampCeil(avoidance, MAX_AVOIDANCE);
+ if (percentChance(avoidance - h.accuracy - 25)) {
combat_text->addMessage(msg->get("miss"), stats.pos, COMBAT_MESSAGE_MISS, true);
return false;
}
- int dmg;
- if (h.dmg_min == h.dmg_max) dmg = h.dmg_min;
- else dmg = h.dmg_min + (rand() % (h.dmg_max - h.dmg_min + 1));
+ int dmg = randBetween(h.dmg_min, h.dmg_max);
// apply elemental resistance
int vulnerable;
- if (h.trait_elemental >= 0 && unsigned(h.trait_elemental) < stats.vulnerable.size())
- {
+ if (h.trait_elemental >= 0 && unsigned(h.trait_elemental) < stats.vulnerable.size()) {
unsigned i = h.trait_elemental;
if (MAX_RESIST < stats.vulnerable[i] && stats.vulnerable[i] < 100) vulnerable = MAX_RESIST;
else vulnerable = stats.vulnerable[i];
@@ -715,10 +713,8 @@ bool Avatar::takeHit(const Hazard &h) {
}
if (!h.trait_armor_penetration) { // armor penetration ignores all absorption
- int absorption; // apply absorption
-
- if (stats.absorb_min == stats.absorb_max) absorption = stats.absorb_min;
- else absorption = stats.absorb_min + (rand() % (stats.absorb_max - stats.absorb_min + 1));
+ // apply absorption
+ int absorption = randBetween(stats.absorb_min, stats.absorb_max);
if (stats.effects.triggered_block) {
absorption += absorption + stats.absorb_max; // blocking doubles your absorb amount
@@ -833,45 +829,28 @@ void Avatar::transform() {
stats.cur_state = AVATAR_STANCE;
// damage
- if (charmed_stats->dmg_melee_min > stats.dmg_melee_min)
- stats.dmg_melee_min = charmed_stats->dmg_melee_min;
-
- if (charmed_stats->dmg_melee_max > stats.dmg_melee_max)
- stats.dmg_melee_max = charmed_stats->dmg_melee_max;
-
- if (charmed_stats->dmg_ment_min > stats.dmg_ment_min)
- stats.dmg_ment_min = charmed_stats->dmg_ment_min;
-
- if (charmed_stats->dmg_ment_max > stats.dmg_ment_max)
- stats.dmg_ment_max = charmed_stats->dmg_ment_max;
+ clampFloor(stats.dmg_melee_min, charmed_stats->dmg_melee_min);
+ clampCeil(stats.dmg_melee_max, charmed_stats->dmg_melee_max);
- if (charmed_stats->dmg_ranged_min > stats.dmg_ranged_min)
- stats.dmg_ranged_min = charmed_stats->dmg_ranged_min;
+ clampFloor(stats.dmg_ment_min, charmed_stats->dmg_ment_min);
+ clampCeil(stats.dmg_ment_max, charmed_stats->dmg_ment_max);
- if (charmed_stats->dmg_ranged_max > stats.dmg_ranged_max)
- stats.dmg_ranged_max = charmed_stats->dmg_ranged_max;
+ clampFloor(stats.dmg_ranged_min, charmed_stats->dmg_ranged_min);
+ clampCeil(stats.dmg_ranged_max, charmed_stats->dmg_ranged_max);
// dexterity
- if (charmed_stats->absorb_min > stats.absorb_min)
- stats.absorb_min = charmed_stats->absorb_min;
+ clampFloor(stats.absorb_min, charmed_stats->absorb_min);
+ clampCeil(stats.absorb_max, charmed_stats->absorb_max);
- if (charmed_stats->absorb_max > stats.absorb_max)
- stats.absorb_max = charmed_stats->absorb_max;
+ clampFloor(stats.avoidance, charmed_stats->avoidance);
- if (charmed_stats->avoidance > stats.avoidance)
- stats.avoidance = charmed_stats->avoidance;
+ clampFloor(stats.accuracy, charmed_stats->accuracy);
- if (charmed_stats->accuracy > stats.accuracy)
- stats.accuracy = charmed_stats->accuracy;
-
- if (charmed_stats->crit > stats.crit)
- stats.crit = charmed_stats->crit;
+ clampFloor(stats.crit, charmed_stats->crit);
// resistances
- for (unsigned int i=0; i<stats.vulnerable.size(); i++) {
- if (charmed_stats->vulnerable[i] < stats.vulnerable[i])
- stats.vulnerable[i] = charmed_stats->vulnerable[i];
- }
+ for (unsigned int i=0; i<stats.vulnerable.size(); i++)
+ clampCeil(stats.vulnerable[i], charmed_stats->vulnerable[i]);
loadStepFX("NULL");
}
View
17 src/BehaviorStandard.cpp
@@ -23,6 +23,7 @@ FLARE. If not, see http://www.gnu.org/licenses/
#include "MapRenderer.h"
#include "PowerManager.h"
#include "StatBlock.h"
+#include "UtilsMath.h"
BehaviorStandard::BehaviorStandard(Enemy *_e) : EnemyBehavior(_e) {
los = false;
@@ -210,7 +211,7 @@ void BehaviorStandard::checkPower() {
// check half dead power use
if (!e->stats.on_half_dead_casted && e->stats.hp <= e->stats.maxhp/2) {
- if ((rand() % 100) < e->stats.power_chance[ON_HALF_DEAD]) {
+ if (percentChance(e->stats.power_chance[ON_HALF_DEAD])) {
e->newState(ENEMY_POWER);
e->stats.activated_powerslot = ON_HALF_DEAD;
return;
@@ -220,12 +221,12 @@ void BehaviorStandard::checkPower() {
// check ranged power use
if (dist > e->stats.melee_range) {
- if ((rand() % 100) < e->stats.power_chance[RANGED_PHYS] && e->stats.power_ticks[RANGED_PHYS] == 0) {
+ if (percentChance(e->stats.power_chance[RANGED_PHYS]) && e->stats.power_ticks[RANGED_PHYS] == 0) {
e->newState(ENEMY_POWER);
e->stats.activated_powerslot = RANGED_PHYS;
return;
}
- if ((rand() % 100) < e->stats.power_chance[RANGED_MENT] && e->stats.power_ticks[RANGED_MENT] == 0) {
+ if (percentChance(e->stats.power_chance[RANGED_MENT]) && e->stats.power_ticks[RANGED_MENT] == 0) {
e->newState(ENEMY_POWER);
e->stats.activated_powerslot = RANGED_MENT;
return;
@@ -234,12 +235,12 @@ void BehaviorStandard::checkPower() {
}
else { // check melee power use
- if ((rand() % 100) < e->stats.power_chance[MELEE_PHYS] && e->stats.power_ticks[MELEE_PHYS] == 0) {
+ if (percentChance(e->stats.power_chance[MELEE_PHYS]) && e->stats.power_ticks[MELEE_PHYS] == 0) {
e->newState(ENEMY_POWER);
e->stats.activated_powerslot = MELEE_PHYS;
return;
}
- if ((rand() % 100) < e->stats.power_chance[MELEE_MENT] && e->stats.power_ticks[MELEE_MENT] == 0) {
+ if (percentChance(e->stats.power_chance[MELEE_MENT]) && e->stats.power_ticks[MELEE_MENT] == 0) {
e->newState(ENEMY_POWER);
e->stats.activated_powerslot = MELEE_MENT;
return;
@@ -324,7 +325,7 @@ void BehaviorStandard::checkMove() {
if (dist < e->stats.melee_range) {
// too close, do nothing
}
- else if ((rand() % 100) < e->stats.chance_pursue) {
+ else if (percentChance(e->stats.chance_pursue)) {
if (e->move()) {
e->newState(ENEMY_MOVE);
@@ -469,7 +470,7 @@ void BehaviorStandard::updateState() {
e->stats.effects.clearEffects();
}
if (e->activeAnimation->isSecondLastFrame()) {
- if ((rand() % 100) < e->stats.power_chance[ON_DEATH])
+ if (percentChance(e->stats.power_chance[ON_DEATH]))
e->powers->activate(e->stats.power_index[ON_DEATH], &e->stats, e->stats.pos);
}
if (e->activeAnimation->isLastFrame()) e->stats.corpse = true; // puts renderable under object layer
@@ -485,7 +486,7 @@ void BehaviorStandard::updateState() {
e->stats.effects.clearEffects();
}
if (e->activeAnimation->isSecondLastFrame()) {
- if ((rand() % 100) < e->stats.power_chance[ON_DEATH])
+ if (percentChance(e->stats.power_chance[ON_DEATH]))
e->powers->activate(e->stats.power_index[ON_DEATH], &e->stats, e->stats.pos);
}
if (e->activeAnimation->isLastFrame()) e->stats.corpse = true; // puts renderable under object layer
View
25 src/Enemy.cpp
@@ -30,6 +30,7 @@ FLARE. If not, see http://www.gnu.org/licenses/
#include "MapRenderer.h"
#include "PowerManager.h"
#include "SharedResources.h"
+#include "UtilsMath.h"
#include <sstream>
@@ -166,21 +167,18 @@ bool Enemy::takeHit(const Hazard &h) {
// if it's a miss, do nothing
int avoidance = stats.avoidance;
- if (MAX_AVOIDANCE < avoidance) avoidance = MAX_AVOIDANCE;
- if (rand() % 100 > (h.accuracy - avoidance + 25)) {
+ clampCeil(avoidance, MAX_AVOIDANCE);
+ if (percentChance(avoidance - h.accuracy - 25)) {
combat_text->addMessage(msg->get("miss"), stats.pos, COMBAT_MESSAGE_MISS, false);
return false;
}
// calculate base damage
- int dmg;
- if (h.dmg_max > h.dmg_min) dmg = rand() % (h.dmg_max - h.dmg_min + 1) + h.dmg_min;
- else dmg = h.dmg_min;
+ int dmg = randBetween(h.dmg_min, h.dmg_max);
// apply elemental resistance
int vulnerable;
- if (h.trait_elemental >= 0 && unsigned(h.trait_elemental) < stats.vulnerable.size())
- {
+ if (h.trait_elemental >= 0 && unsigned(h.trait_elemental) < stats.vulnerable.size()) {
unsigned i = h.trait_elemental;
if (MAX_RESIST < stats.vulnerable[i] && stats.vulnerable[i] < 100) vulnerable = MAX_RESIST;
else vulnerable = stats.vulnerable[i];
@@ -188,9 +186,8 @@ bool Enemy::takeHit(const Hazard &h) {
}
if (!h.trait_armor_penetration) { // armor penetration ignores all absorption
- int absorption; // substract absorption from armor
- if (stats.absorb_min == stats.absorb_max) absorption = stats.absorb_min;
- else absorption = stats.absorb_min + (rand() % (stats.absorb_max - stats.absorb_min + 1));
+ // substract absorption from armor
+ int absorption = randBetween(stats.absorb_min, stats.absorb_max);
if (absorption > 0) {
if ((dmg*100)/absorption > MAX_ABSORB)
absorption = (absorption * MAX_ABSORB) / 100;
@@ -212,7 +209,7 @@ bool Enemy::takeHit(const Hazard &h) {
if (stats.effects.stun || stats.effects.speed < 100)
true_crit_chance += h.trait_crits_impaired;
- bool crit = (rand() % 100) < true_crit_chance;
+ bool crit = percentChance(true_crit_chance);
if (crit) {
dmg = dmg + h.dmg_max;
map->shaky_cam_ticks = MAX_FRAMES_PER_SEC/2;
@@ -249,14 +246,14 @@ bool Enemy::takeHit(const Hazard &h) {
if (heal_amt == 0 && dmg > 0) heal_amt = 1;
combat_text->addMessage(msg->get("+%d HP",heal_amt), h.src_stats->pos, COMBAT_MESSAGE_BUFF, true);
h.src_stats->hp += heal_amt;
- if (h.src_stats->hp > h.src_stats->maxhp) h.src_stats->hp = h.src_stats->maxhp;
+ clampCeil(h.src_stats->hp, h.src_stats->maxhp);
}
if (h.mp_steal != 0) {
int heal_amt = (dmg * h.mp_steal) / 100;
if (heal_amt == 0 && dmg > 0) heal_amt = 1;
combat_text->addMessage(msg->get("+%d MP",heal_amt), h.src_stats->pos, COMBAT_MESSAGE_BUFF, true);
h.src_stats->mp += heal_amt;
- if (h.src_stats->mp > h.src_stats->maxmp) h.src_stats->mp = h.src_stats->maxmp;
+ clampCeil(h.src_stats->mp, h.src_stats->maxmp);
}
// post effect power
@@ -285,7 +282,7 @@ bool Enemy::takeHit(const Hazard &h) {
else if (!stats.effects.stun) {
stats.cur_state = ENEMY_HIT;
// roll to see if the enemy's ON_HIT power is casted
- if ((rand() % 100) < stats.power_chance[ON_HIT]) {
+ if (percentChance(stats.power_chance[ON_HIT])) {
powers->activate(stats.power_index[ON_HIT], &stats, stats.pos);
}
}
View
3  src/MapRenderer.cpp
@@ -24,6 +24,7 @@ FLARE. If not, see http://www.gnu.org/licenses/
#include "PowerManager.h"
#include "StatBlock.h"
#include "UtilsFileSystem.h"
+#include "UtilsMath.h"
#include "UtilsParsing.h"
#include <stdint.h>
@@ -102,7 +103,7 @@ void MapRenderer::push_enemy_group(Map_Group g) {
// actual places, so have an upper bound of tries.
// random number of enemies
- int enemies_to_spawn = g.numbermin + rand() % (g.numbermax + 1 - g.numbermin);
+ int enemies_to_spawn = randBetween(g.numbermin, g.numbermax);
// pick an upper bound, which is definitely larger than threetimes the enemy number to spawn.
int allowed_misses = 3 * g.numbermax;
View
7 src/PowerManager.cpp
@@ -33,6 +33,7 @@ FLARE. If not, see http://www.gnu.org/licenses/
#include "StatBlock.h"
#include "MapCollision.h"
#include "UtilsFileSystem.h"
+#include "UtilsMath.h"
#include "UtilsParsing.h"
#include <cmath>
@@ -683,10 +684,8 @@ bool PowerManager::effect(StatBlock *src_stats, int power_index) {
// heal for ment weapon damage * damage multiplier
int heal_max = (int)ceil(src_stats->dmg_ment_max * powers[power_index].damage_multiplier / 100.0) + (src_stats->get_mental()*src_stats->bonus_per_mental);
int heal_min = (int)ceil(src_stats->dmg_ment_min * powers[power_index].damage_multiplier / 100.0) + (src_stats->get_mental()*src_stats->bonus_per_mental);
- if (heal_max > heal_min)
- magnitude = rand() % (heal_max - heal_min) + heal_min;
- else // avoid div by 0
- magnitude = heal_min;
+ magnitude = randBetween(heal_min, heal_max-1);
+
comb->addMessage(msg->get("+%d HP",magnitude), src_stats->pos, COMBAT_MESSAGE_BUFF, src_stats->hero);
src_stats->hp += magnitude;
if (src_stats->hp > src_stats->maxhp) src_stats->hp = src_stats->maxhp;
View
84 src/UtilsMath.h
@@ -0,0 +1,84 @@
+/*
+Copyright © 2012 Piotr Rak
+
+This file is part of FLARE.
+
+FLARE is free software: you can redistribute it and/or modify it under the terms
+of the GNU General Public License as published by the Free Software Foundation,
+either version 3 of the License, or (at your option) any later version.
+
+FLARE is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+FLARE. If not, see http://www.gnu.org/licenses/
+*/
+
+#pragma once
+#ifndef UTILS_MATH_H
+#define UTILS_MATH_H 1
+
+#include <cassert>
+#include <cstdlib>
+#include <algorithm> // for std::min()/std::max()
+
+/**
+ * Clamps value to floor.
+ *
+ * Postcondition: value >= floor
+ */
+template <typename Ty1_, typename Ty2_>
+inline void clampFloor(Ty1_& value, Ty2_ floor) {
+ value = std::max<Ty1_>(value, floor);
+}
+
+/**
+ * Clamps value to ceiling.
+ *
+ * Postcondition: value <= ceiling
+ */
+template <typename Ty1_, typename Ty2_>
+inline void clampCeil(Ty1_& value, Ty2_ ceiling) {
+ value = std::min<Ty1_>(value, ceiling);
+}
+
+/**
+ * Clamps value.
+ *
+ * Postcondition: floor <= value <= ceiling
+ */
+template <typename Ty1_, typename Ty2_>
+inline void clamp(Ty1_& value, Ty2_ floor, Ty2_ ceiling) {
+ clampFloor(value, floor);
+ clampCeil(value, ceiling);
+}
+
+/**
+ * Returns sign of value.
+ */
+template <typename Ty_>
+inline Ty_ signum(Ty_ value)
+{
+ return (Ty_(0) < value) - (value < Ty_(0));
+}
+
+/**
+ * Returns random number between minVal and maxVal.
+ */
+inline int randBetween(int minVal, int maxVal)
+{
+ if (minVal == maxVal) return minVal;
+ int d = maxVal - minVal;
+ return minVal + (rand() % (d + signum(d)));
+}
+
+/**
+ * Returns true with random percent chance.
+ */
+inline bool percentChance(int percent)
+{
+ return rand() % 100 < percent;
+}
+
+#endif // UTILS_MATH_H

0 comments on commit 5e9c0f4

Please sign in to comment.
Something went wrong with that request. Please try again.