--- deliantra/server/common/map.C 2007/05/28 21:21:40 1.106 +++ deliantra/server/common/map.C 2007/08/15 04:57:48 1.116 @@ -1,23 +1,22 @@ /* - * This file is part of Crossfire TRT, the Multiplayer Online Role Playing Game. + * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. * * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team * Copyright (©) 2001-2003,2007 Mark Wedel & Crossfire Development Team * Copyright (©) 1992,2007 Frank Tore Johansen * - * Crossfire TRT is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * Crossfire TRT is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with Crossfire TRT; if not, write to the Free Software Foundation, Inc. 51 - * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * * The authors can be reached via e-mail to */ @@ -31,72 +30,6 @@ #include "path.h" -/* - * This makes a path absolute outside the world of Crossfire. - * In other words, it prepends LIBDIR/MAPDIR/ to the given path - * and returns the pointer to a static array containing the result. - * it really should be called create_mapname - */ -const char * -create_pathname (const char *name) -{ - static char buf[8192]; - snprintf (buf, sizeof (buf), "%s/%s/%s", settings.datadir, settings.mapdir, name); - return buf; -} - -/* - * This function checks if a file with the given path exists. - * -1 is returned if it fails, otherwise the mode of the file - * is returned. - * It tries out all the compression suffixes listed in the uncomp[] array. - * - * If prepend_dir is set, then we call create_pathname (which prepends - * libdir & mapdir). Otherwise, we assume the name given is fully - * complete. - * Only the editor actually cares about the writablity of this - - * the rest of the code only cares that the file is readable. - * when the editor goes away, the call to stat should probably be - * replaced by an access instead (similar to the windows one, but - * that seems to be missing the prepend_dir processing - */ -int -check_path (const char *name, int prepend_dir) -{ - char buf[MAX_BUF]; - - char *endbuf; - struct stat statbuf; - int mode = 0; - - if (prepend_dir) - assign (buf, create_pathname (name)); - else - assign (buf, name); - - /* old method (strchr(buf, '\0')) seemd very odd to me - - * this method should be equivalant and is clearer. - * Can not use strcat because we need to cycle through - * all the names. - */ - endbuf = buf + strlen (buf); - - if (stat (buf, &statbuf)) - return -1; - if (!S_ISREG (statbuf.st_mode)) - return (-1); - - if (((statbuf.st_mode & S_IRGRP) && getegid () == statbuf.st_gid) || - ((statbuf.st_mode & S_IRUSR) && geteuid () == statbuf.st_uid) || (statbuf.st_mode & S_IROTH)) - mode |= 4; - - if ((statbuf.st_mode & S_IWGRP && getegid () == statbuf.st_gid) || - (statbuf.st_mode & S_IWUSR && geteuid () == statbuf.st_uid) || (statbuf.st_mode & S_IWOTH)) - mode |= 2; - - return (mode); -} - /* This rolls up wall, blocks_magic, blocks_view, etc, all into * one function that just returns a P_.. value (see map.h) * it will also do map translation for tiled maps, returning @@ -278,9 +211,9 @@ return m1->at (sx, sy).move_block; } - for (tmp = ob->arch; tmp; tmp = tmp->more) + for (tmp = ob->arch; tmp; tmp = (archetype *)tmp->more) { - flag = get_map_flags (m, &m1, x + tmp->clone.x, y + tmp->clone.y, &sx, &sy); + flag = get_map_flags (m, &m1, x + tmp->x, y + tmp->y, &sx, &sy); if (flag & P_OUT_OF_MAP) return P_OUT_OF_MAP; @@ -358,16 +291,28 @@ return; for (mapspace *ms = spaces + size (); ms-- > spaces; ) - for (object *op = ms->bot; op; op = op->above) - { - /* already multipart - don't do anything more */ - if (op->head_ () == op && !op->more && op->arch->more) - { - op->remove (); - op->expand_tail (); - insert (op, op->x, op->y, 0, INS_NO_MERGE | INS_ABOVE_FLOOR_ONLY | INS_NO_WALK_ON); - } - } + { + object *op = ms->bot; + while (op) + { + /* already multipart - don't do anything more */ + if (op->head_ () == op && !op->more && op->arch->more) + { + op->remove (); + op->expand_tail (); + + // FIXME: INS_ON_TOP is just a workaround for the pentagram vs. + // multi-tile monster bug, where INS_ABOVE_FLOOR_ONLY put the monsters + // below the pentagrams... hopefully INS_ON_TOP doesn't break anything + insert (op, op->x, op->y, 0, INS_NO_MERGE | INS_ON_TOP | INS_NO_WALK_ON); + + op = ms->bot; // we are mutating the mapspace too much with INS_ON_TOP + // so we have to reset the iteration through the mapspace + } + else + op = op->above; + } + } } /* @@ -412,8 +357,6 @@ void maptile::activate () { - active = true; - if (spaces) for (mapspace *ms = spaces + size (); ms-- > spaces; ) for (object *op = ms->bot; op; op = op->above) @@ -423,8 +366,6 @@ void maptile::deactivate () { - active = false; - if (spaces) for (mapspace *ms = spaces + size (); ms-- > spaces; ) for (object *op = ms->bot; op; op = op->above) @@ -716,6 +657,7 @@ case KW_per_player: thawer.get (per_player); break; case KW_per_party: thawer.get (per_party); break; + case KW_no_reset: thawer.get (no_reset); break; case KW_region: default_region = region::find (thawer.get_str ()); break; case KW_shopitems: shopitems = parse_shop_string (thawer.get_str ()); break; @@ -736,6 +678,10 @@ case KW_tile_path_3: thawer.get (tile_path [2]); break; case KW_tile_path_4: thawer.get (tile_path [3]); break; + case KW_ERROR: + set_key (thawer.kw_str, thawer.value); + break; + case KW_end: return true; @@ -802,6 +748,7 @@ MAP_OUT (reset_time); MAP_OUT (reset_timeout); MAP_OUT (fixed_resettime); + MAP_OUT (no_reset); MAP_OUT (difficulty); if (default_region) MAP_OUT2 (region, default_region->name); @@ -865,8 +812,8 @@ void maptile::clear () { - sfree (regions, size ()), regions = 0; - free (regionmap), regionmap = 0; + sfree (regions, size ()); regions = 0; + delete [] regionmap; regionmap = 0; if (spaces) { @@ -924,6 +871,74 @@ clear (); } +/* decay and destroy perishable items in a map */ +void +maptile::do_decay_objects () +{ + if (!spaces) + return; + + for (mapspace *ms = spaces + size (); ms-- > spaces; ) + for (object *above, *op = ms->bot; op; op = above) + { + above = op->above; + + bool destroy = 0; + + // do not decay anything above unique floor tiles (yet :) + if (QUERY_FLAG (op, FLAG_IS_FLOOR) && QUERY_FLAG (op, FLAG_UNIQUE)) + break; + + if (QUERY_FLAG (op, FLAG_IS_FLOOR) + || QUERY_FLAG (op, FLAG_OBJ_ORIGINAL) + || QUERY_FLAG (op, FLAG_OBJ_SAVE_ON_OVL) + || QUERY_FLAG (op, FLAG_UNIQUE) + || QUERY_FLAG (op, FLAG_OVERLAY_FLOOR) + || QUERY_FLAG (op, FLAG_UNPAID) + || op->is_alive ()) + ; // do not decay + else if (op->is_weapon ()) + { + op->stats.dam--; + if (op->stats.dam < 0) + destroy = 1; + } + else if (op->is_armor ()) + { + op->stats.ac--; + if (op->stats.ac < 0) + destroy = 1; + } + else if (op->type == FOOD) + { + op->stats.food -= rndm (5, 20); + if (op->stats.food < 0) + destroy = 1; + } + else + { + int mat = op->materials; + + if (mat & M_PAPER + || mat & M_LEATHER + || mat & M_WOOD + || mat & M_ORGANIC + || mat & M_CLOTH + || mat & M_LIQUID + || (mat & M_IRON && rndm (1, 5) == 1) + || (mat & M_GLASS && rndm (1, 2) == 1) + || ((mat & M_STONE || mat & M_ADAMANT) && rndm (1, 10) == 1) + || ((mat & M_SOFT_METAL || mat & M_BONE) && rndm (1, 3) == 1) + || (mat & M_ICE && temp > 32)) + destroy = 1; + } + + /* adjust overall chance below */ + if (destroy && rndm (0, 1)) + op->destroy (); + } +} + /* * Updates every button on the map (by calling update_button() for them). */ @@ -979,7 +994,7 @@ total_exp += op->stats.exp; if (archetype *at = type_to_archetype (GENERATE_TYPE (op))) - total_exp += at->clone.stats.exp * 8; + total_exp += at->stats.exp * 8; monster_cnt++; } @@ -1653,3 +1668,23 @@ return get_archetype ("blocked"); } +void +maptile::play_sound (faceidx sound, int x, int y) const +{ + if (!sound) + return; + + for_all_players (pl) + if (pl->ob->map == this) + if (client *ns = pl->ns) + { + int dx = x - pl->ob->x; + int dy = y - pl->ob->y; + + int distance = idistance (dx, dy); + + if (distance <= MAX_SOUND_DISTANCE) + ns->play_sound (sound, dx, dy); + } +} +