Atrinik Server 2.5
server/move.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00042 int move_ob(object *op, int dir, object *originator)
00043 {
00044     object *tmp;
00045     mapstruct *m;
00046     int xt, yt, flags;
00047 
00048     if (op == NULL)
00049     {
00050         LOG(llevBug, "move_ob(): Trying to move NULL.\n");
00051         return 0;
00052     }
00053 
00054     if (QUERY_FLAG(op, FLAG_REMOVED))
00055     {
00056         LOG(llevBug, "move_ob: monster has been removed - will not process further\n");
00057         return 0;
00058     }
00059 
00060     /* this function should now only be used on the head - it won't call itself
00061      * recursively, and functions calling us should pass the right part. */
00062     if (op->head)
00063     {
00064         LOG(llevDebug, "move_ob() called with non head object: %s %s (%d,%d)\n", query_name(op->head, NULL), op->map->path ? op->map->path : "<no map>", op->x, op->y);
00065         op = op->head;
00066     }
00067 
00068     /* animation stuff */
00069     if (op->head)
00070     {
00071         op->head->anim_moving_dir = dir;
00072     }
00073     else
00074     {
00075         op->anim_moving_dir = dir;
00076     }
00077 
00078     op->direction = dir;
00079 
00080     xt = op->x + freearr_x[dir];
00081     yt = op->y + freearr_y[dir];
00082 
00083     /* we have here a get_map_from_coord - we can skip all */
00084     if (!(m = get_map_from_coord(op->map, &xt, &yt)))
00085     {
00086         return 0;
00087     }
00088 
00089     /* Don't allow non-players to move onto player-only tiles. */
00090     if (op->type != PLAYER && GET_MAP_FLAGS(m, xt, yt) & P_PLAYER_ONLY)
00091     {
00092         return 0;
00093     }
00094 
00095     /* multi arch objects... */
00096     if (op->more)
00097     {
00098         /* Look in single tile move to see how we handle doors.
00099          * This needs to be done before we allow multi tile mobs to do
00100          * more fancy things. */
00101         if (blocked_link(op, freearr_x[dir], freearr_y[dir]))
00102         {
00103             return 0;
00104         }
00105 
00106         remove_ob(op);
00107 
00108         if (check_walk_off(op, originator, MOVE_APPLY_MOVE) & (CHECK_WALK_DESTROYED | CHECK_WALK_MOVED))
00109         {
00110             return 1;
00111         }
00112 
00113         for (tmp = op; tmp != NULL; tmp = tmp->more)
00114         {
00115             tmp->x += freearr_x[dir], tmp->y += freearr_y[dir];
00116         }
00117 
00118         insert_ob_in_map(op, op->map, op, 0);
00119 
00120         return 1;
00121     }
00122 
00123     /* Single arch */
00124     if (!QUERY_FLAG(op, FLAG_WIZPASS))
00125     {
00126         /* Is the spot blocked from something? */
00127         if ((flags = blocked(op, m, xt, yt, op->terrain_flag)))
00128         {
00129             /* A closed door which we can open? */
00130             if ((flags & P_DOOR_CLOSED) && (op->behavior & BEHAVIOR_OPEN_DOORS) && open_door(op, m, xt, yt, 1))
00131             {
00132                 if (op->type == PLAYER)
00133                 {
00134                     return 1;
00135                 }
00136             }
00137             else
00138             {
00139                 return 0;
00140             }
00141         }
00142     }
00143 
00144     remove_ob(op);
00145 
00146     if (check_walk_off(op, originator, MOVE_APPLY_MOVE) & (CHECK_WALK_DESTROYED | CHECK_WALK_MOVED))
00147     {
00148         return 1;
00149     }
00150 
00151     op->x += freearr_x[dir];
00152     op->y += freearr_y[dir];
00153 
00154     insert_ob_in_map(op, op->map, originator, 0);
00155 
00156     if (op->type == PLAYER)
00157     {
00158         CONTR(op)->stat_steps_taken++;
00159     }
00160 
00161     return 1;
00162 }
00163 
00176 int transfer_ob(object *op, int x, int y, int randomly, object *originator, object *trap)
00177 {
00178     int i, ret;
00179     object *tmp;
00180 
00181     /* this is not 100% tested for mobs - enter_exit will still fail to return for mobs */
00182     /* but some testing should make it for mobs too */
00183     if (trap != NULL && EXIT_PATH(trap))
00184     {
00185         if (op->type == PLAYER && trap->msg && strncmp(EXIT_PATH(trap), "/!", 2) && strncmp(EXIT_PATH(trap), "/random/", 8))
00186         {
00187             new_draw_info(0, COLOR_NAVY, op, trap->msg);
00188         }
00189 
00190         enter_exit(op, trap);
00191         return 1;
00192     }
00193     else if (randomly)
00194     {
00195         i = find_free_spot(op->arch, NULL, op->map, x, y, 0, SIZEOFFREE);
00196     }
00197     else
00198     {
00199         i = find_first_free_spot(op->arch, op, op->map, x, y);
00200     }
00201 
00202     /* No free spot */
00203     if (i == -1)
00204     {
00205         return 0;
00206     }
00207 
00208     if (op->head != NULL)
00209     {
00210         op = op->head;
00211     }
00212 
00213     remove_ob(op);
00214 
00215     if (check_walk_off(op, NULL, MOVE_APPLY_DEFAULT) != CHECK_WALK_OK)
00216     {
00217         return 1;
00218     }
00219 
00220     for (tmp = op; tmp != NULL; tmp = tmp->more)
00221     {
00222         tmp->x = x + freearr_x[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.x);
00223         tmp->y = y + freearr_y[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.y);
00224     }
00225 
00226     ret = (insert_ob_in_map(op, op->map, originator, 0) == NULL);
00227 
00228     return ret;
00229 }
00230 
00237 int teleport(object *teleporter, uint8 tele_type, object *user)
00238 {
00239     /* Better use c/malloc here in the future */
00240     object *altern[120];
00241     int i, j, k, nrofalt = 0, xt, yt;
00242     object *other_teleporter, *tmp;
00243     mapstruct *m;
00244 
00245     if (user == NULL)
00246     {
00247         return 0;
00248     }
00249 
00250     if (user->head != NULL)
00251     {
00252         user = user->head;
00253     }
00254 
00255     /* Find all other teleporters within range. This range should really
00256      * be setable by some object attribute instead of using hard coded
00257      * values. */
00258     for (i = -5; i < 6; i++)
00259     {
00260         for (j = -5; j < 6; j++)
00261         {
00262             if (i == 0 && j == 0)
00263             {
00264                 continue;
00265             }
00266 
00267             xt = teleporter->x + i;
00268             yt = teleporter->y + j;
00269 
00270             if (!(m = get_map_from_coord(teleporter->map, &xt, &yt)))
00271             {
00272                 continue;
00273             }
00274 
00275             other_teleporter = get_map_ob(m, xt, yt);
00276 
00277             while (other_teleporter)
00278             {
00279                 if (other_teleporter->type == tele_type)
00280                 {
00281                     break;
00282                 }
00283 
00284                 other_teleporter = other_teleporter->above;
00285             }
00286 
00287             if (other_teleporter)
00288             {
00289                 altern[nrofalt++] = other_teleporter;
00290             }
00291         }
00292     }
00293 
00294     if (!nrofalt)
00295     {
00296         LOG(llevBug, "teleport(): No alternative teleporters around!\n");
00297         return 0;
00298     }
00299 
00300     other_teleporter = altern[RANDOM() % nrofalt];
00301     k = find_free_spot(user->arch, user, other_teleporter->map, other_teleporter->x, other_teleporter->y, 1, 9);
00302 
00303     if (k == -1)
00304     {
00305         return 0;
00306     }
00307 
00308     remove_ob(user);
00309 
00310     if (check_walk_off(user, NULL, MOVE_APPLY_VANISHED) != CHECK_WALK_OK)
00311     {
00312         return 1;
00313     }
00314 
00315     /* Update location for the object */
00316     for (tmp = user; tmp != NULL; tmp = tmp->more)
00317     {
00318         tmp->x = other_teleporter->x + freearr_x[k] + (tmp->arch == NULL ? 0 : tmp->arch->clone.x);
00319         tmp->y = other_teleporter->y + freearr_y[k] + (tmp->arch == NULL ? 0 : tmp->arch->clone.y);
00320     }
00321 
00322     tmp = insert_ob_in_map(user, other_teleporter->map, NULL, 0);
00323 
00324     return (tmp == NULL);
00325 }
00326 
00333 int push_ob(object *op, int dir, object *pusher)
00334 {
00335     object *tmp, *floor;
00336     mapstruct *m;
00337     int x, y, flags;
00338 
00339     /* Don't allow pushing multi-arch objects. */
00340     if (op->head)
00341     {
00342         return 0;
00343     }
00344 
00345     /* Check whether we are strong enough to push this object. */
00346     if (op->weight && (op->weight / 50000 - 1 > 0 ? rndm(0, op->weight / 50000 - 1) : 0) > pusher->stats.Str)
00347     {
00348         return 0;
00349     }
00350 
00351     x = op->x + freearr_x[dir];
00352     y = op->y + freearr_y[dir];
00353 
00354     if (!(m = get_map_from_coord(op->map, &x, &y)))
00355     {
00356         return 0;
00357     }
00358 
00359     floor = GET_MAP_OB_LAYER(m, x, y, 0);
00360 
00361     /* Floor has no-push flag set? */
00362     if (floor && QUERY_FLAG(floor, FLAG_XRAYS))
00363     {
00364         return 0;
00365     }
00366 
00367     flags = blocked(op, m, x, y, op->terrain_flag);
00368 
00369     if (flags)
00370     {
00371         if (flags & (P_NO_PASS | P_CHECK_INV) || ((flags & P_DOOR_CLOSED) && !open_door(op, m, x, y, 1)))
00372         {
00373             return 0;
00374         }
00375         else
00376         {
00377             return 0;
00378         }
00379     }
00380 
00381     /* Try to find something that would block the push. */
00382     for (tmp = GET_MAP_OB(m, x, y); tmp; tmp = tmp->above)
00383     {
00384         if (tmp->head || IS_LIVE(tmp) || tmp->type == TELEPORTER || tmp->type == SHOP_MAT)
00385         {
00386             return 0;
00387         }
00388     }
00389 
00390     remove_ob(op);
00391 
00392     if (check_walk_off(op, NULL, MOVE_APPLY_VANISHED) != CHECK_WALK_OK)
00393     {
00394         return 0;
00395     }
00396 
00397     op->x = op->x + freearr_x[dir];
00398     op->y = op->y + freearr_y[dir];
00399     insert_ob_in_map(op, op->map, pusher, 0);
00400     return 1;
00401 }
00402 
00403 int missile_reflection_adjust(object *op, int flag)
00404 {
00405     /* no more direction/reflection! */
00406     if (!op->stats.maxgrace)
00407     {
00408         return 0;
00409     }
00410 
00411     op->stats.maxgrace--;
00412 
00413     /* restore the "how long we can fly" counter */
00414     if (!flag)
00415     {
00416         op->last_sp = op->stats.grace;
00417     }
00418 
00419     /* go on with reflection/direction */
00420     return 1;
00421 }