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

File Contents

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