/* Destroy Doors (and traps) */ static void project_feature_handler_KILL_DOOR(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Destroy all doors and traps */ if (square_isplayertrap(cave, y, x) || square_isdoor(cave, y, x)) { /* Check line of sight */ if (square_isview(cave, y, x)) { /* Message */ msg("There is a bright flash of light!"); context->obvious = true; /* Visibility change */ if (square_isdoor(cave, y, x)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Forget the door */ square_forget(cave, y, x); } /* Destroy the feature */ if (square_isdoor(cave, y, x)) square_destroy_door(cave, y, x); else square_destroy_trap(cave, y, x); } }
/** * Creates magical stairs after finishing a quest monster. */ static void build_quest_stairs(int y, int x) { int ny, nx; /* Stagger around */ while (!square_changeable(cave, y, x) && !square_iswall(cave, y, x) && !square_isdoor(cave, y, x)) { /* Pick a location */ scatter(cave, &ny, &nx, y, x, 1, FALSE); /* Stagger */ y = ny; x = nx; } /* Push any objects */ push_object(y, x); /* Explain the staircase */ msg("A magical staircase appears..."); /* Create stairs down */ square_set_feat(cave, y, x, FEAT_MORE); /* Update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Fully update the flow */ player->upkeep->update |= (PU_FORGET_FLOW | PU_UPDATE_FLOW); }
void square_destroy_door(struct chunk *c, int y, int x) { assert(square_isdoor(c, y, x)); square_remove_trap(c, y, x, FALSE, -1); square_set_feat(c, y, x, FEAT_FLOOR); }
/** * Examine a grid, return a keypress. * * The "mode" argument contains the "TARGET_LOOK" bit flag, which * indicates that the "space" key should scan through the contents * of the grid, instead of simply returning immediately. This lets * the "look" command get complete information, without making the * "target" command annoying. * * The "info" argument contains the "commands" which should be shown * inside the "[xxx]" text. This string must never be empty, or grids * containing monsters will be displayed with an extra comma. * * Note that if a monster is in the grid, we update both the monster * recall info and the health bar info to track that monster. * * This function correctly handles multiple objects per grid, and objects * and terrain features in the same grid, though the latter never happens. * * This function must handle blindness/hallucination. */ static ui_event target_set_interactive_aux(int y, int x, int mode) { struct object *obj = NULL; const char *s1, *s2, *s3; bool boring; int floor_max = z_info->floor_size; struct object **floor_list = mem_zalloc(floor_max * sizeof(*floor_list)); int floor_num; ui_event press; char out_val[TARGET_OUT_VAL_SIZE]; char coords[20]; const char *name; /* Describe the square location */ coords_desc(coords, sizeof(coords), y, x); /* Repeat forever */ while (1) { /* Paranoia */ press.type = EVT_KBRD; press.key.code = ' '; press.key.mods = 0; /* Assume boring */ boring = TRUE; /* Default */ s1 = "You see "; s2 = ""; s3 = ""; /* The player */ if (cave->squares[y][x].mon < 0) { /* Description */ s1 = "You are "; /* Preposition */ s2 = "on "; } /* Hallucination messes things up */ if (player->timed[TMD_IMAGE]) { const char *name = "something strange"; /* Display a message */ if (player->wizard) strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, name, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); else strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); prt(out_val, 0, 0); move_cursor_relative(y, x); press.key = inkey(); /* Stop on everything but "return" */ if (press.key.code == KC_ENTER) continue; mem_free(floor_list); return press; } /* Actual monsters */ if (cave->squares[y][x].mon > 0) { monster_type *m_ptr = square_monster(cave, y, x); const monster_lore *l_ptr = get_lore(m_ptr->race); /* Visible */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE) && !mflag_has(m_ptr->mflag, MFLAG_UNAWARE)) { bool recall = FALSE; char m_name[80]; /* Not boring */ boring = FALSE; /* Get the monster name ("a kobold") */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND_VIS); /* Hack -- track this monster race */ monster_race_track(player->upkeep, m_ptr->race); /* Hack -- health bar for this monster */ health_track(player->upkeep, m_ptr); /* Hack -- handle stuff */ handle_stuff(player); /* Interact */ while (1) { /* Recall or target */ if (recall) { lore_show_interactive(m_ptr->race, l_ptr); press = inkey_m(); } else { char buf[80]; /* Describe the monster */ look_mon_desc(buf, sizeof(buf), cave->squares[y][x].mon); /* Describe, and prompt for recall */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, m_name, buf, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s.", s1, s2, s3, m_name, buf, coords); } prt(out_val, 0, 0); /* Place cursor */ move_cursor_relative(y, x); /* Command */ press = inkey_m(); } /* Normal commands */ if ((press.type == EVT_MOUSE) && (press.mouse.button == 1) && (KEY_GRID_X(press) == x) && (KEY_GRID_Y(press) == y)) recall = !recall; else if ((press.type == EVT_KBRD) && (press.key.code == 'r')) recall = !recall; else break; } if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button == 2) break; /* Sometimes stop at "space" key */ if (press.mouse.button && !(mode & (TARGET_LOOK))) break; } else { /* Stop on everything but "return"/"space" */ if (press.key.code != KC_ENTER && press.key.code != ' ') break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; } /* Take account of gender */ if (rf_has(m_ptr->race->flags, RF_FEMALE)) s1 = "She is "; else if (rf_has(m_ptr->race->flags, RF_MALE)) s1 = "He is "; else s1 = "It is "; /* Use a verb */ s2 = "carrying "; /* Scan all objects being carried */ for (obj = m_ptr->held_obj; obj; obj = obj->next) { char o_name[80]; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, o_name, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button == 2) break; /* Sometimes stop at "space" key */ if (press.mouse.button && !(mode & (TARGET_LOOK))) break; } else { /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; } /* Change the intro */ s2 = "also carrying "; } /* Double break */ if (obj) break; /* Use a preposition */ s2 = "on "; } } /* A trap */ if (square_isvisibletrap(cave, y, x)) { struct trap *trap = cave->squares[y][x].trap; /* Not boring */ boring = FALSE; /* Interact */ while (1) { /* Change the intro */ if (cave->squares[y][x].mon < 0) { s1 = "You are "; s2 = "on "; } else { s1 = "You see "; s2 = ""; } /* Pick proper indefinite article */ s3 = (is_a_vowel(trap->kind->desc[0])) ? "an " : "a "; /* Describe, and prompt for recall */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, trap->kind->name, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, trap->kind->desc, coords); } prt(out_val, 0, 0); /* Place cursor */ move_cursor_relative(y, x); /* Command */ press = inkey_m(); /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; } } /* Double break */ if (square_isvisibletrap(cave, y, x)) break; /* Assume not floored */ floor_num = scan_floor(floor_list, floor_max, y, x, 0x0A, NULL); /* Scan all marked objects in the grid */ if ((floor_num > 0) && (!(player->timed[TMD_BLIND]) || (y == player->py && x == player->px))) { /* Not boring */ boring = FALSE; track_object(player->upkeep, floor_list[0]); handle_stuff(player); /* If there is more than one item... */ if (floor_num > 1) while (1) { /* Describe the pile */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, floor_num, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } else { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s.", s1, s2, s3, floor_num, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); /* Display objects */ if (((press.type == EVT_MOUSE) && (press.mouse.button == 1) && (KEY_GRID_X(press) == x) && (KEY_GRID_Y(press) == y)) || ((press.type == EVT_KBRD) && (press.key.code == 'r'))) { int rdone = 0; int pos; while (!rdone) { /* Save screen */ screen_save(); /* Display */ show_floor(floor_list, floor_num, (OLIST_WEIGHT | OLIST_GOLD), NULL); /* Describe the pile */ prt(out_val, 0, 0); press = inkey_m(); /* Load screen */ screen_load(); if (press.type == EVT_MOUSE) { pos = press.mouse.y-1; } else { pos = press.key.code - 'a'; } if (0 <= pos && pos < floor_num) { track_object(player->upkeep, floor_list[pos]); handle_stuff(player); continue; } rdone = 1; } /* Now that the user's done with the display loop, * let's do the outer loop over again */ continue; } /* Done */ break; } /* Only one object to display */ else { /* Get the single object in the list */ struct object *obj = floor_list[0]; /* Allow user to recall an object */ press = target_recall_loop_object(obj, y, x, out_val, s1, s2, s3, coords); /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; /* Plurals */ s1 = VERB_AGREEMENT(obj->number, "It is ", "They are "); /* Preposition */ s2 = "on "; } } /* Double break */ if (obj) break; name = square_apparent_name(cave, player, y, x); /* Terrain feature if needed */ if (boring || square_isinteresting(cave, y, x)) { /* Hack -- handle unknown grids */ /* Pick a prefix */ if (*s2 && square_isdoor(cave, y, x)) s2 = "in "; /* Pick proper indefinite article */ s3 = (is_a_vowel(name[0])) ? "an " : "a "; /* Hack -- special introduction for store doors */ if (square_isshop(cave, y, x)) s3 = "the entrance to the "; /* Display a message */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, name, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button == 2) break; } else { /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; } } /* Stop on everything but "return" */ if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button != 2) break; } else { if (press.key.code != KC_ENTER) break; } } mem_free(floor_list); /* Keep going */ return (press); }
/* Destroy walls (and doors) */ static void project_feature_handler_KILL_WALL(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Non-walls (etc) */ if (square_ispassable(cave, y, x)) return; /* Permanent walls */ if (square_isperm(cave, y, x)) return; /* Different treatment for different walls */ if (square_iswall(cave, y, x) && !square_hasgoldvein(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The wall turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the wall */ square_destroy_wall(cave, y, x); } else if (square_iswall(cave, y, x) && square_hasgoldvein(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The vein turns into mud!"); msg("You have found something!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the wall */ square_destroy_wall(cave, y, x); /* Place some gold */ place_gold(cave, y, x, player->depth, ORIGIN_FLOOR); } else if (square_ismagma(cave, y, x) || square_isquartz(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The vein turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the wall */ square_destroy_wall(cave, y, x); } else if (square_isrubble(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The rubble turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the rubble */ square_destroy_rubble(cave, y, x); /* Hack -- place an object */ if (randint0(100) < 10){ if (square_isseen(cave, y, x)) { msg("There was something buried in the rubble!"); context->obvious = true; } place_object(cave, y, x, player->depth, false, false, ORIGIN_RUBBLE, 0); } } else if (square_isdoor(cave, y, x)) { /* Hack -- special message */ if (square_isseen(cave, y, x)) { msg("The door turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the feature */ square_destroy_door(cave, y, x); } /* Update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Fully update the flow */ player->upkeep->update |= (PU_FORGET_FLOW | PU_UPDATE_FLOW); }