Crossfire Server, Branch 1.12  R12190
potion.c
Go to the documentation of this file.
00001 /*
00002     CrossFire, A Multiplayer game for X-windows
00003 
00004     Copyright (C) 2007 Mark Wedel & Crossfire Development Team
00005     Copyright (C) 1992 Frank Tore Johansen
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 
00021     The authors can be reached via e-mail at crossfire-devel@real-time.com
00022 */
00026 #include <global.h>
00027 #include <ob_methods.h>
00028 #include <ob_types.h>
00029 #include <sounds.h>
00030 #include <sproto.h>
00031 
00032 static method_ret potion_type_apply(ob_methods *context, object *potion,
00033     object *applier, int aflags);
00034 
00038 void init_type_potion(void) {
00039     register_apply(POTION, potion_type_apply);
00040 }
00041 
00050 static method_ret potion_type_apply(ob_methods *context, object *potion,
00051     object *applier, int aflags) {
00052     int got_one = 0, i;
00053     object *force;
00054 
00055     if (applier->type == PLAYER) {
00056         if (!QUERY_FLAG(potion, FLAG_IDENTIFIED))
00057             identify(potion);
00058     }
00059 
00060     handle_apply_yield(potion);
00061 
00062     /* Potion of restoration - only for players */
00063     if (applier->type == PLAYER && (potion->attacktype&AT_DEPLETE)) {
00064         object *depl;
00065         archetype *at;
00066 
00067         if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
00068             drain_stat(applier);
00069             fix_object(applier);
00070             decrease_ob(potion);
00071             return METHOD_OK;
00072         }
00073 
00074         if ((at = find_archetype(ARCH_DEPLETION)) == NULL) {
00075             LOG(llevError, "Could not find archetype depletion\n");
00076             return METHOD_ERROR;
00077         }
00078 
00079         depl = present_arch_in_ob(at, applier);
00080         if (depl != NULL
00081         && (potion->level != 0 && potion->level >= applier->level)) {
00082             for (i = 0; i < NUM_STATS; i++)
00083                 if (get_attr_value(&depl->stats, i)) {
00084                     draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_ATTRIBUTE, MSG_TYPE_ATTRIBUTE_STAT_GAIN,
00085                         restore_msg[i], NULL);
00086                 }
00087             remove_ob(depl);
00088             free_object(depl);
00089             fix_object(applier);
00090         }
00091         else
00092             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
00093                 "You potion had no effect.", NULL);
00094 
00095         decrease_ob(potion);
00096         return METHOD_OK;
00097     }
00098 
00099     /* improvement potion - only for players */
00100     if (applier->type == PLAYER && potion->attacktype&AT_GODPOWER) {
00101         for (i = 1; i < MIN(11, applier->level); i++) {
00102             if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
00103                 if (applier->contr->levhp[i] != 1) {
00104                     applier->contr->levhp[i] = 1;
00105                     break;
00106                 }
00107                 if (applier->contr->levsp[i] != 1) {
00108                     applier->contr->levsp[i] = 1;
00109                     break;
00110                 }
00111                 if (applier->contr->levgrace[i] != 1) {
00112                     applier->contr->levgrace[i] = 1;
00113                     break;
00114                 }
00115             } else {
00116                 if (applier->contr->levhp[i] < 9) {
00117                     applier->contr->levhp[i] = 9;
00118                     break;
00119                 }
00120                 if (applier->contr->levsp[i] < 6) {
00121                     applier->contr->levsp[i] = 6;
00122                     break;
00123                 }
00124                 if (applier->contr->levgrace[i] < 3) {
00125                     applier->contr->levgrace[i] = 3;
00126                     break;
00127                 }
00128             }
00129         }
00130             /* Just makes checking easier */
00131         if (i < MIN(11, applier->level))
00132             got_one = 1;
00133         if (!QUERY_FLAG(potion, FLAG_CURSED) && !QUERY_FLAG(potion, FLAG_DAMNED)) {
00134             if (got_one) {
00135                 fix_object(applier);
00136                 draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00137                               "The Gods smile upon you and remake you a little more in their image."
00138                               "You feel a little more perfect.", NULL);
00139             } else
00140                 draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
00141                               "The potion had no effect - you are already perfect", NULL);
00142         } else {  /* cursed potion */
00143             if (got_one) {
00144                 fix_object(applier);
00145                 draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED,
00146                               "The Gods are angry and punish you.", NULL);
00147             } else
00148                 draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED,
00149                               "You are fortunate that you are so pathetic.", NULL);
00150         }
00151         decrease_ob(potion);
00152         return METHOD_OK;
00153     }
00154 
00155     /* A potion that casts a spell.  Healing, restore spellpoint
00156      * (power potion) and heroism all fit into this category.
00157      * Given the spell object code, there is no limit to the number
00158      * of spells that potions can be cast, but direction is
00159      * problematic to try and imbue fireball potions for example.
00160      */
00161     if (potion->inv) {
00162         if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
00163             object *fball;
00164 
00165             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED,
00166                 "Yech!  Your lungs are on fire!", NULL);
00167             /* Explodes a fireball centered at player */
00168             fball = create_archetype(EXPLODING_FIREBALL);
00169             fball->dam_modifier = random_roll(1, applier->level, applier, PREFER_LOW)/5+1;
00170             fball->stats.maxhp = random_roll(1, applier->level, applier, PREFER_LOW)/10+2;
00171             fball->x = applier->x;
00172             fball->y = applier->y;
00173             insert_ob_in_map(fball, applier->map, NULL, 0);
00174         } else
00175             cast_spell(applier, potion, applier->facing, potion->inv, NULL);
00176 
00177         decrease_ob(potion);
00178         /* if youre dead, no point in doing this... */
00179         if (!QUERY_FLAG(applier, FLAG_REMOVED))
00180             fix_object(applier);
00181         return METHOD_OK;
00182     }
00183 
00184     /* Deal with protection potions */
00185     force = NULL;
00186     for (i = 0; i < NROFATTACKS; i++) {
00187         if (potion->resist[i]) {
00188             if (!force)
00189                 force = create_archetype(FORCE_NAME);
00190             memcpy(force->resist, potion->resist, sizeof(potion->resist));
00191             force->type = POTION_EFFECT;
00192             break;  /* Only need to find one protection since we cappliery entire batch */
00193         }
00194     }
00195     /* This is a protection potion */
00196     if (force) {
00197         /* cursed items last longer */
00198         if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
00199             force->stats.food *= 10;
00200             for (i = 0; i < NROFATTACKS; i++)
00201                 if (force->resist[i] > 0)
00202                     force->resist[i] = -force->resist[i];  /* prot => vuln */
00203         }
00204         force->speed_left = -1;
00205         force = insert_ob_in_ob(force, applier);
00206         CLEAR_FLAG(potion, FLAG_APPLIED);
00207         SET_FLAG(force, FLAG_APPLIED);
00208         change_abil(applier, force);
00209         decrease_ob(potion);
00210         return METHOD_OK;
00211     }
00212 
00213     /* Only thing left are the stat potions */
00214     if (applier->type == PLAYER) { /* only for players */
00215         if ((QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED))
00216         && potion->value != 0)
00217             CLEAR_FLAG(potion, FLAG_APPLIED);
00218         else
00219             SET_FLAG(potion, FLAG_APPLIED);
00220         if (!change_abil(applier, potion))
00221             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
00222                 "Nothing happened.", NULL);
00223     }
00224 
00225     /* CLEAR_FLAG is so that if the character has other potions
00226      * that were grouped with the one consumed, his
00227      * stat will not be raised by them.  fix_object just clears
00228      * up all the stats.
00229      */
00230     CLEAR_FLAG(potion, FLAG_APPLIED);
00231     fix_object(applier);
00232     decrease_ob(potion);
00233     return METHOD_OK;
00234 }