/*      $NetBSD: hack.do_name.c,v 1.13 2011/08/07 06:03:45 dholland 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.do_name.c,v 1.13 2011/08/07 06:03:45 dholland Exp $");
#endif                          /* not lint */

#include <stdlib.h>
#include "hack.h"
#include "extern.h"

static void do_oname(struct obj *);
static char *xmonnam(struct monst *, int);
static char *lmonnam(struct monst *);
static char *visctrl(int);

coord
getpos(int force, const char *goal)
{
       int             cx, cy, i, c;
       coord           cc;
       pline("(For instructions type a ?)");
       cx = u.ux;
       cy = u.uy;
       curs(cx, cy + 2);
       while ((c = readchar()) != '.') {
               for (i = 0; i < 8; i++)
                       if (sdir[i] == c) {
                               if (1 <= cx + xdir[i] && cx + xdir[i] <= COLNO)
                                       cx += xdir[i];
                               if (0 <= cy + ydir[i] && cy + ydir[i] <= ROWNO - 1)
                                       cy += ydir[i];
                               goto nxtc;
                       }
               if (c == '?') {
                       pline("Use [hjkl] to move the cursor to %s.", goal);
                       pline("Type a . when you are at the right place.");
               } else {
                       pline("Unknown direction: '%s' (%s).",
                             visctrl(c),
                             force ? "use hjkl or ." : "aborted");
                       if (force)
                               goto nxtc;
                       cc.x = -1;
                       cc.y = 0;
                       return (cc);
               }
nxtc:           ;
               curs(cx, cy + 2);
       }
       cc.x = cx;
       cc.y = cy;
       return (cc);
}

int
do_mname(void)
{
       char            buf[BUFSZ];
       coord           cc;
       int             cx, cy;
       size_t lth;
       unsigned        i;
       struct monst   *mtmp, *mtmp2;
       cc = getpos(0, "the monster you want to name");
       cx = cc.x;
       cy = cc.y;
       if (cx < 0)
               return (0);
       mtmp = m_at(cx, cy);
       if (!mtmp) {
               if (cx == u.ux && cy == u.uy)
                       pline("This ugly monster is called %s and cannot be renamed.",
                             plname);
               else
                       pline("There is no monster there.");
               return (1);
       }
       if (mtmp->mimic) {
               pline("I see no monster there.");
               return (1);
       }
       if (!cansee(cx, cy)) {
               pline("I cannot see a monster there.");
               return (1);
       }
       pline("What do you want to call %s? ", lmonnam(mtmp));
       getlin(buf);
       clrlin();
       if (!*buf || *buf == '\033')
               return (1);
       lth = strlen(buf) + 1;
       if (lth > 63) {
               buf[62] = 0;
               lth = 63;
       }
       mtmp2 = newmonst(mtmp->mxlth + lth);
       *mtmp2 = *mtmp;
       for (i = 0; i < mtmp->mxlth; i++)
               ((char *) mtmp2->mextra)[i] = ((char *) mtmp->mextra)[i];
       mtmp2->mnamelth = lth;
       (void) strcpy(NAME(mtmp2), buf);
       replmon(mtmp, mtmp2);
       return (1);
}

/*
* This routine changes the address of  obj . Be careful not to call it
* when there might be pointers around in unknown places. For now: only
* when  obj  is in the inventory.
*/
static void
do_oname(struct obj *obj)
{
       struct obj     *otmp, *otmp2;
       size_t lth;
       char            buf[BUFSZ];
       pline("What do you want to name %s? ", doname(obj));
       getlin(buf);
       clrlin();
       if (!*buf || *buf == '\033')
               return;
       lth = strlen(buf) + 1;
       if (lth > 63) {
               buf[62] = 0;
               lth = 63;
       }
       otmp2 = newobj(lth);
       *otmp2 = *obj;
       otmp2->onamelth = lth;
       (void) strcpy(ONAME(otmp2), buf);

       setworn((struct obj *) 0, obj->owornmask);
       setworn(otmp2, otmp2->owornmask);

       /*
        * do freeinv(obj); etc. by hand in order to preserve the position of
        * this object in the inventory
        */
       if (obj == invent)
               invent = otmp2;
       else
               for (otmp = invent;; otmp = otmp->nobj) {
                       if (!otmp)
                               panic("Do_oname: cannot find obj.");
                       if (otmp->nobj == obj) {
                               otmp->nobj = otmp2;
                               break;
                       }
               }
#if 0
       obfree(obj, otmp2);     /* now unnecessary: no pointers on bill */
#endif
       free(obj);      /* let us hope nobody else saved a pointer */
}

int
ddocall(void)
{
       struct obj     *obj;

       pline("Do you want to name an individual object? [ny] ");
       switch (readchar()) {
       case '\033':
               break;
       case 'y':
               obj = getobj("#", "name");
               if (obj)
                       do_oname(obj);
               break;
       default:
               obj = getobj("?!=/", "call");
               if (obj)
                       docall(obj);
       }
       return (0);
}

void
docall(struct obj *obj)
{
       char            buf[BUFSZ];
       struct obj      otemp;
       char          **str1;
       char           *str;

       otemp = *obj;
       otemp.quan = 1;
       otemp.onamelth = 0;
       str = xname(&otemp);
       pline("Call %s %s: ", strchr(vowels, *str) ? "an" : "a", str);
       getlin(buf);
       clrlin();
       if (!*buf || *buf == '\033')
               return;
       str = newstring(strlen(buf) + 1);
       (void) strcpy(str, buf);
       str1 = &(objects[obj->otyp].oc_uname);
       if (*str1)
               free(*str1);
       *str1 = str;
}

static const char *const ghostnames[] = {
       /* these names should have length < PL_NSIZ */
       "adri", "andries", "andreas", "bert", "david", "dirk", "emile",
       "frans", "fred", "greg", "hether", "jay", "john", "jon", "kay",
       "kenny", "maud", "michiel", "mike", "peter", "robert", "ron",
       "tom", "wilmar"
};

static char *
xmonnam(struct monst *mtmp, int vb)
{
       static char     buf[BUFSZ];     /* %% */
       if (mtmp->mnamelth && !vb) {
               (void) strlcpy(buf, NAME(mtmp), sizeof(buf));
               return (buf);
       }
       switch (mtmp->data->mlet) {
       case ' ':
               {
                       const char           *gn = (char *) mtmp->mextra;
                       if (!*gn) {     /* might also look in scorefile */
                               gn = ghostnames[rn2(SIZE(ghostnames))];
                               if (!rn2(2))
                                       (void)
                                               strlcpy((char *) mtmp->mextra, !rn2(5) ? plname : gn, mtmp->mxlth);
                       }
                       (void) snprintf(buf, sizeof(buf), "%s's ghost", gn);
               }
               break;
       case '@':
               if (mtmp->isshk) {
                       (void) strlcpy(buf, shkname(mtmp), sizeof(buf));
                       break;
               }
               /* FALLTHROUGH */
       default:
               (void) snprintf(buf, sizeof(buf), "the %s%s",
                              mtmp->minvis ? "invisible " : "",
                              mtmp->data->mname);
       }
       if (vb && mtmp->mnamelth) {
               (void) strlcat(buf, " called ", sizeof(buf));
               (void) strlcat(buf, NAME(mtmp), sizeof(buf));
       }
       return (buf);
}

static char *
lmonnam(struct monst *mtmp)
{
       return (xmonnam(mtmp, 1));
}

char           *
monnam(struct monst *mtmp)
{
       return (xmonnam(mtmp, 0));
}

char           *
Monnam(struct monst *mtmp)
{
       char           *bp = monnam(mtmp);
       if ('a' <= *bp && *bp <= 'z')
               *bp += ('A' - 'a');
       return (bp);
}

char           *
amonnam(struct monst *mtmp, const char *adj)
{
       char           *bp = monnam(mtmp);
       static char     buf[BUFSZ];     /* %% */

       if (!strncmp(bp, "the ", 4))
               bp += 4;
       (void) snprintf(buf, sizeof(buf), "the %s %s", adj, bp);
       return (buf);
}

char           *
Amonnam(struct monst *mtmp, const char *adj)
{
       char           *bp = amonnam(mtmp, adj);

       *bp = 'T';
       return (bp);
}

char           *
Xmonnam(struct monst *mtmp)
{
       char           *bp = Monnam(mtmp);
       if (!strncmp(bp, "The ", 4)) {
               bp += 2;
               *bp = 'A';
       }
       return (bp);
}

static char *
visctrl(int c)
{
       static char     ccc[3];
       if (c < 040) {
               ccc[0] = '^';
               ccc[1] = c + 0100;
               ccc[2] = 0;
       } else {
               ccc[0] = c;
               ccc[1] = 0;
       }
       return (ccc);
}