root/games/hack/hack.do_name.c
/*      $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 <hack@gnu.org>
 * 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);
}