1 /* $Id$ */
2 /* File: cave.c */
3
4 /* Purpose: low level dungeon routines -BEN- */
5
6 #define SERVER
7
8 #include "angband.h"
9
10 /*
11 * monsters with 'RF1_ATTR_MULTI' uses colour according to their
12 * breath if it is on. (possible bottleneck, tho)
13 */
14 #define MULTI_HUED_PROPER
15
16 /* View_shade_floor really shades all floor types, not just FEAT_FLOOR.
17 For this, the floor feats must have SPECIAL_LITE flag (or LAMP_LITE).
18 This usually doesn't look as cool as you might expect. - C. Blue
19 Note: This overrides NO_SHADE flag. */
20 //#define SHADE_ALL_FLOOR
21
22 /* Don't shade self-illuminated grids that are out of view, if they are on the
23 world surface and it's night time.
24 Primary idea: Shop entrance areas don't get partially shaded with slate tone
25 when player circles around them. It looked a little bit odd maybe. */
26 #define DONT_SHADE_GLOW_AT_NIGHT
27
28 /*
29 * Scans for cave_type array pointer.
30 * Returns cave array relative to the dimensions
31 * specified in the arguments. Returns NULL for
32 * a failure.
33 */
getcave(struct worldpos * wpos)34 cave_type **getcave(struct worldpos *wpos)
35 {
36 struct wilderness_type *wild;
37 wild = &wild_info[wpos->wy][wpos->wx];
38 if (wpos->wx > MAX_WILD_X || wpos->wx < 0 || wpos->wy > MAX_WILD_Y || wpos->wy < 0) return(NULL);
39 if (wpos->wz == 0) {
40 return(wild->cave);
41 } else {
42 if (wpos->wz > 0) {
43 if (wild->tower && wpos->wz <= wild->tower->maxdepth) {
44 return(wild->tower->level[wpos->wz-1].cave);
45 }
46 }
47 else if (wild->dungeon && wpos->wz >= -wild->dungeon->maxdepth)
48 return(wild->dungeon->level[ABS(wpos->wz)-1].cave);
49 }
50 return ((cave_type **)NULL);
51 }
52
53 /* an afterthought - it is often needed without up/down info */
getdungeon(struct worldpos * wpos)54 struct dungeon_type *getdungeon(struct worldpos *wpos)
55 {
56 struct wilderness_type *wild;
57 wild = &wild_info[wpos->wy][wpos->wx];
58 if (wpos->wz == 0) return NULL;
59 else {
60 if ((wpos->wz > 0) && !wild->tower) return NULL;
61 if ((wpos->wz < 0) && !wild->dungeon) return NULL;
62 return(wpos->wz > 0 ? wild->tower : wild->dungeon);
63 }
64 }
65
66 /* another afterthought - it is often needed without up/down info */
getfloor(struct worldpos * wpos)67 struct dun_level *getfloor(struct worldpos *wpos)
68 {
69 struct wilderness_type *wild;
70 wild = &wild_info[wpos->wy][wpos->wx];
71 if (wpos->wz == 0) {
72 /* return(wild); */
73 return(NULL);
74 } else {
75 if (wpos->wz > 0)
76 return(&wild->tower->level[wpos->wz - 1]);
77 else
78 return(&wild->dungeon->level[ABS(wpos->wz) - 1]);
79 }
80 }
81
new_level_up_x(struct worldpos * wpos,int pos)82 void new_level_up_x(struct worldpos *wpos, int pos)
83 {
84 struct wilderness_type *wild;
85 wild = &wild_info[wpos->wy][wpos->wx];
86 if (wpos->wz == 0) wild->up_x = pos;
87 else if (wpos->wz > 0)
88 wild->tower->level[wpos->wz - 1].up_x = pos;
89 else
90 wild->dungeon->level[ABS(wpos->wz) - 1].up_x = pos;
91 }
new_level_up_y(struct worldpos * wpos,int pos)92 void new_level_up_y(struct worldpos *wpos, int pos)
93 {
94 struct wilderness_type *wild;
95 wild = &wild_info[wpos->wy][wpos->wx];
96 if (wpos->wz == 0) wild->up_y = pos;
97 else if (wpos->wz > 0)
98 wild->tower->level[wpos->wz - 1].up_y = pos;
99 else
100 wild->dungeon->level[ABS(wpos->wz) - 1].up_y = pos;
101 }
new_level_down_x(struct worldpos * wpos,int pos)102 void new_level_down_x(struct worldpos *wpos, int pos)
103 {
104 struct wilderness_type *wild;
105 wild = &wild_info[wpos->wy][wpos->wx];
106 if (wpos->wz == 0) wild->dn_x = pos;
107 else if (wpos->wz > 0)
108 wild->tower->level[wpos->wz - 1].dn_x = pos;
109 else
110 wild->dungeon->level[ABS(wpos->wz) - 1].dn_x = pos;
111 }
new_level_down_y(struct worldpos * wpos,int pos)112 void new_level_down_y(struct worldpos *wpos, int pos)
113 {
114 struct wilderness_type *wild;
115 wild = &wild_info[wpos->wy][wpos->wx];
116 if (wpos->wz == 0) wild->dn_y = pos;
117 else if (wpos->wz > 0)
118 wild->tower->level[wpos->wz - 1].dn_y = pos;
119 else
120 wild->dungeon->level[ABS(wpos->wz) - 1].dn_y = pos;
121 }
new_level_rand_x(struct worldpos * wpos,int pos)122 void new_level_rand_x(struct worldpos *wpos, int pos)
123 {
124 struct wilderness_type *wild;
125 wild = &wild_info[wpos->wy][wpos->wx];
126 if (wpos->wz == 0) wild->rn_x = pos;
127 else if (wpos->wz > 0)
128 wild->tower->level[wpos->wz - 1].rn_x = pos;
129 else
130 wild->dungeon->level[ABS(wpos->wz) - 1].rn_x = pos;
131 }
new_level_rand_y(struct worldpos * wpos,int pos)132 void new_level_rand_y(struct worldpos *wpos, int pos)
133 {
134 struct wilderness_type *wild;
135 wild = &wild_info[wpos->wy][wpos->wx];
136 if (wpos->wz == 0) wild->rn_y = pos;
137 else if (wpos->wz > 0)
138 wild->tower->level[wpos->wz - 1].rn_y = pos;
139 else
140 wild->dungeon->level[ABS(wpos->wz) - 1].rn_y = pos;
141 }
142
level_up_x(struct worldpos * wpos)143 byte level_up_x(struct worldpos *wpos)
144 {
145 struct wilderness_type *wild;
146 wild = &wild_info[wpos->wy][wpos->wx];
147 if (wpos->wz == 0) return (wild->up_x);
148 return (wpos->wz > 0? wild->tower->level[wpos->wz - 1].up_x : wild->dungeon->level[ABS(wpos->wz) - 1].up_x);
149 }
level_up_y(struct worldpos * wpos)150 byte level_up_y(struct worldpos *wpos)
151 {
152 struct wilderness_type *wild;
153 wild = &wild_info[wpos->wy][wpos->wx];
154 if (wpos->wz == 0) return (wild->up_y);
155 return (wpos->wz > 0 ? wild->tower->level[wpos->wz - 1].up_y : wild->dungeon->level[ABS(wpos->wz) - 1].up_y);
156 }
level_down_x(struct worldpos * wpos)157 byte level_down_x(struct worldpos *wpos)
158 {
159 struct wilderness_type *wild;
160 wild = &wild_info[wpos->wy][wpos->wx];
161 if (wpos->wz == 0) return (wild->dn_x);
162 return(wpos->wz > 0 ? wild->tower->level[wpos->wz - 1].dn_x : wild->dungeon->level[ABS(wpos->wz) - 1].dn_x);
163 }
level_down_y(struct worldpos * wpos)164 byte level_down_y(struct worldpos *wpos)
165 {
166 struct wilderness_type *wild;
167 wild = &wild_info[wpos->wy][wpos->wx];
168 if (wpos->wz == 0) return (wild->dn_y);
169 return (wpos->wz > 0 ? wild->tower->level[wpos->wz - 1].dn_y : wild->dungeon->level[ABS(wpos->wz) - 1].dn_y);
170 }
level_rand_x(struct worldpos * wpos)171 byte level_rand_x(struct worldpos *wpos)
172 {
173 struct wilderness_type *wild;
174 wild = &wild_info[wpos->wy][wpos->wx];
175 if (wpos->wz == 0) return(wild->rn_x);
176 return (wpos->wz > 0 ? wild->tower->level[wpos->wz - 1].rn_x : wild->dungeon->level[ABS(wpos->wz) - 1].rn_x);
177 }
level_rand_y(struct worldpos * wpos)178 byte level_rand_y(struct worldpos *wpos)
179 {
180 struct wilderness_type *wild;
181 wild = &wild_info[wpos->wy][wpos->wx];
182 if (wpos->wz == 0) return (wild->rn_y);
183 return (wpos->wz > 0 ? wild->tower->level[wpos->wz - 1].rn_y : wild->dungeon->level[ABS(wpos->wz) - 1].rn_y);
184 }
185
get_staircase_colour(dungeon_type * d_ptr,byte * c)186 static int get_staircase_colour(dungeon_type *d_ptr, byte *c) {
187 /* (experimental testing stuff) */
188 if (d_ptr->flags3 & (DF3_NO_TELE | DF3_NO_ESP | DF3_LIMIT_ESP | DF3_NO_SUMMON)) {
189 *c = TERM_L_UMBER;
190 return 0;
191 }
192
193 /* override colour from easiest to worst */
194 /* joker overrides the king ;) */
195 if (d_ptr->flags2 & DF2_NO_DEATH) {
196 *c = TERM_GREEN;
197 return -1;
198 }
199
200 if (d_ptr->flags2 & DF2_NO_EXIT_WOR) {
201 if ((d_ptr->flags2 & DF2_IRON) || (d_ptr->flags1 & (DF1_FORCE_DOWN | DF1_NO_UP))) {
202 *c = TERM_DARKNESS;
203 return 7;
204 }
205 }
206 if ((d_ptr->flags2 & DF2_NO_EXIT_STAIR)
207 && (d_ptr->flags2 & DF2_NO_EXIT_PROB)
208 && (d_ptr->flags2 & DF2_NO_EXIT_FLOAT)
209 && (d_ptr->flags2 & DF2_NO_EXIT_WOR)) {
210 *c = TERM_DARKNESS;
211 return 7;
212 }
213
214 if (d_ptr->flags2 & DF2_IRON) {
215 *c = TERM_L_DARK;
216 return 6;
217 }
218 if (d_ptr->flags2 & DF2_HELL) {
219 *c = TERM_FIRE;
220 return 5;
221 }
222 if (d_ptr->flags1 & DF1_FORCE_DOWN) {
223 *c = TERM_L_RED;
224 return 4;
225 }
226 if (d_ptr->flags1 & DF1_NO_RECALL) {
227 *c = TERM_RED;
228 return 3;
229 }
230 if (d_ptr->flags1 & DF1_NO_UP) {
231 *c = TERM_ORANGE;
232 return 2;
233 }
234 if (d_ptr->flags2 & DF2_NO_RECALL_INTO) {
235 *c = TERM_YELLOW;
236 return 1;
237 }
238
239 /* normal */
240 *c = TERM_WHITE;
241 return 0;
242 }
243
244 /* For staircase-placement.
245 Mode: 1 stairs, (doesn't make sense? 2 wor,) (handled in cmd2.c, can't handle here actually: 4 probtravel, 8 ghostfloating) */
can_go_up(struct worldpos * wpos,byte mode)246 bool can_go_up(struct worldpos *wpos, byte mode)
247 {
248 struct wilderness_type *wild = &wild_info[wpos->wy][wpos->wx];
249
250 struct dungeon_type *d_ptr = wild->tower;
251 if (wpos->wz < 0) d_ptr = wild->dungeon;
252
253 #if 0 /* fixed (old /update-dun killed flags2) */
254 /* paranoia, but caused panic: in wilderness_gen() cmd_up({0,0,0},0x1) would return 1
255 resulting in bad up/down values for staircase generation when it attempts to locate
256 a staircase leading into pvp-arena and put some feats around it (at coords 0,0 ...).
257 Apparently, WILD_F_UP is set here, too. And even w_ptr->tower was also valid.
258 todo: fix this. -C. Blue */
259 if (wpos->wz == 0 && wpos->wx == WPOS_PVPARENA_X && wpos->wy == WPOS_PVPARENA_Y &&
260 WPOS_PVPARENA_Z > 0) return (FALSE);
261 #endif
262
263 /* Check for empty staircase without any connected dungeon/tower! */
264 if (!d_ptr) return((wild->flags&WILD_F_UP)?TRUE:FALSE); /* you MAY create 'empty' staircase */
265
266 if (mode & 0x1) {
267 if (!wpos->wz && (d_ptr->flags2 & DF2_NO_ENTRY_STAIR)) return(FALSE);
268 if (wpos->wz == -1 && (d_ptr->flags2 & DF2_NO_EXIT_STAIR)) return(FALSE);
269 if (wpos->wz && (d_ptr->flags2 & DF2_NO_STAIRS_UP)) return(FALSE);
270 }
271
272 if (wpos->wz<0) {
273 if ((d_ptr->flags1 & (DF1_NO_UP | DF1_FORCE_DOWN)) ||
274 (d_ptr->flags2 & DF2_IRON))
275 return(FALSE);
276 return(TRUE);
277 }
278
279 if (wpos->wz>0) return(wpos->wz < wild->tower->maxdepth);
280
281 return((wild->flags&WILD_F_UP)?TRUE:FALSE);
282 }
283 /* For staircase-placement and sinking/pit traps.
284 Mode: 1 stairs, (doesn't make sense? 2 wor,) (handled in cmd2.c, can't handle here actually: 4 probtravel, 8 ghostfloating) */
can_go_down(struct worldpos * wpos,byte mode)285 bool can_go_down(struct worldpos *wpos, byte mode)
286 {
287 struct wilderness_type *wild = &wild_info[wpos->wy][wpos->wx];
288
289 struct dungeon_type *d_ptr = wild->dungeon;
290 if (wpos->wz > 0) d_ptr = wild->tower;
291
292 #if 0 /* fixed (old /update-dun killed flags2) */
293 /* paranoia, but caused panic: in wilderness_gen() cmd_up({0,0,0},0x1) would return 1
294 resulting in bad up/down values for staircase generation when it attempts to locate
295 a staircase leading into pvp-arena and put some feats around it (at coords 0,0 ...).
296 Apparently, WILD_F_UP is set here, too. And even w_ptr->tower was also valid.
297 todo: fix this. -C. Blue */
298 if (wpos->wz == 0 && wpos->wx == WPOS_PVPARENA_X && wpos->wy == WPOS_PVPARENA_Y &&
299 WPOS_PVPARENA_Z < 0) return (FALSE);
300 #endif
301
302 /* Check for empty staircase without any connected dungeon/tower! */
303 if (!d_ptr) return((wild->flags&WILD_F_DOWN)?TRUE:FALSE); /* you MAY create 'empty' staircase */
304
305 if (mode & 0x1) {
306 if (!wpos->wz && (d_ptr->flags2 & DF2_NO_ENTRY_STAIR)) return(FALSE);
307 if (wpos->wz == 1 && (d_ptr->flags2 & DF2_NO_EXIT_STAIR)) return(FALSE);
308 if (wpos->wz && (d_ptr->flags2 & DF2_NO_STAIRS_DOWN)) return(FALSE);
309 }
310
311 if (wpos->wz>0) {
312 if ((d_ptr->flags1 & (DF1_NO_UP | DF1_FORCE_DOWN)) ||
313 (d_ptr->flags2 & DF2_IRON)) return(FALSE);
314 return(TRUE);
315 }
316
317 if (wpos->wz<0) return(ABS(wpos->wz) < wild->dungeon->maxdepth);
318
319 return((wild->flags&WILD_F_DOWN)?TRUE:FALSE);
320 }
321 /* ignore all dungeon/floor flags */
can_go_up_simple(struct worldpos * wpos)322 bool can_go_up_simple(struct worldpos *wpos)
323 {
324 struct wilderness_type *wild = &wild_info[wpos->wy][wpos->wx];
325 if (wpos->wz < 0) return(TRUE);
326 if (wpos->wz > 0) return(wpos->wz < wild->tower->maxdepth);
327 return ((wild->flags & WILD_F_UP) ? TRUE : FALSE);
328 }
329 /* ignore all dungeon/floor flags */
can_go_down_simple(struct worldpos * wpos)330 bool can_go_down_simple(struct worldpos *wpos)
331 {
332 struct wilderness_type *wild = &wild_info[wpos->wy][wpos->wx];
333 if (wpos->wz > 0) return(TRUE);
334 if (wpos->wz < 0) return(ABS(wpos->wz) < wild->dungeon->maxdepth);
335 return ((wild->flags & WILD_F_DOWN) ? TRUE : FALSE);
336 }
337
wpcopy(struct worldpos * dest,struct worldpos * src)338 void wpcopy(struct worldpos *dest, struct worldpos *src)
339 {
340 dest->wx = src->wx;
341 dest->wy = src->wy;
342 dest->wz = src->wz;
343 }
344
update_uniques_killed(struct worldpos * wpos)345 static void update_uniques_killed(struct worldpos *wpos)
346 {
347 int i, j;
348 player_type *p_ptr;
349 dun_level *l_ptr;
350
351 /* Update the list of uniques that have been killed by all players on the level */
352 l_ptr = getfloor(wpos);
353
354 if (l_ptr && l_ptr->uniques_killed) {
355 int admins = 0, players = 0;
356
357 for (i = 1; i <= NumPlayers; i++) {
358 p_ptr = Players[i];
359
360 /* Skip disconnected players */
361 if (p_ptr->conn == NOT_CONNECTED)
362 continue;
363
364 /* Player on this depth? */
365 if (!inarea(&p_ptr->wpos, wpos))
366 continue;
367
368 /* Count the admins and non-admins */
369 if (admin_p(i)) admins++;
370 else players++;
371 }
372
373 if (admins || players) {
374 for (j = 1; j < MAX_R_IDX; j++) {
375 monster_race *r_ptr = &r_info[j];
376
377 if (r_ptr->flags1 & RF1_UNIQUE) {
378 /* Assume that the unique has been killed unless a player has killed it */
379 l_ptr->uniques_killed[j] = TRUE;
380
381 for (i = 1; i <= NumPlayers; i++) {
382 p_ptr = Players[i];
383
384 /* Skip disconnected players */
385 if (p_ptr->conn == NOT_CONNECTED)
386 continue;
387
388 /* Player on this depth? */
389 if (!inarea(&p_ptr->wpos, wpos))
390 continue;
391
392 /* Ignore admins if players are on the level */
393 if (players && admin_p(i))
394 continue;
395
396 /* Check that every player has killed the unique */
397 l_ptr->uniques_killed[j] = l_ptr->uniques_killed[j] && p_ptr->r_killed[j] == 1;
398 }
399 }
400 }
401 } else {
402 /* No players around, no restrictions */
403 C_WIPE(l_ptr->uniques_killed, MAX_R_IDX, char);
404 }
405 }
406 }
407
new_players_on_depth(struct worldpos * wpos,int value,bool inc)408 void new_players_on_depth(struct worldpos *wpos, int value, bool inc) {
409 struct wilderness_type *w_ptr;
410 time_t now;
411
412 int henc = 0, henc_top = 0, i;
413 player_type *p_ptr;
414 monster_type *m_ptr;
415
416 object_type *o_ptr;
417 char o_name[ONAME_LEN];
418
419 cave_type **zcave;
420 bool flag = FALSE;
421 if ((zcave = getcave(wpos))) flag = TRUE;
422
423 now = time(&now);
424
425 w_ptr = &wild_info[wpos->wy][wpos->wx];
426 #if DEBUG_LEVEL > 2
427 s_printf("new_players_on_depth.. %s now:%d value:%d inc:%s\n", wpos_format(0, wpos), now, value, inc?"TRUE":"FALSE");
428 #endif
429 if (in_valinor(wpos)) {
430 for (i = 1; i <= NumPlayers; i++) {
431 p_ptr = Players[i];
432 if (p_ptr->conn == NOT_CONNECTED) continue;
433 if (admin_p(i)) continue;
434 if (inarea(&p_ptr->wpos, wpos)) s_printf("%s VALINOR: Player %s is here.\n", showtime(), p_ptr->name);
435 }
436 }
437
438 /* Page all dungeon masters to notify them of a Nether Realm breach >:) - C. Blue */
439 if (value > 0) {
440 if (watch_nr && in_netherrealm(wpos)) {
441 for (i = 1; i <= NumPlayers; i++) {
442 if (Players[i]->conn == NOT_CONNECTED) continue;
443 if (Players[i]->admin_dm && !Players[i]->afk) Players[i]->paging = 2;
444 }
445 } else if (watch_cp && wpos->wz && getdungeon(wpos)->type == DI_CLOUD_PLANES) {
446 for (i = 1; i <= NumPlayers; i++) {
447 if (Players[i]->conn == NOT_CONNECTED) continue;
448 if (Players[i]->admin_dm && !Players[i]->afk) Players[i]->paging = 2;
449 }
450 }
451 }
452
453 if (wpos->wz) {
454 struct dungeon_type *d_ptr;
455 struct dun_level *l_ptr;
456 if (wpos->wz > 0)
457 d_ptr = wild_info[wpos->wy][wpos->wx].tower;
458 else
459 d_ptr = wild_info[wpos->wy][wpos->wx].dungeon;
460
461
462 l_ptr = &d_ptr->level[ABS(wpos->wz) - 1];
463
464 l_ptr->ondepth = (inc ? l_ptr->ondepth + value : value);
465 if (l_ptr->ondepth < 0) l_ptr->ondepth = 0;
466
467 if (!l_ptr->ondepth) l_ptr->lastused = 0;
468 if (value > 0) l_ptr->lastused = now;
469 } else {
470 w_ptr->ondepth = (inc ? w_ptr->ondepth + value : value);
471 if (w_ptr->ondepth < 0) w_ptr->ondepth = 0;
472 if (!w_ptr->ondepth) w_ptr->lastused = 0;
473 if (value > 0) w_ptr->lastused = now;
474 /* remove 'deposited' true artefacts if last player leaves a level,
475 and if true artefacts aren't allowed to be stored (in houses for example) */
476 if (!w_ptr->ondepth && cfg.anti_arts_wild) {
477 for (i = 0; i < o_max; i++) {
478 o_ptr = &o_list[i];
479 if (o_ptr->k_idx && inarea(&o_ptr->wpos, wpos) &&
480 undepositable_artifact_p(o_ptr)) {
481 object_desc(0, o_name, o_ptr, FALSE, 0);
482 s_printf("WILD_ART: %s of %s erased at (%d, %d, %d)\n",
483 o_name, lookup_player_name(o_ptr->owner), o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz);
484 handle_art_d(o_ptr->name1);
485 if (flag && in_bounds_array(o_ptr->iy, o_ptr->ix))
486 zcave[o_ptr->iy][o_ptr->ix].o_idx = 0;
487 WIPE(o_ptr, object_type);
488 }
489 }
490 }
491 }
492
493 update_uniques_killed(wpos);
494
495 /* Perform henc_strictness anti-cheeze - mode 4 : monster is on the same dungeon level as a player */
496 /* If a player enters a new level */
497 if ((value <= 0) || (cfg.henc_strictness < 4)) return;
498 if (in_bree(wpos)) return; /* not in Bree, because of Halloween :) */
499
500 /* Who is the highest player around? */
501 for (i = 1; i <= NumPlayers; i++) {
502 p_ptr = Players[i];
503
504 /* skip disconnected players */
505 if (p_ptr->conn == NOT_CONNECTED)
506 continue;
507
508 /* skip admins */
509 if (admin_p(i)) continue;
510
511 /* player on this depth? */
512 if (!inarea(&p_ptr->wpos, wpos)) continue;
513
514 if (henc < p_ptr->max_lev) henc = p_ptr->max_lev;
515 if (henc_top < (p_ptr->max_lev + p_ptr->max_plv) / 2) henc_top = (p_ptr->max_lev + p_ptr->max_plv) / 2;
516 if (henc < p_ptr->supp) henc = p_ptr->supp;
517 if (henc_top < (p_ptr->max_lev + p_ptr->supp_top) / 2) henc_top = (p_ptr->max_lev + p_ptr->supp_top) / 2;
518 }
519
520 /* Process the monsters, check against the highest player around */
521 for (i = m_top - 1; i >= 0; i--) {
522 /* Access the monster */
523 m_ptr = &m_list[m_fast[i]];
524
525 /* On this level? Test its highest encounter so far */
526 if (!inarea(&m_ptr->wpos, wpos)) continue;
527
528 if (m_ptr->henc < henc) m_ptr->henc = henc;
529 if (m_ptr->henc_top < henc_top) m_ptr->henc_top = henc_top;
530 }
531 }
532
533
check_Pumpkin(void)534 void check_Pumpkin(void) {
535 int k, i, m_idx;
536 struct worldpos *wpos;
537 char msg[80];
538 player_type *p_ptr;
539 monster_type *m_ptr;
540
541 /* only during Halloween! */
542 if (!season_halloween) return;
543
544 /* Process the monsters */
545 for (k = m_top - 1; k >= 0; k--) {
546 /* Access the index */
547 m_idx = m_fast[k];
548 /* Access the monster */
549 m_ptr = &m_list[m_idx];
550 /* Excise "dead" monsters */
551 if (!m_ptr->r_idx) {
552 /* Excise the monster */
553 m_fast[k] = m_fast[--m_top];
554 /* Skip */
555 continue;
556 }
557
558 /* Players of too high level cannot participate in killing attemps (anti-cheeze) */
559 /* search for Great Pumpkins */
560 if (m_ptr->r_idx == RI_PUMPKIN1 || m_ptr->r_idx == RI_PUMPKIN2 || m_ptr->r_idx == RI_PUMPKIN3) {
561 wpos = &m_ptr->wpos;
562
563 /* Exception for IDDC - just allow */
564 if (in_irondeepdive(wpos)) continue;
565
566 for (i = 1; i <= NumPlayers; i++) {
567 p_ptr = Players[i];
568 if (is_admin(p_ptr)) continue;
569 if (inarea(&p_ptr->wpos, wpos) &&
570 #if 0
571 #ifndef RPG_SERVER
572 (p_ptr->max_lev > 30))
573 #else
574 (p_ptr->max_lev > 40))
575 #endif
576 #else
577 #ifndef RPG_SERVER
578 (p_ptr->max_lev > 35))
579 #else
580 (p_ptr->max_lev > 40))
581 #endif
582 #endif
583 {
584 sprintf(msg, "\377oA ghostly force drives you out of this dungeon!");
585 /* log */
586 #ifndef RPG_SERVER
587 s_printf("HALLOWEEN: Recalled>35: %s\n", p_ptr->name);
588 #else
589 s_printf("HALLOWEEN: Recalled>40: %s\n", p_ptr->name);
590 #endif
591 /* get him out of here */
592 p_ptr->new_level_method = (p_ptr->wpos.wz > 0 ? LEVEL_RECALL_DOWN : LEVEL_RECALL_UP);
593 p_ptr->recall_pos.wx = p_ptr->wpos.wx;
594 p_ptr->recall_pos.wy = p_ptr->wpos.wy;
595 p_ptr->recall_pos.wz = 0;
596 // p_ptr->word_recall =- 666;/*HACK: avoid recall_player loops! */
597 recall_player(i, msg);
598 }
599 }
600 }
601 }
602 }
603
604 /* This lets Morgoth become stronger, weaker or teleport himself away if
605 * a King/Queen joins his level or if a player enters it who hasn't killed
606 * Sauron, the Sorceror yet - C. Blue
607 */
check_Morgoth(int Ind)608 void check_Morgoth(int Ind)
609 {
610 int k, i, x, y, num_on_depth = 0, m_idx;
611 s32b tmphp;
612 struct worldpos *wpos;
613 char msg[80];
614 player_type *p_ptr;
615 monster_type *m_ptr;
616
617
618 if (season_halloween) check_Pumpkin();
619
620
621 /* Let Morgoth, Lord of Darkness gain additional power
622 for each player who joins the depth */
623
624 /* Process the monsters */
625 for (k = m_top - 1; k >= 0; k--) {
626 /* Access the index */
627 m_idx = m_fast[k];
628 /* Access the monster */
629 m_ptr = &m_list[m_idx];
630 /* Excise "dead" monsters */
631 if (!m_ptr->r_idx) {
632 /* Excise the monster */
633 m_fast[k] = m_fast[--m_top];
634 /* Skip */
635 continue;
636 }
637
638 /* search for Morgy */
639 if (m_ptr->r_idx != RI_MORGOTH) continue;
640 wpos = &m_ptr->wpos;
641
642 /* check if players are on his depth */
643 num_on_depth = 0;
644 for (i = 1; i <= NumPlayers; i++) {
645 /* skip disconnected players */
646 if (Players[i]->conn == NOT_CONNECTED) continue;
647 /* skip admins */
648 if (admin_p(i)) continue;
649 /* player on this depth? */
650 p_ptr = Players[i];
651 if (inarea(&p_ptr->wpos, wpos)) num_on_depth++;
652 }
653
654 /* if the last player leaves, don't reduce Morgy's power */
655 if (num_on_depth == 0) continue;
656
657 /* Page all dungeon masters to notify them of a possible Morgoth-fight >:) - C. Blue */
658 if (watch_morgoth
659 /* new: only page if a player actually entered Morgoth's level */
660 && Ind && inarea(&Players[Ind]->wpos, wpos))
661 for (i = 1; i <= NumPlayers; i++) {
662 if (Players[i]->conn == NOT_CONNECTED) continue;
663 if (Players[i]->admin_dm && !(Players[i]->afk && !streq(Players[i]->afk_msg, "watch"))) Players[i]->paging = 4;
664 }
665
666 /* save coordinates to redraw the spot after deletion later */
667 x = m_ptr->fx;
668 y = m_ptr->fy;
669
670 /* If a King/Queen or a Sauron-missing player enters Morgy's level:
671 if there was an allowed player already on the level, the bad player
672 will be insta-recalled to town. Otherwise, Morgy will be removed.
673 Invalid player alone with Morgy?: Yes->Remove Morgy, No->recall */
674 for (i = 1; i <= NumPlayers; i++) {
675 if (Players[i]->conn == NOT_CONNECTED) continue;
676 p_ptr = Players[i];
677 if (is_admin(p_ptr)) continue;
678
679 if (inarea(&p_ptr->wpos, wpos) &&
680 ((p_ptr->mode & MODE_PVP) || p_ptr->total_winner || (p_ptr->r_killed[RI_SAURON] != 1)))
681 {
682 /* Replace Morgoth with Sauron if Sauron is missing,
683 the other two cases have no repercussions for now -- just allow - C. Blue */
684 if (in_irondeepdive(&p_ptr->wpos)) {
685 if (p_ptr->r_killed[RI_SAURON] != 1) {
686 dun_level *l_ptr = getfloor(wpos);
687
688 /* remove morgy here */
689 delete_monster_idx(k, TRUE); /* careful, 'wpos' is now zero'ed */
690 l_ptr->flags1 &= ~LF1_NO_GHOST;
691
692 /* notifications */
693 sprintf(msg, "\377sMorgoth, Lord of Darkness summons Sauron, the Sorceror, and teleports out!");
694 for (i = 1; i <= NumPlayers; i++) {
695 if (Players[i]->conn == NOT_CONNECTED) continue;
696 /* Player on Morgy depth? */
697 if (inarea(&Players[i]->wpos, &p_ptr->wpos)) {
698 msg_print(i, msg);
699 handle_music(i); /* :-o */
700 }
701 }
702 s_printf("Morgoth left level (inserting Sauron) due to %s\n", p_ptr->name);
703
704 /* place Sauron so players can kill him first */
705 summon_override_checks = SO_ALL; /* (SO_IDDC?) */
706 place_monster_one(&p_ptr->wpos, y, x, RI_SAURON, FALSE, FALSE, FALSE, 0, 0);
707 summon_override_checks = SO_NONE;
708
709 /* Notice */
710 note_spot_depth(&p_ptr->wpos, y, x);
711 /* Display */
712 everyone_lite_spot(&p_ptr->wpos, y, x);
713 }
714 /* the rest is allowed..
715 -PvP chars can't enter IDDC anyway
716 -and kings may just help their team mates for now, maybe cool */
717 }
718
719 /* Teleport player in question out, tell the others on this depth */
720 else if (num_on_depth > 1) {
721 /* tell a message to the player */
722 if (p_ptr->total_winner) {
723 sprintf(msg, "\377sA hellish force drives you out of this dungeon!");
724 /* log */
725 s_printf("Morgoth recalled winner %s\n", p_ptr->name);
726 } else if (p_ptr->mode & MODE_PVP) {
727 sprintf(msg, "\377sA hellish force drives you out of this dungeon!");
728 /* log */
729 s_printf("Morgoth recalled MODE_PVP %s\n", p_ptr->name);
730 } else {
731 sprintf(msg, "\377sYou hear Sauron's laughter as his spell drives you out of the dungeon!");
732 /* log */
733 s_printf("Morgoth recalled Sauron-misser %s\n", p_ptr->name);
734 }
735
736 /* get him out of here */
737 p_ptr->new_level_method = (p_ptr->wpos.wz > 0 ? LEVEL_RECALL_DOWN : LEVEL_RECALL_UP);
738 p_ptr->recall_pos.wx = p_ptr->wpos.wx;
739 p_ptr->recall_pos.wy = p_ptr->wpos.wy;
740 p_ptr->recall_pos.wz = 0;
741 recall_player(i, msg);
742
743 /* Teleport Morgoth out, since no other players are affected */
744 } else {
745 sprintf(msg, "\377sMorgoth, Lord of Darkness teleports to a different dungeon floor!");
746 for (i = 1; i <= NumPlayers; i++) {
747 if (Players[i]->conn == NOT_CONNECTED) continue;
748 /* Player on Morgy depth? */
749 if (inarea(&Players[i]->wpos, wpos))
750 msg_print(i, msg);
751 }
752
753 /* log */
754 s_printf("Morgoth left level due to %s\n", p_ptr->name);
755 /* remove morgy here */
756 delete_monster_idx(k, TRUE);
757
758 /* place replacement monster (clone): Death Orb (Star-Spawn, GB, GWoP) */
759 summon_override_checks = SO_ALL; /* needed? */
760 // place_monster_one(&p_ptr->wpos, y, x, 975, FALSE, FALSE, FALSE, 100, 4 + cfg.clone_summoning);//DOrb (kills items)
761 place_monster_one(&p_ptr->wpos, y, x, 847, FALSE, FALSE, FALSE, 100, 4 + cfg.clone_summoning);//GWoP (best maybe)
762 summon_override_checks = SO_NONE;
763
764 /* Notice */
765 note_spot_depth(&p_ptr->wpos, y, x);
766 /* Display */
767 everyone_lite_spot(&p_ptr->wpos, y, x);
768 }
769 return;
770 }
771 }
772
773 tmphp = (m_ptr->org_maxhp * (2 * (num_on_depth - 1) + 3)) / 3; /* 2/3 HP boost for each additional player */
774 /* More players here than Morgy has power for? */
775 if (m_ptr->maxhp < tmphp) {
776 m_ptr->maxhp = tmphp;
777 m_ptr->mspeed += 6;
778 m_ptr->speed += 6; /* also adjust base speed, only important for aggr-haste */
779 /* Anti-cheeze: Fully heal!
780 Otherwise 2 players could bring him down and the 3rd one
781 just joins for the last 'few' HP.. */
782 m_ptr->hp = m_ptr->maxhp;
783
784 /* log */
785 s_printf("Morgoth grows stronger\n");
786 /* Tell everyone related to Morgy's depth */
787 msg_print_near_monster(m_idx, "becomes stronger!");
788 return;
789 }
790 /* Less players here than Morgy has power for? */
791 else if (m_ptr->maxhp > tmphp) {
792 /* anti-cheeze */
793 if (m_ptr->hp == m_ptr->maxhp) {
794 m_ptr->hp -= (tmphp - m_ptr->maxhp);
795 }
796 m_ptr->maxhp = tmphp;
797 if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
798 m_ptr->mspeed -= 6;
799 m_ptr->speed -= 6; /* also adjust base speed, only important for aggr-haste */
800
801 /* log */
802 s_printf("Morgoth weakens\n");
803 /* Tell everyone related to Morgy's depth */
804 msg_print_near_monster(m_idx, "becomes weaker!");
805 return;
806 }
807 }
808 }
809
players_on_depth(struct worldpos * wpos)810 int players_on_depth(struct worldpos *wpos)
811 {
812 if (wpos->wx>MAX_WILD_X || wpos->wx<0 || wpos->wy>MAX_WILD_Y || wpos->wy<0) return(0);
813 if (wpos->wz == 0)
814 return(wild_info[wpos->wy][wpos->wx].ondepth);
815 else {
816 struct dungeon_type *d_ptr;
817 if (wpos->wz > 0)
818 d_ptr = wild_info[wpos->wy][wpos->wx].tower;
819 else
820 d_ptr = wild_info[wpos->wy][wpos->wx].dungeon;
821
822 return(d_ptr->level[ABS(wpos->wz) - 1].ondepth);
823 }
824 }
825
826 /* Don't determine wilderness level just from town radius, but also from the
827 level of that town? */
828 #define WILD_LEVEL_DEPENDS_ON_TOWN
829 /* Determine wilderness level (for monster generation) */
getlevel(struct worldpos * wpos)830 int getlevel(struct worldpos *wpos) {
831 wilderness_type *w_ptr = &wild_info[wpos->wy][wpos->wx];
832
833 if (wpos->wz == 0) {
834 /* ground level */
835 #ifdef WILD_LEVEL_DEPENDS_ON_TOWN
836 return (w_ptr->radius + w_ptr->town_lev / 3);
837 #else
838 return (w_ptr->radius);
839 #endif
840 } else {
841 struct dungeon_type *d_ptr;
842 int base;
843
844 if (wpos->wz > 0) d_ptr = w_ptr->tower;
845 else d_ptr = w_ptr->dungeon;
846 base = d_ptr->baselevel + ABS(wpos->wz) - 1;
847 return (base);
848 }
849 }
850
851 /* Simple finder routine. Scan list of c_special, return match */
852 /* NOTE only ONE of each type !!! */
GetCS(cave_type * c_ptr,unsigned char type)853 struct c_special *GetCS(cave_type *c_ptr, unsigned char type) {
854 struct c_special *trav;
855
856 if (!c_ptr->special) return(NULL);
857 trav = c_ptr->special;
858 while (trav) {
859 if (trav->type == type) return(trav);
860 trav = trav->next;
861 }
862 return(NULL); /* returns ** to the structs. always dealloc */
863 }
864
865 /* check for duplication, and also set the type - Jir - */
AddCS(cave_type * c_ptr,byte type)866 struct c_special *AddCS(cave_type *c_ptr, byte type) {
867 struct c_special *cs_ptr;
868 if (GetCS(c_ptr, type)) {
869 return(NULL); /* already exists! */
870 }
871 MAKE(cs_ptr, struct c_special);
872 if (!cs_ptr) return(NULL);
873 cs_ptr->next = c_ptr->special;
874 c_ptr->special = cs_ptr;
875 cs_ptr->type = type;
876 return(cs_ptr);
877 }
878
879 /* like AddCS, but override already-existing one */
ReplaceCS(cave_type * c_ptr,byte type)880 c_special *ReplaceCS(cave_type *c_ptr, byte type)
881 {
882 struct c_special *cs_ptr;
883 if (!(cs_ptr = GetCS(c_ptr, type)))
884 {
885 MAKE(cs_ptr, struct c_special);
886 if (!cs_ptr) return(NULL);
887 cs_ptr->next = c_ptr->special;
888 c_ptr->special = cs_ptr;
889 }
890 cs_ptr->type = type;
891 return(cs_ptr);
892 }
893
894 /* Free all memory related to c_ptr->special - mikaelh */
895 /* Note: doesn't clear the c_ptr->special pointer */
FreeCS(cave_type * c_ptr)896 void FreeCS(cave_type *c_ptr)
897 {
898 struct c_special *trav, *prev;
899
900 prev = trav = c_ptr->special;
901
902 while (trav)
903 {
904 prev = trav;
905 trav = trav->next;
906 FREE(prev, struct c_special);
907 }
908 }
909
910
911
912 /*
913 * Approximate Distance between two points.
914 *
915 * When either the X or Y component dwarfs the other component,
916 * this function is almost perfect, and otherwise, it tends to
917 * over-estimate about one grid per fifteen grids of distance.
918 *
919 * Algorithm: hypot(dy,dx) = max(dy,dx) + min(dy,dx) / 2
920 */
921 /*
922 * For radius-affecting things, consider using tdx[], tdy[], tdi[] instead,
923 * which contain pre-calculated results of this function. - Jir -
924 * (Please see prepare_distance() )
925 */
distance(int y1,int x1,int y2,int x2)926 int distance(int y1, int x1, int y2, int x2)
927 {
928 int dy, dx, d;
929
930 /* Find the absolute y/x distance components */
931 dy = (y1 > y2) ? (y1 - y2) : (y2 - y1);
932 dx = (x1 > x2) ? (x1 - x2) : (x2 - x1);
933
934 /* Hack -- approximate the distance */
935 d = (dy > dx) ? (dy + (dx>>1)) : (dx + (dy>>1));
936
937 /* Return the distance */
938 return (d);
939 }
940
941 /*
942 * Returns TRUE if a grid is considered to be a wall for the purpose
943 * of magic mapping / clairvoyance
944 */
is_wall(cave_type * c_ptr)945 static bool is_wall(cave_type *c_ptr)
946 {
947 int feat;
948
949 feat = c_ptr->feat;
950
951 /* Paranoia */
952 if (feat > MAX_F_IDX) return FALSE;
953
954 /* Vanilla floors and doors aren't considered to be walls */
955 if (feat < FEAT_SECRET) return FALSE;
956
957 /* Exception #1: a glass wall is a wall but doesn't prevent LOS */
958 if (feat == FEAT_GLASS_WALL) return FALSE;
959
960 /* Exception #2: an illusion wall is not a wall but obstructs view */
961 if (feat == FEAT_ILLUS_WALL) return TRUE;
962
963 /* Exception #3: Ivy (formerly: a small tree) is a floor but obstructs view */
964 if (feat == FEAT_IVY) return TRUE;
965
966 /* Normal cases: use the WALL flag in f_info.txt */
967 return (f_info[feat].flags1 & FF1_WALL) ? TRUE : FALSE;
968 }
969
970
971 /*
972 * A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall,
973 * 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu.
974 *
975 * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2).
976 *
977 * The LOS begins at the center of the tile (x1,y1) and ends at the center of
978 * the tile (x2,y2). If los() is to return TRUE, all of the tiles this line
979 * passes through must be floor tiles, except for (x1,y1) and (x2,y2).
980 *
981 * We assume that the "mathematical corner" of a non-floor tile does not
982 * block line of sight.
983 *
984 * Because this function uses (short) ints for all calculations, overflow may
985 * occur if dx and dy exceed 90.
986 *
987 * Once all the degenerate cases are eliminated, the values "qx", "qy", and
988 * "m" are multiplied by a scale factor "f1 = abs(dx * dy * 2)", so that
989 * we can use integer arithmetic.
990 *
991 * We travel from start to finish along the longer axis, starting at the border
992 * between the first and second tiles, where the y offset = .5 * slope, taking
993 * into account the scale factor. See below.
994 *
995 * Also note that this function and the "move towards target" code do NOT
996 * share the same properties. Thus, you can see someone, target them, and
997 * then fire a bolt at them, but the bolt may hit a wall, not them. However,
998 * by clever choice of target locations, you can sometimes throw a "curve".
999 *
1000 * Note that "line of sight" is not "reflexive" in all cases.
1001 *
1002 * Use the "projectable()" routine to test "spell/missile line of sight".
1003 *
1004 * Use the "update_view()" function to determine player line-of-sight.
1005 */
1006 #ifdef DOUBLE_LOS_SAFETY
1007 static bool los_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2);
los(struct worldpos * wpos,int y1,int x1,int y2,int x2)1008 bool los(struct worldpos *wpos, int y1, int x1, int y2, int x2) {
1009 return (los_DLS(wpos, y1, x1, y2, x2) || los_DLS(wpos, y2, x2, y1, x1));
1010 }
los_DLS(struct worldpos * wpos,int y1,int x1,int y2,int x2)1011 static bool los_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2) {
1012 #else
1013 bool los(struct worldpos *wpos, int y1, int x1, int y2, int x2) {
1014 #endif
1015 /* Delta */
1016 int dx, dy;
1017
1018 /* Absolute */
1019 int ax, ay;
1020
1021 /* Signs */
1022 int sx, sy;
1023
1024 /* Fractions */
1025 int qx, qy;
1026
1027 /* Scanners */
1028 int tx, ty;
1029
1030 /* Scale factors */
1031 int f1, f2;
1032
1033 /* Slope, or 1/Slope, of LOS */
1034 int m;
1035
1036 cave_type **zcave;
1037 if (!(zcave = getcave(wpos))) return FALSE;
1038
1039 /* Extract the offset */
1040 dy = y2 - y1;
1041 dx = x2 - x1;
1042
1043 /* Extract the absolute offset */
1044 ay = ABS(dy);
1045 ax = ABS(dx);
1046
1047
1048 /* Handle adjacent (or identical) grids */
1049 if ((ax < 2) && (ay < 2)) return (TRUE);
1050
1051
1052 /* Paranoia -- require "safe" origin */
1053 /* if (!in_bounds(y1, x1)) return (FALSE); */
1054
1055
1056 /* Directly South/North */
1057 if (!dx)
1058 {
1059 /* South -- check for walls */
1060 if (dy > 0)
1061 {
1062 for (ty = y1 + 1; ty < y2; ty++)
1063 {
1064 if (!cave_los(zcave, ty, x1)) return (FALSE);
1065 }
1066 }
1067
1068 /* North -- check for walls */
1069 else
1070 {
1071 for (ty = y1 - 1; ty > y2; ty--)
1072 {
1073 if (!cave_los(zcave, ty, x1)) return (FALSE);
1074 }
1075 }
1076
1077 /* Assume los */
1078 return (TRUE);
1079 }
1080
1081 /* Directly East/West */
1082 if (!dy)
1083 {
1084 /* East -- check for walls */
1085 if (dx > 0)
1086 {
1087 for (tx = x1 + 1; tx < x2; tx++)
1088 {
1089 if (!cave_los(zcave, y1, tx)) return (FALSE);
1090 }
1091 }
1092
1093 /* West -- check for walls */
1094 else
1095 {
1096 for (tx = x1 - 1; tx > x2; tx--)
1097 {
1098 if (!cave_los(zcave, y1, tx)) return (FALSE);
1099 }
1100 }
1101
1102 /* Assume los */
1103 return (TRUE);
1104 }
1105
1106
1107 /* Extract some signs */
1108 sx = (dx < 0) ? -1 : 1;
1109 sy = (dy < 0) ? -1 : 1;
1110
1111
1112 /* Vertical "knights" */
1113 if (ax == 1)
1114 {
1115 if (ay == 2)
1116 {
1117 if (cave_los(zcave, y1 + sy, x1)) return (TRUE);
1118 }
1119 }
1120
1121 /* Horizontal "knights" */
1122 else if (ay == 1)
1123 {
1124 if (ax == 2)
1125 {
1126 if (cave_los(zcave, y1, x1 + sx)) return (TRUE);
1127 }
1128 }
1129
1130
1131 /* Calculate scale factor div 2 */
1132 f2 = (ax * ay);
1133
1134 /* Calculate scale factor */
1135 f1 = f2 << 1;
1136
1137
1138 /* Travel horizontally */
1139 if (ax >= ay)
1140 {
1141 /* Let m = dy / dx * 2 * (dy * dx) = 2 * dy * dy */
1142 qy = ay * ay;
1143 m = qy << 1;
1144
1145 tx = x1 + sx;
1146
1147 /* Consider the special case where slope == 1. */
1148 if (qy == f2)
1149 {
1150 ty = y1 + sy;
1151 qy -= f1;
1152 }
1153 else
1154 {
1155 ty = y1;
1156 }
1157
1158 /* Note (below) the case (qy == f2), where */
1159 /* the LOS exactly meets the corner of a tile. */
1160 while (x2 - tx)
1161 {
1162 if (!cave_los(zcave, ty, tx)) return (FALSE);
1163
1164 qy += m;
1165
1166 if (qy < f2)
1167 {
1168 tx += sx;
1169 }
1170 else if (qy > f2)
1171 {
1172 ty += sy;
1173 if (!cave_los(zcave, ty, tx)) return (FALSE);
1174 qy -= f1;
1175 tx += sx;
1176 }
1177 else
1178 {
1179 ty += sy;
1180 qy -= f1;
1181 tx += sx;
1182 }
1183 }
1184 }
1185
1186 /* Travel vertically */
1187 else
1188 {
1189 /* Let m = dx / dy * 2 * (dx * dy) = 2 * dx * dx */
1190 qx = ax * ax;
1191 m = qx << 1;
1192
1193 ty = y1 + sy;
1194
1195 if (qx == f2)
1196 {
1197 tx = x1 + sx;
1198 qx -= f1;
1199 }
1200 else
1201 {
1202 tx = x1;
1203 }
1204
1205 /* Note (below) the case (qx == f2), where */
1206 /* the LOS exactly meets the corner of a tile. */
1207 while (y2 - ty)
1208 {
1209 if (!cave_los(zcave, ty, tx)) return (FALSE);
1210
1211 qx += m;
1212
1213 if (qx < f2)
1214 {
1215 ty += sy;
1216 }
1217 else if (qx > f2)
1218 {
1219 tx += sx;
1220 if (!cave_los(zcave, ty, tx)) return (FALSE);
1221 qx -= f1;
1222 ty += sy;
1223 }
1224 else
1225 {
1226 tx += sx;
1227 qx -= f1;
1228 ty += sy;
1229 }
1230 }
1231 }
1232
1233 /* Assume los */
1234 return (TRUE);
1235 }
1236
1237 /* Same as los, just ignores non-perma-wall grids - for monster targetting - C. Blue */
1238 #ifdef DOUBLE_LOS_SAFETY
1239 static bool los_wall_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2);
1240 bool los_wall(struct worldpos *wpos, int y1, int x1, int y2, int x2) {
1241 return (los_wall_DLS(wpos, y1, x1, y2, x2) || los_wall_DLS(wpos, y2, x2, y1, x1));
1242 }
1243 static bool los_wall_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2) {
1244 #else
1245 bool los_wall(struct worldpos *wpos, int y1, int x1, int y2, int x2) {
1246 #endif
1247 /* Delta */
1248 int dx, dy;
1249
1250 /* Absolute */
1251 int ax, ay;
1252
1253 /* Signs */
1254 int sx, sy;
1255
1256 /* Fractions */
1257 int qx, qy;
1258
1259 /* Scanners */
1260 int tx, ty;
1261
1262 /* Scale factors */
1263 int f1, f2;
1264
1265 /* Slope, or 1/Slope, of LOS */
1266 int m;
1267
1268 cave_type **zcave;
1269 if (!(zcave = getcave(wpos))) return FALSE;
1270
1271 /* Extract the offset */
1272 dy = y2 - y1;
1273 dx = x2 - x1;
1274
1275 /* Extract the absolute offset */
1276 ay = ABS(dy);
1277 ax = ABS(dx);
1278
1279
1280 /* Handle adjacent (or identical) grids */
1281 if ((ax < 2) && (ay < 2)) return (TRUE);
1282
1283
1284 /* Paranoia -- require "safe" origin */
1285 /* if (!in_bounds(y1, x1)) return (FALSE); */
1286
1287
1288 /* Directly South/North */
1289 if (!dx)
1290 {
1291 /* South -- check for walls */
1292 if (dy > 0)
1293 {
1294 for (ty = y1 + 1; ty < y2; ty++)
1295 {
1296 if (!cave_los_wall(zcave, ty, x1)) return (FALSE);
1297 }
1298 }
1299
1300 /* North -- check for walls */
1301 else
1302 {
1303 for (ty = y1 - 1; ty > y2; ty--)
1304 {
1305 if (!cave_los_wall(zcave, ty, x1)) return (FALSE);
1306 }
1307 }
1308
1309 /* Assume los */
1310 return (TRUE);
1311 }
1312
1313 /* Directly East/West */
1314 if (!dy)
1315 {
1316 /* East -- check for walls */
1317 if (dx > 0)
1318 {
1319 for (tx = x1 + 1; tx < x2; tx++)
1320 {
1321 if (!cave_los_wall(zcave, y1, tx)) return (FALSE);
1322 }
1323 }
1324
1325 /* West -- check for walls */
1326 else
1327 {
1328 for (tx = x1 - 1; tx > x2; tx--)
1329 {
1330 if (!cave_los_wall(zcave, y1, tx)) return (FALSE);
1331 }
1332 }
1333
1334 /* Assume los */
1335 return (TRUE);
1336 }
1337
1338
1339 /* Extract some signs */
1340 sx = (dx < 0) ? -1 : 1;
1341 sy = (dy < 0) ? -1 : 1;
1342
1343
1344 /* Vertical "knights" */
1345 if (ax == 1)
1346 {
1347 if (ay == 2)
1348 {
1349 if (cave_los_wall(zcave, y1 + sy, x1)) return (TRUE);
1350 }
1351 }
1352
1353 /* Horizontal "knights" */
1354 else if (ay == 1)
1355 {
1356 if (ax == 2)
1357 {
1358 if (cave_los_wall(zcave, y1, x1 + sx)) return (TRUE);
1359 }
1360 }
1361
1362
1363 /* Calculate scale factor div 2 */
1364 f2 = (ax * ay);
1365
1366 /* Calculate scale factor */
1367 f1 = f2 << 1;
1368
1369
1370 /* Travel horizontally */
1371 if (ax >= ay)
1372 {
1373 /* Let m = dy / dx * 2 * (dy * dx) = 2 * dy * dy */
1374 qy = ay * ay;
1375 m = qy << 1;
1376
1377 tx = x1 + sx;
1378
1379 /* Consider the special case where slope == 1. */
1380 if (qy == f2)
1381 {
1382 ty = y1 + sy;
1383 qy -= f1;
1384 }
1385 else
1386 {
1387 ty = y1;
1388 }
1389
1390 /* Note (below) the case (qy == f2), where */
1391 /* the LOS exactly meets the corner of a tile. */
1392 while (x2 - tx)
1393 {
1394 if (!cave_los_wall(zcave, ty, tx)) return (FALSE);
1395
1396 qy += m;
1397
1398 if (qy < f2)
1399 {
1400 tx += sx;
1401 }
1402 else if (qy > f2)
1403 {
1404 ty += sy;
1405 if (!cave_los_wall(zcave, ty, tx)) return (FALSE);
1406 qy -= f1;
1407 tx += sx;
1408 }
1409 else
1410 {
1411 ty += sy;
1412 qy -= f1;
1413 tx += sx;
1414 }
1415 }
1416 }
1417
1418 /* Travel vertically */
1419 else
1420 {
1421 /* Let m = dx / dy * 2 * (dx * dy) = 2 * dx * dx */
1422 qx = ax * ax;
1423 m = qx << 1;
1424
1425 ty = y1 + sy;
1426
1427 if (qx == f2)
1428 {
1429 tx = x1 + sx;
1430 qx -= f1;
1431 }
1432 else
1433 {
1434 tx = x1;
1435 }
1436
1437 /* Note (below) the case (qx == f2), where */
1438 /* the LOS exactly meets the corner of a tile. */
1439 while (y2 - ty)
1440 {
1441 if (!cave_los_wall(zcave, ty, tx)) return (FALSE);
1442
1443 qx += m;
1444
1445 if (qx < f2)
1446 {
1447 ty += sy;
1448 }
1449 else if (qx > f2)
1450 {
1451 tx += sx;
1452 if (!cave_los_wall(zcave, ty, tx)) return (FALSE);
1453 qx -= f1;
1454 ty += sy;
1455 }
1456 else
1457 {
1458 tx += sx;
1459 qx -= f1;
1460 ty += sy;
1461 }
1462 }
1463 }
1464
1465 /* Assume los */
1466 return (TRUE);
1467 }
1468
1469
1470
1471
1472
1473 /*
1474 * Can the player "see" the given grid in detail?
1475 *
1476 * He must have vision, illumination, and line of sight.
1477 *
1478 * Note -- "CAVE_LITE" is only set if the "torch" has "los()".
1479 * So, given "CAVE_LITE", we know that the grid is "fully visible".
1480 *
1481 * Note that "CAVE_GLOW" makes little sense for a wall, since it would mean
1482 * that a wall is visible from any direction. That would be odd. Except
1483 * under wizard light, which might make sense. Thus, for walls, we require
1484 * not only that they be "CAVE_GLOW", but also, that they be adjacent to a
1485 * grid which is not only "CAVE_GLOW", but which is a non-wall, and which is
1486 * in line of sight of the player.
1487 *
1488 * This extra check is expensive, but it provides a more "correct" semantics.
1489 *
1490 * Note that we should not run this check on walls which are "outer walls" of
1491 * the dungeon, or we will induce a memory fault, but actually verifying all
1492 * of the locations would be extremely expensive.
1493 *
1494 * Thus, to speed up the function, we assume that all "perma-walls" which are
1495 * "CAVE_GLOW" are "illuminated" from all sides. This is correct for all cases
1496 * except "vaults" and the "buildings" in town. But the town is a hack anyway,
1497 * and the player has more important things on his mind when he is attacking a
1498 * monster vault. It is annoying, but an extremely important optimization.
1499 *
1500 * Note that "glowing walls" are only considered to be "illuminated" if the
1501 * grid which is next to the wall in the direction of the player is also a
1502 * "glowing" grid. This prevents the player from being able to "see" the
1503 * walls of illuminated rooms from a corridor outside the room.
1504 */
1505 bool player_can_see_bold(int Ind, int y, int x)
1506 {
1507 player_type *p_ptr = Players[Ind];
1508 int xx, yy;
1509
1510 cave_type *c_ptr;
1511 byte *w_ptr;
1512 cave_type **zcave;
1513 struct worldpos *wpos;
1514 wpos = &p_ptr->wpos;
1515
1516 /* Blind players see nothing */
1517 if (p_ptr->blind) return (FALSE);
1518
1519 /* temp bug fix - evileye */
1520 if (!(zcave = getcave(wpos))) return FALSE;
1521 c_ptr = &zcave[y][x];
1522 w_ptr = &p_ptr->cave_flag[y][x];
1523
1524 /* Note that "torch-lite" yields "illumination" */
1525 if ((c_ptr->info & CAVE_LITE) && (*w_ptr & CAVE_VIEW))
1526 return (TRUE);
1527
1528 /* Require line of sight to the grid */
1529 if (!player_has_los_bold(Ind, y, x)) return (FALSE);
1530
1531 /* Require "perma-lite" of the grid */
1532 if (!(c_ptr->info & CAVE_GLOW)) return (FALSE);
1533
1534 /* Floors are simple */
1535 if (cave_floor_bold(zcave, y, x)) return (TRUE);
1536
1537 /* Hack -- move towards player */
1538 yy = (y < p_ptr->py) ? (y + 1) : (y > p_ptr->py) ? (y - 1) : y;
1539 xx = (x < p_ptr->px) ? (x + 1) : (x > p_ptr->px) ? (x - 1) : x;
1540
1541 /* Check for "local" illumination */
1542 if (zcave[yy][xx].info & CAVE_GLOW) {
1543 /* Assume the wall is really illuminated */
1544 return (TRUE);
1545 }
1546
1547 /* Assume not visible */
1548 return (FALSE);
1549 }
1550
1551
1552
1553 /*
1554 * Returns true if the player's grid is dark
1555 */
1556 bool no_lite(int Ind)
1557 {
1558 player_type *p_ptr = Players[Ind];
1559 if (p_ptr->admin_dm) return(FALSE);
1560 return (!player_can_see_bold(Ind, p_ptr->py, p_ptr->px));
1561 }
1562
1563
1564 /*
1565 * Determine if a given location may be "destroyed"
1566 *
1567 * Used by destruction spells, and for placing stairs, etc.
1568 */
1569 /* Borrowed from ToME, with some extra checks */
1570 bool cave_valid_bold(cave_type **zcave, int y, int x)
1571 {
1572 cave_type *c_ptr = &zcave[y][x];
1573
1574 s16b this_o_idx, next_o_idx = 0;
1575
1576 u32b f1, f2, f3, f4, f5, f6, esp;
1577
1578 /* Forbid perma-grids */
1579 /* if (cave_perma_grid(c_ptr)) return (FALSE); */
1580 if (cave_perma_bold(zcave, y, x)) return (FALSE);
1581
1582 /* Check objects */
1583 for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
1584 {
1585 object_type *o_ptr;
1586
1587 /* Acquire object */
1588 o_ptr = &o_list[this_o_idx];
1589
1590 /* Acquire next object */
1591 next_o_idx = o_ptr->next_o_idx;
1592
1593 /* Forbid artifact grids */
1594 if (true_artifact_p(o_ptr))
1595 {
1596 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
1597 if (f4 & TR4_SPECIAL_GENE) return (FALSE);
1598 }
1599 }
1600
1601 /* Accept */
1602 return (TRUE);
1603 }
1604
1605
1606
1607
1608
1609
1610
1611
1612 /*
1613 * Hack -- Legal monster codes
1614 */
1615 static cptr image_monster_hack = \
1616 "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1617
1618 /*
1619 * Mega-Hack -- Hallucinatory monster
1620 */
1621 static void image_monster(byte *ap, char *cp)
1622 {
1623 int n = strlen(image_monster_hack);
1624
1625 /* Random symbol from set above */
1626 (*cp) = (image_monster_hack[rand_int(n)]);
1627
1628 /* Random color */
1629 (*ap) = randint(15);
1630 }
1631
1632
1633 /*
1634 * Hack -- Legal object codes
1635 */
1636 static cptr image_object_hack = \
1637 "?/|\\\"!$()_-=[]{},~";
1638
1639 /*
1640 * Mega-Hack -- Hallucinatory object
1641 */
1642 static void image_object(byte *ap, char *cp)
1643 {
1644 int n = strlen(image_object_hack);
1645
1646 /* Random symbol from set above */
1647 (*cp) = (image_object_hack[rand_int(n)]);
1648
1649 /* Random color */
1650 (*ap) = randint(15);
1651 }
1652
1653 /*
1654 * Mega-Hack -- Mimic outlook
1655 * (Pleaes bear with us till really implemented..)
1656 */
1657 static void mimic_object(byte *ap, char *cp, int seed)
1658 {
1659 int n = strlen(image_object_hack);
1660
1661 /* Random symbol from set above */
1662 (*cp) = (image_object_hack[seed % n]);
1663
1664 /* Random color */
1665 (*ap) = seed % 15 + 1;
1666 }
1667
1668
1669 /*
1670 * Hack -- Random hallucination
1671 */
1672 static void image_random(byte *ap, char *cp)
1673 {
1674 /* Normally, assume monsters */
1675 if (rand_int(100) < 75)
1676 {
1677 image_monster(ap, cp);
1678 }
1679
1680 /* Otherwise, assume objects */
1681 else
1682 {
1683 image_object(ap, cp);
1684 }
1685 }
1686
1687 #ifndef CLIENT_SHIMMER
1688 /*
1689 * Some eye-candies from PernAngband :) - Jir -
1690 */
1691 char get_shimmer_color()
1692 {
1693 switch (randint(7))
1694 {
1695 case 1:
1696 return TERM_RED;
1697 case 2:
1698 return TERM_L_RED;
1699 case 3:
1700 return TERM_WHITE;
1701 case 4:
1702 return TERM_L_GREEN;
1703 case 5:
1704 return TERM_BLUE;
1705 case 6:
1706 return TERM_L_DARK;
1707 case 7:
1708 return TERM_GREEN;
1709 }
1710 return (TERM_VIOLET);
1711 }
1712 #endif
1713
1714 /*
1715 * Table of breath colors. Must match listings in a single set of
1716 * monster spell flags.
1717 *
1718 * The value "255" is special. Monsters with that kind of breath
1719 * may be any color.
1720 */
1721 #if 0 /* old */
1722 static byte breath_to_attr[32][2] =
1723 {
1724 { 0, 0 },
1725 { 0, 0 },
1726 { 0, 0 },
1727 { 0, 0 },
1728 { 0, 0 },
1729 { 0, 0 },
1730 { 0, 0 },
1731 { 0, 0 },
1732 { TERM_SLATE, TERM_L_DARK }, /* RF4_BRTH_ACID */
1733 { TERM_BLUE, TERM_L_BLUE }, /* RF4_BRTH_ELEC */
1734 { TERM_RED, TERM_L_RED }, /* RF4_BRTH_FIRE */
1735 { TERM_WHITE, TERM_L_WHITE }, /* RF4_BRTH_COLD */
1736 { TERM_GREEN, TERM_L_GREEN }, /* RF4_BRTH_POIS */
1737 { TERM_L_GREEN, TERM_GREEN }, /* RF4_BRTH_NETHR */
1738 { TERM_YELLOW, TERM_ORANGE }, /* RF4_BRTH_LITE */
1739 { TERM_L_DARK, TERM_SLATE }, /* RF4_BRTH_DARK */
1740 { TERM_L_UMBER, TERM_UMBER }, /* RF4_BRTH_CONFU */
1741 { TERM_YELLOW, TERM_L_UMBER }, /* RF4_BRTH_SOUND */
1742 { 255, 255 }, /* (any color) */ /* RF4_BRTH_CHAOS */
1743 { TERM_VIOLET, TERM_VIOLET }, /* RF4_BRTH_DISEN */
1744 { TERM_L_RED, TERM_VIOLET }, /* RF4_BRTH_NEXUS */
1745 { TERM_L_BLUE, TERM_L_BLUE }, /* RF4_BRTH_TIME */
1746 { TERM_L_WHITE, TERM_SLATE }, /* RF4_BRTH_INER */
1747 { TERM_L_WHITE, TERM_SLATE }, /* RF4_BRTH_GRAV */
1748 { TERM_UMBER, TERM_L_UMBER }, /* RF4_BRTH_SHARD */
1749 { TERM_ORANGE, TERM_RED }, /* RF4_BRTH_PLAS */
1750 { TERM_UMBER, TERM_L_UMBER }, /* RF4_BRTH_FORCE */
1751 { TERM_L_BLUE, TERM_WHITE }, /* RF4_BRTH_MANA */
1752 { TERM_WHITE, TERM_L_RED }, /* RF4_BRTH_DISINT */
1753 { TERM_GREEN, TERM_L_GREEN }, /* RF4_BRTH_NUKE */
1754 { 0, 0 }, /* */
1755 { 0, 0 }, /* */
1756 };
1757 #else
1758 /* new table that uses animated TERM_ colour codes - C. Blue */
1759 static byte breath_to_attr[32][2] =
1760 {
1761 { 0, 0},
1762 { 0, 0},
1763 { 0, 0},
1764 { 0, 0},
1765 { 0, 0},
1766 { 0, 0},
1767 { 0, 0},
1768 { 0, 0},
1769 { TERM_ACID }, /* RF4_BRTH_ACID */
1770 { TERM_ELEC }, /* RF4_BRTH_ELEC */
1771 { TERM_FIRE }, /* RF4_BRTH_FIRE */
1772 { TERM_COLD }, /* RF4_BRTH_COLD */
1773 { TERM_POIS }, /* RF4_BRTH_POIS */
1774 { TERM_L_GREEN, TERM_L_DARK }, /* RF4_BRTH_NETHR */
1775 { TERM_LITE, 0 }, /* RF4_BRTH_LITE */
1776 { TERM_DARKNESS, 0 }, /* RF4_BRTH_DARK */
1777 { TERM_CONF, 0 }, /* RF4_BRTH_CONFU */
1778 { TERM_SOUN, 0 }, /* RF4_BRTH_SOUND */
1779 { 255, 255 }, /* (any color) */ /* RF4_BRTH_CHAOS */
1780 { TERM_ORANGE, TERM_BLUE }, /* RF4_BRTH_DISEN */
1781 { TERM_L_RED, TERM_VIOLET }, /* RF4_BRTH_NEXUS */
1782 { TERM_L_BLUE, TERM_L_GREEN }, /* RF4_BRTH_TIME */
1783 { TERM_L_WHITE, TERM_SLATE }, /* RF4_BRTH_INER */
1784 { TERM_L_UMBER, TERM_UMBER }, /* RF4_BRTH_GRAV */
1785 { TERM_SHAR, 0 }, /* RF4_BRTH_SHARD */
1786 { TERM_L_RED, TERM_RED }, /* RF4_BRTH_PLAS */
1787 { TERM_L_WHITE, TERM_ORANGE }, /* RF4_BRTH_FORCE */
1788 { TERM_VIOLET, TERM_L_BLUE }, /* RF4_BRTH_MANA */
1789 { TERM_L_DARK, TERM_ORANGE }, /* RF4_BRTH_DISINT */
1790 { TERM_GREEN, TERM_RED }, /* RF4_BRTH_NUKE */
1791 { 0, 0 }, /* */
1792 { 0, 0 }, /* */
1793 };
1794 #endif
1795 /*
1796 * Multi-hued monsters shimmer acording to their breaths.
1797 *
1798 * If a monster has only one kind of breath, it uses both colors
1799 * associated with that breath. Otherwise, it just uses the first
1800 * color for any of its breaths.
1801 *
1802 * If a monster does not breath anything, it can be any color.
1803 */
1804 static byte multi_hued_attr(monster_race *r_ptr)
1805 {
1806 byte allowed_attrs[15];
1807 int stored_colors = 0;
1808
1809 byte a;
1810
1811 int i, j;
1812 int breaths = 0;
1813 int first_color = 0;
1814 int second_color = 0;
1815
1816 /* Monsters with no ranged attacks can be any color */
1817 #ifdef CLIENT_SHIMMER
1818 if (!r_ptr->freq_innate) return (TERM_HALF);
1819 #else
1820 if (!r_ptr->freq_innate) return (get_shimmer_color());
1821 #endif
1822
1823 /* Check breaths */
1824 for (i = 0; i < 32; i++) {
1825 bool stored = FALSE;
1826
1827 /* Don't have that breath */
1828 if (!(r_ptr->flags4 & (1L << i))) continue;
1829
1830 /* Get the first color of this breath */
1831 first_color = breath_to_attr[i][0];
1832
1833 /* Breath has no color associated with it */
1834 if (first_color == 0) continue;
1835
1836 /* Monster can be of any color */
1837 #ifdef CLIENT_SHIMMER
1838 if (first_color == 255) return (TERM_MULTI);
1839 #else
1840 if (first_color == 255) return (randint(15));
1841 #endif
1842
1843
1844 /* Increment the number of breaths */
1845 breaths++;
1846
1847 /* Monsters with lots of breaths may be any color. */
1848 #ifdef CLIENT_SHIMMER
1849 if (breaths == 6) return (TERM_MULTI);
1850 #else
1851 if (breaths == 6) return (randint(15));
1852 #endif
1853
1854
1855 /* Always store the first color */
1856 for (j = 0; j < stored_colors; j++) {
1857 /* Already stored */
1858 if (allowed_attrs[j] == first_color) stored = TRUE;
1859 }
1860 if (!stored) {
1861 allowed_attrs[stored_colors] = first_color;
1862 stored_colors++;
1863 }
1864
1865 /*
1866 * Remember (but do not immediately store) the second color
1867 * of the first breath.
1868 */
1869 if (breaths == 1) {
1870 second_color = breath_to_attr[i][1];
1871 /* make sure breath colour gets more showtime than base colour - C. Blue */
1872 if (!second_color) second_color = first_color;
1873 }
1874 }
1875
1876 /* Monsters with no breaths may be of any color. */
1877 #ifdef CLIENT_SHIMMER
1878 if (breaths == 0 || breaths == 5) {
1879 return (TERM_HALF);
1880 }
1881 #else
1882 if (breaths == 0) return (get_shimmer_color());
1883 #endif
1884
1885 /* If monster has one breath, store the second color too. */
1886 if (breaths == 1) {
1887 /* only 1 breath, and one of these? -> discard its r_info
1888 base colour completely if ATTR_BASE isn't set: */
1889 if (!(r_ptr->flags7 & RF7_ATTR_BASE)) {
1890 switch(r_ptr->flags4 & 0x3fffff00) {
1891 case RF4_BR_ACID:
1892 return(TERM_ACID);
1893 case RF4_BR_COLD:
1894 return(TERM_COLD);
1895 case RF4_BR_FIRE:
1896 return(TERM_FIRE);
1897 case RF4_BR_ELEC:
1898 return(TERM_ELEC);
1899 case RF4_BR_POIS:
1900 return(TERM_POIS);
1901 case RF4_BR_CONF:
1902 return(TERM_CONF);
1903 case RF4_BR_SOUN:
1904 return(TERM_SOUN);
1905 case RF4_BR_SHAR:
1906 return(TERM_SHAR);
1907 case RF4_BR_LITE:
1908 return(TERM_LITE);
1909 default:
1910 /* This is annoying - mikaelh */
1911 // printf("fla: %x\n", r_ptr->flags4 & 0x3fffff00);
1912 break;
1913 }
1914 }
1915 allowed_attrs[stored_colors] = second_color;
1916 stored_colors++;
1917 }
1918
1919 /*
1920 * Hack -- Always has the base colour
1921 * (otherwise, Dragonriders are all red)
1922 */
1923 #if 0
1924 if (!m_ptr->special && !m_ptr->questor && p_ptr->use_r_gfx) a = p_ptr->r_attr[m_ptr->r_idx];
1925 else a = r_ptr->d_attr;
1926 #endif /* 0 */
1927 a = r_ptr->d_attr;
1928
1929 allowed_attrs[stored_colors] = a;
1930 stored_colors++;
1931
1932 /* Pick a color at random */
1933 return (allowed_attrs[rand_int(stored_colors)]);
1934 }
1935
1936 /* Despite of its name, this gets both, attr and char, for a monster race.. */
1937 static void get_monster_color(int Ind, monster_type *m_ptr, monster_race *r_ptr, cave_type *c_ptr, byte *ap, char *cp)
1938 {
1939 player_type *p_ptr = Players[Ind];
1940 byte a;
1941 char c;
1942 //monster_race *r_ptr = race_inf(m_ptr);
1943
1944 /* Possibly GFX corrupts with egos;
1945 * in that case use m_ptr->r_ptr instead. - Jir -
1946 */
1947 /* Desired attr */
1948 /* a = r_ptr->x_attr; */
1949 if (m_ptr && !m_ptr->special && !m_ptr->questor && p_ptr->use_r_gfx) a = p_ptr->r_attr[m_ptr->r_idx];
1950 else a = r_ptr->d_attr;
1951 /* else a = m_ptr->r_ptr->d_attr; */
1952
1953 /* Desired char */
1954 /* c = r_ptr->x_char; */
1955 if (m_ptr && !m_ptr->special && !m_ptr->questor && p_ptr->use_r_gfx) c = p_ptr->r_char[m_ptr->r_idx];
1956 else c = r_ptr->d_char;
1957 /* else c = m_ptr->r_ptr->d_char; */
1958
1959 /* Hack -- mimics */
1960 if (r_ptr->flags9 & RF9_MIMIC) {
1961 mimic_object(&a, &c, c_ptr->m_idx);
1962 }
1963
1964 /* Ignore weird codes */
1965 if (avoid_other) {
1966 /* Use char */
1967 (*cp) = c;
1968
1969 /* Use attr */
1970 (*ap) = a;
1971 }
1972
1973 /* Special attr/char codes */
1974 else if ((a & 0x80) && (c & 0x80)) {
1975 /* Use char */
1976 (*cp) = c;
1977
1978 /* Use attr */
1979 (*ap) = a;
1980 }
1981
1982 #ifdef M_EGO_NEW_FLICKER
1983 /* Hack -- Unique/Ego 'glitters' sometimes */
1984 else if ((((r_ptr->flags1 & RF1_UNIQUE) && magik(30)) ||
1985 (m_ptr && m_ptr->ego &&
1986 ((re_info[m_ptr->ego].d_attr != MEGO_CHAR_ANY) ?
1987 magik(85) : magik(5)))
1988 ) &&
1989 (!(r_ptr->flags1 & (RF1_ATTR_CLEAR | RF1_CHAR_CLEAR)) &&
1990 !(r_ptr->flags2 & (RF2_SHAPECHANGER))))
1991 {
1992 (*cp) = c;
1993
1994 if (r_ptr->flags1 & RF1_UNIQUE) {
1995 /* Multi-hued attr */
1996 if (r_ptr->flags2 & (RF2_ATTR_ANY))
1997 (*ap) = TERM_MULTI;
1998 else
1999 (*ap) = TERM_HALF;
2000 } else { /* m_ptr->ego is set: */
2001 if (re_info[m_ptr->ego].d_attr != MEGO_CHAR_ANY) {
2002 /* ego colour differs from race colour? */
2003 if (a != re_info[m_ptr->ego].d_attr) {
2004 /* flicker in ego colour */
2005 (*ap) = re_info[m_ptr->ego].d_attr;
2006 } else if (magik(20)) {
2007 /* flash randomly, rarely */
2008 (*ap) = TERM_HALF;
2009 } else {
2010 (*ap) = a;
2011 }
2012 } else { /* no ego colour? rarely flash (similar to old way) */
2013 /* ego has no colour - flicker in random colour */
2014 (*ap) = TERM_HALF;
2015 }
2016 }
2017 }
2018 #else
2019 /* Hack -- Unique/Ego 'glitters' sometimes */
2020 else if ((((r_ptr->flags1 & RF1_UNIQUE) && magik(30)) ||
2021 (m_ptr && m_ptr->ego && magik(5)) ) &&
2022 (!(r_ptr->flags1 & (RF1_ATTR_CLEAR | RF1_CHAR_CLEAR)) &&
2023 !(r_ptr->flags2 & (RF2_SHAPECHANGER))))
2024 {
2025 (*cp) = c;
2026
2027 /* Multi-hued attr */
2028 if (r_ptr->flags2 & (RF2_ATTR_ANY))
2029 (*ap) = TERM_MULTI;
2030 else
2031 (*ap) = TERM_HALF;
2032 }
2033 #endif
2034 /* Multi-hued monster */
2035 else if (r_ptr->flags1 & RF1_ATTR_MULTI) {
2036 /* Is it a shapechanger? */
2037 if (r_ptr->flags2 & RF2_SHAPECHANGER) {
2038 (*cp) = (randint((r_ptr->flags7 & RF7_VORTEX) ? 1 : 25) == 1?
2039 image_object_hack[randint(strlen(image_object_hack))]:
2040 image_monster_hack[randint(strlen(image_monster_hack))]);
2041 } else
2042 (*cp) = c;
2043
2044 /* Multi-hued attr */
2045 if (r_ptr->flags2 & (RF2_ATTR_ANY))
2046 (*ap) = randint(15);
2047 #ifdef MULTI_HUED_PROPER
2048 else (*ap) = multi_hued_attr(r_ptr);
2049 #else
2050 #ifdef CLIENT_SHIMMER
2051 else (*ap) = TERM_HALF;
2052 #else
2053 else (*ap) = get_shimmer_color();
2054 #endif
2055 #endif /* MULTI_HUED_PROPER */
2056 #if 0
2057 /* Normal char */
2058 (*cp) = c;
2059
2060 /* Multi-hued attr */
2061 (*ap) = randint(15);
2062 #endif /* 0 */
2063 }
2064 /* Special ATTR_BNW flag: Monster just flickers black and white,
2065 possibly also its base colour if ATTR_BASE is set either.
2066 Added this 'hack flag' to display silly Pandas - C. Blue */
2067 else if (r_ptr->flags7 & RF7_ATTR_BNW) {
2068 (*cp) = c;
2069 #ifdef SLOW_ATTR_BNW /* handle server-side -> slower speed flickering */
2070 if ((r_ptr->flags7 & RF7_ATTR_BASE) && !rand_int(3)) {
2071 /* Use base attr */
2072 (*ap) = a;
2073 } else {
2074 (*ap) = rand_int(2) ? TERM_L_DARK : TERM_WHITE;
2075 }
2076 #else /* handle client-side -> the usual fast flickering, same as dungeon wizards */
2077 #ifdef EXTENDED_TERM_COLOURS
2078 if (is_older_than(&p_ptr->version, 4, 5, 1, 2, 0, 0))
2079 (*ap) = TERM_OLD_BNW + ((r_ptr->flags7 & RF7_ATTR_BASE) ? a : 0x0);
2080 else
2081 #endif
2082 (*ap) = TERM_BNW + ((r_ptr->flags7 & RF7_ATTR_BASE) ? a : 0x0);
2083 #endif
2084 }
2085 /* Normal monster (not "clear" in any way) */
2086 else if (!(r_ptr->flags1 & (RF1_ATTR_CLEAR | RF1_CHAR_CLEAR))) {
2087 /* Use char */
2088 (*cp) = c;
2089
2090 /* Is it a non-colourchanging shapechanger? */
2091 if (r_ptr->flags2 & RF2_SHAPECHANGER) {
2092 (*cp) = (randint((r_ptr->flags7 & RF7_VORTEX) ? 1 : 25) == 1?
2093 image_object_hack[randint(strlen(image_object_hack))]:
2094 image_monster_hack[randint(strlen(image_monster_hack))]);
2095 }
2096
2097 /* Use attr */
2098 (*ap) = a;
2099 }
2100
2101 /* Hack -- Bizarre grid under monster */
2102 else if ((*ap & 0x80) || (*cp & 0x80)) {
2103 /* Use char */
2104 (*cp) = c;
2105
2106 /* Use attr */
2107 (*ap) = a;
2108 }
2109
2110 /* Normal */
2111 else {
2112 /* Normal (non-clear char) monster */
2113 if (!(r_ptr->flags1 & RF1_CHAR_CLEAR)) {
2114 /* Normal char */
2115 (*cp) = c;
2116
2117 /* Is it a non-colourchanging shapechanger? */
2118 if (r_ptr->flags2 & RF2_SHAPECHANGER) {
2119 (*cp) = (randint((r_ptr->flags7 & RF7_VORTEX) ? 1 : 25) == 1?
2120 image_object_hack[randint(strlen(image_object_hack))]:
2121 image_monster_hack[randint(strlen(image_monster_hack))]);
2122 }
2123
2124 }
2125
2126 /* Normal (non-clear attr) monster */
2127 else if (!(r_ptr->flags1 & RF1_ATTR_CLEAR)) {
2128 /* Normal attr */
2129 (*ap) = a;
2130 }
2131 }
2132
2133 /* Hack -- hallucination */
2134 if (p_ptr->image) {
2135 /* Hallucinatory monster */
2136 image_monster(ap, cp);
2137 }
2138 }
2139
2140 /*
2141 * Return the correct "color" of another player
2142 */
2143 static byte player_color(int Ind)
2144 {
2145 player_type *p_ptr = Players[Ind];
2146 // monster_race *r_ptr = &r_info[p_ptr->body_monster];
2147 byte pcolor = p_ptr->pclass;
2148 char dummy;
2149 cave_type **zcave = getcave(&p_ptr->wpos);
2150 cave_type *c_ptr;
2151 pcolor = p_ptr->cp_ptr->color;
2152
2153 /* Check that zcave isn't NULL - mikaelh */
2154 if (!zcave) {
2155 s_printf("DEBUG: zcave was NULL in player_color\n");
2156 return TERM_L_DARK;
2157 }
2158
2159 c_ptr = &zcave[p_ptr->py][p_ptr->px];
2160
2161 /* Ghosts are black */
2162 if (p_ptr->ghost) {
2163 if (p_ptr->admin_wiz)
2164 #ifdef EXTENDED_TERM_COLOURS
2165 return TERM_L_DARK + (is_older_than(&p_ptr->version, 4, 5, 1, 2, 0, 0) ? TERM_OLD_BNW : TERM_BNW);
2166 #else
2167 return TERM_L_DARK + TERM_BNW;
2168 #endif
2169 return TERM_L_DARK;
2170 }
2171
2172 /* Black Breath carriers emit malignant aura sometimes.. */
2173 if (p_ptr->black_breath && magik(50)) return TERM_L_DARK;
2174
2175 /* Covered by a mummy wrapping? */
2176 if (TOOL_EQUIPPED(p_ptr) == SV_TOOL_WRAPPING) pcolor = TERM_L_DARK;
2177 if (p_ptr->cloaked == 1) pcolor = TERM_L_DARK; /* ignore cloak_neutralized for now */
2178
2179 /* Mimicing a monster */
2180 /* TODO: handle 'ATTR_MULTI', 'ATTR_CLEAR' */
2181 /* the_sandman: an attempt to actually diplay the mhd flickers on mimicking player using DS spell */
2182 if (p_ptr->body_monster)
2183 get_monster_color(Ind, NULL, &r_info[p_ptr->body_monster], c_ptr, &pcolor, &dummy);
2184
2185 /* Wearing a costume */
2186 if ((p_ptr->inventory[INVEN_BODY].tval == TV_SOFT_ARMOR) && (p_ptr->inventory[INVEN_BODY].sval == SV_COSTUME))
2187 get_monster_color(Ind, NULL, &r_info[p_ptr->inventory[INVEN_BODY].bpval], c_ptr, &pcolor, &dummy);
2188
2189 /* See vampires burn in the sun sometimes.. */
2190 if (p_ptr->sun_burn && magik(33)) return TERM_FIRE;
2191
2192 /* Mana Shield and GOI also flicker */
2193 /* NOTE: For the player looking at himself, this is done in lite_spot(),
2194 which is called from set_tim_manashield(). */
2195 #ifdef EXTENDED_TERM_COLOURS
2196 if (!is_older_than(&p_ptr->version, 4, 5, 1, 2, 0, 0)) {
2197 if (p_ptr->tim_manashield > 15) return TERM_SHIELDM;
2198 else if (p_ptr->tim_manashield) return TERM_NEXU;
2199 } else
2200 #endif
2201 if (p_ptr->tim_manashield > 15) return TERM_SHIELDM;
2202
2203 #ifdef EXTENDED_TERM_COLOURS
2204 if (!is_older_than(&p_ptr->version, 4, 5, 1, 2, 0, 0)) {
2205 if (p_ptr->invuln > 5) return TERM_SHIELDI;
2206 else if (p_ptr->invuln && p_ptr->invuln_dur >= 5) return TERM_NUKE;
2207 } else
2208 #endif
2209 if (p_ptr->invuln > 5) return TERM_SHIELDI;
2210
2211 /* Holy Martyr or shadow running */
2212 /* Admin wizards sometimes flicker black & white (TERM_BNW) */
2213 if (p_ptr->shadow_running || p_ptr->martyr || p_ptr->admin_wiz)
2214 #ifdef EXTENDED_TERM_COLOURS
2215 pcolor += is_older_than(&p_ptr->version, 4, 5, 1, 2, 0, 0) ? TERM_OLD_BNW : TERM_BNW;
2216 #else
2217 pcolor += TERM_BNW;
2218 #endif
2219
2220 /* Team colours have highest priority */
2221 if (p_ptr->team) {
2222 /* may have multiteam */
2223 switch(p_ptr->team) {
2224 case 1:
2225 pcolor = TERM_L_RED; //the_sandman: changed it to light red
2226 //since red == istari.
2227 break;
2228 case 2:
2229 pcolor = TERM_L_BLUE;
2230 break;
2231 case 3:
2232 pcolor = TERM_YELLOW;
2233 break;
2234 case 4:
2235 pcolor = TERM_UMBER;
2236 break;
2237 default:
2238 break;
2239 }
2240 if ((has_ball(p_ptr) != -1) && magik(50)) pcolor = TERM_ORANGE; /* game ball carrier has orange flickering - mikaelh */
2241 }
2242
2243 /* Color is based off of class */
2244 return pcolor;
2245 }
2246
2247 byte get_trap_color(int Ind, int t_idx, int feat)
2248 {
2249 player_type *p_ptr = Players[Ind];
2250 byte a;
2251
2252 /* Get attr */
2253 a = t_info[t_idx].color;
2254
2255 /* Get a new color with a strange formula :) */
2256 if (t_info[t_idx].flags & FTRAP_CHANGE)
2257 {
2258 u32b tmp;
2259
2260 /* tmp = dlev + dungeon_type + c_ptr->feat; */
2261 tmp = p_ptr->wpos.wx + p_ptr->wpos.wy + p_ptr->wpos.wz + feat;
2262
2263 /* a = tmp % 16; */
2264 /* mega-hack: use trap-like colours only */
2265 a = tmp % 6 + 1;
2266 }
2267
2268 /* Hack -- always l.blue if underwater */
2269 if (feat == FEAT_DEEP_WATER || feat == FEAT_SHAL_WATER)
2270 a = TERM_L_BLUE;
2271
2272 return a;
2273 }
2274
2275 byte get_monster_trap_color(int Ind, int o_idx, int feat) {
2276 byte a;
2277 object_type *kit_o_ptr;
2278 // object_type *load_o_ptr;
2279
2280 /* Get the trap objects */
2281 kit_o_ptr = &o_list[o_idx];
2282 // load_o_ptr = &o_list[kit_o_ptr->next_o_idx];
2283
2284 /* Get attr */
2285 a = k_info[kit_o_ptr->k_idx].d_attr;
2286
2287 /* Hack -- always l.blue if underwater */
2288 if (feat == FEAT_DEEP_WATER || feat == FEAT_SHAL_WATER)
2289 a = TERM_L_BLUE;
2290
2291 return a;
2292 }
2293
2294 byte get_rune_color(int Ind, int typ) {
2295 byte a = spell_color(r_projections[typ].gf_type);
2296 return a;
2297 }
2298
2299 /*
2300 * Manipulate map grid colours, for example outside on world surface,
2301 * depending on clima or daytime! - C. Blue
2302 */
2303 static int manipulate_cave_colour_season(cave_type *c_ptr, worldpos *wpos, int x, int y, int colour) {
2304 bool old_rand = Rand_quick;
2305 u32b tmp_seed = Rand_value; /* save RNG */
2306 wilderness_type *w_ptr = &wild_info[wpos->wy][wpos->wx];
2307
2308 /* World surface manipulation only */
2309 if (wpos->wz) return colour;
2310
2311 /* To use always the same feats for this everytime the player
2312 enters a worldmap sector, we seed the RNG with that particular
2313 worldmap coords. */
2314 Rand_quick = TRUE;
2315 /* My attempt to create something chaotic - mikaelh */
2316 Rand_value = (3623 * wpos->wy + 29753) * (2843 * wpos->wx + 48869) +
2317 (1741 * y + 22109) * y * x + (x + 96779) * x + 42;
2318
2319 /* Seasons */
2320 switch (season) {
2321 case SEASON_WINTER:
2322 /* Replace green trees and grass by white =-} - using live information of original finnish winter */
2323 if (w_ptr->type != WILD_VOLCANO && (w_ptr->type != WILD_DESERT || c_ptr->feat == FEAT_GRASS)) {
2324 /* Sometimes display a feat still as green, sometimes brown. */
2325 switch (c_ptr->feat) {
2326 case FEAT_DIRT:
2327 switch (Rand_div(7)) {
2328 case 0: case 1: case 2: case 3: case 4:
2329 colour = TERM_L_WHITE; break;
2330 case 5: if (c_ptr->info & CAVE_LITE) colour = TERM_L_UMBER;
2331 else colour = TERM_UMBER;
2332 break;
2333 case 6: colour = TERM_SLATE; break;
2334 }
2335 break;
2336 #if 0 /* maybe keep disabled, for stone2mud effects on world surface - doesn't matter much though? */
2337 case FEAT_MUD:
2338 switch (Rand_div(7)) {
2339 case 0: case 1: case 2: case 3:
2340 colour = TERM_L_WHITE; break;
2341 case 4: case 5: case 6: if (c_ptr->info & CAVE_LITE) colour = TERM_L_UMBER;
2342 else colour = TERM_UMBER;
2343 break;
2344 }
2345 break;
2346 #endif
2347 case FEAT_GRASS:
2348 switch (Rand_div(7)) {
2349 case 0: case 1: case 2: case 3: case 4:
2350 colour = TERM_L_WHITE; break;
2351 case 5: case 6:
2352 if (c_ptr->info & CAVE_LITE) colour = TERM_L_UMBER;
2353 else colour = TERM_UMBER;
2354 break;
2355 // case 7: colour = TERM_GREEN; break;
2356 }
2357 break;
2358 case FEAT_TREE:
2359 case FEAT_BUSH:
2360 if (Rand_div(50)) colour = TERM_WHITE;
2361 else if (Rand_div(3)) colour = TERM_UMBER;
2362 else colour = TERM_GREEN;
2363 break;
2364 case FEAT_IVY:
2365 if (Rand_div(50)) colour = TERM_WHITE;
2366 else if (Rand_div(3)) colour = TERM_UMBER;
2367 else colour = TERM_GREEN;
2368 break;
2369 case FEAT_MOUNTAIN:
2370 if (Rand_div(4)) colour = TERM_WHITE;
2371 break;
2372 }
2373 }
2374 break;
2375 case SEASON_SPRING:
2376 /* More saplings and all green goodness in spring time, yay */
2377 if (w_ptr->type != WILD_DESERT || c_ptr->feat == FEAT_GRASS) {
2378 switch (c_ptr->feat) {
2379 case FEAT_GRASS:
2380 switch (Rand_div(7)) {
2381 case 0: case 1: case 2: case 3: case 4:
2382 colour = TERM_L_GREEN; break;
2383 case 5: if (c_ptr->info & CAVE_LITE) colour = TERM_L_UMBER;
2384 else colour = TERM_UMBER;
2385 break;
2386 case 6: colour = TERM_GREEN; break;
2387 }
2388 break;
2389 case FEAT_TREE:
2390 case FEAT_BUSH:
2391 if (Rand_div(300)) colour = TERM_L_GREEN;
2392 else if (Rand_div(3)) colour = TERM_L_UMBER;
2393 else colour = TERM_UMBER;
2394 break;
2395 case FEAT_IVY:
2396 if (Rand_div(500)) colour = TERM_GREEN;
2397 else if (Rand_div(3)) colour = TERM_GREEN;
2398 else colour = TERM_UMBER;
2399 break;
2400 }
2401 }
2402 break;
2403 case SEASON_SUMMER:
2404 /* Mostly grown trees, some bushes, all saturated green, some light green and yellow/light umber */
2405 if (w_ptr->type != WILD_DESERT || c_ptr->feat == FEAT_GRASS) {
2406 switch (c_ptr->feat) {
2407 case FEAT_GRASS:
2408 switch (Rand_div(6)) {
2409 case 0:
2410 colour = TERM_L_GREEN; break;
2411 case 1: case 2:
2412 if (c_ptr->info & CAVE_LITE) colour = TERM_YELLOW;
2413 else colour = TERM_L_UMBER;
2414 break;
2415 case 3: case 4:
2416 colour = TERM_GREEN; break;
2417 case 5:
2418 colour = TERM_YELLOW; break;
2419 }
2420 break;
2421 case FEAT_TREE:
2422 case FEAT_BUSH:
2423 if (Rand_div(4)) colour = TERM_GREEN;
2424 else if (Rand_div(10)) colour = TERM_L_GREEN;
2425 else colour = TERM_L_UMBER;
2426 break;
2427 case FEAT_IVY:
2428 if (Rand_div(3)) colour = TERM_GREEN;
2429 else if (Rand_div(3)) colour = TERM_L_UMBER;
2430 else colour = TERM_UMBER;
2431 break;
2432 }
2433 }
2434 break;
2435 case SEASON_AUTUMN:
2436 /* Rarely saplings, very colourful trees, turning to other tones than green */
2437 if (w_ptr->type != WILD_DESERT || c_ptr->feat == FEAT_GRASS) {
2438 switch (c_ptr->feat) {
2439 case FEAT_GRASS:
2440 switch (Rand_div(7)) {
2441 case 0: case 1: case 2:
2442 colour = TERM_GREEN; break;
2443 case 3: case 4:
2444 if (c_ptr->info & CAVE_LITE) colour = TERM_L_UMBER;
2445 else colour = TERM_UMBER;
2446 break;
2447 case 5: case 6:
2448 colour = TERM_YELLOW; break;
2449 }
2450 break;
2451 case FEAT_TREE:
2452 case FEAT_BUSH:
2453 if (Rand_div(50))
2454 switch (Rand_div(10)) {
2455 case 0: case 1: colour = TERM_GREEN; break;
2456 case 2: case 3: case 4: colour = TERM_YELLOW; break;
2457 case 5: case 6: case 7: colour = TERM_L_UMBER; break;
2458 case 8: case 9: colour = TERM_UMBER; break;
2459 }
2460 else colour = TERM_RED;
2461 break;
2462 case FEAT_IVY:
2463 if (Rand_div(3)) colour = TERM_GREEN;
2464 else if (Rand_div(3)) colour = TERM_L_UMBER;
2465 else colour = TERM_UMBER;
2466 break;
2467 }
2468 }
2469 break;
2470 }
2471
2472 Rand_quick = old_rand; /* resume complex rng - mikaelh */
2473 Rand_value = tmp_seed; /* restore RNG */
2474 return colour;
2475 }
2476 static int manipulate_cave_colour_daytime(cave_type *c_ptr, worldpos *wpos, int x, int y, int colour) {
2477 /* World surface manipulation only */
2478 if (wpos->wz) return colour;
2479
2480 /* Darkness on the world surface at night. Darken all colours. */
2481 if (night_surface &&
2482 (!(c_ptr->info & (CAVE_GLOW | CAVE_LITE)) ||
2483 (f_info[c_ptr->feat].flags2 & FF2_NIGHT_DARK))) {
2484 switch (colour) {
2485 case TERM_DARK: return TERM_DARK;
2486 case TERM_WHITE: return TERM_SLATE;
2487 case TERM_SLATE: return TERM_L_DARK;
2488 case TERM_ORANGE: return TERM_UMBER;
2489 case TERM_RED: return TERM_RED;
2490 case TERM_GREEN: return TERM_GREEN;
2491 case TERM_BLUE: return TERM_BLUE;
2492 case TERM_UMBER: return TERM_UMBER;
2493 case TERM_L_DARK: return TERM_L_DARK;
2494 case TERM_L_WHITE: return TERM_SLATE;
2495 case TERM_VIOLET: return TERM_VIOLET;
2496 case TERM_YELLOW: return TERM_L_UMBER;
2497 case TERM_L_RED: return TERM_RED;
2498 case TERM_L_GREEN: return TERM_GREEN;
2499 case TERM_L_BLUE: return TERM_BLUE;
2500 case TERM_L_UMBER: return TERM_UMBER;
2501 }
2502 }
2503
2504 return colour;
2505 }
2506 static int manipulate_cave_colour(cave_type *c_ptr, worldpos *wpos, int x, int y, int colour) {
2507 colour = manipulate_cave_colour_season(c_ptr, wpos, x, y, colour);
2508 return manipulate_cave_colour_daytime(c_ptr, wpos, x, y, colour);
2509 }
2510 #ifdef SHADE_ALL_FLOOR
2511 static int manipulate_cave_colour_shade(cave_type *c_ptr, worldpos *wpos, int x, int y, int colour) {
2512 switch (colour) {
2513 case TERM_DARK: return TERM_DARK;
2514 case TERM_WHITE: return TERM_SLATE;
2515 case TERM_SLATE: return TERM_L_DARK;
2516 case TERM_ORANGE: return TERM_UMBER;
2517 case TERM_RED: return TERM_RED;
2518 case TERM_GREEN: return TERM_GREEN;
2519 case TERM_BLUE: return TERM_BLUE;
2520 case TERM_UMBER: return TERM_UMBER;
2521 case TERM_L_DARK: return TERM_L_DARK;
2522 case TERM_L_WHITE: return TERM_SLATE;
2523 case TERM_VIOLET: return TERM_VIOLET;
2524 case TERM_YELLOW: return TERM_L_UMBER;
2525 case TERM_L_RED: return TERM_RED;
2526 case TERM_L_GREEN: return TERM_GREEN;
2527 case TERM_L_BLUE: return TERM_BLUE;
2528 case TERM_L_UMBER: return TERM_UMBER;
2529 }
2530 return colour;
2531 }
2532 #endif
2533
2534
2535 /*
2536 * Extract the attr/char to display at the given (legal) map location
2537 *
2538 * Basically, we "paint" the chosen attr/char in several passes, starting
2539 * with any known "terrain features" (defaulting to darkness), then adding
2540 * any known "objects", and finally, adding any known "monsters". This
2541 * is not the fastest method but since most of the calls to this function
2542 * are made for grids with no monsters or objects, it is fast enough.
2543 *
2544 * Note that this function, if used on the grid containing the "player",
2545 * will return the attr/char of the grid underneath the player, and not
2546 * the actual player attr/char itself, allowing a lot of optimization
2547 * in various "display" functions.
2548 *
2549 * Note that the "zero" entry in the feature/object/monster arrays are
2550 * used to provide "special" attr/char codes, with "monster zero" being
2551 * used for the player attr/char, "object zero" being used for the "stack"
2552 * attr/char, and "feature zero" being used for the "nothing" attr/char,
2553 * though this function makes use of only "feature zero".
2554 *
2555 * Note that monsters can have some "special" flags, including "ATTR_MULTI",
2556 * which means their color changes, and "ATTR_CLEAR", which means they take
2557 * the color of whatever is under them, and "CHAR_CLEAR", which means that
2558 * they take the symbol of whatever is under them. Technically, the flag
2559 * "CHAR_MULTI" is supposed to indicate that a monster looks strange when
2560 * examined, but this flag is currently ignored. All of these flags are
2561 * ignored if the "avoid_other" option is set, since checking for these
2562 * conditions is expensive and annoying on some systems.
2563 *
2564 * Currently, we do nothing with multi-hued objects. We should probably
2565 * just add a flag to wearable object, or even to all objects, now that
2566 * everyone can use the same flags. Then the "SHIMMER_OBJECT" code can
2567 * be used to request occasional "redraw" of those objects. It will be
2568 * very hard to associate flags with the "flavored" objects, so maybe
2569 * they will never be "multi-hued".
2570 *
2571 * Note the effects of hallucination. Objects always appear as random
2572 * "objects", monsters as random "monsters", and normal grids occasionally
2573 * appear as random "monsters" or "objects", but note that these random
2574 * "monsters" and "objects" are really just "colored ascii symbols".
2575 *
2576 * Note that "floors" and "invisible traps" (and "zero" features) are
2577 * drawn as "floors" using a special check for optimization purposes,
2578 * and these are the only features which get drawn using the special
2579 * lighting effects activated by "floor_lighting".
2580 *
2581 * Note the use of the "mimic" field in the "terrain feature" processing,
2582 * which allows any feature to "pretend" to be another feature. This is
2583 * used to "hide" secret doors, and to make all "doors" appear the same,
2584 * and all "walls" appear the same, and "hidden" treasure stay hidden.
2585 * It is possible to use this field to make a feature "look" like a floor,
2586 * but the "special lighting effects" for floors will not be used.
2587 *
2588 * Note the use of the new "terrain feature" information. Note that the
2589 * assumption that all interesting "objects" and "terrain features" are
2590 * memorized allows extremely optimized processing below. Note the use
2591 * of separate flags on objects to mark them as memorized allows a grid
2592 * to have memorized "terrain" without granting knowledge of any object
2593 * which may appear in that grid.
2594 *
2595 * Note the efficient code used to determine if a "floor" grid is
2596 * "memorized" or "viewable" by the player, where the test for the
2597 * grid being "viewable" is based on the facts that (1) the grid
2598 * must be "lit" (torch-lit or perma-lit), (2) the grid must be in
2599 * line of sight, and (3) the player must not be blind, and uses the
2600 * assumption that all torch-lit grids are in line of sight.
2601 *
2602 * Note that floors (and invisible traps) are the only grids which are
2603 * not memorized when seen, so only these grids need to check to see if
2604 * the grid is "viewable" to the player (if it is not memorized). Since
2605 * most non-memorized grids are in fact walls, this induces *massive*
2606 * efficiency, at the cost of *forcing* the memorization of non-floor
2607 * grids when they are first seen. Note that "invisible traps" are
2608 * always treated exactly like "floors", which prevents "cheating".
2609 *
2610 * Note the "special lighting effects" which can be activated for floor
2611 * grids using the "floor_lighting" option (for "white" floor grids),
2612 * causing certain grids to be displayed using special colors. If the
2613 * player is "blind", we will use "dark gray", else if the grid is lit
2614 * by the torch, and the "view_lamp_lite" option is set, we will use
2615 * "yellow", else if the grid is "dark", we will use "dark gray", else
2616 * if the grid is not "viewable", and the "view_shade_floor" option is
2617 * set, and the we will use "slate" (gray). We will use "white" for all
2618 * other cases, in particular, for illuminated viewable floor grids.
2619 *
2620 * Note the "special lighting effects" which can be activated for wall
2621 * grids using the "wall_lighting" option (for "white" wall grids),
2622 * causing certain grids to be displayed using special colors. If the
2623 * player is "blind", we will use "dark gray", else if the grid is lit
2624 * by the torch, and the "view_lamp_lite" option is set, we will use
2625 * "yellow", else if the "view_shade_floor" option is set, and the grid
2626 * is not "viewable", or is "dark", or is glowing, but not when viewed
2627 * from the player's current location, we will use "slate" (gray). We
2628 * will use "white" for all other cases, in particular, for correctly
2629 * illuminated viewable wall grids.
2630 *
2631 * Note that, when "wall_lighting" is set, we use an inline version
2632 * of the "player_can_see_bold()" function to check the "viewability" of
2633 * grids when the "view_shade_floor" option is set, and we do NOT use
2634 * any special colors for "dark" wall grids, since this would allow the
2635 * player to notice the walls of illuminated rooms from a hallway that
2636 * happened to run beside the room. The alternative, by the way, would
2637 * be to prevent the generation of hallways next to rooms, but this
2638 * would still allow problems when digging towards a room.
2639 *
2640 * Note that bizarre things must be done when the "attr" and/or "char"
2641 * codes have the "high-bit" set, since these values are used to encode
2642 * various "special" pictures in some versions, and certain situations,
2643 * such as "multi-hued" or "clear" monsters, cause the attr/char codes
2644 * to be "scrambled" in various ways.
2645 *
2646 * Note that eventually we may use the "&" symbol for embedded treasure,
2647 * and use the "*" symbol to indicate multiple objects, though this will
2648 * have to wait for Angband 2.8.0 or later. Note that currently, this
2649 * is not important, since only one object or terrain feature is allowed
2650 * in each grid. If needed, "k_info[0]" will hold the "stack" attr/char.
2651 *
2652 * Note the assumption that doing "x_ptr = &x_info[x]" plus a few of
2653 * "x_ptr->xxx", is quicker than "x_info[x].xxx", if this is incorrect
2654 * then a whole lot of code should be changed... XXX XXX
2655 */
2656 void map_info(int Ind, int y, int x, byte *ap, char *cp) {
2657 player_type *p_ptr = Players[Ind];
2658
2659 cave_type *c_ptr;
2660 byte *w_ptr;
2661
2662 feature_type *f_ptr;
2663
2664 int feat;
2665
2666 byte a;
2667 char c;
2668
2669 int a_org;
2670 bool lite_snow, keep = FALSE;
2671
2672 cave_type **zcave;
2673 if (!(zcave = getcave(&p_ptr->wpos))) return;
2674
2675 /* Get the cave */
2676 c_ptr = &zcave[y][x];
2677 w_ptr = &p_ptr->cave_flag[y][x];
2678
2679
2680 /* Feature code */
2681 feat = c_ptr->feat;
2682
2683 #if 0
2684 /* bad hack to display visible wall instead of clear wall in sector00 events */
2685 if (sector00separation &&
2686 *cp == ' ' && feat == FEAT_PERM_CLEAR &&
2687 p_ptr->wpos.wx == WPOS_SECTOR00_X &&
2688 p_ptr->wpos.wy == WPOS_SECTOR00_Y && p_ptr->wpos.wz == 0
2689 && sector00wall) {
2690 if (!p_ptr->font_map_solid_walls) {
2691 *cp = p_ptr->f_char[sector00wall];
2692 a = p_ptr->f_attr[sector00wall];
2693 } else { /* hack */
2694 *cp = p_ptr->f_char_solid[sector00wall];
2695 a = p_ptr->f_attr_solid[sector00wall];
2696 }
2697 }
2698 #else
2699 /* bad hack to display visible wall instead of clear wall in sector00 events */
2700 if (sector00separation &&
2701 feat == FEAT_PERM_CLEAR &&
2702 p_ptr->wpos.wx == WPOS_SECTOR00_X &&
2703 p_ptr->wpos.wy == WPOS_SECTOR00_Y && p_ptr->wpos.wz == 0
2704 && sector00wall)
2705 feat = sector00wall;
2706 #endif
2707
2708 /* Access floor */
2709 f_ptr = &f_info[feat];
2710
2711 /* Floors (etc) */
2712 /* XXX XXX Erm, it is DIRTY. should be replaced soon */
2713 // if (feat <= FEAT_INVIS)
2714 if (f_ptr->flags1 & (FF1_FLOOR)) {
2715
2716 /* Memorized (or visible) floor */
2717 /* Hack -- space are visible to the dungeon master */
2718 if (((*w_ptr & CAVE_MARK) ||
2719 ((((c_ptr->info & CAVE_LITE) &&
2720 (*w_ptr & CAVE_VIEW)) ||
2721 ((c_ptr->info & CAVE_GLOW) &&
2722 (*w_ptr & CAVE_VIEW))) &&
2723 !p_ptr->blind)) || (p_ptr->admin_dm))
2724 {
2725 struct c_special *cs_ptr;
2726
2727 /* for FEAT_ILLUS_WALL, which aren't walls but floors! */
2728 if (!p_ptr->font_map_solid_walls) {
2729 /* Normal char */
2730 (*cp) = p_ptr->f_char[feat];
2731
2732 /* Normal attr */
2733 a = p_ptr->f_attr[feat];
2734 } else { /* hack */
2735 (*cp) = p_ptr->f_char_solid[feat];
2736 a = p_ptr->f_attr_solid[feat];
2737 }
2738
2739 /* Hack to display monster traps */
2740 /* Illusory wall masks everythink */
2741 if ((cs_ptr = GetCS(c_ptr, CS_MON_TRAP)) && c_ptr->feat != FEAT_ILLUS_WALL) {
2742 /* Hack -- random hallucination */
2743 if (p_ptr->image) {
2744 /* image_random(ap, cp); */
2745 image_object(ap, cp);
2746 a = randint(15);
2747 } else {
2748 /* If trap isn't on door display it */
2749 /* if (!(f_ptr->flags1 & FF1_DOOR)) c = '^'; */
2750 // (*cp) = ';';
2751 a = get_monster_trap_color(Ind,
2752 cs_ptr->sc.montrap.trap_kit,
2753 feat);
2754 }
2755 keep = TRUE;
2756 }
2757
2758 /* Hack to display "runes of warding" which are coloured by GF_TYPE */
2759 /* Illusory wall masks everythink */
2760 if ((cs_ptr = GetCS(c_ptr, CS_RUNE)) && c_ptr->feat != FEAT_ILLUS_WALL) {
2761 a = get_rune_color(Ind, cs_ptr->sc.rune.typ);
2762 keep = TRUE;
2763 }
2764
2765 /* Hack to display detected traps */
2766 /* Illusory wall masks everythink */
2767 if ((cs_ptr = GetCS(c_ptr, CS_TRAPS)) && c_ptr->feat != FEAT_ILLUS_WALL) {
2768 int t_idx = cs_ptr->sc.trap.t_idx;
2769 if (cs_ptr->sc.trap.found) {
2770 /* Hack -- random hallucination */
2771 if (p_ptr->image) {
2772 /* image_random(ap, cp); */
2773 image_object(ap, cp);
2774 a = randint(15);
2775 } else {
2776 /* If trap isn't on door display it */
2777 /* if (!(f_ptr->flags1 & FF1_DOOR)) c = '^'; */
2778 (*cp) = '^';
2779
2780 a = get_trap_color(Ind, t_idx, feat);
2781 }
2782 keep = TRUE;
2783 }
2784 }
2785
2786 /* Quick Hack -- shop */
2787 if ((cs_ptr = GetCS(c_ptr, CS_SHOP))) {
2788 (*cp) = st_info[cs_ptr->sc.omni].d_char;
2789 a = st_info[cs_ptr->sc.omni].d_attr;
2790
2791 a = manipulate_cave_colour(c_ptr, &p_ptr->wpos, x, y, a);
2792 }
2793
2794 /* apply colour to OPEN house doors (which have FF1_FLOOR,
2795 are hence separated from close house doors - C. Blue */
2796 else if ((cs_ptr = GetCS(c_ptr, CS_DNADOOR))) {
2797 a = access_door_colour(Ind, cs_ptr->sc.ptr);
2798
2799 a = manipulate_cave_colour(c_ptr, &p_ptr->wpos, x, y, a);
2800 }
2801
2802 /* don't apply special lighting/shading on traps/montraps/runes! */
2803 else if (keep) {
2804 /* nothing */
2805 }
2806
2807 /* Special lighting effects */
2808 else if (p_ptr->floor_lighting &&
2809 (a_org = manipulate_cave_colour_season(c_ptr, &p_ptr->wpos, x, y, a)) != -1 && /* dummy */
2810 ((lite_snow = ((f_ptr->flags2 & FF2_LAMP_LITE_SNOW) && /* dirty snow and clean slow */
2811 (a_org == TERM_WHITE || a_org == TERM_L_WHITE))) ||
2812 (f_ptr->flags2 & (FF2_LAMP_LITE | FF2_SPECIAL_LITE)) ||
2813 ((f_ptr->flags2 & FF2_LAMP_LITE_OPTIONAL) && p_ptr->view_lite_extra))) {
2814 a = manipulate_cave_colour_daytime(c_ptr, &p_ptr->wpos, x, y, a_org);
2815
2816 /* Handle "blind" */
2817 if (p_ptr->blind) {
2818 /* Use "dark gray" */
2819 a = TERM_L_DARK;
2820 }
2821
2822 /* Handle "torch-lit" grids */
2823 else if (((f_ptr->flags2 & FF2_LAMP_LITE) ||
2824 ((f_ptr->flags2 & FF2_LAMP_LITE_OPTIONAL) && p_ptr->view_lite_extra) ||
2825 lite_snow) &&
2826 ((c_ptr->info & CAVE_LITE) && (*w_ptr & CAVE_VIEW))) {
2827 /* Torch lite */
2828 if (p_ptr->view_lamp_floor) {
2829 #ifdef CAVE_LITE_COLOURS
2830 if ((c_ptr->info & CAVE_LITE_WHITE)) {
2831 if (!(f_ptr->flags2 & FF2_NO_LITE_WHITEN)) a = (a == TERM_L_DARK) ? TERM_SLATE ://<-specialty for ash
2832 TERM_WHITE;//normal
2833 } else if ((c_ptr->info & CAVE_LITE_VAMP)) {
2834 if (!(f_ptr->flags2 & FF2_NO_LITE_WHITEN)) a = (a == TERM_L_DARK) ? TERM_SLATE ://<-specialty for ash
2835 TERM_WHITE; /* usual glowing floor grids are TERM_WHITE, so lamp light shouldn't be darker (TERM_L_WHITE).. */
2836 } else if (is_newer_than(&p_ptr->version, 4, 5, 2, 0, 0, 0) && p_ptr->view_animated_lite) {
2837 if (is_newer_than(&p_ptr->version, 4, 5, 7, 2, 0, 0)) a = (a == TERM_L_DARK) ? TERM_LAMP_DARK : TERM_LAMP;//<-specialty: shaded ash
2838 else a = (a == TERM_L_DARK) ? TERM_UMBER : TERM_LAMP;//<-specialty: shaded ash
2839 }
2840 else a = (a == TERM_L_DARK) ? TERM_UMBER : TERM_YELLOW;//<-specialty: shaded ash
2841 #else
2842 a = TERM_YELLOW;
2843 #endif
2844 }
2845 }
2846
2847 /* Special flag */
2848 if (p_ptr->view_shade_floor
2849 #ifndef SHADE_ALL_FLOOR
2850 && (!(f_ptr->flags2 & FF2_NO_SHADE) || lite_snow)
2851 #endif
2852 ) {
2853 /* Handle "dark" grids */
2854 if (!(c_ptr->info & (CAVE_GLOW | CAVE_LITE))) {
2855 /* Use "dark gray" */
2856 if (a != TERM_DARK) //<-hack: don't accidentally lighten up naturally-dark grids
2857 a = TERM_L_DARK;
2858 }
2859 /* Handle "out-of-sight" grids */
2860 else if (!(*w_ptr & CAVE_VIEW)) {
2861 #ifndef SHADE_ALL_FLOOR
2862 /* Use "gray" */
2863 if (a != TERM_DARK && a != TERM_L_DARK) //<-hack: don't accidentally lighten up naturally-dark grids (FEAT_ASH)
2864 a = TERM_SLATE;
2865 #else
2866 if (p_ptr->wpos.wz || !night_surface) /* not already shaded in m.c.c.daytime() above? */
2867 a = manipulate_cave_colour_shade(c_ptr, &p_ptr->wpos, x, y, a);
2868 #endif
2869 }
2870 }
2871 }
2872 else a = manipulate_cave_colour(c_ptr, &p_ptr->wpos, x, y, a);
2873
2874 /* The attr */
2875 (*ap) = a;
2876 }
2877
2878 /* Unknown */
2879 else {
2880 /* Access darkness */
2881 f_ptr = &f_info[FEAT_NONE];
2882
2883 /* Normal attr */
2884 /* (*ap) = f_ptr->f_attr; */
2885 (*ap) = p_ptr->f_attr[FEAT_NONE];
2886
2887 /* Normal char */
2888 /* (*cp) = f_ptr->f_char; */
2889 (*cp) = p_ptr->f_char[FEAT_NONE];
2890 }
2891 }
2892
2893 /* Non floors */
2894 else {
2895 /* Memorized grids */
2896 /* Hack -- everything is visible to dungeon masters */
2897 if ((*w_ptr & CAVE_MARK) || (p_ptr->admin_dm)) {
2898 struct c_special *cs_ptr;
2899
2900 /* Apply "mimic" field */
2901 //feat = f_info[feat].mimic;
2902
2903 /* Hack -- hide the secret door */
2904 //if (feat == FEAT_SECRET && (cs_ptr = GetCS(c_ptr, CS_MIMIC)))
2905 if ((cs_ptr = GetCS(c_ptr, CS_MIMIC))) {
2906 feat = cs_ptr->sc.omni;
2907 } else {
2908 /* Apply "mimic" field */
2909 feat = f_info[feat].mimic;
2910 }
2911
2912 /* Access feature */
2913 f_ptr = &f_info[feat];
2914
2915 if (!p_ptr->font_map_solid_walls) {
2916 /* Normal char */
2917 /* (*cp) = f_ptr->f_char; */
2918 (*cp) = p_ptr->f_char[feat];
2919
2920 /* Normal attr */
2921 /* a = f_ptr->f_attr; */
2922 a = p_ptr->f_attr[feat];
2923 } else { /* hack */
2924 (*cp) = p_ptr->f_char_solid[feat];
2925 a = p_ptr->f_attr_solid[feat];
2926 }
2927
2928
2929 /* Add trap color - Illusory wall masks everythink */
2930 /* Hack to display detected traps */
2931 /*
2932 if ((c_ptr->t_idx != 0) && (c_ptr->info & CAVE_TRDT) &&
2933 (c_ptr->feat != FEAT_ILLUS_WALL))
2934 if ((c_ptr->special.type == CS_TRAPS) && (c_ptr->special.sc.ptr->found))
2935 */
2936 /* Hack to display detected traps */
2937 if ((cs_ptr = GetCS(c_ptr, CS_TRAPS)) && c_ptr->feat != FEAT_ILLUS_WALL) {
2938 int t_idx = cs_ptr->sc.trap.t_idx;
2939 if (cs_ptr->sc.trap.found) {
2940 /* Hack -- random hallucination */
2941 if (p_ptr->image) {
2942 image_object(ap, cp);
2943 a = randint(15);
2944 } else {
2945 a = get_trap_color(Ind, t_idx, feat);
2946 }
2947 keep = TRUE;
2948 }
2949 }
2950 /* Hack -- gee it's great to be back home */
2951 if ((cs_ptr = GetCS(c_ptr, CS_DNADOOR))) {
2952 #if 0
2953 if (access_door(Ind, cs_ptr->sc.ptr, FALSE)) {
2954 a = TERM_L_GREEN;
2955 } else {
2956 struct dna_type *dna = cs_ptr->sc.ptr;
2957 if (dna->owner && dna->owner_type)
2958 a = TERM_L_DARK;
2959 }
2960 #else
2961 a = access_door_colour(Ind, cs_ptr->sc.ptr);
2962 #endif
2963 keep = TRUE;
2964 }
2965
2966 /* don't apply special lighting/shading on traps in 'walls' (secret doors) or closed doors */
2967 if (keep) {
2968 /* nothing */
2969 }
2970
2971 /* Special lighting effects */
2972 else if (p_ptr->wall_lighting &&
2973 (a_org = manipulate_cave_colour_season(c_ptr, &p_ptr->wpos, x, y, a)) != -1 && /* dummy */
2974 ((lite_snow = ((f_ptr->flags2 & FF2_LAMP_LITE_SNOW) && /* dirty snow and clean slow */
2975 (a_org == TERM_WHITE || a_org == TERM_L_WHITE))) ||
2976 (f_ptr->flags2 & (FF2_LAMP_LITE | FF2_SPECIAL_LITE)) ||
2977 ((f_ptr->flags2 & FF2_LAMP_LITE_OPTIONAL) && p_ptr->view_lite_extra))) {
2978 a = manipulate_cave_colour_daytime(c_ptr, &p_ptr->wpos, x, y, a_org);
2979
2980 /* Handle "blind" */
2981 if (p_ptr->blind) {
2982 /* Use "dark gray" */
2983 a = TERM_L_DARK;
2984 }
2985
2986 /* Handle "torch-lit" grids */
2987 else if (((f_ptr->flags2 & FF2_LAMP_LITE) ||
2988 ((f_ptr->flags2 & FF2_LAMP_LITE_OPTIONAL) && p_ptr->view_lite_extra) ||
2989 lite_snow) &&
2990 (c_ptr->info & CAVE_LITE)) {
2991 /* Torch lite */
2992 if (p_ptr->view_lamp_walls) {
2993 #ifdef CAVE_LITE_COLOURS
2994 if ((c_ptr->info & CAVE_LITE_WHITE)) {
2995 if (!(f_ptr->flags2 & FF2_NO_LITE_WHITEN) && a != TERM_WHITE) //don't darken max white
2996 a = (a == TERM_L_DARK) ? TERM_SLATE ://<-specialty for magma vein/volcanic rock
2997 TERM_L_WHITE; /* for now: instead of TERM_WHITE; to distinguish lit granite from permanent walls */
2998 } else if ((c_ptr->info & CAVE_LITE_VAMP)) {
2999 //if (!(f_ptr->flags2 & FF2_NO_LITE_WHITEN)) a = TERM_SLATE; /* to make a difference to TERM_L_WHITE; for the time being (see above) */
3000 if (!(f_ptr->flags2 & FF2_NO_LITE_WHITEN) && a != TERM_WHITE) //don't darken max white
3001 a = (a == TERM_L_DARK) ? TERM_SLATE ://<-specialty for magma vein
3002 TERM_L_WHITE; /* TERM_SLATE just looks too weird */
3003 } else if (is_newer_than(&p_ptr->version, 4, 5, 2, 0, 0, 0) && p_ptr->view_animated_lite) {
3004 if (is_newer_than(&p_ptr->version, 4, 5, 7, 2, 0, 0)) a = (a == TERM_L_DARK) ? TERM_LAMP_DARK : TERM_LAMP;//<-specialty: shaded magma vein
3005 else a = TERM_LAMP;//(a == TERM_L_DARK) ? TERM_L_UMBER : TERM_LAMP;//<-specialty: shaded magma vein
3006 }
3007 else a = (a == TERM_L_DARK) ? TERM_L_UMBER : TERM_YELLOW;//<-specialty: shaded magma vein
3008 #else
3009 a = TERM_YELLOW;
3010 #endif
3011 }
3012 }
3013
3014 /* Handle "view_shade_walls" */
3015 /* NOTE: The only prob here is that if magma doesn't have a different
3016 symbol from granite walls, for example if the player maps
3017 both to 'solid block' character, shaded granite walls and
3018 magma veins will look the same - C. Blue */
3019 //else if (p_ptr->view_shade_walls && !(f_ptr->flags2 & FF2_NO_SHADE)) {
3020 else if (p_ptr->view_shade_walls && (!(f_ptr->flags2 & FF2_NO_SHADE) || lite_snow)) {
3021 /* Not glowing */
3022 if (!(c_ptr->info & (CAVE_GLOW | CAVE_LITE))) {
3023 /* Allow distinguishing permanent walls from granite */
3024 if (a_org != TERM_WHITE) {
3025 if (a_org == TERM_L_WHITE) a = TERM_SLATE;
3026 else a = TERM_L_DARK;
3027 }
3028 /* don't "brighten up" if it was darkened by night */
3029 else if (a == TERM_WHITE) a = TERM_L_WHITE;
3030 }
3031 /* Not viewable */
3032 else if (!(*w_ptr & CAVE_VIEW)
3033 #ifdef DONT_SHADE_GLOW_AT_NIGHT
3034 && !(night_surface && !p_ptr->wpos.wz)
3035 #endif
3036 ) {
3037 /* Allow distinguishing permanent walls from granite */
3038 if (a_org != TERM_WHITE) {
3039 if (a_org == TERM_L_WHITE) a = TERM_SLATE;
3040 else a = TERM_L_DARK;
3041 }
3042 /* don't "brighten up" if it was darkened by night */
3043 else if (a == TERM_WHITE) a = TERM_L_WHITE;
3044 }
3045
3046 #if 0 /* anyone know what the idea for this is? It causes a visual glitch, so disabling it for now */
3047 /* Not glowing correctly */
3048 else {
3049 int xx, yy;
3050
3051 /* Hack -- move towards player */
3052 yy = (y < p_ptr->py) ? (y + 1) : (y > p_ptr->py) ? (y - 1) : y;
3053 xx = (x < p_ptr->px) ? (x + 1) : (x > p_ptr->px) ? (x - 1) : x;
3054
3055 /* Check for "local" illumination */
3056 if (!(zcave[yy][xx].info & CAVE_GLOW)) {
3057 /* Use "gray" */
3058 a = TERM_SLATE;
3059 }
3060 }
3061 #endif
3062 }
3063 }
3064 else a = manipulate_cave_colour(c_ptr, &p_ptr->wpos, x, y, a);
3065
3066 /* The attr */
3067 (*ap) = a;
3068
3069 for (cs_ptr = c_ptr->special; cs_ptr; cs_ptr = cs_ptr->next) {
3070 /* testing only - need c/a PRIORITIES!!! */
3071 csfunc[cs_ptr->type].see(cs_ptr, cp, ap, Ind);
3072 }
3073 }
3074
3075 /* Unknown */
3076 else {
3077 /* Access darkness */
3078 f_ptr = &f_info[FEAT_NONE];
3079
3080 /* Normal attr */
3081 /* (*ap) = f_ptr->f_attr; */
3082 (*ap) = p_ptr->f_attr[FEAT_NONE];
3083
3084 /* Normal char */
3085 /* (*cp) = f_ptr->f_char; */
3086 (*cp) = p_ptr->f_char[FEAT_NONE];
3087 }
3088 }
3089
3090
3091 /**** Apply special random effects ****/
3092 /* if (!avoid_other) */
3093 if (((*w_ptr & CAVE_MARK) ||
3094 ((((c_ptr->info & CAVE_LITE) && (*w_ptr & CAVE_VIEW)) ||
3095 ((c_ptr->info & CAVE_GLOW) && (*w_ptr & CAVE_VIEW))) &&
3096 !p_ptr->blind)) || (p_ptr->admin_dm))
3097 {
3098 f_ptr = &f_info[feat];
3099
3100 /* Special terrain effect */
3101 if (c_ptr->effect) {
3102 #if 0
3103 (*ap) = spell_color(effects[c_ptr->effect].type);
3104 #else /* allow 'transparent' spells */
3105 a = spell_color(effects[c_ptr->effect].type);
3106 if (a != 127) (*ap) = a;
3107 #endif
3108 }
3109
3110 #if 1
3111 /* Multi-hued attr */
3112 /* TODO: this should be done in client-side too, so that
3113 * they shimmer when player isn't moving */
3114 else if (f_ptr->flags1 & FF1_ATTR_MULTI) {
3115 a = f_ptr->shimmer[rand_int(7)];
3116
3117 if (rand_int(8) != 1)
3118 a = manipulate_cave_colour(c_ptr, &p_ptr->wpos, x, y, a);
3119
3120 (*ap) = a;
3121 }
3122 #if 1
3123 /* Give staircases different colours depending on dungeon flags -C. Blue :) */
3124 if ((c_ptr->feat == FEAT_MORE) || (c_ptr->feat == FEAT_WAY_MORE) ||
3125 (c_ptr->feat == FEAT_WAY_LESS) || (c_ptr->feat == FEAT_LESS)) {
3126 struct dungeon_type *d_ptr;
3127 worldpos *tpos = &p_ptr->wpos;
3128 wilderness_type *wild = &wild_info[tpos->wy][tpos->wx];
3129
3130 if (!tpos->wz) {
3131 if ((c_ptr->feat == FEAT_MORE) || (c_ptr->feat == FEAT_WAY_MORE)) d_ptr = wild->dungeon;
3132 else d_ptr = wild->tower;
3133 } else if (tpos->wz < 0) d_ptr = wild->dungeon;
3134 else d_ptr = wild->tower;
3135
3136 /* Check for empty staircase without any connected dungeon/tower! */
3137 if (!d_ptr) {
3138 (*ap) = TERM_SLATE;
3139 } else {
3140 /* override colour from easiest to worst */
3141 get_staircase_colour(d_ptr, ap);
3142 }
3143 }
3144 #endif
3145
3146 #ifdef HOUSE_PAINTING
3147 if (c_ptr->feat == FEAT_WALL_HOUSE && c_ptr->colour) {
3148 #ifdef HOUSE_PAINTING_HIDE_BAD_MODE
3149 if (is_admin(p_ptr)) {
3150 if (c_ptr->colour > 100) (*ap) = c_ptr->colour - 100 - 1;
3151 else (*ap) = c_ptr->colour - 1;
3152 } else if (c_ptr->colour > 100) {
3153 if ((p_ptr->mode & MODE_EVERLASTING)) (*ap) = c_ptr->colour - 100 - 1;
3154 } else {
3155 if (!(p_ptr->mode & MODE_EVERLASTING)) (*ap) = c_ptr->colour - 1;
3156 }
3157 #else
3158 if (c_ptr->colour > 100) (*ap) = c_ptr->colour - 100 - 1;
3159 else (*ap) = c_ptr->colour - 1;
3160 #endif
3161 }
3162 #endif
3163
3164 /* jails */
3165 if (c_ptr->info & CAVE_JAIL) (*ap) = TERM_L_DARK;
3166
3167 #endif
3168 }
3169
3170 /* Hack -- rare random hallucination, except on outer dungeon walls */
3171 if (p_ptr->image && (!rand_int(256)) && !(f_info[c_ptr->feat].flags2 & FF2_BOUNDARY)) {
3172 /* Hallucinate */
3173 image_random(ap, cp);
3174 }
3175
3176
3177 /* Objects */
3178 if (c_ptr->o_idx
3179 #ifdef FIX_NOTHINGS_ON_SIGHT
3180 && !nothing_test(&o_list[c_ptr->o_idx], p_ptr, &p_ptr->wpos, x, y, 5)
3181 #endif
3182 ) {
3183 struct c_special *cs_ptr;
3184
3185 /* Hack - Traps override objects while searching - mikaelh */
3186 if (!p_ptr->searching || !((cs_ptr = GetCS(c_ptr, CS_TRAPS)) && cs_ptr->sc.trap.found)) {
3187 /* Get the actual item */
3188 object_type *o_ptr = &o_list[c_ptr->o_idx];
3189
3190 /* Memorized objects */
3191 /* Hack -- the dungeon master knows where everything is */
3192 if ((p_ptr->obj_vis[c_ptr->o_idx]) || (p_ptr->admin_dm)) {
3193 /* Normal char */
3194 (*cp) = object_char(o_ptr);
3195
3196 /* Normal attr */
3197 (*ap) = object_attr(o_ptr);
3198
3199 /* Hack -- always l.blue if underwater */
3200 // if (feat == FEAT_WATER)
3201 if (feat == FEAT_DEEP_WATER || feat == FEAT_SHAL_WATER)
3202 (*ap) = TERM_L_BLUE;
3203
3204 /* hacks: mindcrafter 'crystals' are yellow, custom books' colour depends on their content! - C. Blue */
3205 if (o_ptr->tval == TV_BOOK) {
3206 if (o_ptr->pval >= __lua_M_FIRST && o_ptr->pval <= __lua_M_LAST)
3207 (*ap) = TERM_YELLOW;
3208 else if (is_custom_tome(o_ptr->sval))
3209 (*ap) = get_book_name_color(Ind, o_ptr);
3210 }
3211
3212 /* hack: colour of fancy shirts or custom objects can vary */
3213 if ((o_ptr->tval == TV_SOFT_ARMOR && o_ptr->sval == SV_SHIRT) ||
3214 (o_ptr->tval == TV_SPECIAL && o_ptr->sval == SV_CUSTOM_OBJECT)) {
3215 if (!o_ptr->xtra1) o_ptr->xtra1 = (*ap); //wut.. remove this hack? should be superfluous anyway
3216 (*ap) = o_ptr->xtra1;
3217 /* new: also allow custom char */
3218 if (o_ptr->xtra2) (*cp) = o_ptr->xtra2;
3219 }
3220
3221 /* quest items can have custom appearance too */
3222 if (o_ptr->tval == TV_SPECIAL && o_ptr->sval == SV_QUEST) {
3223 (*cp) = o_ptr->xtra1;
3224 (*ap) = o_ptr->xtra2;
3225 }
3226
3227 /* Abnormal attr */
3228 /* if ((!avoid_other) && (!(((*ap) & 0x80) && ((*cp) & 0x80))) && (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI)) (*ap) = get_shimmer_color(); */
3229 if (k_info[o_ptr->k_idx].flags5 & TR5_ATTR_MULTI)
3230 #ifdef CLIENT_SHIMMER
3231 (*ap) = TERM_HALF;
3232 #else
3233 (*ap) = get_shimmer_color();
3234 #endif
3235 /* (*ap) = randint(15); */
3236
3237 /* hack: questors may have specific attr */
3238 if (o_ptr->questor) (*ap) = q_info[o_ptr->quest - 1].questor[o_ptr->questor_idx].oattr;
3239
3240 /* Hack -- hallucination */
3241 if (p_ptr->image) image_object(ap, cp);
3242 }
3243 }
3244 }
3245
3246
3247 /* Handle monsters */
3248 if (c_ptr->m_idx > 0) {
3249 monster_type *m_ptr = &m_list[c_ptr->m_idx];
3250
3251 if (c_ptr->m_idx >= m_max) {
3252 /* Clear invalid monster references - mikaelh */
3253
3254 /* Log it */
3255 s_printf("MIDX_FIX: Cleared an invalid monster reference (m_idx = %d, m_max = %d) (wpos = %d, %d, %d) (x = %d, y = %d)\n", c_ptr->m_idx, m_max, p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz, x, y);
3256
3257 c_ptr->m_idx = 0;
3258 }
3259
3260 /* Visible monster */
3261 if (p_ptr->mon_vis[c_ptr->m_idx]) {
3262 monster_race *r_ptr = race_inf(m_ptr);
3263
3264 /* hack: mindcrafters/rogues can see through
3265 shadowing (shadowed ego) / cloaking (master thief ego) */
3266 if ((p_ptr->pclass == CLASS_MINDCRAFTER || p_ptr->pclass == CLASS_ROGUE) && p_ptr->lev >= 30 &&
3267 #if 0 /* this works, but maybe let's be more specific, in case some exceptional new re-power gets added that shouldn't be affected.. */
3268 (r_ptr->flags1 & RF1_CHAR_CLEAR) && (r_ptr->flags1 & RF1_ATTR_CLEAR) &&
3269 !(r_info[m_ptr->r_idx].flags1 & (RF1_CHAR_CLEAR | RF1_ATTR_CLEAR)))
3270 #else
3271 (m_ptr->ego == RE_MASTER_THIEF || m_ptr->ego == RE_SHADOWED))
3272 #endif
3273 /* slightly paranoid: we only remove the flags that REALLY weren't
3274 in the base version.. such cases shouldn't really occur though */
3275 r_ptr->flags1 &= ~((r_ptr->flags1 & RF1_CHAR_CLEAR) | (r_ptr->flags1 & RF1_ATTR_CLEAR));
3276
3277 get_monster_color(Ind, m_ptr, r_ptr, c_ptr, ap, cp);
3278 }
3279 }
3280
3281 /* -APD-
3282 Taking D. Gandy's advice and making it display the char as a number if
3283 they are severly wounded (60% health or less)
3284 I multiply by 95 instead of 100 because it always rounds down.....
3285 and I want to give PCs a little more breathing room.
3286 */
3287
3288 else if (c_ptr->m_idx < 0) {
3289 int Ind2 = 0 - c_ptr->m_idx;
3290 player_type *p2_ptr = Players[Ind2];
3291
3292 if (!p2_ptr) {
3293 /* Clear invalid players, I'm tired of crashes - mikaelh */
3294 c_ptr->m_idx = 0;
3295
3296 /* Log it */
3297 s_printf("MIDX_FIX: Cleared an invalid player m_idx (Ind = %d) (wpos = %d, %d, %d) (x = %d, y = %d)\n", Ind2, p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz, x, y);
3298 }
3299
3300 /* Check for doppelgangers - mikaelh */
3301 else if (memcmp(&p_ptr->wpos, &p2_ptr->wpos, sizeof(struct worldpos)) != 0 || x != p2_ptr->px || y != p2_ptr->py) {
3302 /* Clear doppelgangers */
3303 c_ptr->m_idx = 0;
3304
3305 /* Log it */
3306 s_printf("MIDX_FIX: Cleared a doppelganger (Ind = %d, \"%s\") (wpos = %d, %d, %d) (x = %d, y = %d)\n", Ind2, Players[Ind2]->name, p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz, x, y);
3307 }
3308
3309 /* Is that player visible? */
3310 else if (p_ptr->play_vis[Ind2]) {
3311 /* part 'A' now here (experimental, see below) */
3312
3313 /* Hack: For monster-forms, player_color() calls get_monster_color() which will
3314 result in color flickering if player is hallucinating, although this call
3315 should instead determine the colour an _outside_ player gets to see. So we
3316 have to temporarily suppress his hallucinations to get the correct value. */
3317 int tmp_image = p2_ptr->image;
3318 p2_ptr->image = 0;
3319 a = player_color(Ind2);
3320 p2_ptr->image = tmp_image;
3321
3322 #if 0 /* player_color() should already handle all of this - C. Blue */
3323 if ((p2_ptr->inventory[INVEN_BODY].tval == TV_SOFT_ARMOR) && (p2_ptr->inventory[INVEN_BODY].sval == SV_COSTUME)) {
3324 get_monster_color(Ind, NULL, &r_info[p2_ptr->inventory[INVEN_BODY].bpval], c_ptr, &a, &c);
3325 }
3326 else if (p2_ptr->body_monster) get_monster_color(Ind, NULL, &r_info[p2_ptr->body_monster], c_ptr, &a, &c);
3327 else if (p2_ptr->fruit_bat) c = 'b';
3328 else c = '@';
3329 #else
3330 if ((p2_ptr->inventory[INVEN_BODY].tval == TV_SOFT_ARMOR) && (p2_ptr->inventory[INVEN_BODY].sval == SV_COSTUME)) {
3331 c = r_info[p2_ptr->inventory[INVEN_BODY].bpval].d_char;
3332 }
3333 else if (p2_ptr->body_monster) {
3334 c = r_info[p2_ptr->body_monster].d_char;
3335 #if 1 /* just for fun */
3336 if (p2_ptr->body_monster == RI_DOOR_MIMIC && p2_ptr->dummy_option_7) c = '\'';
3337 #endif
3338 }
3339 else if (p2_ptr->fruit_bat) c = 'b';
3340 else c = '@';
3341
3342 #endif
3343 /* Always show party members as dark grey @. Allow pvp flickers still */
3344 if (p_ptr->consistent_players) {
3345 c = '@';
3346 a = TERM_L_DARK;
3347 if (p_ptr->black_breath && magik(50)) {
3348 a = TERM_SLATE;
3349 }
3350 }
3351
3352 /* part 'A' end */
3353
3354 /* TERM_BNW if blood bonded - mikaelh */
3355 if (check_blood_bond(Ind, Ind2))
3356 #ifdef EXTENDED_TERM_COLOURS
3357 a |= is_older_than(&p_ptr->version, 4, 5, 1, 2, 0, 0) ? TERM_OLD_BNW : TERM_BNW;
3358 #else
3359 a |= TERM_BNW;
3360 #endif
3361 /* new: renamed TERM_RLE (unused) to TERM_PVP for use for this: - C. Blue */
3362 else if (is_newer_than(&p_ptr->version, 4, 4, 2, 0, 0, 0) &&
3363 (check_hostile(Ind, Ind2) || p2_ptr->stormbringer))
3364 #ifdef EXTENDED_TERM_COLOURS
3365 a |= is_older_than(&p_ptr->version, 4, 5, 1, 2, 0, 0) ? TERM_OLD_PVP : TERM_PVP;
3366 #else
3367 a |= TERM_PVP;
3368 #endif
3369
3370 if (((p2_ptr->chp * 95) / (p2_ptr->mhp * 10)) > TURN_CHAR_INTO_NUMBER) {
3371 /* part 'A' used to be here */
3372 } else {
3373 if (p2_ptr->chp < 0) c = '-';
3374 else {
3375 int num;
3376 num = (p2_ptr->chp * 95) / (p2_ptr->mhp * 10);
3377 c = '0' + num;
3378 }
3379 }
3380
3381 /* admins sees intensity of mana shields */
3382 if (p_ptr->admin_dm && p2_ptr->tim_manashield && p2_ptr->msp > 0) {
3383 if (((p2_ptr->csp * 100) / (p2_ptr->msp * 10)) < 10) {
3384 int num;
3385 num = (p2_ptr->csp * 100) / (p2_ptr->msp * 10);
3386 c = '0' + num;
3387 }
3388 }
3389
3390 (*cp) = c;
3391 (*ap) = a;
3392
3393 if (p_ptr->image) {
3394 /* Change the other player into a hallucination */
3395 image_monster(ap, cp);
3396 }
3397 }
3398 }
3399
3400
3401 if (!c_ptr->effect) return;
3402
3403 /* display blue raindrops */
3404 if ((effects[c_ptr->effect].flags & EFF_RAINING)) {
3405 (*ap) = TERM_BLUE;
3406 if (wind_gust > 0) (*cp) = '/';
3407 else if (wind_gust < 0) (*cp) = '\\';
3408 else (*cp) = '|';
3409 }
3410 /* for WINTER_SEASON */
3411 /* display white snowflakes */
3412 if ((effects[c_ptr->effect].flags & EFF_SNOWING)) {
3413 (*ap) = TERM_WHITE;
3414 (*cp) = '*'; /* a little bit large maybe, but '.' won't be noticed on the other hand? */
3415 }
3416 /* for NEW_YEARS_EVE */
3417 /* display fireworks */
3418 if ((effects[c_ptr->effect].flags & (EFF_FIREWORKS1 | EFF_FIREWORKS2 | EFF_FIREWORKS3))) {
3419 switch (effects[c_ptr->effect].type) {
3420 case GF_FW_FIRE: (*ap) = TERM_FIRE; break;
3421 case GF_FW_ELEC: (*ap) = TERM_ELEC; break;
3422 case GF_FW_POIS: (*ap) = TERM_POIS; break;
3423 case GF_FW_LITE: (*ap) = TERM_LITE; break;
3424 case GF_FW_SHDI: (*ap) = TERM_SHIELDI; break;
3425 case GF_FW_SHDM: (*ap) = TERM_SHIELDM; break;
3426 case GF_FW_MULT: (*ap) = TERM_MULTI; break;
3427 }
3428 (*cp) = '*'; /* a little bit large maybe, but '.' won't be noticed on the other hand? */
3429 }
3430 /* for Nether Realm finishing */
3431 if ((effects[c_ptr->effect].flags & (EFF_LIGHTNING1 | EFF_LIGHTNING2 | EFF_LIGHTNING3))) {
3432 (*ap) = TERM_LITE;
3433 switch (c_ptr->effect_xtra) {
3434 case 0: (*cp) = '|'; break;
3435 case 1: (*cp) = '/'; break;
3436 case -1: (*cp) = '\\'; break;
3437 case 2: (*cp) = '_'; break;
3438 default: (*cp) = '*';
3439 }
3440 }
3441
3442 /* #ifdef ARCADE_SERVER
3443 if ((effects[c_ptr->effect].flags & EFF_CROSSHAIR_A) || (effects[c_ptr->effect].flags & EFF_CROSSHAIR_B) || (effects[c_ptr->effect].flags & EFF_CROSSHAIR_C))
3444 {
3445 (*ap) = TERM_L_UMBER;
3446 (*cp) = '+';
3447 }
3448 #endif */
3449 }
3450
3451
3452 /*
3453 * Memorize the given grid (or object) if it is "interesting"
3454 *
3455 * This function should only be called on "legal" grids.
3456 *
3457 * This function should be called every time the "memorization" of
3458 * a grid (or the object in a grid) is called into question.
3459 *
3460 * Note that the player always memorized all "objects" which are seen,
3461 * using a different method than the one used for terrain features,
3462 * which not only allows a lot of optimization, but also prevents the
3463 * player from "knowing" when objects are dropped out of sight but in
3464 * memorized grids.
3465 *
3466 * Note that the player always memorizes "interesting" terrain features
3467 * (everything but floors and invisible traps). This allows incredible
3468 * amounts of optimization in various places.
3469 *
3470 * Note that the player is allowed to memorize floors and invisible
3471 * traps under various circumstances, and with various options set.
3472 *
3473 * This function is slightly non-optimal, since it memorizes objects
3474 * and terrain features separately, though both are dependant on the
3475 * "player_can_see_bold()" macro.
3476 */
3477 void note_spot(int Ind, int y, int x)
3478 {
3479 player_type *p_ptr = Players[Ind];
3480 byte *w_ptr = &p_ptr->cave_flag[y][x];
3481
3482 cave_type **zcave;
3483 cave_type *c_ptr;
3484 if (!(zcave = getcave(&p_ptr->wpos))) return;
3485 c_ptr = &zcave[y][x];
3486
3487 /* Hack -- memorize objects */
3488 if (c_ptr->o_idx) {
3489 /* Only memorize once */
3490 if (!(p_ptr->obj_vis[c_ptr->o_idx])) {
3491 /* Memorize visible objects */
3492 if (player_can_see_bold(Ind, y, x)) {
3493 /* Memorize */
3494 p_ptr->obj_vis[c_ptr->o_idx] = TRUE;
3495
3496 }
3497 }
3498 }
3499
3500
3501 /* Hack -- memorize grids */
3502 if (!(*w_ptr & CAVE_MARK)) {
3503 /* Memorize visible grids */
3504 if (player_can_see_bold(Ind, y, x)) {
3505 /* Memorize normal features */
3506 if (!cave_plain_floor_grid(c_ptr)) {
3507 /* Memorize */
3508 *w_ptr |= CAVE_MARK;
3509 }
3510
3511 /* Option -- memorize all perma-lit floors */
3512 else if (p_ptr->view_perma_grids && (c_ptr->info & CAVE_GLOW)) {
3513 /* Memorize */
3514 *w_ptr |= CAVE_MARK;
3515 }
3516
3517 /* Option -- memorize all torch-lit floors */
3518 else if (p_ptr->view_torch_grids && (c_ptr->info & CAVE_LITE)) {
3519 /* Memorize */
3520 *w_ptr |= CAVE_MARK;
3521 }
3522 }
3523 }
3524 }
3525
3526
3527 void note_spot_depth(struct worldpos *wpos, int y, int x)
3528 {
3529 int i;
3530
3531 for (i = 1; i < NumPlayers + 1; i++)
3532 {
3533 if (Players[i]->conn == NOT_CONNECTED)
3534 continue;
3535
3536 if (inarea(wpos, &Players[i]->wpos))
3537 {
3538 note_spot(i, y, x);
3539 }
3540 }
3541 }
3542
3543 void everyone_lite_spot(struct worldpos *wpos, int y, int x)
3544 {
3545 int i;
3546
3547 /* Check everyone */
3548 for (i = 1; i < NumPlayers + 1; i++)
3549 {
3550 /* If he's not playing, skip him */
3551 if (Players[i]->conn == NOT_CONNECTED)
3552 continue;
3553
3554 /* If he's not here, skip him */
3555 if (!inarea(wpos, &Players[i]->wpos))
3556 continue;
3557
3558 /* Actually lite that spot for that player */
3559 lite_spot(i, y, x);
3560 }
3561 }
3562
3563 void everyone_clear_ovl_spot(struct worldpos *wpos, int y, int x)
3564 {
3565 int i;
3566
3567 /* Check everyone */
3568 for (i = 1; i < NumPlayers + 1; i++) {
3569 /* If he's not playing, skip him */
3570 if (Players[i]->conn == NOT_CONNECTED)
3571 continue;
3572
3573 /* If he's not here, skip him */
3574 if (!inarea(wpos, &Players[i]->wpos))
3575 continue;
3576
3577 /* Actually clear the overlay on that spot for that player */
3578 clear_ovl_spot(i, y, x);
3579 }
3580 }
3581
3582 /*
3583 * Wipe the "CAVE_MARK" bit in everyone's array
3584 */
3585 void everyone_forget_spot(struct worldpos *wpos, int y, int x)
3586 {
3587 int i;
3588
3589 /* Check everyone */
3590 for (i = 1; i < NumPlayers + 1; i++)
3591 {
3592 /* If he's not playing, skip him */
3593 if (Players[i]->conn == NOT_CONNECTED)
3594 continue;
3595
3596 /* If he's not here, skip him */
3597 if (!inarea(wpos, &Players[i]->wpos))
3598 continue;
3599
3600 /* Forget the spot */
3601 Players[i]->cave_flag[y][x] &= ~CAVE_MARK;
3602 }
3603 }
3604
3605 /*
3606 * Redraw (on the screen) a given MAP location
3607 */
3608 void lite_spot(int Ind, int y, int x)
3609 {
3610 player_type *p_ptr = Players[Ind];
3611 bool is_us = FALSE;
3612
3613 /* Redraw if on screen */
3614 if (panel_contains(y, x)) {
3615 int dispx, dispy;
3616
3617 byte a;
3618 char c;
3619
3620 /* Handle "player" */
3621 if ((y == p_ptr->py) && (x == p_ptr->px)) {
3622 monster_race *r_ptr = &r_info[p_ptr->body_monster];
3623
3624 if ((p_ptr->inventory[INVEN_BODY].tval == TV_SOFT_ARMOR) && (p_ptr->inventory[INVEN_BODY].sval == SV_COSTUME)) {
3625 r_ptr = &r_info[p_ptr->inventory[INVEN_BODY].bpval];
3626 }
3627
3628 /* Get the "player" attr */
3629 a = r_ptr->d_attr;
3630
3631 /* Get the "player" char */
3632 c = r_ptr->d_char;
3633 #if 1 /* just for fun */
3634 if (p_ptr->body_monster == RI_DOOR_MIMIC && p_ptr->dummy_option_7) c = '\'';
3635 #endif
3636
3637 /* if (p_ptr->invis && !p_ptr->body_monster) { - hmm why not always TERM_VIOLET */
3638 if (p_ptr->invis) {
3639 /* special invis colour */
3640 a = TERM_VIOLET;
3641 }
3642 if (p_ptr->cloaked == 1) {
3643 if (p_ptr->cloak_neutralized) a = TERM_SLATE;
3644 else a = TERM_L_DARK;
3645 }
3646 /* Mana Shield and GOI also flicker */
3647 if (p_ptr->tim_manashield && rand_int(2)) {
3648 if (p_ptr->tim_manashield > 15) {
3649 /* prevent too much violet colour in our mix.. */
3650 if (a != TERM_VIOLET)
3651 a = (randint(2) < 2) ? TERM_VIOLET : TERM_ORANGE;
3652 else
3653 a = (randint(2) < 2) ? TERM_L_RED : TERM_ORANGE;
3654 } else {
3655 a = TERM_BNW;
3656 }
3657 }
3658 if (p_ptr->invuln && rand_int(4)) {
3659 if (p_ptr->invuln > 5) {
3660 switch (randint(5)) {
3661 case 1: a = TERM_L_RED; break;
3662 case 2: a = TERM_L_GREEN; break;
3663 case 3: a = TERM_L_BLUE; break;
3664 case 4: a = TERM_YELLOW; break;
3665 case 5: a = TERM_VIOLET; break;
3666 }
3667 } else if (p_ptr->invuln_dur >= 5) { /* avoid animating normal stair-GoI */
3668 a = TERM_BNW;
3669 }
3670 }
3671
3672 /* notice own Black Breath by colour instead just from occasional message */
3673 if (p_ptr->black_breath && magik(50)) a = TERM_L_DARK;
3674
3675 /* see oneself burning in the sun */
3676 if (p_ptr->sun_burn && magik(33)) a = TERM_FIRE;
3677
3678 /* Polymorph ring power running out */
3679 if (p_ptr->tim_mimic && p_ptr->body_monster == p_ptr->tim_mimic_what && p_ptr->tim_mimic <= 100) {
3680 if (!rand_int(10)) {
3681 a = TERM_DISE;
3682 c = '@';
3683 }
3684 }
3685
3686 /* Holy Martyr */
3687 /* Admin wizards sometimes flicker black & white (TERM_BNW) */
3688 if (p_ptr->shadow_running || p_ptr->martyr || p_ptr->admin_wiz)
3689 #ifdef EXTENDED_TERM_COLOURS
3690 a += is_older_than(&p_ptr->version, 4, 5, 1, 2, 0, 0) ? TERM_OLD_BNW : TERM_BNW;
3691 #else
3692 a += TERM_BNW;
3693 #endif
3694
3695 if (p_ptr->team) {
3696 if (magik(25)) { /* chance for showing him/her which team (s)he's in - mikaelh */
3697 switch(p_ptr->team) {
3698 case 1:
3699 a = TERM_L_RED;
3700 break;
3701 case 2:
3702 a = TERM_L_BLUE;
3703 break;
3704 default:
3705 break;
3706 }
3707 }
3708 else if ((has_ball(p_ptr) != -1) && magik(25)) a = TERM_ORANGE; /* game ball carrier has orange flickering - mikaelh */
3709 }
3710
3711
3712 if (p_ptr->consistent_players) {
3713 a = TERM_WHITE;
3714 if (p_ptr->tim_mimic > 0 && p_ptr->body_monster == p_ptr->tim_mimic_what) {
3715 if (p_ptr->tim_mimic <= 100 && !rand_int(10)) a = TERM_WHITE;
3716 else a = TERM_ORANGE;
3717 }
3718 if (p_ptr->tim_manashield && p_ptr->msp > 0 && p_ptr->csp > 0) {
3719 a = TERM_YELLOW;
3720 }
3721 if (p_ptr->black_breath && magik(50)) {
3722 a = TERM_SLATE;
3723 }
3724 }
3725
3726 #ifdef ENABLE_SELF_FLASHING
3727 /* display player in really easily spottable colours */
3728 if (p_ptr->flash_self > 0) a = (p_ptr->flash_self % 2) ? TERM_L_RED : TERM_L_GREEN;
3729 #endif
3730
3731 /* bugfix on MASSIVE deaths (det/death) */
3732 if (p_ptr->fruit_bat && !p_ptr->body_monster &&
3733 !((p_ptr->inventory[INVEN_BODY].tval == TV_SOFT_ARMOR) && (p_ptr->inventory[INVEN_BODY].sval == SV_COSTUME))) c = 'b';
3734
3735 if (p_ptr->consistent_players) c = '@';
3736
3737 if (p_ptr->chp < 0) c = '-';
3738 else if (!p_ptr->tim_manashield) {
3739 if (((p_ptr->chp * 95) / (p_ptr->mhp*10)) <= TURN_CHAR_INTO_NUMBER) {
3740 int num;
3741 num = (p_ptr->chp * 95) / (p_ptr->mhp * 10);
3742 c = '0' + num;
3743 }
3744 } else if (p_ptr->msp > 0) {
3745 if (((p_ptr->csp * 95) / (p_ptr->msp * 10)) <= TURN_CHAR_INTO_NUMBER) {
3746 int num;
3747 num = (p_ptr->csp * 95) / (p_ptr->msp * 10);
3748 c = '0' + num;
3749 }
3750 }
3751
3752
3753 /* >4.5.4: Mark that it is the player himself */
3754 if (p_ptr->hilite_player) is_us = TRUE;
3755 }
3756
3757 /* Normal (not player coords) */
3758 else {
3759 /* Examine the grid */
3760 map_info(Ind, y, x, &a, &c);
3761 }
3762
3763 /* Hack -- fake monochrome */
3764 if (!use_color) a = TERM_WHITE;
3765
3766 dispx = x - p_ptr->panel_col_prt;
3767 dispy = y - p_ptr->panel_row_prt;
3768
3769 /* Only draw if different than buffered */
3770 if (p_ptr->scr_info[dispy][dispx].c != c ||
3771 p_ptr->scr_info[dispy][dispx].a != a ||
3772 (x == p_ptr->px && y == p_ptr->py && !p_ptr->afk)) /* let's try disabling this when AFK to save bandwidth - mikaelh */
3773 {
3774 /* Modify screen buffer */
3775 p_ptr->scr_info[dispy][dispx].c = c;
3776 p_ptr->scr_info[dispy][dispx].a = a;
3777
3778 /* Compare against the overlay buffer */
3779 if ((p_ptr->ovl_info[dispy][dispx].c != c) ||
3780 (p_ptr->ovl_info[dispy][dispx].a != a))
3781 {
3782 /* Tell client to redraw this grid */
3783 if (is_us && is_newer_than(&p_ptr->version, 4, 5, 4, 0, 0, 0)) c |= 0x80;
3784 Send_char(Ind, dispx, dispy, a, c);
3785 }
3786
3787 /* Clear the overlay buffer */
3788 p_ptr->ovl_info[dispy][dispx].c = 0;
3789 p_ptr->ovl_info[dispy][dispx].a = 0;
3790 }
3791 }
3792 }
3793
3794
3795 /*
3796 * Draw something on the overlay layer.
3797 */
3798 void draw_spot_ovl(int Ind, int y, int x, byte a, char c)
3799 {
3800 player_type *p_ptr = Players[Ind];
3801
3802 /* Redraw if on screen */
3803 if (panel_contains(y, x))
3804 {
3805 int dispx, dispy;
3806
3807 /* Handle "player" */
3808 if ((y == p_ptr->py) && (x == p_ptr->px))
3809 {
3810 /* Never redraw the player */
3811 return;
3812 }
3813
3814 /* Hack -- fake monochrome */
3815 if (!use_color) a = TERM_WHITE;
3816
3817 dispx = x - p_ptr->panel_col_prt;
3818 dispy = y - p_ptr->panel_row_prt;
3819
3820 /* Only draw if different than buffered */
3821 if (p_ptr->ovl_info[dispy][dispx].c != c ||
3822 p_ptr->ovl_info[dispy][dispx].a != a)
3823 {
3824 /* Modify internal buffer */
3825 p_ptr->ovl_info[dispy][dispx].c = c;
3826 p_ptr->ovl_info[dispy][dispx].a = a;
3827
3828 /* Tell client to redraw this grid */
3829 Send_char(Ind, dispx, dispy, a, c);
3830 }
3831 }
3832 }
3833
3834
3835 /*
3836 * Clear a spot on the overlay layer.
3837 */
3838 void clear_ovl_spot(int Ind, int y, int x)
3839 {
3840 player_type *p_ptr = Players[Ind];
3841
3842 /* Redraw if on screen */
3843 if (panel_contains(y, x)) {
3844 int dispx, dispy;
3845
3846 dispx = x - p_ptr->panel_col_prt;
3847 dispy = y - p_ptr->panel_row_prt;
3848
3849 if (p_ptr->ovl_info[dispy][dispx].c) {
3850 /* Check if the overlay buffer is different from the screen buffer */
3851 if ((p_ptr->ovl_info[dispy][dispx].a != p_ptr->scr_info[dispy][dispx].a) ||
3852 (p_ptr->ovl_info[dispy][dispx].c != p_ptr->scr_info[dispy][dispx].c)) {
3853 /* Clear the overlay buffer */
3854 p_ptr->ovl_info[dispy][dispx].c = 0;
3855 p_ptr->ovl_info[dispy][dispx].a = 0;
3856
3857 /* Clear the screen buffer to force redraw */
3858 p_ptr->scr_info[dispy][dispx].c = 0;
3859 p_ptr->scr_info[dispy][dispx].a = 0;
3860
3861 /* Redraw */
3862 lite_spot(Ind, y, x);
3863 } else {
3864 /* Clear the overlay buffer */
3865 p_ptr->ovl_info[dispy][dispx].c = 0;
3866 p_ptr->ovl_info[dispy][dispx].a = 0;
3867
3868 /* No redraw needed */
3869 }
3870 }
3871 }
3872 }
3873
3874
3875 /*
3876 * Clear the entire overlay ler.
3877 */
3878 void clear_ovl(int Ind)
3879 {
3880 player_type *p_ptr = Players[Ind];
3881
3882 int y, x;
3883
3884 for (y = p_ptr->panel_row_min; y <= p_ptr->panel_row_max; y++) {
3885 for (x = p_ptr->panel_col_min; x <= p_ptr->panel_col_max; x++) {
3886 clear_ovl_spot(Ind, y, x);
3887 }
3888 }
3889 }
3890
3891
3892
3893
3894
3895 /*
3896 * Prints the map of the dungeon
3897 *
3898 * Note that, for efficiency, we contain an "optimized" version
3899 * of both "lite_spot()" and "print_rel()", and that we use the
3900 * "lite_spot()" function to display the player grid, if needed.
3901 */
3902
3903 void prt_map(int Ind)
3904 {
3905 player_type *p_ptr = Players[Ind];
3906
3907 int x, y;
3908 int dispx, dispy;
3909 byte a;
3910 char c;
3911
3912 /* Make sure he didn't just change depth */
3913 if (p_ptr->new_level_flag) return;
3914
3915 /* First clear the old stuff */
3916 memset(p_ptr->scr_info, 0, sizeof(p_ptr->scr_info));
3917
3918 /* Clear the overlay buffer */
3919 memset(p_ptr->ovl_info, 0, sizeof(p_ptr->ovl_info));
3920
3921 /* Dump the map */
3922 for (y = p_ptr->panel_row_min; y <= p_ptr->panel_row_max; y++)
3923 {
3924 dispy = y - p_ptr->panel_row_prt;
3925
3926 /* Scan the columns of row "y" */
3927 for (x = p_ptr->panel_col_min; x <= p_ptr->panel_col_max; x++)
3928 {
3929 /* Determine what is there */
3930 map_info(Ind, y, x, &a, &c);
3931
3932 /* Hack -- fake monochrome */
3933 if (!use_color) a = TERM_WHITE;
3934
3935 dispx = x - p_ptr->panel_col_prt;
3936
3937 /* Redraw that grid of the map */
3938 p_ptr->scr_info[dispy][dispx].c = c;
3939 p_ptr->scr_info[dispy][dispx].a = a;
3940 }
3941
3942 /* Send that line of info */
3943 Send_line_info(Ind, dispy);
3944 }
3945
3946 /* Display player */
3947 lite_spot(Ind, p_ptr->py, p_ptr->px);
3948 }
3949
3950
3951
3952
3953 /*
3954 * Display highest priority object in the RATIO by RATIO area
3955 */
3956 /*#define RATIO 3 */
3957
3958 /*
3959 * Display the entire map
3960 */
3961 #define MAP_HGT (MAX_HGT / RATIO)
3962 #define MAP_WID (MAX_WID / RATIO)
3963
3964 /*
3965 * Hack -- priority array (see below)
3966 *
3967 * Note that all "walls" always look like "secret doors" (see "map_info()").
3968 */
3969 static byte priority_table[][2] = {
3970 /* Dark */
3971 { FEAT_NONE, 2 },
3972
3973 /* Dirt */
3974 { FEAT_DIRT, 3 },
3975 { FEAT_SAND, 3},
3976 { FEAT_MUD, 3},
3977
3978 /* Grass */
3979 { FEAT_GRASS, 4 },
3980 { FEAT_ASH, 4},
3981 { FEAT_ICE, 4},
3982
3983 /* Tree */
3984 { FEAT_BUSH, 5 },
3985 { FEAT_DEAD_TREE, 6 },
3986 { FEAT_TREE, 6 },
3987
3988 /* Water */
3989 { FEAT_DEEP_WATER, 7 },
3990
3991 /* Floors */
3992 { FEAT_FLOOR, 8 },
3993
3994 /* Walls */
3995 { FEAT_SECRET, 10 },
3996
3997 /* Quartz */
3998 { FEAT_QUARTZ, 11 },
3999
4000 /* Magma */
4001 { FEAT_MAGMA, 12 },
4002
4003 /* Rubble */
4004 { FEAT_RUBBLE, 13 },
4005
4006 /* Open doors */
4007 { FEAT_OPEN, 15 },
4008 { FEAT_BROKEN, 15 },
4009
4010 /* Closed doors */
4011 { FEAT_DOOR_HEAD + 0x00, 17 },
4012
4013 /* Hidden gold */
4014 { FEAT_QUARTZ_K, 19 },
4015 { FEAT_MAGMA_K, 19 },
4016
4017 /* water, lava, & trees oh my! -KMW- */
4018 { FEAT_DEEP_WATER, 20 },
4019 { FEAT_SHAL_WATER, 20 },
4020 { FEAT_DEEP_LAVA, 20 },
4021 { FEAT_SHAL_LAVA, 20 },
4022 { FEAT_DARK_PIT, 20 },
4023 { FEAT_MOUNTAIN, 20 },
4024
4025 /* Fountain */
4026 { FEAT_FOUNTAIN, 21 },
4027 { FEAT_FOUNTAIN_BLOOD, 21 },
4028 { FEAT_EMPTY_FOUNTAIN, 21 },
4029
4030 { FEAT_SEALED_DOOR, 22 }, /* for pvp-arena */
4031 { FEAT_UNSEALED_DOOR, 22},
4032 { FEAT_ESCAPE_DOOR, 22}, /* for quests */
4033
4034 /* Shops */
4035 { FEAT_SHOP, 23 },
4036
4037 /* Void Jump Gates */
4038 { FEAT_BETWEEN_TEMP, 24 },
4039 { FEAT_BETWEEN, 24 },
4040
4041 /* Stairs */
4042 { FEAT_LESS, 25 },
4043 { FEAT_MORE, 25 },
4044
4045 /* Stairs */
4046 { FEAT_WAY_LESS, 25 },
4047 { FEAT_WAY_MORE, 25 },
4048
4049 { FEAT_SHAFT_UP, 25 },
4050 { FEAT_SHAFT_DOWN, 25 },
4051
4052 /* Event Beacon (Dungeon Keeper) */
4053 { FEAT_BEACON, 26 },
4054
4055 /* End */
4056 { 0, 0 }
4057 };
4058
4059
4060 /*
4061 * Hack -- a priority function (see below)
4062 */
4063 static byte priority(byte a, char c) {
4064 int i, p0, p1;
4065
4066 feature_type *f_ptr;
4067
4068 /* hack for shops: every shop's base door is actually '1' */
4069 if (c >= '1' && c <= '9') c = '1';
4070
4071 /* Scan the table */
4072 for (i = 0; TRUE; i++) {
4073 /* Priority level */
4074 p1 = priority_table[i][1];
4075
4076 /* End of table */
4077 if (!p1) break;
4078
4079 /* Feature index */
4080 p0 = priority_table[i][0];
4081
4082 /* Access the feature */
4083 f_ptr = &f_info[p0];
4084
4085 /* Check character and attribute, accept matches.
4086 PROBLEM: Colour can be modified for various reasons:
4087 Seasons, effects, and especially _staircase type-colouring_!! - C. Blue */
4088 #if 0 /* for this reason, let's skip the colour check for now >_> */
4089 if ((f_ptr->z_char == c) && (f_ptr->z_attr == a)) return (p1);
4090 #else
4091 if (f_ptr->z_char == c) return (p1);
4092 #endif
4093 }
4094
4095 /* Default */
4096 return (20);
4097 }
4098
4099
4100 /*
4101 * Display a "small-scale" map of the dungeon in the active Term
4102 *
4103 * Note that the "map_info()" function must return fully colorized
4104 * data or this function will not work correctly.
4105 *
4106 * Note that this function must "disable" the special lighting
4107 * effects so that the "priority" function will work.
4108 *
4109 * Note the use of a specialized "priority" function to allow this
4110 * function to work with any graphic attr/char mappings, and the
4111 * attempts to optimize this function where possible.
4112 */
4113
4114
4115 void display_map(int Ind, int *cy, int *cx) {
4116 player_type *p_ptr = Players[Ind];
4117
4118 int i, j, x, y;
4119
4120 byte ta;
4121 char tc;
4122
4123 byte tp;
4124
4125 byte ma[MAP_HGT + 2][MAP_WID + 2];
4126 char mc[MAP_HGT + 2][MAP_WID + 2];
4127
4128 byte mp[MAP_HGT + 2][MAP_WID + 2];
4129
4130 byte sa[80];
4131 char sc[80];
4132
4133 bool old_floor_lighting;
4134 bool old_wall_lighting;
4135
4136
4137 /* Save lighting effects */
4138 old_floor_lighting = p_ptr->floor_lighting;
4139 old_wall_lighting = p_ptr->wall_lighting;
4140
4141 /* Disable lighting effects */
4142 p_ptr->floor_lighting = FALSE;
4143 p_ptr->wall_lighting = FALSE;
4144
4145
4146 /* Clear the chars and attributes */
4147 memset(ma, TERM_WHITE, sizeof(ma));
4148 memset(mc, ' ', sizeof(mc));
4149
4150 /* No priority */
4151 memset(mp, 0, sizeof(mp));
4152
4153 /* Fill in the map */
4154 for (i = 0; i < p_ptr->cur_wid; ++i) {
4155 for (j = 0; j < p_ptr->cur_hgt; ++j) {
4156 /* Location */
4157 x = i / RATIO + 1;
4158 y = j / RATIO + 1;
4159
4160 /* Extract the current attr/char at that map location */
4161 map_info(Ind, j, i, &ta, &tc);
4162
4163 /* Extract the priority of that attr/char */
4164 tp = priority(ta, tc);
4165 /* duplicate code, maybe create function player_char(Ind) .. */
4166 /* Hack - Player(@) should always be displayed */
4167 if (i == p_ptr->px && j == p_ptr->py) {
4168 tp = 99;
4169 ta = player_color(Ind);
4170
4171 if ((p_ptr->inventory[INVEN_BODY].tval == TV_SOFT_ARMOR) && (p_ptr->inventory[INVEN_BODY].sval == SV_COSTUME)) {
4172 tc = r_info[p_ptr->inventory[INVEN_BODY].bpval].d_char;
4173 }
4174 else if (p_ptr->body_monster) tc = r_info[p_ptr->body_monster].d_char;
4175 else if (p_ptr->fruit_bat) tc = 'b';
4176 else if ((( p_ptr->chp * 95)/ (p_ptr->mhp * 10)) > TURN_CHAR_INTO_NUMBER) tc = '@';
4177 else {
4178 if (p_ptr->chp < 0) tc = '-';
4179 else {
4180 int num;
4181 num = (p_ptr->chp * 95) / (p_ptr->mhp * 10);
4182 tc = '0' + num;
4183 }
4184 }
4185 }
4186 /* duplicate code end */
4187 /* Save "best" */
4188 if (mp[y][x] < tp) {
4189 /* Save the char */
4190 mc[y][x] = tc;
4191
4192 /* Save the attr */
4193 ma[y][x] = ta;
4194
4195 /* Save priority */
4196 mp[y][x] = tp;
4197 }
4198 }
4199 }
4200
4201
4202 /* Corners */
4203 x = MAP_WID + 1;
4204 y = MAP_HGT + 1;
4205
4206 /* Draw the corners */
4207 mc[0][0] = mc[0][x] = mc[y][0] = mc[y][x] = '+';
4208
4209 /* Draw the horizontal edges */
4210 for (x = 1; x <= MAP_WID; x++) mc[0][x] = mc[y][x] = '-';
4211
4212 /* Draw the vertical edges */
4213 for (y = 1; y <= MAP_HGT; y++) mc[y][0] = mc[y][x] = '|';
4214
4215
4216 /* Display each map line in order */
4217 for (y = 0; y < MAP_HGT+2; ++y) {
4218 /* Clear the screen buffer */
4219 #if 0
4220 memset(sa, 0, sizeof(sa));
4221 memset(sc, 0, sizeof(sc));
4222 #else
4223 /* Allow for creation of an empty border
4224 (or maybe instructions on how to navigate)
4225 to eg the left and right side of the map */
4226 memset(sa, TERM_WHITE, sizeof(sa));
4227 memset(sc, ' ', sizeof(sc));
4228 #endif
4229
4230 /* Display the line */
4231 for (x = 0; x < MAP_WID+2; ++x) {
4232 ta = ma[y][x];
4233 tc = mc[y][x];
4234
4235 /* Hack -- fake monochrome */
4236 if (!use_color) ta = TERM_WHITE;
4237
4238 #if 0
4239 /* Put the character into the screen buffer */
4240 sa[x] = ta;
4241 sc[x] = tc;
4242 #else /* add a symmetrical 'border' to the left and right side of the map */
4243 sa[x + (80 - MAP_WID - 2) / 2] = ta;
4244 sc[x + (80 - MAP_WID - 2) / 2] = tc;
4245 #endif
4246 }
4247
4248 /* Send that line of info */
4249 Send_mini_map(Ind, y, sa, sc);
4250 }
4251
4252
4253 /* Player location */
4254 (*cy) = p_ptr->py / RATIO + 1;
4255 (*cx) = p_ptr->px / RATIO + 1;
4256
4257
4258 /* Restore lighting effects */
4259 p_ptr->floor_lighting = old_floor_lighting;
4260 p_ptr->wall_lighting = old_wall_lighting;
4261 }
4262
4263
4264 #define WILDMAP_SHOWS_STAIRS
4265 static void wild_display_map(int Ind, char mode) {
4266 player_type *p_ptr = Players[Ind];
4267
4268 int x, y, type;
4269 int max_wx, offset_x;
4270 int max_wy;//, offset_y;
4271
4272 byte ta;
4273 char tc;
4274
4275 /* map is displayed "full-screen" ie we can use all of the main window */
4276 byte ma[MAX_WINDOW_HGT][MAX_WINDOW_WID];
4277 char mc[MAX_WINDOW_HGT][MAX_WINDOW_WID];
4278
4279 byte sa[80];
4280 char sc[80];
4281
4282 bool old_floor_lighting;
4283 bool old_wall_lighting;
4284 struct worldpos twpos;
4285 twpos.wz = 0;
4286
4287 byte c_dun, c_tow;
4288 int c_dun_diff, c_tow_diff, mmpx = 0, mmpy = 0;
4289 bool admin = is_admin(p_ptr), sent_pos = FALSE;
4290
4291
4292 if (CL_WINDOW_WID > MAX_WILD_X + 2) {//+ 2 for border
4293 offset_x = (CL_WINDOW_WID - MAX_WILD_X) / 2 - 1;//-1 for border
4294 max_wx = MAX_WILD_X + 2;
4295 } else {
4296 offset_x = 0;
4297 max_wx = CL_WINDOW_WID;
4298 }
4299 if (CL_WINDOW_HGT > MAX_WILD_Y + 2) {//+ 2 for border
4300 //offset_y = (CL_WINDOW_HGT - MAX_WILD_Y) / 2 - 1;//-1 for border
4301 max_wy = MAX_WILD_Y + 2;
4302 } else {
4303 //offset_y = 0;
4304 max_wy = CL_WINDOW_HGT;
4305 }
4306
4307
4308 /* Save lighting effects */
4309 old_floor_lighting = p_ptr->floor_lighting;
4310 old_wall_lighting = p_ptr->wall_lighting;
4311
4312 /* Disable lighting effects */
4313 p_ptr->floor_lighting = FALSE;
4314 p_ptr->wall_lighting = FALSE;
4315
4316
4317 /* Clear the chars and attributes */
4318 memset(ma, TERM_WHITE, sizeof(ma));
4319 memset(mc, ' ', sizeof(mc));
4320
4321
4322 /* Modify location */
4323 if ((mode & ~0x1) == 0x0) {
4324 p_ptr->tmp_x = p_ptr->wpos.wx;
4325 p_ptr->tmp_y = p_ptr->wpos.wy;
4326 }
4327 if (mode & 0x2) p_ptr->tmp_y -= 9;//10..11*2
4328 if (mode & 0x4) p_ptr->tmp_x += 9;//31..32*2
4329 if (mode & 0x8) p_ptr->tmp_y += 9;//10..11*2
4330 if (mode & 0x10) p_ptr->tmp_x -= 9;//31..32*2
4331 #if 0
4332 /* limit */
4333 if (p_ptr->tmp_x < 0) p_ptr->tmp_x = 0;
4334 if (p_ptr->tmp_y < 0) p_ptr->tmp_y = 0;
4335 if (p_ptr->tmp_x >= MAX_WILD_X) p_ptr->tmp_x = MAX_WILD_X - 1;
4336 if (p_ptr->tmp_y >= MAX_WILD_Y) p_ptr->tmp_y = MAX_WILD_Y - 1;
4337 #else
4338 /* limit, align so that the map fills out the screen,
4339 instead of always centering the '@-sector'. */
4340 if (p_ptr->tmp_x < (max_wx + 0) / 2 - 1) p_ptr->tmp_x = (max_wx + 0) / 2 - 1;
4341 if (p_ptr->tmp_y < (max_wy - 0) / 2 - 2) p_ptr->tmp_y = (max_wy - 0) / 2 - 2;
4342 if (p_ptr->tmp_x > MAX_WILD_X - (max_wx - 0) / 2 + 1) p_ptr->tmp_x = MAX_WILD_X - (max_wx - 0) / 2 + 1;
4343 if (p_ptr->tmp_y > MAX_WILD_Y - (max_wy + 0) / 2 - 0) p_ptr->tmp_y = MAX_WILD_Y - (max_wy + 0) / 2 - 0;
4344 #endif
4345
4346
4347 /* for each row */
4348 for (y = 0; y < max_wy; y++) {
4349 /* for each column */
4350 for (x = 0; x < max_wx; x++) {
4351 /* Location */
4352 twpos.wy = p_ptr->tmp_y + (max_wy) / 2 - y;
4353 twpos.wx = p_ptr->tmp_x - (max_wx) / 2 + x;
4354
4355 if (twpos.wy >= 0 && twpos.wy < MAX_WILD_Y && twpos.wx >= 0 && twpos.wx < MAX_WILD_X)
4356 type = determine_wilderness_type(&twpos);
4357 /* if off the map, set to unknown type */
4358 else type = -1;
4359
4360 /* if the player hasnt been here, dont show him the terrain */
4361 /* Hack -- serverchez has knowledge of the full world */
4362 if (!p_ptr->admin_dm)
4363 if (!(p_ptr->wild_map[wild_idx(&twpos) / 8] & (1 << (wild_idx(&twpos) % 8)))) type = -1;
4364 /* hack -- the town is always known */
4365
4366 switch (type) {
4367 case WILD_LAKE: tc = '~'; ta = TERM_BLUE; break;
4368 case WILD_GRASSLAND: tc = '.'; ta = TERM_GREEN; break;
4369 case WILD_FOREST: tc = '*'; ta = TERM_GREEN; break;
4370 case WILD_SWAMP: tc = '%'; ta = TERM_VIOLET; break;
4371 case WILD_DENSEFOREST: tc = '*'; ta = TERM_L_DARK; break;
4372 case WILD_WASTELAND: tc = '.'; ta = TERM_UMBER; break;
4373 case WILD_TOWN: tc = 'T'; ta = TERM_YELLOW; break;
4374 case WILD_CLONE: tc = 'C'; ta = TERM_RED; break;
4375 case WILD_MOUNTAIN: tc = '^'; ta = TERM_L_DARK; break;
4376 case WILD_VOLCANO: tc = '^'; ta = TERM_RED; break;
4377 case WILD_RIVER: tc = '~'; ta = TERM_L_BLUE; break;
4378 case WILD_COAST: tc = ','; ta = TERM_L_UMBER; break;//TERM_YELLOW
4379 case WILD_OCEAN: tc = '%'; ta = TERM_BLUE; break;
4380 case WILD_DESERT: tc = '.'; ta = TERM_YELLOW; break;
4381 case WILD_ICE: tc = '.'; ta = TERM_WHITE; break;
4382 case -1: tc = ' '; ta = TERM_DARK; break;
4383 default: tc = 'O'; ta = TERM_YELLOW; break;
4384 }
4385 #ifdef WILDMAP_SHOWS_STAIRS
4386 if (type != -1 && type != WILD_TOWN) {
4387 dungeon_type *dun = wild_info[twpos.wy][twpos.wx].dungeon, *tow = wild_info[twpos.wy][twpos.wx].tower;
4388 if (dun && !strcmp(d_info[dun->type].name + d_name, "The Shores of Valinor") && !admin) dun = NULL;
4389 if (tow && !strcmp(d_info[tow->type].name + d_name, "The Shores of Valinor") && !admin) tow = NULL;
4390 if (dun) {
4391 if (tow) {
4392 tc = 'X';
4393 c_dun_diff = get_staircase_colour(dun, &c_dun);
4394 c_tow_diff = get_staircase_colour(tow, &c_tow);
4395 if (c_dun == c_tow) ta = c_dun;
4396 else if (c_dun_diff > c_tow_diff) ta = c_dun;
4397 else ta = c_tow;
4398 } else {
4399 tc = '>';
4400 get_staircase_colour(dun, &ta);
4401 }
4402 } else if (tow) {
4403 tc = '<';
4404 get_staircase_colour(tow, &ta);
4405 }
4406 }
4407 #endif
4408
4409 #if 0
4410 /* put the @ in the center */
4411 if ((y == (MAP_HGT + 2) / 2) && (x == (MAP_WID + 2) / 2)) {
4412 tc = '@';
4413 ta = TERM_WHITE;
4414 }
4415 #else
4416 /* since map is navigatable, only put @ if we are there */
4417 if (twpos.wx == p_ptr->wpos.wx && twpos.wy == p_ptr->wpos.wy) {
4418 if (is_older_than(&p_ptr->version, 4, 5, 5, 1, 0, 0)) {
4419 /* directly "hard-sub" it ;) */
4420 tc = '@';
4421 ta = TERM_WHITE;
4422 } else {
4423 /* overlay a blinking '@' */
4424 mmpx = x;
4425 mmpy = y;
4426 sent_pos = TRUE;
4427 }
4428 } else if (!sent_pos) {
4429 /* allow overlay on map borders, as indicator */
4430 if (twpos.wx == p_ptr->wpos.wx) mmpx = x;
4431 if (twpos.wy == p_ptr->wpos.wy) mmpy = y;
4432 }
4433 #endif
4434
4435 /* Save the char */
4436 mc[y][x] = tc;
4437
4438 /* Save the attr */
4439 ma[y][x] = ta;
4440 }
4441 }
4442
4443 /* Corners */
4444 x = max_wx - 1;
4445 y = max_wy - 1;
4446
4447 /* Draw the corners */
4448 mc[0][0] = mc[0][x] = mc[y][0] = mc[y][x] = '+';
4449
4450 /* Draw the horizontal edges */
4451 for (x = 1; x < max_wx; x++) mc[0][x] = mc[y][x] = '-';
4452
4453 /* Draw the vertical edges */
4454 for (y = 1; y < max_wy; y++) mc[y][0] = mc[y][x] = '|';
4455
4456
4457 /* If we are off-screen, don't draw the usual '@' icon */
4458 if (!sent_pos) {
4459 #if 0
4460 /* Don't draw it at all */
4461 Send_mini_map_pos(Ind, -1, 0, 0, 0);
4462 #else
4463 /* Draw it on the map border as indicator:
4464 max_wx/wy - 2 (border size of 1 in each direction).
4465 Note: Does currently ignore left/right borders, since they don't exist atm. */
4466
4467 int yy = p_ptr->tmp_y + max_wy / 2;
4468
4469 /* On bottom border? */
4470 if (p_ptr->wpos.wy < yy - (max_wy - 2)) Send_mini_map_pos(Ind, mmpx + offset_x, max_wy - 1, ma[max_wy - 1][mmpx], '-');
4471 /* On top border? */
4472 else if (p_ptr->wpos.wy > yy) Send_mini_map_pos(Ind, mmpx + offset_x, 0, ma[0][mmpx], '-');
4473 /* On pfft? */
4474 else Send_mini_map_pos(Ind, -1, 0, 0, 0); /* paranoia */
4475 #endif
4476 } else Send_mini_map_pos(Ind, mmpx + offset_x, mmpy, ma[mmpy][mmpx], mc[mmpy][mmpx]);
4477
4478
4479 /* Display each map line in order */
4480 for (y = 0; y < max_wy; ++y) {
4481 /* Clear the screen buffer */
4482 #if 0
4483 memset(sa, 0, sizeof(sa));
4484 memset(sc, 0, sizeof(sc));
4485 #else
4486 /* Allow for creation of an empty border
4487 (or maybe instructions on how to navigate)
4488 to eg the left and right side of the map */
4489 memset(sa, TERM_WHITE, sizeof(sa));
4490 memset(sc, ' ', sizeof(sc));
4491 #endif
4492
4493 /* Display the line */
4494 for (x = 0; x < max_wx; ++x) {
4495 ta = ma[y][x];
4496 tc = mc[y][x];
4497
4498 /* Hack -- fake monochrome */
4499 if (!use_color) ta = TERM_WHITE;
4500
4501 /* Put the character into the screen buffer */
4502 #if 0
4503 sa[x] = ta;
4504 sc[x] = tc;
4505 #else /* add a symmetrical 'border' to the left and right side of the map */
4506 sa[x + offset_x] = ta;
4507 sc[x + offset_x] = tc;
4508 #endif
4509 }
4510
4511 /* Send that line of info */
4512 Send_mini_map(Ind, y, sa, sc);
4513 }
4514
4515 /* Restore lighting effects */
4516 p_ptr->floor_lighting = old_floor_lighting;
4517 p_ptr->wall_lighting = old_wall_lighting;
4518 }
4519
4520
4521 /*
4522 * Display a "small-scale" map of the dungeon for the player
4523 */
4524
4525 /* in the wilderness, have several scales of maps availiable... adding one
4526 "wilderness map" mode now that will represent each level with one character.
4527 */
4528
4529 void do_cmd_view_map(int Ind, char mode) {
4530 int cy, cx;
4531
4532 /* Display the map */
4533
4534 /* if not in town or the dungeon, do normal map */
4535 /* is player in a town or dungeon? */
4536 /* only off floor ATM */
4537 if ((Players[Ind]->wpos.wz != 0 || (istown(&Players[Ind]->wpos)))
4538 && !(mode & 0x1))
4539 display_map(Ind, &cy, &cx);
4540 /* do wilderness map */
4541 /* pfft, fix me pls, Evileye ;) */
4542 /* pfft. fixed */
4543 else wild_display_map(Ind, mode);
4544 /*else display_map(Ind, &cy, &cx); */
4545 }
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556 /*
4557 * Some comments on the cave grid flags. -BEN-
4558 *
4559 *
4560 * One of the major bottlenecks in previous versions of Angband was in
4561 * the calculation of "line of sight" from the player to various grids,
4562 * such as monsters. This was such a nasty bottleneck that a lot of
4563 * silly things were done to reduce the dependancy on "line of sight",
4564 * for example, you could not "see" any grids in a lit room until you
4565 * actually entered the room, and there were all kinds of bizarre grid
4566 * flags to enable this behavior. This is also why the "call light"
4567 * spells always lit an entire room.
4568 *
4569 * The code below provides functions to calculate the "field of view"
4570 * for the player, which, once calculated, provides extremely fast
4571 * calculation of "line of sight from the player", and to calculate
4572 * the "field of torch lite", which, again, once calculated, provides
4573 * extremely fast calculation of "which grids are lit by the player's
4574 * lite source". In addition to marking grids as "GRID_VIEW" and/or
4575 * "GRID_LITE", as appropriate, these functions maintain an array for
4576 * each of these two flags, each array containing the locations of all
4577 * of the grids marked with the appropriate flag, which can be used to
4578 * very quickly scan through all of the grids in a given set.
4579 *
4580 * To allow more "semantically valid" field of view semantics, whenever
4581 * the field of view (or the set of torch lit grids) changes, all of the
4582 * grids in the field of view (or the set of torch lit grids) are "drawn"
4583 * so that changes in the world will become apparent as soon as possible.
4584 * This has been optimized so that only grids which actually "change" are
4585 * redrawn, using the "temp" array and the "GRID_TEMP" flag to keep track
4586 * of the grids which are entering or leaving the relevent set of grids.
4587 *
4588 * These new methods are so efficient that the old nasty code was removed.
4589 *
4590 * Note that there is no reason to "update" the "viewable space" unless
4591 * the player "moves", or walls/doors are created/destroyed, and there
4592 * is no reason to "update" the "torch lit grids" unless the field of
4593 * view changes, or the "light radius" changes. This means that when
4594 * the player is resting, or digging, or doing anything that does not
4595 * involve movement or changing the state of the dungeon, there is no
4596 * need to update the "view" or the "lite" regions, which is nice.
4597 *
4598 * Note that the calls to the nasty "los()" function have been reduced
4599 * to a bare minimum by the use of the new "field of view" calculations.
4600 *
4601 * I wouldn't be surprised if slight modifications to the "update_view()"
4602 * function would allow us to determine "reverse line-of-sight" as well
4603 * as "normal line-of-sight", which would allow monsters to use a more
4604 * "correct" calculation to determine if they can "see" the player. For
4605 * now, monsters simply "cheat" somewhat and assume that if the player
4606 * has "line of sight" to the monster, then the monster can "pretend"
4607 * that it has "line of sight" to the player.
4608 *
4609 *
4610 * The "update_lite()" function maintains the "CAVE_LITE" flag for each
4611 * grid and maintains an array of all "CAVE_LITE" grids.
4612 *
4613 * This set of grids is the complete set of all grids which are lit by
4614 * the players light source, which allows the "player_can_see_bold()"
4615 * function to work very quickly.
4616 *
4617 * Note that every "CAVE_LITE" grid is also a "CAVE_VIEW" grid, and in
4618 * fact, the player (unless blind) can always "see" all grids which are
4619 * marked as "CAVE_LITE", unless they are "off screen".
4620 *
4621 *
4622 * The "update_view()" function maintains the "CAVE_VIEW" flag for each
4623 * grid and maintains an array of all "CAVE_VIEW" grids.
4624 *
4625 * This set of grids is the complete set of all grids within line of sight
4626 * of the player, allowing the "player_has_los_bold()" macro to work very
4627 * quickly.
4628 *
4629 *
4630 * The current "update_view()" algorithm uses the "CAVE_XTRA" flag as a
4631 * temporary internal flag to mark those grids which are not only in view,
4632 * but which are also "easily" in line of sight of the player. This flag
4633 * is always cleared when we are done.
4634 *
4635 *
4636 * The current "update_lite()" and "update_view()" algorithms use the
4637 * "CAVE_TEMP" flag, and the array of grids which are marked as "CAVE_TEMP",
4638 * to keep track of which grids were previously marked as "CAVE_LITE" or
4639 * "CAVE_VIEW", which allows us to optimize the "screen updates".
4640 *
4641 * The "CAVE_TEMP" flag, and the array of "CAVE_TEMP" grids, is also used
4642 * for various other purposes, such as spreading lite or darkness during
4643 * "lite_room()" / "unlite_room()", and for calculating monster flow.
4644 *
4645 *
4646 * Any grid can be marked as "CAVE_GLOW" which means that the grid itself is
4647 * in some way permanently lit. However, for the player to "see" anything
4648 * in the grid, as determined by "player_can_see()", the player must not be
4649 * blind, the grid must be marked as "CAVE_VIEW", and, in addition, "wall"
4650 * grids, even if marked as "perma lit", are only illuminated if they touch
4651 * a grid which is not a wall and is marked both "CAVE_GLOW" and "CAVE_VIEW".
4652 *
4653 *
4654 * To simplify various things, a grid may be marked as "CAVE_MARK", meaning
4655 * that even if the player cannot "see" the grid, he "knows" the terrain in
4656 * that grid. This is used to "remember" walls/doors/stairs/floors when they
4657 * are "seen" or "detected", and also to "memorize" floors, after "wiz_lite()",
4658 * or when one of the "memorize floor grids" options induces memorization.
4659 *
4660 * Objects are "memorized" in a different way, using a special "marked" flag
4661 * on the object itself, which is set when an object is observed or detected.
4662 *
4663 *
4664 * A grid may be marked as "CAVE_ROOM" which means that it is part of a "room",
4665 * and should be illuminated by "lite room" and "darkness" spells.
4666 *
4667 *
4668 * A grid may be marked as "CAVE_ICKY" which means it is part of a "vault",
4669 * and should be unavailable for "teleportation" destinations.
4670 * Note that CAVE_ICKY is also used for other purposes like houses. - C. Blue
4671 *
4672 *
4673 * The "view_perma_grids" allows the player to "memorize" every perma-lit grid
4674 * which is observed, and the "view_torch_grids" allows the player to memorize
4675 * every torch-lit grid. The player will always memorize important walls,
4676 * doors, stairs, and other terrain features, as well as any "detected" grids.
4677 *
4678 * Note that the new "update_view()" method allows, among other things, a room
4679 * to be "partially" seen as the player approaches it, with a growing cone of
4680 * floor appearing as the player gets closer to the door. Also, by not turning
4681 * on the "memorize perma-lit grids" option, the player will only "see" those
4682 * floor grids which are actually in line of sight.
4683 *
4684 * And my favorite "plus" is that you can now use a special option to draw the
4685 * "floors" in the "viewable region" brightly (actually, to draw the *other*
4686 * grids dimly), providing a "pretty" effect as the player runs around, and
4687 * to efficiently display the "torch lite" in a special color.
4688 *
4689 *
4690 * Some comments on the "update_view()" algorithm...
4691 *
4692 * The algorithm is very fast, since it spreads "obvious" grids very quickly,
4693 * and only has to call "los()" on the borderline cases. The major axes/diags
4694 * even terminate early when they hit walls. I need to find a quick way
4695 * to "terminate" the other scans.
4696 *
4697 * Note that in the worst case (a big empty area with say 5% scattered walls),
4698 * each of the 1500 or so nearby grids is checked once, most of them getting
4699 * an "instant" rating, and only a small portion requiring a call to "los()".
4700 *
4701 * The only time that the algorithm appears to be "noticeably" too slow is
4702 * when running, and this is usually only important in town, since the town
4703 * provides about the worst scenario possible, with large open regions and
4704 * a few scattered obstructions. There is a special "efficiency" option to
4705 * allow the player to reduce his field of view in town, if needed.
4706 *
4707 * In the "best" case (say, a normal stretch of corridor), the algorithm
4708 * makes one check for each viewable grid, and makes no calls to "los()".
4709 * So running in corridors is very fast, and if a lot of monsters are
4710 * nearby, it is much faster than the old methods.
4711 *
4712 * Note that resting, most normal commands, and several forms of running,
4713 * plus all commands executed near large groups of monsters, are strictly
4714 * more efficient with "update_view()" that with the old "compute los() on
4715 * demand" method, primarily because once the "field of view" has been
4716 * calculated, it does not have to be recalculated until the player moves
4717 * (or a wall or door is created or destroyed).
4718 *
4719 * Note that we no longer have to do as many "los()" checks, since once the
4720 * "view" region has been built, very few things cause it to be "changed"
4721 * (player movement, and the opening/closing of doors, changes in wall status).
4722 * Note that door/wall changes are only relevant when the door/wall itself is
4723 * in the "view" region.
4724 *
4725 * The algorithm seems to only call "los()" from zero to ten times, usually
4726 * only when coming down a corridor into a room, or standing in a room, just
4727 * misaligned with a corridor. So if, say, there are five "nearby" monsters,
4728 * we will be reducing the calls to "los()".
4729 *
4730 * I am thinking in terms of an algorithm that "walks" from the central point
4731 * out to the maximal "distance", at each point, determining the "view" code
4732 * (above). For each grid not on a major axis or diagonal, the "view" code
4733 * depends on the "cave_floor_bold()" and "view" of exactly two other grids
4734 * (the one along the nearest diagonal, and the one next to that one, see
4735 * "update_view_aux()"...).
4736 *
4737 * We "memorize" the viewable space array, so that at the cost of under 3000
4738 * bytes, we reduce the time taken by "forget_view()" to one assignment for
4739 * each grid actually in the "viewable space". And for another 3000 bytes,
4740 * we prevent "erase + redraw" ineffiencies via the "seen" set. These bytes
4741 * are also used by other routines, thus reducing the cost to almost nothing.
4742 *
4743 * A similar thing is done for "forget_lite()" in which case the savings are
4744 * much less, but save us from doing bizarre maintenance checking.
4745 *
4746 * In the worst "normal" case (in the middle of the town), the reachable space
4747 * actually reaches to more than half of the largest possible "circle" of view,
4748 * or about 800 grids, and in the worse case (in the middle of a dungeon level
4749 * where all the walls have been removed), the reachable space actually reaches
4750 * the theoretical maximum size of just under 1500 grids.
4751 *
4752 * Each grid G examines the "state" of two (?) other (adjacent) grids, G1 & G2.
4753 * If G1 is lite, G is lite. Else if G2 is lite, G is half. Else if G1 and G2
4754 * are both half, G is half. Else G is dark. It only takes 2 (or 4) bits to
4755 * "name" a grid, so (for MAX_RAD of 20) we could use 1600 bytes, and scan the
4756 * entire possible space (including initialization) in one step per grid. If
4757 * we do the "clearing" as a separate step (and use an array of "view" grids),
4758 * then the clearing will take as many steps as grids that were viewed, and the
4759 * algorithm will be able to "stop" scanning at various points.
4760 * Oh, and outside of the "torch radius", only "lite" grids need to be scanned.
4761 */
4762
4763
4764
4765
4766
4767
4768
4769
4770 /*
4771 * Actually erase the entire "lite" array, redrawing every grid
4772 */
4773 void forget_lite(int Ind)
4774 {
4775 player_type *p_ptr = Players[Ind];
4776 int i, x, y;
4777
4778 cave_type **zcave;
4779 struct worldpos *wpos = &p_ptr->wpos;
4780 if (!(zcave = getcave(&p_ptr->wpos))) return;
4781
4782
4783 /* None to forget */
4784 if (!(p_ptr->lite_n)) return;
4785
4786 /* Clear them all */
4787 for (i = 0; i < p_ptr->lite_n; i++)
4788 {
4789 int j;
4790
4791 y = p_ptr->lite_y[i];
4792 x = p_ptr->lite_x[i];
4793
4794 /* Forget "LITE" flag */
4795 p_ptr->cave_flag[y][x] &= ~CAVE_LITE;
4796 zcave[y][x].info &= ~(CAVE_LITE | CAVE_LITE_VAMP | CAVE_LITE_WHITE);
4797
4798 for (j = 1; j <= NumPlayers; j++)
4799 {
4800 /* Make sure player is connected */
4801 if (Players[j]->conn == NOT_CONNECTED)
4802 continue;
4803
4804 /* Make sure player is on the level */
4805 if (!inarea(wpos, &Players[j]->wpos))
4806 continue;
4807
4808 /* Ignore the player that we're updating */
4809 if (j == Ind)
4810 continue;
4811
4812 /* If someone else also lites this spot relite it */
4813 if (Players[j]->cave_flag[y][x] & CAVE_LITE) {
4814 zcave[y][x].info |= CAVE_LITE;
4815 switch (Players[j]->lite_type) {
4816 case 1: zcave[y][x].info |= CAVE_LITE_VAMP; break;
4817 case 2: zcave[y][x].info |= CAVE_LITE_WHITE;
4818 }
4819 }
4820 }
4821
4822 /* Redraw */
4823 everyone_lite_spot(wpos, y, x);
4824 }
4825
4826 /* None left */
4827 p_ptr->lite_n = 0;
4828 }
4829
4830
4831 /*
4832 * XXX XXX XXX
4833 *
4834 * This macro allows us to efficiently add a grid to the "lite" array,
4835 * note that we are never called for illegal grids, or for grids which
4836 * have already been placed into the "lite" array, and we are never
4837 * called when the "lite" array is full.
4838 *
4839 * Note that I'm assuming that we can use "p_ptr", because this macro
4840 * should only be called from functions that have it defined at the
4841 * top. --KLJ--
4842 */
4843 #define cave_lite_hack(Y,X) \
4844 switch (p_ptr->lite_type) { \
4845 case 0: zcave[Y][X].info &= ~(CAVE_LITE_WHITE | CAVE_LITE_VAMP); break; \
4846 case 1: if (!(zcave[Y][X].info & (CAVE_LITE | CAVE_LITE_WHITE))) zcave[Y][X].info |= CAVE_LITE_VAMP; break; \
4847 case 2: if (!(zcave[Y][X].info & CAVE_LITE)) zcave[Y][X].info |= CAVE_LITE_WHITE; \
4848 } \
4849 zcave[Y][X].info |= CAVE_LITE; \
4850 p_ptr->cave_flag[Y][X] |= CAVE_LITE; \
4851 p_ptr->lite_y[p_ptr->lite_n] = (Y); \
4852 p_ptr->lite_x[p_ptr->lite_n] = (X); \
4853 p_ptr->lite_n++
4854
4855 /*
4856 * Update the set of grids "illuminated" by the player's lite.
4857 *
4858 * This routine needs to use the results of "update_view()"
4859 *
4860 * Note that "blindness" does NOT affect "torch lite". Be careful!
4861 *
4862 * We optimize most lites (all non-artifact lites) by using "obvious"
4863 * facts about the results of "small" lite radius, and we attempt to
4864 * list the "nearby" grids before the more "distant" ones in the
4865 * array of torch-lit grids.
4866 *
4867 * We will correctly handle "large" radius lites, though currently,
4868 * it is impossible for the player to have more than radius 3 lite.
4869 *
4870 * We assume that "radius zero" lite is in fact no lite at all.
4871 *
4872 * Torch Lantern Artifacts
4873 * (etc)
4874 * ***
4875 * *** *****
4876 * *** ***** *******
4877 * *@* **@** ***@***
4878 * *** ***** *******
4879 * *** *****
4880 * ***
4881 */
4882 void update_lite(int Ind)
4883 {
4884 player_type *p_ptr = Players[Ind];
4885 int i, x, y, min_x, max_x, min_y, max_y;
4886
4887 struct worldpos *wpos = &p_ptr->wpos;
4888 cave_type **zcave;
4889 if (!(zcave = getcave(wpos))) return;
4890
4891 /*** Special case ***/
4892
4893 /* Hack -- Player has no lite */
4894 if (p_ptr->cur_lite <= 0 && p_ptr->cur_vlite <= 0)
4895 {
4896 /* Forget the old lite */
4897 forget_lite(Ind);
4898
4899 /* Draw the player */
4900 lite_spot(Ind, p_ptr->py, p_ptr->px);
4901
4902 /* All done */
4903 return;
4904 }
4905
4906
4907 /*** Save the old "lite" grids for later ***/
4908
4909 /* Clear them all */
4910 for (i = 0; i < p_ptr->lite_n; i++)
4911 {
4912 int j;
4913
4914 y = p_ptr->lite_y[i];
4915 x = p_ptr->lite_x[i];
4916
4917 /* Mark the grid as not "lite" */
4918 p_ptr->cave_flag[y][x] &= ~CAVE_LITE;
4919 zcave[y][x].info &= ~(CAVE_LITE | CAVE_LITE_VAMP | CAVE_LITE_WHITE);
4920
4921 for (j = 1; j <= NumPlayers; j++)
4922 {
4923 /* Make sure player is connected */
4924 if (Players[j]->conn == NOT_CONNECTED)
4925 continue;
4926
4927 /* Make sure player is on the level */
4928 if (!inarea(wpos, &Players[j]->wpos))
4929 continue;
4930
4931 /* Ignore the player that we're updating */
4932 if (j == Ind)
4933 continue;
4934
4935 /* If someone else also lites this spot relite it */
4936 if (Players[j]->cave_flag[y][x] & CAVE_LITE) {
4937 zcave[y][x].info |= CAVE_LITE;
4938 switch (Players[j]->lite_type) {
4939 case 1: zcave[y][x].info |= CAVE_LITE_VAMP; break;
4940 case 2: zcave[y][x].info |= CAVE_LITE_WHITE;
4941 }
4942 }
4943 }
4944 /* Mark the grid as "seen" */
4945 zcave[y][x].info |= CAVE_TEMP;
4946
4947 /* Add it to the "seen" set */
4948 p_ptr->temp_y[p_ptr->temp_n] = y;
4949 p_ptr->temp_x[p_ptr->temp_n] = x;
4950 p_ptr->temp_n++;
4951 }
4952
4953 /* None left */
4954 p_ptr->lite_n = 0;
4955
4956
4957 /*** Collect the new "lite" grids ***/
4958
4959 /* Player grid */
4960 cave_lite_hack(p_ptr->py, p_ptr->px);
4961
4962 /* Radius 1 -- torch radius */
4963 if (p_ptr->cur_lite >= 1 || p_ptr->cur_vlite >= 1) {
4964 /* Adjacent grid */
4965 cave_lite_hack(p_ptr->py+1, p_ptr->px);
4966 cave_lite_hack(p_ptr->py-1, p_ptr->px);
4967 cave_lite_hack(p_ptr->py, p_ptr->px+1);
4968 cave_lite_hack(p_ptr->py, p_ptr->px-1);
4969
4970 /* Diagonal grids */
4971 cave_lite_hack(p_ptr->py+1, p_ptr->px+1);
4972 cave_lite_hack(p_ptr->py+1, p_ptr->px-1);
4973 cave_lite_hack(p_ptr->py-1, p_ptr->px+1);
4974 cave_lite_hack(p_ptr->py-1, p_ptr->px-1);
4975 }
4976
4977 /* Radius 2 -- lantern radius */
4978 if (p_ptr->cur_lite >= 2 || p_ptr->cur_vlite >= 2) {
4979 /* South of the player */
4980 // if (cave_floor_bold(zcave, p_ptr->py+1, p_ptr->px))
4981 /* cave_los includes dark pits */
4982 if (cave_los(zcave, p_ptr->py+1, p_ptr->px))
4983 {
4984 cave_lite_hack(p_ptr->py+2, p_ptr->px);
4985 cave_lite_hack(p_ptr->py+2, p_ptr->px+1);
4986 cave_lite_hack(p_ptr->py+2, p_ptr->px-1);
4987 }
4988
4989 /* North of the player */
4990 // if (cave_floor_bold(zcave, p_ptr->py-1, p_ptr->px))
4991 if (cave_los(zcave, p_ptr->py-1, p_ptr->px)) {
4992 cave_lite_hack(p_ptr->py-2, p_ptr->px);
4993 cave_lite_hack(p_ptr->py-2, p_ptr->px+1);
4994 cave_lite_hack(p_ptr->py-2, p_ptr->px-1);
4995 }
4996
4997 /* East of the player */
4998 // if (cave_floor_bold(zcave, p_ptr->py, p_ptr->px+1))
4999 if (cave_los(zcave, p_ptr->py, p_ptr->px+1)) {
5000 cave_lite_hack(p_ptr->py, p_ptr->px+2);
5001 cave_lite_hack(p_ptr->py+1, p_ptr->px+2);
5002 cave_lite_hack(p_ptr->py-1, p_ptr->px+2);
5003 }
5004
5005 /* West of the player */
5006 // if (cave_floor_bold(zcave, p_ptr->py, p_ptr->px-1))
5007 if (cave_los(zcave, p_ptr->py, p_ptr->px-1)) {
5008 cave_lite_hack(p_ptr->py, p_ptr->px-2);
5009 cave_lite_hack(p_ptr->py+1, p_ptr->px-2);
5010 cave_lite_hack(p_ptr->py-1, p_ptr->px-2);
5011 }
5012 }
5013
5014 /* Radius 3+ -- artifact radius */
5015 if (p_ptr->cur_lite >= 3 || p_ptr->cur_vlite >= 3) {
5016 int d, p;
5017
5018 /* Maximal radius */
5019 p = p_ptr->cur_lite;
5020 if (p_ptr->cur_vlite > p) p = p_ptr->cur_vlite;
5021
5022 /* Paranoia -- see "LITE_MAX" */
5023 if (p > LITE_CAP) p = LITE_CAP;
5024
5025 /* South-East of the player */
5026 // if (cave_floor_bold(zcave, p_ptr->py+1, p_ptr->px+1))
5027 if (cave_los(zcave, p_ptr->py+1, p_ptr->px+1)) {
5028 cave_lite_hack(p_ptr->py+2, p_ptr->px+2);
5029 }
5030
5031 /* South-West of the player */
5032 // if (cave_floor_bold(zcave, p_ptr->py+1, p_ptr->px-1))
5033 if (cave_los(zcave, p_ptr->py+1, p_ptr->px-1)) {
5034 cave_lite_hack(p_ptr->py+2, p_ptr->px-2);
5035 }
5036
5037 /* North-East of the player */
5038 // if (cave_floor_bold(zcave, p_ptr->py-1, p_ptr->px+1))
5039 if (cave_los(zcave, p_ptr->py-1, p_ptr->px+1)) {
5040 cave_lite_hack(p_ptr->py-2, p_ptr->px+2);
5041 }
5042
5043 /* North-West of the player */
5044 // if (cave_floor_bold(zcave, p_ptr->py-1, p_ptr->px-1))
5045 if (cave_los(zcave, p_ptr->py-1, p_ptr->px-1)) {
5046 cave_lite_hack(p_ptr->py-2, p_ptr->px-2);
5047 }
5048
5049 /* Maximal north */
5050 min_y = p_ptr->py - p;
5051 if (min_y < 0) min_y = 0;
5052
5053 /* Maximal south */
5054 max_y = p_ptr->py + p;
5055 if (max_y > p_ptr->cur_hgt-1) max_y = p_ptr->cur_hgt-1;
5056
5057 /* Maximal west */
5058 min_x = p_ptr->px - p;
5059 if (min_x < 0) min_x = 0;
5060
5061 /* Maximal east */
5062 max_x = p_ptr->px + p;
5063 if (max_x > p_ptr->cur_wid-1) max_x = p_ptr->cur_wid-1;
5064
5065 /* Scan the maximal box */
5066 for (y = min_y; y <= max_y; y++) {
5067 for (x = min_x; x <= max_x; x++) {
5068 int dy = (p_ptr->py > y) ? (p_ptr->py - y) : (y - p_ptr->py);
5069 int dx = (p_ptr->px > x) ? (p_ptr->px - x) : (x - p_ptr->px);
5070
5071 /* Skip the "central" grids (above) */
5072 if ((dy <= 2) && (dx <= 2)) continue;
5073
5074 /* Hack -- approximate the distance */
5075 d = (dy > dx) ? (dy + (dx>>1)) : (dx + (dy>>1));
5076
5077 /* Skip distant grids */
5078 if (d > p) continue;
5079
5080 /* Viewable, nearby, grids get "torch lit" */
5081 if (player_has_los_bold(Ind, y, x)) {
5082 /* This grid is "torch lit" */
5083 cave_lite_hack(y, x);
5084 }
5085 }
5086 }
5087 }
5088
5089
5090 /*** Complete the algorithm ***/
5091
5092 /* Draw the new grids */
5093 for (i = 0; i < p_ptr->lite_n; i++) {
5094 y = p_ptr->lite_y[i];
5095 x = p_ptr->lite_x[i];
5096
5097 /* Update fresh grids */
5098 if (zcave[y][x].info & CAVE_TEMP) continue;
5099
5100 /* Note */
5101 note_spot_depth(wpos, y, x);
5102
5103 /* Redraw */
5104 everyone_lite_spot(wpos, y, x);
5105 }
5106
5107 /* Clear them all */
5108 for (i = 0; i < p_ptr->temp_n; i++) {
5109 y = p_ptr->temp_y[i];
5110 x = p_ptr->temp_x[i];
5111
5112 /* No longer in the array */
5113 zcave[y][x].info &= ~CAVE_TEMP;
5114
5115 /* Update stale grids */
5116 if (p_ptr->cave_flag[y][x] & CAVE_LITE) continue;
5117
5118 /* Redraw */
5119 everyone_lite_spot(wpos, y, x);
5120 }
5121
5122 /* None left */
5123 p_ptr->temp_n = 0;
5124 }
5125
5126
5127
5128
5129
5130
5131
5132 /*
5133 * Clear the viewable space
5134 */
5135 void forget_view(int Ind)
5136 {
5137 player_type *p_ptr = Players[Ind];
5138 int i;
5139
5140 byte *w_ptr;
5141
5142 /* None to forget */
5143 if (!(p_ptr->view_n)) return;
5144
5145 /* Clear them all */
5146 for (i = 0; i < p_ptr->view_n; i++)
5147 {
5148 int y = p_ptr->view_y[i];
5149 int x = p_ptr->view_x[i];
5150
5151 /* Access the grid */
5152 w_ptr = &p_ptr->cave_flag[y][x];
5153
5154 /* Forget that the grid is viewable */
5155 *w_ptr &= ~CAVE_VIEW;
5156
5157 /* Update the screen */
5158 lite_spot(Ind, y, x);
5159 }
5160
5161 /* None left */
5162 p_ptr->view_n = 0;
5163 }
5164
5165
5166
5167 /*
5168 * This macro allows us to efficiently add a grid to the "view" array,
5169 * note that we are never called for illegal grids, or for grids which
5170 * have already been placed into the "view" array, and we are never
5171 * called when the "view" array is full.
5172 *
5173 * I'm again assuming that using p_ptr is OK (see above) --KLJ--
5174 */
5175 #define cave_view_hack(W,Y,X) \
5176 (*(W)) |= CAVE_VIEW; \
5177 p_ptr->view_y[p_ptr->view_n] = (Y); \
5178 p_ptr->view_x[p_ptr->view_n] = (X); \
5179 p_ptr->view_n++
5180
5181
5182
5183 #ifdef USE_OLD_UPDATE_VIEW
5184 /*
5185 * Helper function for "update_view()" below
5186 *
5187 * We are checking the "viewability" of grid (y,x) by the player.
5188 *
5189 * This function assumes that (y,x) is legal (i.e. on the map).
5190 *
5191 * Grid (y1,x1) is on the "diagonal" between (py,px) and (y,x)
5192 * Grid (y2,x2) is "adjacent", also between (py,px) and (y,x).
5193 *
5194 * Note that we are using the "CAVE_XTRA" field for marking grids as
5195 * "easily viewable". This bit is cleared at the end of "update_view()".
5196 *
5197 * This function adds (y,x) to the "viewable set" if necessary.
5198 *
5199 * This function now returns "TRUE" if vision is "blocked" by grid (y,x).
5200 */
5201
5202
5203 static bool update_view_aux(int Ind, int y, int x, int y1, int x1, int y2, int x2)
5204 {
5205 player_type *p_ptr = Players[Ind];
5206
5207 bool f1, f2, v1, v2, z1, z2, wall;
5208
5209 cave_type *c_ptr;
5210 byte *w_ptr;
5211
5212 cave_type *g1_c_ptr;
5213 cave_type *g2_c_ptr;
5214
5215 byte *g1_w_ptr;
5216 byte *g2_w_ptr;
5217
5218 struct worldpos *wpos = &p_ptr->wpos;
5219 cave_type **zcave;
5220 if (!(zcave = getcave(wpos))) return FALSE;
5221
5222 if (y < 0 || y >= MAX_HGT || x < 0 || x >= MAX_WID) return(FALSE);
5223
5224 /* Access the grids */
5225 g1_c_ptr = &zcave[y1][x1];
5226 g2_c_ptr = &zcave[y2][x2];
5227
5228 g1_w_ptr = &p_ptr->cave_flag[y1][x1];
5229 g2_w_ptr = &p_ptr->cave_flag[y2][x2];
5230
5231
5232 /* Check for walls */
5233 f1 = (cave_los_grid(g1_c_ptr));
5234 f2 = (cave_los_grid(g2_c_ptr));
5235
5236 /* Totally blocked by physical walls */
5237 if (!f1 && !f2) return (TRUE);
5238
5239
5240 /* Check for visibility */
5241 v1 = (f1 && (*(g1_w_ptr) & CAVE_VIEW));
5242 v2 = (f2 && (*(g2_w_ptr) & CAVE_VIEW));
5243
5244 /* Totally blocked by "unviewable neighbors" */
5245 if (!v1 && !v2) return (TRUE);
5246
5247
5248 /* Access the grid */
5249 c_ptr = &zcave[y][x];
5250 w_ptr = &p_ptr->cave_flag[y][x];
5251
5252
5253 /* Check for walls */
5254 wall = (!cave_los_grid(c_ptr));
5255
5256
5257 /* Check the "ease" of visibility */
5258 z1 = (v1 && (g1_c_ptr->info & CAVE_XTRA));
5259 z2 = (v2 && (g2_c_ptr->info & CAVE_XTRA));
5260
5261 /* Hack -- "easy" plus "easy" yields "easy" */
5262 if (z1 && z2)
5263 {
5264 c_ptr->info |= CAVE_XTRA;
5265
5266 cave_view_hack(w_ptr, y, x);
5267
5268 return (wall);
5269 }
5270
5271 /* Hack -- primary "easy" yields "viewed" */
5272 if (z1)
5273 {
5274 cave_view_hack(w_ptr, y, x);
5275
5276 return (wall);
5277 }
5278
5279
5280 /* Hack -- "view" plus "view" yields "view" */
5281 if (v1 && v2)
5282 {
5283 /* c_ptr->info |= CAVE_XTRA; */
5284
5285 cave_view_hack(w_ptr, y, x);
5286
5287 return (wall);
5288 }
5289
5290
5291 /* Mega-Hack -- the "los()" function works poorly on walls */
5292 if (wall)
5293 {
5294 cave_view_hack(w_ptr, y, x);
5295
5296 return (wall);
5297 }
5298
5299
5300 /* Hack -- check line of sight */
5301 if (los(wpos, p_ptr->py, p_ptr->px, y, x))
5302 {
5303 cave_view_hack(w_ptr, y, x);
5304
5305 return (wall);
5306 }
5307
5308
5309 /* Assume no line of sight. */
5310 return (TRUE);
5311 }
5312
5313
5314
5315 /*
5316 * Calculate the viewable space
5317 *
5318 * 1: Process the player
5319 * 1a: The player is always (easily) viewable
5320 * 2: Process the diagonals
5321 * 2a: The diagonals are (easily) viewable up to the first wall
5322 * 2b: But never go more than 2/3 of the "full" distance
5323 * 3: Process the main axes
5324 * 3a: The main axes are (easily) viewable up to the first wall
5325 * 3b: But never go more than the "full" distance
5326 * 4: Process sequential "strips" in each of the eight octants
5327 * 4a: Each strip runs along the previous strip
5328 * 4b: The main axes are "previous" to the first strip
5329 * 4c: Process both "sides" of each "direction" of each strip
5330 * 4c1: Each side aborts as soon as possible
5331 * 4c2: Each side tells the next strip how far it has to check
5332 *
5333 * Note that the octant processing involves some pretty interesting
5334 * observations involving when a grid might possibly be viewable from
5335 * a given grid, and on the order in which the strips are processed.
5336 *
5337 * Note the use of the mathematical facts shown below, which derive
5338 * from the fact that (1 < sqrt(2) < 1.5), and that the length of the
5339 * hypotenuse of a right triangle is primarily determined by the length
5340 * of the longest side, when one side is small, and is strictly less
5341 * than one-and-a-half times as long as the longest side when both of
5342 * the sides are large.
5343 *
5344 * if (manhatten(dy,dx) < R) then (hypot(dy,dx) < R)
5345 * if (manhatten(dy,dx) > R*3/2) then (hypot(dy,dx) > R)
5346 *
5347 * hypot(dy,dx) is approximated by (dx+dy+MAX(dx,dy)) / 2
5348 *
5349 * These observations are important because the calculation of the actual
5350 * value of "hypot(dx,dy)" is extremely expensive, involving square roots,
5351 * while for small values (up to about 20 or so), the approximations above
5352 * are correct to within an error of at most one grid or so.
5353 *
5354 * Observe the use of "full" and "over" in the code below, and the use of
5355 * the specialized calculation involving "limit", all of which derive from
5356 * the observations given above. Basically, we note that the "circle" of
5357 * view is completely contained in an "octagon" whose bounds are easy to
5358 * determine, and that only a few steps are needed to derive the actual
5359 * bounds of the circle given the bounds of the octagon.
5360 *
5361 * Note that by skipping all the grids in the corners of the octagon, we
5362 * place an upper limit on the number of grids in the field of view, given
5363 * that "full" is never more than 20. Of the 1681 grids in the "square" of
5364 * view, only about 1475 of these are in the "octagon" of view, and even
5365 * fewer are in the "circle" of view, so 1500 or 1536 is more than enough
5366 * entries to completely contain the actual field of view.
5367 *
5368 * Note also the care taken to prevent "running off the map". The use of
5369 * explicit checks on the "validity" of the "diagonal", and the fact that
5370 * the loops are never allowed to "leave" the map, lets "update_view_aux()"
5371 * use the optimized "cave_floor_bold()" macro, and to avoid the overhead
5372 * of multiple checks on the validity of grids.
5373 *
5374 * Note the "optimizations" involving the "se","sw","ne","nw","es","en",
5375 * "ws","wn" variables. They work like this: While travelling down the
5376 * south-bound strip just to the east of the main south axis, as soon as
5377 * we get to a grid which does not "transmit" viewing, if all of the strips
5378 * preceding us (in this case, just the main axis) had terminated at or before
5379 * the same point, then we can stop, and reset the "max distance" to ourself.
5380 * So, each strip (named by major axis plus offset, thus "se" in this case)
5381 * maintains a "blockage" variable, initialized during the main axis step,
5382 * and checks it whenever a blockage is observed. After processing each
5383 * strip as far as the previous strip told us to process, the next strip is
5384 * told not to go farther than the current strip's farthest viewable grid,
5385 * unless open space is still available. This uses the "k" variable.
5386 *
5387 * Note the use of "inline" macros for efficiency. The "cave_floor_grid()"
5388 * macro is a replacement for "cave_floor_bold()" which takes a pointer to
5389 * a cave grid instead of its location. The "cave_view_hack()" macro is a
5390 * chunk of code which adds the given location to the "view" array if it
5391 * is not already there, using both the actual location and a pointer to
5392 * the cave grid. See above.
5393 *
5394 * By the way, the purpose of this code is to reduce the dependancy on the
5395 * "los()" function which is slow, and, in some cases, not very accurate.
5396 *
5397 * It is very possible that I am the only person who fully understands this
5398 * function, and for that I am truly sorry, but efficiency was very important
5399 * and the "simple" version of this function was just not fast enough. I am
5400 * more than willing to replace this function with a simpler one, if it is
5401 * equally efficient, and especially willing if the new function happens to
5402 * derive "reverse-line-of-sight" at the same time, since currently monsters
5403 * just use an optimized hack of "you see me, so I see you", and then use the
5404 * actual "projectable()" function to check spell attacks.
5405 *
5406 * Well, I for one don't understand it, so I'm hoping I didn't screw anything
5407 * up while trying to do this. --KLJ--
5408 */
5409
5410 /* Hmm, this function doesn't seem to be very "mangworld" friendly...
5411 lets add some speedbumps/sanity checks.
5412 -APD-
5413
5414 With my new "invisible wall" code this shouldn't be neccecary.
5415
5416 */
5417
5418 /* TODO: Hrm, recent variants seem to get better algorithm
5419 * - let's port them! */
5420
5421 void update_view(int Ind)
5422 {
5423 player_type *p_ptr = Players[Ind];
5424
5425 int n, m, d, k, y, x, z;
5426
5427 int se, sw, ne, nw, es, en, ws, wn;
5428
5429 int full, over;
5430
5431 int y_max = MAX_HGT - 1;
5432 int x_max = MAX_WID - 1;
5433
5434 cave_type *c_ptr;
5435 byte *w_ptr;
5436 bool unmap = FALSE;
5437
5438 cave_type **zcave;
5439 struct worldpos *wpos;
5440 wpos = &p_ptr->wpos;
5441 if (!(zcave = getcave(wpos))) return;
5442
5443 if (p_ptr->wpos.wz) {
5444 dun_level *l_ptr = getfloor(&p_ptr->wpos);
5445 if (l_ptr && l_ptr->flags1 & LF1_NO_MAP) unmap = TRUE;
5446 }
5447
5448
5449 /*** Initialize ***/
5450
5451 /* Optimize */
5452 if (p_ptr->view_reduce_view && istown(wpos)) /* town */
5453 {
5454 /* Full radius (10) */
5455 full = MAX_SIGHT / 2;
5456
5457 /* Octagon factor (15) */
5458 over = MAX_SIGHT * 3 / 4;
5459 }
5460
5461 /* Normal */
5462 else
5463 {
5464 /* Full radius (20) */
5465 full = MAX_SIGHT;
5466
5467 /* Octagon factor (30) */
5468 over = MAX_SIGHT * 3 / 2;
5469 }
5470
5471
5472 /*** Step 0 -- Begin ***/
5473
5474 /* Save the old "view" grids for later */
5475 for (n = 0; n < p_ptr->view_n; n++) {
5476 y = p_ptr->view_y[n];
5477 x = p_ptr->view_x[n];
5478
5479 /* Access the grid */
5480 c_ptr = &zcave[y][x];
5481 w_ptr = &p_ptr->cave_flag[y][x];
5482
5483 /* Mark the grid as not in "view" */
5484 *w_ptr &= ~(CAVE_VIEW);
5485
5486 /* Mark the grid as "seen" */
5487 c_ptr->info |= CAVE_TEMP;
5488
5489 /* Add it to the "seen" set */
5490 p_ptr->temp_y[p_ptr->temp_n] = y;
5491 p_ptr->temp_x[p_ptr->temp_n] = x;
5492 p_ptr->temp_n++;
5493 }
5494
5495 /* Start over with the "view" array */
5496 p_ptr->view_n = 0;
5497
5498
5499 /*** Step 1 -- adjacent grids ***/
5500
5501 /* Now start on the player */
5502 y = p_ptr->py;
5503 x = p_ptr->px;
5504
5505 /* Access the grid */
5506 c_ptr = &zcave[y][x];
5507 w_ptr = &p_ptr->cave_flag[y][x];
5508
5509 /* Assume the player grid is easily viewable */
5510 c_ptr->info |= CAVE_XTRA;
5511
5512 /* Assume the player grid is viewable */
5513 cave_view_hack(w_ptr, y, x);
5514
5515
5516 /*** Step 2 -- Major Diagonals ***/
5517
5518 /* Hack -- Limit */
5519 z = full * 2 / 3;
5520
5521 /* Scan south-east */
5522 for (d = 1; d <= z; d++) {
5523 //superfluous if (!in_bounds_array(y+d, x+d)) break;
5524 if (y + d >= MAX_HGT) break;
5525 c_ptr = &zcave[y+d][x+d];
5526 w_ptr = &p_ptr->cave_flag[y+d][x+d];
5527 c_ptr->info |= CAVE_XTRA;
5528 cave_view_hack(w_ptr, y+d, x+d);
5529 if (!cave_los_grid(c_ptr)) break;
5530 }
5531
5532 /* Scan south-west */
5533 for (d = 1; d <= z; d++) {
5534 //superfluous if (!in_bounds_array(y+d, x-d)) break;
5535 if (y + d >= MAX_HGT) break;
5536 c_ptr = &zcave[y+d][x-d];
5537 w_ptr = &p_ptr->cave_flag[y+d][x-d];
5538 c_ptr->info |= CAVE_XTRA;
5539 cave_view_hack(w_ptr, y+d, x-d);
5540 if (!cave_los_grid(c_ptr)) break;
5541 }
5542
5543 /* Scan north-east */
5544 for (d = 1; d <= z; d++) {
5545 //superfluous if (!in_bounds_array(y-d, x+d)) break;
5546 if (d > y) break;
5547 c_ptr = &zcave[y-d][x+d];
5548 w_ptr = &p_ptr->cave_flag[y-d][x+d];
5549 c_ptr->info |= CAVE_XTRA;
5550 cave_view_hack(w_ptr, y-d, x+d);
5551 if (!cave_los_grid(c_ptr)) break;
5552 }
5553
5554 /* Scan north-west */
5555 for (d = 1; d <= z; d++) {
5556 //superfluous if (!in_bounds_array(y-d, x-d)) break;
5557 if (d > y) break;
5558 c_ptr = &zcave[y-d][x-d];
5559 w_ptr = &p_ptr->cave_flag[y-d][x-d];
5560 c_ptr->info |= CAVE_XTRA;
5561 cave_view_hack(w_ptr, y-d, x-d);
5562 if (!cave_los_grid(c_ptr)) break;
5563 }
5564
5565
5566 /*** Step 3 -- major axes ***/
5567
5568 /* Scan south */
5569 for (d = 1; d <= full; d++) {
5570 /*if (y + d >= MAX_HGT) break;*/
5571 c_ptr = &zcave[y+d][x];
5572 w_ptr = &p_ptr->cave_flag[y+d][x];
5573 c_ptr->info |= CAVE_XTRA;
5574 cave_view_hack(w_ptr, y+d, x);
5575 if (!cave_los_grid(c_ptr)) break;
5576 //superfluous if (!in_bounds_array(y+d+1, x)) break;
5577 }
5578
5579 /* Initialize the "south strips" */
5580 se = sw = d;
5581
5582 /* Scan north */
5583 for (d = 1; d <= full; d++) {
5584 /*if (d > y) break;*/
5585 c_ptr = &zcave[y-d][x];
5586 w_ptr = &p_ptr->cave_flag[y-d][x];
5587 c_ptr->info |= CAVE_XTRA;
5588 cave_view_hack(w_ptr, y-d, x);
5589 if (!cave_los_grid(c_ptr)) break;
5590 //superfluous if (!in_bounds_array(y-d-1, x)) break;
5591 }
5592
5593 /* Initialize the "north strips" */
5594 ne = nw = d;
5595
5596 /* Scan east */
5597 for (d = 1; d <= full; d++) {
5598 c_ptr = &zcave[y][x+d];
5599 w_ptr = &p_ptr->cave_flag[y][x+d];
5600 c_ptr->info |= CAVE_XTRA;
5601 cave_view_hack(w_ptr, y, x+d);
5602 if (!cave_los_grid(c_ptr)) break;
5603 //superfluous if (!in_bounds_array(y, x+d+1)) break;
5604 }
5605
5606 /* Initialize the "east strips" */
5607 es = en = d;
5608
5609 /* Scan west */
5610 for (d = 1; d <= full; d++) {
5611 c_ptr = &zcave[y][x-d];
5612 w_ptr = &p_ptr->cave_flag[y][x-d];
5613 c_ptr->info |= CAVE_XTRA;
5614 cave_view_hack(w_ptr, y, x-d);
5615 if (!cave_los_grid(c_ptr)) break;
5616 //superfluous if (!in_bounds_array(y, x-d-1)) break;
5617 }
5618
5619 /* Initialize the "west strips" */
5620 ws = wn = d;
5621
5622
5623 /*** Step 4 -- Divide each "octant" into "strips" ***/
5624
5625 /* Now check each "diagonal" (in parallel) */
5626 for (n = 1; n <= over / 2; n++) {
5627 int ypn, ymn, xpn, xmn;
5628
5629
5630 /* Acquire the "bounds" of the maximal circle */
5631 z = over - n - n;
5632 if (z > full - n) z = full - n;
5633 while ((z + n + (n>>1)) > full) z--;
5634
5635
5636 /* Access the four diagonal grids */
5637 ypn = y + n;
5638 ymn = y - n;
5639 xpn = x + n;
5640 xmn = x - n;
5641
5642
5643 /* South strip */
5644 if (ypn < y_max) {
5645 /* Maximum distance */
5646 m = MIN(z, y_max - ypn);
5647
5648 /* East side */
5649 if ((xpn <= x_max) && (n < se)) {
5650 /* Scan */
5651 for (k = n, d = 1; d <= m; d++) {
5652 /*if (ypn + d >= MAX_HGT) break; */
5653
5654 /* Check grid "d" in strip "n", notice "blockage" */
5655 if (update_view_aux(Ind, ypn+d, xpn, ypn+d-1, xpn-1, ypn+d-1, xpn))
5656 {
5657 if (n + d >= se) break;
5658 }
5659
5660 /* Track most distant "non-blockage" */
5661 else
5662 {
5663 k = n + d;
5664 }
5665 }
5666
5667 /* Limit the next strip */
5668 se = k + 1;
5669 }
5670
5671 /* West side */
5672 if ((xmn >= 0) && (n < sw)) {
5673 /* Scan */
5674 for (k = n, d = 1; d <= m; d++) {
5675 /*if (ypn + d >= MAX_HGT) break;*/
5676
5677 /* Check grid "d" in strip "n", notice "blockage" */
5678 if (update_view_aux(Ind, ypn+d, xmn, ypn+d-1, xmn+1, ypn+d-1, xmn))
5679 {
5680 if (n + d >= sw) break;
5681 }
5682
5683 /* Track most distant "non-blockage" */
5684 else
5685 {
5686 k = n + d;
5687 }
5688
5689 }
5690
5691 /* Limit the next strip */
5692 sw = k + 1;
5693 }
5694 }
5695
5696
5697 /* North strip */
5698 if (ymn > 0)
5699 {
5700 /* Maximum distance */
5701 m = MIN(z, ymn);
5702
5703 /* East side */
5704 if ((xpn <= x_max) && (n < ne))
5705 {
5706 /* Scan */
5707 for (k = n, d = 1; d <= m; d++)
5708 {
5709 /*if (d > ymn) break;*/
5710
5711 /* Check grid "d" in strip "n", notice "blockage" */
5712 if (update_view_aux(Ind, ymn-d, xpn, ymn-d+1, xpn-1, ymn-d+1, xpn))
5713 {
5714 if (n + d >= ne) break;
5715 }
5716
5717 /* Track most distant "non-blockage" */
5718 else
5719 {
5720 k = n + d;
5721 }
5722 }
5723
5724 /* Limit the next strip */
5725 ne = k + 1;
5726 }
5727
5728 /* West side */
5729 if ((xmn >= 0) && (n < nw))
5730 {
5731 /* Scan */
5732 for (k = n, d = 1; d <= m; d++)
5733 {
5734 /*if (d > ymn) break;*/
5735
5736 /* Check grid "d" in strip "n", notice "blockage" */
5737 if (update_view_aux(Ind, ymn-d, xmn, ymn-d+1, xmn+1, ymn-d+1, xmn))
5738 {
5739 if (n + d >= nw) break;
5740 }
5741
5742 /* Track most distant "non-blockage" */
5743 else
5744 {
5745 k = n + d;
5746 }
5747 }
5748
5749 /* Limit the next strip */
5750 nw = k + 1;
5751 }
5752 }
5753
5754
5755 /* East strip */
5756 if (xpn < x_max)
5757 {
5758 /* Maximum distance */
5759 m = MIN(z, x_max - xpn);
5760
5761 /* South side */
5762 if ((ypn <= x_max) && (n < es))
5763 {
5764 /* Scan */
5765 for (k = n, d = 1; d <= m; d++)
5766 {
5767 /*if (ypn >= MAX_HGT) break;*/
5768
5769 /* Check grid "d" in strip "n", notice "blockage" */
5770 if (update_view_aux(Ind, ypn, xpn+d, ypn-1, xpn+d-1, ypn, xpn+d-1))
5771 {
5772 if (n + d >= es) break;
5773 }
5774
5775 /* Track most distant "non-blockage" */
5776 else
5777 {
5778 k = n + d;
5779 }
5780 }
5781
5782 /* Limit the next strip */
5783 es = k + 1;
5784 }
5785
5786 /* North side */
5787 if ((ymn >= 0) && (n < en))
5788 {
5789 /* Scan */
5790 for (k = n, d = 1; d <= m; d++)
5791 {
5792 /*if (ymn >= MAX_HGT) break;*/
5793
5794 /* Check grid "d" in strip "n", notice "blockage" */
5795 if (update_view_aux(Ind, ymn, xpn+d, ymn+1, xpn+d-1, ymn, xpn+d-1))
5796 {
5797 if (n + d >= en) break;
5798 }
5799
5800 /* Track most distant "non-blockage" */
5801 else
5802 {
5803 k = n + d;
5804 }
5805 }
5806
5807 /* Limit the next strip */
5808 en = k + 1;
5809 }
5810 }
5811
5812
5813 /* West strip */
5814 if (xmn > 0)
5815 {
5816 /* Maximum distance */
5817 m = MIN(z, xmn);
5818
5819 /* South side */
5820 if ((ypn <= y_max) && (n < ws))
5821 {
5822 /* Scan */
5823 for (k = n, d = 1; d <= m; d++)
5824 {
5825 /*if (ypn >= MAX_HGT) break;*/
5826
5827 /* Check grid "d" in strip "n", notice "blockage" */
5828 if (update_view_aux(Ind, ypn, xmn-d, ypn-1, xmn-d+1, ypn, xmn-d+1))
5829 {
5830 if (n + d >= ws) break;
5831 }
5832
5833 /* Track most distant "non-blockage" */
5834 else
5835 {
5836 k = n + d;
5837 }
5838 }
5839
5840 /* Limit the next strip */
5841 ws = k + 1;
5842 }
5843
5844 /* North side */
5845 if ((ymn >= 0) && (n < wn))
5846 {
5847 /* Scan */
5848 for (k = n, d = 1; d <= m; d++)
5849 {
5850 /*if (ymn >= MAX_HGT) break;*/
5851
5852 /* Check grid "d" in strip "n", notice "blockage" */
5853 if (update_view_aux(Ind, ymn, xmn-d, ymn+1, xmn-d+1, ymn, xmn-d+1))
5854 {
5855 if (n + d >= wn) break;
5856 }
5857
5858 /* Track most distant "non-blockage" */
5859 else
5860 {
5861 k = n + d;
5862 }
5863 }
5864
5865 /* Limit the next strip */
5866 wn = k + 1;
5867 }
5868 }
5869 }
5870
5871
5872 /*** Step 5 -- Complete the algorithm ***/
5873
5874 /* Update all the new grids */
5875 for (n = 0; n < p_ptr->view_n; n++)
5876 {
5877 y = p_ptr->view_y[n];
5878 x = p_ptr->view_x[n];
5879
5880 /* Access the grid */
5881 c_ptr = &zcave[y][x];
5882
5883 /* Clear the "CAVE_XTRA" flag */
5884 c_ptr->info &= ~CAVE_XTRA;
5885
5886 /* Update only newly viewed grids */
5887 if (c_ptr->info & CAVE_TEMP) continue;
5888
5889 /* Note */
5890 note_spot(Ind, y, x);
5891
5892 /* Redraw */
5893 lite_spot(Ind, y, x);
5894 }
5895
5896 /* Wipe the old grids, update as needed */
5897 for (n = 0; n < p_ptr->temp_n; n++)
5898 {
5899 y = p_ptr->temp_y[n];
5900 x = p_ptr->temp_x[n];
5901
5902 /* Access the grid */
5903 c_ptr = &zcave[y][x];
5904 w_ptr = &p_ptr->cave_flag[y][x];
5905
5906 /* No longer in the array */
5907 c_ptr->info &= ~CAVE_TEMP;
5908
5909 /* Update only non-viewable grids */
5910 if (*w_ptr & CAVE_VIEW) continue;
5911
5912 /* Forget it, dude */
5913 if (unmap)
5914 {
5915 u16b this_o_idx, next_o_idx = 0;
5916
5917 *w_ptr &= ~CAVE_MARK;
5918
5919 /* make player forget of objects too */
5920 /* too bad, traps cannot be forgotten this way.. */
5921 for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
5922 {
5923 /* Acquire next object */
5924 next_o_idx = o_list[this_o_idx].next_o_idx;
5925
5926 /* Forget the object */
5927 p_ptr->obj_vis[this_o_idx] = FALSE;
5928 }
5929 }
5930
5931 /* Redraw */
5932 lite_spot(Ind, y, x);
5933 }
5934
5935 /* None left */
5936 p_ptr->temp_n = 0;
5937 }
5938 #else /* USE_OLD_UPDATE_VIEW */
5939 /* New update_view code from ToME... but it was slower than ours in fact.
5940 * pfft
5941 */
5942
5943 /*
5944 * Maximum number of grids in a single octant
5945 */
5946 #define VINFO_MAX_GRIDS 161
5947
5948
5949 /*
5950 * Maximum number of slopes in a single octant
5951 */
5952 #define VINFO_MAX_SLOPES 126
5953
5954
5955 /*
5956 * Mask of bits used in a single octant
5957 */
5958 #define VINFO_BITS_3 0x3FFFFFFF
5959 #define VINFO_BITS_2 0xFFFFFFFF
5960 #define VINFO_BITS_1 0xFFFFFFFF
5961 #define VINFO_BITS_0 0xFFFFFFFF
5962
5963
5964 /*
5965 * Forward declare
5966 */
5967 typedef struct vinfo_type vinfo_type;
5968
5969
5970 /*
5971 * The 'vinfo_type' structure
5972 */
5973 struct vinfo_type
5974 {
5975 s16b grid_y[8];
5976 s16b grid_x[8];
5977
5978 u32b bits_3;
5979 u32b bits_2;
5980 u32b bits_1;
5981 u32b bits_0;
5982
5983 vinfo_type *next_0;
5984 vinfo_type *next_1;
5985
5986 byte y;
5987 byte x;
5988 byte d;
5989 byte r;
5990 };
5991
5992
5993
5994 /*
5995 * The array of "vinfo" objects, initialized by "vinfo_init()"
5996 */
5997 static vinfo_type vinfo[VINFO_MAX_GRIDS];
5998
5999
6000
6001
6002 /*
6003 * Slope scale factor
6004 */
6005 #define SCALE 100000L
6006
6007
6008 /*
6009 * Forward declare
6010 */
6011 typedef struct vinfo_hack vinfo_hack;
6012
6013
6014 /*
6015 * Temporary data used by "vinfo_init()"
6016 *
6017 * - Number of grids
6018 *
6019 * - Number of slopes
6020 *
6021 * - Slope values
6022 *
6023 * - Slope range per grid
6024 */
6025 struct vinfo_hack {
6026
6027 int num_slopes;
6028
6029 long slopes[VINFO_MAX_SLOPES];
6030
6031 long slopes_min[MAX_SIGHT+1][MAX_SIGHT+1];
6032 long slopes_max[MAX_SIGHT+1][MAX_SIGHT+1];
6033 };
6034
6035
6036
6037 /*
6038 * Sorting hook -- comp function -- array of long's (see below)
6039 *
6040 * We use "u" to point to an array of long integers.
6041 */
6042 /* Ind is utter dummy. */
6043 static bool ang_sort_comp_hook_longs(int Ind, vptr u, vptr v, int a, int b)
6044 {
6045 long *x = (long*)(u);
6046
6047 return (x[a] <= x[b]);
6048 }
6049
6050
6051 /*
6052 * Sorting hook -- comp function -- array of long's (see below)
6053 *
6054 * We use "u" to point to an array of long integers.
6055 */
6056 static void ang_sort_swap_hook_longs(int Ind, vptr u, vptr v, int a, int b)
6057 {
6058 long *x = (long*)(u);
6059
6060 long temp;
6061
6062 /* Swap */
6063 temp = x[a];
6064 x[a] = x[b];
6065 x[b] = temp;
6066 }
6067
6068
6069
6070 /*
6071 * Save a slope
6072 */
6073 static void vinfo_init_aux(vinfo_hack *hack, int y, int x, long m)
6074 {
6075 int i;
6076
6077 /* Handle "legal" slopes */
6078 if ((m > 0) && (m <= SCALE))
6079 {
6080 /* Look for that slope */
6081 for (i = 0; i < hack->num_slopes; i++)
6082 {
6083 if (hack->slopes[i] == m) break;
6084 }
6085
6086 /* New slope */
6087 if (i == hack->num_slopes)
6088 {
6089 /* Paranoia */
6090 if (hack->num_slopes >= VINFO_MAX_SLOPES)
6091 {
6092 quit_fmt("Too many slopes (%d)!",
6093 VINFO_MAX_SLOPES);
6094 }
6095
6096 /* Save the slope, and advance */
6097 hack->slopes[hack->num_slopes++] = m;
6098 }
6099 }
6100
6101 /* Track slope range */
6102 if (hack->slopes_min[y][x] > m) hack->slopes_min[y][x] = m;
6103 if (hack->slopes_max[y][x] < m) hack->slopes_max[y][x] = m;
6104 }
6105
6106
6107
6108 /*
6109 * Initialize the "vinfo" array
6110 *
6111 * Full Octagon (radius 20), Grids=1149
6112 *
6113 * Quadrant (south east), Grids=308, Slopes=251
6114 *
6115 * Octant (east then south), Grids=161, Slopes=126
6116 *
6117 * This function assumes that VINFO_MAX_GRIDS and VINFO_MAX_SLOPES
6118 * have the correct values, which can be derived by setting them to
6119 * a number which is too high, running this function, and using the
6120 * error messages to obtain the correct values.
6121 */
6122 errr vinfo_init(void)
6123 {
6124 int i, y, x;
6125
6126 long m;
6127
6128 vinfo_hack *hack;
6129
6130 int num_grids = 0;
6131
6132 int queue_head = 0;
6133 int queue_tail = 0;
6134 vinfo_type *queue[VINFO_MAX_GRIDS*2];
6135
6136
6137 /* Make hack */
6138 MAKE(hack, vinfo_hack);
6139
6140
6141 /* Analyze grids */
6142 for (y = 0; y <= MAX_SIGHT; ++y)
6143 {
6144 for (x = y; x <= MAX_SIGHT; ++x)
6145 {
6146 /* Skip grids which are out of sight range */
6147 if (distance(0, 0, y, x) > MAX_SIGHT) continue;
6148
6149 /* Default slope range */
6150 hack->slopes_min[y][x] = 999999999;
6151 hack->slopes_max[y][x] = 0;
6152
6153 /* Paranoia */
6154 if (num_grids >= VINFO_MAX_GRIDS)
6155 {
6156 quit_fmt("Too many grids (%d >= %d)!",
6157 num_grids, VINFO_MAX_GRIDS);
6158 }
6159
6160 /* Count grids */
6161 num_grids++;
6162
6163 /* Slope to the top right corner */
6164 m = SCALE * (1000L * y - 500) / (1000L * x + 500);
6165
6166 /* Handle "legal" slopes */
6167 vinfo_init_aux(hack, y, x, m);
6168
6169 /* Slope to top left corner */
6170 m = SCALE * (1000L * y - 500) / (1000L * x - 500);
6171
6172 /* Handle "legal" slopes */
6173 vinfo_init_aux(hack, y, x, m);
6174
6175 /* Slope to bottom right corner */
6176 m = SCALE * (1000L * y + 500) / (1000L * x + 500);
6177
6178 /* Handle "legal" slopes */
6179 vinfo_init_aux(hack, y, x, m);
6180
6181 /* Slope to bottom left corner */
6182 m = SCALE * (1000L * y + 500) / (1000L * x - 500);
6183
6184 /* Handle "legal" slopes */
6185 vinfo_init_aux(hack, y, x, m);
6186 }
6187 }
6188
6189
6190 /* Enforce maximal efficiency */
6191 if (num_grids < VINFO_MAX_GRIDS)
6192 {
6193 quit_fmt("Too few grids (%d < %d)!",
6194 num_grids, VINFO_MAX_GRIDS);
6195 }
6196
6197 /* Enforce maximal efficiency */
6198 if (hack->num_slopes < VINFO_MAX_SLOPES)
6199 {
6200 quit_fmt("Too few slopes (%d < %d)!",
6201 hack->num_slopes, VINFO_MAX_SLOPES);
6202 }
6203
6204
6205 /* Sort slopes numerically */
6206 ang_sort_comp = ang_sort_comp_hook_longs;
6207
6208 /* Sort slopes numerically */
6209 ang_sort_swap = ang_sort_swap_hook_longs;
6210
6211 /* Sort the (unique) slopes */
6212 ang_sort(0, hack->slopes, NULL, hack->num_slopes);
6213
6214
6215
6216 /* Enqueue player grid */
6217 queue[queue_tail++] = &vinfo[0];
6218
6219 /* Process queue */
6220 while (queue_head < queue_tail)
6221 {
6222 int e;
6223
6224 vinfo_type *p;
6225
6226
6227 /* Index */
6228 e = queue_head;
6229
6230 /* Dequeue next grid */
6231 p = queue[queue_head++];
6232
6233 /* Location of main grid */
6234 y = vinfo[e].grid_y[0];
6235 x = vinfo[e].grid_x[0];
6236
6237
6238 /* Compute grid offsets */
6239 vinfo[e].grid_y[0] = +y; vinfo[e].grid_x[0] = +x;
6240 vinfo[e].grid_y[1] = +x; vinfo[e].grid_x[1] = +y;
6241 vinfo[e].grid_y[2] = +x; vinfo[e].grid_x[2] = -y;
6242 vinfo[e].grid_y[3] = +y; vinfo[e].grid_x[3] = -x;
6243 vinfo[e].grid_y[4] = -y; vinfo[e].grid_x[4] = -x;
6244 vinfo[e].grid_y[5] = -x; vinfo[e].grid_x[5] = -y;
6245 vinfo[e].grid_y[6] = -x; vinfo[e].grid_x[6] = +y;
6246 vinfo[e].grid_y[7] = -y; vinfo[e].grid_x[7] = +x;
6247
6248
6249 /* Analyze slopes */
6250 for (i = 0; i < hack->num_slopes; ++i)
6251 {
6252 m = hack->slopes[i];
6253
6254 /* Memorize intersection slopes (for non-player-grids) */
6255 if ((e > 0) &&
6256 (hack->slopes_min[y][x] < m) &&
6257 (m < hack->slopes_max[y][x]))
6258 {
6259 switch (i / 32)
6260 {
6261 case 3: vinfo[e].bits_3 |= (1L << (i % 32)); break;
6262 case 2: vinfo[e].bits_2 |= (1L << (i % 32)); break;
6263 case 1: vinfo[e].bits_1 |= (1L << (i % 32)); break;
6264 case 0: vinfo[e].bits_0 |= (1L << (i % 32)); break;
6265 }
6266 }
6267 }
6268
6269
6270 /* Default */
6271 vinfo[e].next_0 = &vinfo[0];
6272
6273 /* Grid next child */
6274 if (distance(0, 0, y, x+1) <= MAX_SIGHT)
6275 {
6276 if ((queue[queue_tail-1]->grid_y[0] != y) ||
6277 (queue[queue_tail-1]->grid_x[0] != x + 1))
6278 {
6279 vinfo[queue_tail].grid_y[0] = y;
6280 vinfo[queue_tail].grid_x[0] = x + 1;
6281 queue[queue_tail] = &vinfo[queue_tail];
6282 queue_tail++;
6283 }
6284
6285 vinfo[e].next_0 = &vinfo[queue_tail - 1];
6286 }
6287
6288
6289 /* Default */
6290 vinfo[e].next_1 = &vinfo[0];
6291
6292 /* Grid diag child */
6293 if (distance(0, 0, y+1, x+1) <= MAX_SIGHT)
6294 {
6295 if ((queue[queue_tail-1]->grid_y[0] != y + 1) ||
6296 (queue[queue_tail-1]->grid_x[0] != x + 1))
6297 {
6298 vinfo[queue_tail].grid_y[0] = y + 1;
6299 vinfo[queue_tail].grid_x[0] = x + 1;
6300 queue[queue_tail] = &vinfo[queue_tail];
6301 queue_tail++;
6302 }
6303
6304 vinfo[e].next_1 = &vinfo[queue_tail - 1];
6305 }
6306
6307
6308 /* Hack -- main diagonal has special children */
6309 if (y == x) vinfo[e].next_0 = vinfo[e].next_1;
6310
6311
6312 /* Extra values */
6313 vinfo[e].y = y;
6314 vinfo[e].x = x;
6315 vinfo[e].d = ((y > x) ? (y + x/2) : (x + y/2));
6316 vinfo[e].r = ((!y) ? x : (!x) ? y : (y == x) ? y : 0);
6317 }
6318
6319
6320 /* Verify maximal bits XXX XXX XXX */
6321 if (((vinfo[1].bits_3 | vinfo[2].bits_3) != VINFO_BITS_3) ||
6322 ((vinfo[1].bits_2 | vinfo[2].bits_2) != VINFO_BITS_2) ||
6323 ((vinfo[1].bits_1 | vinfo[2].bits_1) != VINFO_BITS_1) ||
6324 ((vinfo[1].bits_0 | vinfo[2].bits_0) != VINFO_BITS_0))
6325 {
6326 quit("Incorrect bit masks!");
6327 }
6328
6329
6330 /* Kill hack */
6331 KILL(hack, vinfo_hack);
6332
6333
6334 /* Success */
6335 return (0);
6336 }
6337
6338
6339 void update_view(int Ind)
6340 {
6341 player_type *p_ptr = Players[Ind];
6342
6343
6344 int full, over;
6345 int o, n;
6346 int y, x;
6347 u16b info;
6348
6349 #if 0
6350 int y_max = p_ptr->cur_hgt - 1;
6351 int x_max = p_ptr->cur_wid - 1;
6352 #else /* Inefficient, but prevents south-west dead angle bug.. */
6353 int y_max = MAX_HGT - 1;
6354 int x_max = MAX_WID - 1;
6355 #endif /* 0 */
6356
6357 int py = p_ptr->py;
6358 int px = p_ptr->px;
6359
6360
6361 cave_type *c_ptr;
6362 byte *w_ptr;
6363 bool unmap = FALSE;
6364
6365 cave_type **zcave;
6366 struct worldpos *wpos;
6367 wpos = &p_ptr->wpos;
6368 if (!(zcave = getcave(wpos))) return;
6369 if (p_ptr->wpos.wz) {
6370 dun_level *l_ptr = getfloor(&p_ptr->wpos);
6371 if (l_ptr && l_ptr->flags1 & LF1_NO_MAP) unmap = TRUE;
6372 }
6373
6374
6375 /*** Initialize ***/
6376
6377 #if 0
6378 /* Optimize */
6379 if (p_ptr->view_reduce_view && istown(wpos)) /* town */
6380 {
6381 /* Full radius (10) */
6382 full = MAX_SIGHT / 2;
6383
6384 /* Octagon factor (15) */
6385 over = MAX_SIGHT * 3 / 4;
6386 }
6387
6388 /* Normal */
6389 else
6390 {
6391 /* Full radius (20) */
6392 full = MAX_SIGHT;
6393
6394 /* Octagon factor (30) */
6395 over = MAX_SIGHT * 3 / 2;
6396 }
6397 #endif // 0
6398
6399 /* It's needed, none..? XXX */
6400 p_ptr->temp_n = 0;
6401
6402 /*** Step 0 -- Begin ***/
6403
6404 /* Save the old "view" grids for later */
6405 for (n = 0; n < p_ptr->view_n; n++)
6406 {
6407 y = p_ptr->view_y[n];
6408 x = p_ptr->view_x[n];
6409
6410 /* Access the grid */
6411 c_ptr = &zcave[y][x];
6412 w_ptr = &p_ptr->cave_flag[y][x];
6413
6414 /* Mark the grid as not in "view" */
6415 *w_ptr &= ~(CAVE_VIEW);
6416
6417 /* Save "CAVE_SEEN" grids */
6418 if (*w_ptr & (CAVE_XTRA))
6419 {
6420 /* Set "CAVE_TEMP" flag */
6421 info |= (CAVE_TEMP);
6422
6423 /* Save grid for later */
6424 p_ptr->temp_y[p_ptr->temp_n] = y;
6425 p_ptr->temp_x[p_ptr->temp_n++] = x;
6426 }
6427
6428 /* Mark the grid as "seen" */
6429 *w_ptr &= ~(CAVE_XTRA);
6430 }
6431
6432 /* Start over with the "view" array */
6433 p_ptr->view_n = 0;
6434
6435
6436 /*** Step 1 -- adjacent grids ***/
6437
6438 /* Now start on the player */
6439 y = py;
6440 x = px;
6441
6442 /* Access the grid */
6443 c_ptr = &zcave[y][x];
6444 w_ptr = &p_ptr->cave_flag[y][x];
6445
6446 /* Assume the player grid is easily viewable */
6447 /* c_ptr->info |= CAVE_XTRA; */
6448
6449 /* Assume the player grid is viewable */
6450 cave_view_hack(w_ptr, y, x);
6451
6452 if (c_ptr->info & (CAVE_GLOW | CAVE_LITE))
6453 {
6454 /* Mark as "CAVE_SEEN" */
6455 *w_ptr |= (CAVE_XTRA);
6456 }
6457
6458
6459 /*** Step 2 -- octants ***/
6460
6461 /* Scan each octant */
6462 for (o = 0; o < 8; o++)
6463 {
6464 vinfo_type *p;
6465
6466 /* Last added */
6467 vinfo_type *last = &vinfo[0];
6468
6469 /* Grid queue */
6470 int queue_head = 0;
6471 int queue_tail = 0;
6472 vinfo_type *queue[VINFO_MAX_GRIDS*2];
6473
6474 /* Slope bit vector */
6475 u32b bits0 = VINFO_BITS_0;
6476 u32b bits1 = VINFO_BITS_1;
6477 u32b bits2 = VINFO_BITS_2;
6478 u32b bits3 = VINFO_BITS_3;
6479
6480 /* Reset queue */
6481 queue_head = queue_tail = 0;
6482
6483 /* Initial grids */
6484 queue[queue_tail++] = &vinfo[1];
6485 queue[queue_tail++] = &vinfo[2];
6486
6487 /* Process queue */
6488 while (queue_head < queue_tail)
6489 {
6490 /* Dequeue next grid */
6491 p = queue[queue_head++];
6492
6493 /* Check bits */
6494 if ((bits0 & (p->bits_0)) ||
6495 (bits1 & (p->bits_1)) ||
6496 (bits2 & (p->bits_2)) ||
6497 (bits3 & (p->bits_3)))
6498 {
6499 /* Extract coordinate value */
6500 y = py + p->grid_y[o];
6501 x = px + p->grid_x[o];
6502
6503 /* Access the grid */
6504 c_ptr = &zcave[y][x];
6505 w_ptr = &p_ptr->cave_flag[y][x];
6506
6507 /* Get grid info */
6508 info = c_ptr->info;
6509
6510 /* Handle wall */
6511 /* if (info & (CAVE_WALL)) */
6512 if (!cave_los_grid(c_ptr))
6513 {
6514 /* Clear bits */
6515 bits0 &= ~(p->bits_0);
6516 bits1 &= ~(p->bits_1);
6517 bits2 &= ~(p->bits_2);
6518 bits3 &= ~(p->bits_3);
6519
6520 /* Newly viewable wall */
6521 if (!(*w_ptr & (CAVE_VIEW)))
6522 {
6523 /* Mark as viewable */
6524 /* *w_ptr |= (CAVE_VIEW); */
6525
6526 #if 0 /* cannot handle other players' lite.. */
6527 /* Torch-lit grids */
6528 if (p->d < radius)
6529 {
6530 /* Mark as "CAVE_SEEN" and torch-lit */
6531 info |= (CAVE_SEEN | CAVE_PLIT);
6532 }
6533
6534 /* Monster-lit grids */
6535 else if (info & (CAVE_MLIT))
6536 {
6537 /* Mark as "CAVE_SEEN" */
6538 info |= (CAVE_SEEN);
6539 }
6540 else
6541 #endif /* 0 */
6542
6543 /* Perma-lit grids */
6544 if (info & (CAVE_GLOW | CAVE_LITE))
6545 {
6546 /* Hack -- move towards player */
6547 int yy = (y < py) ? (y + 1) : (y > py) ? (y - 1) : y;
6548 int xx = (x < px) ? (x + 1) : (x > px) ? (x - 1) : x;
6549
6550 #ifdef UPDATE_VIEW_COMPLEX_WALL_ILLUMINATION
6551 /* seemingly it's not used in ToME too */
6552
6553 /* Check for "complex" illumination */
6554 if ((!(cave[yy][xx].info & (CAVE_WALL)) &&
6555 (cave[yy][xx].info & (CAVE_GLOW))) ||
6556 (!(cave[y][xx].info & (CAVE_WALL)) &&
6557 (cave[y][xx].info & (CAVE_GLOW))) ||
6558 (!(cave[yy][x].info & (CAVE_WALL)) &&
6559 (cave[yy][x].info & (CAVE_GLOW))))
6560 {
6561 /* Mark as seen */
6562 info |= (CAVE_SEEN);
6563 }
6564
6565 #else /* UPDATE_VIEW_COMPLEX_WALL_ILLUMINATION */
6566
6567 /* Check for "simple" illumination */
6568 if (zcave[yy][xx].info & (CAVE_GLOW))
6569 {
6570 /* Mark as seen */
6571 *w_ptr |= (CAVE_XTRA);
6572 }
6573
6574 #endif /* UPDATE_VIEW_COMPLEX_WALL_ILLUMINATION */
6575
6576 }
6577
6578 /* Save cave info */
6579 /* c_ptr->info = info; */
6580
6581 /* Save in array */
6582 cave_view_hack(w_ptr, y, x);
6583 }
6584 }
6585
6586 /* Handle non-wall */
6587 else
6588 {
6589 /* Enqueue child */
6590 if (last != p->next_0)
6591 {
6592 queue[queue_tail++] = last = p->next_0;
6593 }
6594
6595 /* Enqueue child */
6596 if (last != p->next_1)
6597 {
6598 queue[queue_tail++] = last = p->next_1;
6599 }
6600
6601 /* Newly viewable non-wall */
6602 if (!(*w_ptr & (CAVE_VIEW)))
6603 {
6604 /* Mark as "viewable" */
6605 /* *w_ptr |= (CAVE_VIEW); */
6606
6607 #if 0
6608
6609 /* Torch-lit grids */
6610 if (p->d < radius)
6611 {
6612 /* Mark as "CAVE_SEEN" and torch-lit */
6613 info |= (CAVE_SEEN | CAVE_PLIT);
6614 }
6615
6616 /* Perma-lit or monster-lit grids */
6617 else if (info & (CAVE_GLOW | CAVE_MLIT))
6618 {
6619 /* Mark as "CAVE_SEEN" */
6620 info |= (CAVE_SEEN);
6621 }
6622 #endif /* 0 */
6623
6624 if (info & (CAVE_GLOW | CAVE_LITE))
6625 {
6626 /* Mark as "CAVE_SEEN" */
6627 *w_ptr |= (CAVE_XTRA);
6628 }
6629
6630 /* Save cave info */
6631 /* c_ptr->info = info; */
6632
6633 /* Save in array */
6634 cave_view_hack(w_ptr, y, x);
6635 }
6636 }
6637 }
6638 }
6639 }
6640
6641
6642
6643 /*** Step 3 -- Complete the algorithm ***/
6644
6645 #if 0 /* not here (?) */
6646 /* Handle blindness */
6647 if (p_ptr->blind)
6648 {
6649 /* Process "new" grids */
6650 for (i = 0; i < fast_view_n; i++)
6651 {
6652 /* Location */
6653 y = view_y[i];
6654 x = view_x[i];
6655
6656 /* Grid cannot be "CAVE_SEEN" */
6657 cave[y][x].info &= ~(CAVE_SEEN);
6658 }
6659 }
6660 #endif /* 0 */
6661
6662 /* Update all the new grids */
6663 for (n = 0; n < p_ptr->view_n; n++)
6664 {
6665 y = p_ptr->view_y[n];
6666 x = p_ptr->view_x[n];
6667
6668 /* Access the grid */
6669 c_ptr = &zcave[y][x];
6670 w_ptr = &p_ptr->cave_flag[y][x];
6671
6672 #if 0
6673 /* Clear the "CAVE_XTRA" flag */
6674 c_ptr->info &= ~CAVE_XTRA;
6675
6676 /* Update only newly viewed grids */
6677 if (c_ptr->info & CAVE_TEMP) continue;
6678 #endif /* 0 */
6679
6680 if (!((*w_ptr & (CAVE_XTRA)) && !(c_ptr->info & (CAVE_TEMP)))) continue;
6681
6682 /* Note */
6683 note_spot(Ind, y, x);
6684
6685 /* Redraw */
6686 lite_spot(Ind, y, x);
6687 }
6688
6689 /* Wipe the old grids, update as needed */
6690 for (n = 0; n < p_ptr->temp_n; n++)
6691 {
6692 y = p_ptr->temp_y[n];
6693 x = p_ptr->temp_x[n];
6694
6695 /* Access the grid */
6696 c_ptr = &zcave[y][x];
6697 w_ptr = &p_ptr->cave_flag[y][x];
6698
6699 /* No longer in the array */
6700 c_ptr->info &= ~CAVE_TEMP;
6701
6702 /* Update only non-viewable grids */
6703 // if (*w_ptr & CAVE_VIEW) continue;
6704 if ((*w_ptr & (CAVE_XTRA))) continue;
6705
6706 /* Forget it, dude */
6707 if (unmap)
6708 {
6709 u16b this_o_idx, next_o_idx = 0;
6710
6711 *w_ptr &= ~CAVE_MARK;
6712
6713 /* make player forget of objects too */
6714 /* too bad, traps cannot be forgotten this way.. */
6715 for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
6716 {
6717 /* Acquire next object */
6718 next_o_idx = o_list[this_o_idx].next_o_idx;
6719
6720 /* Forget the object */
6721 p_ptr->obj_vis[this_o_idx] = FALSE;
6722 }
6723 }
6724
6725 /* Redraw */
6726 lite_spot(Ind, y, x);
6727 }
6728
6729 /* None left */
6730 p_ptr->temp_n = 0;
6731 }
6732 #endif /* USE_OLD_UPDATE_VIEW */
6733
6734
6735
6736
6737
6738
6739 /*
6740 * Hack -- provide some "speed" for the "flow" code
6741 * This entry is the "current index" for the "when" field
6742 * Note that a "when" value of "zero" means "not used".
6743 *
6744 * Note that the "cost" indexes from 1 to 127 are for
6745 * "old" data, and from 128 to 255 are for "new" data.
6746 *
6747 * This means that as long as the player does not "teleport",
6748 * then any monster up to 128 + MONSTER_FLOW_DEPTH will be
6749 * able to track down the player, and in general, will be
6750 * able to track down either the player or a position recently
6751 * occupied by the player.
6752 */
6753 /*static int flow_n = 0;*/
6754
6755
6756 /*
6757 * Hack -- forget the "flow" information
6758 */
6759 void forget_flow(void)
6760 {
6761
6762 #ifdef MONSTER_FLOW
6763
6764 int x, y;
6765
6766 /* Nothing to forget */
6767 if (!flow_n) return;
6768
6769 /* Check the entire dungeon */
6770 for (y = 0; y < cur_hgt; y++)
6771 {
6772 for (x = 0; x < cur_wid; x++)
6773 {
6774 /* Forget the old data */
6775 cave[y][x].cost = 0;
6776 cave[y][x].when = 0;
6777 }
6778 }
6779
6780 /* Start over */
6781 flow_n = 0;
6782
6783 #endif
6784
6785 }
6786
6787
6788 #ifdef MONSTER_FLOW
6789
6790 /*
6791 * Hack -- Allow us to treat the "seen" array as a queue
6792 */
6793 static int flow_head = 0;
6794 static int flow_tail = 0;
6795
6796
6797 /*
6798 * Take note of a reachable grid. Assume grid is legal.
6799 */
6800 static void update_flow_aux(int y, int x, int n)
6801 {
6802 cave_type *c_ptr;
6803
6804 int old_head = flow_head;
6805
6806
6807 /* Get the grid */
6808 c_ptr = &cave[y][x];
6809
6810 /* Ignore "pre-stamped" entries */
6811 if (c_ptr->when == flow_n) return;
6812
6813 /* Ignore "walls" and "rubble" */
6814 if (c_ptr->feat >= FEAT_RUBBLE) return;
6815
6816 /* Save the time-stamp */
6817 c_ptr->when = flow_n;
6818
6819 /* Save the flow cost */
6820 c_ptr->cost = n;
6821
6822 /* Hack -- limit flow depth */
6823 if (n == MONSTER_FLOW_DEPTH) return;
6824
6825 /* Enqueue that entry */
6826 temp_y[flow_head] = y;
6827 temp_x[flow_head] = x;
6828
6829 /* Advance the queue */
6830 if (++flow_head == TEMP_MAX) flow_head = 0;
6831
6832 /* Hack -- notice overflow by forgetting new entry */
6833 if (flow_head == flow_tail) flow_head = old_head;
6834 }
6835
6836 #endif
6837
6838
6839 /*
6840 * Hack -- fill in the "cost" field of every grid that the player
6841 * can "reach" with the number of steps needed to reach that grid.
6842 * This also yields the "distance" of the player from every grid.
6843 *
6844 * In addition, mark the "when" of the grids that can reach
6845 * the player with the incremented value of "flow_n".
6846 *
6847 * Hack -- use the "seen" array as a "circular queue".
6848 *
6849 * We do not need a priority queue because the cost from grid
6850 * to grid is always "one" and we process them in order.
6851 */
6852 void update_flow(void)
6853 {
6854
6855 #ifdef MONSTER_FLOW
6856
6857 int x, y, d;
6858
6859 /* Hack -- disabled */
6860 if (!flow_by_sound && !flow_by_smell) return;
6861
6862 /* Paranoia -- make sure the array is empty */
6863 if (temp_n) return;
6864
6865 /* Cycle the old entries (once per 128 updates) */
6866 if (flow_n == 255)
6867 {
6868 /* Rotate the time-stamps */
6869 for (y = 0; y < cur_hgt; y++)
6870 {
6871 for (x = 0; x < cur_wid; x++)
6872 {
6873 int w = cave[y][x].when;
6874 cave[y][x].when = (w > 128) ? (w - 128) : 0;
6875 }
6876 }
6877
6878 /* Restart */
6879 flow_n = 127;
6880 }
6881
6882 /* Start a new flow (never use "zero") */
6883 flow_n++;
6884
6885
6886 /* Reset the "queue" */
6887 flow_head = flow_tail = 0;
6888
6889 /* Add the player's grid to the queue */
6890 update_flow_aux(py, px, 0);
6891
6892 /* Now process the queue */
6893 while (flow_head != flow_tail)
6894 {
6895 /* Extract the next entry */
6896 y = temp_y[flow_tail];
6897 x = temp_x[flow_tail];
6898
6899 /* Forget that entry */
6900 if (++flow_tail == TEMP_MAX) flow_tail = 0;
6901
6902 /* Add the "children" */
6903 for (d = 0; d < 8; d++)
6904 {
6905 /* Add that child if "legal" */
6906 update_flow_aux(y+ddy_ddd[d], x+ddx_ddd[d], cave[y][x].cost+1);
6907 }
6908 }
6909
6910 /* Forget the flow info */
6911 flow_head = flow_tail = 0;
6912
6913 #endif
6914
6915 }
6916
6917
6918
6919
6920
6921
6922
6923 /*
6924 * Hack -- map the current panel (plus some) ala "magic mapping"
6925 */
6926 void map_area(int Ind) {
6927 player_type *p_ptr = Players[Ind];
6928 int i, x, y, y1, y2, x1, x2;
6929
6930 cave_type *c_ptr;
6931 byte *w_ptr;
6932
6933 /* dungeon_type *d_ptr = getdungeon(&p_ptr->wpos); */
6934 dun_level *l_ptr = getfloor(&p_ptr->wpos);
6935 worldpos *wpos = &p_ptr->wpos;
6936 cave_type **zcave;
6937
6938 /* anti-exploit */
6939 if (!local_panel(Ind)) return;
6940
6941 if (!(zcave = getcave(wpos))) return;
6942 /* if (d_ptr && d_ptr->flags & DUNGEON_NO_MAP) return; */
6943 if (l_ptr && (l_ptr->flags1 & LF1_NO_MAGIC_MAP)) return;
6944 if (in_sector00(wpos) && (sector00flags1 & LF1_NO_MAGIC_MAP)) return;
6945
6946 /* Pick an area to map */
6947 y1 = TRADPANEL_ROW_MIN - randint(10);
6948 y2 = TRADPANEL_ROW_MAX + randint(10);
6949 x1 = TRADPANEL_COL_MIN - randint(20);
6950 x2 = TRADPANEL_COL_MAX + randint(20);
6951
6952 /* Speed -- shrink to fit legal bounds */
6953 if (y1 < 1) y1 = 1;
6954 if (y2 > p_ptr->cur_hgt-2) y2 = p_ptr->cur_hgt-2;
6955 if (x1 < 1) x1 = 1;
6956 if (x2 > p_ptr->cur_wid-2) x2 = p_ptr->cur_wid-2;
6957
6958 /* Scan that area */
6959 for (y = y1; y <= y2; y++) {
6960 for (x = x1; x <= x2; x++) {
6961 c_ptr = &zcave[y][x];
6962 w_ptr = &p_ptr->cave_flag[y][x];
6963
6964 /* All non-walls are "checked" */
6965 // if (c_ptr->feat < FEAT_SECRET)
6966 if (!is_wall(c_ptr)) {
6967 /* Memorize normal features */
6968 // if (c_ptr->feat > FEAT_INVIS)
6969 if (!cave_plain_floor_grid(c_ptr)) {
6970 /* Memorize the object */
6971 *w_ptr |= CAVE_MARK;
6972 }
6973
6974 /* Memorize known walls */
6975 for (i = 0; i < 8; i++) {
6976 c_ptr = &zcave[y + ddy_ddd[i]][x + ddx_ddd[i]];
6977 w_ptr = &p_ptr->cave_flag[y + ddy_ddd[i]][x + ddx_ddd[i]];
6978
6979 /* Memorize walls (etc) */
6980 // if (c_ptr->feat >= FEAT_SECRET)
6981 if (is_wall(c_ptr)) {
6982 /* Memorize the walls */
6983 *w_ptr |= CAVE_MARK;
6984 }
6985 }
6986 }
6987 }
6988 }
6989
6990 /* Redraw map */
6991 p_ptr->redraw |= (PR_MAP);
6992
6993 /* Window stuff */
6994 p_ptr->window |= (PW_OVERHEAD);
6995 }
6996
6997 /* Mindcrafter's magic mapping spell - C. Blue */
6998 /* This spell's behaviour:
6999 easy, old: like magic mapping, combined with short-time esp
7000 good, new: like magic mapping, without any esp */
7001 #define MML_NEW
7002 void mind_map_level(int Ind, int pow) {
7003 player_type *p_ptr = Players[Ind];
7004 int m, y, x, rad;
7005 int i, j, plist[MAX_PLAYERS + 1], plist_size = 1;
7006
7007 monster_race *r_ptr;
7008 monster_type *m_ptr;
7009 cave_type *c_ptr;
7010
7011 dun_level *l_ptr = getfloor(&p_ptr->wpos);
7012 struct worldpos *wpos = &p_ptr->wpos;
7013 cave_type **zcave;
7014 if (!(zcave = getcave(wpos))) return;
7015
7016 /* for mindcrafters too (NR requires) */
7017 if (l_ptr && l_ptr->flags1 & LF1_NO_MAGIC_MAP) return;
7018 if (in_sector00(wpos) && (sector00flags1 & LF1_NO_MAGIC_MAP)) return;
7019
7020 /* build list of players to share the vision with */
7021 /* oneself too */
7022 plist[0] = Ind;
7023 for (i = 1; i <= NumPlayers; i++) {
7024 /* Skip self */
7025 if (i == Ind) continue;
7026 /* Skip disconnected players */
7027 if (Players[i]->conn == NOT_CONNECTED) continue;
7028 /* Skip DM if not DM himself */
7029 if (Players[i]->admin_dm && !p_ptr->admin_dm) continue;
7030 /* Skip Ghosts */
7031 if (Players[i]->ghost && !Players[i]->admin_dm) continue;
7032 /* Skip players not on this depth */
7033 if (!inarea(&Players[i]->wpos, &p_ptr->wpos)) continue;
7034 /* Skip players not in the same party */
7035 if (Players[i]->party == 0 || p_ptr->party != Players[i]->party) continue;
7036 /* Skip players who haven't opened their mind */
7037 if (!(Players[i]->esp_link_flags & LINKF_OPEN)) continue;
7038
7039 /* add him */
7040 plist[plist_size++] = i;
7041 }
7042
7043 /* Is grid in LOS of a monster with a mind? */
7044 for (m = m_top - 1; m >= 0; m--) {
7045 /* Access the monster */
7046 m_ptr = &m_list[m_fast[m]];
7047 r_ptr = race_inf(m_ptr);
7048
7049 if (!inarea(&m_ptr->wpos, &p_ptr->wpos)) continue;
7050
7051 /* sleeping */
7052 //hypnosis yay if (m_ptr->csleep) continue;
7053
7054 /* no mind */
7055 if ((r_ptr->flags9 & RF9_IM_PSI) ||
7056 (r_ptr->flags2 & RF2_EMPTY_MIND) ||
7057 (r_ptr->flags3 & RF3_NONLIVING))
7058 continue;
7059
7060 /* 'clouded' */
7061 if ((r_ptr->flags9 & RF9_RES_PSI) ||
7062 (r_ptr->flags2 & RF2_WEIRD_MIND) ||
7063 (r_ptr->flags3 & RF3_UNDEAD))
7064 rad = (pow + 1) / 2;
7065 else rad = pow;
7066
7067 /* test nearby grids */
7068 for (y = m_ptr->fy - rad; y < m_ptr->fy + rad; y++)
7069 for (x = m_ptr->fx - rad; x < m_ptr->fx + rad; x++) {
7070
7071 if (!in_bounds(y, x)) continue;
7072
7073 if (distance(y, x, m_ptr->fy, m_ptr->fx) > rad ||
7074 distance(y, x, m_ptr->fy, m_ptr->fx) > r_ptr->aaf ||
7075 !los(wpos, y, x, m_ptr->fy, m_ptr->fx))
7076 continue;
7077
7078 /* Access the grid */
7079 c_ptr = &zcave[y][x];
7080
7081 /* Memorize all objects */
7082 if (c_ptr->o_idx) {
7083 for (i = 0; i < plist_size; i++) {
7084 Players[plist[i]]->obj_vis[c_ptr->o_idx]= TRUE;
7085 }
7086 }
7087
7088 #if 0 /* like wiz-lite? */
7089 #if 1 /* should be enabled too if CAVE_MARK below is enabled.. */
7090 /* perma-lite grid? */
7091 c_ptr->info |= (CAVE_GLOW);
7092 #endif
7093 #if 1
7094 /* Process all non-walls */
7095 //if (c_ptr->feat < FEAT_SECRET)
7096 {
7097 /* Memorize normal features */
7098 // if (c_ptr->feat > FEAT_INVIS)
7099 if (!cave_plain_floor_grid(c_ptr)) {
7100 for (i = 0; i < plist_size; i++) {
7101 /* Memorize the grid */
7102 Players[plist[i]]->cave_flag[y][x] |= CAVE_MARK;
7103 }
7104 }
7105
7106 /* Normally, memorize floors (see above) */
7107 else if (p_ptr->view_perma_grids && !p_ptr->view_torch_grids) {
7108 for (i = 0; i < plist_size; i++) {
7109 /* Memorize the grid */
7110 Players[plist[i]]->cave_flag[y][x] |= CAVE_MARK;
7111 }
7112 }
7113 }
7114 #endif
7115 #else /* like magic mapping? */
7116 /* All non-walls are "checked" */
7117 // if (c_ptr->feat < FEAT_SECRET)
7118 if (!is_wall(c_ptr)) {
7119 /* Memorize normal features */
7120 // if (c_ptr->feat > FEAT_INVIS) {
7121 if (!cave_plain_floor_grid(c_ptr)) {
7122 for (i = 0; i < plist_size; i++) {
7123 /* Memorize the feature */
7124 Players[plist[i]]->cave_flag[y][x] |= CAVE_MARK;
7125 #ifdef MML_NEW
7126 lite_spot(plist[i], y, x);
7127 #endif
7128 }
7129 }
7130
7131 /* Memorize known walls */
7132 for (j = 0; j < 8; j++) {
7133 if (!in_bounds(y + ddy_ddd[j], x + ddx_ddd[j])) continue;
7134
7135 /* Memorize walls (etc) */
7136 // if (c_ptr->feat >= FEAT_SECRET)
7137 if (is_wall(&zcave[y + ddy_ddd[j]][x + ddx_ddd[j]])) {
7138 for (i = 0; i < plist_size; i++) {
7139 /* Memorize the walls */
7140 Players[plist[i]]->cave_flag[y + ddy_ddd[j]][x + ddx_ddd[j]] |= CAVE_MARK;
7141 #ifdef MML_NEW
7142 lite_spot(plist[i], y + ddy_ddd[j], x + ddx_ddd[j]);
7143 #endif
7144 }
7145 }
7146 }
7147 }
7148 #endif
7149 }
7150
7151 #if 0 /* this will be overheady, since it requires prt_map() here as a bad \
7152 hack, and PR_MAP/PU_MONSTERS commented out in for-loop below. \
7153 See same for-loop for clean solution as good alternative! */
7154 prt_map(plist[i]); /* bad hack */
7155 /* like detect_creatures(), not excluding invisible monsters though */
7156 for (i = 0; i < plist_size; i++) {
7157 if (Players[plist[i]]->mon_vis[m_fast[m]]) continue;
7158 Players[plist[i]]->mon_vis[m_fast[m]] = TRUE;
7159 lite_spot(plist[i], m_ptr->fy, m_ptr->fx);
7160 Players[plist[i]]->mon_vis[m_fast[m]] = FALSE; /* the usual hack: don't update screen after this */
7161 }
7162 #elif defined(MML_NEW) /* new attempt */
7163 /* like detect_creatures(), not excluding invisible monsters though */
7164 for (i = 0; i < plist_size; i++) {
7165 if (Players[plist[i]]->mon_vis[m_fast[m]]) continue;
7166 Players[plist[i]]->mon_vis[m_fast[m]] = TRUE;
7167 lite_spot(plist[i], m_ptr->fy, m_ptr->fx);
7168 Players[plist[i]]->mon_vis[m_fast[m]] = FALSE; /* the usual hack: don't update screen after this */
7169 }
7170 #endif
7171 }
7172
7173 /* Specialty: Detect all dungeon stores! */
7174 //TODO: Store the 1 or maybe 2 stores in the l_ptr array instead -_-' */
7175 for (y = 0; y < MAX_HGT; y++)
7176 for (x = 0; x < MAX_WID; x++) {
7177 if (zcave[y][x].feat != FEAT_SHOP) continue;
7178 for (i = 0; i < plist_size; i++) {
7179 Players[plist[i]]->cave_flag[y][x] |= CAVE_MARK;
7180 lite_spot(plist[i], y, x);
7181 }
7182 }
7183
7184 #ifndef MML_NEW
7185 for (i = 0; i < plist_size; i++) {
7186 #if 1
7187 /* clean solution instead: give some temporary ESP (makes sense also).
7188 Note however: this is thereby becoming an auto-projectable ESP spell^^ */
7189 set_tim_esp(plist[i], 10);
7190 #endif
7191
7192 /* Update the monsters */
7193 Players[plist[i]]->update |= (PU_MONSTERS);
7194 /* Redraw map */
7195 Players[plist[i]]->redraw |= (PR_MAP);
7196 /* Window stuff */
7197 Players[plist[i]]->window |= (PW_OVERHEAD);
7198 }
7199 #endif
7200 }
7201
7202 /*
7203 * Light up the dungeon using "claravoyance"
7204 *
7205 * This function "illuminates" every grid in the dungeon, memorizes all
7206 * "objects", memorizes all grids as with magic mapping, and, under the
7207 * standard option settings (view_perma_grids but not view_torch_grids)
7208 * memorizes all floor grids too.
7209 *
7210 * Note that if "view_perma_grids" is not set, we do not memorize floor
7211 * grids, since this would defeat the purpose of "view_perma_grids", not
7212 * that anyone seems to play without this option.
7213 *
7214 * Note that if "view_torch_grids" is set, we do not memorize floor grids,
7215 * since this would prevent the use of "view_torch_grids" as a method to
7216 * keep track of what grids have been observed directly.
7217 */
7218 void wiz_lite(int Ind) {
7219 player_type *p_ptr = Players[Ind];
7220 int y, x, i;
7221
7222 cave_type *c_ptr;
7223 byte *w_ptr;
7224
7225 /* dungeon_type *d_ptr = getdungeon(&p_ptr->wpos); */
7226 dun_level *l_ptr = getfloor(&p_ptr->wpos);
7227 struct worldpos *wpos = &p_ptr->wpos;
7228 cave_type **zcave;
7229
7230 /* don't ruin the mood ^^ */
7231 bool mood = (wpos->wz == 0 && (season_halloween || season_newyearseve));
7232
7233 if (!(zcave = getcave(wpos))) return;
7234
7235 /* if (d_ptr && d_ptr->flags & DUNGEON_NO_MAP) return; */
7236 if (l_ptr && l_ptr->flags1 & LF1_NO_MAGIC_MAP) return;
7237 if (in_sector00(wpos) && (sector00flags1 & LF1_NO_MAGIC_MAP)) return;
7238
7239 /* Scan all normal grids */
7240 for (y = 1; y < p_ptr->cur_hgt-1; y++) {
7241 /* Scan all normal grids */
7242 for (x = 1; x < p_ptr->cur_wid-1; x++) {
7243 /* Access the grid */
7244 c_ptr = &zcave[y][x];
7245 if (mood && !(c_ptr->info & CAVE_ICKY)) continue;
7246 w_ptr = &p_ptr->cave_flag[y][x];
7247
7248 /* Memorize all objects */
7249 if (c_ptr->o_idx) {
7250 /* Memorize */
7251 p_ptr->obj_vis[c_ptr->o_idx]= TRUE;
7252 }
7253
7254 /* Process all non-walls */
7255 //if (c_ptr->feat < FEAT_SECRET) <- deprecated; use next line if you want "clean" wizlite ;) - C. Blue
7256 // if (!(f_info[c_ptr->feat].flags1 & FF1_WALL))
7257 {
7258 /* Scan all neighbors */
7259 for (i = 0; i < 9; i++) {
7260 int yy = y + ddy_ddd[i];
7261 int xx = x + ddx_ddd[i];
7262
7263 /* Get the grid */
7264 c_ptr = &zcave[yy][xx];
7265 if (mood && !(c_ptr->info & CAVE_ICKY)) continue; //if this were commented out, house walls would be *bright*
7266 w_ptr = &p_ptr->cave_flag[yy][xx];
7267
7268 /* Perma-lite the grid */
7269 c_ptr->info |= (CAVE_GLOW);
7270
7271 /* Memorize normal features */
7272 // if (c_ptr->feat > FEAT_INVIS)
7273 if (!cave_plain_floor_grid(c_ptr)) {
7274 /* Memorize the grid */
7275 *w_ptr |= CAVE_MARK;
7276 }
7277
7278 /* Normally, memorize floors (see above) */
7279 if (p_ptr->view_perma_grids && !p_ptr->view_torch_grids) {
7280 /* Memorize the grid */
7281 *w_ptr |= CAVE_MARK;
7282 }
7283 }
7284 }
7285 }
7286 }
7287
7288 /* Update the monsters */
7289 p_ptr->update |= (PU_MONSTERS);
7290
7291 /* Redraw map */
7292 p_ptr->redraw |= (PR_MAP);
7293
7294 /* Window stuff */
7295 p_ptr->window |= (PW_OVERHEAD);
7296
7297 }
7298
7299
7300 /* from PernA - Jir - */
7301 void wiz_lite_extra(int Ind)
7302 {
7303 player_type *p_ptr = Players[Ind];
7304 int y, x;
7305 struct worldpos *wpos = &p_ptr->wpos;
7306 // dun_level *l_ptr = getfloor(wpos);
7307 cave_type **zcave;
7308 cave_type *c_ptr;
7309
7310 /* don't ruin the mood ^^ */
7311 bool mood = (wpos->wz == 0 && (season_halloween || season_newyearseve));
7312
7313 if (!(zcave = getcave(wpos))) return;
7314
7315 /* if (d_ptr && d_ptr->flags & DUNGEON_NO_MAP) return; */
7316
7317 for (y = 0; y < p_ptr->cur_hgt; y++) {
7318 for (x = 0; x < p_ptr->cur_wid; x++) {
7319 c_ptr = &zcave[y][x];
7320 if (mood && !(c_ptr->info & CAVE_ICKY)) continue;
7321 /* ligten up all grids and remember features */
7322 // c_ptr->info |= (CAVE_GLOW | CAVE_MARK);
7323 /* lighten up all grids */
7324 c_ptr->info |= CAVE_GLOW;
7325 }
7326 }
7327
7328
7329 /* remember features too? */
7330 // if (!(l_ptr && l_ptr->flags1 & LF1_NO_MAGIC_MAP))
7331 wiz_lite(Ind);
7332
7333
7334 for (x = 1; x <= NumPlayers; x++) {
7335 p_ptr = Players[x];
7336
7337 /* Only works for players on the level */
7338 if (!inarea(wpos, &p_ptr->wpos)) continue;
7339
7340 /* Update some things */
7341 p_ptr->update |= (PU_VIEW | PU_DISTANCE);
7342 p_ptr->redraw |= PR_MAP;
7343 p_ptr->window |= PW_OVERHEAD;
7344 }
7345
7346 }
7347
7348 /*
7349 * Forget the dungeon map (ala "Thinking of Maud...").
7350 */
7351 void wiz_dark(int Ind) {
7352 player_type *p_ptr, *q_ptr = Players[Ind];
7353 struct worldpos *wpos;
7354 cave_type **zcave;
7355 cave_type *c_ptr;
7356 int y, x, i;
7357 object_type *o_ptr;
7358
7359 wpos = &q_ptr->wpos;
7360 if (!(zcave = getcave(wpos))) return;
7361
7362 /* Check for every other player */
7363
7364 for (i = 1; i <= NumPlayers; i++) {
7365 p_ptr = Players[i];
7366
7367 /* Only works for players on the level */
7368 if (!inarea(wpos, &p_ptr->wpos)) continue;
7369
7370 o_ptr = &p_ptr->inventory[INVEN_LITE];
7371
7372 /* Bye bye light */
7373 if (o_ptr->k_idx &&
7374 ((o_ptr->sval == SV_LITE_TORCH) || (o_ptr->sval == SV_LITE_LANTERN))
7375 && (!o_ptr->name1) && o_ptr->timeout) {
7376 bool refilled = FALSE;
7377
7378 disturb(Ind, 0, 0);
7379
7380 /* If flint is ready, refill at once */
7381 if (TOOL_EQUIPPED(p_ptr) == SV_TOOL_FLINT &&
7382 !p_ptr->paralyzed) {
7383 msg_print(Ind, "You prepare a flint...");
7384 refilled = do_auto_refill(Ind);
7385 if (!refilled) msg_print(Ind, "Oops, you're out of fuel!");
7386 }
7387
7388 if (!refilled) {
7389 msg_print(i, "Your light suddenly empties.");
7390
7391 /* No more light, it's Rogues day today :) */
7392 o_ptr->timeout = 0;
7393 }
7394 }
7395
7396 /* Forget every grid */
7397 for (y = 0; y < p_ptr->cur_hgt; y++) {
7398 for (x = 0; x < p_ptr->cur_wid; x++) {
7399 byte *w_ptr = &p_ptr->cave_flag[y][x];
7400 c_ptr = &zcave[y][x];
7401
7402 /* Process the grid */
7403 *w_ptr &= ~CAVE_MARK;
7404 c_ptr->info &= ~CAVE_GLOW;
7405
7406 /* Forget every object */
7407 if (c_ptr->o_idx)
7408 {
7409 /* Forget the object */
7410 p_ptr->obj_vis[c_ptr->o_idx] = FALSE;
7411 }
7412 }
7413 }
7414
7415 /* Mega-Hack -- Forget the view and lite */
7416 p_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);
7417
7418 /* Update the view and lite */
7419 p_ptr->update |= (PU_VIEW | PU_LITE);
7420
7421 /* Update the monsters */
7422 p_ptr->update |= (PU_MONSTERS);
7423
7424 /* Redraw map */
7425 p_ptr->redraw |= (PR_MAP);
7426
7427 /* Window stuff */
7428 p_ptr->window |= (PW_OVERHEAD);
7429 }
7430 }
7431
7432 #ifdef ARCADE_SERVER
7433 extern int check_feat(worldpos *wpos, int y, int x)
7434 {
7435 cave_type **zcave;
7436 cave_type *c_ptr;
7437
7438 if (!(zcave = getcave(wpos))) return(0);
7439
7440 if (!in_bounds(y, x)) return(0);
7441
7442 c_ptr = &zcave[y][x];
7443 return(c_ptr->feat);
7444 }
7445 #endif
7446
7447 /*
7448 * Change the "feat" flag for a grid, and notice/redraw the grid
7449 * (Adapted from PernAngband)
7450 */
7451 bool level_generation_time = FALSE;
7452 void cave_set_feat(worldpos *wpos, int y, int x, int feat)
7453 {
7454 player_type *p_ptr;
7455 cave_type **zcave;
7456 cave_type *c_ptr;
7457 // struct c_special *cs_ptr;
7458 int i;
7459
7460 if (!(zcave = getcave(wpos))) return;
7461 if (!in_bounds(y, x)) return;
7462 c_ptr = &zcave[y][x];
7463
7464 /* Trees in greater fire become dead trees at once */
7465 if ((feat == FEAT_TREE || feat == FEAT_BUSH) &&
7466 (c_ptr->feat == FEAT_SHAL_LAVA ||
7467 c_ptr->feat == FEAT_FIRE ||
7468 c_ptr->feat == FEAT_GREAT_FIRE))
7469 feat = FEAT_DEAD_TREE;
7470
7471 /* Don't mess with inns please! */
7472 if (f_info[c_ptr->feat].flags1 & FF1_PROTECTED) return;
7473
7474 /* in Nether Realm, floor is always nether mist (or lava)! */
7475 if (in_netherrealm(wpos)) switch (feat) {
7476 case FEAT_IVY:
7477 case FEAT_SHAL_WATER:
7478 case FEAT_DEEP_WATER:
7479 case FEAT_ICE:
7480 case FEAT_FLOOR:
7481 case FEAT_DIRT:
7482 case FEAT_GRASS:
7483 case FEAT_SAND:
7484 case FEAT_ASH:
7485 case FEAT_MUD:
7486 /* case FEAT_PUDDLE: new feature to be added: same as shallow water, but dries out after a while */
7487 case FEAT_FLOWER: feat = FEAT_NETHER_MIST;
7488 }
7489 /* todo: submerged ruins/small water cave only water floor, grinding ice only ice floor.
7490 maybe add d_info flags for this stuff instead of hard-coding here */
7491
7492 /* Change the feature */
7493 c_ptr->feat = feat;
7494 aquatic_terrain_hack(zcave, x, y);
7495
7496 if (level_generation_time) return;
7497
7498 /* XXX it's not needed when called from generate.c */
7499 for (i = 1; i <= NumPlayers; i++) {
7500 p_ptr = Players[i];
7501
7502 /* Only works for players on the level */
7503 if (!inarea(wpos, &p_ptr->wpos)) continue;
7504
7505 /* Notice */
7506 note_spot(i, y, x);
7507
7508 /* Redraw */
7509 lite_spot(i, y, x);
7510 }
7511 }
7512
7513 /*
7514 * This is a copy of cave_set_feat that is used for "live" changes to the world
7515 * by players and monsters. More specific restrictions can be placed here.
7516 * NOTE: We assume, that allow_terraforming() has already been checked before
7517 * cave_set_feat_live() is actually called.
7518 */
7519 void cave_set_feat_live(worldpos *wpos, int y, int x, int feat) {
7520 player_type *p_ptr;
7521 cave_type **zcave;
7522 cave_type *c_ptr;
7523 struct c_special *cs_ptr;
7524 int i;
7525 // struct town_type *t_ptr; /* have town keep track of number of feature changes (not yet implemented) */
7526
7527 if (!(zcave = getcave(wpos))) return;
7528 if (!in_bounds(y, x)) return;
7529 c_ptr = &zcave[y][x];
7530
7531 /* apply town-specific restrictions, preserving the intended town layout */
7532 if (istown(wpos)) {
7533 #if 0
7534 t_ptr = &town[wild_info[wpos->wx][wpos->wy].town_idx];
7535
7536 switch (feat) {
7537 case FEAT_TREE:
7538 case FEAT_BUSH:
7539 if (TOWN_TERRAFORM_TREES == 0) return;
7540 break;
7541 case FEAT_WALL_EXTRA:
7542 case FEAT_QUARTZ:
7543 case FEAT_MAGMA:
7544 if (TOWN_TERRAFORM_WALLS == 0) return;
7545 break;
7546 case FEAT_SHAL_WATER:
7547 case FEAT_DEEP_WATER:
7548 if (TOWN_TERRAFORM_WATER == 0) return;
7549 break;
7550 case FEAT_GLYPH:
7551 case FEAT_RUNE:
7552 if (TOWN_TERRAFORM_GLYPHS == 0) return;
7553 break;
7554 }
7555
7556 switch (c_ptr->feat) {
7557 case FEAT_TREE:
7558 case FEAT_BUSH:
7559 if (TOWN_TERRAFORM_TREES == 0) return;
7560 break;
7561 case FEAT_WALL_EXTRA:
7562 case FEAT_QUARTZ:
7563 case FEAT_MAGMA:
7564 if (TOWN_TERRAFORM_WALLS == 0) return;
7565 break;
7566 case FEAT_SHAL_WATER:
7567 case FEAT_DEEP_WATER:
7568 if (TOWN_TERRAFORM_WATER == 0) return;
7569 break;
7570 case FEAT_GLYPH:
7571 case FEAT_RUNE:
7572 if (TOWN_TERRAFORM_GLYPHS == 0) return;
7573 break;
7574 }
7575 #else
7576 /* hack: only allow around store entrances */
7577 if (feat == FEAT_GLYPH || feat == FEAT_RUNE) {
7578 return; //disallow glyphs
7579
7580 for (i = 0; i < 9; i++)
7581 if (zcave[y + ddy_ddd[i]][x + ddx_ddd[i]].feat == FEAT_SHOP) break;
7582 /* no nearby store entrance found? */
7583 if (i == 9) return;
7584 }
7585 #endif
7586 }
7587
7588 /* No runes of protection / glyphs of warding on non-empty grids - C. Blue */
7589 if ((feat == FEAT_GLYPH || feat == FEAT_RUNE) && !(cave_clean_bold(zcave, y, x) && /* cave_clean_bold also checks for object absence */
7590 ((c_ptr->feat == FEAT_NONE) ||
7591 (c_ptr->feat == FEAT_FLOOR) ||
7592 (c_ptr->feat == FEAT_DIRT) ||
7593 (c_ptr->feat == FEAT_LOOSE_DIRT) || /* used for gardens (fields) in wild.c */
7594 (c_ptr->feat == FEAT_CROP) || /* used for gardens (fields) in wild.c */
7595 (c_ptr->feat == FEAT_GRASS) ||
7596 (c_ptr->feat == FEAT_ICE) ||
7597 (c_ptr->feat == FEAT_SAND) ||
7598 (c_ptr->feat == FEAT_ASH) ||
7599 (c_ptr->feat == FEAT_MUD) ||
7600 (c_ptr->feat == FEAT_FLOWER) ||
7601 (c_ptr->feat == FEAT_NETHER_MIST))))
7602 return;
7603
7604 /* Don't mess with inns please! */
7605 if (f_info[c_ptr->feat].flags1 & FF1_PROTECTED) return;
7606
7607 /* No terraforming on impossible ground -
7608 compare twall_erosion() for consistency */
7609 #if 0
7610 if ((feat == FEAT_TREE || feat == FEAT_BUSH || feat == FEAT_FLOOR ||
7611 feat == FEAT_WALL_EXTRA || feat == FEAT_QUARTZ || feat == FEAT_MAGMA) &&
7612 feat_mud, feat_dirt, etc.... just #else maybe easier?..
7613 (c_ptr->feat == FEAT_DEEP_LAVA ||
7614 c_ptr->feat == FEAT_DEEP_WATER))
7615 #else
7616 if (c_ptr->feat == FEAT_DEEP_LAVA || c_ptr->feat == FEAT_DEEP_WATER)
7617 #endif
7618 return;
7619
7620 /* in Nether Realm, floor is always nether mist (or lava)! */
7621 if (in_netherrealm(wpos)) switch (feat) {
7622 case FEAT_IVY:
7623 case FEAT_SHAL_WATER:
7624 case FEAT_DEEP_WATER:
7625 case FEAT_ICE:
7626 case FEAT_FLOOR:
7627 case FEAT_DIRT:
7628 case FEAT_GRASS:
7629 case FEAT_SAND:
7630 case FEAT_ASH:
7631 case FEAT_MUD:
7632 /* case FEAT_PUDDLE: new feature to be added: same as shallow water, but dries out after a while */
7633 case FEAT_FLOWER: feat = FEAT_NETHER_MIST;
7634 }
7635
7636 /* todo: submerged ruins/small water cave only water floor, grinding ice only ice floor.
7637 maybe add d_info flags for this stuff instead of hard-coding here */
7638
7639
7640
7641 /* Trees in greater fire become dead trees at once */
7642 if ((feat == FEAT_TREE || feat == FEAT_BUSH) &&
7643 (c_ptr->feat == FEAT_SHAL_LAVA ||
7644 c_ptr->feat == FEAT_FIRE ||
7645 c_ptr->feat == FEAT_GREAT_FIRE))
7646 feat = FEAT_DEAD_TREE;
7647
7648 /* Clear mimic feature left by a secret door - mikaelh */
7649 if ((cs_ptr = GetCS(c_ptr, CS_MIMIC)))
7650 cs_erase(c_ptr, cs_ptr);
7651
7652 /* Change the feature */
7653 if (c_ptr->feat != feat) c_ptr->info &= ~CAVE_NEST_PIT; /* clear teleport protection for nest grid if it gets changed */
7654 c_ptr->feat = feat;
7655
7656 for (i = 1; i <= NumPlayers; i++) {
7657 p_ptr = Players[i];
7658
7659 /* Only works for players on the level */
7660 if (!inarea(wpos, &p_ptr->wpos)) continue;
7661
7662 #if 0 /* done in melee2.c when a monster eats a wall, so it's visible from afar, if level is mapped, that "walls turn black" */
7663 /* Forget the spot */
7664 Players[i]->cave_flag[y][x] &= ~CAVE_MARK;
7665 #endif
7666
7667 /* Notice */
7668 note_spot(i, y, x);
7669
7670 /* Redraw */
7671 lite_spot(i, y, x);
7672
7673 /* Update some things */
7674 p_ptr->update |= (PU_VIEW | PU_DISTANCE);
7675 // p_ptr->update |= PU_FLOW;
7676
7677 // p_ptr->redraw |= PR_MAP;
7678 // p_ptr->window |= PW_OVERHEAD;
7679 }
7680 }
7681
7682
7683
7684 /*
7685 * Calculate "incremental motion". Used by project() and shoot().
7686 * Assumes that (*y,*x) lies on the path from (y1,x1) to (y2,x2).
7687 */
7688 void mmove2(int *y, int *x, int y1, int x1, int y2, int x2)
7689 {
7690 int dy, dx, dist, shift;
7691
7692 /* Extract the distance travelled */
7693 dy = (*y < y1) ? y1 - *y : *y - y1;
7694 dx = (*x < x1) ? x1 - *x : *x - x1;
7695
7696 /* Number of steps */
7697 dist = (dy > dx) ? dy : dx;
7698
7699 /* We are calculating the next location */
7700 dist++;
7701
7702
7703 /* Calculate the total distance along each axis */
7704 dy = (y2 < y1) ? (y1 - y2) : (y2 - y1);
7705 dx = (x2 < x1) ? (x1 - x2) : (x2 - x1);
7706
7707 /* Paranoia -- Hack -- no motion */
7708 if (!dy && !dx) return;
7709
7710
7711 /* Move mostly vertically */
7712 if (dy > dx)
7713 {
7714
7715 #if 0
7716
7717 int k;
7718
7719 /* Starting shift factor */
7720 shift = dy >> 1;
7721
7722 /* Extract a shift factor */
7723 for (k = 0; k < dist; k++)
7724 {
7725 if (shift <= 0) shift += dy;
7726 shift -= dx;
7727 }
7728
7729 /* Sometimes move along minor axis */
7730 if (shift <= 0) (*x) = (x2 < x1) ? (*x - 1) : (*x + 1);
7731
7732 /* Always move along major axis */
7733 (*y) = (y2 < y1) ? (*y - 1) : (*y + 1);
7734
7735 #endif
7736
7737 /* Extract a shift factor */
7738 shift = (dist * dx + (dy-1) / 2) / dy;
7739
7740 /* Sometimes move along the minor axis */
7741 (*x) = (x2 < x1) ? (x1 - shift) : (x1 + shift);
7742
7743 /* Always move along major axis */
7744 (*y) = (y2 < y1) ? (y1 - dist) : (y1 + dist);
7745 }
7746
7747 /* Move mostly horizontally */
7748 else
7749 {
7750
7751 #if 0
7752
7753 int k;
7754
7755 /* Starting shift factor */
7756 shift = dx >> 1;
7757
7758 /* Extract a shift factor */
7759 for (k = 0; k < dist; k++)
7760 {
7761 if (shift <= 0) shift += dx;
7762 shift -= dy;
7763 }
7764
7765 /* Sometimes move along minor axis */
7766 if (shift <= 0) (*y) = (y2 < y1) ? (*y - 1) : (*y + 1);
7767
7768 /* Always move along major axis */
7769 (*x) = (x2 < x1) ? (*x - 1) : (*x + 1);
7770
7771 #endif
7772
7773 /* Extract a shift factor */
7774 shift = (dist * dy + (dx-1) / 2) / dx;
7775
7776 /* Sometimes move along the minor axis */
7777 (*y) = (y2 < y1) ? (y1 - shift) : (y1 + shift);
7778
7779 /* Always move along major axis */
7780 (*x) = (x2 < x1) ? (x1 - dist) : (x1 + dist);
7781 }
7782 }
7783
7784
7785 /*
7786 * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
7787 * at the final destination, assuming no monster gets in the way.
7788 *
7789 * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
7790 */
7791 #ifdef DOUBLE_LOS_SAFETY
7792 static bool projectable_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range);
7793 bool projectable(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range) {
7794 return (projectable_DLS(wpos, y1, x1, y2, x2, range) || projectable_DLS(wpos, y2, x2, y1, x1, range));
7795 }
7796 static bool projectable_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range) {
7797 #else
7798 bool projectable(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range) {
7799 #endif
7800 int dist, y, x;
7801 cave_type **zcave;
7802 if (!(zcave = getcave(wpos))) return FALSE;
7803
7804 #ifdef DOUBLE_LOS_SAFETY
7805 /* catch ball-spell related call in project() which adds '+ dir * 99' aka distance of 99 */
7806 if (!in_bounds(y1, x1)) return(FALSE);
7807 #endif
7808
7809 /* Start at the initial location */
7810 y = y1, x = x1;
7811
7812 /* See "project()" */
7813 for (dist = 0; dist <= range; dist++) {
7814 /* Never pass through walls */
7815 if (dist && !cave_los(zcave, y, x)) break;
7816
7817 /* Stopped by protected grids (Inn doors, also stopping monsters' ranged attacks!) */
7818 if (f_info[zcave[y][x].feat].flags1 & (FF1_BLOCK_LOS | FF1_BLOCK_CONTACT)) break;
7819
7820 /* Check for arrival at "final target" */
7821 if ((x == x2) && (y == y2)) return (TRUE);
7822
7823 /* Calculate the new location */
7824 mmove2(&y, &x, y1, x1, y2, x2);
7825 }
7826
7827 /* Assume obstruction */
7828 return (FALSE);
7829 }
7830
7831 /* Same as projectable(), but allows targetting the first grid in a wall */
7832 #ifdef DOUBLE_LOS_SAFETY
7833 static bool projectable_wall_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range);
7834 bool projectable_wall(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range) {
7835 return (projectable_wall_DLS(wpos, y1, x1, y2, x2, range) || projectable_wall_DLS(wpos, y2, x2, y1, x1, range));
7836 }
7837 static bool projectable_wall_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range) {
7838 #else
7839 bool projectable_wall(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range) {
7840 #endif
7841 int dist, y, x;
7842 cave_type **zcave;
7843 if (!(zcave = getcave(wpos))) return(FALSE);
7844
7845 #ifdef DOUBLE_LOS_SAFETY
7846 /* catch ball-spell related call in project() which adds '+ dir * 99' aka distance of 99 */
7847 if (!in_bounds(y1, x1)) return(FALSE);
7848 #endif
7849
7850 /* Start at the initial location */
7851 y = y1, x = x1;
7852
7853 /* See "project()" */
7854 for (dist = 0; dist <= range; dist++) {
7855 /* Protected grids prevent targetting */
7856 if (f_info[zcave[y][x].feat].flags1 & (FF1_BLOCK_LOS | FF1_BLOCK_CONTACT)) break;
7857
7858 /* Check for arrival at "final target" */
7859 if ((x == x2) && (y == y2)) return (TRUE);
7860
7861 /* Never go through walls */
7862 if (dist && !cave_los(zcave, y, x)) break;
7863
7864 /* Calculate the new location */
7865 mmove2(&y, &x, y1, x1, y2, x2);
7866 }
7867
7868 /* Assume obstruction */
7869 return (FALSE);
7870 }
7871
7872 /* like projectable_wall(), but assumes that only _permanent walls_ are really obstacles to us
7873 (for movement strategies of PASS_WALL/KILL_WALL monsters) - C. Blue */
7874 #ifdef DOUBLE_LOS_SAFETY
7875 static bool projectable_wall_perm_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range);
7876 bool projectable_wall_perm(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range) {
7877 return (projectable_wall_perm_DLS(wpos, y1, x1, y2, x2, range) || projectable_wall_perm_DLS(wpos, y2, x2, y1, x1, range));
7878 }
7879 static bool projectable_wall_perm_DLS(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range) {
7880 #else
7881 bool projectable_wall_perm(struct worldpos *wpos, int y1, int x1, int y2, int x2, int range) {
7882 #endif
7883 int dist, y, x;
7884 cave_type **zcave;
7885 if (!(zcave = getcave(wpos))) return(FALSE);
7886
7887 /* Start at the initial location */
7888 y = y1, x = x1;
7889
7890 /* See "project()" */
7891 for (dist = 0; dist <= range; dist++) {
7892 /* Protected grids prevent targetting */
7893 if (f_info[zcave[y][x].feat].flags1 & FF1_PERMANENT) break;
7894
7895 /* Check for arrival at "final target" */
7896 if ((x == x2) && (y == y2)) return (TRUE);
7897
7898 /* Calculate the new location */
7899 mmove2(&y, &x, y1, x1, y2, x2);
7900 }
7901
7902 /* Assume obstruction */
7903 return (FALSE);
7904 }
7905
7906 /*
7907 * Created for shoot_till_kill mode in do_cmd_fire().
7908 * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
7909 * at the final destination, and if no monster/hostile player is in the way. - C. Blue
7910 * Note: Only sleeping monsters are tested for!
7911 * Note: The hostile-player part is commented out for efficiency atm.
7912 *
7913 */
7914 #ifdef DOUBLE_LOS_SAFETY
7915 static bool projectable_real_DLS(int Ind, int y1, int x1, int y2, int x2, int range);
7916 bool projectable_real(int Ind, int y1, int x1, int y2, int x2, int range) {
7917 return ((projectable_DLS(&Players[Ind]->wpos, y1, x1, y2, x2, range) || projectable_DLS(&Players[Ind]->wpos, y2, x2, y1, x1, range))
7918 /* important: make sure we really don't hit an awake monster from our direction of shooting :-p : */
7919 && projectable_real_DLS(Ind, y1, x1, y2, x2, range));
7920 }
7921 static bool projectable_real_DLS(int Ind, int y1, int x1, int y2, int x2, int range) {
7922 int dist, y = y1, x = x1;
7923 cave_type **zcave;
7924 if (!(zcave = getcave(&Players[Ind]->wpos))) return FALSE;
7925
7926 for (dist = 0; dist <= range; dist++) {
7927 if ((x == x2) && (y == y2)) return (TRUE);
7928
7929 /* Never pass through SLEEPING monsters */
7930 if (dist && (zcave[y][x].m_idx > 0)
7931 && target_able(Ind, zcave[y][x].m_idx)
7932 && m_list[zcave[y][x].m_idx].csleep) break;
7933
7934 #if 0
7935 /* Never pass through hostile player */
7936 if (dist && zcave[y][x].m_idx < 0) {
7937 if (check_hostile(Ind, -zcave[y][x].m_idx)) break;
7938 }
7939 #endif
7940 mmove2(&y, &x, y1, x1, y2, x2);
7941 }
7942 return (FALSE);
7943 }
7944 #else
7945 bool projectable_real(int Ind, int y1, int x1, int y2, int x2, int range) {
7946 int dist, y, x;
7947 cave_type **zcave;
7948 if (!(zcave = getcave(&Players[Ind]->wpos))) return FALSE;
7949
7950 /* Start at the initial location */
7951 y = y1, x = x1;
7952
7953 /* See "project()" */
7954 for (dist = 0; dist <= range; dist++) {
7955 /* Never pass through walls */
7956 if (dist && !cave_los(zcave, y, x)) break;
7957
7958 /* Stopped by protected grids (Inn doors, also stopping monsters' ranged attacks!) */
7959 if (f_info[zcave[y][x].feat].flags1 & (FF1_BLOCK_LOS | FF1_BLOCK_CONTACT)) break;
7960
7961 /* Check for arrival at "final target" */
7962 if ((x == x2) && (y == y2)) return (TRUE);
7963
7964 /* Never pass through SLEEPING monsters */
7965 if (dist && (zcave[y][x].m_idx > 0)
7966 && target_able(Ind, zcave[y][x].m_idx)
7967 && m_list[zcave[y][x].m_idx].csleep) break;
7968
7969 #if 0
7970 /* Never pass through hostile player */
7971 if (dist && zcave[y][x].m_idx < 0) {
7972 if (check_hostile(Ind, -zcave[y][x].m_idx)) break;
7973 }
7974 #endif
7975
7976 /* Calculate the new location */
7977 mmove2(&y, &x, y1, x1, y2, x2);
7978 }
7979
7980 /* Assume obstruction */
7981 return (FALSE);
7982 }
7983 #endif
7984
7985 /* Relates to projectable_real like projectable_wall to projectable */
7986 #ifdef DOUBLE_LOS_SAFETY
7987 static bool projectable_wall_real_DLS(int Ind, int y1, int x1, int y2, int x2, int range);
7988 bool projectable_wall_real(int Ind, int y1, int x1, int y2, int x2, int range) {
7989 return ((projectable_wall_DLS(&Players[Ind]->wpos, y1, x1, y2, x2, range) || projectable_wall_DLS(&Players[Ind]->wpos, y2, x2, y1, x1, range))
7990 /* important: make sure we really don't hit an awake monster from our direction of shooting :-p : */
7991 && projectable_wall_real_DLS(Ind, y1, x1, y2, x2, range));
7992 }
7993 static bool projectable_wall_real_DLS(int Ind, int y1, int x1, int y2, int x2, int range) {
7994 int dist, y, x;
7995 cave_type **zcave;
7996 if (!(zcave = getcave(&Players[Ind]->wpos))) return FALSE;
7997
7998 /* Start at the initial location */
7999 y = y1, x = x1;
8000
8001 /* See "project()" */
8002 for (dist = 0; dist <= range; dist++) {
8003 /* Check for arrival at "final target" */
8004 if ((x == x2) && (y == y2)) return (TRUE);
8005
8006 /* Never pass through SLEEPING monsters */
8007 if (dist && (zcave[y][x].m_idx > 0)
8008 && target_able(Ind, zcave[y][x].m_idx)
8009 && m_list[zcave[y][x].m_idx].csleep) break;
8010
8011 #if 0
8012 /* Never pass through hostile player */
8013 if (dist && zcave[y][x].m_idx < 0) {
8014 if (check_hostile(Ind, -zcave[y][x].m_idx)) break;
8015 }
8016 #endif
8017
8018 /* Calculate the new location */
8019 mmove2(&y, &x, y1, x1, y2, x2);
8020 }
8021
8022 /* Assume obstruction */
8023 return (FALSE);
8024 }
8025 #else
8026 bool projectable_wall_real(int Ind, int y1, int x1, int y2, int x2, int range)
8027 {
8028 int dist, y, x;
8029 cave_type **zcave;
8030 if (!(zcave = getcave(&Players[Ind]->wpos))) return FALSE;
8031
8032 /* Start at the initial location */
8033 y = y1, x = x1;
8034
8035 /* See "project()" */
8036 for (dist = 0; dist <= range; dist++) {
8037 /* Stopped by protected grids (Inn doors, also stopping monsters' ranged attacks!) */
8038 if (f_info[zcave[y][x].feat].flags1 & (FF1_BLOCK_LOS | FF1_BLOCK_CONTACT)) break;
8039
8040 /* Check for arrival at "final target" */
8041 if ((x == x2) && (y == y2)) return (TRUE);
8042
8043 /* Never pass through walls */
8044 if (dist && !cave_los(zcave, y, x)) break;
8045
8046 /* Never pass through SLEEPING monsters */
8047 if (dist && (zcave[y][x].m_idx > 0)
8048 && target_able(Ind, zcave[y][x].m_idx)
8049 && m_list[zcave[y][x].m_idx].csleep) break;
8050
8051 #if 0
8052 /* Never pass through hostile player */
8053 if (dist && zcave[y][x].m_idx < 0) {
8054 if (check_hostile(Ind, -zcave[y][x].m_idx)) break;
8055 }
8056 #endif
8057
8058 /* Calculate the new location */
8059 mmove2(&y, &x, y1, x1, y2, x2);
8060 }
8061
8062 /* Assume obstruction */
8063 return (FALSE);
8064 }
8065 #endif
8066
8067 /*
8068 * Standard "find me a location" function
8069 *
8070 * Obtains a legal location within the given distance of the initial
8071 * location, and with "los()" from the source to destination location.
8072 *
8073 * This function is often called from inside a loop which searches for
8074 * locations while increasing the "d" distance.
8075 *
8076 * Currently the "m" parameter is unused.
8077 *
8078 * But now the "m" parameter specifies whether "los" is necessary.
8079 */
8080 /* if d<16, consider using tdi,tdy,tdx; considerably quicker! */
8081 void scatter(struct worldpos *wpos, int *yp, int *xp, int y, int x, int d, int m)
8082 {
8083 int nx, ny;
8084 // long tries = 100000;
8085 /* Reduced to 10k to lessen lockups - mikaelh */
8086 long tries = 10000;
8087
8088 cave_type **zcave;
8089 if (!(zcave = getcave(wpos))) {
8090 (*yp) = y;
8091 (*xp) = x;
8092 return;
8093 }
8094
8095 /* Pick a location */
8096 while (TRUE)
8097 {
8098 /* Don't freeze in infinite loop!
8099 Conditions: wpos is not allocated.
8100 Note: los() returns TRUE if x==nx and y==ny.
8101 Due to the conditions, following code will probably cause panic save,
8102 that's still better than infinite loop though. */
8103 tries--;
8104 if (!tries) {
8105 s_printf("!!! INFINITE LOOP IN scatter() !!! -- Please reboot server and do '/unsta %d,%d,%d (%d,%d; %d,%d; %d %d)'\n",
8106 wpos->wx, wpos->wy,wpos->wz, yp, xp, y, x, d, m);
8107 ny = y;
8108 nx = x;
8109 break;
8110 }
8111
8112 /* Pick a new location */
8113 ny = rand_spread(y, d);
8114 nx = rand_spread(x, d);
8115
8116 /* Ignore illegal locations and outer walls */
8117 if (!in_bounds(ny, nx)) continue;
8118
8119 /* Ignore "excessively distant" locations */
8120 if ((d > 1) && (distance(y, x, ny, nx) > d)) continue;
8121
8122 /* Require "line of sight" */
8123 if (m || los(wpos, y, x, ny, nx)) break;
8124 }
8125
8126 /* Save the location */
8127 (*yp) = ny;
8128 (*xp) = nx;
8129 }
8130
8131 /*
8132 * Track a new monster
8133 */
8134 void health_track(int Ind, int m_idx)
8135 {
8136 player_type *p_ptr = Players[Ind];
8137
8138 /* Track a new guy */
8139 p_ptr->health_who = m_idx;
8140
8141 /* Redraw (later) */
8142 p_ptr->redraw |= (PR_HEALTH);
8143 }
8144
8145 /*
8146 * Update the health bars for anyone tracking a monster
8147 */
8148 void update_health(int m_idx)
8149 {
8150 player_type *p_ptr;
8151 int i;
8152
8153 /* Each player */
8154 for (i = 1; i <= NumPlayers; i++)
8155 {
8156 p_ptr = Players[i];
8157
8158 /* Check connection */
8159 if (p_ptr->conn == NOT_CONNECTED)
8160 continue;
8161
8162 /* See if he is tracking this monster */
8163 if (p_ptr->health_who == m_idx)
8164 {
8165 /* Redraw */
8166 p_ptr->redraw |= (PR_HEALTH);
8167 }
8168 }
8169 }
8170
8171
8172
8173 /*
8174 * Hack -- track the given monster race
8175 *
8176 * Monster recall is disabled for now --KLJ--
8177 */
8178 void recent_track(int r_idx)
8179 {
8180 /* Save this monster ID */
8181 /*recent_idx = r_idx;*/
8182
8183 /* Window stuff */
8184 /*p_ptr->window |= (PW_MONSTER);*/
8185 }
8186
8187
8188
8189
8190 /*
8191 * Something has happened to disturb the player.
8192 *
8193 * The first arg indicates a major disturbance, which affects search.
8194 *
8195 * The second arg is currently unused, but could induce output flush.
8196 *
8197 * All disturbance cancels repeated commands, resting, and running.
8198 */
8199 void disturb(int Ind, int stop_search, int keep_resting) {
8200 player_type *p_ptr = Players[Ind];
8201
8202 /* Calm down from silly running */
8203 p_ptr->corner_turn = 0;
8204
8205 /* Cancel auto-commands */
8206 /* command_new = 0; */
8207
8208 /* Cancel repeated commands */
8209 if (p_ptr->command_rep) {
8210 /* Cancel */
8211 p_ptr->command_rep = 0;
8212 #ifdef ENABLE_XID_SPELL
8213 p_ptr->current_item = -1; //unnecessary?
8214 #endif
8215
8216 /* Hack -- Clear the buffer */
8217 Handle_clear_buffer(Ind);
8218
8219 /* Redraw the state (later) */
8220 p_ptr->redraw |= (PR_STATE);
8221 }
8222
8223 /* Cancel Resting */
8224 if (!keep_resting && p_ptr->resting) {
8225 /* Cancel */
8226 p_ptr->resting = 0;
8227
8228 /* Redraw the state (later) */
8229 p_ptr->redraw |= (PR_STATE);
8230 }
8231
8232 /* Cancel running */
8233 if (p_ptr->running) {
8234 /* Cancel */
8235 p_ptr->running = 0;
8236
8237 /* Calculate torch radius */
8238 p_ptr->update |= (PU_TORCH);
8239 }
8240
8241 /* Cancel searching if requested */
8242 if (stop_search && p_ptr->searching) {
8243 /* Cancel */
8244 p_ptr->searching = FALSE;
8245
8246 /* Recalculate bonuses */
8247 p_ptr->update |= (PU_BONUS);
8248
8249 /* Redraw stuff */
8250 p_ptr->redraw |= (PR_STATE | PR_MAP);
8251
8252 /* cancel cloaking preparations too */
8253 stop_cloaking(Ind);
8254 }
8255 }
8256
8257
8258
8259
8260
8261 /*
8262 * Hack -- Check if a level is a "quest" level
8263 */
8264 /* FIXME - use worldpos and dungeon array! */
8265 bool is_xorder(struct worldpos *wpos) {
8266 /* not implemented yet :p */
8267 return (FALSE);
8268 #if 0
8269 int i;
8270
8271 /* Town is never a quest */
8272 if (!level) return (FALSE);
8273
8274 /* Check quests */
8275 for (i = 0; i < MAX_XO_IDX; i++) {
8276 /* Check for quest */
8277 if (xo_list[i].level == level) return (TRUE);
8278 }
8279
8280 /* Nope */
8281 return (FALSE);
8282 #endif
8283 }
8284
8285 /*
8286 * handle spell effects
8287 */
8288 static int effect_pop(int who)
8289 {
8290 int i, cnt = 0;
8291
8292 for (i = 1; i < MAX_EFFECTS; i++) /* effects[0] is not used */
8293 {
8294 if (!effects[i].time) return i;
8295 if (effects[i].who == who)
8296 {
8297 if (++cnt > MAX_EFFECTS_PLAYER) return -1;
8298 }
8299
8300 }
8301 return -1;
8302 }
8303
8304 int new_effect(int who, int type, int dam, int time, int interval, worldpos *wpos, int cy, int cx, int rad, s32b flags)
8305 {
8306 int i, who2 = who;
8307 /* player_type *p_ptr = NULL; */
8308 #if 0 /* isn't this wrong? */
8309 if (who < 0 && who != PROJECTOR_EFFECT)
8310 who2 = 0 - Players[0 - who]->id;
8311 #else
8312 if (who < 0 && who > PROJECTOR_UNUSUAL)
8313 who2 = 0 - Players[0 - who]->id;
8314 #endif
8315
8316 if ((i = effect_pop(who2)) == -1) return -1;
8317 effects[i].interval = interval;
8318 effects[i].type = type;
8319 effects[i].dam = dam;
8320 effects[i].time = time;
8321 effects[i].flags = flags;
8322 effects[i].cx = cx;
8323 effects[i].cy = cy;
8324 effects[i].rad = rad;
8325 effects[i].who = who2;
8326 wpcopy(&effects[i].wpos, wpos);
8327 #ifdef ARCADE_SERVER
8328 if (type == 209)
8329 {
8330 msg_broadcast(0, "mh");
8331 if (flags > 0)
8332 msg_broadcast(0, "some flags");
8333 else
8334 msg_broadcast(0, "no flags");
8335 }
8336 /* if ((flags & EFF_CROSSHAIR_A) || (flags & EFF_CROSSHAIR_B) || (flags & EFF_CROSSHAIR_C))
8337 {
8338 msg_broadcast(0, "making an effect");
8339 player_type *pfft_ptr = Players[interval];
8340 pfft_ptr->e = i;
8341 } */
8342 #endif
8343
8344 return i;
8345 }
8346
8347 bool allow_terraforming(struct worldpos *wpos, byte feat) {
8348 bool bree = in_bree(wpos);
8349 bool town = istown(wpos) || isdungeontown(wpos);
8350 bool townarea = istownarea(wpos, MAX_TOWNAREA);
8351 //unused atm bool dungeon_town = isdungeontown(wpos);
8352 bool sector00 = (in_sector00(wpos));
8353 bool valinor = in_valinor(wpos);
8354 bool nr_bottom = in_netherrealm(wpos) && getlevel(wpos) == netherrealm_end;
8355 bool arena_pvp = (wpos->wx == WPOS_PVPARENA_X && wpos->wy == WPOS_PVPARENA_Y && wpos->wz == WPOS_PVPARENA_Z);
8356 bool arena_monster = (ge_special_sector && wpos->wx == WPOS_ARENA_X && wpos->wy == WPOS_ARENA_Y && wpos->wz == WPOS_ARENA_Z);
8357
8358 /* usually allow all changes (normal dungeons and town-unrelated world map) */
8359 if (!arena_monster && !arena_pvp && !bree && !town && !townarea && !sector00 && !valinor && !nr_bottom) return(TRUE);
8360
8361 /* preserve arenas; disallow trees for balancing (pvp-arena) */
8362 if (arena_pvp || arena_monster) return(FALSE);
8363
8364 switch (feat) {
8365 /* water is annoying in all towns - mikaelh */
8366 case FEAT_SHAL_WATER:
8367 case FEAT_DEEP_WATER:
8368 if (town) return(FALSE);
8369 break;
8370
8371 /* allow only harmless as well as non-obstructing changes: */
8372 case FEAT_IVY:
8373 case FEAT_DEAD_TREE:
8374 case FEAT_ICE:
8375 if (town || sector00 || valinor || nr_bottom) return(FALSE);
8376 break;
8377
8378 case FEAT_WALL_EXTRA: /* tested by earthquake() and destroy_area() */
8379 case FEAT_SHAL_LAVA:
8380 case FEAT_DEEP_LAVA:
8381 if (town || townarea || sector00 || valinor || nr_bottom) return(FALSE);
8382 break;
8383
8384 case FEAT_TREE: /* also for 'digging' and 'stone2mud' */
8385 case FEAT_BUSH: /* just moved here because FEAT_TREE is also here */
8386 if (town || sector00 || valinor || nr_bottom) return(FALSE);
8387 break;
8388
8389 case FEAT_GLYPH:
8390 case FEAT_RUNE:
8391 /* generally allow in town, restrictions are applied in cave_set_feat_live().) */
8392 if (sector00 || valinor || nr_bottom) return(FALSE);
8393 break;
8394
8395 /* don't allow any changes at all to preserve the visuals 100% */
8396 case FEAT_NONE:
8397 case FEAT_FLOOR:
8398 case FEAT_DIRT:
8399 case FEAT_GRASS:
8400 case FEAT_SAND:
8401 case FEAT_ASH:
8402 case FEAT_MUD:
8403 case FEAT_FLOWER:
8404 /* case FEAT_PUDDLE: new feature to be added: same as shallow water, but dries out after a while */
8405 if (town || valinor || nr_bottom) return(FALSE);
8406 break;
8407
8408 /* generate.c uses these for staircases in towns */
8409 case FEAT_MORE:
8410 case FEAT_LESS:
8411 case FEAT_WAY_MORE:
8412 case FEAT_WAY_LESS:
8413 case FEAT_BETWEEN:
8414 case FEAT_BEACON:
8415 break;
8416
8417 /* forgot any? just paranoia */
8418 default: ;
8419 }
8420
8421 return (TRUE);
8422 }
8423
8424 /*
8425 * Queues a spot for redrawing at the beginning of the next turn.
8426 * Can be used for leaving temporary effects on the screen for one turn.
8427 */
8428 void everyone_lite_later_spot(struct worldpos *wpos, int y, int x) {
8429 struct worldspot *wspot;
8430
8431 if (lite_later_num >= lite_later_alloc) {
8432 /* Grow the array to meet the demand */
8433 GROW(lite_later, lite_later_alloc, lite_later_alloc * 2, struct worldspot);
8434 lite_later_alloc *= 2;
8435 }
8436
8437 /* Add a new spot to the array */
8438 wspot = &lite_later[lite_later_num];
8439 lite_later_num++;
8440
8441 wpcopy(&wspot->wpos, wpos);
8442 wspot->x = x;
8443 wspot->y = y;
8444 }
8445
8446 /* change between the four seasons - C. Blue
8447 s: the season (0..3 -> spring,summer,autumn,winter)
8448 force: true -> force redrawing all sectors
8449 even if season didn't change. */
8450 void season_change(int s, bool force) {
8451 int x, y;
8452 struct worldpos wpos;
8453
8454 /* if 'force' is off, at least ensure correct weather frequency here: */
8455 #if defined CLIENT_WEATHER_GLOBAL || !defined CLIENT_SIDE_WEATHER
8456 /* adjust weather somewhat according to season! (server-side or global weather) */
8457 switch (s) {
8458 case SEASON_SPRING: /* rain relatively often */
8459 weather_frequency = 2; break;
8460 case SEASON_SUMMER: /* rain rarely */
8461 weather_frequency = 1; break;
8462 case SEASON_AUTUMN: /* rain very often */
8463 weather_frequency = 3; break;
8464 case SEASON_WINTER: /* snow relatively often */
8465 weather_frequency = 2; break;
8466 }
8467 #else
8468 /* adjust weather somewhat according to season! (client-side non-global weather) */
8469 switch (s) {
8470 case SEASON_SPRING: /* rain relatively often */
8471 max_clouds_seasonal = MAX_CLOUDS / 10; break;
8472 case SEASON_SUMMER: /* rain rarely */
8473 max_clouds_seasonal = MAX_CLOUDS / 14; break;
8474 case SEASON_AUTUMN: /* rain very often */
8475 max_clouds_seasonal = MAX_CLOUDS / 7; break;
8476 case SEASON_WINTER: /* snow pretty often */
8477 max_clouds_seasonal = MAX_CLOUDS / 8; break;
8478 }
8479 #endif
8480
8481 if ((season == s) && !force) return;
8482 season = s;
8483
8484 /* make wilderness more lively again */
8485 lively_wild(0);
8486
8487 /* rebuild wilderness + town layout everywhere! */
8488 wpos.wz = 0;
8489 for (x = 0; x < MAX_WILD_X; x++)
8490 for (y = 0; y < MAX_WILD_Y; y++) {
8491 wpos.wx = x;
8492 wpos.wy = y;
8493 if (getcave(&wpos)) regenerate_cave(&wpos);
8494 }
8495
8496 s_printf("(%s) SEASON_CHANGE: %d", showtime(), s);
8497 if (s == SEASON_SPRING) {
8498 s_printf(" spring");
8499 world_surface_msg("\374\377GSpring has arrived.");
8500 }
8501 if (s == SEASON_SUMMER) {
8502 s_printf(" summer");
8503 world_surface_msg("\374\377GSummer has come.");
8504 }
8505 if (s == SEASON_AUTUMN) {
8506 s_printf(" autumn");
8507 world_surface_msg("\374\377GAutumn paints the scenery.");
8508 }
8509 if (s == SEASON_WINTER) {
8510 s_printf(" winter");
8511 world_surface_msg("\374\377GWinter embraces the lands.");
8512 }
8513 s_printf("\n");
8514
8515 /* redraw map for all players */
8516 for (x = 1; x <= NumPlayers; x++) Players[x]->redraw |= PR_MAP;
8517
8518 /* make all clouds terminate soon, to account for changed climate situation */
8519 for (x = 0; x < MAX_CLOUDS; x++) {
8520 /* does cloud exist? */
8521 if (cloud_dur[x]) /* also affects 'dur = -1' clouds */
8522 cloud_dur[x] = 5 + rand_int(10); /* terminate in 5..15 seconds */
8523 }
8524 }
8525
8526 /* Update players' client-side weather. - C. Blue
8527 entered_level = TRUE : player just newly entered this sector
8528 weather_changed = TRUE : weather just changed, reset the player's
8529 client-side weather synchronization timings (see c-xtra1.c).
8530 NOTE: if entered_level is TRUE, so should be weather_changed!
8531 panel_redraw is only TRUE if we also want to instantly redraw the current
8532 panel without waiting for usual number of client ticks.
8533 NOTE: Called on opportunities (ie when player moves around)
8534 and also by players_weather(). */
8535 #if 1
8536 /* make rain fall down slower? */
8537 #define WEATHER_GEN_TICKS 3
8538 #define WEATHER_SNOW_MULT 3
8539 #else
8540 /* make rain fall down faster? */
8541 #define WEATHER_GEN_TICKS 2
8542 #define WEATHER_SNOW_MULT 4
8543 #endif
8544 void player_weather(int Ind, bool entered_level, bool weather_changed, bool panel_redraw) {
8545 player_type *p_ptr = Players[Ind];
8546 int w;
8547
8548 /* running custom weather for debugging purpose? */
8549 if (p_ptr->custom_weather) return;
8550
8551 /* not in dungeon? erase weather and exit */
8552 if (p_ptr->wpos.wz) {
8553 if (!entered_level) return;
8554 /* erase weather */
8555 Send_weather(Ind, -1, 0, WEATHER_GEN_TICKS,
8556 WEATHER_GEN_TICKS, WEATHER_GEN_TICKS,
8557 FALSE, TRUE);
8558 return;
8559 }
8560
8561 /* no weather in sector00 during events */
8562 if (in_sector00(&p_ptr->wpos)) {
8563 if (!entered_level) return;
8564 /* erase weather */
8565 Send_weather(Ind, -1, 0, WEATHER_GEN_TICKS,
8566 WEATHER_GEN_TICKS, WEATHER_GEN_TICKS,
8567 FALSE, TRUE);
8568 return;
8569 }
8570
8571 #ifdef CLIENT_WEATHER_GLOBAL /* use global weather instead of sector-specific? */
8572 w = ((entered_level) ? ((weather) ? 200 : -1) : 0);
8573 Send_weather(Ind,
8574 weather + w
8575 + ((weather_changed && (w != -1)) ? 10000 : 0)
8576 + ((weather && panel_redraw) ? 20000 : 0),
8577 /* (wind_gust > 0 ? 1 : (wind_gust < 0 ? 2 : 0))
8578 + ((wind_gust != 0) && (season == SEASON_WINTER) ? 4 : 0), */
8579 (wind_gust > 0 ? 2 * (season == SEASON_WINTER ? WEATHER_SNOW_MULT : 1) * WEATHER_GEN_TICKS - 1
8580 : (wind_gust < 0 ? 2 * (season == SEASON_WINTER ? WEATHER_SNOW_MULT : 1) * WEATHER_GEN_TICKS : 0)),
8581 WEATHER_GEN_TICKS,
8582 (season == SEASON_WINTER) ? 5 : 8,
8583 (season == SEASON_WINTER) ? WEATHER_SNOW_MULT * WEATHER_GEN_TICKS :
8584 /* hack: for non-windy rainfall, accelerate raindrop falling speed by 1: */
8585 (wind_gust ? 1 * WEATHER_GEN_TICKS : WEATHER_GEN_TICKS - 1),
8586 FALSE, TRUE); /* no virtual cloud if weather is global */
8587
8588 #else /* send his worldmap sector's specific weather situation */
8589 w = ((entered_level) ? ((wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_type) ? 200 : -1) : 0); /* +(n*10): pre-generate n particles? */
8590 #if 0 /* buggy? */
8591 Send_weather(Ind,
8592 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_type + w
8593 #else
8594 Send_weather(Ind,
8595 ((w == -1) ? -1 : (wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_type + w))
8596 #endif
8597 + ((weather_changed && (w != -1)) ? 10000 : 0) /* sync panel? */
8598 #if 0 /* glitchy? paranoia maybe */
8599 + (weather && panel_redraw ? 20000 : 0),
8600 #else
8601 + ((weather && panel_redraw && (w != -1)) ? 20000 : 0), /* insta-refresh? */
8602 #endif
8603 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_wind,
8604 WEATHER_GEN_TICKS,
8605 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_intensity,
8606 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_speed,
8607 TRUE, FALSE); /* <- apply clouds! */
8608
8609 #ifdef TEST_SERVER /* DEBUG */
8610 #if 0
8611 s_printf(" updated weather for player %d to type %d (real: %d).\n", Ind,
8612 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_type + w
8613 + ((weather_changed && (w != -1)) ? 10000 : 0)
8614 + (weather && panel_redraw ? 20000 : 0),
8615 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_type);
8616 s_printf(" (wind %d, intensity %d, speed %d)\n",
8617 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_wind,
8618 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_intensity,
8619 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_speed);
8620 #endif
8621 #endif
8622 #endif
8623 }
8624
8625
8626 /* The is_stairs/is_doors hack in monster_can_cross_terrain() that allows
8627 aquatic monsters to cross doors and stairs in 'underwater' levels had the
8628 bad side effect of causing aquatic monsters on normal levels to seek out
8629 stairs/doors and get stuck on them. To fix this in turn, I added CAVE_WATERY
8630 and this hack that applies it. - C. Blue */
8631 void aquatic_terrain_hack(cave_type **zcave, int x, int y) {
8632 int d, xx, yy;
8633
8634 if (!is_always_passable(zcave[y][x].feat)) return;
8635
8636 for (d = 1; d <= 9; d++) {
8637 if (d == 5) continue;
8638 xx = x + ddx[d];
8639 yy = y + ddy[d];
8640 if (!in_bounds(yy, xx)) continue;
8641 if (zcave[yy][xx].feat == FEAT_DEEP_WATER) {
8642 zcave[y][x].info |= CAVE_WATERY;
8643 return;
8644 }
8645 }
8646 }
8647
8648 /* Special wpos that ought to keep monsters and/or objects instead of deleting
8649 or compacting them, even though the floor might not necessarily be kept
8650 static. - C. Blue
8651 Added for IDDC static towns, could maybe also be used for quests. */
8652 bool sustained_wpos(struct worldpos *wpos) {
8653 if (is_fixed_irondeepdive_town(wpos, getlevel(wpos))) return TRUE;
8654 return FALSE;
8655 }
8656