|
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 00032 static int container_trap(object *op, object *container); 00033 00043 int esrv_apply_container(object *op, object *sack) 00044 { 00045 object *cont, *tmp; 00046 00047 if (op->type != PLAYER) 00048 { 00049 LOG(llevBug, "esrv_apply_container: called from non player: <%s>!\n", query_name(op, NULL)); 00050 return 0; 00051 } 00052 00053 /* cont is NULL or the container player already has opened */ 00054 cont = CONTR(op)->container; 00055 00056 if (sack == NULL || sack->type != CONTAINER || (cont && cont->type != CONTAINER)) 00057 { 00058 LOG(llevBug, "esrv_apply_container: object *sack = %s is not container (cont:<%s>)!\n", query_name(sack, NULL), query_name(cont, NULL)); 00059 return 0; 00060 } 00061 00062 /* close container? 00063 * if cont != sack || cont == sack - in both cases we close cont */ 00064 if (cont) 00065 { 00066 /* Trigger the CLOSE event */ 00067 if (trigger_event(EVENT_CLOSE, op, cont, NULL, NULL, 0, 0, 0, SCRIPT_FIX_ALL)) 00068 { 00069 return 1; 00070 } 00071 00072 if (container_unlink(CONTR(op), cont)) 00073 { 00074 new_draw_info_format(0, COLOR_WHITE, op, "You close %s.", query_name(cont, op)); 00075 } 00076 else 00077 { 00078 new_draw_info_format(0, COLOR_WHITE, op, "You leave %s.", query_name(cont, op)); 00079 } 00080 00081 /* we closing the one we applied */ 00082 if (cont == sack) 00083 { 00084 return 1; 00085 } 00086 } 00087 00088 /* at this point we ready a container OR we open it! */ 00089 00090 /* If the player is trying to open it (which he must be doing if we got here), 00091 * and it is locked, check to see if player has the equipment to open it. */ 00092 if (sack->slaying || sack->stats.maxhp) 00093 { 00094 /* Locked container */ 00095 if (sack->sub_type == ST1_CONTAINER_NORMAL) 00096 { 00097 tmp = find_key(op, sack); 00098 00099 if (tmp) 00100 { 00101 if (tmp->type == KEY) 00102 { 00103 new_draw_info_format(0, COLOR_WHITE, op, "You unlock %s with %s.", query_name(sack, op), query_name(tmp, op)); 00104 } 00105 else if (tmp->type == FORCE) 00106 { 00107 new_draw_info_format(0, COLOR_WHITE, op, "The %s is unlocked for you.", query_name(sack, op)); 00108 } 00109 } 00110 else 00111 { 00112 new_draw_info_format(0, COLOR_WHITE, op, "You don't have the key to unlock %s.", query_name(sack, op)); 00113 return 0; 00114 } 00115 } 00116 /* Personalized container */ 00117 else 00118 { 00119 /* Party corpse */ 00120 if (sack->sub_type == ST1_CONTAINER_CORPSE_party && !party_can_open_corpse(op, sack)) 00121 { 00122 return 0; 00123 } 00124 /* Only give player with right name access */ 00125 else if (sack->sub_type == ST1_CONTAINER_CORPSE_player && sack->slaying != op->name) 00126 { 00127 new_draw_info(0, COLOR_WHITE, op, "It's not your bounty."); 00128 return 0; 00129 } 00130 } 00131 } 00132 00133 /* By the time we get here, we have made sure any other container has been closed and 00134 * if this is a locked container, the player they key to open it. */ 00135 00136 /* There are really two cases - the sack is either on the ground, or the sack is 00137 * part of the players inventory. If on the ground, we assume that the player is 00138 * opening it, since if it was being closed, that would have been taken care of above. 00139 * If it in the players inventory, we can READY the container. */ 00140 /* container is NOT in players inventory */ 00141 if (sack->env != op) 00142 { 00143 /* this is not possible - opening a container inside another container or an another player */ 00144 if (sack->env) 00145 { 00146 new_draw_info_format(0, COLOR_WHITE, op, "You can't open %s.", query_name(sack, op)); 00147 return 0; 00148 } 00149 00150 new_draw_info_format(0, COLOR_WHITE, op, "You open %s.", query_name(sack, op)); 00151 container_link(CONTR(op), sack); 00152 00153 if (sack->slaying && sack->sub_type == ST1_CONTAINER_CORPSE_party) 00154 { 00155 party_handle_corpse(op, sack); 00156 } 00157 } 00158 /* Sack is in player's inventory */ 00159 else 00160 { 00161 /* readied sack becoming open */ 00162 if (QUERY_FLAG(sack, FLAG_APPLIED)) 00163 { 00164 new_draw_info_format(0, COLOR_WHITE, op, "You open %s.", query_name(sack, op)); 00165 container_link(CONTR(op), sack); 00166 } 00167 else 00168 { 00169 CLEAR_FLAG(sack, FLAG_APPLIED); 00170 new_draw_info_format(0, COLOR_WHITE, op, "You readied %s.", query_name(sack, op)); 00171 SET_FLAG(sack, FLAG_APPLIED); 00172 00173 update_object(sack, UP_OBJ_FACE); 00174 esrv_update_item(UPD_FLAGS, op, sack); 00175 /* search & explode a rune in the container */ 00176 container_trap(op, sack); 00177 } 00178 } 00179 00180 if ((sack->sub_type == ST1_CONTAINER_CORPSE_party || sack->sub_type == ST1_CONTAINER_CORPSE_player) && !QUERY_FLAG(sack, FLAG_BEEN_APPLIED)) 00181 { 00182 CONTR(op)->stat_corpses_searched++; 00183 } 00184 00185 /* Only after actually readying/opening the container we know more 00186 * about it. */ 00187 SET_FLAG(sack, FLAG_BEEN_APPLIED); 00188 00189 return 1; 00190 } 00191 00198 int container_link(player *pl, object *sack) 00199 { 00200 int ret = 0; 00201 00202 /* For safety reasons, let's check this is valid */ 00203 if (sack->attacked_by) 00204 { 00205 if (sack->attacked_by->type != PLAYER || !CONTR(sack->attacked_by) || CONTR(sack->attacked_by)->container != sack) 00206 { 00207 LOG(llevBug, "container_link() - invalid player linked: <%s>\n", query_name(sack->attacked_by, NULL)); 00208 sack->attacked_by = NULL; 00209 } 00210 } 00211 00212 /* the open/close logic should be handled elsewhere. 00213 * for that reason, this function should only be called 00214 * when valid - broken open/close logic elsewhere is bad. 00215 * so, give a bug warning out! */ 00216 if (pl->container) 00217 { 00218 LOG(llevBug, "container_link() - called from player with open container!: <%s> sack:<%s>\n", query_name(sack->attacked_by, NULL), query_name(sack, NULL)); 00219 container_unlink(pl, sack); 00220 } 00221 00222 /* Check for quest containers. */ 00223 if (HAS_EVENT(sack, EVENT_QUEST)) 00224 { 00225 object *tmp; 00226 00227 for (tmp = sack->inv; tmp; tmp = tmp->below) 00228 { 00229 if (tmp->type == QUEST_CONTAINER) 00230 { 00231 check_quest(pl->ob, tmp); 00232 } 00233 } 00234 } 00235 00236 pl->container = sack; 00237 pl->container_count = sack->count; 00238 00239 pl->container_above = sack->attacked_by; 00240 00241 if (sack->attacked_by) 00242 { 00243 CONTR(sack->attacked_by)->container_below = pl->ob; 00244 } 00245 /* we are the first one opening this container */ 00246 else 00247 { 00248 SET_FLAG(sack, FLAG_APPLIED); 00249 00250 /* faking open container face */ 00251 if (sack->other_arch) 00252 { 00253 sack->face = sack->other_arch->clone.face; 00254 sack->animation_id = sack->other_arch->clone.animation_id; 00255 00256 if (sack->animation_id) 00257 { 00258 SET_ANIMATION(sack, (NUM_ANIMATIONS(sack) / NUM_FACINGS(sack)) * sack->direction); 00259 } 00260 00261 update_object(sack, UP_OBJ_FACE); 00262 } 00263 00264 update_object(sack, UP_OBJ_FACE); 00265 esrv_update_item (UPD_FLAGS|UPD_FACE, pl->ob, sack); 00266 container_trap(pl->ob, sack); 00267 ret = 1; 00268 } 00269 00270 esrv_send_inventory(pl->ob, sack); 00271 /* we are first element */ 00272 pl->container_below = NULL; 00273 sack->attacked_by = pl->ob; 00274 sack->attacked_by_count = pl->ob->count; 00275 00276 return ret; 00277 } 00278 00287 int container_unlink(player *pl, object *sack) 00288 { 00289 object *tmp, *tmp2; 00290 00291 if (pl == NULL && sack == NULL) 00292 { 00293 LOG(llevBug, "container_unlink() - *pl AND *sack == NULL!\n"); 00294 return 0; 00295 } 00296 00297 if (pl) 00298 { 00299 if (!pl->container) 00300 { 00301 return 0; 00302 } 00303 00304 if (pl->container->count != pl->container_count) 00305 { 00306 pl->container = NULL; 00307 pl->container_count = 0; 00308 return 0; 00309 } 00310 00311 sack = pl->container; 00312 update_object(sack, UP_OBJ_FACE); 00313 esrv_close_container(pl->ob); 00314 00315 /* ok, there is a valid container - unlink the player now */ 00316 00317 /* we are only applier */ 00318 if (!pl->container_below && !pl->container_above) 00319 { 00320 /* we should be that object... */ 00321 if (pl->container->attacked_by != pl->ob) 00322 { 00323 LOG(llevBug, "container_unlink() - container link don't match player!: <%s> sack:<%s> (%s)\n", query_name(pl->ob, NULL), query_name(sack->attacked_by, NULL), query_name(sack, NULL)); 00324 return 0; 00325 } 00326 00327 pl->container = NULL; 00328 pl->container_count = 0; 00329 00330 CLEAR_FLAG(sack, FLAG_APPLIED); 00331 00332 if (sack->other_arch) 00333 { 00334 sack->face = sack->arch->clone.face; 00335 sack->animation_id = sack->arch->clone.animation_id; 00336 00337 if (sack->animation_id) 00338 { 00339 SET_ANIMATION(sack, (NUM_ANIMATIONS(sack) / NUM_FACINGS(sack)) * sack->direction); 00340 } 00341 00342 update_object(sack, UP_OBJ_FACE); 00343 } 00344 00345 sack->attacked_by = NULL; 00346 sack->attacked_by_count = 0; 00347 esrv_update_item (UPD_FLAGS|UPD_FACE, pl->ob, sack); 00348 return 1; 00349 } 00350 00351 /* because there is another player applying that container, we don't close it */ 00352 00353 /* we are first player in list */ 00354 if (!pl->container_below) 00355 { 00356 /* mark above as first player applying this container */ 00357 sack->attacked_by = pl->container_above; 00358 sack->attacked_by_count = pl->container_above->count; 00359 CONTR(pl->container_above)->container_below = NULL; 00360 00361 pl->container_above = NULL; 00362 pl->container = NULL; 00363 pl->container_count = 0; 00364 return 0; 00365 } 00366 00367 /* we are somewhere in the middle or last one - it don't matter */ 00368 CONTR(pl->container_below)->container_above = pl->container_above; 00369 00370 if (pl->container_above) 00371 { 00372 CONTR(pl->container_above)->container_below = pl->container_below; 00373 } 00374 00375 pl->container_below=NULL; 00376 pl->container_above=NULL; 00377 pl->container = NULL; 00378 pl->container_count = 0; 00379 return 0; 00380 } 00381 00382 CLEAR_FLAG(sack, FLAG_APPLIED); 00383 00384 if (sack->other_arch) 00385 { 00386 sack->face = sack->arch->clone.face; 00387 sack->animation_id = sack->arch->clone.animation_id; 00388 00389 if (sack->animation_id) 00390 { 00391 SET_ANIMATION(sack, (NUM_ANIMATIONS(sack) / NUM_FACINGS(sack)) * sack->direction); 00392 } 00393 00394 update_object(sack, UP_OBJ_FACE); 00395 } 00396 00397 tmp = sack->attacked_by; 00398 sack->attacked_by = NULL; 00399 sack->attacked_by_count = 0; 00400 00401 /* if we are here, we are called with (NULL,sack) */ 00402 while (tmp) 00403 { 00404 /* valid player in list? */ 00405 if (!CONTR(tmp) || CONTR(tmp)->container != sack) 00406 { 00407 LOG(llevBug,"container_unlink() - container link list mismatch!: player?:<%s> sack:<%s> (%s)\n", query_name(tmp, NULL), query_name(sack, NULL), query_name(sack->attacked_by, NULL)); 00408 return 1; 00409 } 00410 00411 tmp2 = CONTR(tmp)->container_above; 00412 CONTR(tmp)->container = NULL; 00413 CONTR(tmp)->container_count = 0; 00414 CONTR(tmp)->container_below = NULL; 00415 CONTR(tmp)->container_above = NULL; 00416 esrv_update_item(UPD_FLAGS|UPD_FACE, tmp, sack); 00417 esrv_close_container(tmp); 00418 tmp = tmp2; 00419 } 00420 00421 return 1; 00422 } 00423 00428 void free_container_monster(object *monster, object *op) 00429 { 00430 int i; 00431 object *container = monster->env; 00432 00433 if (container == NULL) 00434 { 00435 return; 00436 } 00437 00438 /* in container, no walk off check */ 00439 remove_ob(monster); 00440 monster->x = container->x; 00441 monster->y = container->y; 00442 i = find_free_spot(monster->arch, NULL, op->map, monster->x, monster->y, 0, 9); 00443 00444 if (i != -1) 00445 { 00446 monster->x += freearr_x[i]; 00447 monster->y += freearr_y[i]; 00448 } 00449 00450 fix_monster(monster); 00451 00452 if (insert_ob_in_map(monster, op->map, monster, 0)) 00453 { 00454 new_draw_info_format(0, COLOR_WHITE, op, "A %s jumps out of the %s.", query_name(monster, NULL), query_name(container, NULL)); 00455 } 00456 } 00457 00468 static int container_trap(object *op, object *container) 00469 { 00470 int ret = 0; 00471 object *tmp; 00472 00473 for (tmp = container->inv; tmp; tmp = tmp->below) 00474 { 00475 /* Search for traps and runes */ 00476 if (tmp->type == RUNE) 00477 { 00478 ret++; 00479 spring_trap(tmp, op); 00480 } 00481 /* Search for monsters living in containers */ 00482 else if (tmp->type == MONSTER) 00483 { 00484 ret++; 00485 free_container_monster(tmp, op); 00486 } 00487 } 00488 00489 return ret; 00490 } 00491 00498 int check_magical_container(object *op, object *container) 00499 { 00500 if (op->type == CONTAINER && container->type == CONTAINER && op->weapon_speed != 1.0f && container->weapon_speed != 1.0f) 00501 { 00502 return 1; 00503 } 00504 00505 return 0; 00506 }
1.7.4