/*      $NetBSD: hack.potion.c,v 1.9 2011/05/23 22:53:25 joerg Exp $    */

/*
* Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
* Amsterdam
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Stichting Centrum voor Wiskunde en
* Informatica, nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
* Copyright (c) 1982 Jay Fenlason <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
*    derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: hack.potion.c,v 1.9 2011/05/23 22:53:25 joerg Exp $");
#endif                          /* not lint */

#include "hack.h"
#include "extern.h"

static void ghost_from_bottle(void);

int
dodrink(void)
{
       struct obj     *otmp, *objs;
       struct monst   *mtmp;
       int             unkn = 0, nothing = 0;

       otmp = getobj("!", "drink");
       if (!otmp)
               return (0);
       if (!strcmp(objects[otmp->otyp].oc_descr, "smoky") && !rn2(13)) {
               ghost_from_bottle();
               goto use_it;
       }
       switch (otmp->otyp) {
       case POT_RESTORE_STRENGTH:
               unkn++;
               pline("Wow!  This makes you feel great!");
               if (u.ustr < u.ustrmax) {
                       u.ustr = u.ustrmax;
                       flags.botl = 1;
               }
               break;
       case POT_BOOZE:
               unkn++;
               pline("Ooph!  This tastes like liquid fire!");
               Confusion += d(3, 8);
               /* the whiskey makes us feel better */
               if (u.uhp < u.uhpmax)
                       losehp(-1, "bottle of whiskey");
               if (!rn2(4)) {
                       pline("You pass out.");
                       multi = -rnd(15);
                       nomovemsg = "You awake with a headache.";
               }
               break;
       case POT_INVISIBILITY:
               if (Invis || See_invisible)
                       nothing++;
               else {
                       if (!Blind)
                               pline("Gee!  All of a sudden, you can't see yourself.");
                       else
                               pline("You feel rather airy."), unkn++;
                       newsym(u.ux, u.uy);
               }
               Invis += rn1(15, 31);
               break;
       case POT_FRUIT_JUICE:
               pline("This tastes like fruit juice.");
               lesshungry(20);
               break;
       case POT_HEALING:
               pline("You begin to feel better.");
               flags.botl = 1;
               u.uhp += rnd(10);
               if (u.uhp > u.uhpmax)
                       u.uhp = ++u.uhpmax;
               if (Blind)
                       Blind = 1;      /* see on next move */
               if (Sick)
                       Sick = 0;
               break;
       case POT_PARALYSIS:
               if (Levitation)
                       pline("You are motionlessly suspended.");
               else
                       pline("Your feet are frozen to the floor!");
               nomul(-(rn1(10, 25)));
               break;
       case POT_MONSTER_DETECTION:
               if (!fmon) {
                       strange_feeling(otmp, "You feel threatened.");
                       return (1);
               } else {
                       cls();
                       for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
                               if (mtmp->mx > 0)
                                       at(mtmp->mx, mtmp->my, mtmp->data->mlet);
                       prme();
                       pline("You sense the presence of monsters.");
                       more();
                       docrt();
               }
               break;
       case POT_OBJECT_DETECTION:
               if (!fobj) {
                       strange_feeling(otmp, "You feel a pull downward.");
                       return (1);
               } else {
                       for (objs = fobj; objs; objs = objs->nobj)
                               if (objs->ox != u.ux || objs->oy != u.uy)
                                       goto outobjmap;
                       pline("You sense the presence of objects close nearby.");
                       break;
       outobjmap:
                       cls();
                       for (objs = fobj; objs; objs = objs->nobj)
                               at(objs->ox, objs->oy, objs->olet);
                       prme();
                       pline("You sense the presence of objects.");
                       more();
                       docrt();
               }
               break;
       case POT_SICKNESS:
               pline("Yech! This stuff tastes like poison.");
               if (Poison_resistance)
                       pline("(But in fact it was biologically contaminated orange juice.)");
               losestr(rn1(4, 3));
               losehp(rnd(10), "contaminated potion");
               break;
       case POT_CONFUSION:
               if (!Confusion)
                       pline("Huh, What?  Where am I?");
               else
                       nothing++;
               Confusion += rn1(7, 16);
               break;
       case POT_GAIN_STRENGTH:
               pline("Wow do you feel strong!");
               if (u.ustr >= 118)
                       break;  /* > 118 is impossible */
               if (u.ustr > 17)
                       u.ustr += rnd(118 - u.ustr);
               else
                       u.ustr++;
               if (u.ustr > u.ustrmax)
                       u.ustrmax = u.ustr;
               flags.botl = 1;
               break;
       case POT_SPEED:
               if (Wounded_legs) {
                       heal_legs();
                       unkn++;
                       break;
               }
               if (!(Fast & ~INTRINSIC))
                       pline("You are suddenly moving much faster.");
               else
                       pline("Your legs get new energy."), unkn++;
               Fast += rn1(10, 100);
               break;
       case POT_BLINDNESS:
               if (!Blind)
                       pline("A cloud of darkness falls upon you.");
               else
                       nothing++;
               Blind += rn1(100, 250);
               seeoff(0);
               break;
       case POT_GAIN_LEVEL:
               pluslvl();
               break;
       case POT_EXTRA_HEALING:
               pline("You feel much better.");
               flags.botl = 1;
               u.uhp += d(2, 20) + 1;
               if (u.uhp > u.uhpmax)
                       u.uhp = (u.uhpmax += 2);
               if (Blind)
                       Blind = 1;
               if (Sick)
                       Sick = 0;
               break;
       case POT_LEVITATION:
               if (!Levitation)
                       float_up();
               else
                       nothing++;
               Levitation += rnd(100);
               u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down;
               break;
       default:
               impossible("What a funny potion! (%u)", otmp->otyp);
               return (0);
       }
       if (nothing) {
               unkn++;
               pline("You have a peculiar feeling for a moment, then it passes.");
       }
       if (otmp->dknown && !objects[otmp->otyp].oc_name_known) {
               if (!unkn) {
                       objects[otmp->otyp].oc_name_known = 1;
                       more_experienced(0, 10);
               } else if (!objects[otmp->otyp].oc_uname)
                       docall(otmp);
       }
use_it:
       useup(otmp);
       return (1);
}

void
pluslvl(void)
{
       int num;

       pline("You feel more experienced.");
       num = rnd(10);
       u.uhpmax += num;
       u.uhp += num;
       if (u.ulevel < 14) {
               u.uexp = newuexp() + 1;
               pline("Welcome to experience level %u.", ++u.ulevel);
       }
       flags.botl = 1;
}

void
strange_feeling(struct obj *obj, const char *txt)
{
       if (flags.beginner)
               pline("You have a strange feeling for a moment, then it passes.");
       else
               pline("%s", txt);
       if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
               docall(obj);
       useup(obj);
}

static const char *const bottlenames[] = {
       "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial"
};

void
potionhit(struct monst *mon, struct obj *obj)
{
       const char           *botlnam = bottlenames[rn2(SIZE(bottlenames))];
       boolean         uclose, isyou = (mon == &youmonst);

       if (isyou) {
               uclose = TRUE;
               pline("The %s crashes on your head and breaks into shivers.",
                     botlnam);
               losehp(rnd(2), "thrown potion");
       } else {
               uclose = (dist(mon->mx, mon->my) < 3);
               /* perhaps 'E' and 'a' have no head? */
               pline("The %s crashes on %s's head and breaks into shivers.",
                     botlnam, monnam(mon));
               if (rn2(5) && mon->mhp > 1)
                       mon->mhp--;
       }
       pline("The %s evaporates.", xname(obj));

       if (!isyou && !rn2(3))
               switch (obj->otyp) {

               case POT_RESTORE_STRENGTH:
               case POT_GAIN_STRENGTH:
               case POT_HEALING:
               case POT_EXTRA_HEALING:
                       if (mon->mhp < mon->mhpmax) {
                               mon->mhp = mon->mhpmax;
                               pline("%s looks sound and hale again!", Monnam(mon));
                       }
                       break;
               case POT_SICKNESS:
                       if (mon->mhpmax > 3)
                               mon->mhpmax /= 2;
                       if (mon->mhp > 2)
                               mon->mhp /= 2;
                       break;
               case POT_CONFUSION:
               case POT_BOOZE:
                       mon->mconf = 1;
                       break;
               case POT_INVISIBILITY:
                       unpmon(mon);
                       mon->minvis = 1;
                       pmon(mon);
                       break;
               case POT_PARALYSIS:
                       mon->mfroz = 1;
                       break;
               case POT_SPEED:
                       mon->mspeed = MFAST;
                       break;
               case POT_BLINDNESS:
                       mon->mblinded |= 64 + rn2(64);
                       break;
                       /*
                        * case POT_GAIN_LEVEL: case POT_LEVITATION: case
                        * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case
                        * POT_OBJECT_DETECTION: break;
                        */
               }
       if (uclose && rn2(5))
               potionbreathe(obj);
       obfree(obj, Null(obj));
}

void
potionbreathe(struct obj *obj)
{
       switch (obj->otyp) {
       case POT_RESTORE_STRENGTH:
       case POT_GAIN_STRENGTH:
               if (u.ustr < u.ustrmax)
                       u.ustr++, flags.botl = 1;
               break;
       case POT_HEALING:
       case POT_EXTRA_HEALING:
               if (u.uhp < u.uhpmax)
                       u.uhp++, flags.botl = 1;
               break;
       case POT_SICKNESS:
               if (u.uhp <= 5)
                       u.uhp = 1;
               else
                       u.uhp -= 5;
               flags.botl = 1;
               break;
       case POT_CONFUSION:
       case POT_BOOZE:
               if (!Confusion)
                       pline("You feel somewhat dizzy.");
               Confusion += rnd(5);
               break;
       case POT_INVISIBILITY:
               pline("For an instant you couldn't see your right hand.");
               break;
       case POT_PARALYSIS:
               pline("Something seems to be holding you.");
               nomul(-rnd(5));
               break;
       case POT_SPEED:
               Fast += rnd(5);
               pline("Your knees seem more flexible now.");
               break;
       case POT_BLINDNESS:
               if (!Blind)
                       pline("It suddenly gets dark.");
               Blind += rnd(5);
               seeoff(0);
               break;
               /*
                * case POT_GAIN_LEVEL: case POT_LEVITATION: case
                * POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case
                * POT_OBJECT_DETECTION: break;
                */
       }
       /* note: no obfree() */
}

/*
* -- rudimentary -- to do this correctly requires much more work
* -- all sharp weapons get one or more qualities derived from the potions
* -- texts on scrolls may be (partially) wiped out; do they become blank?
* --   or does their effect change, like under Confusion?
* -- all objects may be made invisible by POT_INVISIBILITY
* -- If the flask is small, can one dip a large object? Does it magically
* --   become a jug? Etc.
*/
int
dodip(void)
{
       struct obj     *potion, *obj;

       if (!(obj = getobj("#", "dip")))
               return (0);
       if (!(potion = getobj("!", "dip into")))
               return (0);
       pline("Interesting...");
       if (obj->otyp == ARROW || obj->otyp == DART ||
           obj->otyp == CROSSBOW_BOLT) {
               if (potion->otyp == POT_SICKNESS) {
                       useup(potion);
                       if (obj->spe < 7)
                               obj->spe++;     /* %% */
               }
       }
       return (1);
}

static void
ghost_from_bottle(void)
{
       struct monst   *mtmp;

       if (!(mtmp = makemon(PM_GHOST, u.ux, u.uy))) {
               pline("This bottle turns out to be empty.");
               return;
       }
       mnexto(mtmp);
       pline("As you open the bottle, an enormous ghost emerges!");
       pline("You are frightened to death, and unable to move.");
       nomul(-3);
}