|
Atrinik Server 2.5
|
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 }
1.7.4