|
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 00031 #include <global.h> 00032 00033 static void remove_force(object *op); 00034 static void remove_blindness(object *op); 00035 static void remove_confusion(object *op); 00036 static void execute_wor(object *op); 00037 static void animate_trigger(object *op); 00038 static void change_object(object *op); 00039 00043 static void remove_force(object *op) 00044 { 00045 if (op->env == NULL) 00046 { 00047 remove_ob(op); 00048 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 00049 return; 00050 } 00051 00052 CLEAR_FLAG(op, FLAG_APPLIED); 00053 change_abil(op->env, op); 00054 fix_player(op->env); 00055 remove_ob(op); 00056 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 00057 } 00058 00062 static void remove_blindness(object *op) 00063 { 00064 if (--op->stats.food > 0) 00065 { 00066 return; 00067 } 00068 00069 CLEAR_FLAG(op, FLAG_APPLIED); 00070 00071 if (op->env) 00072 { 00073 change_abil(op->env, op); 00074 fix_player(op->env); 00075 } 00076 00077 remove_ob(op); 00078 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 00079 } 00080 00084 static void remove_confusion(object *op) 00085 { 00086 if (--op->stats.food > 0) 00087 { 00088 return; 00089 } 00090 00091 if (op->env) 00092 { 00093 CLEAR_FLAG(op->env, FLAG_CONFUSED); 00094 00095 if (op->env->type == PLAYER) 00096 { 00097 new_draw_info(0, COLOR_WHITE, op->env, "You regain your senses."); 00098 } 00099 } 00100 00101 remove_ob(op); 00102 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 00103 } 00104 00108 static void execute_wor(object *op) 00109 { 00110 object *wor = op; 00111 00112 while (op && op->type != PLAYER) 00113 { 00114 op = op->env; 00115 } 00116 00117 if (op != NULL) 00118 { 00119 if (blocks_magic(op->map, op->x, op->y)) 00120 { 00121 new_draw_info(0, COLOR_WHITE, op, "You feel something fizzle inside you."); 00122 } 00123 else 00124 { 00125 enter_exit(op, wor); 00126 } 00127 } 00128 00129 remove_ob(wor); 00130 check_walk_off(wor, NULL, MOVE_APPLY_VANISHED); 00131 } 00132 00136 static void animate_trigger(object *op) 00137 { 00138 if (++op->stats.wc >= NUM_ANIMATIONS(op) / NUM_FACINGS(op)) 00139 { 00140 op->stats.wc = 0; 00141 check_trigger(op, NULL); 00142 } 00143 else 00144 { 00145 op->state = op->stats.wc; 00146 SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction + op->state); 00147 update_object(op, UP_OBJ_FACE); 00148 } 00149 } 00150 00161 object *stop_item(object *op) 00162 { 00163 if (op->map == NULL) 00164 { 00165 return op; 00166 } 00167 00168 switch (op->type) 00169 { 00170 case THROWN_OBJ: 00171 { 00172 object *payload = op->inv; 00173 00174 if (payload == NULL) 00175 { 00176 return NULL; 00177 } 00178 00179 remove_ob(payload); 00180 check_walk_off(payload, NULL, MOVE_APPLY_VANISHED); 00181 remove_ob(op); 00182 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 00183 return payload; 00184 } 00185 00186 case ARROW: 00187 if (op->speed >= MIN_ACTIVE_SPEED) 00188 { 00189 op = fix_stopped_arrow(op); 00190 } 00191 00192 return op; 00193 00194 case CONE: 00195 if (op->speed < MIN_ACTIVE_SPEED) 00196 { 00197 return op; 00198 } 00199 else 00200 { 00201 return NULL; 00202 } 00203 00204 default: 00205 return op; 00206 } 00207 } 00208 00216 void fix_stopped_item(object *op, mapstruct *map, object *originator) 00217 { 00218 if (map == NULL) 00219 { 00220 return; 00221 } 00222 00223 if (QUERY_FLAG(op, FLAG_REMOVED)) 00224 { 00225 insert_ob_in_map(op, map, originator, 0); 00226 } 00227 else if (op->type == ARROW) 00228 { 00229 /* Only some arrows actually need this. */ 00230 merge_ob(op, NULL); 00231 } 00232 } 00233 00237 static void change_object(object *op) 00238 { 00239 object *tmp, *env; 00240 int j; 00241 00242 /* In non-living items only change when food value is 0 */ 00243 if (!IS_LIVE(op)) 00244 { 00245 if (op->stats.food-- > 0) 00246 { 00247 return; 00248 } 00249 else 00250 { 00251 /* We had hooked applyable light object here - handle them special */ 00252 if (op->type == LIGHT_APPLY) 00253 { 00254 CLEAR_FLAG(op, FLAG_CHANGING); 00255 00256 /* Special light like lamp which can be refilled */ 00257 if (op->other_arch == NULL) 00258 { 00259 op->stats.food = 0; 00260 00261 if (op->other_arch && op->other_arch->clone.sub_type & 1) 00262 { 00263 op->animation_id = op->other_arch->clone.animation_id; 00264 SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction); 00265 } 00266 else 00267 { 00268 CLEAR_FLAG(op, FLAG_ANIMATE); 00269 op->face = op->arch->clone.face; 00270 } 00271 00272 /* Not on map? */ 00273 if (op->env) 00274 { 00275 /* Inside player? */ 00276 if (op->env->type == PLAYER) 00277 { 00278 new_draw_info_format(0, COLOR_WHITE, op->env, "The %s burnt out.", query_name(op, NULL)); 00279 op->glow_radius = 0; 00280 esrv_send_item(op->env, op); 00281 /* Fix player will take care about adjusting light masks */ 00282 fix_player(op->env); 00283 } 00284 else 00285 { 00286 op->glow_radius = 0; 00287 00288 if (op->env->type == CONTAINER) 00289 { 00290 esrv_send_item(NULL, op); 00291 } 00292 } 00293 } 00294 /* Object is on map. */ 00295 else 00296 { 00297 /* Remove light mask from map. */ 00298 adjust_light_source(op->map, op->x, op->y, -(op->glow_radius)); 00299 /* Tell map update we have something changed. */ 00300 update_object(op, UP_OBJ_FACE); 00301 op->glow_radius = 0; 00302 } 00303 00304 return; 00305 } 00306 /* This object will be deleted and exchanged with other_arch */ 00307 else 00308 { 00309 /* But give the player a note about it too. */ 00310 if (op->env && op->env->type == PLAYER) 00311 { 00312 new_draw_info_format(0, COLOR_WHITE, op->env, "The %s burnt out.", query_name(op, NULL)); 00313 } 00314 } 00315 } 00316 } 00317 } 00318 00319 if (op->other_arch == NULL) 00320 { 00321 LOG(llevBug, "Change object (%s) without other_arch error.\n", op->name); 00322 return; 00323 } 00324 00325 env = op->env; 00326 remove_ob(op); 00327 check_walk_off(op, NULL,MOVE_APPLY_VANISHED); 00328 00329 tmp = arch_to_object(op->other_arch); 00330 /* The only variable it keeps. */ 00331 tmp->stats.hp = op->stats.hp; 00332 00333 if (env) 00334 { 00335 tmp->x = env->x; 00336 tmp->y = env->y; 00337 tmp = insert_ob_in_ob(tmp, env); 00338 00339 if (env->type == PLAYER) 00340 { 00341 esrv_del_item(CONTR(env), op->count, NULL); 00342 esrv_send_item(env, tmp); 00343 } 00344 else if (env->type == CONTAINER) 00345 { 00346 esrv_del_item(NULL, op->count, env); 00347 esrv_send_item(env, tmp); 00348 } 00349 } 00350 else 00351 { 00352 j = find_first_free_spot(tmp->arch, NULL, op->map, op->x, op->y); 00353 00354 /* Found a free spot */ 00355 if (j != -1) 00356 { 00357 tmp->x = op->x + freearr_x[j]; 00358 tmp->y = op->y + freearr_y[j]; 00359 insert_ob_in_map(tmp, op->map, op, 0); 00360 } 00361 } 00362 } 00363 00370 void move_firewall(object *op) 00371 { 00372 /* DM has created a firewall in his inventory or no legal spell 00373 * selected. */ 00374 if (!op->map || !op->last_eat || op->stats.dam == -1) 00375 { 00376 return; 00377 } 00378 00379 cast_spell(op, op, op->direction, op->stats.dam, 1, CAST_NPC, NULL); 00380 } 00381 00387 void process_object(object *op) 00388 { 00389 /* No need to process objects inside creators. */ 00390 if (op->env && op->env->type == CREATOR) 00391 { 00392 return; 00393 } 00394 00395 if (QUERY_FLAG(op, FLAG_MONSTER)) 00396 { 00397 if (move_monster(op) || OBJECT_FREE(op)) 00398 { 00399 return; 00400 } 00401 } 00402 00403 if (QUERY_FLAG(op, FLAG_CHANGING) && !op->state) 00404 { 00405 change_object(op); 00406 return; 00407 } 00408 00409 if (QUERY_FLAG(op, FLAG_IS_USED_UP) && --op->stats.food <= 0) 00410 { 00411 if (QUERY_FLAG(op, FLAG_APPLIED) && op->type != CONTAINER) 00412 { 00413 remove_force(op); 00414 } 00415 else 00416 { 00417 /* We have a decaying container on the floor (assuming it's 00418 * only possible here) */ 00419 if (op->type == CONTAINER && (op->sub_type & 1) == ST1_CONTAINER_CORPSE) 00420 { 00421 /* This means someone has the corpse open. */ 00422 if (op->attacked_by) 00423 { 00424 /* Give him a bit time back */ 00425 op->stats.food += 3; 00426 return; 00427 } 00428 00429 /* When the corpse is a personal bounty, we delete the 00430 * bounty marker (->slaying) and resetting the counter. 00431 * Now other people can access the corpse for stuff which 00432 * are left here. */ 00433 if (op->slaying || op->stats.maxhp) 00434 { 00435 if (op->slaying) 00436 { 00437 FREE_AND_CLEAR_HASH2(op->slaying); 00438 } 00439 00440 if (op->stats.maxhp) 00441 { 00442 op->stats.maxhp = 0; 00443 } 00444 00445 op->stats.food = op->arch->clone.stats.food; 00446 remove_ob(op); 00447 insert_ob_in_map(op, op->map, NULL, INS_NO_WALK_ON); 00448 return; 00449 } 00450 00451 if (op->env && op->env->type == CONTAINER) 00452 { 00453 esrv_del_item(NULL, op->count, op->env); 00454 } 00455 else 00456 { 00457 object *pl = is_player_inv(op); 00458 00459 if (pl) 00460 { 00461 esrv_del_item(CONTR(pl), op->count, op->env); 00462 } 00463 } 00464 00465 remove_ob(op); 00466 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 00467 return; 00468 } 00469 00470 /* If necessary, delete the item from the player's inventory. */ 00471 if (op->env && op->env->type == CONTAINER) 00472 { 00473 esrv_del_item(NULL, op->count, op->env); 00474 } 00475 else 00476 { 00477 object *pl = is_player_inv(op); 00478 00479 if (pl) 00480 { 00481 esrv_del_item(CONTR(pl), op->count, op->env); 00482 } 00483 } 00484 00485 destruct_ob(op); 00486 } 00487 00488 return; 00489 } 00490 00491 if (HAS_EVENT(op, EVENT_TIME)) 00492 { 00493 trigger_event(EVENT_TIME, NULL, op, NULL, NULL, 0, 0, 0, SCRIPT_FIX_NOTHING); 00494 } 00495 00496 switch (op->type) 00497 { 00498 case ROD: 00499 case HORN: 00500 regenerate_rod(op); 00501 return; 00502 00503 case FORCE: 00504 case POTION_EFFECT: 00505 if (!QUERY_FLAG(op, FLAG_IS_USED_UP)) 00506 { 00507 remove_force(op); 00508 } 00509 00510 return; 00511 00512 case SPAWN_POINT: 00513 spawn_point(op); 00514 return; 00515 00516 case BLINDNESS: 00517 remove_blindness(op); 00518 return; 00519 00520 case CONFUSION: 00521 remove_confusion(op); 00522 return; 00523 00524 case POISONING: 00525 poison_more(op); 00526 return; 00527 00528 case DISEASE: 00529 move_disease(op); 00530 return; 00531 00532 case SYMPTOM: 00533 move_symptom(op); 00534 return; 00535 00536 case WORD_OF_RECALL: 00537 execute_wor(op); 00538 return; 00539 00540 case BULLET: 00541 move_fired_arch(op); 00542 return; 00543 00544 case THROWN_OBJ: 00545 case ARROW: 00546 case POTION: 00547 move_arrow(op); 00548 return; 00549 00550 /* It now moves twice as fast */ 00551 case LIGHTNING: 00552 move_bolt(op); 00553 return; 00554 00555 case CONE: 00556 move_cone(op); 00557 return; 00558 00559 /* Handle autoclosing */ 00560 case DOOR: 00561 close_locked_door(op); 00562 return; 00563 00564 case TELEPORTER: 00565 move_teleporter(op); 00566 return; 00567 00568 case BOMB: 00569 animate_bomb(op); 00570 return; 00571 00572 case FIREWALL: 00573 move_firewall(op); 00574 return; 00575 00576 case MOOD_FLOOR: 00577 do_mood_floor(op); 00578 return; 00579 00580 case GATE: 00581 move_gate(op); 00582 return; 00583 00584 case TIMED_GATE: 00585 move_timed_gate(op); 00586 return; 00587 00588 case TRIGGER: 00589 case TRIGGER_BUTTON: 00590 case TRIGGER_PEDESTAL: 00591 case TRIGGER_ALTAR: 00592 animate_trigger(op); 00593 return; 00594 00595 case DETECTOR: 00596 move_detector(op); 00597 return; 00598 00599 case PIT: 00600 move_pit(op); 00601 return; 00602 00603 case DEEP_SWAMP: 00604 move_deep_swamp(op); 00605 return; 00606 00607 case SWARM_SPELL: 00608 move_swarm_spell(op); 00609 return; 00610 00611 case PLAYERMOVER: 00612 move_player_mover(op); 00613 return; 00614 00615 case CREATOR: 00616 move_creator(op); 00617 return; 00618 00619 case MARKER: 00620 move_marker(op); 00621 return; 00622 } 00623 }
1.7.4