Food update

This commit is contained in:
kinther 2025-10-03 13:02:24 -07:00
parent 61b0435d5d
commit b23927580a
10 changed files with 348 additions and 41 deletions

View file

@ -1 +1,10 @@
$
#1
board immortal~
the immortal board~
The immortal bulletin board is here.~
Made specifically for immortals to post on.
~
13 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0
0 0 0 0 0
$~

View file

@ -331,5 +331,57 @@ of liquid.
~
17 0 0 0 0 a 0 0 0 0 0 0 0
4 4 0 0
1 15 0 0 0
9 8 0 0 0
#139
skewer erdlu meat~
an erdlu meat skewer~
A skewer with some browned meat is here.~
A thin piece of wood has been carved into a long skewer, with one end tied
into a small hook. Pieces of dark erdlu meat have been pressed into the skewer
and cooked over an open fire.
~
19 0 0 0 0 ap 0 0 0 0 0 0 0
2 2 1 0
1 12 0 0 0
#140
steak carru thick~
a thick carru steak~
A thick, cooked steak is here.~
This steak is a very large piece of meat that has been cooked over an open
fire. Grill marks can be seen on both sides which form small X's.
~
19 0 0 0 0 a 0 0 0 0 0 0 0
8 8 1 0
2 20 0 0 0
#141
bacon aprig plate~
a plate of aprig bacon~
A plate with several slices of cooked bacon is here.~
This plate is small, but piled high with pieces of bacon. They are cooked to
the point that they are still chewy but not quite crunchy.
~
19 0 0 0 0 a 0 0 0 0 0 0 0
4 4 1 0
1 18 0 0 0
#142
bread hunk~
a hunk of bread~
A piece of bread has been torn from a loaf and left here.~
Torn from a larger piece of bread, this hunk is a still a decent size. The
crust is brown and the inside is fluffy.
~
19 0 0 0 0 a 0 0 0 0 0 0 0
2 2 1 0
1 14 0 0 0
#143
cot small~
a small cot~
A small cot has been set up here.~
This cot is made primarily from pieces of wood that are lashed together with
rope. Pieces of hide have been tied down, providing a soft yet supportive place
for someone to rest upon.
~
6 0 0 0 0 0 0 0 0 0 0 0 0
2 0 0 0
10 100 0 0 0
$~

View file

@ -0,0 +1,19 @@
#R 1 1759515981
O 1 0 0 0 0
X 0 0
X 1 0
X 2 0
X 3 0
W 0 0
W 1 0
W 2 0
W 3 0
V 0 0
V 1 0
V 2 0
V 3 0
V 4 0
V 5 0
V 6 0
V 7 0
.

View file

@ -24,15 +24,19 @@ E 15 117
E 16 117
E 17 127
.
#R 134 1759515738
#R 134 1759521685
M 103
M 102
E 9 112
E 14 113
G 138
G 137
G 136
G 142
G 141
G 140
G 139
G 135
M 103
G 136
G 137
G 138
O 132 0 200 0 0
X 0 0
X 1 0

View file

@ -4,6 +4,10 @@ CircleMUD v3.0 Shop File~
136
137
138
139
140
141
142
-1
1.00
1.00

View file

@ -1,6 +1,6 @@
#1
Limbo~
You are in an unfinished room.
Floating in the void, you lose all sense of time and space.
~
0 0 0 0 0 0
S

View file

@ -534,11 +534,15 @@ from a curtained doorway. In a corner is an L-shaped counter made of rough-hewn
stone which has a selection of drinks behind it. Near the eastern wall, a
stairway heads upward toward an open dormitory.
~
1 131080 0 0 0 0
1 8 0 0 0 0
D0
~
~
0 0 108
D4
~
~
0 0 200
S
#135
Wall Road~
@ -1474,4 +1478,21 @@ D3
~
0 0 196
S
#200
A Cramped Dormitory~
While this room is rather large, the amount of cots crammed into it makes it
feel quite cramped. Between the cots are small pathways that one can walk,
though backpacks and other items spill out from below their respective cots to
occasionally block the way. The walls have small hooks on them and some appear
to have cloaks attached. An opening in the wall lets light in from the north
and allows for fresh air to circulate. A pair of sconces are on either side of
the room to provide light during the evening hours. On the south side of the
room, a staircase descends to the room below.
~
1 131080 0 0 0 0
D5
~
~
0 0 134
S
$~

View file

@ -1062,9 +1062,9 @@ ACMD(do_drink)
ACMD(do_eat)
{
char arg[MAX_INPUT_LENGTH];
struct obj_data *food;
struct obj_data *obj = NULL;
struct affected_type af;
int amount;
int amount = 0;
one_argument(argument, arg);
@ -1075,60 +1075,247 @@ ACMD(do_eat)
send_to_char(ch, "Eat what?\r\n");
return;
}
if (!(food = get_obj_in_list_vis(ch, arg, NULL, ch->carrying))) {
send_to_char(ch, "You don't seem to have %s %s.\r\n", AN(arg), arg);
return;
/* Find in inventory first, then in room */
if (!(obj = get_obj_in_list_vis(ch, arg, NULL, ch->carrying))) {
if (!(obj = get_obj_in_list_vis(ch, arg, NULL, world[IN_ROOM(ch)].contents))) {
send_to_char(ch, "You can't find it!\r\n");
return;
}
}
if (subcmd == SCMD_TASTE && ((GET_OBJ_TYPE(food) == ITEM_DRINKCON) ||
(GET_OBJ_TYPE(food) == ITEM_FOUNTAIN))) {
do_drink(ch, argument, 0, SCMD_SIP);
return;
/* If the player used 'taste', we handle both food and drink here (no delegation). */
if (subcmd == SCMD_TASTE) {
/* DRINKS: sip logic (inline; do not call do_drink) */
if (GET_OBJ_TYPE(obj) == ITEM_DRINKCON || GET_OBJ_TYPE(obj) == ITEM_FOUNTAIN) {
int cap = GET_OBJ_VAL(obj, 0);
int rem = GET_OBJ_VAL(obj, 1);
int liq = GET_OBJ_VAL(obj, 2); /* liquid type */
if (GET_COND(ch, DRUNK) > 10 && GET_COND(ch, THIRST) > 0) {
send_to_char(ch, "You can't seem to get close enough to your mouth.\r\n");
act("$n tries to drink but misses $s mouth!", TRUE, ch, 0, 0, TO_ROOM);
return;
}
if (rem < 1) {
send_to_char(ch, "It is empty.\r\n");
/* Update sdesc to "an empty <container>" like our drink update */
if (GET_OBJ_TYPE(obj) == ITEM_DRINKCON) {
obj_rnum rnum = GET_OBJ_RNUM(obj);
const char *proto_sd = (rnum != NOTHING) ? obj_proto[rnum].short_description : NULL;
const char *base = obj->short_description ? obj->short_description : proto_sd;
const char *noun = base ? base : "container";
/* strip leading article */
if (!strn_cmp(noun, "a ", 2)) noun += 2;
else if (!strn_cmp(noun, "an ", 3)) noun += 3;
else if (!strn_cmp(noun, "the ", 4)) noun += 4;
char sbuf[MAX_STRING_LENGTH];
const char *ofp = strstr(noun, " of ");
size_t noun_len = ofp ? (size_t)(ofp - noun) : strlen(noun);
snprintf(sbuf, sizeof(sbuf), "an empty %.*s", (int)MIN(noun_len, sizeof(sbuf) - 10), noun);
if (obj->short_description && obj->short_description != proto_sd)
free(obj->short_description);
obj->short_description = strdup(sbuf);
}
return;
}
/* Take a single sip */
amount = 1;
rem = MAX(0, rem - amount);
GET_OBJ_VAL(obj, 1) = rem;
/* Condition effects: use HUNGER (not FULL) in this codebase */
gain_condition(ch, DRUNK, (drink_aff[liq][DRUNK] * amount) / 4);
gain_condition(ch, HUNGER,(drink_aff[liq][HUNGER] * amount) / 4); /* <-- FIX */
gain_condition(ch, THIRST,(drink_aff[liq][THIRST] * amount) / 4);
if (GET_COND(ch, DRUNK) > 10)
send_to_char(ch, "You feel drunk.\r\n");
if (GET_COND(ch, THIRST) > 20)
send_to_char(ch, "You don't feel thirsty.\r\n");
if (GET_OBJ_VAL(obj, 3) && GET_LEVEL(ch) < LVL_IMMORT) {
send_to_char(ch, "It tastes strange!\r\n");
act("$n tastes something strange and coughs.", FALSE, ch, 0, 0, TO_ROOM);
memset(&af, 0, sizeof(af));
af.spell = SPELL_POISON; /* <-- FIX: use spell, not type */
af.duration = amount * 3;
af.location = APPLY_NONE;
af.modifier = 0;
/* no af.bonus in this codebase */
af.bitvector[0] = af.bitvector[1] = af.bitvector[2] = af.bitvector[3] = 0;
SET_BIT_AR(af.bitvector, AFF_POISON);
affect_join(ch, &af, FALSE, FALSE, FALSE, FALSE);
}
act("You sip from $p.", FALSE, ch, obj, 0, TO_CHAR);
act("$n sips from $p.", TRUE, ch, obj, 0, TO_ROOM);
/* Update dynamic sdesc band like drink code ("partially filled", etc.) */
if (GET_OBJ_TYPE(obj) == ITEM_DRINKCON) {
obj_rnum rnum = GET_OBJ_RNUM(obj);
const char *proto_sd = (rnum != NOTHING) ? obj_proto[rnum].short_description : NULL;
const char *base = obj->short_description ? obj->short_description : proto_sd;
const char *noun = base ? base : "container";
/* Strip leading article */
if (!strn_cmp(noun, "a ", 2)) noun += 2;
else if (!strn_cmp(noun, "an ", 3)) noun += 3;
else if (!strn_cmp(noun, "the ", 4)) noun += 4;
char sbuf[MAX_STRING_LENGTH];
if (rem <= 0) {
const char *ofp = strstr(noun, " of ");
size_t noun_len = ofp ? (size_t)(ofp - noun) : strlen(noun);
snprintf(sbuf, sizeof(sbuf), "an empty %.*s", (int)MIN(noun_len, sizeof(sbuf) - 10), noun);
} else {
const char *status = "partially filled";
if (cap > 0) {
int pct = (rem * 100) / cap;
if (pct >= 75)
status = "partially filled";
else if (pct >= 50)
status = "half-filled";
else
status = "nearly empty";
}
bool use_an = FALSE;
if (status && *status) {
char first = LOWER((unsigned char)status[0]);
use_an = (first == 'a' || first == 'e' || first == 'i' || first == 'o' || first == 'u');
}
const char *article = use_an ? "an" : "a";
size_t prefix_len = strlen(article) + 1 + strlen(status) + 1;
size_t max_noun = (sizeof(sbuf) > (prefix_len + 1))
? (sizeof(sbuf) - prefix_len - 1) : 0;
snprintf(sbuf, sizeof(sbuf), "%s %s %.*s", article, status, (int)max_noun, noun);
}
if (obj->short_description && obj->short_description != proto_sd)
free(obj->short_description);
obj->short_description = strdup(sbuf);
}
return;
} /* end taste of drink container */
/* otherwise fall through to taste FOOD below */
}
if ((GET_OBJ_TYPE(food) != ITEM_FOOD) && (GET_LEVEL(ch) < LVL_IMMORT)) {
/* From here: regular EAT/TASTE handling for FOOD (multi-bite) */
if (GET_OBJ_TYPE(obj) != ITEM_FOOD && GET_LEVEL(ch) < LVL_IMMORT) {
send_to_char(ch, "You can't eat THAT!\r\n");
return;
}
if (GET_COND(ch, HUNGER) > 20) { /* Stomach full */
/* Prevent overstuffing */
if (GET_COND(ch, HUNGER) > 20) {
send_to_char(ch, "You are too full to eat more!\r\n");
return;
}
if (!consume_otrigger(food, ch, OCMD_EAT)) /* check trigger */
if (!consume_otrigger(obj, ch, OCMD_EAT)) /* check trigger */
return;
if (subcmd == SCMD_EAT) {
act("You eat $p.", FALSE, ch, food, 0, TO_CHAR);
act("$n eats $p.", TRUE, ch, food, 0, TO_ROOM);
} else {
act("You nibble a little bit of $p.", FALSE, ch, food, 0, TO_CHAR);
act("$n tastes a little bit of $p.", TRUE, ch, food, 0, TO_ROOM);
/* Determine bites & nutrition */
int cap = GET_OBJ_VAL(obj, VAL_FOOD_BITE_CAP);
int left = GET_OBJ_VAL(obj, VAL_FOOD_BITES_LEFT);
int per = GET_OBJ_VAL(obj, VAL_FOOD_HOURS_PER_BITE);
bool poisoned = (GET_OBJ_VAL(obj, VAL_FOOD_POISONED) != 0);
if (left < 1) {
send_to_char(ch, "There's nothing left of it.\r\n");
return;
}
amount = (subcmd == SCMD_EAT ? GET_OBJ_VAL(food, 0) : 1);
/* Messaging differs for taste vs eat, nutrition identical per bite */
if (subcmd == SCMD_EAT) {
act("You eat a bite of $p.", FALSE, ch, obj, 0, TO_CHAR);
act("$n eats a bite of $p.", TRUE, ch, obj, 0, TO_ROOM);
} else {
act("You nibble a little bit of $p.", FALSE, ch, obj, 0, TO_CHAR);
act("$n tastes a little bit of $p.", TRUE, ch, obj, 0, TO_ROOM);
}
/* One bite per action (simple & consistent). */
left = MAX(0, left - 1);
GET_OBJ_VAL(obj, VAL_FOOD_BITES_LEFT) = left;
/* Apply hunger gain from one bite */
amount = MAX(0, per);
gain_condition(ch, HUNGER, amount);
if (GET_COND(ch, HUNGER) > 20)
send_to_char(ch, "You are full.\r\n");
if (GET_OBJ_VAL(food, 3) && (GET_LEVEL(ch) < LVL_IMMORT)) {
/* The crap was poisoned ! */
if (poisoned && GET_LEVEL(ch) < LVL_IMMORT) {
send_to_char(ch, "Oops, that tasted rather strange!\r\n");
act("$n coughs and utters some strange sounds.", FALSE, ch, 0, 0, TO_ROOM);
new_affect(&af);
af.spell = SPELL_POISON;
af.duration = amount * 2;
memset(&af, 0, sizeof(af));
af.spell = SPELL_POISON; /* <-- FIX: use spell, not type */
af.duration = MAX(1, amount * 2);
af.location = APPLY_NONE;
af.modifier = 0;
/* no af.bonus in this codebase */
af.bitvector[0] = af.bitvector[1] = af.bitvector[2] = af.bitvector[3] = 0;
SET_BIT_AR(af.bitvector, AFF_POISON);
affect_join(ch, &af, FALSE, FALSE, FALSE, FALSE);
}
if (subcmd == SCMD_EAT)
extract_obj(food);
else {
if (!(--GET_OBJ_VAL(food, 0))) {
send_to_char(ch, "There's nothing left now.\r\n");
extract_obj(food);
/* If no bites remain, consume the object.
* Otherwise, update the instance sdesc with an "eaten" status band. */
if (left <= 0) {
send_to_char(ch, "There's nothing left now.\r\n");
extract_obj(obj);
} else {
/* Build "<a/an> <status> <noun>" using the instance/proto sdesc as noun */
obj_rnum rnum = GET_OBJ_RNUM(obj);
const char *proto_sd = (rnum != NOTHING) ? obj_proto[rnum].short_description : NULL;
const char *base = obj->short_description ? obj->short_description : proto_sd;
const char *noun = base ? base : "food";
/* Strip leading article from noun */
if (!strn_cmp(noun, "a ", 2)) noun += 2;
else if (!strn_cmp(noun, "an ", 3)) noun += 3;
else if (!strn_cmp(noun, "the ", 4)) noun += 4;
const char *status = "partially eaten";
if (cap > 0) {
int pct = (left * 100) / cap;
if (pct >= 75)
status = "partially eaten";
else if (pct >= 50)
status = "half-eaten";
else
status = "nearly eaten";
}
bool use_an = FALSE;
if (status && *status) {
char first = LOWER((unsigned char)status[0]);
use_an = (first == 'a' || first == 'e' || first == 'i' || first == 'o' || first == 'u');
}
const char *article = use_an ? "an" : "a";
char sbuf[MAX_STRING_LENGTH];
size_t prefix_len = strlen(article) + 1 + strlen(status) + 1;
size_t max_noun = (sizeof(sbuf) > (prefix_len + 1))
? (sizeof(sbuf) - prefix_len - 1) : 0;
snprintf(sbuf, sizeof(sbuf), "%s %s %.*s", article, status, (int)max_noun, noun);
if (obj->short_description && obj->short_description != proto_sd)
free(obj->short_description);
obj->short_description = strdup(sbuf);
}
}

View file

@ -90,7 +90,7 @@ static const char *drink_val_labels[NUM_OBJ_VAL_POSITIONS] = {
/* Food */
static const char *food_val_labels[NUM_OBJ_VAL_POSITIONS] = {
"hours_full", "unused1", "unused2", "poisoned",
"bites_capacity", "bites_left", "hours_full_per_bite", "poisoned",
"Value[4]", "Value[5]", "Value[6]", "Value[7]"
};
@ -519,6 +519,7 @@ static void oedit_disp_values_menu(struct descriptor_data *d)
case ITEM_FOUNTAIN: labels = drink_val_labels; break;
case ITEM_CONTAINER: labels = container_val_labels; break;
case ITEM_FURNITURE: labels = furniture_val_labels; break;
case ITEM_FOOD: labels = food_val_labels; break;
default: labels = generic_val_labels; break;
}

View file

@ -1331,13 +1331,23 @@ void loadout_free_list(struct mob_loadout **head);
void loadout_add_entry(struct mob_loadout **head, obj_vnum vnum, sh_int wear_pos, int qty);
struct mob_loadout *loadout_deep_copy(const struct mob_loadout *src);
/* Furniture defines for object values */
/* Furniture object values (obj_flags.value[x]) */
#define VAL_FURN_CAPACITY 0 /* maximum number of people who can use furniture */
#define VAL_FURN_MAX_OCC 1 /* current number of people using furniture (runtime only, managed by game engine) */
#define VAL_FURN_POSITIONS 2 /* allowed positions bitvector: bit 0=STAND(1), bit 1=SIT(2), bit 2=REST(4), bit 3=SLEEP(8) */
/* Food value indices (mirrors drinkcon layout for multi-bite foods)
* 0: bites_capacity - total bite capacity
* 1: bites_left - remaining bites
* 2: hours_full_per_bite- hunger gain per bite (like hours_full)
* 3: poisoned - 1 if poisoned
*/
#define VAL_FOOD_BITE_CAP 0
#define VAL_FOOD_BITES_LEFT 1
#define VAL_FOOD_HOURS_PER_BITE 2
#define VAL_FOOD_POISONED 3
/* Config structs */
/** The game configuration structure used for configurating the game play