1 /**
2 * \file cave.c
3 * \brief chunk allocation and utility functions
4 *
5 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6 *
7 * This work is free software; you can redistribute it and/or modify it
8 * under the terms of either:
9 *
10 * a) the GNU General Public License as published by the Free Software
11 * Foundation, version 2, or
12 *
13 * b) the "Angband licence":
14 * This software may be copied and distributed for educational, research,
15 * and not for profit purposes provided that this copyright and statement
16 * are included in all such copies. Other copyrights may also apply.
17 */
18
19 #include "angband.h"
20 #include "cave.h"
21 #include "cmds.h"
22 #include "cmd-core.h"
23 #include "game-event.h"
24 #include "game-world.h"
25 #include "init.h"
26 #include "mon-group.h"
27 #include "monster.h"
28 #include "obj-ignore.h"
29 #include "obj-pile.h"
30 #include "obj-tval.h"
31 #include "obj-util.h"
32 #include "object.h"
33 #include "player-timed.h"
34 #include "trap.h"
35
36 struct feature *f_info;
37 struct chunk *cave = NULL;
38
39 int FEAT_NONE;
40 int FEAT_FLOOR;
41 int FEAT_CLOSED;
42 int FEAT_OPEN;
43 int FEAT_BROKEN;
44 int FEAT_LESS;
45 int FEAT_MORE;
46 int FEAT_SECRET;
47 int FEAT_RUBBLE;
48 int FEAT_PASS_RUBBLE;
49 int FEAT_MAGMA;
50 int FEAT_QUARTZ;
51 int FEAT_MAGMA_K;
52 int FEAT_QUARTZ_K;
53 int FEAT_GRANITE;
54 int FEAT_PERM;
55 int FEAT_LAVA;
56
57 /**
58 * Global array for looping through the "keypad directions".
59 */
60 const s16b ddd[9] =
61 { 2, 8, 6, 4, 3, 1, 9, 7, 5 };
62
63 /**
64 * Global arrays for converting "keypad direction" into "offsets".
65 */
66 const s16b ddx[10] =
67 { 0, -1, 0, 1, -1, 0, 1, -1, 0, 1 };
68
69 const s16b ddy[10] =
70 { 0, 1, 1, 1, 0, 0, 0, -1, -1, -1 };
71
72
73 const struct loc ddgrid[10] =
74 { {0, 0}, {-1, 1}, {0, 1}, {1, 1}, {-1, 0}, {0, 0}, {1, 0}, {-1, -1}, {0, -1},
75 {1, -1} };
76
77 /**
78 * Global arrays for optimizing "ddx[ddd[i]]", "ddy[ddd[i]]" and
79 * "loc(ddx[ddd[i]], ddy[ddd[i]])".
80 *
81 * This means that each entry in this array corresponds to the direction
82 * with the same array index in ddd[].
83 */
84 const s16b ddx_ddd[9] =
85 { 0, 0, 1, -1, 1, -1, 1, -1, 0 };
86
87 const s16b ddy_ddd[9] =
88 { 1, -1, 0, 0, 1, 1, -1, -1, 0 };
89
90 const struct loc ddgrid_ddd[9] =
91 {{0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, 1}, {-1, 1}, {1, -1}, {-1, -1}, {0, 0}};
92
93 /* Can mult these by 45 deg or 1.5 o'clock e.g. [6] -> 270 deg or 9 o'clock */
94 const s16b clockwise_ddd[9] =
95 { 8, 9, 6, 3, 2, 1, 4, 7, 5 };
96
97 const struct loc clockwise_grid[9] =
98 {{0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, 0}};
99
100 /**
101 * Hack -- Precompute a bunch of calls to distance().
102 *
103 * The pair of arrays dist_offsets_y[n] and dist_offsets_x[n] contain the
104 * offsets of all the locations with a distance of n from a central point,
105 * with an offset of (0,0) indicating no more offsets at this distance.
106 *
107 * This is, of course, fairly unreadable, but it eliminates multiple loops
108 * from the previous version.
109 *
110 * It is probably better to replace these arrays with code to compute
111 * the relevant arrays, even if the storage is pre-allocated in hard
112 * coded sizes. At the very least, code should be included which is
113 * able to generate and dump these arrays (ala "los()"). XXX XXX XXX
114 */
115
116
117 static const int d_off_y_0[] =
118 { 0 };
119
120 static const int d_off_x_0[] =
121 { 0 };
122
123
124 static const int d_off_y_1[] =
125 { -1, -1, -1, 0, 0, 1, 1, 1, 0 };
126
127 static const int d_off_x_1[] =
128 { -1, 0, 1, -1, 1, -1, 0, 1, 0 };
129
130
131 static const int d_off_y_2[] =
132 { -1, -1, -2, -2, -2, 0, 0, 1, 1, 2, 2, 2, 0 };
133
134 static const int d_off_x_2[] =
135 { -2, 2, -1, 0, 1, -2, 2, -2, 2, -1, 0, 1, 0 };
136
137
138 static const int d_off_y_3[] =
139 { -1, -1, -2, -2, -3, -3, -3, 0, 0, 1, 1, 2, 2,
140 3, 3, 3, 0 };
141
142 static const int d_off_x_3[] =
143 { -3, 3, -2, 2, -1, 0, 1, -3, 3, -3, 3, -2, 2,
144 -1, 0, 1, 0 };
145
146
147 static const int d_off_y_4[] =
148 { -1, -1, -2, -2, -3, -3, -3, -3, -4, -4, -4, 0,
149 0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 0 };
150
151 static const int d_off_x_4[] =
152 { -4, 4, -3, 3, -2, -3, 2, 3, -1, 0, 1, -4, 4,
153 -4, 4, -3, 3, -2, -3, 2, 3, -1, 0, 1, 0 };
154
155
156 static const int d_off_y_5[] =
157 { -1, -1, -2, -2, -3, -3, -4, -4, -4, -4, -5, -5,
158 -5, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5,
159 5, 0 };
160
161 static const int d_off_x_5[] =
162 { -5, 5, -4, 4, -4, 4, -2, -3, 2, 3, -1, 0, 1,
163 -5, 5, -5, 5, -4, 4, -4, 4, -2, -3, 2, 3, -1,
164 0, 1, 0 };
165
166
167 static const int d_off_y_6[] =
168 { -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -5, -5,
169 -6, -6, -6, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5,
170 5, 5, 6, 6, 6, 0 };
171
172 static const int d_off_x_6[] =
173 { -6, 6, -5, 5, -5, 5, -4, 4, -2, -3, 2, 3, -1,
174 0, 1, -6, 6, -6, 6, -5, 5, -5, 5, -4, 4, -2,
175 -3, 2, 3, -1, 0, 1, 0 };
176
177
178 static const int d_off_y_7[] =
179 { -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -5, -5,
180 -6, -6, -6, -6, -7, -7, -7, 0, 0, 1, 1, 2, 2, 3,
181 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 0 };
182
183 static const int d_off_x_7[] =
184 { -7, 7, -6, 6, -6, 6, -5, 5, -4, -5, 4, 5, -2,
185 -3, 2, 3, -1, 0, 1, -7, 7, -7, 7, -6, 6, -6,
186 6, -5, 5, -4, -5, 4, 5, -2, -3, 2, 3, -1, 0,
187 1, 0 };
188
189
190 static const int d_off_y_8[] =
191 { -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6,
192 -6, -6, -7, -7, -7, -7, -8, -8, -8, 0, 0, 1, 1,
193 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
194 8, 8, 8, 0 };
195
196 static const int d_off_x_8[] =
197 { -8, 8, -7, 7, -7, 7, -6, 6, -6, 6, -4, -5, 4,
198 5, -2, -3, 2, 3, -1, 0, 1, -8, 8, -8, 8, -7,
199 7, -7, 7, -6, 6, -6, 6, -4, -5, 4, 5, -2, -3,
200 2, 3, -1, 0, 1, 0 };
201
202
203 static const int d_off_y_9[] =
204 { -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6,
205 -7, -7, -7, -7, -8, -8, -8, -8, -9, -9, -9, 0,
206 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7,
207 7, 8, 8, 8, 8, 9, 9, 9, 0 };
208
209 static const int d_off_x_9[] =
210 { -9, 9, -8, 8, -8, 8, -7, 7, -7, 7, -6, 6, -4,
211 -5, 4, 5, -2, -3, 2, 3, -1, 0, 1, -9, 9, -9,
212 9, -8, 8, -8, 8, -7, 7, -7, 7, -6, 6, -4, -5,
213 4, 5, -2, -3, 2, 3, -1, 0, 1, 0 };
214
215
216 const int *dist_offsets_y[10] =
217 {
218 d_off_y_0, d_off_y_1, d_off_y_2, d_off_y_3, d_off_y_4,
219 d_off_y_5, d_off_y_6, d_off_y_7, d_off_y_8, d_off_y_9
220 };
221
222 const int *dist_offsets_x[10] =
223 {
224 d_off_x_0, d_off_x_1, d_off_x_2, d_off_x_3, d_off_x_4,
225 d_off_x_5, d_off_x_6, d_off_x_7, d_off_x_8, d_off_x_9
226 };
227
228
229 /**
230 * Given a central direction at position [dir #][0], return a series
231 * of directions radiating out on both sides from the central direction
232 * all the way back to its rear.
233 *
234 * Side directions come in pairs; for example, directions '1' and '3'
235 * flank direction '2'. The code should know which side to consider
236 * first. If the left, it must add 10 to the central direction to
237 * access the second part of the table.
238 */
239 const byte side_dirs[20][8] = {
240 {0, 0, 0, 0, 0, 0, 0, 0}, /* bias right */
241 {1, 4, 2, 7, 3, 8, 6, 9},
242 {2, 1, 3, 4, 6, 7, 9, 8},
243 {3, 2, 6, 1, 9, 4, 8, 7},
244 {4, 7, 1, 8, 2, 9, 3, 6},
245 {5, 5, 5, 5, 5, 5, 5, 5},
246 {6, 3, 9, 2, 8, 1, 7, 4},
247 {7, 8, 4, 9, 1, 6, 2, 3},
248 {8, 9, 7, 6, 4, 3, 1, 2},
249 {9, 6, 8, 3, 7, 2, 4, 1},
250
251 {0, 0, 0, 0, 0, 0, 0, 0}, /* bias left */
252 {1, 2, 4, 3, 7, 6, 8, 9},
253 {2, 3, 1, 6, 4, 9, 7, 8},
254 {3, 6, 2, 9, 1, 8, 4, 7},
255 {4, 1, 7, 2, 8, 3, 9, 6},
256 {5, 5, 5, 5, 5, 5, 5, 5},
257 {6, 9, 3, 8, 2, 7, 1, 4},
258 {7, 4, 8, 1, 9, 2, 6, 3},
259 {8, 7, 9, 4, 6, 1, 3, 2},
260 {9, 8, 6, 7, 3, 4, 2, 1}
261 };
262
263 /**
264 * Given a "start" and "finish" location, extract a "direction",
265 * which will move one step from the "start" towards the "finish".
266 *
267 * Note that we use "diagonal" motion whenever possible.
268 *
269 * We return DIR_NONE if no motion is needed.
270 */
motion_dir(struct loc start,struct loc finish)271 int motion_dir(struct loc start, struct loc finish)
272 {
273 /* No movement required */
274 if (loc_eq(start, finish)) return (DIR_NONE);
275
276 /* South or North */
277 if (start.x == finish.x) return ((start.y < finish.y) ? DIR_S : DIR_N);
278
279 /* East or West */
280 if (start.y == finish.y) return ((start.x < finish.x) ? DIR_E : DIR_W);
281
282 /* South-east or South-west */
283 if (start.y < finish.y) return ((start.x < finish.x) ? DIR_SE : DIR_SW);
284
285 /* North-east or North-west */
286 if (start.y > finish.y) return ((start.x < finish.x) ? DIR_NE : DIR_NW);
287
288 /* Paranoia */
289 return (DIR_NONE);
290 }
291
292 /**
293 * Given a grid and a direction, extract the adjacent grid in that direction
294 */
next_grid(struct loc grid,int dir)295 struct loc next_grid(struct loc grid, int dir)
296 {
297 return loc(grid.x + ddgrid[dir].x, grid.y + ddgrid[dir].y);
298 }
299
300 /**
301 * Find a terrain feature index by name
302 */
lookup_feat(const char * name)303 int lookup_feat(const char *name)
304 {
305 int i;
306
307 /* Look for it */
308 for (i = 0; i < z_info->f_max; i++) {
309 struct feature *feat = &f_info[i];
310 if (!feat->name)
311 continue;
312
313 /* Test for equality */
314 if (streq(name, feat->name))
315 return i;
316 }
317
318 /* Fail horribly */
319 quit_fmt("Failed to find terrain feature %s", name);
320 return -1;
321 }
322
323 /**
324 * Set terrain constants to the indices from terrain.txt
325 */
set_terrain(void)326 void set_terrain(void)
327 {
328 FEAT_NONE = lookup_feat("unknown grid");
329 FEAT_FLOOR = lookup_feat("open floor");
330 FEAT_CLOSED = lookup_feat("closed door");
331 FEAT_OPEN = lookup_feat("open door");
332 FEAT_BROKEN = lookup_feat("broken door");
333 FEAT_LESS = lookup_feat("up staircase");
334 FEAT_MORE = lookup_feat("down staircase");
335 FEAT_SECRET = lookup_feat("secret door");
336 FEAT_RUBBLE = lookup_feat("pile of rubble");
337 FEAT_PASS_RUBBLE = lookup_feat("pile of passable rubble");
338 FEAT_MAGMA = lookup_feat("magma vein");
339 FEAT_QUARTZ = lookup_feat("quartz vein");
340 FEAT_MAGMA_K = lookup_feat("magma vein with treasure");
341 FEAT_QUARTZ_K = lookup_feat("quartz vein with treasure");
342 FEAT_GRANITE = lookup_feat("granite wall");
343 FEAT_PERM = lookup_feat("permanent wall");
344 FEAT_LAVA = lookup_feat("lava");
345 }
346
347 /**
348 * Allocate a new chunk of the world
349 */
cave_new(int height,int width)350 struct chunk *cave_new(int height, int width) {
351 int y, x;
352
353 struct chunk *c = mem_zalloc(sizeof *c);
354 c->height = height;
355 c->width = width;
356 c->feat_count = mem_zalloc((z_info->f_max + 1) * sizeof(int));
357
358 c->squares = mem_zalloc(c->height * sizeof(struct square*));
359 c->noise.grids = mem_zalloc(c->height * sizeof(u16b*));
360 c->scent.grids = mem_zalloc(c->height * sizeof(u16b*));
361 for (y = 0; y < c->height; y++) {
362 c->squares[y] = mem_zalloc(c->width * sizeof(struct square));
363 for (x = 0; x < c->width; x++) {
364 c->squares[y][x].info = mem_zalloc(SQUARE_SIZE * sizeof(bitflag));
365 }
366 c->noise.grids[y] = mem_zalloc(c->width * sizeof(u16b));
367 c->scent.grids[y] = mem_zalloc(c->width * sizeof(u16b));
368 }
369
370 c->objects = mem_zalloc(OBJECT_LIST_SIZE * sizeof(struct object*));
371 c->obj_max = OBJECT_LIST_SIZE - 1;
372
373 c->monsters = mem_zalloc(z_info->level_monster_max *sizeof(struct monster));
374 c->mon_max = 1;
375 c->mon_current = -1;
376
377 c->monster_groups = mem_zalloc(z_info->level_monster_max *
378 sizeof(struct monster_group*));
379
380 c->turn = turn;
381 return c;
382 }
383
384 /**
385 * Free a chunk
386 */
cave_free(struct chunk * c)387 void cave_free(struct chunk *c) {
388 int y, x, i;
389
390 while (c->join) {
391 struct connector *current = c->join;
392 mem_free(current->info);
393 c->join = current->next;
394 mem_free(current);
395 }
396
397 /* Look for orphaned objects and delete them. */
398 for (i = 1; i < c->obj_max; i++) {
399 if (c->objects[i] && loc_is_zero(c->objects[i]->grid)) {
400 object_delete(&c->objects[i]);
401 }
402 }
403
404 for (y = 0; y < c->height; y++) {
405 for (x = 0; x < c->width; x++) {
406 mem_free(c->squares[y][x].info);
407 if (c->squares[y][x].trap)
408 square_free_trap(c, loc(x, y));
409 if (c->squares[y][x].obj)
410 object_pile_free(c->squares[y][x].obj);
411 }
412 mem_free(c->squares[y]);
413 mem_free(c->noise.grids[y]);
414 mem_free(c->scent.grids[y]);
415 }
416 mem_free(c->squares);
417 mem_free(c->noise.grids);
418 mem_free(c->scent.grids);
419
420 mem_free(c->feat_count);
421 mem_free(c->objects);
422 mem_free(c->monsters);
423 mem_free(c->monster_groups);
424 if (c->name)
425 string_free(c->name);
426 mem_free(c);
427 }
428
429
430 /**
431 * Enter an object in the list of objects for the current level/chunk. This
432 * function is robust against listing of duplicates or non-objects
433 */
list_object(struct chunk * c,struct object * obj)434 void list_object(struct chunk *c, struct object *obj)
435 {
436 int i, newsize;
437
438 /* Check for duplicates and objects already deleted or combined */
439 if (!obj) return;
440 for (i = 1; i < c->obj_max; i++)
441 if (c->objects[i] == obj)
442 return;
443
444 /* Put objects in holes in the object list */
445 for (i = 1; i < c->obj_max; i++) {
446 /* If there is a known object, skip this slot */
447 if ((c == cave) && player->cave && player->cave->objects[i]) {
448 continue;
449 }
450
451 /* Put the object in a hole */
452 if (c->objects[i] == NULL) {
453 c->objects[i] = obj;
454 obj->oidx = i;
455 return;
456 }
457 }
458
459 /* Extend the list */
460 newsize = (c->obj_max + OBJECT_LIST_INCR + 1) * sizeof(struct object*);
461 c->objects = mem_realloc(c->objects, newsize);
462 c->objects[c->obj_max] = obj;
463 obj->oidx = c->obj_max;
464 for (i = c->obj_max + 1; i <= c->obj_max + OBJECT_LIST_INCR; i++)
465 c->objects[i] = NULL;
466 c->obj_max += OBJECT_LIST_INCR;
467
468 /* If we're on the current level, extend the known list */
469 if ((c == cave) && player->cave) {
470 player->cave->objects = mem_realloc(player->cave->objects, newsize);
471 for (i = player->cave->obj_max; i <= c->obj_max; i++)
472 player->cave->objects[i] = NULL;
473 player->cave->obj_max = c->obj_max;
474 }
475 }
476
477 /**
478 * Remove an object from the list of objects for the current level/chunk. This
479 * function is robust against delisting of unlisted objects.
480 */
delist_object(struct chunk * c,struct object * obj)481 void delist_object(struct chunk *c, struct object *obj)
482 {
483 if (!obj->oidx) return;
484 assert(c->objects[obj->oidx] == obj);
485
486 /* Don't delist an actual object if it still has a listed known object */
487 if ((c == cave) && player->cave->objects[obj->oidx]) return;
488
489 c->objects[obj->oidx] = NULL;
490 obj->oidx = 0;
491 }
492
493 /**
494 * Check consistency of an object list or a pair of object lists
495 *
496 * If one list, check the listed objects relate to locations of
497 * objects correctly
498 */
object_lists_check_integrity(struct chunk * c,struct chunk * c_k)499 void object_lists_check_integrity(struct chunk *c, struct chunk *c_k)
500 {
501 int i;
502 if (c_k) {
503 assert(c->obj_max == c_k->obj_max);
504 for (i = 0; i < c->obj_max; i++) {
505 struct object *obj = c->objects[i];
506 struct object *known_obj = c_k->objects[i];
507 if (obj) {
508 assert(obj->oidx == i);
509 if (!loc_is_zero(obj->grid))
510 assert(pile_contains(square_object(c, obj->grid), obj));
511 }
512 if (known_obj) {
513 assert (obj);
514 if (player->upkeep->playing) {
515 assert(known_obj == obj->known);
516 }
517 if (!loc_is_zero(known_obj->grid))
518 assert (pile_contains(square_object(c_k, known_obj->grid),
519 known_obj));
520 assert (known_obj->oidx == i);
521 }
522 }
523 } else {
524 for (i = 0; i < c->obj_max; i++) {
525 struct object *obj = c->objects[i];
526 if (obj) {
527 assert(obj->oidx == i);
528 if (!loc_is_zero(obj->grid))
529 assert(pile_contains(square_object(c, obj->grid), obj));
530 }
531 }
532 }
533 }
534
535 /**
536 * Standard "find me a location" function, now with all legal outputs!
537 *
538 * Obtains a legal location within the given distance of the initial
539 * location, and with "los()" from the source to destination location.
540 *
541 * This function is often called from inside a loop which searches for
542 * locations while increasing the "d" distance.
543 *
544 * need_los determines whether line of sight is needed
545 */
scatter(struct chunk * c,struct loc * place,struct loc grid,int d,bool need_los)546 void scatter(struct chunk *c, struct loc *place, struct loc grid, int d,
547 bool need_los)
548 {
549 int tries = 0;
550
551 /* Pick a location, try many times */
552 while (tries < 1000) {
553 /* Pick a new location */
554 struct loc new_grid = rand_loc(grid, d, d);
555 tries++;
556
557 /* Ignore annoying locations */
558 if (!square_in_bounds_fully(c, new_grid)) continue;
559
560 /* Ignore "excessively distant" locations */
561 if ((d > 1) && (distance(grid, new_grid) > d)) continue;
562
563 /* Require "line of sight" if set */
564 if (need_los && !los(c, grid, new_grid)) continue;
565
566 /* Set the location and return */
567 *place = new_grid;
568 return;
569 }
570 }
571
572
573 /**
574 * Get a monster on the current level by its index.
575 */
cave_monster(struct chunk * c,int idx)576 struct monster *cave_monster(struct chunk *c, int idx) {
577 if (idx <= 0) return NULL;
578 return &c->monsters[idx];
579 }
580
581 /**
582 * The maximum number of monsters allowed in the level.
583 */
cave_monster_max(struct chunk * c)584 int cave_monster_max(struct chunk *c) {
585 return c->mon_max;
586 }
587
588 /**
589 * The current number of monsters present on the level.
590 */
cave_monster_count(struct chunk * c)591 int cave_monster_count(struct chunk *c) {
592 return c->mon_cnt;
593 }
594
595 /**
596 * Return the number of doors/traps around (or under) the character.
597 */
count_feats(struct loc * grid,bool (* test)(struct chunk * c,struct loc grid),bool under)598 int count_feats(struct loc *grid,
599 bool (*test)(struct chunk *c, struct loc grid), bool under)
600 {
601 int d;
602 struct loc grid1;
603 int count = 0; /* Count how many matches */
604
605 /* Check around (and under) the character */
606 for (d = 0; d < 9; d++) {
607 /* if not searching under player continue */
608 if ((d == 8) && !under) continue;
609
610 /* Extract adjacent (legal) location */
611 grid1 = loc_sum(player->grid, ddgrid_ddd[d]);
612
613 /* Paranoia */
614 if (!square_in_bounds_fully(cave, grid1)) continue;
615
616 /* Must have knowledge */
617 if (!square_isknown(cave, grid1)) continue;
618
619 /* Not looking for this feature */
620 if (!((*test)(cave, grid1))) continue;
621
622 /* Count it */
623 ++count;
624
625 /* Remember the location of the last door found */
626 if (grid) {
627 *grid = grid1;
628 }
629 }
630
631 /* All done */
632 return count;
633 }
634
cave_find_decoy(struct chunk * c)635 struct loc cave_find_decoy(struct chunk *c)
636 {
637 return c->decoy;
638 }
639