ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/map.C
Revision: 1.127
Committed: Fri Sep 7 18:03:31 2007 UTC (16 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.126: +14 -6 lines
Log Message:
try to fix the (surprisingly only coming up now) problem of crashing
due to endless loops in clear, by not calling remove (thus not triggering
any remove actions) but by manually removing objects. also keep region info
intatc a bit longer (should not make a difference).

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