| 1797 | | |
|---|
| 1798 | | /* |
|---|
| 1799 | | * Monster health description |
|---|
| 1800 | | */ |
|---|
| 1801 | | static void look_mon_desc(char *buf, size_t max, int m_idx) |
|---|
| 1802 | | { |
|---|
| 1803 | | monster_type *m_ptr = &mon_list[m_idx]; |
|---|
| 1804 | | monster_race *r_ptr = &r_info[m_ptr->r_idx]; |
|---|
| 1805 | | |
|---|
| 1806 | | bool living = TRUE; |
|---|
| 1807 | | |
|---|
| 1808 | | |
|---|
| 1809 | | /* Determine if the monster is "living" (vs "undead") */ |
|---|
| 1810 | | if (r_ptr->flags3 & (RF3_UNDEAD)) living = FALSE; |
|---|
| 1811 | | if (r_ptr->flags3 & (RF3_DEMON)) living = FALSE; |
|---|
| 1812 | | if (strchr("Egv", r_ptr->d_char)) living = FALSE; |
|---|
| 1813 | | |
|---|
| 1814 | | |
|---|
| 1815 | | /* Healthy monsters */ |
|---|
| 1816 | | if (m_ptr->hp >= m_ptr->maxhp) |
|---|
| 1817 | | { |
|---|
| 1818 | | /* No damage */ |
|---|
| 1819 | | my_strcpy(buf, (living ? "unhurt" : "undamaged"), max); |
|---|
| 1820 | | } |
|---|
| 1821 | | else |
|---|
| 1822 | | { |
|---|
| 1823 | | /* Calculate a health "percentage" */ |
|---|
| 1824 | | int perc = 100L * m_ptr->hp / m_ptr->maxhp; |
|---|
| 1825 | | |
|---|
| 1826 | | if (perc >= 60) |
|---|
| 1827 | | my_strcpy(buf, (living ? "somewhat wounded" : "somewhat damaged"), max); |
|---|
| 1828 | | else if (perc >= 25) |
|---|
| 1829 | | my_strcpy(buf, (living ? "wounded" : "damaged"), max); |
|---|
| 1830 | | else if (perc >= 10) |
|---|
| 1831 | | my_strcpy(buf, (living ? "badly wounded" : "badly damaged"), max); |
|---|
| 1832 | | else |
|---|
| 1833 | | my_strcpy(buf, (living ? "almost dead" : "almost destroyed"), max); |
|---|
| 1834 | | } |
|---|
| 1835 | | |
|---|
| 1836 | | if (m_ptr->csleep) my_strcat(buf, ", asleep", max); |
|---|
| 1837 | | if (m_ptr->confused) my_strcat(buf, ", confused", max); |
|---|
| 1838 | | if (m_ptr->monfear) my_strcat(buf, ", afraid", max); |
|---|
| 1839 | | if (m_ptr->stunned) my_strcat(buf, ", stunned", max); |
|---|
| 1840 | | } |
|---|
| 1841 | | |
|---|
| 1842 | | |
|---|
| 1843 | | |
|---|
| 1844 | | /* |
|---|
| 1845 | | * Angband sorting algorithm -- quick sort in place |
|---|
| 1846 | | * |
|---|
| 1847 | | * Note that the details of the data we are sorting is hidden, |
|---|
| 1848 | | * and we rely on the "ang_sort_comp()" and "ang_sort_swap()" |
|---|
| 1849 | | * function hooks to interact with the data, which is given as |
|---|
| 1850 | | * two pointers, and which may have any user-defined form. |
|---|
| 1851 | | */ |
|---|
| 1852 | | void ang_sort_aux(void *u, void *v, int p, int q) |
|---|
| 1853 | | { |
|---|
| 1854 | | int z, a, b; |
|---|
| 1855 | | |
|---|
| 1856 | | /* Done sort */ |
|---|
| 1857 | | if (p >= q) return; |
|---|
| 1858 | | |
|---|
| 1859 | | /* Pivot */ |
|---|
| 1860 | | z = p; |
|---|
| 1861 | | |
|---|
| 1862 | | /* Begin */ |
|---|
| 1863 | | a = p; |
|---|
| 1864 | | b = q; |
|---|
| 1865 | | |
|---|
| 1866 | | /* Partition */ |
|---|
| 1867 | | while (TRUE) |
|---|
| 1868 | | { |
|---|
| 1869 | | /* Slide i2 */ |
|---|
| 1870 | | while (!(*ang_sort_comp)(u, v, b, z)) b--; |
|---|
| 1871 | | |
|---|
| 1872 | | /* Slide i1 */ |
|---|
| 1873 | | while (!(*ang_sort_comp)(u, v, z, a)) a++; |
|---|
| 1874 | | |
|---|
| 1875 | | /* Done partition */ |
|---|
| 1876 | | if (a >= b) break; |
|---|
| 1877 | | |
|---|
| 1878 | | /* Swap */ |
|---|
| 1879 | | (*ang_sort_swap)(u, v, a, b); |
|---|
| 1880 | | |
|---|
| 1881 | | /* Advance */ |
|---|
| 1882 | | a++, b--; |
|---|
| 1883 | | } |
|---|
| 1884 | | |
|---|
| 1885 | | /* Recurse left side */ |
|---|
| 1886 | | ang_sort_aux(u, v, p, b); |
|---|
| 1887 | | |
|---|
| 1888 | | /* Recurse right side */ |
|---|
| 1889 | | ang_sort_aux(u, v, b+1, q); |
|---|
| 1890 | | } |
|---|
| 1891 | | |
|---|
| 1892 | | |
|---|
| 1893 | | /* |
|---|
| 1894 | | * Angband sorting algorithm -- quick sort in place |
|---|
| 1895 | | * |
|---|
| 1896 | | * Note that the details of the data we are sorting is hidden, |
|---|
| 1897 | | * and we rely on the "ang_sort_comp()" and "ang_sort_swap()" |
|---|
| 1898 | | * function hooks to interact with the data, which is given as |
|---|
| 1899 | | * two pointers, and which may have any user-defined form. |
|---|
| 1900 | | */ |
|---|
| 1901 | | void ang_sort(void *u, void *v, int n) |
|---|
| 1902 | | { |
|---|
| 1903 | | /* Sort the array */ |
|---|
| 1904 | | ang_sort_aux(u, v, 0, n-1); |
|---|
| 1905 | | } |
|---|
| 1906 | | |
|---|
| 1907 | | |
|---|
| 1908 | | |
|---|
| 1909 | | |
|---|
| 1910 | | |
|---|
| 1911 | | /*** Targetting Code ***/ |
|---|
| 1912 | | |
|---|
| 1913 | | |
|---|
| 2010 | | /* |
|---|
| 2011 | | * Determine is a monster makes a reasonable target |
|---|
| 2012 | | * |
|---|
| 2013 | | * The concept of "targetting" was stolen from "Morgul" (?) |
|---|
| 2014 | | * |
|---|
| 2015 | | * The player can target any location, or any "target-able" monster. |
|---|
| 2016 | | * |
|---|
| 2017 | | * Currently, a monster is "target_able" if it is visible, and if |
|---|
| 2018 | | * the player can hit it with a projection, and the player is not |
|---|
| 2019 | | * hallucinating. This allows use of "use closest target" macros. |
|---|
| 2020 | | * |
|---|
| 2021 | | * Future versions may restrict the ability to target "trappers" |
|---|
| 2022 | | * and "mimics", but the semantics is a little bit weird. |
|---|
| 2023 | | */ |
|---|
| 2024 | | bool target_able(int m_idx) |
|---|
| 2025 | | { |
|---|
| 2026 | | int py = p_ptr->py; |
|---|
| 2027 | | int px = p_ptr->px; |
|---|
| 2028 | | |
|---|
| 2029 | | monster_type *m_ptr; |
|---|
| 2030 | | |
|---|
| 2031 | | /* No monster */ |
|---|
| 2032 | | if (m_idx <= 0) return (FALSE); |
|---|
| 2033 | | |
|---|
| 2034 | | /* Get monster */ |
|---|
| 2035 | | m_ptr = &mon_list[m_idx]; |
|---|
| 2036 | | |
|---|
| 2037 | | /* Monster must be alive */ |
|---|
| 2038 | | if (!m_ptr->r_idx) return (FALSE); |
|---|
| 2039 | | |
|---|
| 2040 | | /* Monster must be visible */ |
|---|
| 2041 | | if (!m_ptr->ml) return (FALSE); |
|---|
| 2042 | | |
|---|
| 2043 | | /* Monster must be projectable */ |
|---|
| 2044 | | if (!projectable(py, px, m_ptr->fy, m_ptr->fx)) return (FALSE); |
|---|
| 2045 | | |
|---|
| 2046 | | /* Hack -- no targeting hallucinations */ |
|---|
| 2047 | | if (p_ptr->timed[TMD_IMAGE]) return (FALSE); |
|---|
| 2048 | | |
|---|
| 2049 | | /* Hack -- Never target trappers XXX XXX XXX */ |
|---|
| 2050 | | /* if (CLEAR_ATTR && (CLEAR_CHAR)) return (FALSE); */ |
|---|
| 2051 | | |
|---|
| 2052 | | /* Assume okay */ |
|---|
| 2053 | | return (TRUE); |
|---|
| 2054 | | } |
|---|
| 2055 | | |
|---|
| 2056 | | |
|---|
| 2057 | | |
|---|
| 2058 | | |
|---|
| 2059 | | /* |
|---|
| 2060 | | * Update (if necessary) and verify (if possible) the target. |
|---|
| 2061 | | * |
|---|
| 2062 | | * We return TRUE if the target is "okay" and FALSE otherwise. |
|---|
| 2063 | | */ |
|---|
| 2064 | | bool target_okay(void) |
|---|
| 2065 | | { |
|---|
| 2066 | | /* No target */ |
|---|
| 2067 | | if (!p_ptr->target_set) return (FALSE); |
|---|
| 2068 | | |
|---|
| 2069 | | /* Accept "location" targets */ |
|---|
| 2070 | | if (p_ptr->target_who == 0) return (TRUE); |
|---|
| 2071 | | |
|---|
| 2072 | | /* Check "monster" targets */ |
|---|
| 2073 | | if (p_ptr->target_who > 0) |
|---|
| 2074 | | { |
|---|
| 2075 | | int m_idx = p_ptr->target_who; |
|---|
| 2076 | | |
|---|
| 2077 | | /* Accept reasonable targets */ |
|---|
| 2078 | | if (target_able(m_idx)) |
|---|
| 2079 | | { |
|---|
| 2080 | | monster_type *m_ptr = &mon_list[m_idx]; |
|---|
| 2081 | | |
|---|
| 2082 | | /* Get the monster location */ |
|---|
| 2083 | | p_ptr->target_row = m_ptr->fy; |
|---|
| 2084 | | p_ptr->target_col = m_ptr->fx; |
|---|
| 2085 | | |
|---|
| 2086 | | /* Good target */ |
|---|
| 2087 | | return (TRUE); |
|---|
| 2088 | | } |
|---|
| 2089 | | } |
|---|
| 2090 | | |
|---|
| 2091 | | /* Assume no target */ |
|---|
| 2092 | | return (FALSE); |
|---|
| 2093 | | } |
|---|
| 2094 | | |
|---|
| 2095 | | |
|---|
| 2096 | | /* |
|---|
| 2097 | | * Set the target to a monster (or nobody) |
|---|
| 2098 | | */ |
|---|
| 2099 | | void target_set_monster(int m_idx) |
|---|
| 2100 | | { |
|---|
| 2101 | | /* Acceptable target */ |
|---|
| 2102 | | if ((m_idx > 0) && target_able(m_idx)) |
|---|
| 2103 | | { |
|---|
| 2104 | | monster_type *m_ptr = &mon_list[m_idx]; |
|---|
| 2105 | | |
|---|
| 2106 | | /* Save target info */ |
|---|
| 2107 | | p_ptr->target_set = TRUE; |
|---|
| 2108 | | p_ptr->target_who = m_idx; |
|---|
| 2109 | | p_ptr->target_row = m_ptr->fy; |
|---|
| 2110 | | p_ptr->target_col = m_ptr->fx; |
|---|
| 2111 | | } |
|---|
| 2112 | | |
|---|
| 2113 | | /* Clear target */ |
|---|
| 2114 | | else |
|---|
| 2115 | | { |
|---|
| 2116 | | /* Reset target info */ |
|---|
| 2117 | | p_ptr->target_set = FALSE; |
|---|
| 2118 | | p_ptr->target_who = 0; |
|---|
| 2119 | | p_ptr->target_row = 0; |
|---|
| 2120 | | p_ptr->target_col = 0; |
|---|
| 2121 | | } |
|---|
| 2122 | | } |
|---|
| 2123 | | |
|---|
| 2124 | | |
|---|
| 2125 | | /* |
|---|
| 2126 | | * Set the target to a location |
|---|
| 2127 | | */ |
|---|
| 2128 | | void target_set_location(int y, int x) |
|---|
| 2129 | | { |
|---|
| 2130 | | /* Legal target */ |
|---|
| 2131 | | if (in_bounds_fully(y, x)) |
|---|
| 2132 | | { |
|---|
| 2133 | | /* Save target info */ |
|---|
| 2134 | | p_ptr->target_set = TRUE; |
|---|
| 2135 | | p_ptr->target_who = 0; |
|---|
| 2136 | | p_ptr->target_row = y; |
|---|
| 2137 | | p_ptr->target_col = x; |
|---|
| 2138 | | } |
|---|
| 2139 | | |
|---|
| 2140 | | /* Clear target */ |
|---|
| 2141 | | else |
|---|
| 2142 | | { |
|---|
| 2143 | | /* Reset target info */ |
|---|
| 2144 | | p_ptr->target_set = FALSE; |
|---|
| 2145 | | p_ptr->target_who = 0; |
|---|
| 2146 | | p_ptr->target_row = 0; |
|---|
| 2147 | | p_ptr->target_col = 0; |
|---|
| 2148 | | } |
|---|
| 2149 | | } |
|---|
| 2150 | | |
|---|
| 2151 | | |
|---|
| 2152 | | /* |
|---|
| 2153 | | * Sorting hook -- comp function -- by "distance to player" |
|---|
| 2154 | | * |
|---|
| 2155 | | * We use "u" and "v" to point to arrays of "x" and "y" positions, |
|---|
| 2156 | | * and sort the arrays by double-distance to the player. |
|---|
| 2157 | | */ |
|---|
| 2158 | | static bool ang_sort_comp_distance(const void *u, const void *v, int a, int b) |
|---|
| 2159 | | { |
|---|
| 2160 | | int py = p_ptr->py; |
|---|
| 2161 | | int px = p_ptr->px; |
|---|
| 2162 | | |
|---|
| 2163 | | byte *x = (byte*)(u); |
|---|
| 2164 | | byte *y = (byte*)(v); |
|---|
| 2165 | | |
|---|
| 2166 | | int da, db, kx, ky; |
|---|
| 2167 | | |
|---|
| 2168 | | /* Absolute distance components */ |
|---|
| 2169 | | kx = x[a]; kx -= px; kx = ABS(kx); |
|---|
| 2170 | | ky = y[a]; ky -= py; ky = ABS(ky); |
|---|
| 2171 | | |
|---|
| 2172 | | /* Approximate Double Distance to the first point */ |
|---|
| 2173 | | da = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx)); |
|---|
| 2174 | | |
|---|
| 2175 | | /* Absolute distance components */ |
|---|
| 2176 | | kx = x[b]; kx -= px; kx = ABS(kx); |
|---|
| 2177 | | ky = y[b]; ky -= py; ky = ABS(ky); |
|---|
| 2178 | | |
|---|
| 2179 | | /* Approximate Double Distance to the first point */ |
|---|
| 2180 | | db = ((kx > ky) ? (kx + kx + ky) : (ky + ky + kx)); |
|---|
| 2181 | | |
|---|
| 2182 | | /* Compare the distances */ |
|---|
| 2183 | | return (da <= db); |
|---|
| 2184 | | } |
|---|
| 2185 | | |
|---|
| 2186 | | |
|---|
| 2187 | | /* |
|---|
| 2188 | | * Sorting hook -- swap function -- by "distance to player" |
|---|
| 2189 | | * |
|---|
| 2190 | | * We use "u" and "v" to point to arrays of "x" and "y" positions, |
|---|
| 2191 | | * and sort the arrays by distance to the player. |
|---|
| 2192 | | */ |
|---|
| 2193 | | static void ang_sort_swap_distance(void *u, void *v, int a, int b) |
|---|
| 2194 | | { |
|---|
| 2195 | | byte *x = (byte*)(u); |
|---|
| 2196 | | byte *y = (byte*)(v); |
|---|
| 2197 | | |
|---|
| 2198 | | byte temp; |
|---|
| 2199 | | |
|---|
| 2200 | | /* Swap "x" */ |
|---|
| 2201 | | temp = x[a]; |
|---|
| 2202 | | x[a] = x[b]; |
|---|
| 2203 | | x[b] = temp; |
|---|
| 2204 | | |
|---|
| 2205 | | /* Swap "y" */ |
|---|
| 2206 | | temp = y[a]; |
|---|
| 2207 | | y[a] = y[b]; |
|---|
| 2208 | | y[b] = temp; |
|---|
| 2209 | | } |
|---|
| 2210 | | |
|---|
| 2211 | | |
|---|
| 2212 | | |
|---|
| 2213 | | /* |
|---|
| 2214 | | * Hack -- help "select" a location (see below) |
|---|
| 2215 | | */ |
|---|
| 2216 | | static s16b target_pick(int y1, int x1, int dy, int dx) |
|---|
| 2217 | | { |
|---|
| 2218 | | int i, v; |
|---|
| 2219 | | |
|---|
| 2220 | | int x2, y2, x3, y3, x4, y4; |
|---|
| 2221 | | |
|---|
| 2222 | | int b_i = -1, b_v = 9999; |
|---|
| 2223 | | |
|---|
| 2224 | | |
|---|
| 2225 | | /* Scan the locations */ |
|---|
| 2226 | | for (i = 0; i < temp_n; i++) |
|---|
| 2227 | | { |
|---|
| 2228 | | /* Point 2 */ |
|---|
| 2229 | | x2 = temp_x[i]; |
|---|
| 2230 | | y2 = temp_y[i]; |
|---|
| 2231 | | |
|---|
| 2232 | | /* Directed distance */ |
|---|
| 2233 | | x3 = (x2 - x1); |
|---|
| 2234 | | y3 = (y2 - y1); |
|---|
| 2235 | | |
|---|
| 2236 | | /* Verify quadrant */ |
|---|
| 2237 | | if (dx && (x3 * dx <= 0)) continue; |
|---|
| 2238 | | if (dy && (y3 * dy <= 0)) continue; |
|---|
| 2239 | | |
|---|
| 2240 | | /* Absolute distance */ |
|---|
| 2241 | | x4 = ABS(x3); |
|---|
| 2242 | | y4 = ABS(y3); |
|---|
| 2243 | | |
|---|
| 2244 | | /* Verify quadrant */ |
|---|
| 2245 | | if (dy && !dx && (x4 > y4)) continue; |
|---|
| 2246 | | if (dx && !dy && (y4 > x4)) continue; |
|---|
| 2247 | | |
|---|
| 2248 | | /* Approximate Double Distance */ |
|---|
| 2249 | | v = ((x4 > y4) ? (x4 + x4 + y4) : (y4 + y4 + x4)); |
|---|
| 2250 | | |
|---|
| 2251 | | /* Penalize location XXX XXX XXX */ |
|---|
| 2252 | | |
|---|
| 2253 | | /* Track best */ |
|---|
| 2254 | | if ((b_i >= 0) && (v >= b_v)) continue; |
|---|
| 2255 | | |
|---|
| 2256 | | /* Track best */ |
|---|
| 2257 | | b_i = i; b_v = v; |
|---|
| 2258 | | } |
|---|
| 2259 | | |
|---|
| 2260 | | /* Result */ |
|---|
| 2261 | | return (b_i); |
|---|
| 2262 | | } |
|---|
| 2263 | | |
|---|
| 2264 | | |
|---|
| 2265 | | /* |
|---|
| 2266 | | * Hack -- determine if a given location is "interesting" |
|---|
| 2267 | | */ |
|---|
| 2268 | | static bool target_set_interactive_accept(int y, int x) |
|---|
| 2269 | | { |
|---|
| 2270 | | object_type *o_ptr; |
|---|
| 2271 | | |
|---|
| 2272 | | |
|---|
| 2273 | | /* Player grids are always interesting */ |
|---|
| 2274 | | if (cave_m_idx[y][x] < 0) return (TRUE); |
|---|
| 2275 | | |
|---|
| 2276 | | |
|---|
| 2277 | | /* Handle hallucination */ |
|---|
| 2278 | | if (p_ptr->timed[TMD_IMAGE]) return (FALSE); |
|---|
| 2279 | | |
|---|
| 2280 | | |
|---|
| 2281 | | /* Visible monsters */ |
|---|
| 2282 | | if (cave_m_idx[y][x] > 0) |
|---|
| 2283 | | { |
|---|
| 2284 | | monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; |
|---|
| 2285 | | |
|---|
| 2286 | | /* Visible monsters */ |
|---|
| 2287 | | if (m_ptr->ml) return (TRUE); |
|---|
| 2288 | | } |
|---|
| 2289 | | |
|---|
| 2290 | | /* Scan all objects in the grid */ |
|---|
| 2291 | | for (o_ptr = get_first_object(y, x); o_ptr; o_ptr = get_next_object(o_ptr)) |
|---|
| 2292 | | { |
|---|
| 2293 | | /* Memorized object */ |
|---|
| 2294 | | if (o_ptr->marked && !squelch_hide_item(o_ptr)) return (TRUE); |
|---|
| 2295 | | } |
|---|
| 2296 | | |
|---|
| 2297 | | /* Interesting memorized features */ |
|---|
| 2298 | | if (cave_info[y][x] & (CAVE_MARK)) |
|---|
| 2299 | | { |
|---|
| 2300 | | /* Notice glyphs */ |
|---|
| 2301 | | if (cave_feat[y][x] == FEAT_GLYPH) return (TRUE); |
|---|
| 2302 | | |
|---|
| 2303 | | /* Notice doors */ |
|---|
| 2304 | | if (cave_feat[y][x] == FEAT_OPEN) return (TRUE); |
|---|
| 2305 | | if (cave_feat[y][x] == FEAT_BROKEN) return (TRUE); |
|---|
| 2306 | | |
|---|
| 2307 | | /* Notice stairs */ |
|---|
| 2308 | | if (cave_feat[y][x] == FEAT_LESS) return (TRUE); |
|---|
| 2309 | | if (cave_feat[y][x] == FEAT_MORE) return (TRUE); |
|---|
| 2310 | | |
|---|
| 2311 | | /* Notice shops */ |
|---|
| 2312 | | if ((cave_feat[y][x] >= FEAT_SHOP_HEAD) && |
|---|
| 2313 | | (cave_feat[y][x] <= FEAT_SHOP_TAIL)) return (TRUE); |
|---|
| 2314 | | |
|---|
| 2315 | | /* Notice traps */ |
|---|
| 2316 | | if ((cave_feat[y][x] >= FEAT_TRAP_HEAD) && |
|---|
| 2317 | | (cave_feat[y][x] <= FEAT_TRAP_TAIL)) return (TRUE); |
|---|
| 2318 | | |
|---|
| 2319 | | /* Notice doors */ |
|---|
| 2320 | | if ((cave_feat[y][x] >= FEAT_DOOR_HEAD) && |
|---|
| 2321 | | (cave_feat[y][x] <= FEAT_DOOR_TAIL)) return (TRUE); |
|---|
| 2322 | | |
|---|
| 2323 | | /* Notice rubble */ |
|---|
| 2324 | | if (cave_feat[y][x] == FEAT_RUBBLE) return (TRUE); |
|---|
| 2325 | | |
|---|
| 2326 | | /* Notice veins with treasure */ |
|---|
| 2327 | | if (cave_feat[y][x] == FEAT_MAGMA_K) return (TRUE); |
|---|
| 2328 | | if (cave_feat[y][x] == FEAT_QUARTZ_K) return (TRUE); |
|---|
| 2329 | | } |
|---|
| 2330 | | |
|---|
| 2331 | | /* Nope */ |
|---|
| 2332 | | return (FALSE); |
|---|
| 2333 | | } |
|---|
| 2334 | | |
|---|
| 2335 | | |
|---|
| 2336 | | /* |
|---|
| 2337 | | * Prepare the "temp" array for "target_interactive_set" |
|---|
| 2338 | | * |
|---|
| 2339 | | * Return the number of target_able monsters in the set. |
|---|
| 2340 | | */ |
|---|
| 2341 | | static void target_set_interactive_prepare(int mode) |
|---|
| 2342 | | { |
|---|
| 2343 | | int y, x; |
|---|
| 2344 | | |
|---|
| 2345 | | /* Reset "temp" array */ |
|---|
| 2346 | | temp_n = 0; |
|---|
| 2347 | | |
|---|
| 2348 | | /* Scan the current panel */ |
|---|
| 2349 | | for (y = Term->offset_y; y < Term->offset_y + SCREEN_HGT; y++) |
|---|
| 2350 | | { |
|---|
| 2351 | | for (x = Term->offset_x; x < Term->offset_x + SCREEN_WID; x++) |
|---|
| 2352 | | { |
|---|
| 2353 | | /* Check bounds */ |
|---|
| 2354 | | if (!in_bounds_fully(y, x)) continue; |
|---|
| 2355 | | |
|---|
| 2356 | | /* Require "interesting" contents */ |
|---|
| 2357 | | if (!target_set_interactive_accept(y, x)) continue; |
|---|
| 2358 | | |
|---|
| 2359 | | /* Special mode */ |
|---|
| 2360 | | if (mode & (TARGET_KILL)) |
|---|
| 2361 | | { |
|---|
| 2362 | | /* Must contain a monster */ |
|---|
| 2363 | | if (!(cave_m_idx[y][x] > 0)) continue; |
|---|
| 2364 | | |
|---|
| 2365 | | /* Must be a targettable monster */ |
|---|
| 2366 | | if (!target_able(cave_m_idx[y][x])) continue; |
|---|
| 2367 | | } |
|---|
| 2368 | | |
|---|
| 2369 | | /* Save the location */ |
|---|
| 2370 | | temp_x[temp_n] = x; |
|---|
| 2371 | | temp_y[temp_n] = y; |
|---|
| 2372 | | temp_n++; |
|---|
| 2373 | | } |
|---|
| 2374 | | } |
|---|
| 2375 | | |
|---|
| 2376 | | /* Set the sort hooks */ |
|---|
| 2377 | | ang_sort_comp = ang_sort_comp_distance; |
|---|
| 2378 | | ang_sort_swap = ang_sort_swap_distance; |
|---|
| 2379 | | |
|---|
| 2380 | | /* Sort the positions */ |
|---|
| 2381 | | ang_sort(temp_x, temp_y, temp_n); |
|---|
| 2382 | | } |
|---|
| 2383 | | |
|---|
| 2384 | | |
|---|
| 2385 | | /* |
|---|
| 2386 | | * Examine a grid, return a keypress. |
|---|
| 2387 | | * |
|---|
| 2388 | | * The "mode" argument contains the "TARGET_LOOK" bit flag, which |
|---|
| 2389 | | * indicates that the "space" key should scan through the contents |
|---|
| 2390 | | * of the grid, instead of simply returning immediately. This lets |
|---|
| 2391 | | * the "look" command get complete information, without making the |
|---|
| 2392 | | * "target" command annoying. |
|---|
| 2393 | | * |
|---|
| 2394 | | * The "info" argument contains the "commands" which should be shown |
|---|
| 2395 | | * inside the "[xxx]" text. This string must never be empty, or grids |
|---|
| 2396 | | * containing monsters will be displayed with an extra comma. |
|---|
| 2397 | | * |
|---|
| 2398 | | * Note that if a monster is in the grid, we update both the monster |
|---|
| 2399 | | * recall info and the health bar info to track that monster. |
|---|
| 2400 | | * |
|---|
| 2401 | | * This function correctly handles multiple objects per grid, and objects |
|---|
| 2402 | | * and terrain features in the same grid, though the latter never happens. |
|---|
| 2403 | | * |
|---|
| 2404 | | * This function must handle blindness/hallucination. |
|---|
| 2405 | | */ |
|---|
| 2406 | | static ui_event_data target_set_interactive_aux(int y, int x, int mode, cptr info) |
|---|
| 2407 | | { |
|---|
| 2408 | | s16b this_o_idx = 0, next_o_idx = 0; |
|---|
| 2409 | | |
|---|
| 2410 | | cptr s1, s2, s3; |
|---|
| 2411 | | |
|---|
| 2412 | | bool boring; |
|---|
| 2413 | | |
|---|
| 2414 | | bool floored; |
|---|
| 2415 | | |
|---|
| 2416 | | int feat; |
|---|
| 2417 | | |
|---|
| 2418 | | int floor_list[MAX_FLOOR_STACK]; |
|---|
| 2419 | | int floor_num; |
|---|
| 2420 | | |
|---|
| 2421 | | ui_event_data query; |
|---|
| 2422 | | |
|---|
| 2423 | | char out_val[256]; |
|---|
| 2424 | | |
|---|
| 2425 | | |
|---|
| 2426 | | /* Repeat forever */ |
|---|
| 2427 | | while (1) |
|---|
| 2428 | | { |
|---|
| 2429 | | /* Paranoia */ |
|---|
| 2430 | | query.key = ' '; |
|---|
| 2431 | | |
|---|
| 2432 | | /* Assume boring */ |
|---|
| 2433 | | boring = TRUE; |
|---|
| 2434 | | |
|---|
| 2435 | | /* Default */ |
|---|
| 2436 | | s1 = "You see "; |
|---|
| 2437 | | s2 = ""; |
|---|
| 2438 | | s3 = ""; |
|---|
| 2439 | | |
|---|
| 2440 | | |
|---|
| 2441 | | /* The player */ |
|---|
| 2442 | | if (cave_m_idx[y][x] < 0) |
|---|
| 2443 | | { |
|---|
| 2444 | | /* Description */ |
|---|
| 2445 | | s1 = "You are "; |
|---|
| 2446 | | |
|---|
| 2447 | | /* Preposition */ |
|---|
| 2448 | | s2 = "on "; |
|---|
| 2449 | | } |
|---|
| 2450 | | |
|---|
| 2451 | | |
|---|
| 2452 | | /* Hack -- hallucination */ |
|---|
| 2453 | | if (p_ptr->timed[TMD_IMAGE]) |
|---|
| 2454 | | { |
|---|
| 2455 | | cptr name = "something strange"; |
|---|
| 2456 | | |
|---|
| 2457 | | /* Display a message */ |
|---|
| 2458 | | if (p_ptr->wizard) |
|---|
| 2459 | | { |
|---|
| 2460 | | strnfmt(out_val, sizeof(out_val), |
|---|
| 2461 | | "%s%s%s%s [%s] (%d:%d)", s1, s2, s3, name, info, y, x); |
|---|
| 2462 | | } |
|---|
| 2463 | | else |
|---|
| 2464 | | { |
|---|
| 2465 | | strnfmt(out_val, sizeof(out_val), |
|---|
| 2466 | | "%s%s%s%s [%s]", s1, s2, s3, name, info); |
|---|
| 2467 | | } |
|---|
| 2468 | | |
|---|
| 2469 | | prt(out_val, 0, 0); |
|---|
| 2470 | | move_cursor_relative(y, x); |
|---|
| 2471 | | query = inkey_ex(); |
|---|
| 2472 | | |
|---|
| 2473 | | /* Stop on everything but "return" */ |
|---|
| 2474 | | if ((query.key != '\n') && (query.key != '\r')) break; |
|---|
| 2475 | | |
|---|
| 2476 | | /* Repeat forever */ |
|---|
| 2477 | | continue; |
|---|
| 2478 | | } |
|---|
| 2479 | | |
|---|
| 2480 | | |
|---|
| 2481 | | /* Actual monsters */ |
|---|
| 2482 | | if (cave_m_idx[y][x] > 0) |
|---|
| 2483 | | { |
|---|
| 2484 | | monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; |
|---|
| 2485 | | monster_race *r_ptr = &r_info[m_ptr->r_idx]; |
|---|
| 2486 | | |
|---|
| 2487 | | /* Visible */ |
|---|
| 2488 | | if (m_ptr->ml) |
|---|
| 2489 | | { |
|---|
| 2490 | | bool recall = FALSE; |
|---|
| 2491 | | |
|---|
| 2492 | | char m_name[80]; |
|---|
| 2493 | | |
|---|
| 2494 | | /* Not boring */ |
|---|
| 2495 | | boring = FALSE; |
|---|
| 2496 | | |
|---|
| 2497 | | /* Get the monster name ("a kobold") */ |
|---|
| 2498 | | monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND2); |
|---|
| 2499 | | |
|---|
| 2500 | | /* Hack -- track this monster race */ |
|---|
| 2501 | | monster_race_track(m_ptr->r_idx); |
|---|
| 2502 | | |
|---|
| 2503 | | /* Hack -- health bar for this monster */ |
|---|
| 2504 | | health_track(cave_m_idx[y][x]); |
|---|
| 2505 | | |
|---|
| 2506 | | /* Hack -- handle stuff */ |
|---|
| 2507 | | handle_stuff(); |
|---|
| 2508 | | |
|---|
| 2509 | | /* Interact */ |
|---|
| 2510 | | while (1) |
|---|
| 2511 | | { |
|---|
| 2512 | | /* Recall */ |
|---|
| 2513 | | if (recall) |
|---|
| 2514 | | { |
|---|
| 2515 | | /* Save screen */ |
|---|
| 2516 | | screen_save(); |
|---|
| 2517 | | |
|---|
| 2518 | | /* Recall on screen */ |
|---|
| 2519 | | screen_roff(m_ptr->r_idx); |
|---|
| 2520 | | |
|---|
| 2521 | | /* Hack -- Complete the prompt (again) */ |
|---|
| 2522 | | Term_addstr(-1, TERM_WHITE, format(" [r,%s]", info)); |
|---|
| 2523 | | |
|---|
| 2524 | | /* Command */ |
|---|
| 2525 | | query = inkey_ex(); |
|---|
| 2526 | | |
|---|
| 2527 | | /* Load screen */ |
|---|
| 2528 | | screen_load(); |
|---|
| 2529 | | } |
|---|
| 2530 | | |
|---|
| 2531 | | /* Normal */ |
|---|
| 2532 | | else |
|---|
| 2533 | | { |
|---|
| 2534 | | char buf[80]; |
|---|
| 2535 | | |
|---|
| 2536 | | /* Describe the monster */ |
|---|
| 2537 | | look_mon_desc(buf, sizeof(buf), cave_m_idx[y][x]); |
|---|
| 2538 | | |
|---|
| 2539 | | /* Describe, and prompt for recall */ |
|---|
| 2540 | | if (p_ptr->wizard) |
|---|
| 2541 | | { |
|---|
| 2542 | | strnfmt(out_val, sizeof(out_val), |
|---|
| 2543 | | "%s%s%s%s (%s) [r,%s] (%d:%d)", |
|---|
| 2544 | | s1, s2, s3, m_name, buf, info, y, x); |
|---|
| 2545 | | } |
|---|
| 2546 | | else |
|---|
| 2547 | | { |
|---|
| 2548 | | strnfmt(out_val, sizeof(out_val), |
|---|
| 2549 | | "%s%s%s%s (%s) [r,%s]", |
|---|
| 2550 | | s1, s2, s3, m_name, buf, info); |
|---|
| 2551 | | } |
|---|
| 2552 | | |
|---|
| 2553 | | prt(out_val, 0, 0); |
|---|
| 2554 | | |
|---|
| 2555 | | /* Place cursor */ |
|---|
| 2556 | | move_cursor_relative(y, x); |
|---|
| 2557 | | |
|---|
| 2558 | | /* Command */ |
|---|
| 2559 | | query = inkey_ex(); |
|---|
| 2560 | | } |
|---|
| 2561 | | |
|---|
| 2562 | | /* Normal commands */ |
|---|
| 2563 | | if (query.key != 'r') break; |
|---|
| 2564 | | |
|---|
| 2565 | | /* Toggle recall */ |
|---|
| 2566 | | recall = !recall; |
|---|
| 2567 | | } |
|---|
| 2568 | | |
|---|
| 2569 | | /* Stop on everything but "return"/"space" */ |
|---|
| 2570 | | if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; |
|---|
| 2571 | | |
|---|
| 2572 | | /* Sometimes stop at "space" key */ |
|---|
| 2573 | | if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; |
|---|
| 2574 | | |
|---|
| 2575 | | /* Change the intro */ |
|---|
| 2576 | | s1 = "It is "; |
|---|
| 2577 | | |
|---|
| 2578 | | /* Hack -- take account of gender */ |
|---|
| 2579 | | if (r_ptr->flags1 & (RF1_FEMALE)) s1 = "She is "; |
|---|
| 2580 | | else if (r_ptr->flags1 & (RF1_MALE)) s1 = "He is "; |
|---|
| 2581 | | |
|---|
| 2582 | | /* Use a preposition */ |
|---|
| 2583 | | s2 = "carrying "; |
|---|
| 2584 | | |
|---|
| 2585 | | /* Scan all objects being carried */ |
|---|
| 2586 | | for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) |
|---|
| 2587 | | { |
|---|
| 2588 | | char o_name[80]; |
|---|
| 2589 | | |
|---|
| 2590 | | object_type *o_ptr; |
|---|
| 2591 | | |
|---|
| 2592 | | /* Get the object */ |
|---|
| 2593 | | o_ptr = &o_list[this_o_idx]; |
|---|
| 2594 | | |
|---|
| 2595 | | /* Get the next object */ |
|---|
| 2596 | | next_o_idx = o_ptr->next_o_idx; |
|---|
| 2597 | | |
|---|
| 2598 | | /* Obtain an object description */ |
|---|
| 2599 | | object_desc(o_name, sizeof(o_name), o_ptr, TRUE, ODESC_FULL); |
|---|
| 2600 | | |
|---|
| 2601 | | /* Describe the object */ |
|---|
| 2602 | | if (p_ptr->wizard) |
|---|
| 2603 | | { |
|---|
| 2604 | | strnfmt(out_val, sizeof(out_val), |
|---|
| 2605 | | "%s%s%s%s [%s] (%d:%d)", |
|---|
| 2606 | | s1, s2, s3, o_name, info, y, x); |
|---|
| 2607 | | } |
|---|
| 2608 | | else |
|---|
| 2609 | | { |
|---|
| 2610 | | strnfmt(out_val, sizeof(out_val), |
|---|
| 2611 | | "%s%s%s%s [%s]", s1, s2, s3, o_name, info); |
|---|
| 2612 | | } |
|---|
| 2613 | | |
|---|
| 2614 | | prt(out_val, 0, 0); |
|---|
| 2615 | | move_cursor_relative(y, x); |
|---|
| 2616 | | query = inkey_ex(); |
|---|
| 2617 | | |
|---|
| 2618 | | /* Stop on everything but "return"/"space" */ |
|---|
| 2619 | | if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; |
|---|
| 2620 | | |
|---|
| 2621 | | /* Sometimes stop at "space" key */ |
|---|
| 2622 | | if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; |
|---|
| 2623 | | |
|---|
| 2624 | | /* Change the intro */ |
|---|
| 2625 | | s2 = "also carrying "; |
|---|
| 2626 | | } |
|---|
| 2627 | | |
|---|
| 2628 | | /* Double break */ |
|---|
| 2629 | | if (this_o_idx) break; |
|---|
| 2630 | | |
|---|
| 2631 | | /* Use a preposition */ |
|---|
| 2632 | | s2 = "on "; |
|---|
| 2633 | | } |
|---|
| 2634 | | } |
|---|
| 2635 | | |
|---|
| 2636 | | |
|---|
| 2637 | | /* Assume not floored */ |
|---|
| 2638 | | floored = FALSE; |
|---|
| 2639 | | |
|---|
| 2640 | | floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), y, x, 0x02); |
|---|
| 2641 | | |
|---|
| 2642 | | /* Scan all marked objects in the grid */ |
|---|
| 2643 | | if ((floor_num > 0) && |
|---|
| 2644 | | (!(p_ptr->timed[TMD_BLIND]) || (y == p_ptr->py && x == p_ptr->px))) |
|---|
| 2645 | | { |
|---|
| 2646 | | /* Not boring */ |
|---|
| 2647 | | boring = FALSE; |
|---|
| 2648 | | |
|---|
| 2649 | | /* If there is more than one item... */ |
|---|
| 2650 | | if (floor_num > 1) while (1) |
|---|
| 2651 | | { |
|---|
| 2652 | | floored = TRUE; |
|---|
| 2653 | | |
|---|
| 2654 | | /* Describe the pile */ |
|---|
| 2655 | | if (p_ptr->wizard) |
|---|
| 2656 | | { |
|---|
| 2657 | | strnfmt(out_val, sizeof(out_val), |
|---|
| 2658 | | "%s%s%sa pile of %d objects [r,%s] (%d:%d)", |
|---|
| 2659 | | s1, s2, s3, floor_num, info, y, x); |
|---|
| 2660 | | } |
|---|
| 2661 | | else |
|---|
| 2662 | | { |
|---|
| 2663 | | strnfmt(out_val, sizeof(out_val), |
|---|
| 2664 | | "%s%s%sa pile of %d objects [r,%s]", |
|---|
| 2665 | | s1, s2, s3, floor_num, info); |
|---|
| 2666 | | } |
|---|
| 2667 | | |
|---|
| 2668 | | prt(out_val, 0, 0); |
|---|
| 2669 | | move_cursor_relative(y, x); |
|---|
| 2670 | | query = inkey_ex(); |
|---|
| 2671 | | |
|---|
| 2672 | | /* Display objects */ |
|---|
| 2673 | | if (query.key == 'r') |
|---|
| 2674 | | { |
|---|
| 2675 | | /* Save screen */ |
|---|
| 2676 | | screen_save(); |
|---|
| 2677 | | |
|---|
| 2678 | | /* Display */ |
|---|
| 2679 | | show_floor(floor_list, floor_num, TRUE); |
|---|
| 2680 | | |
|---|
| 2681 | | /* Describe the pile */ |
|---|
| 2682 | | prt(out_val, 0, 0); |
|---|
| 2683 | | query = inkey_ex(); |
|---|
| 2684 | | |
|---|
| 2685 | | /* Load screen */ |
|---|
| 2686 | | screen_load(); |
|---|
| 2687 | | |
|---|
| 2688 | | /* Continue on 'r' only */ |
|---|
| 2689 | | if (query.key == 'r') continue; |
|---|
| 2690 | | } |
|---|
| 2691 | | |
|---|
| 2692 | | /* Done */ |
|---|
| 2693 | | break; |
|---|
| 2694 | | } |
|---|
| 2695 | | /* Only one object to display */ |
|---|
| 2696 | | else |
|---|
| 2697 | | { |
|---|
| 2698 | | |
|---|
| 2699 | | char o_name[80]; |
|---|
| 2700 | | |
|---|
| 2701 | | /* Get the single object in the list */ |
|---|
| 2702 | | object_type *o_ptr = &o_list[floor_list[0]]; |
|---|
| 2703 | | |
|---|
| 2704 | | /* Not boring */ |
|---|
| 2705 | | boring = FALSE; |
|---|
| 2706 | | |
|---|
| 2707 | | /* Obtain an object description */ |
|---|
| 2708 | | object_desc(o_name, sizeof(o_name), o_ptr, TRUE, ODESC_FULL); |
|---|
| 2709 | | |
|---|
| 2710 | | /* Describe the object */ |
|---|
| 2711 | | if (p_ptr->wizard) |
|---|
| 2712 | | { |
|---|
| 2713 | | & |
|---|