rogged/src/items.c
NotAShelf 22ab6fc6eb
combat: rewrite in Zig; add basic damage types and weapon archetypes
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ic8055a1cf6bdad1aca13673ea171b4b46a6a6964
2026-04-05 20:29:12 +03:00

182 lines
3.8 KiB
C

#include "common.h"
#include "map.h"
#include "rng.h"
#include "settings.h"
#include <stddef.h>
typedef struct {
const char *name;
DamageClass dmg_class;
int base_power;
int crit_chance;
int crit_multiplier;
int status_chance;
} WeaponTemplate;
static const WeaponTemplate weapon_templates[NUM_WEAPON_TEMPLATES] = {
{"Dagger", DMG_SLASH, 1, 25, 200, 20}, {"Mace", DMG_IMPACT, 2, 10, 150, 30},
{"Spear", DMG_PIERCE, 2, 15, 175, 25}, {"Torch", DMG_FIRE, 1, 5, 150, 40},
{"Venom Blade", DMG_POISON, 1, 15, 175, 35},
};
void item_spawn(Item items[], int *count, Map *map, int floor) {
*count = 0;
// Number of items scales with floor
int num_items = 2 + rng_int(0, 3);
if (num_items > MAX_ITEMS)
num_items = MAX_ITEMS;
for (int i = 0; i < num_items; i++) {
// Find random floor position
int ix, iy;
get_random_floor_tile(map, &ix, &iy, 50);
// Don't spawn on other items
int occupied = 0;
for (int j = 0; j < *count; j++) {
if (items[j].x == ix && items[j].y == iy) {
occupied = 1;
break;
}
}
if (occupied)
continue;
// Create item
Item item;
item.x = ix;
item.y = iy;
item.floor = floor;
item.picked_up = 0;
item.dmg_class = DMG_SLASH;
item.crit_chance = 0;
item.crit_multiplier = 100;
item.status_chance = 0;
// Item type distribution
int type_roll = rng_int(0, 99);
if (type_roll < 50) {
// 50% chance for potion
item.type = ITEM_POTION;
item.power = 5 + rng_int(0, floor * 2);
} else if (type_roll < 80) {
// 30% chance for weapon, pick a random template
item.type = ITEM_WEAPON;
int tmpl_idx = rng_int(0, NUM_WEAPON_TEMPLATES - 1);
const WeaponTemplate *tmpl = &weapon_templates[tmpl_idx];
item.power = tmpl->base_power + rng_int(0, floor);
item.dmg_class = tmpl->dmg_class;
item.crit_chance = tmpl->crit_chance;
item.crit_multiplier = tmpl->crit_multiplier;
item.status_chance = tmpl->status_chance;
} else {
// 20% chance for armor
item.type = ITEM_ARMOR;
item.power = 1 + rng_int(0, floor / 2);
}
items[*count] = item;
(*count)++;
}
}
// Get item name for display
const char *item_get_name(const Item *i) {
if (i == NULL)
return "";
switch (i->type) {
case ITEM_POTION:
return "Potion";
case ITEM_WEAPON:
switch (i->dmg_class) {
case DMG_SLASH:
return "Dagger";
case DMG_IMPACT:
return "Mace";
case DMG_PIERCE:
return "Spear";
case DMG_FIRE:
return "Torch";
case DMG_POISON:
return "Venom Blade";
default:
return "Weapon";
}
case ITEM_ARMOR:
return "Armor";
default:
return "Unknown";
}
}
// Get item description
const char *item_get_description(const Item *i) {
if (i == NULL)
return "";
switch (i->type) {
case ITEM_POTION:
return "Heals HP";
case ITEM_WEAPON:
return "+Attack";
case ITEM_ARMOR:
return "+Defense";
default:
return "";
}
}
// Get item power value
int item_get_power(const Item *i) {
if (i == NULL)
return 0;
return i->power;
}
void item_use(Player *p, Item *i) {
if (p == NULL || i == NULL)
return;
switch (i->type) {
case ITEM_POTION:
// Heal player
p->hp += i->power;
if (p->hp > p->max_hp) {
p->hp = p->max_hp;
}
break;
case ITEM_WEAPON:
// Increase attack
p->attack += i->power;
break;
case ITEM_ARMOR:
// Increase defense
p->defense += i->power;
break;
default:
break;
}
}
const char *dmg_class_get_short(DamageClass dc) {
switch (dc) {
case DMG_SLASH:
return "SLA";
case DMG_IMPACT:
return "IMP";
case DMG_PIERCE:
return "PRC";
case DMG_FIRE:
return "FIR";
case DMG_POISON:
return "PSN";
default:
return "???";
}
}