Atrinik Server 2.5
types/light.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 
00042 void apply_player_light_refill(object *who, object *op)
00043 {
00044     object *item = find_marked_object(who);
00045     int tmp;
00046 
00047     if (!item)
00048     {
00049         new_draw_info_format(0, COLOR_WHITE, who, "You need to mark a light source you want refill.");
00050         return;
00051     }
00052 
00053     if (item->type != LIGHT_APPLY || !item->race || !strstr(item->race, op->race))
00054     {
00055         new_draw_info_format(0, COLOR_WHITE, who, "You can't refill the %s with the %s.", query_name(item, NULL), query_name(op, NULL));
00056         return;
00057     }
00058 
00059     tmp = (int) item->stats.maxhp - item->stats.food;
00060 
00061     if (!tmp)
00062     {
00063         new_draw_info_format(0, COLOR_WHITE, who, "The %s is full and can't be refilled.", query_name(item, NULL));
00064         return;
00065     }
00066 
00067     if (op->stats.food <= tmp)
00068     {
00069         item->stats.food += op->stats.food;
00070         new_draw_info_format(0, COLOR_WHITE, who, "You refill the %s with %d units of %s.", query_name(item, NULL), op->stats.food, query_name(op, NULL));
00071         decrease_ob(op);
00072     }
00073     else
00074     {
00075         object *filler = op;
00076 
00077         if (filler->nrof > 1)
00078         {
00079             filler = get_split_ob(filler, 1, NULL, 0);
00080             filler->stats.food -= tmp;
00081             insert_ob_in_ob(filler, who);
00082 
00083             if (QUERY_FLAG(op, FLAG_REMOVED))
00084             {
00085                 esrv_del_item(CONTR(who), op->count, op->env);
00086             }
00087             else
00088             {
00089                 esrv_send_item(who, op);
00090             }
00091         }
00092         else
00093         {
00094             filler->stats.food -= tmp;
00095         }
00096 
00097         item->stats.food += tmp;
00098         new_draw_info_format(0, COLOR_WHITE, who, "You refill the %s with %d units of %s.", query_name(item, NULL), tmp, query_name(filler, NULL));
00099         esrv_send_item(who, filler);
00100     }
00101 
00102     esrv_send_item(who, item);
00103     fix_player(who);
00104 }
00105 
00110 void apply_player_light(object *who, object *op)
00111 {
00112     object *tmp;
00113 
00114     if (QUERY_FLAG(op, FLAG_APPLIED))
00115     {
00116         if ((QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)))
00117         {
00118             new_draw_info_format(0, COLOR_WHITE, who, "No matter how hard you try, you just can't remove it!");
00119             return;
00120         }
00121 
00122         if (QUERY_FLAG(op, FLAG_PERM_CURSED))
00123         {
00124             SET_FLAG(op, FLAG_CURSED);
00125         }
00126 
00127         if (QUERY_FLAG(op, FLAG_PERM_DAMNED))
00128         {
00129             SET_FLAG(op, FLAG_DAMNED);
00130         }
00131 
00132         new_draw_info_format(0, COLOR_WHITE, who, "You extinguish the %s.", query_name(op, NULL));
00133 
00134         if (!op->env && op->glow_radius)
00135         {
00136             adjust_light_source(op->map, op->x, op->y, -(op->glow_radius));
00137         }
00138 
00139         op->glow_radius = 0;
00140         CLEAR_FLAG(op, FLAG_APPLIED);
00141         CLEAR_FLAG(op, FLAG_CHANGING);
00142 
00143         if (op->other_arch && op->other_arch->clone.sub_type & 1)
00144         {
00145             op->animation_id = op->other_arch->clone.animation_id;
00146             SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction);
00147         }
00148         else
00149         {
00150             CLEAR_FLAG(op, FLAG_ANIMATE);
00151             op->face = op->arch->clone.face;
00152         }
00153 
00154         update_object(who, UP_OBJ_FACE);
00155         fix_player(who);
00156     }
00157     else
00158     {
00159         /* now the tricky thing: with the first apply cmd, we enlight the light source.
00160          * with the second, we apply it. if we unapply a light source, we always extinguish
00161          * them implicit. */
00162 
00163         /* LIGHT_APPLY light sources with last_sp (aka glow_radius) 0 are useless -
00164          * for example burnt out torches. The burnt out lights are still from same type
00165          * because they are perhaps applied from the player as they burnt out
00166          * and we don't want a player applying an illegal item. */
00167         if (!op->last_sp)
00168         {
00169             new_draw_info_format(0, COLOR_WHITE, who, "The %s can't be lit.", query_name(op, NULL));
00170             return;
00171         }
00172 
00173         /* if glow_radius == 0, we have a extinguish light source.
00174          * before we can put it in the hand to use it, we have to turn
00175          * the light on. */
00176         if (!op->glow_radius)
00177         {
00178             object *op_old;
00179             /* to delay insertion of object - or it simple re-merge! */
00180             int tricky_flag = 0;
00181 
00182             /* we have a non permanent source */
00183             if (op->last_eat)
00184             {
00185             /* if not permanent, this is "filled" counter */
00186                 if (!op->stats.food)
00187                 {
00188                     /* no food charges, we can't light it up.
00189                      * Note that light sources with other_arch set are
00190                      * non rechargeable lights - like torches. */
00191                     new_draw_info_format(0, COLOR_WHITE, who, "You must first refill or recharge the %s.", query_name(op, NULL));
00192                     return;
00193                 }
00194             }
00195 
00196             /* now we have a filled or permanent, extinguish light source
00197              * lets light it - BUT we still have light_radius not active
00198              * when we not drop or apply the source. */
00199 
00200             /* the old split code has some side effects -
00201              * i force now first a split of #1 per hand */
00202             op_old = op;
00203 
00204             if (op->nrof > 1)
00205             {
00206                 object *one = get_object();
00207                 copy_object(op, one, 0);
00208                 op->nrof -= 1;
00209                 one->nrof = 1;
00210 
00211                 if (op->env && (op->env->type == PLAYER || op->env->type == CONTAINER))
00212                 {
00213                     esrv_update_item(UPD_NROF, op->env, op);
00214                 }
00215                 else if (!op->env)
00216                 {
00217                     update_object(op, UP_OBJ_FACE);
00218                 }
00219 
00220                 tricky_flag = 1;
00221                 op = one;
00222             }
00223 
00224             /* light is applied in player inventory - so we
00225              * start the 3 apply chain - because it can be taken
00226              * in hand. */
00227             if (op_old->env && op_old->env->type == PLAYER)
00228             {
00229                 new_draw_info_format(0, COLOR_WHITE, who, "You prepare %s to light.", query_name(op, NULL));
00230 
00231                 /* we have a non permanent source */
00232                 if (op->last_eat)
00233                 {
00234                     SET_FLAG(op, FLAG_CHANGING);
00235                 }
00236 
00237                 if (op->speed)
00238                 {
00239                     SET_FLAG(op, FLAG_ANIMATE);
00240                     /* be sure to get the right anim */
00241                     op->animation_id = op->arch->clone.animation_id;
00242                     SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction);
00243                 }
00244 
00245                 if (tricky_flag)
00246                 {
00247                     op = insert_ob_in_ob(op, op_old->env);
00248                 }
00249 
00250                 op->glow_radius = (sint8) op->last_sp;
00251                 fix_player(who);
00252             }
00253             /* we are not in a player inventory - so simple turn it on */
00254             else
00255             {
00256                 new_draw_info_format(0, COLOR_WHITE, who, "You light the %s.", query_name(op, NULL));
00257 
00258                 /* we have a non permanent source */
00259                 if (op->last_eat)
00260                 {
00261                     SET_FLAG(op, FLAG_CHANGING);
00262                 }
00263 
00264                 if (op->speed)
00265                 {
00266                     SET_FLAG(op, FLAG_ANIMATE);
00267                     op->animation_id = op->arch->clone.animation_id;
00268                     SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction);
00269                 }
00270 
00271                 if (QUERY_FLAG(op, FLAG_PERM_CURSED))
00272                 {
00273                     SET_FLAG(op, FLAG_CURSED);
00274                 }
00275 
00276                 if (QUERY_FLAG(op, FLAG_PERM_DAMNED))
00277                 {
00278                     SET_FLAG(op, FLAG_DAMNED);
00279                 }
00280 
00281                 if (tricky_flag)
00282                 {
00283                     if (!op_old->env)
00284                     {
00285                         /* the item WAS before this on this spot - we only turn it on but we don't moved it */
00286                         insert_ob_in_map(op, op_old->map, op_old, INS_NO_WALK_ON);
00287                     }
00288                     else
00289                     {
00290                         op = insert_ob_in_ob(op, op_old->env);
00291                     }
00292                 }
00293 
00294                 op->glow_radius = (sint8) op->last_sp;
00295 
00296                 if (!op->env && op->glow_radius)
00297                 {
00298                     adjust_light_source(op->map, op->x, op->y, op->glow_radius);
00299                 }
00300 
00301                 update_object(op, UP_OBJ_FACE);
00302             }
00303         }
00304         else
00305         {
00306             if (op->env && op->env->type == PLAYER)
00307             {
00308                 /* remove any other applied light source first */
00309                 for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
00310                 {
00311                     if (tmp->type == op->type && QUERY_FLAG(tmp, FLAG_APPLIED) && tmp != op)
00312                     {
00313                         if ((QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)))
00314                         {
00315                             new_draw_info(0, COLOR_WHITE, who, "No matter how hard you try, you just can't remove it!");
00316                             return;
00317                         }
00318 
00319                         if (QUERY_FLAG(tmp, FLAG_PERM_CURSED))
00320                         {
00321                             SET_FLAG(tmp, FLAG_CURSED);
00322                         }
00323 
00324                         if (QUERY_FLAG(tmp, FLAG_PERM_DAMNED))
00325                         {
00326                             SET_FLAG(tmp, FLAG_DAMNED);
00327                         }
00328 
00329                         new_draw_info_format(0, COLOR_WHITE, who, "You extinguish the %s.", query_name(tmp, NULL));
00330 
00331                         /* on map */
00332                         if (!tmp->env && tmp->glow_radius)
00333                         {
00334                             adjust_light_source(tmp->map, tmp->x, tmp->y, -(tmp->glow_radius));
00335                         }
00336 
00337                         tmp->glow_radius = 0;
00338                         CLEAR_FLAG(tmp, FLAG_APPLIED);
00339                         CLEAR_FLAG(tmp, FLAG_CHANGING);
00340 
00341                         if (op->other_arch && op->other_arch->clone.sub_type & 1)
00342                         {
00343                             op->animation_id = op->other_arch->clone.animation_id;
00344                             SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction);
00345                         }
00346                         else
00347                         {
00348                             CLEAR_FLAG(op, FLAG_ANIMATE);
00349                             op->face = op->arch->clone.face;
00350                         }
00351 
00352                         update_object(tmp, UP_OBJ_FACE);
00353                         esrv_send_item(who, tmp);
00354                     }
00355                 }
00356 
00357                 new_draw_info_format(0, COLOR_WHITE, who, "You apply %s as light.", query_name(op, NULL));
00358                 SET_FLAG(op, FLAG_APPLIED);
00359                 fix_player(who);
00360                 update_object(who, UP_OBJ_FACE);
00361             }
00362             /* not part of player inv - turn light off ! */
00363             else
00364             {
00365                 if (QUERY_FLAG(op, FLAG_PERM_CURSED))
00366                 {
00367                     SET_FLAG(op, FLAG_CURSED);
00368                 }
00369 
00370                 if (QUERY_FLAG(op, FLAG_PERM_DAMNED))
00371                 {
00372                     SET_FLAG(op, FLAG_DAMNED);
00373                 }
00374 
00375                 new_draw_info_format(0, COLOR_WHITE, who, "You extinguish the %s.", query_name(op, NULL));
00376 
00377                 /* on map */
00378                 if (!op->env && op->glow_radius)
00379                 {
00380                     adjust_light_source(op->map, op->x, op->y, -(op->glow_radius));
00381                 }
00382 
00383                 op->glow_radius = 0;
00384                 CLEAR_FLAG(op, FLAG_APPLIED);
00385                 CLEAR_FLAG(op, FLAG_CHANGING);
00386 
00387                 if (op->other_arch && op->other_arch->clone.sub_type & 1)
00388                 {
00389                     op->animation_id = op->other_arch->clone.animation_id;
00390                     SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction);
00391                 }
00392                 else
00393                 {
00394                     CLEAR_FLAG(op, FLAG_ANIMATE);
00395                     op->face = op->arch->clone.face;
00396                 }
00397 
00398                 update_object(op, UP_OBJ_FACE);
00399             }
00400         }
00401     }
00402 
00403     if (op->env && (op->env->type == PLAYER || op->env->type == CONTAINER))
00404     {
00405         esrv_send_item(op->env, op);
00406     }
00407 }
00408 
00416 void apply_lighter(object *who, object *lighter)
00417 {
00418     object *item;
00419     tag_t count;
00420     uint32 nrof;
00421     int is_player_env = 0;
00422     char item_name[MAX_BUF];
00423 
00424     item = find_marked_object(who);
00425 
00426     if (item)
00427     {
00428         /* lighter gets used up */
00429         if (lighter->last_eat && lighter->stats.food)
00430         {
00431             /* Split multiple lighters if they're being used up.  Otherwise *
00432              * one charge from each would be used up.  --DAMN       */
00433             if (lighter->nrof > 1)
00434             {
00435                 object *oneLighter = get_object();
00436                 copy_object(lighter, oneLighter, 0);
00437                 lighter->nrof -= 1;
00438                 oneLighter->nrof = 1;
00439                 oneLighter->stats.food--;
00440                 esrv_send_item(who, lighter);
00441                 oneLighter=insert_ob_in_ob(oneLighter, who);
00442                 esrv_send_item(who, oneLighter);
00443             }
00444             else
00445             {
00446                 lighter->stats.food--;
00447             }
00448         }
00449         /* no charges left in lighter */
00450         else if (lighter->last_eat)
00451         {
00452             new_draw_info_format(0, COLOR_WHITE, who, "You attempt to light the %s with a used up %s.", item->name, lighter->name);
00453             return;
00454         }
00455 
00456         /* Perhaps we should split what we are trying to light on fire?
00457          * I can't see many times when you would want to light multiple
00458          * objects at once. */
00459         nrof = item->nrof;
00460         count = item->count;
00461 
00462         /* If the item is destroyed, we don't have a valid pointer to the
00463          * name object, so make a copy so the message we print out makes
00464          * some sense. */
00465         strcpy(item_name, item->name);
00466 
00467         if (who == is_player_inv(item))
00468         {
00469             is_player_env = 1;
00470         }
00471 
00472         /* Change to check count and not freed, since the object pointer
00473          * may have gotten recycled */
00474         if ((nrof != item->nrof ) || (count != item->count))
00475         {
00476             new_draw_info_format(0, COLOR_WHITE, who, "You light the %s with the %s.", item_name, lighter->name);
00477 
00478             if (is_player_env)
00479             {
00480                 fix_player(who);
00481             }
00482         }
00483         else
00484         {
00485             new_draw_info_format(0, COLOR_WHITE, who, "You attempt to light the %s with the %s and fail.", item->name, lighter->name);
00486         }
00487     }
00488     /* nothing to light */
00489     else
00490     {
00491         new_draw_info(0, COLOR_WHITE, who, "You need to mark a lightable object.");
00492     }
00493 }