OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / src / write.c
1 /* NetHack 3.6  write.c $NHDT-Date: 1446078770 2015/10/29 00:32:50 $  $NHDT-Branch: master $:$NHDT-Revision: 1.16 $ */
2 /* NetHack may be freely redistributed.  See license for details. */
3
4 #include "hack.h"
5
6 STATIC_DCL int FDECL(cost, (struct obj *));
7 STATIC_DCL boolean FDECL(label_known, (int, struct obj *));
8 STATIC_DCL char *FDECL(new_book_description, (int, char *));
9
10 /*
11  * returns basecost of a scroll or a spellbook
12  */
13 STATIC_OVL int
14 cost(otmp)
15 register struct obj *otmp;
16 {
17     if (otmp->oclass == SPBOOK_CLASS)
18         return (10 * objects[otmp->otyp].oc_level);
19
20     switch (otmp->otyp) {
21 #ifdef MAIL
22     case SCR_MAIL:
23         return 2;
24 #endif
25     case SCR_LIGHT:
26     case SCR_GOLD_DETECTION:
27     case SCR_FOOD_DETECTION:
28     case SCR_MAGIC_MAPPING:
29     case SCR_AMNESIA:
30     case SCR_FIRE:
31     case SCR_EARTH:
32         return 8;
33     case SCR_DESTROY_ARMOR:
34     case SCR_CREATE_MONSTER:
35     case SCR_PUNISHMENT:
36         return 10;
37     case SCR_CONFUSE_MONSTER:
38         return 12;
39     case SCR_IDENTIFY:
40         return 14;
41     case SCR_ENCHANT_ARMOR:
42     case SCR_REMOVE_CURSE:
43     case SCR_ENCHANT_WEAPON:
44     case SCR_CHARGING:
45         return 16;
46     case SCR_SCARE_MONSTER:
47     case SCR_STINKING_CLOUD:
48     case SCR_TAMING:
49     case SCR_TELEPORTATION:
50         return 20;
51     case SCR_GENOCIDE:
52         return 30;
53     case SCR_BLANK_PAPER:
54     default:
55         impossible("You can't write such a weird scroll!");
56     }
57     return 1000;
58 }
59
60 /* decide whether the hero knowns a particular scroll's label;
61    unfortunately, we can't track things are haven't been added to
62    the discoveries list and aren't present in current inventory,
63    so some scrolls with ought to yield True will end up False */
64 STATIC_OVL boolean
65 label_known(scrolltype, objlist)
66 int scrolltype;
67 struct obj *objlist;
68 {
69     struct obj *otmp;
70
71     /* only scrolls */
72     if (objects[scrolltype].oc_class != SCROLL_CLASS)
73         return FALSE;
74     /* type known implies full discovery; otherwise,
75        user-assigned name implies partial discovery */
76     if (objects[scrolltype].oc_name_known || objects[scrolltype].oc_uname)
77         return TRUE;
78     /* check inventory, including carried containers with known contents */
79     for (otmp = objlist; otmp; otmp = otmp->nobj) {
80         if (otmp->otyp == scrolltype && otmp->dknown)
81             return TRUE;
82         if (Has_contents(otmp) && otmp->cknown
83             && label_known(scrolltype, otmp->cobj))
84             return TRUE;
85     }
86     /* not found */
87     return FALSE;
88 }
89
90 static NEARDATA const char write_on[] = { SCROLL_CLASS, SPBOOK_CLASS, 0 };
91
92 /* write -- applying a magic marker */
93 int
94 dowrite(pen)
95 register struct obj *pen;
96 {
97     register struct obj *paper;
98     char namebuf[BUFSZ], *nm, *bp;
99     register struct obj *new_obj;
100     int basecost, actualcost;
101     int curseval;
102     char qbuf[QBUFSZ];
103     int first, last, i, deferred, deferralchance;
104     boolean by_descr = FALSE;
105     const char *typeword;
106
107     if (nohands(youmonst.data)) {
108         You("need hands to be able to write!");
109         return 0;
110     } else if (Glib) {
111         pline("%s from your %s.", Tobjnam(pen, "slip"),
112               makeplural(body_part(FINGER)));
113         dropx(pen);
114         return 1;
115     }
116
117     /* get paper to write on */
118     paper = getobj(write_on, "write on");
119     if (!paper)
120         return 0;
121     /* can't write on a novel (unless/until it's been converted into a blank
122        spellbook), but we want messages saying so to avoid "spellbook" */
123     typeword = (paper->otyp == SPE_NOVEL)
124                   ? "book"
125                   : (paper->oclass == SPBOOK_CLASS)
126                      ? "spellbook"
127                      : "scroll";
128     if (Blind) {
129         if (!paper->dknown) {
130             You("don't know if that %s is blank or not.", typeword);
131             return 1;
132         } else if (paper->oclass == SPBOOK_CLASS) {
133             /* can't write a magic book while blind */
134             pline("%s can't create braille text.",
135                   upstart(ysimple_name(pen)));
136             return 1;
137         }
138     }
139     paper->dknown = 1;
140     if (paper->otyp != SCR_BLANK_PAPER && paper->otyp != SPE_BLANK_PAPER) {
141         pline("That %s is not blank!", typeword);
142         exercise(A_WIS, FALSE);
143         return 1;
144     }
145
146     /* what to write */
147     Sprintf(qbuf, "What type of %s do you want to write?", typeword);
148     getlin(qbuf, namebuf);
149     (void) mungspaces(namebuf); /* remove any excess whitespace */
150     if (namebuf[0] == '\033' || !namebuf[0])
151         return 1;
152     nm = namebuf;
153     if (!strncmpi(nm, "scroll ", 7))
154         nm += 7;
155     else if (!strncmpi(nm, "spellbook ", 10))
156         nm += 10;
157     if (!strncmpi(nm, "of ", 3))
158         nm += 3;
159
160     if ((bp = strstri(nm, " armour")) != 0) {
161         (void) strncpy(bp, " armor ", 7); /* won't add '\0' */
162         (void) mungspaces(bp + 1);        /* remove the extra space */
163     }
164
165     deferred = 0;       /* not any scroll or book */
166     deferralchance = 0; /* incremented for each oc_uname match */
167     first = bases[(int) paper->oclass];
168     last = bases[(int) paper->oclass + 1] - 1;
169     for (i = first; i <= last; i++) {
170         /* extra shufflable descr not representing a real object */
171         if (!OBJ_NAME(objects[i]))
172             continue;
173
174         if (!strcmpi(OBJ_NAME(objects[i]), nm))
175             goto found;
176         if (!strcmpi(OBJ_DESCR(objects[i]), nm)) {
177             by_descr = TRUE;
178             goto found;
179         }
180         /* user-assigned name might match real name of a later
181            entry, so we don't simply use first match with it;
182            also, player might assign same name multiple times
183            and if so, we choose one of those matches randomly */
184         if (objects[i].oc_uname && !strcmpi(objects[i].oc_uname, nm)
185             /*
186              * First match: chance incremented to 1,
187              *   !rn2(1) is 1, we remember i;
188              * second match: chance incremented to 2,
189              *   !rn2(2) has 1/2 chance to replace i;
190              * third match: chance incremented to 3,
191              *   !rn2(3) has 1/3 chance to replace i
192              *   and 2/3 chance to keep previous 50:50
193              *   choice; so on for higher match counts.
194              */
195             && !rn2(++deferralchance))
196             deferred = i;
197     }
198     /* writing by user-assigned name is same as by description:
199        fails for books, works for scrolls (having an assigned
200        type name guarantees presence on discoveries list) */
201     if (deferred) {
202         i = deferred;
203         by_descr = TRUE;
204         goto found;
205     }
206
207     There("is no such %s!", typeword);
208     return 1;
209 found:
210
211     if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) {
212         You_cant("write that!");
213         pline("It's obscene!");
214         return 1;
215     } else if (i == SPE_BOOK_OF_THE_DEAD) {
216         pline("No mere dungeon adventurer could write that.");
217         return 1;
218     } else if (by_descr && paper->oclass == SPBOOK_CLASS
219                && !objects[i].oc_name_known) {
220         /* can't write unknown spellbooks by description */
221         pline("Unfortunately you don't have enough information to go on.");
222         return 1;
223     }
224
225     /* KMH, conduct */
226     u.uconduct.literate++;
227
228     new_obj = mksobj(i, FALSE, FALSE);
229     new_obj->bknown = (paper->bknown && pen->bknown);
230
231     /* shk imposes a flat rate per use, not based on actual charges used */
232     check_unpaid(pen);
233
234     /* see if there's enough ink */
235     basecost = cost(new_obj);
236     if (pen->spe < basecost / 2) {
237         Your("marker is too dry to write that!");
238         obfree(new_obj, (struct obj *) 0);
239         return 1;
240     }
241
242     /* we're really going to write now, so calculate cost
243      */
244     actualcost = rn1(basecost / 2, basecost / 2);
245     curseval = bcsign(pen) + bcsign(paper);
246     exercise(A_WIS, TRUE);
247     /* dry out marker */
248     if (pen->spe < actualcost) {
249         pen->spe = 0;
250         Your("marker dries out!");
251         /* scrolls disappear, spellbooks don't */
252         if (paper->oclass == SPBOOK_CLASS) {
253             pline_The("spellbook is left unfinished and your writing fades.");
254             update_inventory(); /* pen charges */
255         } else {
256             pline_The("scroll is now useless and disappears!");
257             useup(paper);
258         }
259         obfree(new_obj, (struct obj *) 0);
260         return 1;
261     }
262     pen->spe -= actualcost;
263
264     /*
265      * Writing by name requires that the hero knows the scroll or
266      * book type.  One has previously been read (and its effect
267      * was evident) or been ID'd via scroll/spell/throne and it
268      * will be on the discoveries list.
269      * (Previous versions allowed scrolls and books to be written
270      * by type name if they were on the discoveries list via being
271      * given a user-assigned name, even though doing the latter
272      * doesn't--and shouldn't--make the actual type become known.)
273      *
274      * Writing by description requires that the hero knows the
275      * description (a scroll's label, that is, since books by_descr
276      * are rejected above).  BUG:  We can only do this for known
277      * scrolls and for the case where the player has assigned a
278      * name to put it onto the discoveries list; we lack a way to
279      * track other scrolls which have been seen closely enough to
280      * read the label without then being ID'd or named.  The only
281      * exception is for currently carried inventory, where we can
282      * check for one [with its dknown bit set] of the same type.
283      *
284      * Normal requirements can be overridden if hero is Lucky.
285      */
286
287     /* if known, then either by-name or by-descr works */
288     if (!objects[new_obj->otyp].oc_name_known
289         /* else if named, then only by-descr works */
290         && !(by_descr && label_known(new_obj->otyp, invent))
291         /* and Luck might override after both checks have failed */
292         && rnl(Role_if(PM_WIZARD) ? 5 : 15)) {
293         You("%s to write that.", by_descr ? "fail" : "don't know how");
294         /* scrolls disappear, spellbooks don't */
295         if (paper->oclass == SPBOOK_CLASS) {
296             You(
297       "write in your best handwriting:  \"My Diary\", but it quickly fades.");
298             update_inventory(); /* pen charges */
299         } else {
300             if (by_descr) {
301                 Strcpy(namebuf, OBJ_DESCR(objects[new_obj->otyp]));
302                 wipeout_text(namebuf, (6 + MAXULEV - u.ulevel) / 6, 0);
303             } else
304                 Sprintf(namebuf, "%s was here!", plname);
305             You("write \"%s\" and the scroll disappears.", namebuf);
306             useup(paper);
307         }
308         obfree(new_obj, (struct obj *) 0);
309         return 1;
310     }
311     /* can write scrolls when blind, but requires luck too;
312        attempts to write books when blind are caught above */
313     if (Blind && rnl(3)) {
314         /* writing while blind usually fails regardless of
315            whether the target scroll is known; even if we
316            have passed the write-an-unknown scroll test
317            above we can still fail this one, so it's doubly
318            hard to write an unknown scroll while blind */
319         You("fail to write the scroll correctly and it disappears.");
320         useup(paper);
321         obfree(new_obj, (struct obj *) 0);
322         return 1;
323     }
324
325     /* useup old scroll / spellbook */
326     useup(paper);
327
328     /* success */
329     if (new_obj->oclass == SPBOOK_CLASS) {
330         /* acknowledge the change in the object's description... */
331         pline_The("spellbook warps strangely, then turns %s.",
332                   new_book_description(new_obj->otyp, namebuf));
333     }
334     new_obj->blessed = (curseval > 0);
335     new_obj->cursed = (curseval < 0);
336 #ifdef MAIL
337     if (new_obj->otyp == SCR_MAIL)
338         new_obj->spe = 1;
339 #endif
340     new_obj =
341         hold_another_object(new_obj, "Oops!  %s out of your grasp!",
342                             The(aobjnam(new_obj, "slip")), (const char *) 0);
343     return 1;
344 }
345
346 /* most book descriptions refer to cover appearance, so we can issue a
347    message for converting a plain book into one of those with something
348    like "the spellbook turns red" or "the spellbook turns ragged";
349    but some descriptions refer to composition and "the book turns vellum"
350    looks funny, so we want to insert "into " prior to such descriptions;
351    even that's rather iffy, indicating that such descriptions probably
352    ought to be eliminated (especially "cloth"!) */
353 STATIC_OVL char *
354 new_book_description(booktype, outbuf)
355 int booktype;
356 char *outbuf;
357 {
358     /* subset of description strings from objects.c; if it grows
359        much, we may need to add a new flag field to objects[] instead */
360     static const char *const compositions[] = {
361         "parchment",
362         "vellum",
363         "cloth",
364 #if 0
365         "canvas", "hardcover", /* not used */
366         "papyrus", /* not applicable--can't be produced via writing */
367 #endif /*0*/
368         0
369     };
370     const char *descr, *const *comp_p;
371
372     descr = OBJ_DESCR(objects[booktype]);
373     for (comp_p = compositions; *comp_p; ++comp_p)
374         if (!strcmpi(descr, *comp_p))
375             break;
376
377     Sprintf(outbuf, "%s%s", *comp_p ? "into " : "", descr);
378     return outbuf;
379 }
380
381 /*write.c*/