1 /*        $NetBSD: hack.do_name.c,v 1.13 2011/08/07 06:03:45 dholland Exp $     */
2 
3 /*
4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5  * Amsterdam
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * - Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * - Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * - Neither the name of the Stichting Centrum voor Wiskunde en
20  * Informatica, nor the names of its contributors may be used to endorse or
21  * promote products derived from this software without specific prior
22  * written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.do_name.c,v 1.13 2011/08/07 06:03:45 dholland Exp $");
67 #endif                                  /* not lint */
68 
69 #include <stdlib.h>
70 #include "hack.h"
71 #include "extern.h"
72 
73 static void do_oname(struct obj *);
74 static char *xmonnam(struct monst *, int);
75 static char *lmonnam(struct monst *);
76 static char *visctrl(int);
77 
78 coord
getpos(int force,const char * goal)79 getpos(int force, const char *goal)
80 {
81           int             cx, cy, i, c;
82           coord           cc;
83           pline("(For instructions type a ?)");
84           cx = u.ux;
85           cy = u.uy;
86           curs(cx, cy + 2);
87           while ((c = readchar()) != '.') {
88                     for (i = 0; i < 8; i++)
89                               if (sdir[i] == c) {
90                                         if (1 <= cx + xdir[i] && cx + xdir[i] <= COLNO)
91                                                   cx += xdir[i];
92                                         if (0 <= cy + ydir[i] && cy + ydir[i] <= ROWNO - 1)
93                                                   cy += ydir[i];
94                                         goto nxtc;
95                               }
96                     if (c == '?') {
97                               pline("Use [hjkl] to move the cursor to %s.", goal);
98                               pline("Type a . when you are at the right place.");
99                     } else {
100                               pline("Unknown direction: '%s' (%s).",
101                                     visctrl(c),
102                                     force ? "use hjkl or ." : "aborted");
103                               if (force)
104                                         goto nxtc;
105                               cc.x = -1;
106                               cc.y = 0;
107                               return (cc);
108                     }
109 nxtc:               ;
110                     curs(cx, cy + 2);
111           }
112           cc.x = cx;
113           cc.y = cy;
114           return (cc);
115 }
116 
117 int
do_mname(void)118 do_mname(void)
119 {
120           char            buf[BUFSZ];
121           coord           cc;
122           int             cx, cy;
123           size_t lth;
124           unsigned        i;
125           struct monst   *mtmp, *mtmp2;
126           cc = getpos(0, "the monster you want to name");
127           cx = cc.x;
128           cy = cc.y;
129           if (cx < 0)
130                     return (0);
131           mtmp = m_at(cx, cy);
132           if (!mtmp) {
133                     if (cx == u.ux && cy == u.uy)
134                               pline("This ugly monster is called %s and cannot be renamed.",
135                                     plname);
136                     else
137                               pline("There is no monster there.");
138                     return (1);
139           }
140           if (mtmp->mimic) {
141                     pline("I see no monster there.");
142                     return (1);
143           }
144           if (!cansee(cx, cy)) {
145                     pline("I cannot see a monster there.");
146                     return (1);
147           }
148           pline("What do you want to call %s? ", lmonnam(mtmp));
149           getlin(buf);
150           clrlin();
151           if (!*buf || *buf == '\033')
152                     return (1);
153           lth = strlen(buf) + 1;
154           if (lth > 63) {
155                     buf[62] = 0;
156                     lth = 63;
157           }
158           mtmp2 = newmonst(mtmp->mxlth + lth);
159           *mtmp2 = *mtmp;
160           for (i = 0; i < mtmp->mxlth; i++)
161                     ((char *) mtmp2->mextra)[i] = ((char *) mtmp->mextra)[i];
162           mtmp2->mnamelth = lth;
163           (void) strcpy(NAME(mtmp2), buf);
164           replmon(mtmp, mtmp2);
165           return (1);
166 }
167 
168 /*
169  * This routine changes the address of  obj . Be careful not to call it
170  * when there might be pointers around in unknown places. For now: only
171  * when  obj  is in the inventory.
172  */
173 static void
do_oname(struct obj * obj)174 do_oname(struct obj *obj)
175 {
176           struct obj     *otmp, *otmp2;
177           size_t lth;
178           char            buf[BUFSZ];
179           pline("What do you want to name %s? ", doname(obj));
180           getlin(buf);
181           clrlin();
182           if (!*buf || *buf == '\033')
183                     return;
184           lth = strlen(buf) + 1;
185           if (lth > 63) {
186                     buf[62] = 0;
187                     lth = 63;
188           }
189           otmp2 = newobj(lth);
190           *otmp2 = *obj;
191           otmp2->onamelth = lth;
192           (void) strcpy(ONAME(otmp2), buf);
193 
194           setworn((struct obj *) 0, obj->owornmask);
195           setworn(otmp2, otmp2->owornmask);
196 
197           /*
198            * do freeinv(obj); etc. by hand in order to preserve the position of
199            * this object in the inventory
200            */
201           if (obj == invent)
202                     invent = otmp2;
203           else
204                     for (otmp = invent;; otmp = otmp->nobj) {
205                               if (!otmp)
206                                         panic("Do_oname: cannot find obj.");
207                               if (otmp->nobj == obj) {
208                                         otmp->nobj = otmp2;
209                                         break;
210                               }
211                     }
212 #if 0
213           obfree(obj, otmp2); /* now unnecessary: no pointers on bill */
214 #endif
215           free(obj);          /* let us hope nobody else saved a pointer */
216 }
217 
218 int
ddocall(void)219 ddocall(void)
220 {
221           struct obj     *obj;
222 
223           pline("Do you want to name an individual object? [ny] ");
224           switch (readchar()) {
225           case '\033':
226                     break;
227           case 'y':
228                     obj = getobj("#", "name");
229                     if (obj)
230                               do_oname(obj);
231                     break;
232           default:
233                     obj = getobj("?!=/", "call");
234                     if (obj)
235                               docall(obj);
236           }
237           return (0);
238 }
239 
240 void
docall(struct obj * obj)241 docall(struct obj *obj)
242 {
243           char            buf[BUFSZ];
244           struct obj      otemp;
245           char          **str1;
246           char           *str;
247 
248           otemp = *obj;
249           otemp.quan = 1;
250           otemp.onamelth = 0;
251           str = xname(&otemp);
252           pline("Call %s %s: ", strchr(vowels, *str) ? "an" : "a", str);
253           getlin(buf);
254           clrlin();
255           if (!*buf || *buf == '\033')
256                     return;
257           str = newstring(strlen(buf) + 1);
258           (void) strcpy(str, buf);
259           str1 = &(objects[obj->otyp].oc_uname);
260           if (*str1)
261                     free(*str1);
262           *str1 = str;
263 }
264 
265 static const char *const ghostnames[] = {
266           /* these names should have length < PL_NSIZ */
267           "adri", "andries", "andreas", "bert", "david", "dirk", "emile",
268           "frans", "fred", "greg", "hether", "jay", "john", "jon", "kay",
269           "kenny", "maud", "michiel", "mike", "peter", "robert", "ron",
270           "tom", "wilmar"
271 };
272 
273 static char *
xmonnam(struct monst * mtmp,int vb)274 xmonnam(struct monst *mtmp, int vb)
275 {
276           static char     buf[BUFSZ];   /* %% */
277           if (mtmp->mnamelth && !vb) {
278                     (void) strlcpy(buf, NAME(mtmp), sizeof(buf));
279                     return (buf);
280           }
281           switch (mtmp->data->mlet) {
282           case ' ':
283                     {
284                               const char           *gn = (char *) mtmp->mextra;
285                               if (!*gn) {         /* might also look in scorefile */
286                                         gn = ghostnames[rn2(SIZE(ghostnames))];
287                                         if (!rn2(2))
288                                                   (void)
289                                                             strlcpy((char *) mtmp->mextra, !rn2(5) ? plname : gn, mtmp->mxlth);
290                               }
291                               (void) snprintf(buf, sizeof(buf), "%s's ghost", gn);
292                     }
293                     break;
294           case '@':
295                     if (mtmp->isshk) {
296                               (void) strlcpy(buf, shkname(mtmp), sizeof(buf));
297                               break;
298                     }
299                     /* FALLTHROUGH */
300           default:
301                     (void) snprintf(buf, sizeof(buf), "the %s%s",
302                                      mtmp->minvis ? "invisible " : "",
303                                      mtmp->data->mname);
304           }
305           if (vb && mtmp->mnamelth) {
306                     (void) strlcat(buf, " called ", sizeof(buf));
307                     (void) strlcat(buf, NAME(mtmp), sizeof(buf));
308           }
309           return (buf);
310 }
311 
312 static char *
lmonnam(struct monst * mtmp)313 lmonnam(struct monst *mtmp)
314 {
315           return (xmonnam(mtmp, 1));
316 }
317 
318 char           *
monnam(struct monst * mtmp)319 monnam(struct monst *mtmp)
320 {
321           return (xmonnam(mtmp, 0));
322 }
323 
324 char           *
Monnam(struct monst * mtmp)325 Monnam(struct monst *mtmp)
326 {
327           char           *bp = monnam(mtmp);
328           if ('a' <= *bp && *bp <= 'z')
329                     *bp += ('A' - 'a');
330           return (bp);
331 }
332 
333 char           *
amonnam(struct monst * mtmp,const char * adj)334 amonnam(struct monst *mtmp, const char *adj)
335 {
336           char           *bp = monnam(mtmp);
337           static char     buf[BUFSZ];   /* %% */
338 
339           if (!strncmp(bp, "the ", 4))
340                     bp += 4;
341           (void) snprintf(buf, sizeof(buf), "the %s %s", adj, bp);
342           return (buf);
343 }
344 
345 char           *
Amonnam(struct monst * mtmp,const char * adj)346 Amonnam(struct monst *mtmp, const char *adj)
347 {
348           char           *bp = amonnam(mtmp, adj);
349 
350           *bp = 'T';
351           return (bp);
352 }
353 
354 char           *
Xmonnam(struct monst * mtmp)355 Xmonnam(struct monst *mtmp)
356 {
357           char           *bp = Monnam(mtmp);
358           if (!strncmp(bp, "The ", 4)) {
359                     bp += 2;
360                     *bp = 'A';
361           }
362           return (bp);
363 }
364 
365 static char *
visctrl(int c)366 visctrl(int c)
367 {
368           static char     ccc[3];
369           if (c < 040) {
370                     ccc[0] = '^';
371                     ccc[1] = c + 0100;
372                     ccc[2] = 0;
373           } else {
374                     ccc[0] = c;
375                     ccc[1] = 0;
376           }
377           return (ccc);
378 }
379