Skip to content

Commit

Permalink
Handle items under the player on level arrival and generally (tmewett…
Browse files Browse the repository at this point in the history
  • Loading branch information
zenzombie authored Mar 5, 2024
1 parent 213e0e0 commit cd04993
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 57 deletions.
4 changes: 4 additions & 0 deletions changes/item-under-player.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Fixed a bug where arriving on a level with items "obstructing" the stairs would cause the player to be moved to a non-item location without using a turn.
- When the player arrives on a level and occupies a location with an item, a message is now displayed in the message pane.
- If the player occupies a location with an item, the item is now shown in the sidebar. Additionally, the item is included in the description when inspecting the player's location.
- When inspecting a location, item descriptions now include details if space permits.
30 changes: 22 additions & 8 deletions src/brogue/IO.c
Original file line number Diff line number Diff line change
Expand Up @@ -1092,8 +1092,6 @@ void getCellAppearance(pos loc, enum displayGlyph *returnChar, color *returnFore
creature *monst = NULL;
item *theItem = NULL;
enum tileType tile = NOTHING;
const enum displayGlyph itemChars[] = {G_POTION, G_SCROLL, G_FOOD, G_WAND,
G_STAFF, G_GOLD, G_ARMOR, G_WEAPON, G_RING, G_CHARM};
enum dungeonLayers layer, maxLayer;

assureCosmeticRNG;
Expand Down Expand Up @@ -1272,7 +1270,7 @@ void getCellAppearance(pos loc, enum displayGlyph *returnChar, color *returnFore
&& (playerCanSeeOrSense(loc.x, loc.y) || ((pmapAt(loc)->flags & DISCOVERED) && !cellHasTerrainFlag(loc, T_MOVES_ITEMS)))) {
needDistinctness = true;
if (player.status[STATUS_HALLUCINATING] && !rogue.playbackOmniscience) {
cellChar = itemChars[rand_range(0, 9)];
cellChar = getItemCategoryGlyph(getHallucinatedItemCategory());
cellForeColor = itemColor;
} else {
theItem = itemAtLoc(loc);
Expand Down Expand Up @@ -3779,6 +3777,13 @@ void refreshSideBar(short focusX, short focusY, boolean focusedEntityMustGoFirst
entityType[displayEntityCount] = EDT_CREATURE;
displayEntityCount++;
addedEntity[player.loc.x][player.loc.y] = true;
// And the item at the player's location, if any
theItem = itemAtLoc(player.loc);
if (theItem) {
entityList[displayEntityCount] = theItem;
entityType[displayEntityCount] = EDT_ITEM;
displayEntityCount++;
}

// Focused entity, if it must go first.
if (focusedEntityMustGoFirst && !addedEntity[focusX][focusY]) {
Expand Down Expand Up @@ -4749,14 +4754,12 @@ short printMonsterInfo(creature *monst, short y, boolean dim, boolean highlight)
}

void describeHallucinatedItem(char *buf) {
const unsigned short itemCats[10] = {FOOD, WEAPON, ARMOR, POTION, SCROLL, STAFF, WAND, RING, CHARM, GOLD};
short cat, kind, maxKinds;
short kind, maxKinds;
assureCosmeticRNG;
cat = itemCats[rand_range(0, 9)];
tableForItemCategory(cat);
enum itemCategory cat = getHallucinatedItemCategory();
maxKinds = itemKindCount(cat, 0);
kind = rand_range(0, maxKinds - 1);
describedItemBasedOnParameters(cat, kind, 1, 1, buf);
describedItemBasedOnParameters((short)cat, kind, 1, 1, buf);
restoreRNG;
}

Expand Down Expand Up @@ -4784,6 +4787,17 @@ short printItemInfo(item *theItem, short y, boolean dim, boolean highlight) {
inPath = (pmapAt(theItem->loc)->flags & IS_IN_PATH) ? true : false;
pmapAt(theItem->loc)->flags &= ~IS_IN_PATH;
getCellAppearance(theItem->loc, &itemChar, &itemForeColor, &itemBackColor);
// override the glyph if the item is at the player's location because
// getCellAppearance returns the player glyph
if (theItem->loc.x == player.loc.x && theItem->loc.y == player.loc.y) {
if (player.status[STATUS_HALLUCINATING] && !rogue.playbackOmniscience) {
itemChar = getItemCategoryGlyph(getHallucinatedItemCategory());
itemForeColor = itemColor;
} else {
itemChar = theItem->displayChar;
itemForeColor = *(theItem->foreColor);
}
}
applyColorBounds(&itemForeColor, 0, 100);
applyColorBounds(&itemBackColor, 0, 100);
if (inPath) {
Expand Down
64 changes: 49 additions & 15 deletions src/brogue/Items.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,51 @@ static unsigned long pickItemCategory(unsigned long theCategory) {
}
}

/// @brief Pick a random item category for hallucination
/// @return the category
enum itemCategory getHallucinatedItemCategory(void) {
const enum itemCategory itemCategories[10] = {FOOD, WEAPON, ARMOR, POTION, SCROLL, STAFF, WAND, RING, CHARM, GOLD};
return itemCategories[rand_range(0, 9)];
}

/// @brief Gets the glyph used to represent an item of the given category
/// @param theCategory The item category
/// @return The glyph
enum displayGlyph getItemCategoryGlyph(const enum itemCategory theCategory) {

switch (theCategory) {
case FOOD:
return G_FOOD;
case WEAPON:
return G_WEAPON;
case ARMOR:
return G_ARMOR;
case SCROLL:
return G_SCROLL;
case POTION:
return G_POTION;
case STAFF:
return G_STAFF;
case WAND:
return G_WAND;
case GEM:
return G_GEM;
case RING:
return G_RING;
case CHARM:
return G_CHARM;
case KEY:
return G_KEY;
case GOLD:
return G_GOLD;
case AMULET:
return G_AMULET;
default:
break;
}
return 0;
}

// Sets an item to the given type and category (or chooses randomly if -1) with all other stats
item *makeItemInto(item *theItem, unsigned long itemCategory, short itemKind) {
const itemTable *theEntry = NULL;
Expand All @@ -117,6 +162,7 @@ item *makeItemInto(item *theItem, unsigned long itemCategory, short itemKind) {
itemCategory = pickItemCategory(itemCategory);

theItem->category = itemCategory;
theItem->displayChar = getItemCategoryGlyph(theItem->category);

switch (itemCategory) {

Expand All @@ -125,7 +171,6 @@ item *makeItemInto(item *theItem, unsigned long itemCategory, short itemKind) {
itemKind = chooseKind(foodTable, NUMBER_FOOD_KINDS);
}
theEntry = &foodTable[itemKind];
theItem->displayChar = G_FOOD;
theItem->flags |= ITEM_IDENTIFIED;
break;

Expand All @@ -136,7 +181,6 @@ item *makeItemInto(item *theItem, unsigned long itemCategory, short itemKind) {
theEntry = &weaponTable[itemKind];
theItem->damage = weaponTable[itemKind].range;
theItem->strengthRequired = weaponTable[itemKind].strengthRequired;
theItem->displayChar = G_WEAPON;

switch (itemKind) {
case DAGGER:
Expand Down Expand Up @@ -214,7 +258,6 @@ item *makeItemInto(item *theItem, unsigned long itemCategory, short itemKind) {
theEntry = &armorTable[itemKind];
theItem->armor = randClump(armorTable[itemKind].range);
theItem->strengthRequired = armorTable[itemKind].strengthRequired;
theItem->displayChar = G_ARMOR;
theItem->charges = gameConst->armorDelayToAutoID; // this many turns until it reveals its enchants and whether runic
if (rand_percent(40)) {
theItem->enchant1 += rand_range(1, 3);
Expand Down Expand Up @@ -244,22 +287,19 @@ item *makeItemInto(item *theItem, unsigned long itemCategory, short itemKind) {
itemKind = chooseKind(scrollTable, gameConst->numberScrollKinds);
}
theEntry = &scrollTable[itemKind];
theItem->displayChar = G_SCROLL;
theItem->flags |= ITEM_FLAMMABLE;
break;
case POTION:
if (itemKind < 0) {
itemKind = chooseKind(potionTable, gameConst->numberPotionKinds);
}
theEntry = &potionTable[itemKind];
theItem->displayChar = G_POTION;
break;
case STAFF:
if (itemKind < 0) {
itemKind = chooseKind(staffTable, NUMBER_STAFF_KINDS);
}
theEntry = &staffTable[itemKind];
theItem->displayChar = G_STAFF;
theItem->charges = 2;
if (rand_percent(50)) {
theItem->charges++;
Expand All @@ -278,15 +318,13 @@ item *makeItemInto(item *theItem, unsigned long itemCategory, short itemKind) {
itemKind = chooseKind(wandTable, gameConst->numberWandKinds);
}
theEntry = &(wandTable[itemKind]);
theItem->displayChar = G_WAND;
theItem->charges = randClump(wandTable[itemKind].range);
break;
case RING:
if (itemKind < 0) {
itemKind = chooseKind(ringTable, NUMBER_RING_KINDS);
}
theEntry = &ringTable[itemKind];
theItem->displayChar = G_RING;
theItem->enchant1 = randClump(ringTable[itemKind].range);
theItem->charges = gameConst->ringDelayToAutoID; // how many turns of being worn until it auto-identifies
if (rand_percent(16)) {
Expand All @@ -303,7 +341,6 @@ item *makeItemInto(item *theItem, unsigned long itemCategory, short itemKind) {
if (itemKind < 0) {
itemKind = chooseKind(charmTable, gameConst->numberCharmKinds);
}
theItem->displayChar = G_CHARM;
theItem->charges = 0; // Charms are initially ready for use.
theItem->enchant1 = randClump(charmTable[itemKind].range);
while (rand_percent(7)) {
Expand All @@ -313,24 +350,20 @@ item *makeItemInto(item *theItem, unsigned long itemCategory, short itemKind) {
break;
case GOLD:
theEntry = NULL;
theItem->displayChar = G_GOLD;
theItem->quantity = rand_range(50 + rogue.depthLevel * 10 * gameConst->depthAccelerator, 100 + rogue.depthLevel * 15 * gameConst->depthAccelerator);
break;
case AMULET:
theEntry = NULL;
theItem->displayChar = G_AMULET;
itemKind = 0;
theItem->flags |= ITEM_IDENTIFIED;
break;
case GEM:
theEntry = NULL;
theItem->displayChar = G_GEM;
itemKind = 0;
theItem->flags |= ITEM_IDENTIFIED;
break;
case KEY:
theEntry = NULL;
theItem->displayChar = G_KEY;
theItem->flags |= ITEM_IDENTIFIED;
break;
default:
Expand Down Expand Up @@ -5132,7 +5165,8 @@ boolean nextTargetAfter(short *returnX,
const int n = (selectedIndex + i) % targetCount;
const int newX = deduplicatedTargetList[n].x;
const int newY = deduplicatedTargetList[n].y;
if ((newX != player.loc.x || newY != player.loc.y)
if (((newX != player.loc.x || newY != player.loc.y)
|| (posEq((pos){newX, newY}, player.loc) && targetItems && itemAtLoc(player.loc)))
&& (newX != targetX || newY != targetY)
&& (!requireOpenPath || openPathBetween(player.loc.x, player.loc.y, newX, newY))) {

Expand All @@ -5155,7 +5189,7 @@ boolean nextTargetAfter(short *returnX,
}
}
item *const theItem = itemAtLoc((pos){ newX, newY });
if (!monst && theItem && targetItems) {
if ((!monst || (monst == &player)) && theItem && targetItems) {
*returnX = newX;
*returnY = newY;
return true;
Expand Down
Loading

0 comments on commit cd04993

Please sign in to comment.