ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/map.C
Revision: 1.110
Committed: Sun Jul 1 05:00:17 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.109: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# Content
1 /*
2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 *
4 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5 * Copyright (©) 2001-2003,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Crossfire TRT is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 */
23
24 #include <unistd.h>
25
26 #include "global.h"
27 #include "funcpoint.h"
28
29 #include "loader.h"
30
31 #include "path.h"
32
33 /*
34 * This makes a path absolute outside the world of Crossfire.
35 * In other words, it prepends LIBDIR/MAPDIR/ to the given path
36 * and returns the pointer to a static array containing the result.
37 * it really should be called create_mapname
38 */
39 const char *
40 create_pathname (const char *name)
41 {
42 static char buf[8192];
43 snprintf (buf, sizeof (buf), "%s/%s/%s", settings.datadir, settings.mapdir, name);
44 return buf;
45 }
46
47 /*
48 * This function checks if a file with the given path exists.
49 * -1 is returned if it fails, otherwise the mode of the file
50 * is returned.
51 * It tries out all the compression suffixes listed in the uncomp[] array.
52 *
53 * If prepend_dir is set, then we call create_pathname (which prepends
54 * libdir & mapdir). Otherwise, we assume the name given is fully
55 * complete.
56 * Only the editor actually cares about the writablity of this -
57 * the rest of the code only cares that the file is readable.
58 * when the editor goes away, the call to stat should probably be
59 * replaced by an access instead (similar to the windows one, but
60 * that seems to be missing the prepend_dir processing
61 */
62 int
63 check_path (const char *name, int prepend_dir)
64 {
65 char buf[MAX_BUF];
66
67 char *endbuf;
68 struct stat statbuf;
69 int mode = 0;
70
71 if (prepend_dir)
72 assign (buf, create_pathname (name));
73 else
74 assign (buf, name);
75
76 /* old method (strchr(buf, '\0')) seemd very odd to me -
77 * this method should be equivalant and is clearer.
78 * Can not use strcat because we need to cycle through
79 * all the names.
80 */
81 endbuf = buf + strlen (buf);
82
83 if (stat (buf, &statbuf))
84 return -1;
85 if (!S_ISREG (statbuf.st_mode))
86 return (-1);
87
88 if (((statbuf.st_mode & S_IRGRP) && getegid () == statbuf.st_gid) ||
89 ((statbuf.st_mode & S_IRUSR) && geteuid () == statbuf.st_uid) || (statbuf.st_mode & S_IROTH))
90 mode |= 4;
91
92 if ((statbuf.st_mode & S_IWGRP && getegid () == statbuf.st_gid) ||
93 (statbuf.st_mode & S_IWUSR && geteuid () == statbuf.st_uid) || (statbuf.st_mode & S_IWOTH))
94 mode |= 2;
95
96 return (mode);
97 }
98
99 /* This rolls up wall, blocks_magic, blocks_view, etc, all into
100 * one function that just returns a P_.. value (see map.h)
101 * it will also do map translation for tiled maps, returning
102 * new values into newmap, nx, and ny. Any and all of those
103 * values can be null, in which case if a new map is needed (returned
104 * by a P_NEW_MAP value, another call to get_map_from_coord
105 * is needed. The case of not passing values is if we're just
106 * checking for the existence of something on those spaces, but
107 * don't expect to insert/remove anything from those spaces.
108 */
109 int
110 get_map_flags (maptile *oldmap, maptile **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny)
111 {
112 sint16 newx = x;
113 sint16 newy = y;
114
115 maptile *mp = get_map_from_coord (oldmap, &newx, &newy);
116
117 if (!mp)
118 return P_OUT_OF_MAP;
119
120 if (newmap) *newmap = mp;
121 if (nx) *nx = newx;
122 if (ny) *ny = newy;
123
124 return mp->at (newx, newy).flags () | (mp != oldmap ? P_NEW_MAP : 0);
125 }
126
127 /*
128 * Returns true if the given coordinate is blocked except by the
129 * object passed is not blocking. This is used with
130 * multipart monsters - if we want to see if a 2x2 monster
131 * can move 1 space to the left, we don't want its own area
132 * to block it from moving there.
133 * Returns TRUE if the space is blocked by something other than the
134 * monster.
135 * m, x, y are the target map/coordinates - needed for map tiling.
136 * the coordinates & map passed in should have been updated for tiling
137 * by the caller.
138 */
139 int
140 blocked_link (object *ob, maptile *m, int sx, int sy)
141 {
142 object *tmp;
143 int mflags, blocked;
144
145 /* Make sure the coordinates are valid - they should be, as caller should
146 * have already checked this.
147 */
148 if (OUT_OF_REAL_MAP (m, sx, sy))
149 {
150 LOG (llevError, "blocked_link: Passed map, x, y coordinates outside of map\n");
151 return 1;
152 }
153
154 /* Save some cycles - instead of calling get_map_flags(), just get the value
155 * directly.
156 */
157 mflags = m->at (sx, sy).flags ();
158
159 blocked = GET_MAP_MOVE_BLOCK (m, sx, sy);
160
161 /* If space is currently not blocked by anything, no need to
162 * go further. Not true for players - all sorts of special
163 * things we need to do for players.
164 */
165 if (ob->type != PLAYER && !(mflags & P_IS_ALIVE) && (blocked == 0))
166 return 0;
167
168 /* if there isn't anytyhing alive on this space, and this space isn't
169 * otherwise blocked, we can return now. Only if there is a living
170 * creature do we need to investigate if it is part of this creature
171 * or another. Likewise, only if something is blocking us do we
172 * need to investigate if there is a special circumstance that would
173 * let the player through (inventory checkers for example)
174 */
175 if (!(mflags & P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK (ob, blocked))
176 return 0;
177
178 ob = ob->head_ ();
179
180 /* We basically go through the stack of objects, and if there is
181 * some other object that has NO_PASS or FLAG_ALIVE set, return
182 * true. If we get through the entire stack, that must mean
183 * ob is blocking it, so return 0.
184 */
185 for (tmp = GET_MAP_OB (m, sx, sy); tmp; tmp = tmp->above)
186 {
187
188 /* This must be before the checks below. Code for inventory checkers. */
189 if (tmp->type == CHECK_INV && OB_MOVE_BLOCK (ob, tmp))
190 {
191 /* If last_sp is set, the player/monster needs an object,
192 * so we check for it. If they don't have it, they can't
193 * pass through this space.
194 */
195 if (tmp->last_sp)
196 {
197 if (check_inv_recursive (ob, tmp) == NULL)
198 return 1;
199 else
200 continue;
201 }
202 else
203 {
204 /* In this case, the player must not have the object -
205 * if they do, they can't pass through.
206 */
207 if (check_inv_recursive (ob, tmp) != NULL) /* player has object */
208 return 1;
209 else
210 continue;
211 }
212 } /* if check_inv */
213 else
214 {
215 /* Broke apart a big nasty if into several here to make
216 * this more readable. first check - if the space blocks
217 * movement, can't move here.
218 * second - if a monster, can't move there, unless it is a
219 * hidden dm
220 */
221 if (OB_MOVE_BLOCK (ob, tmp))
222 return 1;
223
224 if (tmp->flag [FLAG_ALIVE]
225 && tmp->head_ () != ob
226 && tmp != ob
227 && tmp->type != DOOR
228 && !(tmp->flag [FLAG_WIZ] && tmp->contr->hidden))
229 return 1;
230 }
231
232 }
233 return 0;
234 }
235
236 /*
237 * Returns true if the given object can't fit in the given spot.
238 * This is meant for multi space objects - for single space objecs,
239 * just calling get_map_blocked and checking that against movement type
240 * of object. This function goes through all the parts of the
241 * multipart object and makes sure they can be inserted.
242 *
243 * While this doesn't call out of map, the get_map_flags does.
244 *
245 * This function has been used to deprecate arch_out_of_map -
246 * this function also does that check, and since in most cases,
247 * a call to one would follow the other, doesn't make a lot of sense to
248 * have two seperate functions for this.
249 *
250 * This returns nonzero if this arch can not go on the space provided,
251 * 0 otherwise. the return value will contain the P_.. value
252 * so the caller can know why this object can't go on the map.
253 * Note that callers should not expect P_NEW_MAP to be set
254 * in return codes - since the object is multispace - if
255 * we did return values, what do you return if half the object
256 * is one map, half on another.
257 *
258 * Note this used to be arch_blocked, but with new movement
259 * code, we need to have actual object to check its move_type
260 * against the move_block values.
261 */
262 int
263 ob_blocked (const object *ob, maptile *m, sint16 x, sint16 y)
264 {
265 archetype *tmp;
266 int flag;
267 maptile *m1;
268 sint16 sx, sy;
269
270 if (!ob)
271 {
272 flag = get_map_flags (m, &m1, x, y, &sx, &sy);
273 if (flag & P_OUT_OF_MAP)
274 return P_OUT_OF_MAP;
275
276 /* don't have object, so don't know what types would block */
277 return m1->at (sx, sy).move_block;
278 }
279
280 for (tmp = ob->arch; tmp; tmp = (archetype *)tmp->more)
281 {
282 flag = get_map_flags (m, &m1, x + tmp->x, y + tmp->y, &sx, &sy);
283
284 if (flag & P_OUT_OF_MAP)
285 return P_OUT_OF_MAP;
286 if (flag & P_IS_ALIVE)
287 return P_IS_ALIVE;
288
289 mapspace &ms = m1->at (sx, sy);
290
291 /* find_first_free_spot() calls this function. However, often
292 * ob doesn't have any move type (when used to place exits)
293 * so the AND operation in OB_TYPE_MOVE_BLOCK doesn't work.
294 */
295
296 if (ob->move_type == 0 && ms.move_block != MOVE_ALL)
297 continue;
298
299 /* Note it is intentional that we check ob - the movement type of the
300 * head of the object should correspond for the entire object.
301 */
302 if (OB_TYPE_MOVE_BLOCK (ob, ms.move_block))
303 return P_NO_PASS;
304 }
305
306 return 0;
307 }
308
309 /* When the map is loaded, load_object does not actually insert objects
310 * into inventory, but just links them. What this does is go through
311 * and insert them properly.
312 * The object 'container' is the object that contains the inventory.
313 * This is needed so that we can update the containers weight.
314 */
315 void
316 fix_container (object *container)
317 {
318 object *tmp = container->inv, *next;
319
320 container->inv = 0;
321 while (tmp)
322 {
323 next = tmp->below;
324 if (tmp->inv)
325 fix_container (tmp);
326
327 insert_ob_in_ob (tmp, container);
328 tmp = next;
329 }
330
331 /* sum_weight will go through and calculate what all the containers are
332 * carrying.
333 */
334 sum_weight (container);
335 }
336
337 void
338 maptile::set_object_flag (int flag, int value)
339 {
340 if (!spaces)
341 return;
342
343 for (mapspace *ms = spaces + size (); ms-- > spaces; )
344 for (object *tmp = ms->bot; tmp; tmp = tmp->above)
345 tmp->flag [flag] = value;
346 }
347
348 /* link_multipart_objects go through all the objects on the map looking
349 * for objects whose arch says they are multipart yet according to the
350 * info we have, they only have the head (as would be expected when
351 * they are saved).
352 */
353 void
354 maptile::link_multipart_objects ()
355 {
356 if (!spaces)
357 return;
358
359 for (mapspace *ms = spaces + size (); ms-- > spaces; )
360 for (object *op = ms->bot; op; op = op->above)
361 {
362 /* already multipart - don't do anything more */
363 if (op->head_ () == op && !op->more && op->arch->more)
364 {
365 op->remove ();
366 op->expand_tail ();
367 insert (op, op->x, op->y, 0, INS_NO_MERGE | INS_ABOVE_FLOOR_ONLY | INS_NO_WALK_ON);
368 }
369 }
370 }
371
372 /*
373 * Loads (ands parses) the objects into a given map from the specified
374 * file pointer.
375 */
376 bool
377 maptile::_load_objects (object_thawer &f)
378 {
379 for (;;)
380 {
381 coroapi::cede_to_tick_every (100); // cede once in a while
382
383 switch (f.kw)
384 {
385 case KW_arch:
386 if (object *op = object::read (f, this))
387 {
388 if (op->inv)
389 sum_weight (op);
390
391 insert_ob_in_map (op, this, op, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP | INS_MAP_LOAD);
392 }
393
394 continue;
395
396 case KW_EOF:
397 return true;
398
399 default:
400 if (!f.parse_error ("map file"))
401 return false;
402 break;
403 }
404
405 f.next ();
406 }
407
408 return true;
409 }
410
411 void
412 maptile::activate ()
413 {
414 active = true;
415
416 if (spaces)
417 for (mapspace *ms = spaces + size (); ms-- > spaces; )
418 for (object *op = ms->bot; op; op = op->above)
419 op->activate_recursive ();
420 }
421
422 void
423 maptile::deactivate ()
424 {
425 active = false;
426
427 if (spaces)
428 for (mapspace *ms = spaces + size (); ms-- > spaces; )
429 for (object *op = ms->bot; op; op = op->above)
430 op->deactivate_recursive ();
431 }
432
433 bool
434 maptile::_save_objects (object_freezer &f, int flags)
435 {
436 coroapi::cede_to_tick ();
437
438 if (flags & IO_HEADER)
439 _save_header (f);
440
441 if (!spaces)
442 return false;
443
444 for (int i = 0; i < size (); ++i)
445 {
446 int unique = 0;
447 for (object *op = spaces [i].bot; op; op = op->above)
448 {
449 if (op->flag [FLAG_UNIQUE] && op->flag [FLAG_IS_FLOOR])
450 unique = 1;
451
452 if (!op->can_map_save ())
453 continue;
454
455 if (unique || op->flag [FLAG_UNIQUE])
456 {
457 if (flags & IO_UNIQUES)
458 op->write (f);
459 }
460 else if (flags & IO_OBJECTS)
461 op->write (f);
462 }
463 }
464
465 coroapi::cede_to_tick ();
466
467 return true;
468 }
469
470 bool
471 maptile::_load_objects (const char *path, bool skip_header)
472 {
473 object_thawer f (path);
474
475 if (!f)
476 return false;
477
478 f.next ();
479
480 if (skip_header)
481 for (;;)
482 {
483 keyword kw = f.kw;
484 f.skip ();
485 if (kw == KW_end)
486 break;
487 }
488
489 return _load_objects (f);
490 }
491
492 bool
493 maptile::_save_objects (const char *path, int flags)
494 {
495 object_freezer freezer;
496
497 if (!_save_objects (freezer, flags))
498 return false;
499
500 return freezer.save (path);
501 }
502
503 maptile::maptile ()
504 {
505 in_memory = MAP_SWAPPED;
506
507 /* The maps used to pick up default x and y values from the
508 * map archetype. Mimic that behaviour.
509 */
510 width = 16;
511 height = 16;
512 timeout = 300;
513 max_nrof = 1000; // 1000 items of anything
514 max_volume = 2000000; // 2m³
515 }
516
517 maptile::maptile (int w, int h)
518 {
519 in_memory = MAP_SWAPPED;
520
521 width = w;
522 height = h;
523 reset_timeout = 0;
524 timeout = 300;
525 enter_x = 0;
526 enter_y = 0;
527
528 alloc ();
529 }
530
531 /*
532 * Allocates the arrays contained in a maptile.
533 * This basically allocates the dynamic array of spaces for the
534 * map.
535 */
536 void
537 maptile::alloc ()
538 {
539 if (spaces)
540 return;
541
542 spaces = salloc0<mapspace> (size ());
543 }
544
545 /* Takes a string from a map definition and outputs a pointer to the array of shopitems
546 * corresponding to that string. Memory is allocated for this, it must be freed
547 * at a later date.
548 * Called by parse_map_headers below.
549 */
550 static shopitems *
551 parse_shop_string (const char *input_string)
552 {
553 char *shop_string, *p, *q, *next_semicolon, *next_colon;
554 shopitems *items = NULL;
555 int i = 0, number_of_entries = 0;
556 const typedata *current_type;
557
558 shop_string = strdup (input_string);
559 p = shop_string;
560 /* first we'll count the entries, we'll need that for allocating the array shortly */
561 while (p)
562 {
563 p = strchr (p, ';');
564 number_of_entries++;
565 if (p)
566 p++;
567 }
568
569 p = shop_string;
570 strip_endline (p);
571 items = new shopitems[number_of_entries + 1];
572 for (i = 0; i < number_of_entries; i++)
573 {
574 if (!p)
575 {
576 LOG (llevError, "parse_shop_string: I seem to have run out of string, that shouldn't happen.\n");
577 break;
578 }
579
580 next_semicolon = strchr (p, ';');
581 next_colon = strchr (p, ':');
582 /* if there is a stregth specified, figure out what it is, we'll need it soon. */
583 if (next_colon && (!next_semicolon || next_colon < next_semicolon))
584 items[i].strength = atoi (strchr (p, ':') + 1);
585
586 if (isdigit (*p) || *p == '*')
587 {
588 items[i].typenum = atoi (p); /* atoi returns 0 when we have an asterisk */
589 current_type = get_typedata (items[i].typenum);
590 if (current_type)
591 {
592 items[i].name = current_type->name;
593 items[i].name_pl = current_type->name_pl;
594 }
595 }
596 else
597 { /*we have a named type, let's figure out what it is */
598 q = strpbrk (p, ";:");
599 if (q)
600 *q = '\0';
601
602 current_type = get_typedata_by_name (p);
603 if (current_type)
604 {
605 items[i].name = current_type->name;
606 items[i].typenum = current_type->number;
607 items[i].name_pl = current_type->name_pl;
608 }
609 else
610 { /* oh uh, something's wrong, let's free up this one, and try
611 * the next entry while we're at it, better print a warning
612 */
613 LOG (llevError, "invalid type %s defined in shopitems in string %s\n", p, input_string);
614 }
615 }
616
617 items[i].index = number_of_entries;
618 if (next_semicolon)
619 p = ++next_semicolon;
620 else
621 p = NULL;
622 }
623
624 free (shop_string);
625 return items;
626 }
627
628 /* opposite of parse string, this puts the string that was originally fed in to
629 * the map (or something equivilent) into output_string. */
630 static void
631 print_shop_string (maptile *m, char *output_string)
632 {
633 int i;
634 char tmp[MAX_BUF];
635
636 strcpy (output_string, "");
637 for (i = 0; i < m->shopitems[0].index; i++)
638 {
639 if (m->shopitems[i].typenum)
640 {
641 if (m->shopitems[i].strength)
642 sprintf (tmp, "%s:%d;", m->shopitems[i].name, m->shopitems[i].strength);
643 else
644 sprintf (tmp, "%s;", m->shopitems[i].name);
645 }
646 else
647 {
648 if (m->shopitems[i].strength)
649 sprintf (tmp, "*:%d;", m->shopitems[i].strength);
650 else
651 sprintf (tmp, "*");
652 }
653
654 strcat (output_string, tmp);
655 }
656 }
657
658 /* This loads the header information of the map. The header
659 * contains things like difficulty, size, timeout, etc.
660 * this used to be stored in the map object, but with the
661 * addition of tiling, fields beyond that easily named in an
662 * object structure were needed, so it just made sense to
663 * put all the stuff in the map object so that names actually make
664 * sense.
665 * This could be done in lex (like the object loader), but I think
666 * currently, there are few enough fields this is not a big deal.
667 * MSW 2001-07-01
668 */
669 bool
670 maptile::_load_header (object_thawer &thawer)
671 {
672 for (;;)
673 {
674 thawer.next ();
675
676 switch (thawer.kw)
677 {
678 case KW_msg:
679 thawer.get_ml (KW_endmsg, msg);
680 break;
681
682 case KW_lore: // CF+ extension
683 thawer.get_ml (KW_endlore, maplore);
684 break;
685
686 case KW_maplore:
687 thawer.get_ml (KW_endmaplore, maplore);
688 break;
689
690 case KW_arch:
691 if (strcmp (thawer.get_str (), "map"))
692 LOG (llevError, "%s: loading map and got a non 'arch map' line (arch %s), skipping.\n", &path, thawer.get_str ());
693 break;
694
695 case KW_oid:
696 thawer.get (this, thawer.get_sint32 ());
697 break;
698
699 case KW_file_format_version: break; // nop
700
701 case KW_name: thawer.get (name); break;
702 case KW_attach: thawer.get (attach); break;
703 case KW_reset_time: thawer.get (reset_time); break;
704 case KW_shopgreed: thawer.get (shopgreed); break;
705 case KW_shopmin: thawer.get (shopmin); break;
706 case KW_shopmax: thawer.get (shopmax); break;
707 case KW_shoprace: thawer.get (shoprace); break;
708 case KW_outdoor: thawer.get (outdoor); break;
709 case KW_temp: thawer.get (temp); break;
710 case KW_pressure: thawer.get (pressure); break;
711 case KW_humid: thawer.get (humid); break;
712 case KW_windspeed: thawer.get (windspeed); break;
713 case KW_winddir: thawer.get (winddir); break;
714 case KW_sky: thawer.get (sky); break;
715
716 case KW_per_player: thawer.get (per_player); break;
717 case KW_per_party: thawer.get (per_party); break;
718 case KW_no_reset: thawer.get (no_reset); break;
719
720 case KW_region: default_region = region::find (thawer.get_str ()); break;
721 case KW_shopitems: shopitems = parse_shop_string (thawer.get_str ()); break;
722
723 // old names new names
724 case KW_hp: case KW_enter_x: thawer.get (enter_x); break;
725 case KW_sp: case KW_enter_y: thawer.get (enter_y); break;
726 case KW_x: case KW_width: thawer.get (width); break;
727 case KW_y: case KW_height: thawer.get (height); break;
728 case KW_weight: case KW_reset_timeout: thawer.get (reset_timeout); break;
729 case KW_value: case KW_swap_time: thawer.get (timeout); break;
730 case KW_level: case KW_difficulty: thawer.get (difficulty); difficulty = clamp (difficulty, 1, settings.max_level); break;
731 case KW_invisible: case KW_darkness: thawer.get (darkness); break;
732 case KW_stand_still: case KW_fixed_resettime: thawer.get (fixed_resettime); break;
733
734 case KW_tile_path_1: thawer.get (tile_path [0]); break;
735 case KW_tile_path_2: thawer.get (tile_path [1]); break;
736 case KW_tile_path_3: thawer.get (tile_path [2]); break;
737 case KW_tile_path_4: thawer.get (tile_path [3]); break;
738
739 case KW_end:
740 return true;
741
742 default:
743 if (!thawer.parse_error ("map", 0))
744 return false;
745 break;
746 }
747 }
748
749 abort ();
750 }
751
752 bool
753 maptile::_load_header (const char *path)
754 {
755 object_thawer thawer (path);
756
757 if (!thawer)
758 return false;
759
760 return _load_header (thawer);
761 }
762
763 /******************************************************************************
764 * This is the start of unique map handling code
765 *****************************************************************************/
766
767 /* This goes through the maptile and removed any unique items on the map. */
768 void
769 maptile::clear_unique_items ()
770 {
771 for (int i = 0; i < size (); ++i)
772 {
773 int unique = 0;
774 for (object *op = spaces [i].bot; op; )
775 {
776 object *above = op->above;
777
778 if (QUERY_FLAG (op, FLAG_IS_FLOOR) && QUERY_FLAG (op, FLAG_UNIQUE))
779 unique = 1;
780
781 if (op->head_ () == op && (QUERY_FLAG (op, FLAG_UNIQUE) || unique))
782 {
783 op->destroy_inv (false);
784 op->destroy ();
785 }
786
787 op = above;
788 }
789 }
790 }
791
792 bool
793 maptile::_save_header (object_freezer &freezer)
794 {
795 #define MAP_OUT(k) freezer.put (KW_ ## k, k)
796 #define MAP_OUT2(k,v) freezer.put (KW_ ## k, v)
797
798 MAP_OUT2 (arch, "map");
799
800 if (name) MAP_OUT (name);
801 MAP_OUT (swap_time);
802 MAP_OUT (reset_time);
803 MAP_OUT (reset_timeout);
804 MAP_OUT (fixed_resettime);
805 MAP_OUT (no_reset);
806 MAP_OUT (difficulty);
807
808 if (default_region) MAP_OUT2 (region, default_region->name);
809
810 if (shopitems)
811 {
812 char shop[MAX_BUF];
813 print_shop_string (this, shop);
814 MAP_OUT2 (shopitems, shop);
815 }
816
817 MAP_OUT (shopgreed);
818 MAP_OUT (shopmin);
819 MAP_OUT (shopmax);
820 if (shoprace) MAP_OUT (shoprace);
821 MAP_OUT (darkness);
822 MAP_OUT (width);
823 MAP_OUT (height);
824 MAP_OUT (enter_x);
825 MAP_OUT (enter_y);
826
827 if (msg) freezer.put (KW_msg , KW_endmsg , msg);
828 if (maplore) freezer.put (KW_maplore, KW_endmaplore, maplore);
829
830 MAP_OUT (outdoor);
831 MAP_OUT (temp);
832 MAP_OUT (pressure);
833 MAP_OUT (humid);
834 MAP_OUT (windspeed);
835 MAP_OUT (winddir);
836 MAP_OUT (sky);
837
838 MAP_OUT (per_player);
839 MAP_OUT (per_party);
840
841 if (tile_path [0]) MAP_OUT2 (tile_path_1, tile_path [0]);
842 if (tile_path [1]) MAP_OUT2 (tile_path_2, tile_path [1]);
843 if (tile_path [2]) MAP_OUT2 (tile_path_3, tile_path [2]);
844 if (tile_path [3]) MAP_OUT2 (tile_path_4, tile_path [3]);
845
846 freezer.put (this);
847 freezer.put (KW_end);
848
849 return true;
850 }
851
852 bool
853 maptile::_save_header (const char *path)
854 {
855 object_freezer freezer;
856
857 if (!_save_header (freezer))
858 return false;
859
860 return freezer.save (path);
861 }
862
863 /*
864 * Remove and free all objects in the given map.
865 */
866 void
867 maptile::clear ()
868 {
869 sfree (regions, size ()), regions = 0;
870 free (regionmap), regionmap = 0;
871
872 if (spaces)
873 {
874 for (mapspace *ms = spaces + size (); ms-- > spaces; )
875 while (object *op = ms->bot)
876 {
877 op = op->head_ ();
878 op->destroy_inv (false);
879 op->destroy ();
880 }
881
882 sfree (spaces, size ()), spaces = 0;
883 }
884
885 if (buttons)
886 free_objectlinkpt (buttons), buttons = 0;
887 }
888
889 void
890 maptile::clear_header ()
891 {
892 name = 0;
893 msg = 0;
894 maplore = 0;
895 shoprace = 0;
896 delete [] shopitems, shopitems = 0;
897
898 for (int i = 0; i < 4; i++)
899 tile_path [i] = 0;
900 }
901
902 maptile::~maptile ()
903 {
904 assert (destroyed ());
905 }
906
907 void
908 maptile::clear_links_to (maptile *m)
909 {
910 /* We need to look through all the maps and see if any maps
911 * are pointing at this one for tiling information. Since
912 * tiling can be asymetric, we just can not look to see which
913 * maps this map tiles with and clears those.
914 */
915 for (int i = 0; i < 4; i++)
916 if (tile_map[i] == m)
917 tile_map[i] = 0;
918 }
919
920 void
921 maptile::do_destroy ()
922 {
923 attachable::do_destroy ();
924
925 clear ();
926 }
927
928 /* decay and destroy perishable items in a map */
929 void
930 maptile::do_decay_objects ()
931 {
932 if (!spaces)
933 return;
934
935 for (mapspace *ms = spaces + size (); ms-- > spaces; )
936 for (object *above, *op = ms->bot; op; op = above)
937 {
938 above = op->above;
939
940 bool destroy = 0;
941
942 // do not decay anything above unique floor tiles (yet :)
943 if (QUERY_FLAG (op, FLAG_IS_FLOOR) && QUERY_FLAG (op, FLAG_UNIQUE))
944 break;
945
946 if (QUERY_FLAG (op, FLAG_IS_FLOOR)
947 || QUERY_FLAG (op, FLAG_OBJ_ORIGINAL)
948 || QUERY_FLAG (op, FLAG_OBJ_SAVE_ON_OVL)
949 || QUERY_FLAG (op, FLAG_UNIQUE)
950 || QUERY_FLAG (op, FLAG_OVERLAY_FLOOR)
951 || QUERY_FLAG (op, FLAG_UNPAID)
952 || op->is_alive ())
953 ; // do not decay
954 else if (op->is_weapon ())
955 {
956 op->stats.dam--;
957 if (op->stats.dam < 0)
958 destroy = 1;
959 }
960 else if (op->is_armor ())
961 {
962 op->stats.ac--;
963 if (op->stats.ac < 0)
964 destroy = 1;
965 }
966 else if (op->type == FOOD)
967 {
968 op->stats.food -= rndm (5, 20);
969 if (op->stats.food < 0)
970 destroy = 1;
971 }
972 else
973 {
974 int mat = op->materials;
975
976 if (mat & M_PAPER
977 || mat & M_LEATHER
978 || mat & M_WOOD
979 || mat & M_ORGANIC
980 || mat & M_CLOTH
981 || mat & M_LIQUID
982 || (mat & M_IRON && rndm (1, 5) == 1)
983 || (mat & M_GLASS && rndm (1, 2) == 1)
984 || ((mat & M_STONE || mat & M_ADAMANT) && rndm (1, 10) == 1)
985 || ((mat & M_SOFT_METAL || mat & M_BONE) && rndm (1, 3) == 1)
986 || (mat & M_ICE && temp > 32))
987 destroy = 1;
988 }
989
990 /* adjust overall chance below */
991 if (destroy && rndm (0, 1))
992 op->destroy ();
993 }
994 }
995
996 /*
997 * Updates every button on the map (by calling update_button() for them).
998 */
999 void
1000 maptile::update_buttons ()
1001 {
1002 for (oblinkpt *obp = buttons; obp; obp = obp->next)
1003 for (objectlink *ol = obp->link; ol; ol = ol->next)
1004 {
1005 if (!ol->ob)
1006 {
1007 LOG (llevError, "Internal error in update_button (%s (%dx%d), connected %ld).\n",
1008 ol->ob ? (const char *) ol->ob->name : "null", ol->ob ? ol->ob->x : -1, ol->ob ? ol->ob->y : -1, obp->value);
1009 continue;
1010 }
1011
1012 if (ol->ob->type == BUTTON || ol->ob->type == PEDESTAL)
1013 {
1014 update_button (ol->ob);
1015 break;
1016 }
1017 }
1018 }
1019
1020 /*
1021 * This routine is supposed to find out the difficulty of the map.
1022 * difficulty does not have a lot to do with character level,
1023 * but does have a lot to do with treasure on the map.
1024 *
1025 * Difficulty can now be set by the map creature. If the value stored
1026 * in the map is zero, then use this routine. Maps should really
1027 * have a difficulty set than using this function - human calculation
1028 * is much better than this functions guesswork.
1029 */
1030 int
1031 maptile::estimate_difficulty () const
1032 {
1033 long monster_cnt = 0;
1034 double avgexp = 0;
1035 sint64 total_exp = 0;
1036
1037 for (mapspace *ms = spaces + size (); ms-- > spaces; )
1038 for (object *op = ms->bot; op; op = op->above)
1039 {
1040 if (QUERY_FLAG (op, FLAG_MONSTER))
1041 {
1042 total_exp += op->stats.exp;
1043 monster_cnt++;
1044 }
1045
1046 if (QUERY_FLAG (op, FLAG_GENERATOR))
1047 {
1048 total_exp += op->stats.exp;
1049
1050 if (archetype *at = type_to_archetype (GENERATE_TYPE (op)))
1051 total_exp += at->stats.exp * 8;
1052
1053 monster_cnt++;
1054 }
1055 }
1056
1057 avgexp = (double) total_exp / monster_cnt;
1058
1059 for (int i = 1; i <= settings.max_level; i++)
1060 if ((level_exp (i, 1) - level_exp (i - 1, 1)) > (100 * avgexp))
1061 return i;
1062
1063 return 1;
1064 }
1065
1066 /* change_map_light() - used to change map light level (darkness)
1067 * up or down. Returns true if successful. It should now be
1068 * possible to change a value by more than 1.
1069 * Move this from los.c to map.c since this is more related
1070 * to maps than los.
1071 * postive values make it darker, negative make it brighter
1072 */
1073 int
1074 maptile::change_map_light (int change)
1075 {
1076 int new_level = darkness + change;
1077
1078 /* Nothing to do */
1079 if (!change || (new_level <= 0 && darkness == 0) || (new_level >= MAX_DARKNESS && darkness >= MAX_DARKNESS))
1080 return 0;
1081
1082 /* inform all players on the map */
1083 if (change > 0)
1084 new_info_map (NDI_BLACK | NDI_UNIQUE, this, "It becomes darker.");
1085 else
1086 new_info_map (NDI_BLACK | NDI_UNIQUE, this, "It becomes brighter.");
1087
1088 /* Do extra checking. since darkness is a unsigned value,
1089 * we need to be extra careful about negative values.
1090 * In general, the checks below are only needed if change
1091 * is not +/-1
1092 */
1093 if (new_level < 0)
1094 darkness = 0;
1095 else if (new_level >= MAX_DARKNESS)
1096 darkness = MAX_DARKNESS;
1097 else
1098 darkness = new_level;
1099
1100 /* All clients need to get re-updated for the change */
1101 update_all_map_los (this);
1102 return 1;
1103 }
1104
1105 /*
1106 * This function updates various attributes about a specific space
1107 * on the map (what it looks like, whether it blocks magic,
1108 * has a living creatures, prevents people from passing
1109 * through, etc)
1110 */
1111 void
1112 mapspace::update_ ()
1113 {
1114 object *tmp, *last = 0;
1115 uint8 flags = P_UPTODATE, light = 0, anywhere = 0;
1116 MoveType move_block = 0, move_slow = 0, move_on = 0, move_off = 0, move_allow = 0;
1117
1118 //object *middle = 0;
1119 //object *top = 0;
1120 //object *floor = 0;
1121 // this seems to generate better code than using locals, above
1122 object *&top = faces_obj[0] = 0;
1123 object *&middle = faces_obj[1] = 0;
1124 object *&floor = faces_obj[2] = 0;
1125
1126 for (tmp = bot; tmp; last = tmp, tmp = tmp->above)
1127 {
1128 /* This could be made additive I guess (two lights better than
1129 * one). But if so, it shouldn't be a simple additive - 2
1130 * light bulbs do not illuminate twice as far as once since
1131 * it is a dissapation factor that is cubed.
1132 */
1133 if (tmp->glow_radius > light)
1134 light = tmp->glow_radius;
1135
1136 /* This call is needed in order to update objects the player
1137 * is standing in that have animations (ie, grass, fire, etc).
1138 * However, it also causes the look window to be re-drawn
1139 * 3 times each time the player moves, because many of the
1140 * functions the move_player calls eventualy call this.
1141 *
1142 * Always put the player down for drawing.
1143 */
1144 if (!tmp->invisible)
1145 {
1146 if ((tmp->type == PLAYER || QUERY_FLAG (tmp, FLAG_MONSTER)))
1147 top = tmp;
1148 else if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1149 {
1150 /* If we got a floor, that means middle and top were below it,
1151 * so should not be visible, so we clear them.
1152 */
1153 middle = 0;
1154 top = 0;
1155 floor = tmp;
1156 }
1157 /* Flag anywhere have high priority */
1158 else if (QUERY_FLAG (tmp, FLAG_SEE_ANYWHERE))
1159 {
1160 middle = tmp;
1161 anywhere = 1;
1162 }
1163 /* Find the highest visible face around. If equal
1164 * visibilities, we still want the one nearer to the
1165 * top
1166 */
1167 else if (!middle || (::faces [tmp->face].visibility > ::faces [middle->face].visibility && !anywhere))
1168 middle = tmp;
1169 }
1170
1171 if (tmp == tmp->above)
1172 {
1173 LOG (llevError, "Error in structure of map\n");
1174 exit (-1);
1175 }
1176
1177 move_slow |= tmp->move_slow;
1178 move_block |= tmp->move_block;
1179 move_on |= tmp->move_on;
1180 move_off |= tmp->move_off;
1181 move_allow |= tmp->move_allow;
1182
1183 if (QUERY_FLAG (tmp, FLAG_BLOCKSVIEW)) flags |= P_BLOCKSVIEW;
1184 if (QUERY_FLAG (tmp, FLAG_NO_MAGIC)) flags |= P_NO_MAGIC;
1185 if (tmp->type == PLAYER) flags |= P_PLAYER;
1186 if (tmp->type == SAFE_GROUND) flags |= P_SAFE;
1187 if (QUERY_FLAG (tmp, FLAG_ALIVE)) flags |= P_IS_ALIVE;
1188 if (QUERY_FLAG (tmp, FLAG_DAMNED)) flags |= P_NO_CLERIC;
1189 }
1190
1191 this->light = light;
1192 this->flags_ = flags;
1193 this->move_block = move_block & ~move_allow;
1194 this->move_on = move_on;
1195 this->move_off = move_off;
1196 this->move_slow = move_slow;
1197
1198 /* At this point, we have a floor face (if there is a floor),
1199 * and the floor is set - we are not going to touch it at
1200 * this point.
1201 * middle contains the highest visibility face.
1202 * top contains a player/monster face, if there is one.
1203 *
1204 * We now need to fill in top.face and/or middle.face.
1205 */
1206
1207 /* If the top face also happens to be high visibility, re-do our
1208 * middle face. This should not happen, as we already have the
1209 * else statement above so middle should not get set. OTOH, it
1210 * may be possible for the faces to match but be different objects.
1211 */
1212 if (top == middle)
1213 middle = 0;
1214
1215 /* There are three posibilities at this point:
1216 * 1) top face is set, need middle to be set.
1217 * 2) middle is set, need to set top.
1218 * 3) neither middle or top is set - need to set both.
1219 */
1220
1221 for (tmp = last; tmp; tmp = tmp->below)
1222 {
1223 /* Once we get to a floor, stop, since we already have a floor object */
1224 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1225 break;
1226
1227 /* If two top faces are already set, quit processing */
1228 if (top && middle)
1229 break;
1230
1231 /* Only show visible faces */
1232 if (!tmp->invisible)
1233 {
1234 /* Fill in top if needed */
1235 if (!top)
1236 {
1237 top = tmp;
1238 if (top == middle)
1239 middle = 0;
1240 }
1241 else
1242 {
1243 /* top is already set - we should only get here if
1244 * middle is not set
1245 *
1246 * Set the middle face and break out, since there is nothing
1247 * more to fill in. We don't check visiblity here, since
1248 *
1249 */
1250 if (tmp != top)
1251 {
1252 middle = tmp;
1253 break;
1254 }
1255 }
1256 }
1257 }
1258
1259 if (middle == floor)
1260 middle = 0;
1261
1262 if (top == middle)
1263 middle = 0;
1264
1265 #if 0
1266 faces_obj [0] = top;
1267 faces_obj [1] = middle;
1268 faces_obj [2] = floor;
1269 #endif
1270 }
1271
1272 uint64
1273 mapspace::volume () const
1274 {
1275 uint64 vol = 0;
1276
1277 for (object *op = top; op && !op->flag [FLAG_NO_PICK]; op = op->below)
1278 vol += op->volume ();
1279
1280 return vol;
1281 }
1282
1283 /* this updates the orig_map->tile_map[tile_num] value after finding
1284 * the map. It also takes care of linking back the freshly found
1285 * maps tile_map values if it tiles back to this one. It returns
1286 * the value of orig_map->tile_map[tile_num].
1287 */
1288 static inline maptile *
1289 find_and_link (maptile *orig_map, int tile_num)
1290 {
1291 maptile *mp = orig_map->tile_map [tile_num];
1292
1293 if (!mp)
1294 {
1295 mp = orig_map->find_sync (orig_map->tile_path [tile_num], orig_map);
1296
1297 if (!mp)
1298 {
1299 // emergency mode, manufacture a dummy map, this creates a memleak, but thats fine
1300 LOG (llevError, "FATAL: cannot load tiled map %s from %s, leaking memory and worse!\n",
1301 &orig_map->tile_path[tile_num], &orig_map->path);
1302 mp = new maptile (1, 1);
1303 mp->alloc ();
1304 mp->in_memory = MAP_IN_MEMORY;
1305 }
1306 }
1307
1308 int dest_tile = (tile_num + 2) % 4;
1309
1310 orig_map->tile_map [tile_num] = mp;
1311
1312 // optimisation: back-link map to origin map if euclidean
1313 //TODO: non-euclidean maps MUST GO
1314 if (orig_map->tile_map[tile_num]->tile_path[dest_tile] == orig_map->path)
1315 orig_map->tile_map[tile_num]->tile_map[dest_tile] = orig_map;
1316
1317 return mp;
1318 }
1319
1320 static inline void
1321 load_and_link (maptile *orig_map, int tile_num)
1322 {
1323 find_and_link (orig_map, tile_num)->load_sync ();
1324 }
1325
1326 /* this returns TRUE if the coordinates (x,y) are out of
1327 * map m. This function also takes into account any
1328 * tiling considerations, loading adjacant maps as needed.
1329 * This is the function should always be used when it
1330 * necessary to check for valid coordinates.
1331 * This function will recursively call itself for the
1332 * tiled maps.
1333 */
1334 int
1335 out_of_map (maptile *m, int x, int y)
1336 {
1337 /* If we get passed a null map, this is obviously the
1338 * case. This generally shouldn't happen, but if the
1339 * map loads fail below, it could happen.
1340 */
1341 if (!m)
1342 return 0;
1343
1344 if (x < 0)
1345 {
1346 if (!m->tile_path[3])
1347 return 1;
1348
1349 if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY)
1350 find_and_link (m, 3);
1351
1352 return out_of_map (m->tile_map[3], x + m->tile_map[3]->width, y);
1353 }
1354
1355 if (x >= m->width)
1356 {
1357 if (!m->tile_path[1])
1358 return 1;
1359
1360 if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY)
1361 find_and_link (m, 1);
1362
1363 return out_of_map (m->tile_map[1], x - m->width, y);
1364 }
1365
1366 if (y < 0)
1367 {
1368 if (!m->tile_path[0])
1369 return 1;
1370
1371 if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY)
1372 find_and_link (m, 0);
1373
1374 return out_of_map (m->tile_map[0], x, y + m->tile_map[0]->height);
1375 }
1376
1377 if (y >= m->height)
1378 {
1379 if (!m->tile_path[2])
1380 return 1;
1381
1382 if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY)
1383 find_and_link (m, 2);
1384
1385 return out_of_map (m->tile_map[2], x, y - m->height);
1386 }
1387
1388 /* Simple case - coordinates are within this local
1389 * map.
1390 */
1391 return 0;
1392 }
1393
1394 /* This is basically the same as out_of_map above, but
1395 * instead we return NULL if no map is valid (coordinates
1396 * out of bounds and no tiled map), otherwise it returns
1397 * the map as that the coordinates are really on, and
1398 * updates x and y to be the localised coordinates.
1399 * Using this is more efficient of calling out_of_map
1400 * and then figuring out what the real map is
1401 */
1402 maptile *
1403 maptile::xy_find (sint16 &x, sint16 &y)
1404 {
1405 if (x < 0)
1406 {
1407 if (!tile_path[3])
1408 return 0;
1409
1410 find_and_link (this, 3);
1411 x += tile_map[3]->width;
1412 return tile_map[3]->xy_find (x, y);
1413 }
1414
1415 if (x >= width)
1416 {
1417 if (!tile_path[1])
1418 return 0;
1419
1420 find_and_link (this, 1);
1421 x -= width;
1422 return tile_map[1]->xy_find (x, y);
1423 }
1424
1425 if (y < 0)
1426 {
1427 if (!tile_path[0])
1428 return 0;
1429
1430 find_and_link (this, 0);
1431 y += tile_map[0]->height;
1432 return tile_map[0]->xy_find (x, y);
1433 }
1434
1435 if (y >= height)
1436 {
1437 if (!tile_path[2])
1438 return 0;
1439
1440 find_and_link (this, 2);
1441 y -= height;
1442 return tile_map[2]->xy_find (x, y);
1443 }
1444
1445 /* Simple case - coordinates are within this local
1446 * map.
1447 */
1448 return this;
1449 }
1450
1451 /**
1452 * Return whether map2 is adjacent to map1. If so, store the distance from
1453 * map1 to map2 in dx/dy.
1454 */
1455 int
1456 adjacent_map (const maptile *map1, const maptile *map2, int *dx, int *dy)
1457 {
1458 if (!map1 || !map2)
1459 return 0;
1460
1461 //TODO: this doesn't actually check corretcly when intermediate maps are not loaded
1462 //fix: compare paths instead (this is likely faster, too!)
1463 if (map1 == map2)
1464 {
1465 *dx = 0;
1466 *dy = 0;
1467 }
1468 else if (map1->tile_map[0] == map2)
1469 { /* up */
1470 *dx = 0;
1471 *dy = -map2->height;
1472 }
1473 else if (map1->tile_map[1] == map2)
1474 { /* right */
1475 *dx = map1->width;
1476 *dy = 0;
1477 }
1478 else if (map1->tile_map[2] == map2)
1479 { /* down */
1480 *dx = 0;
1481 *dy = map1->height;
1482 }
1483 else if (map1->tile_map[3] == map2)
1484 { /* left */
1485 *dx = -map2->width;
1486 *dy = 0;
1487 }
1488 else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2)
1489 { /* up right */
1490 *dx = map1->tile_map[0]->width;
1491 *dy = -map1->tile_map[0]->height;
1492 }
1493 else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2)
1494 { /* up left */
1495 *dx = -map2->width;
1496 *dy = -map1->tile_map[0]->height;
1497 }
1498 else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2)
1499 { /* right up */
1500 *dx = map1->width;
1501 *dy = -map2->height;
1502 }
1503 else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2)
1504 { /* right down */
1505 *dx = map1->width;
1506 *dy = map1->tile_map[1]->height;
1507 }
1508 else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2)
1509 { /* down right */
1510 *dx = map1->tile_map[2]->width;
1511 *dy = map1->height;
1512 }
1513 else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2)
1514 { /* down left */
1515 *dx = -map2->width;
1516 *dy = map1->height;
1517 }
1518 else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2)
1519 { /* left up */
1520 *dx = -map1->tile_map[3]->width;
1521 *dy = -map2->height;
1522 }
1523 else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2)
1524 { /* left down */
1525 *dx = -map1->tile_map[3]->width;
1526 *dy = map1->tile_map[3]->height;
1527 }
1528 else
1529 return 0;
1530
1531 return 1;
1532 }
1533
1534 maptile *
1535 maptile::xy_load (sint16 &x, sint16 &y)
1536 {
1537 maptile *map = xy_find (x, y);
1538
1539 if (map)
1540 map->load_sync ();
1541
1542 return map;
1543 }
1544
1545 maptile *
1546 get_map_from_coord (maptile *m, sint16 *x, sint16 *y)
1547 {
1548 return m->xy_load (*x, *y);
1549 }
1550
1551 /* From map.c
1552 * This is used by get_player to determine where the other
1553 * creature is. get_rangevector takes into account map tiling,
1554 * so you just can not look the the map coordinates and get the
1555 * righte value. distance_x/y are distance away, which
1556 * can be negative. direction is the crossfire direction scheme
1557 * that the creature should head. part is the part of the
1558 * monster that is closest.
1559 *
1560 * get_rangevector looks at op1 and op2, and fills in the
1561 * structure for op1 to get to op2.
1562 * We already trust that the caller has verified that the
1563 * two objects are at least on adjacent maps. If not,
1564 * results are not likely to be what is desired.
1565 * if the objects are not on maps, results are also likely to
1566 * be unexpected
1567 *
1568 * currently, the only flag supported (0x1) is don't translate for
1569 * closest body part of 'op1'
1570 */
1571 void
1572 get_rangevector (object *op1, object *op2, rv_vector * retval, int flags)
1573 {
1574 if (!adjacent_map (op1->map, op2->map, &retval->distance_x, &retval->distance_y))
1575 {
1576 /* be conservative and fill in _some_ data */
1577 retval->distance = 10000;
1578 retval->distance_x = 10000;
1579 retval->distance_y = 10000;
1580 retval->direction = 0;
1581 retval->part = 0;
1582 }
1583 else
1584 {
1585 object *best;
1586
1587 retval->distance_x += op2->x - op1->x;
1588 retval->distance_y += op2->y - op1->y;
1589
1590 best = op1;
1591 /* If this is multipart, find the closest part now */
1592 if (!(flags & 0x1) && op1->more)
1593 {
1594 int best_distance = retval->distance_x * retval->distance_x + retval->distance_y * retval->distance_y, tmpi;
1595
1596 /* we just take the offset of the piece to head to figure
1597 * distance instead of doing all that work above again
1598 * since the distance fields we set above are positive in the
1599 * same axis as is used for multipart objects, the simply arithmetic
1600 * below works.
1601 */
1602 for (object *tmp = op1->more; tmp; tmp = tmp->more)
1603 {
1604 tmpi = (op1->x - tmp->x + retval->distance_x) * (op1->x - tmp->x + retval->distance_x) +
1605 (op1->y - tmp->y + retval->distance_y) * (op1->y - tmp->y + retval->distance_y);
1606 if (tmpi < best_distance)
1607 {
1608 best_distance = tmpi;
1609 best = tmp;
1610 }
1611 }
1612
1613 if (best != op1)
1614 {
1615 retval->distance_x += op1->x - best->x;
1616 retval->distance_y += op1->y - best->y;
1617 }
1618 }
1619
1620 retval->part = best;
1621 retval->distance = upos_max (abs (retval->distance_x), abs (retval->distance_y));
1622 retval->direction = find_dir_2 (-retval->distance_x, -retval->distance_y);
1623 }
1624 }
1625
1626 /* this is basically the same as get_rangevector above, but instead of
1627 * the first parameter being an object, it instead is the map
1628 * and x,y coordinates - this is used for path to player -
1629 * since the object is not infact moving but we are trying to traverse
1630 * the path, we need this.
1631 * flags has no meaning for this function at this time - I kept it in to
1632 * be more consistant with the above function and also in case they are needed
1633 * for something in the future. Also, since no object is pasted, the best
1634 * field of the rv_vector is set to NULL.
1635 */
1636 void
1637 get_rangevector_from_mapcoord (const maptile *m, int x, int y, const object *op2, rv_vector *retval, int flags)
1638 {
1639 if (!adjacent_map (m, op2->map, &retval->distance_x, &retval->distance_y))
1640 {
1641 /* be conservative and fill in _some_ data */
1642 retval->distance = 100000;
1643 retval->distance_x = 32767;
1644 retval->distance_y = 32767;
1645 retval->direction = 0;
1646 retval->part = 0;
1647 }
1648 else
1649 {
1650 retval->distance_x += op2->x - x;
1651 retval->distance_y += op2->y - y;
1652
1653 retval->part = NULL;
1654 retval->distance = idistance (retval->distance_x, retval->distance_y);
1655 retval->direction = find_dir_2 (-retval->distance_x, -retval->distance_y);
1656 }
1657 }
1658
1659 /* Returns true of op1 and op2 are effectively on the same map
1660 * (as related to map tiling). Note that this looks for a path from
1661 * op1 to op2, so if the tiled maps are asymetric and op2 has a path
1662 * to op1, this will still return false.
1663 * Note we only look one map out to keep the processing simple
1664 * and efficient. This could probably be a macro.
1665 * MSW 2001-08-05
1666 */
1667 int
1668 on_same_map (const object *op1, const object *op2)
1669 {
1670 int dx, dy;
1671
1672 return adjacent_map (op1->map, op2->map, &dx, &dy);
1673 }
1674
1675 object *
1676 maptile::insert (object *op, int x, int y, object *originator, int flags)
1677 {
1678 if (!op->flag [FLAG_REMOVED])
1679 op->remove ();
1680
1681 return insert_ob_in_map_at (op, this, originator, flags, x, y);
1682 }
1683
1684 region *
1685 maptile::region (int x, int y) const
1686 {
1687 if (regions
1688 && regionmap
1689 && !OUT_OF_REAL_MAP (this, x, y))
1690 if (struct region *reg = regionmap [regions [y * width + x]])
1691 return reg;
1692
1693 if (default_region)
1694 return default_region;
1695
1696 return ::region::default_region ();
1697 }
1698
1699 /* picks a random object from a style map.
1700 * Redone by MSW so it should be faster and not use static
1701 * variables to generate tables.
1702 */
1703 object *
1704 maptile::pick_random_object () const
1705 {
1706 /* while returning a null object will result in a crash, that
1707 * is actually preferable to an infinite loop. That is because
1708 * most servers will automatically restart in case of crash.
1709 * Change the logic on getting the random space - shouldn't make
1710 * any difference, but this seems clearer to me.
1711 */
1712 for (int i = 1000; --i;)
1713 {
1714 object *pick = at (rndm (width), rndm (height)).bot;
1715
1716 // do not prefer big monsters just because they are big.
1717 if (pick && pick->head_ () == pick)
1718 return pick->head_ ();
1719 }
1720
1721 // instead of crashing in the unlikely(?) case, try to return *something*
1722 return get_archetype ("blocked");
1723 }
1724