diff --git a/src/act.h b/src/act.h index f4694d1..f4ce33f 100644 --- a/src/act.h +++ b/src/act.h @@ -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 diff --git a/src/act.item.c b/src/act.item.c index c7a03d8..de2c1de 100644 --- a/src/act.item.c +++ b/src/act.item.c @@ -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); +} diff --git a/src/class.c b/src/class.c index 7081ef4..a81c1cf 100644 --- a/src/class.c +++ b/src/class.c @@ -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 */ diff --git a/src/db.c b/src/db.c index affbb5c..cca20cd 100644 --- a/src/db.c +++ b/src/db.c @@ -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 ).", 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; +} diff --git a/src/db.h b/src/db.h index bfb0d91..e2fc090 100644 --- a/src/db.h +++ b/src/db.h @@ -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); diff --git a/src/genwld.c b/src/genwld.c index ce2211a..f6f3396 100644 --- a/src/genwld.c +++ b/src/genwld.c @@ -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++) { diff --git a/src/interpreter.c b/src/interpreter.c index 2517f44..cecfc7e 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -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 }, diff --git a/src/oasis.h b/src/oasis.h index 8dc8e23..4e48c53 100644 --- a/src/oasis.h +++ b/src/oasis.h @@ -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 diff --git a/src/redit.c b/src/redit.c index de23817..6cee02d 100644 --- a/src/redit.c +++ b/src/redit.c @@ -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: \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': diff --git a/src/structs.h b/src/structs.h index b95c76e..77f27b8 100644 --- a/src/structs.h +++ b/src/structs.h @@ -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