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

# User Rev Content
1 elmex 1.1 /*
2 root 1.110 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 pippijn 1.76 *
4 root 1.106 * 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 pippijn 1.76 *
8 root 1.110 * 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 pippijn 1.76 *
13 root 1.110 * 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 pippijn 1.76 *
18 root 1.110 * 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 root 1.106 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 pippijn 1.76 */
23 elmex 1.1
24 root 1.85 #include <unistd.h>
25    
26     #include "global.h"
27     #include "funcpoint.h"
28 elmex 1.1
29 root 1.85 #include "loader.h"
30 elmex 1.1
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 root 1.29 int
44 root 1.46 get_map_flags (maptile *oldmap, maptile **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny)
45 elmex 1.1 {
46 root 1.56 sint16 newx = x;
47     sint16 newy = y;
48 root 1.46
49 root 1.56 maptile *mp = get_map_from_coord (oldmap, &newx, &newy);
50 root 1.46
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 elmex 1.3
58 root 1.56 return mp->at (newx, newy).flags () | (mp != oldmap ? P_NEW_MAP : 0);
59 elmex 1.1 }
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 root 1.29 int
74 root 1.31 blocked_link (object *ob, maptile *m, int sx, int sy)
75 root 1.29 {
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 elmex 1.1 }
87    
88 root 1.29 /* Save some cycles - instead of calling get_map_flags(), just get the value
89     * directly.
90     */
91 root 1.46 mflags = m->at (sx, sy).flags ();
92 root 1.29
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 root 1.102 ob = ob->head_ ();
113 root 1.29
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 root 1.45 for (tmp = GET_MAP_OB (m, sx, sy); tmp; tmp = tmp->above)
120 root 1.29 {
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 root 1.102 * second - if a monster, can't move there, unless it is a
153 root 1.29 * hidden dm
154     */
155     if (OB_MOVE_BLOCK (ob, tmp))
156     return 1;
157 root 1.102
158 root 1.103 if (tmp->flag [FLAG_ALIVE]
159 root 1.102 && tmp->head_ () != ob
160     && tmp != ob
161     && tmp->type != DOOR
162 root 1.103 && !(tmp->flag [FLAG_WIZ] && tmp->contr->hidden))
163 root 1.29 return 1;
164 root 1.10 }
165 elmex 1.1
166     }
167 root 1.29 return 0;
168 elmex 1.1 }
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 root 1.29 int
197 root 1.31 ob_blocked (const object *ob, maptile *m, sint16 x, sint16 y)
198 root 1.29 {
199     archetype *tmp;
200     int flag;
201 root 1.31 maptile *m1;
202 root 1.29 sint16 sx, sy;
203 elmex 1.1
204 root 1.59 if (!ob)
205 root 1.29 {
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 elmex 1.1
210 root 1.29 /* don't have object, so don't know what types would block */
211 root 1.47 return m1->at (sx, sy).move_block;
212 elmex 1.1 }
213    
214 root 1.108 for (tmp = ob->arch; tmp; tmp = (archetype *)tmp->more)
215 root 1.29 {
216 root 1.107 flag = get_map_flags (m, &m1, x + tmp->x, y + tmp->y, &sx, &sy);
217 elmex 1.1
218 root 1.29 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 root 1.47 mapspace &ms = m1->at (sx, sy);
224    
225 root 1.29 /* 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 elmex 1.1
230 root 1.47 if (ob->move_type == 0 && ms.move_block != MOVE_ALL)
231 root 1.29 continue;
232 elmex 1.1
233 root 1.29 /* 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 root 1.47 if (OB_TYPE_MOVE_BLOCK (ob, ms.move_block))
237 root 1.45 return P_NO_PASS;
238     }
239 elmex 1.1
240 root 1.29 return 0;
241 elmex 1.1 }
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 root 1.29 void
250     fix_container (object *container)
251 elmex 1.1 {
252 root 1.29 object *tmp = container->inv, *next;
253 elmex 1.1
254 root 1.56 container->inv = 0;
255     while (tmp)
256 root 1.29 {
257     next = tmp->below;
258     if (tmp->inv)
259     fix_container (tmp);
260 root 1.56
261     insert_ob_in_ob (tmp, container);
262 root 1.29 tmp = next;
263     }
264 root 1.56
265 root 1.29 /* sum_weight will go through and calculate what all the containers are
266     * carrying.
267     */
268     sum_weight (container);
269 elmex 1.1 }
270    
271 root 1.64 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 elmex 1.1 /* 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 root 1.99 * they are saved).
286 elmex 1.1 */
287 root 1.56 void
288     maptile::link_multipart_objects ()
289 elmex 1.1 {
290 root 1.56 if (!spaces)
291     return;
292    
293     for (mapspace *ms = spaces + size (); ms-- > spaces; )
294 elmex 1.111 {
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 elmex 1.1 }
317 root 1.29
318 elmex 1.1 /*
319     * Loads (ands parses) the objects into a given map from the specified
320     * file pointer.
321     */
322 root 1.56 bool
323 root 1.88 maptile::_load_objects (object_thawer &f)
324 root 1.24 {
325 root 1.88 for (;;)
326     {
327 root 1.100 coroapi::cede_to_tick_every (100); // cede once in a while
328 elmex 1.1
329 root 1.88 switch (f.kw)
330 root 1.24 {
331 root 1.88 case KW_arch:
332 root 1.90 if (object *op = object::read (f, this))
333 root 1.88 {
334     if (op->inv)
335     sum_weight (op);
336 root 1.10
337 root 1.88 insert_ob_in_map (op, this, op, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP | INS_MAP_LOAD);
338     }
339 root 1.41
340 root 1.88 continue;
341 root 1.41
342 root 1.88 case KW_EOF:
343     return true;
344 root 1.41
345 root 1.88 default:
346     if (!f.parse_error ("map file"))
347     return false;
348 root 1.41 break;
349 root 1.10 }
350 root 1.24
351 root 1.88 f.next ();
352 elmex 1.1 }
353 root 1.24
354 root 1.56 return true;
355     }
356    
357     void
358     maptile::activate ()
359     {
360 root 1.101 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 root 1.56 }
365    
366     void
367     maptile::deactivate ()
368     {
369 root 1.101 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 root 1.56 }
374    
375     bool
376 root 1.88 maptile::_save_objects (object_freezer &f, int flags)
377 root 1.56 {
378 root 1.100 coroapi::cede_to_tick ();
379 root 1.65
380 root 1.56 if (flags & IO_HEADER)
381 root 1.88 _save_header (f);
382 root 1.56
383     if (!spaces)
384     return false;
385    
386     for (int i = 0; i < size (); ++i)
387 root 1.24 {
388 root 1.121 bool unique = 0;
389    
390 root 1.56 for (object *op = spaces [i].bot; op; op = op->above)
391 root 1.24 {
392 root 1.121 unique |= op->flag [FLAG_UNIQUE] && op->flag [FLAG_IS_FLOOR];
393 root 1.56
394 root 1.121 if (expect_false (!op->can_map_save ()))
395 root 1.56 continue;
396    
397 root 1.121 if (expect_false (unique || op->flag [FLAG_UNIQUE]))
398 root 1.24 {
399 root 1.56 if (flags & IO_UNIQUES)
400 root 1.88 op->write (f);
401 root 1.10 }
402 root 1.121 else if (expect_true (flags & IO_OBJECTS))
403 root 1.88 op->write (f);
404 root 1.10 }
405 elmex 1.1 }
406 root 1.24
407 root 1.100 coroapi::cede_to_tick ();
408 root 1.97
409 root 1.56 return true;
410 elmex 1.1 }
411    
412 root 1.56 bool
413 root 1.72 maptile::_save_objects (const char *path, int flags)
414 root 1.56 {
415     object_freezer freezer;
416 root 1.29
417 root 1.72 if (!_save_objects (freezer, flags))
418 root 1.56 return false;
419 root 1.29
420 root 1.56 return freezer.save (path);
421 elmex 1.1 }
422    
423 root 1.34 maptile::maptile ()
424     {
425     in_memory = MAP_SWAPPED;
426 root 1.54
427 root 1.34 /* The maps used to pick up default x and y values from the
428 root 1.85 * map archetype. Mimic that behaviour.
429 root 1.34 */
430 root 1.85 width = 16;
431     height = 16;
432     timeout = 300;
433     max_nrof = 1000; // 1000 items of anything
434     max_volume = 2000000; // 2m³
435 root 1.34 }
436    
437 root 1.56 maptile::maptile (int w, int h)
438 root 1.54 {
439 root 1.56 in_memory = MAP_SWAPPED;
440 root 1.54
441 root 1.56 width = w;
442     height = h;
443     reset_timeout = 0;
444     timeout = 300;
445     enter_x = 0;
446     enter_y = 0;
447 root 1.54
448 root 1.56 alloc ();
449 elmex 1.1 }
450    
451     /*
452 root 1.31 * Allocates the arrays contained in a maptile.
453 elmex 1.1 * This basically allocates the dynamic array of spaces for the
454     * map.
455     */
456 root 1.29 void
457 root 1.56 maptile::alloc ()
458 root 1.29 {
459 root 1.34 if (spaces)
460 root 1.56 return;
461 elmex 1.1
462 root 1.53 spaces = salloc0<mapspace> (size ());
463 elmex 1.1 }
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 root 1.29 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 root 1.43 shop_string = strdup (input_string);
479 root 1.29 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 root 1.54
489 root 1.29 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 root 1.54
500 root 1.29 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 root 1.54
537 root 1.29 items[i].index = number_of_entries;
538     if (next_semicolon)
539     p = ++next_semicolon;
540     else
541     p = NULL;
542 elmex 1.1 }
543 root 1.54
544 root 1.29 free (shop_string);
545     return items;
546 elmex 1.1 }
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 root 1.29 static void
551 root 1.31 print_shop_string (maptile *m, char *output_string)
552 root 1.29 {
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 root 1.54 sprintf (tmp, "%s:%d;", m->shopitems[i].name, m->shopitems[i].strength);
563 root 1.29 else
564     sprintf (tmp, "%s;", m->shopitems[i].name);
565 root 1.10 }
566 root 1.29 else
567     {
568     if (m->shopitems[i].strength)
569 root 1.54 sprintf (tmp, "*:%d;", m->shopitems[i].strength);
570 root 1.29 else
571     sprintf (tmp, "*");
572     }
573 root 1.54
574 root 1.29 strcat (output_string, tmp);
575 elmex 1.1 }
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 root 1.56 bool
590 root 1.72 maptile::_load_header (object_thawer &thawer)
591 elmex 1.1 {
592 root 1.56 for (;;)
593 root 1.29 {
594 root 1.105 switch (thawer.kw)
595 root 1.29 {
596 root 1.56 case KW_msg:
597     thawer.get_ml (KW_endmsg, msg);
598     break;
599 root 1.22
600 root 1.56 case KW_lore: // CF+ extension
601     thawer.get_ml (KW_endlore, maplore);
602     break;
603 root 1.10
604 root 1.56 case KW_maplore:
605     thawer.get_ml (KW_endmaplore, maplore);
606     break;
607 root 1.10
608 root 1.56 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 root 1.29
613 root 1.56 case KW_oid:
614     thawer.get (this, thawer.get_sint32 ());
615     break;
616 root 1.29
617 root 1.56 case KW_file_format_version: break; // nop
618 root 1.29
619 root 1.56 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 root 1.109 case KW_no_reset: thawer.get (no_reset); break;
637 root 1.56
638 root 1.81 case KW_region: default_region = region::find (thawer.get_str ()); break;
639 root 1.56 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 root 1.83
657 root 1.112 case KW_ERROR:
658 root 1.123 set_key_text (thawer.kw_str, thawer.value);
659 root 1.112 break;
660    
661 root 1.83 case KW_end:
662 root 1.124 thawer.next ();
663 root 1.83 return true;
664    
665     default:
666 root 1.87 if (!thawer.parse_error ("map", 0))
667 root 1.83 return false;
668     break;
669 root 1.10 }
670 root 1.124
671     thawer.next ();
672 elmex 1.1 }
673 root 1.41
674 root 1.56 abort ();
675 elmex 1.1 }
676    
677 root 1.56 /******************************************************************************
678     * This is the start of unique map handling code
679     *****************************************************************************/
680 root 1.29
681 root 1.56 /* This goes through the maptile and removed any unique items on the map. */
682     void
683     maptile::clear_unique_items ()
684 root 1.29 {
685 root 1.56 for (int i = 0; i < size (); ++i)
686 root 1.29 {
687 root 1.56 int unique = 0;
688     for (object *op = spaces [i].bot; op; )
689     {
690     object *above = op->above;
691 elmex 1.1
692 root 1.56 if (QUERY_FLAG (op, FLAG_IS_FLOOR) && QUERY_FLAG (op, FLAG_UNIQUE))
693     unique = 1;
694 root 1.14
695 root 1.102 if (op->head_ () == op && (QUERY_FLAG (op, FLAG_UNIQUE) || unique))
696 root 1.56 {
697     op->destroy_inv (false);
698     op->destroy ();
699     }
700 elmex 1.1
701 root 1.56 op = above;
702     }
703 root 1.29 }
704 elmex 1.1 }
705    
706 root 1.56 bool
707 root 1.72 maptile::_save_header (object_freezer &freezer)
708 root 1.29 {
709 root 1.56 #define MAP_OUT(k) freezer.put (KW_ ## k, k)
710     #define MAP_OUT2(k,v) freezer.put (KW_ ## k, v)
711 elmex 1.1
712 root 1.56 MAP_OUT2 (arch, "map");
713 elmex 1.1
714 root 1.56 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 root 1.109 MAP_OUT (no_reset);
720 root 1.56 MAP_OUT (difficulty);
721 root 1.9
722 root 1.80 if (default_region) MAP_OUT2 (region, default_region->name);
723 root 1.29
724 root 1.56 if (shopitems)
725 root 1.29 {
726 root 1.56 char shop[MAX_BUF];
727     print_shop_string (this, shop);
728     MAP_OUT2 (shopitems, shop);
729 elmex 1.1 }
730    
731 root 1.56 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 root 1.14
741 root 1.56 if (msg) freezer.put (KW_msg , KW_endmsg , msg);
742     if (maplore) freezer.put (KW_maplore, KW_endmaplore, maplore);
743 elmex 1.1
744 root 1.56 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 elmex 1.1
752 root 1.56 MAP_OUT (per_player);
753     MAP_OUT (per_party);
754 elmex 1.1
755 root 1.56 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 root 1.40
760 root 1.63 freezer.put (this);
761 root 1.61 freezer.put (KW_end);
762 root 1.40
763 root 1.56 return true;
764 elmex 1.1 }
765    
766 root 1.56 bool
767 root 1.72 maptile::_save_header (const char *path)
768 root 1.29 {
769 root 1.17 object_freezer freezer;
770 root 1.10
771 root 1.72 if (!_save_header (freezer))
772 root 1.56 return false;
773 elmex 1.1
774 root 1.56 return freezer.save (path);
775 elmex 1.1 }
776    
777     /*
778     * Remove and free all objects in the given map.
779     */
780 root 1.29 void
781 root 1.56 maptile::clear ()
782 root 1.29 {
783 root 1.81 if (spaces)
784     {
785     for (mapspace *ms = spaces + size (); ms-- > spaces; )
786 root 1.104 while (object *op = ms->bot)
787 root 1.81 {
788 root 1.127 // 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 root 1.81 }
800 root 1.29
801 root 1.81 sfree (spaces, size ()), spaces = 0;
802     }
803 root 1.29
804 root 1.56 if (buttons)
805     free_objectlinkpt (buttons), buttons = 0;
806 root 1.127
807     sfree (regions, size ()); regions = 0;
808     delete [] regionmap; regionmap = 0;
809 elmex 1.1 }
810    
811 root 1.29 void
812 root 1.56 maptile::clear_header ()
813 root 1.29 {
814 root 1.56 name = 0;
815     msg = 0;
816     maplore = 0;
817     shoprace = 0;
818     delete [] shopitems, shopitems = 0;
819 root 1.42
820 root 1.47 for (int i = 0; i < 4; i++)
821 root 1.56 tile_path [i] = 0;
822 root 1.47 }
823 root 1.42
824 root 1.47 maptile::~maptile ()
825     {
826 root 1.53 assert (destroyed ());
827 elmex 1.1 }
828    
829 root 1.29 void
830 root 1.56 maptile::clear_links_to (maptile *m)
831 root 1.29 {
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 root 1.47 * tiling can be asymetric, we just can not look to see which
835 root 1.29 * maps this map tiles with and clears those.
836     */
837 root 1.56 for (int i = 0; i < 4; i++)
838     if (tile_map[i] == m)
839     tile_map[i] = 0;
840 root 1.47 }
841 elmex 1.1
842 root 1.47 void
843 root 1.56 maptile::do_destroy ()
844 root 1.47 {
845 root 1.56 attachable::do_destroy ();
846    
847     clear ();
848 elmex 1.1 }
849    
850 root 1.109 /* 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 elmex 1.1 /*
918 root 1.56 * Updates every button on the map (by calling update_button() for them).
919 elmex 1.1 */
920 root 1.56 void
921     maptile::update_buttons ()
922 root 1.29 {
923 root 1.56 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 elmex 1.1
933 root 1.56 if (ol->ob->type == BUTTON || ol->ob->type == PEDESTAL)
934     {
935     update_button (ol->ob);
936     break;
937     }
938     }
939 elmex 1.1 }
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 root 1.29 int
952 root 1.56 maptile::estimate_difficulty () const
953 root 1.29 {
954 elmex 1.1 long monster_cnt = 0;
955     double avgexp = 0;
956     sint64 total_exp = 0;
957    
958 root 1.56 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 elmex 1.1
967 root 1.56 if (QUERY_FLAG (op, FLAG_GENERATOR))
968     {
969     total_exp += op->stats.exp;
970 elmex 1.1
971 root 1.56 if (archetype *at = type_to_archetype (GENERATE_TYPE (op)))
972 root 1.107 total_exp += at->stats.exp * 8;
973 elmex 1.1
974 root 1.56 monster_cnt++;
975     }
976     }
977 elmex 1.1
978     avgexp = (double) total_exp / monster_cnt;
979    
980 root 1.56 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 elmex 1.1
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 root 1.29 int
995 root 1.56 maptile::change_map_light (int change)
996 root 1.29 {
997 root 1.56 int new_level = darkness + change;
998 root 1.29
999     /* Nothing to do */
1000 root 1.56 if (!change || (new_level <= 0 && darkness == 0) || (new_level >= MAX_DARKNESS && darkness >= MAX_DARKNESS))
1001     return 0;
1002 elmex 1.1
1003 root 1.29 /* inform all players on the map */
1004     if (change > 0)
1005 root 1.56 new_info_map (NDI_BLACK | NDI_UNIQUE, this, "It becomes darker.");
1006 root 1.29 else
1007 root 1.56 new_info_map (NDI_BLACK | NDI_UNIQUE, this, "It becomes brighter.");
1008 root 1.29
1009 root 1.56 /* Do extra checking. since darkness is a unsigned value,
1010 root 1.29 * 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 root 1.56 darkness = 0;
1016 root 1.29 else if (new_level >= MAX_DARKNESS)
1017 root 1.56 darkness = MAX_DARKNESS;
1018 root 1.29 else
1019 root 1.56 darkness = new_level;
1020 elmex 1.1
1021 root 1.29 /* All clients need to get re-updated for the change */
1022 root 1.56 update_all_map_los (this);
1023 root 1.29 return 1;
1024 elmex 1.1 }
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 root 1.29 void
1033 root 1.46 mapspace::update_ ()
1034 root 1.29 {
1035 root 1.45 object *tmp, *last = 0;
1036 root 1.74 uint8 flags = P_UPTODATE, light = 0, anywhere = 0;
1037 root 1.29 MoveType move_block = 0, move_slow = 0, move_on = 0, move_off = 0, move_allow = 0;
1038    
1039 root 1.94 //object *middle = 0;
1040     //object *top = 0;
1041     //object *floor = 0;
1042     // this seems to generate better code than using locals, above
1043 root 1.95 object *&top = faces_obj[0] = 0;
1044     object *&middle = faces_obj[1] = 0;
1045     object *&floor = faces_obj[2] = 0;
1046 root 1.29
1047 root 1.49 for (tmp = bot; tmp; last = tmp, tmp = tmp->above)
1048 root 1.29 {
1049     /* This could be made additive I guess (two lights better than
1050 root 1.45 * one). But if so, it shouldn't be a simple additive - 2
1051 root 1.29 * light bulbs do not illuminate twice as far as once since
1052 root 1.45 * it is a dissapation factor that is cubed.
1053 root 1.29 */
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 root 1.94 top = tmp;
1069 root 1.29 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 root 1.94 middle = 0;
1075     top = 0;
1076     floor = tmp;
1077 root 1.29 }
1078     /* Flag anywhere have high priority */
1079     else if (QUERY_FLAG (tmp, FLAG_SEE_ANYWHERE))
1080     {
1081 root 1.94 middle = tmp;
1082 root 1.29 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 root 1.94 else if (!middle || (::faces [tmp->face].visibility > ::faces [middle->face].visibility && !anywhere))
1089     middle = tmp;
1090 root 1.29 }
1091 root 1.45
1092 root 1.29 if (tmp == tmp->above)
1093     {
1094     LOG (llevError, "Error in structure of map\n");
1095     exit (-1);
1096     }
1097    
1098 root 1.45 move_slow |= tmp->move_slow;
1099 root 1.29 move_block |= tmp->move_block;
1100 root 1.45 move_on |= tmp->move_on;
1101     move_off |= tmp->move_off;
1102 root 1.29 move_allow |= tmp->move_allow;
1103    
1104 root 1.45 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 root 1.29
1112 root 1.46 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 root 1.29
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 root 1.94 middle = 0;
1135 root 1.29
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 root 1.94 if (top && middle)
1150 root 1.29 break;
1151 root 1.10
1152 elmex 1.67 /* Only show visible faces */
1153     if (!tmp->invisible)
1154 root 1.29 {
1155     /* Fill in top if needed */
1156 root 1.94 if (!top)
1157 root 1.29 {
1158 root 1.94 top = tmp;
1159 root 1.29 if (top == middle)
1160 root 1.94 middle = 0;
1161 root 1.29 }
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 root 1.94 if (tmp != top)
1172 root 1.29 {
1173 root 1.94 middle = tmp;
1174 root 1.29 break;
1175 root 1.10 }
1176     }
1177     }
1178 elmex 1.1 }
1179 root 1.45
1180 root 1.29 if (middle == floor)
1181 root 1.94 middle = 0;
1182 root 1.45
1183 root 1.29 if (top == middle)
1184 root 1.94 middle = 0;
1185 root 1.45
1186 root 1.94 #if 0
1187     faces_obj [0] = top;
1188     faces_obj [1] = middle;
1189     faces_obj [2] = floor;
1190     #endif
1191 elmex 1.1 }
1192    
1193 root 1.85 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 root 1.117 bool
1205     maptile::tile_available (int dir, bool load)
1206 elmex 1.1 {
1207 root 1.118 if (!tile_path[dir])
1208     return 0;
1209    
1210 root 1.117 if (tile_map[dir] && (!load || tile_map[dir]->in_memory == MAP_IN_MEMORY))
1211     return 1;
1212 root 1.60
1213 root 1.117 if ((tile_map[dir] = find_async (tile_path[dir], this, load)))
1214     return 1;
1215 root 1.56
1216 root 1.117 return 0;
1217 root 1.68 }
1218    
1219 elmex 1.1 /* 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 root 1.29 int
1228 root 1.31 out_of_map (maptile *m, int x, int y)
1229 elmex 1.1 {
1230 root 1.29 /* 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 elmex 1.1
1237 root 1.29 if (x < 0)
1238     {
1239 root 1.119 if (!m->tile_available (3))
1240 root 1.29 return 1;
1241 root 1.46
1242 root 1.56 return out_of_map (m->tile_map[3], x + m->tile_map[3]->width, y);
1243 elmex 1.1 }
1244 root 1.46
1245 root 1.48 if (x >= m->width)
1246 root 1.29 {
1247 root 1.119 if (!m->tile_available (1))
1248 root 1.29 return 1;
1249 root 1.46
1250 root 1.56 return out_of_map (m->tile_map[1], x - m->width, y);
1251 elmex 1.1 }
1252 root 1.46
1253 root 1.29 if (y < 0)
1254     {
1255 root 1.119 if (!m->tile_available (0))
1256 root 1.29 return 1;
1257 root 1.46
1258 root 1.56 return out_of_map (m->tile_map[0], x, y + m->tile_map[0]->height);
1259 elmex 1.1 }
1260 root 1.46
1261 root 1.48 if (y >= m->height)
1262 root 1.29 {
1263 root 1.119 if (!m->tile_available (2))
1264 root 1.29 return 1;
1265 root 1.46
1266 root 1.56 return out_of_map (m->tile_map[2], x, y - m->height);
1267 elmex 1.1 }
1268    
1269 root 1.29 /* Simple case - coordinates are within this local
1270     * map.
1271     */
1272     return 0;
1273 elmex 1.1 }
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 pippijn 1.66 * updates x and y to be the localised coordinates.
1280 elmex 1.1 * Using this is more efficient of calling out_of_map
1281     * and then figuring out what the real map is
1282     */
1283 root 1.31 maptile *
1284 root 1.68 maptile::xy_find (sint16 &x, sint16 &y)
1285 elmex 1.1 {
1286 root 1.68 if (x < 0)
1287 root 1.29 {
1288 root 1.119 if (!tile_available (3))
1289 root 1.46 return 0;
1290 root 1.56
1291 root 1.68 x += tile_map[3]->width;
1292     return tile_map[3]->xy_find (x, y);
1293 elmex 1.1 }
1294 root 1.46
1295 root 1.68 if (x >= width)
1296 root 1.29 {
1297 root 1.119 if (!tile_available (1))
1298 root 1.46 return 0;
1299    
1300 root 1.68 x -= width;
1301     return tile_map[1]->xy_find (x, y);
1302 elmex 1.1 }
1303 root 1.46
1304 root 1.68 if (y < 0)
1305 root 1.29 {
1306 root 1.119 if (!tile_available (0))
1307 root 1.46 return 0;
1308    
1309 root 1.68 y += tile_map[0]->height;
1310     return tile_map[0]->xy_find (x, y);
1311 elmex 1.1 }
1312 root 1.46
1313 root 1.68 if (y >= height)
1314 root 1.29 {
1315 root 1.119 if (!tile_available (2))
1316 root 1.46 return 0;
1317    
1318 root 1.68 y -= height;
1319     return tile_map[2]->xy_find (x, y);
1320 elmex 1.1 }
1321    
1322 root 1.29 /* Simple case - coordinates are within this local
1323     * map.
1324     */
1325 root 1.68 return this;
1326 elmex 1.1 }
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 root 1.82 int
1333 root 1.31 adjacent_map (const maptile *map1, const maptile *map2, int *dx, int *dy)
1334 root 1.29 {
1335     if (!map1 || !map2)
1336     return 0;
1337    
1338 root 1.120 //TODO: this doesn't actually check correctly when intermediate maps are not loaded
1339 root 1.68 //fix: compare paths instead (this is likely faster, too!)
1340 root 1.29 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 root 1.48 *dy = -map2->height;
1349 root 1.29 }
1350     else if (map1->tile_map[1] == map2)
1351     { /* right */
1352 root 1.48 *dx = map1->width;
1353 root 1.29 *dy = 0;
1354     }
1355     else if (map1->tile_map[2] == map2)
1356     { /* down */
1357     *dx = 0;
1358 root 1.48 *dy = map1->height;
1359 root 1.29 }
1360     else if (map1->tile_map[3] == map2)
1361     { /* left */
1362 root 1.48 *dx = -map2->width;
1363 root 1.29 *dy = 0;
1364     }
1365     else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2)
1366     { /* up right */
1367 root 1.48 *dx = map1->tile_map[0]->width;
1368     *dy = -map1->tile_map[0]->height;
1369 root 1.29 }
1370     else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2)
1371     { /* up left */
1372 root 1.48 *dx = -map2->width;
1373     *dy = -map1->tile_map[0]->height;
1374 root 1.29 }
1375     else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2)
1376     { /* right up */
1377 root 1.48 *dx = map1->width;
1378     *dy = -map2->height;
1379 root 1.29 }
1380     else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2)
1381     { /* right down */
1382 root 1.48 *dx = map1->width;
1383     *dy = map1->tile_map[1]->height;
1384 root 1.29 }
1385     else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2)
1386     { /* down right */
1387 root 1.48 *dx = map1->tile_map[2]->width;
1388     *dy = map1->height;
1389 root 1.29 }
1390     else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2)
1391     { /* down left */
1392 root 1.48 *dx = -map2->width;
1393     *dy = map1->height;
1394 root 1.29 }
1395     else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2)
1396     { /* left up */
1397 root 1.48 *dx = -map1->tile_map[3]->width;
1398     *dy = -map2->height;
1399 root 1.29 }
1400     else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2)
1401     { /* left down */
1402 root 1.48 *dx = -map1->tile_map[3]->width;
1403     *dy = map1->tile_map[3]->height;
1404 root 1.29 }
1405     else
1406 root 1.56 return 0;
1407 elmex 1.1
1408 root 1.29 return 1;
1409 elmex 1.1 }
1410    
1411 root 1.68 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 elmex 1.1 /* 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 root 1.79 * can be negative. direction is the crossfire direction scheme
1434 elmex 1.1 * 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 root 1.29 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 root 1.86 retval->distance = 10000;
1455     retval->distance_x = 10000;
1456     retval->distance_y = 10000;
1457 root 1.29 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 root 1.86 for (object *tmp = op1->more; tmp; tmp = tmp->more)
1480 root 1.29 {
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 elmex 1.1 }
1488     }
1489 root 1.75
1490 root 1.29 if (best != op1)
1491     {
1492     retval->distance_x += op1->x - best->x;
1493     retval->distance_y += op1->y - best->y;
1494 elmex 1.1 }
1495     }
1496 root 1.75
1497 root 1.29 retval->part = best;
1498 root 1.86 retval->distance = upos_max (abs (retval->distance_x), abs (retval->distance_y));
1499 root 1.29 retval->direction = find_dir_2 (-retval->distance_x, -retval->distance_y);
1500 elmex 1.1 }
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 root 1.29 void
1514 root 1.82 get_rangevector_from_mapcoord (const maptile *m, int x, int y, const object *op2, rv_vector *retval, int flags)
1515 root 1.29 {
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 root 1.75 retval->distance = idistance (retval->distance_x, retval->distance_y);
1532 root 1.29 retval->direction = find_dir_2 (-retval->distance_x, -retval->distance_y);
1533 elmex 1.1 }
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 root 1.56 * op1 to op2, so if the tiled maps are asymetric and op2 has a path
1539 elmex 1.1 * 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 root 1.29 int
1545     on_same_map (const object *op1, const object *op2)
1546     {
1547     int dx, dy;
1548 elmex 1.1
1549 root 1.29 return adjacent_map (op1->map, op2->map, &dx, &dy);
1550 elmex 1.1 }
1551 root 1.52
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 root 1.81 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 root 1.91 /* 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 root 1.92 if (pick && pick->head_ () == pick)
1595 root 1.91 return pick->head_ ();
1596     }
1597    
1598     // instead of crashing in the unlikely(?) case, try to return *something*
1599     return get_archetype ("blocked");
1600     }
1601 root 1.85
1602 root 1.114 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 root 1.125 if (pl->observe->map == this)
1610 root 1.114 if (client *ns = pl->ns)
1611     {
1612 root 1.126 int dx = x - pl->observe->x;
1613     int dy = y - pl->observe->y;
1614 root 1.114
1615     int distance = idistance (dx, dy);
1616    
1617     if (distance <= MAX_SOUND_DISTANCE)
1618     ns->play_sound (sound, dx, dy);
1619     }
1620     }
1621