Forage command update

This commit is contained in:
kinther 2025-12-23 09:24:09 -08:00
parent 715e778b29
commit 0267a4c091
10 changed files with 280 additions and 0 deletions

View file

@ -159,6 +159,7 @@ ACMD(do_remove);
ACMD(do_wear);
ACMD(do_wield);
ACMD(do_skin);
ACMD(do_forage);
/*****************************************************************************
* Begin Functions and defines for act.movement.c

View file

@ -2039,3 +2039,58 @@ ACMD(do_skin)
extract_obj(corpse);
}
ACMD(do_forage)
{
room_rnum room;
struct forage_entry *entry, *best = NULL;
struct obj_data *obj;
int total;
int best_dc = -1;
int prof_bonus, cost;
int delay_seconds;
room = IN_ROOM(ch);
if (room == NOWHERE) {
send_to_char(ch, "You can't do that here.\r\n");
return;
}
prof_bonus = GET_PROFICIENCY(GET_SKILL(ch, SKILL_SURVIVAL));
cost = MAX(1, 10 - prof_bonus);
if (!IS_NPC(ch) && GET_MOVE(ch) < cost) {
send_to_char(ch, "You are too exhausted to forage.\r\n");
return;
}
delay_seconds = rand_number(8, 12);
WAIT_STATE(ch, delay_seconds * PASSES_PER_SEC);
if (!IS_NPC(ch))
GET_MOVE(ch) = MAX(0, GET_MOVE(ch) - cost);
total = roll_skill_check(ch, SKILL_SURVIVAL, 0, NULL);
for (entry = world[room].forage; entry; entry = entry->next) {
if (total >= entry->dc && entry->dc > best_dc) {
best = entry;
best_dc = entry->dc;
}
}
if (best) {
obj = read_object(best->obj_vnum, VIRTUAL);
if (obj) {
obj_to_char(obj, ch);
act("You take some time to look around, and end up finding $p.", FALSE, ch, obj, 0, TO_CHAR);
act("$n takes some time to look around, and ends up finding $p.", FALSE, ch, obj, 0, TO_ROOM);
gain_skill(ch, "survival", TRUE);
return;
}
}
send_to_char(ch, "You take some time to look around, but don't find anything.\r\n");
act("$n takes some time to look around, but doesn't find anything.", FALSE, ch, 0, 0, TO_ROOM);
gain_skill(ch, "survival", FALSE);
}

View file

@ -454,6 +454,7 @@ void grant_class_skills(struct char_data *ch, bool reset)
SET_SKILL(ch, SKILL_SURVIVAL, 5);
break;
}
}
/* Some initializations for characters, including initial skills */

View file

@ -1352,6 +1352,7 @@ void parse_room(FILE *fl, int virtual_nr)
world[room_nr].dir_option[i] = NULL;
world[room_nr].ex_description = NULL;
world[room_nr].forage = NULL;
snprintf(buf, sizeof(buf), "SYSERR: Format error in room #%d (expecting D/E/S)", virtual_nr);
@ -1373,6 +1374,38 @@ void parse_room(FILE *fl, int virtual_nr)
new_descr->next = world[room_nr].ex_description;
world[room_nr].ex_description = new_descr;
break;
case 'F':
for (;;) {
obj_vnum ovnum;
int dc;
if (!get_line(fl, line)) {
log("SYSERR: Unexpected EOF while reading 'F' block in room #%d.", virtual_nr);
break;
}
if (sscanf(line, "%d %d", &ovnum, &dc) != 2) {
log("SYSERR: Bad 'F' line in room #%d: '%s' (need <obj_vnum> <dc>).", virtual_nr, line);
continue;
}
if (ovnum == 0 && dc == 0)
break;
struct forage_entry *e;
struct forage_entry *tail;
CREATE(e, struct forage_entry, 1);
e->obj_vnum = ovnum;
e->dc = dc;
e->next = NULL;
if (!world[room_nr].forage) {
world[room_nr].forage = e;
} else {
tail = world[room_nr].forage;
while (tail->next)
tail = tail->next;
tail->next = e;
}
}
break;
case 'S': /* end of room */
/* DG triggers -- script is defined after the end of the room */
letter = fread_letter(fl);
@ -4453,3 +4486,28 @@ struct skin_yield_entry *copy_skin_yields(struct skin_yield_entry *src)
}
return head;
}
void free_forage_list(struct forage_entry *list)
{
struct forage_entry *e, *next;
for (e = list; e; e = next) {
next = e->next;
free(e);
}
}
struct forage_entry *copy_forage_list(struct forage_entry *src)
{
struct forage_entry *head = NULL, *tail = NULL, *e;
for (; src; src = src->next) {
CREATE(e, struct forage_entry, 1);
*e = *src;
e->next = NULL;
if (!head) head = e;
else tail->next = e;
tail = e;
}
return head;
}

View file

@ -260,6 +260,8 @@ void new_mobile_data(struct char_data *ch);
void equip_mob_from_loadout(struct char_data *mob);
void free_skin_yields(struct skin_yield_entry *list);
struct skin_yield_entry *copy_skin_yields(struct skin_yield_entry *src);
void free_forage_list(struct forage_entry *list);
struct forage_entry *copy_forage_list(struct forage_entry *src);
zone_rnum real_zone(zone_vnum vnum);
room_rnum real_room(room_vnum vnum);

View file

@ -373,6 +373,13 @@ int save_rooms(zone_rnum rzone)
"%s~\n", xdesc->keyword, buf);
}
}
if (room->forage) {
struct forage_entry *entry;
fprintf(sf, "F\n");
for (entry = room->forage; entry; entry = entry->next)
fprintf(sf, "%d %d\n", entry->obj_vnum, entry->dc);
fprintf(sf, "0 0\n");
}
fprintf(sf, "S\n");
script_save_to_disk(sf, room, WLD_TRIGGER);
}
@ -439,6 +446,9 @@ int copy_room_strings(struct room_data *dest, struct room_data *source)
if (source->ex_description)
copy_ex_descriptions(&dest->ex_description, source->ex_description);
if (source->forage)
dest->forage = copy_forage_list(source->forage);
return TRUE;
}
@ -453,6 +463,9 @@ int free_room_strings(struct room_data *room)
free(room->description);
if (room->ex_description)
free_ex_descriptions(room->ex_description);
if (room->forage)
free_forage_list(room->forage);
room->forage = NULL;
/* Free exits. */
for (i = 0; i < DIR_COUNT; i++) {

View file

@ -281,6 +281,7 @@ cpp_extern const struct command_info cmd_info[] = {
{ "set" , "set" , POS_DEAD , do_set , LVL_IMMORT, 0 },
{ "shout" , "sho" , POS_RESTING , do_gen_comm , 0, SCMD_SHOUT },
{ "skills" , "sk" , POS_SLEEPING, do_skills , 0, 0 },
{ "forage" , "for" , POS_STANDING, do_forage , 0, 0 },
{ "skin" , "skin" , POS_STANDING, do_skin, 0, 0 },
{ "show" , "show" , POS_DEAD , do_show , LVL_IMMORT, 0 },
{ "shutdow" , "shutdow" , POS_DEAD , do_shutdown , LVL_IMPL, 0 },

View file

@ -227,6 +227,9 @@ extern const char *nrm, *grn, *cyn, *yel;
#define REDIT_EXTRADESC_DESCRIPTION 16
#define REDIT_DELETE 17
#define REDIT_COPY 18
#define REDIT_FORAGE_MENU 19
#define REDIT_FORAGE_ADD 20
#define REDIT_FORAGE_DELETE 21
/* Submodes of ZEDIT connectedness. */
#define ZEDIT_MAIN_MENU 0

View file

@ -29,6 +29,7 @@ static void redit_disp_exit_menu(struct descriptor_data *d);
static void redit_disp_exit_flag_menu(struct descriptor_data *d);
static void redit_disp_flag_menu(struct descriptor_data *d);
static void redit_disp_sector_menu(struct descriptor_data *d);
static void redit_disp_forage_menu(struct descriptor_data *d);
static void redit_disp_menu(struct descriptor_data *d);
/* Utils and exported functions. */
@ -161,6 +162,7 @@ static void redit_setup_new(struct descriptor_data *d)
OLC_ROOM(d)->number = NOWHERE;
OLC_ITEM_TYPE(d) = WLD_TRIGGER;
OLC_ROOM(d)->proto_script = OLC_SCRIPT(d) = NULL;
OLC_ROOM(d)->forage = NULL;
OLC_VAL(d) = 0;
}
@ -221,6 +223,8 @@ void redit_setup_existing(struct descriptor_data *d, int real_num)
}
}
room->forage = copy_forage_list(world[real_num].forage);
/* Attach copy of room to player's descriptor. */
OLC_ROOM(d) = room;
OLC_VAL(d) = 0;
@ -412,16 +416,57 @@ static void redit_disp_sector_menu(struct descriptor_data *d)
OLC_MODE(d) = REDIT_SECTOR;
}
static int redit_forage_count(struct forage_entry *list)
{
int count = 0;
for (; list; list = list->next)
count++;
return count;
}
static void redit_disp_forage_menu(struct descriptor_data *d)
{
struct forage_entry *entry;
int i = 0;
get_char_colors(d->character);
clear_screen(d);
write_to_output(d, "Forage table:\r\n");
for (entry = OLC_ROOM(d)->forage; entry; entry = entry->next) {
obj_rnum rnum = real_object(entry->obj_vnum);
const char *sdesc = (rnum != NOTHING) ? obj_proto[rnum].short_description : "Unknown object";
write_to_output(d, "%s%2d%s) [%s%d%s] DC %s%d%s - %s%s%s\r\n",
grn, ++i, nrm,
cyn, entry->obj_vnum, nrm,
yel, entry->dc, nrm,
yel, sdesc, nrm);
}
if (i == 0)
write_to_output(d, " None.\r\n");
write_to_output(d,
"\r\n%sA%s) Add item\r\n"
"%sD%s) Delete item\r\n"
"%sQ%s) Quit\r\n"
"Enter choice : ",
grn, nrm, grn, nrm, grn, nrm);
OLC_MODE(d) = REDIT_FORAGE_MENU;
}
/* The main menu. */
static void redit_disp_menu(struct descriptor_data *d)
{
char buf1[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
struct room_data *room;
int forage_count;
get_char_colors(d->character);
clear_screen(d);
room = OLC_ROOM(d);
forage_count = redit_forage_count(room->forage);
sprintbitarray(room->room_flags, room_bits, RF_ARRAY_MAX, buf1);
sprinttype(room->sector_type, sector_types, buf2, sizeof(buf2));
@ -493,6 +538,7 @@ static void redit_disp_menu(struct descriptor_data *d)
"%s9%s) Exit up : %s%d\r\n"
"%sA%s) Exit down : %s%d\r\n"
"%sF%s) Extra descriptions menu\r\n"
"%sG%s) Forage table: %s%d%s entries\r\n"
"%sS%s) Script : %s%s\r\n"
"%sW%s) Copy Room\r\n"
"%sX%s) Delete Room\r\n"
@ -505,6 +551,7 @@ static void redit_disp_menu(struct descriptor_data *d)
room->dir_option[DOWN] && room->dir_option[DOWN]->to_room != NOWHERE ?
world[room->dir_option[DOWN]->to_room].number : -1,
grn, nrm,
grn, nrm, cyn, forage_count, nrm,
grn, nrm, cyn, OLC_SCRIPT(d) ? "Set." : "Not Set.",
grn, nrm,
grn, nrm,
@ -655,6 +702,10 @@ void redit_parse(struct descriptor_data *d, char *arg)
OLC_DESC(d) = OLC_ROOM(d)->ex_description;
redit_disp_extradesc_menu(d);
break;
case 'g':
case 'G':
redit_disp_forage_menu(d);
break;
case 'w':
case 'W':
write_to_output(d, "Copy what room? ");
@ -727,6 +778,91 @@ void redit_parse(struct descriptor_data *d, char *arg)
OLC_ROOM(d)->sector_type = number;
break;
case REDIT_FORAGE_MENU:
switch (LOWER(*arg)) {
case 'a':
write_to_output(d, "Enter object vnum and DC: ");
OLC_MODE(d) = REDIT_FORAGE_ADD;
return;
case 'd':
if (!OLC_ROOM(d)->forage) {
write_to_output(d, "No forage entries to delete.\r\n");
redit_disp_forage_menu(d);
} else {
write_to_output(d, "Delete which entry (number)? ");
OLC_MODE(d) = REDIT_FORAGE_DELETE;
}
return;
case 'q':
redit_disp_menu(d);
return;
default:
redit_disp_forage_menu(d);
return;
}
case REDIT_FORAGE_ADD: {
int vnum, dc;
struct forage_entry *entry;
if (sscanf(arg, "%d %d", &vnum, &dc) != 2) {
write_to_output(d, "Usage: <vnum> <dc>\r\n");
redit_disp_forage_menu(d);
return;
}
if (vnum <= 0 || dc <= 0) {
write_to_output(d, "Both vnum and DC must be positive.\r\n");
redit_disp_forage_menu(d);
return;
}
if (real_object(vnum) == NOTHING) {
write_to_output(d, "That object vnum doesn't exist.\r\n");
redit_disp_forage_menu(d);
return;
}
CREATE(entry, struct forage_entry, 1);
entry->obj_vnum = vnum;
entry->dc = dc;
entry->next = OLC_ROOM(d)->forage;
OLC_ROOM(d)->forage = entry;
OLC_VAL(d) = 1;
redit_disp_forage_menu(d);
return;
}
case REDIT_FORAGE_DELETE: {
struct forage_entry *entry = OLC_ROOM(d)->forage;
struct forage_entry *prev = NULL;
int count = 0;
number = atoi(arg);
if (number <= 0) {
redit_disp_forage_menu(d);
return;
}
while (entry && ++count < number) {
prev = entry;
entry = entry->next;
}
if (!entry) {
write_to_output(d, "Invalid entry number.\r\n");
redit_disp_forage_menu(d);
return;
}
if (prev)
prev->next = entry->next;
else
OLC_ROOM(d)->forage = entry->next;
free(entry);
OLC_VAL(d) = 1;
redit_disp_forage_menu(d);
return;
}
case REDIT_EXIT_MENU:
switch (*arg) {
case '0':

View file

@ -816,6 +816,8 @@ struct room_direction_data
room_rnum to_room; /**< Where direction leads, or NOWHERE if not defined */
};
struct forage_entry;
/** The Room Structure. */
struct room_data
{
@ -834,6 +836,7 @@ struct room_data
struct obj_data *contents; /**< List of items in room */
struct char_data *people; /**< List of NPCs / PCs in room */
struct forage_entry *forage; /**< Forage table entries for this room */
struct list_data * events;
};
@ -1350,6 +1353,13 @@ struct skin_yield_entry {
struct skin_yield_entry *next;
};
/* Forage table entries attached to rooms */
struct forage_entry {
obj_vnum obj_vnum; /* object to create on success */
int dc; /* DC required */
struct forage_entry *next;
};
/* Config structs */
/** The game configuration structure used for configurating the game play