|
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 #include <book.h> 00032 00039 sint64 find_traps(object *pl, int level) 00040 { 00041 object *tmp, *tmp2; 00042 mapstruct *m; 00043 int xt, yt, i, suc = 0; 00044 00045 /* First we search all around us for runes and traps, which are 00046 * all type RUNE */ 00047 for (i = 0; i < 9; i++) 00048 { 00049 /* Check everything in the square for trapness */ 00050 xt = pl->x + freearr_x[i]; 00051 yt = pl->y + freearr_y[i]; 00052 00053 if (!(m = get_map_from_coord(pl->map, &xt, &yt))) 00054 { 00055 continue; 00056 } 00057 00058 for (tmp = get_map_ob(m, xt, yt); tmp != NULL; tmp = tmp->above) 00059 { 00060 /* And now we'd better do an inventory traversal of each 00061 * of these objects' inventory */ 00062 if (pl != tmp && (tmp->type == PLAYER || tmp->type == MONSTER)) 00063 { 00064 continue; 00065 } 00066 00067 for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->below) 00068 { 00069 if (tmp2->type == RUNE) 00070 { 00071 if (trap_see(pl, tmp2, level)) 00072 { 00073 trap_show(tmp2, tmp); 00074 00075 if (!suc) 00076 { 00077 suc = 1; 00078 } 00079 } 00080 else 00081 { 00082 /* Give out a "we have found signs of traps" 00083 * if the traps level is not 1.8 times higher. */ 00084 if (tmp2->level <= (level * 1.8f)) 00085 { 00086 suc = 2; 00087 } 00088 } 00089 } 00090 } 00091 00092 if (tmp->type == RUNE) 00093 { 00094 if (trap_see(pl, tmp, level)) 00095 { 00096 trap_show(tmp, tmp); 00097 00098 if (!suc) 00099 { 00100 suc = 1; 00101 } 00102 } 00103 else 00104 { 00105 /* Give out a "we have found signs of traps" 00106 * if the traps level is not 1.8 times higher. */ 00107 if (tmp->level <= (level * 1.8f)) 00108 { 00109 suc = 2; 00110 } 00111 } 00112 } 00113 } 00114 } 00115 00116 if (!suc) 00117 { 00118 new_draw_info(0, COLOR_WHITE, pl, "You can't detect any trap here."); 00119 } 00120 else if (suc == 2) 00121 { 00122 new_draw_info(0, COLOR_WHITE, pl, "You detect trap signs!"); 00123 } 00124 00125 return 0; 00126 } 00127 00132 sint64 remove_trap(object *op) 00133 { 00134 object *tmp, *tmp2; 00135 mapstruct *m; 00136 int i, x, y; 00137 00138 for (i = 0; i < 9; i++) 00139 { 00140 x = op->x + freearr_x[i]; 00141 y = op->y + freearr_y[i]; 00142 00143 if (!(m = get_map_from_coord(op->map, &x, &y))) 00144 { 00145 continue; 00146 } 00147 00148 /* Check everything in the square for trapness */ 00149 for (tmp = get_map_ob(m, x, y); tmp != NULL; tmp = tmp->above) 00150 { 00151 /* And now we'd better do an inventory traversal of each 00152 * of these objects' inventory */ 00153 for (tmp2 = tmp->inv; tmp2; tmp2 = tmp2->below) 00154 { 00155 if (tmp2->type == RUNE && tmp2->stats.Cha <= 1) 00156 { 00157 if (QUERY_FLAG(tmp2, FLAG_SYS_OBJECT) || QUERY_FLAG(tmp2, FLAG_IS_INVISIBLE)) 00158 { 00159 trap_show(tmp2, tmp); 00160 } 00161 00162 trap_disarm(op, tmp2); 00163 return 0; 00164 } 00165 } 00166 00167 if (tmp->type == RUNE && tmp->stats.Cha <= 1) 00168 { 00169 if (QUERY_FLAG(tmp, FLAG_SYS_OBJECT) || QUERY_FLAG(tmp, FLAG_IS_INVISIBLE)) 00170 { 00171 trap_show(tmp, tmp); 00172 } 00173 00174 trap_disarm(op, tmp); 00175 return 0; 00176 } 00177 } 00178 } 00179 00180 new_draw_info(0, COLOR_WHITE, op, "There is no trap to remove nearby."); 00181 return 0; 00182 } 00183 00195 object *find_throw_tag(object *op, tag_t tag) 00196 { 00197 object *tmp; 00198 00199 if (CONTR(op)->socket.socket_version < 1048) 00200 { 00201 /* Look through the inventory. */ 00202 for (tmp = op->inv; tmp; tmp = tmp->below) 00203 { 00204 /* Can't toss invisible or inv-locked items */ 00205 if (IS_SYS_INVISIBLE(tmp) || QUERY_FLAG(tmp, FLAG_INV_LOCKED)) 00206 { 00207 continue; 00208 } 00209 00210 if (tmp->count == tag) 00211 { 00212 break; 00213 } 00214 } 00215 } 00216 else 00217 { 00218 tmp = CONTR(op)->ready_object[READY_OBJ_THROW]; 00219 } 00220 00221 if (!tmp) 00222 { 00223 return NULL; 00224 } 00225 00226 if (CONTR(op)->socket.socket_version >= 1048 && !OBJECT_VALID(tmp, CONTR(op)->ready_object_tag[READY_OBJ_THROW])) 00227 { 00228 return NULL; 00229 } 00230 00231 if (QUERY_FLAG(tmp, FLAG_APPLIED)) 00232 { 00233 /* We can't apply throwing stuff like darts, so this must be a 00234 * weapon. Skip if not OR when it can't be thrown OR when it is 00235 * startequip which can't be dropped. */ 00236 if (tmp->type != WEAPON || !QUERY_FLAG(tmp, FLAG_IS_THROWN)) 00237 { 00238 new_draw_info_format(0, COLOR_WHITE, op, "You can't throw %s.", query_base_name(tmp, NULL)); 00239 return NULL; 00240 } 00241 else if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) 00242 { 00243 new_draw_info(0, COLOR_WHITE, op, "You can't throw god-given item!"); 00244 return NULL; 00245 } 00246 /* If cursed or damned, we can't unapply it - no throwing. */ 00247 else if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) 00248 { 00249 new_draw_info_format(0, COLOR_WHITE, op, "The %s sticks to your hand!", query_base_name(tmp, NULL)); 00250 return NULL; 00251 } 00252 /* It's a throw hybrid weapon - unapply it. Then we will fire it 00253 * after this function returns. */ 00254 else 00255 { 00256 if (apply_special(op, tmp, AP_UNAPPLY | AP_NO_MERGE)) 00257 { 00258 LOG(llevBug, "find_throw_ob(): couldn't unapply throwing item %s from %s\n", query_name(tmp, NULL), query_name(op, NULL)); 00259 return NULL; 00260 } 00261 } 00262 } 00263 else 00264 { 00265 /* Not weapon nor throwable - no throwing. */ 00266 if ((tmp->type != WEAPON && tmp->type != POTION) && !QUERY_FLAG(tmp, FLAG_IS_THROWN)) 00267 { 00268 new_draw_info_format(0, COLOR_WHITE, op, "You can't throw %s.", query_base_name(tmp, NULL)); 00269 return NULL; 00270 } 00271 /* Special message for throw hybrid weapons. */ 00272 else if (tmp->type == WEAPON) 00273 { 00274 new_draw_info_format(0, COLOR_WHITE, op, "You must apply the %s first.", query_base_name(tmp, NULL)); 00275 return NULL; 00276 } 00277 } 00278 00279 return tmp; 00280 } 00281 00287 void do_throw(object *op, object *toss_item, int dir) 00288 { 00289 object *left_cont, *throw_ob = toss_item, *left = NULL, *tmp_op; 00290 tag_t left_tag; 00291 rv_vector range_vector; 00292 00293 if (!throw_ob) 00294 { 00295 if (op->type == PLAYER) 00296 { 00297 new_draw_info(0, COLOR_WHITE, op, "You have nothing to throw."); 00298 } 00299 00300 return; 00301 } 00302 00303 if (QUERY_FLAG(throw_ob, FLAG_STARTEQUIP)) 00304 { 00305 if (op->type == PLAYER) 00306 { 00307 new_draw_info(0, COLOR_WHITE, op, "The gods won't let you throw that."); 00308 } 00309 00310 return; 00311 } 00312 00313 if (throw_ob->weight <= 0) 00314 { 00315 new_draw_info_format(0, COLOR_WHITE, op, "You can't throw %s.\n", query_base_name(throw_ob, NULL)); 00316 return; 00317 } 00318 00319 /* These are throwing objects left to the player */ 00320 left = throw_ob; 00321 left_cont = left->env; 00322 left_tag = left->count; 00323 00324 /* Sometimes get_split_ob can't split an object (because op->nrof==0?) 00325 * and returns NULL. We must use 'left' then */ 00326 if ((throw_ob = get_split_ob(throw_ob, 1, NULL, 0)) == NULL) 00327 { 00328 throw_ob = left; 00329 remove_ob(left); 00330 check_walk_off(left, NULL, MOVE_APPLY_VANISHED); 00331 00332 if (op->type == PLAYER) 00333 { 00334 esrv_del_item(CONTR(op), left->count, left->env); 00335 } 00336 } 00337 else if (op->type == PLAYER) 00338 { 00339 if (was_destroyed(left, left_tag)) 00340 { 00341 esrv_del_item(CONTR(op), left_tag, left_cont); 00342 } 00343 else 00344 { 00345 esrv_update_item(UPD_NROF, op, left); 00346 } 00347 } 00348 00349 /* Special case: throwing powdery substances like dust, dirt */ 00350 if (QUERY_FLAG(throw_ob, FLAG_DUST)) 00351 { 00352 cast_dust(op, throw_ob, dir); 00353 00354 /* update the shooting speed for the player action timer. 00355 * We init the used skill with it - its not calculated here. 00356 * cast_dust() can change the used skill... */ 00357 if (op->type == PLAYER) 00358 { 00359 op->chosen_skill->stats.maxsp = throw_ob->last_grace; 00360 } 00361 00362 return; 00363 } 00364 00365 /* Targetting throwing */ 00366 if (!dir && op->type == PLAYER && OBJECT_VALID(CONTR(op)->target_object, CONTR(op)->target_object_count)) 00367 { 00368 dir = get_dir_to_target(op, CONTR(op)->target_object, &range_vector); 00369 } 00370 00371 /* Three things here prevent a throw, you aimed at your feet, you 00372 * have no effective throwing strength, or you threw at a wall */ 00373 if (!dir || wall(op->map, op->x + freearr_x[dir], op->y + freearr_y[dir])) 00374 { 00375 /* Bounces off 'wall', and drops to feet */ 00376 if (!QUERY_FLAG(throw_ob, FLAG_REMOVED)) 00377 { 00378 remove_ob(throw_ob); 00379 00380 if (check_walk_off(throw_ob, NULL, MOVE_APPLY_MOVE) != CHECK_WALK_OK) 00381 { 00382 return; 00383 } 00384 } 00385 00386 if (op->type == PLAYER) 00387 { 00388 if (!dir) 00389 { 00390 new_draw_info_format(0, COLOR_WHITE, op, "You drop %s at the ground.", query_name(throw_ob, NULL)); 00391 } 00392 else 00393 { 00394 new_draw_info(0, COLOR_WHITE, op, "Something is in the way."); 00395 } 00396 } 00397 00398 throw_ob->x = op->x; 00399 throw_ob->y = op->y; 00400 00401 if (!insert_ob_in_map(throw_ob, op->map, op, 0)) 00402 { 00403 return; 00404 } 00405 00406 return; 00407 } 00408 00409 CONTR(op)->stat_missiles_thrown++; 00410 00411 set_owner(throw_ob, op); 00412 set_owner(throw_ob->inv, op); 00413 throw_ob->direction = dir; 00414 throw_ob->x = op->x; 00415 throw_ob->y = op->y; 00416 00417 /* Save original wc and dam */ 00418 throw_ob->last_heal = throw_ob->stats.wc; 00419 throw_ob->stats.hp = throw_ob->stats.dam; 00420 00421 /* Speed */ 00422 throw_ob->speed = MIN(1.0f, (speed_bonus[op->stats.Str] + 1.0f) / 1.5f); 00423 00424 /* Now we get the wc from the used skill. */ 00425 if ((tmp_op = SK_skill(op))) 00426 { 00427 throw_ob->stats.wc += tmp_op->last_heal; 00428 } 00429 /* Monsters */ 00430 else 00431 { 00432 throw_ob->stats.wc += 10; 00433 } 00434 00435 throw_ob->stats.wc_range = op->stats.wc_range; 00436 00437 if (QUERY_FLAG(throw_ob, FLAG_IS_THROWN)) 00438 { 00439 throw_ob->stats.dam += throw_ob->magic; 00440 throw_ob->stats.wc += throw_ob->magic; 00441 00442 /* Adjust for players */ 00443 if (op->type == PLAYER) 00444 { 00445 op->chosen_skill->stats.maxsp = throw_ob->last_grace; 00446 throw_ob->stats.dam = FABS((int) ((float) (throw_ob->stats.dam + dam_bonus[op->stats.Str] / 2) * LEVEL_DAMAGE(SK_level(op)))); 00447 throw_ob->stats.wc += thaco_bonus[op->stats.Dex] + SK_level(op); 00448 } 00449 else 00450 { 00451 throw_ob->stats.dam = FABS((int) ((float) (throw_ob->stats.dam) * LEVEL_DAMAGE(op->level))); 00452 throw_ob->stats.wc += 10 + op->level; 00453 } 00454 00455 throw_ob->stats.grace = throw_ob->last_sp; 00456 throw_ob->stats.maxgrace = 60 + (RANDOM() % 12); 00457 00458 /* Only throw objects get directional faces */ 00459 if (GET_ANIM_ID(throw_ob) && NUM_ANIMATIONS(throw_ob)) 00460 { 00461 SET_ANIMATION(throw_ob, (NUM_ANIMATIONS(throw_ob) / NUM_FACINGS(throw_ob)) * dir); 00462 } 00463 00464 /* Adjust damage with item condition */ 00465 throw_ob->stats.dam = (sint16) (((float) throw_ob->stats.dam / 100.0f) * (float) throw_ob->item_condition); 00466 } 00467 00468 if (throw_ob->stats.dam < 0) 00469 { 00470 throw_ob->stats.dam = 0; 00471 } 00472 00473 update_ob_speed(throw_ob); 00474 throw_ob->speed_left = 0; 00475 00476 SET_MULTI_FLAG(throw_ob, FLAG_FLYING); 00477 SET_FLAG(throw_ob, FLAG_FLY_ON); 00478 SET_FLAG(throw_ob, FLAG_WALK_ON); 00479 00480 play_sound_map(op->map, CMD_SOUND_EFFECT, "throw.ogg", op->x, op->y, 0, 0); 00481 00482 /* Trigger the THROW event */ 00483 trigger_event(EVENT_THROW, op, throw_ob, NULL, NULL, 0, 0, 0, SCRIPT_FIX_ACTIVATOR); 00484 00485 if (insert_ob_in_map(throw_ob, op->map, op, 0)) 00486 { 00487 move_arrow(throw_ob); 00488 } 00489 }
1.7.4