Atrinik Server 2.5
server/object_process.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 
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 }