forked from NotAShelf/rogged
combat: tune damage math and enemy scaling
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I983d5980f8d14ccebc6b681100af8a146a6a6964
This commit is contained in:
parent
ee116ef33f
commit
1875d94e44
3 changed files with 34 additions and 14 deletions
|
|
@ -7,8 +7,9 @@ fn rng(min: c_int, max: c_int) c_int {
|
|||
}
|
||||
|
||||
fn applyResistance(damage: c_int, resistance: c_int) c_int {
|
||||
if (resistance >= 100) return 0;
|
||||
const factor = 100 - resistance;
|
||||
var r = resistance;
|
||||
if (r > 75) r = 75;
|
||||
const factor = 100 - r;
|
||||
var result = @divTrunc(damage * factor, 100);
|
||||
if (result < 1) result = 1;
|
||||
return result;
|
||||
|
|
@ -63,15 +64,17 @@ pub fn playerAttack(p: [*c]c.Player, e: [*c]c.Enemy) void {
|
|||
base_attack -= c.WEAKEN_ATTACK_REDUCTION;
|
||||
if (base_attack < 1) base_attack = 1;
|
||||
|
||||
const variance = rng(80, 120);
|
||||
var damage = @divTrunc(base_attack * variance, 100);
|
||||
if (damage < 1) damage = 1;
|
||||
var damage = base_attack;
|
||||
|
||||
if (rng(0, 99) < crit_chance) {
|
||||
damage = @divTrunc(damage * crit_mult, 100);
|
||||
event.last.is_critical = 1;
|
||||
}
|
||||
|
||||
const variance = rng(80, 120);
|
||||
damage = @divTrunc(damage * variance, 100);
|
||||
if (damage < 1) damage = 1;
|
||||
|
||||
const res_index: usize = @intCast(dmg_class);
|
||||
if (res_index < c.NUM_DMG_CLASSES) {
|
||||
damage = applyResistance(damage, e[0].resistance[res_index]);
|
||||
|
|
@ -139,15 +142,19 @@ pub fn enemyAttack(e: [*c]c.Enemy, p: [*c]c.Player) void {
|
|||
base_damage -= p[0].defense;
|
||||
if (base_damage < 1) base_damage = 1;
|
||||
|
||||
const variance = rng(80, 120);
|
||||
var damage = @divTrunc(base_damage * variance, 100);
|
||||
if (damage < 1) damage = 1;
|
||||
var damage = base_damage;
|
||||
|
||||
if (rng(0, 99) < c.ENEMY_CRIT_CHANCE) {
|
||||
damage = @divTrunc(damage * c.ENEMY_CRIT_MULT, 100);
|
||||
const e_crit_chance = if (e[0].crit_chance > 0) e[0].crit_chance else c.ENEMY_CRIT_CHANCE;
|
||||
const e_crit_mult = if (e[0].crit_mult > 0) e[0].crit_mult else c.ENEMY_CRIT_MULT;
|
||||
if (rng(0, 99) < e_crit_chance) {
|
||||
damage = @divTrunc(damage * e_crit_mult, 100);
|
||||
event.last.is_critical = 1;
|
||||
}
|
||||
|
||||
const variance = rng(80, 120);
|
||||
damage = @divTrunc(damage * variance, 100);
|
||||
if (damage < 1) damage = 1;
|
||||
|
||||
if (p[0].block > 0 and rng(0, 99) < 30) {
|
||||
var blocked = p[0].block;
|
||||
if (blocked > damage) blocked = damage;
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ typedef struct {
|
|||
int resistance[NUM_DMG_CLASSES];
|
||||
DamageClass dmg_class;
|
||||
int status_chance;
|
||||
int crit_chance; // crit chance percentage (0-100)
|
||||
int crit_mult; // crit damage multiplier percentage (e.g. 150 = 1.5x)
|
||||
// status effects
|
||||
StatusEffect effects[MAX_EFFECTS];
|
||||
int effect_count;
|
||||
|
|
|
|||
19
src/enemy.c
19
src/enemy.c
|
|
@ -48,16 +48,21 @@ void enemy_spawn(Enemy enemies[], int *count, Map *map, Player *p, int floor) {
|
|||
e.effect_count = 0;
|
||||
|
||||
// Stats based on type and floor
|
||||
// Attack scales with floor: +1 per 2 floors so deeper enemies hit harder
|
||||
int floor_atk = floor / 2;
|
||||
|
||||
switch (e.type) {
|
||||
case ENEMY_GOBLIN:
|
||||
e.max_hp = ENEMY_BASE_HP + floor;
|
||||
e.hp = e.max_hp;
|
||||
e.attack = ENEMY_BASE_ATTACK;
|
||||
e.attack = ENEMY_BASE_ATTACK + floor_atk;
|
||||
e.speed = 55 + rng_int(0, 10);
|
||||
e.dodge = 15;
|
||||
e.block = 0;
|
||||
e.dmg_class = DMG_POISON;
|
||||
e.status_chance = 15;
|
||||
e.crit_chance = 8;
|
||||
e.crit_mult = 150;
|
||||
e.resistance[DMG_SLASH] = 0;
|
||||
e.resistance[DMG_IMPACT] = 0;
|
||||
e.resistance[DMG_PIERCE] = 0;
|
||||
|
|
@ -67,27 +72,31 @@ void enemy_spawn(Enemy enemies[], int *count, Map *map, Player *p, int floor) {
|
|||
case ENEMY_SKELETON:
|
||||
e.max_hp = ENEMY_BASE_HP + floor + 2;
|
||||
e.hp = e.max_hp;
|
||||
e.attack = ENEMY_BASE_ATTACK + 1;
|
||||
e.attack = ENEMY_BASE_ATTACK + 1 + floor_atk;
|
||||
e.speed = 70 + rng_int(0, 10);
|
||||
e.dodge = 5;
|
||||
e.block = 0;
|
||||
e.dmg_class = DMG_SLASH;
|
||||
e.status_chance = 10;
|
||||
e.crit_chance = 6;
|
||||
e.crit_mult = 150;
|
||||
e.resistance[DMG_SLASH] = -25;
|
||||
e.resistance[DMG_IMPACT] = -50;
|
||||
e.resistance[DMG_PIERCE] = 50;
|
||||
e.resistance[DMG_FIRE] = 25;
|
||||
e.resistance[DMG_POISON] = 100;
|
||||
e.resistance[DMG_POISON] = 75;
|
||||
break;
|
||||
case ENEMY_ORC:
|
||||
e.max_hp = ENEMY_BASE_HP + floor + 4;
|
||||
e.hp = e.max_hp;
|
||||
e.attack = ENEMY_BASE_ATTACK + 2;
|
||||
e.attack = ENEMY_BASE_ATTACK + 2 + floor_atk;
|
||||
e.speed = 85 + rng_int(0, 10);
|
||||
e.dodge = 0;
|
||||
e.block = 3;
|
||||
e.dmg_class = DMG_IMPACT;
|
||||
e.status_chance = 20;
|
||||
e.crit_chance = 5;
|
||||
e.crit_mult = 175;
|
||||
e.resistance[DMG_SLASH] = 0;
|
||||
e.resistance[DMG_IMPACT] = 25;
|
||||
e.resistance[DMG_PIERCE] = -25;
|
||||
|
|
@ -103,6 +112,8 @@ void enemy_spawn(Enemy enemies[], int *count, Map *map, Player *p, int floor) {
|
|||
e.block = 0;
|
||||
e.dmg_class = DMG_IMPACT;
|
||||
e.status_chance = 0;
|
||||
e.crit_chance = ENEMY_CRIT_CHANCE;
|
||||
e.crit_mult = ENEMY_CRIT_MULT;
|
||||
memset(e.resistance, 0, sizeof(e.resistance));
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue