/** * Light or Darken the town */ void cave_illuminate(struct chunk *c, bool daytime) { int y, x, i; /* Apply light or darkness */ for (y = 0; y < c->height; y++) { for (x = 0; x < c->width; x++) { int d; bool light = false; /* Skip grids with no surrounding floors or stairs */ for (d = 0; d < 9; d++) { /* Extract adjacent (legal) location */ int yy = y + ddy_ddd[d]; int xx = x + ddx_ddd[d]; /* Paranoia */ if (!square_in_bounds_fully(c, yy, xx)) continue; /* Test */ if (square_isfloor(c, yy, xx) || square_isstairs(c, yy, xx)) light = true; } if (!light) continue; /* Only interesting grids at night */ if (daytime || !square_isfloor(c, y, x)) { sqinfo_on(c->squares[y][x].info, SQUARE_GLOW); square_memorize(c, y, x); } else if (!square_isbright(c, y, x)) { sqinfo_off(c->squares[y][x].info, SQUARE_GLOW); square_forget(c, y, x); } } } /* Light shop doorways */ for (y = 0; y < c->height; y++) { for (x = 0; x < c->width; x++) { if (!square_isshop(c, y, x)) continue; for (i = 0; i < 8; i++) { int yy = y + ddy_ddd[i]; int xx = x + ddx_ddd[i]; sqinfo_on(c->squares[yy][xx].info, SQUARE_GLOW); square_memorize(c, yy, xx); } } } /* Fully update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Redraw map, monster list */ player->upkeep->redraw |= (PR_MAP | PR_MONLIST | PR_ITEMLIST); }
/** * True if the square is an untrapped floor square without items. */ bool square_canputitem(struct chunk *c, int y, int x) { if (!square_isfloor(c, y, x)) return FALSE; if (square_iswarded(c, y, x) || square_isplayertrap(c, y, x)) return FALSE; return !square_object(c, y, x); }
/** * This routine will "darken" all grids in the set passed in. * * In addition, some of these grids will be "unmarked". * * This routine is used (only) by "light_room()" */ static void cave_unlight(struct point_set *ps) { int i; /* Apply flag changes */ for (i = 0; i < ps->n; i++) { int y = ps->pts[i].y; int x = ps->pts[i].x; /* Darken the grid */ sqinfo_off(cave->squares[y][x].info, SQUARE_GLOW); /* Hack -- Forget "boring" grids */ if (square_isfloor(cave, y, x)) sqinfo_off(cave->squares[y][x].info, SQUARE_MARK); } /* Fully update the visuals */ player->upkeep->update |= (PU_FORGET_VIEW | PU_UPDATE_VIEW | PU_MONSTERS); /* Update stuff */ update_stuff(player); /* Process the grids */ for (i = 0; i < ps->n; i++) { int y = ps->pts[i].y; int x = ps->pts[i].x; /* Redraw the grid */ square_light_spot(cave, y, x); } }
/* Make doors */ static void project_feature_handler_MAKE_DOOR(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Require a grid without monsters */ if (square_monster(cave, y, x)) return; /* Require a floor grid */ if (!square_isfloor(cave, y, x)) return; /* Push objects off the grid */ if (square_object(cave, y, x)) push_object(y,x); /* Create closed door */ square_add_door(cave, y, x, true); /* Observe */ if (square_isknown(cave, y, x)) context->obvious = true; /* Update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); }
/** * This routine will "darken" all grids in the set passed in. * * In addition, some of these grids will be "unmarked". * * This routine is used (only) by "light_room()" */ static void cave_unlight(struct point_set *ps) { int i; /* Apply flag changes */ for (i = 0; i < ps->n; i++) { int y = ps->pts[i].y; int x = ps->pts[i].x; /* Darken the grid */ if (!square_isbright(cave, y, x)) { sqinfo_off(cave->squares[y][x].info, SQUARE_GLOW); } /* Hack -- Forget "boring" grids */ if (square_isfloor(cave, y, x)) square_forget(cave, y, x); } /* Process the grids */ for (i = 0; i < ps->n; i++) { int y = ps->pts[i].y; int x = ps->pts[i].x; /* Redraw the grid */ square_light_spot(cave, y, x); } }
/** * Light up the dungeon using "claravoyance" * * This function "illuminates" every grid in the dungeon, memorizes all * "objects" (or notes the existence of an object "if" full is true), * and memorizes all grids as with magic mapping. */ void wiz_light(struct chunk *c, struct player *p, bool full) { int i, y, x; /* Scan all grids */ for (y = 1; y < c->height - 1; y++) { for (x = 1; x < c->width - 1; x++) { /* Process all non-walls */ if (!square_seemslikewall(c, y, x)) { if (!square_in_bounds_fully(c, y, x)) continue; /* Scan all neighbors */ for (i = 0; i < 9; i++) { int yy = y + ddy_ddd[i]; int xx = x + ddx_ddd[i]; /* Perma-light the grid */ sqinfo_on(c->squares[yy][xx].info, SQUARE_GLOW); /* Memorize normal features */ if (!square_isfloor(c, yy, xx) || square_isvisibletrap(c, yy, xx)) { square_memorize(c, yy, xx); square_mark(c, yy, xx); } } } /* Memorize objects */ if (full) { square_know_pile(c, y, x); } else { square_sense_pile(c, y, x); } /* Forget unprocessed, unknown grids in the mapping area */ if (!square_ismark(c, y, x) && square_isnotknown(c, y, x)) square_forget(c, y, x); } } /* Unmark grids */ for (y = 1; y < c->height - 1; y++) { for (x = 1; x < c->width - 1; x++) { if (!square_in_bounds(c, y, x)) continue; square_unmark(c, y, x); } } /* Fully update the visuals */ p->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Redraw whole map, monster list */ p->upkeep->redraw |= (PR_MAP | PR_MONLIST | PR_ITEMLIST); }
/** * Light up the dungeon using "claravoyance" * * This function "illuminates" every grid in the dungeon, memorizes all * "objects" (or notes the existence of an object "if" full is TRUE), * and memorizes all grids as with magic mapping. */ void wiz_light(struct chunk *c, bool full) { int i, y, x; /* Scan all grids */ for (y = 1; y < c->height - 1; y++) { for (x = 1; x < c->width - 1; x++) { struct object *obj; /* Process all non-walls */ if (!square_seemslikewall(c, y, x)) { /* Scan all neighbors */ for (i = 0; i < 9; i++) { int yy = y + ddy_ddd[i]; int xx = x + ddx_ddd[i]; /* Perma-light the grid */ sqinfo_on(c->squares[yy][xx].info, SQUARE_GLOW); /* Memorize normal features */ if (!square_isfloor(c, yy, xx) || square_isvisibletrap(c, yy, xx)) { sqinfo_on(c->squares[yy][xx].info, SQUARE_MARK); cave_k->squares[yy][xx].feat = c->squares[yy][xx].feat; } } } /* Memorize objects */ for (obj = square_object(cave, y, x); obj; obj = obj->next) { /* Skip dead objects */ assert(obj->kind); /* Memorize it */ if (obj->marked < MARK_SEEN) obj->marked = full ? MARK_SEEN : MARK_AWARE; } } } /* Fully update the visuals */ player->upkeep->update |= (PU_FORGET_VIEW | PU_UPDATE_VIEW | PU_MONSTERS); /* Redraw whole map, monster list */ player->upkeep->redraw |= (PR_MAP | PR_MONLIST | PR_ITEMLIST); }
bool square_canward(struct chunk *c, int y, int x) { return square_isfloor(c, y, x); }
/** * True if the square is open (a floor square not occupied by a monster). */ bool square_isopen(struct chunk *c, int y, int x) { return square_isfloor(c, y, x) && !c->squares[y][x].mon; }
/** * True if the square is a floor square without items. */ bool square_canputitem(struct chunk *c, int y, int x) { return square_isfloor(c, y, x) && !square_object(c, y, x); }
/** * Find a grid near the given one for an object to fall on * * We check several locations to see if we can find a location at which * the object can combine, stack, or be placed. Artifacts will try very * hard to be placed, including "teleporting" to a useful grid if needed. * * If no appropriate grid is found, the given grid is unchanged */ static void drop_find_grid(struct object *drop, int *y, int *x) { int best_score = -1; int best_y = *y; int best_x = *x; int i, dy, dx; struct object *obj; /* Scan local grids */ for (dy = -3; dy <= 3; dy++) { for (dx = -3; dx <= 3; dx++) { bool combine = false; int dist = (dy * dy) + (dx * dx); int ty = *y + dy; int tx = *x + dx; int num_shown = 0; int num_ignored = 0; int score; /* Lots of reasons to say no */ if ((dist > 10) || !square_in_bounds_fully(cave, ty, tx) || !los(cave, *y, *x, ty, tx) || !square_isfloor(cave, ty, tx) || square_isplayertrap(cave, ty, tx) || square_iswarded(cave, ty, tx)) continue; /* Analyse the grid for carrying the new object */ for (obj = square_object(cave, ty, tx); obj; obj = obj->next) { /* Check for possible combination */ if (object_similar(obj, drop, OSTACK_FLOOR)) combine = true; /* Count objects */ if (!ignore_item_ok(obj)) num_shown++; else num_ignored++; } if (!combine) num_shown++; /* Disallow if the stack size is too big */ if ((OPT(player, birth_stacking) && (num_shown > 1)) || ((num_shown + num_ignored) > z_info->floor_size && !floor_get_oldest_ignored(ty, tx))) continue; /* Score the location based on how close and how full the grid is */ score = 1000 - (dist + num_shown * 5); if ((score < best_score) || ((score == best_score) && one_in_(2))) continue; best_score = score; best_y = ty; best_x = tx; } } /* Return if we have a score, otherwise fail or try harder for artifacts */ if (best_score >= 0) { *y = best_y; *x = best_x; return; } else if (!drop->artifact) { return; } for (i = 0; i < 2000; i++) { /* Start bouncing from grid to grid, stopping if we find an empty one */ if (i < 1000) { best_y = rand_spread(best_y, 1); best_x = rand_spread(best_x, 1); } else { /* Now go to purely random locations */ best_y = randint0(cave->height); best_x = randint0(cave->width); } if (square_canputitem(cave, best_y, best_x)) { *y = best_y; *x = best_x; return; } } }
/** * Let an object fall to the ground at or near a location. * * The initial location is assumed to be "square_in_bounds_fully(cave, )". * * This function takes a parameter "chance". This is the percentage * chance that the item will "disappear" instead of drop. If the object * has been thrown, then this is the chance of disappearance on contact. * * This function will produce a description of a drop event under the player * when "verbose" is true. * * We check several locations to see if we can find a location at which * the object can combine, stack, or be placed. Artifacts will try very * hard to be placed, including "teleporting" to a useful grid if needed. * * Objects which fail to be carried by the floor are deleted. This function * attempts to add successfully dropped objects to, and to remove failures * from, the object list (as dropped items may or may not be already listed). */ void drop_near(struct chunk *c, struct object *dropped, int chance, int y, int x, bool verbose) { int i, k, n, d, s; int bs, bn; int by, bx; int dy, dx; int ty, tx; struct object *obj; char o_name[80]; bool flag = false; /* Only called in the current level */ assert(c == cave); /* Describe object */ object_desc(o_name, sizeof(o_name), dropped, ODESC_BASE); /* Handle normal "breakage" */ if (!dropped->artifact && (randint0(100) < chance)) { /* Message */ msg("The %s %s.", o_name, VERB_AGREEMENT(dropped->number, "breaks", "break")); /* Failure */ if (dropped->known) { delist_object(cave_k, dropped->known); object_delete(&dropped->known); } delist_object(c, dropped); object_delete(&dropped); return; } /* Score */ bs = -1; /* Picker */ bn = 0; /* Default */ by = y; bx = x; /* Scan local grids */ for (dy = -3; dy <= 3; dy++) { for (dx = -3; dx <= 3; dx++) { bool comb = false; /* Calculate actual distance */ d = (dy * dy) + (dx * dx); /* Ignore distant grids */ if (d > 10) continue; /* Location */ ty = y + dy; tx = x + dx; /* Skip illegal grids */ if (!square_in_bounds_fully(c, ty, tx)) continue; /* Require line of sight */ if (!los(c, y, x, ty, tx)) continue; /* Require floor space */ if (!square_isfloor(c, ty, tx)) continue; /* Require no trap or rune */ if (square_isplayertrap(c, ty, tx) || square_iswarded(c, ty, tx)) continue; /* No objects */ k = 0; n = 0; /* Scan objects in that grid */ for (obj = square_object(c, ty, tx); obj; obj = obj->next) { /* Check for possible combination */ if (object_similar(obj, dropped, OSTACK_FLOOR)) comb = true; /* Count objects */ if (!ignore_item_ok(obj)) k++; else n++; } /* Add new object */ if (!comb) k++; /* Option -- disallow stacking */ if (OPT(birth_no_stacking) && (k > 1)) continue; /* Paranoia? */ if ((k + n) > z_info->floor_size && !floor_get_oldest_ignored(ty, tx)) continue; /* Calculate score */ s = 1000 - (d + k * 5); /* Skip bad values */ if (s < bs) continue; /* New best value */ if (s > bs) bn = 0; /* Apply the randomizer to equivalent values */ if ((++bn >= 2) && (randint0(bn) != 0)) continue; /* Keep score */ bs = s; /* Track it */ by = ty; bx = tx; /* Okay */ flag = true; } } /* Handle lack of space */ if (!flag && !dropped->artifact) { /* Message */ msg("The %s %s.", o_name, VERB_AGREEMENT(dropped->number, "disappears", "disappear")); /* Debug */ if (player->wizard) msg("Breakage (no floor space)."); /* Failure */ if (dropped->known) { delist_object(cave_k, dropped->known); object_delete(&dropped->known); } delist_object(c, dropped); object_delete(&dropped); return; } /* Find a grid */ for (i = 0; !flag; i++) { /* Bounce around */ if (i < 1000) { ty = rand_spread(by, 1); tx = rand_spread(bx, 1); } else { /* Random locations */ ty = randint0(c->height); tx = randint0(c->width); } /* Require floor space */ if (!square_canputitem(c, ty, tx)) continue; /* Bounce to that location */ by = ty; bx = tx; /* Okay */ flag = true; } /* Give it to the floor */ if (!floor_carry(c, by, bx, dropped, false)) { /* Message */ msg("The %s %s.", o_name, VERB_AGREEMENT(dropped->number, "disappears", "disappear")); /* Debug */ if (player->wizard) msg("Breakage (too many objects)."); if (dropped->artifact) dropped->artifact->created = false; /* Failure */ if (dropped->known) { delist_object(cave_k, dropped->known); object_delete(&dropped->known); } delist_object(c, dropped); object_delete(&dropped); return; } /* Sound */ sound(MSG_DROP); /* Message when an object falls under the player */ if (verbose && (c->squares[by][bx].mon < 0)) /* Check the item still exists and isn't ignored */ if (c->objects[dropped->oidx] && !ignore_item_ok(dropped)) msg("You feel something roll beneath your feet."); }