1 | /* SCCS Id: @(#)write.c 3.3 96/05/05 */
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 |
8 | /*
9 | * returns basecost of a scroll or a spellbook
10 | */
11 | STATIC_OVL int
12 | cost(otmp)
13 | register struct obj *otmp;
14 | {
15 |
16 | if (otmp->oclass == SPBOOK_CLASS)
17 | return(10 * objects[otmp->otyp].oc_level);
18 |
19 | switch (otmp->otyp) {
20 | # ifdef MAIL
21 | case SCR_MAIL:
22 | return(2);
23 | /* break; */
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 | /* break; */
34 | case SCR_DESTROY_ARMOR:
35 | case SCR_CREATE_MONSTER:
36 | case SCR_PUNISHMENT:
37 | return(10);
38 | /* break; */
39 | case SCR_CONFUSE_MONSTER:
40 | return(12);
41 | /* break; */
42 | case SCR_IDENTIFY:
43 | return(14);
44 | /* break; */
45 | case SCR_ENCHANT_ARMOR:
46 | case SCR_REMOVE_CURSE:
47 | case SCR_ENCHANT_WEAPON:
48 | case SCR_CHARGING:
49 | return(16);
50 | /* break; */
51 | case SCR_SCARE_MONSTER:
52 | case SCR_STINKING_CLOUD:
53 | case SCR_TAMING:
54 | case SCR_TELEPORTATION:
55 | return(20);
56 | /* break; */
57 | case SCR_GENOCIDE:
58 | return(30);
59 | /* break; */
60 | case SCR_BLANK_PAPER:
61 | default:
62 | impossible("You can't write such a weird scroll!");
63 | }
64 | return(1000);
65 | }
66 |
67 | static NEARDATA const char write_on[] = { SCROLL_CLASS, SPBOOK_CLASS, 0 };
68 |
69 | int
70 | dowrite(pen)
71 | register struct obj *pen;
72 | {
73 | register struct obj *paper;
74 | char namebuf[BUFSZ], *nm, *bp;
75 | register struct obj *new_obj;
76 | int basecost, actualcost;
77 | int curseval;
78 | char qbuf[QBUFSZ];
79 | int first, last, i;
80 | boolean by_descr = FALSE;
81 | const char *typeword;
82 |
83 | if (nohands(youmonst.data)) {
84 | You("need hands to be able to write!");
85 | return 0;
86 | } else if (Glib) {
87 | dropx(pen);
88 | pline("%s slips from your %s.", The(xname(pen)),
89 | makeplural(body_part(FINGER)));
90 | return 1;
91 | }
92 |
93 | /* get paper to write on */
94 | paper = getobj(write_on,"write on");
95 | if(!paper)
96 | return(0);
97 | typeword = (paper->oclass == SPBOOK_CLASS) ? "spellbook" : "scroll";
98 | if(Blind && !paper->dknown) {
99 | You("don't know if that %s is blank or not!", typeword);
100 | return(1);
101 | }
102 | paper->dknown = 1;
103 | if(paper->otyp != SCR_BLANK_PAPER && paper->otyp != SPE_BLANK_PAPER) {
104 | pline("That %s is not blank!", typeword);
105 | exercise(A_WIS, FALSE);
106 | return(1);
107 | }
108 |
109 | /* what to write */
110 | Sprintf(qbuf, "What type of %s do you want to write?", typeword);
111 | getlin(qbuf, namebuf);
112 | (void)mungspaces(namebuf); /* remove any excess whitespace */
113 | if(namebuf[0] == '\033' || !namebuf[0])
114 | return(1);
115 | nm = namebuf;
116 | if (!strncmpi(nm, "scroll ", 7)) nm += 7;
117 | else if (!strncmpi(nm, "spellbook ", 10)) nm += 10;
118 | if (!strncmpi(nm, "of ", 3)) nm += 3;
119 |
120 | if ((bp = strstri(nm, " armour")) != 0) {
121 | (void)strncpy(bp, " armor ", 7); /* won't add '\0' */
122 | (void)mungspaces(bp + 1); /* remove the extra space */
123 | }
124 |
125 | first = bases[(int)paper->oclass];
126 | last = bases[(int)paper->oclass + 1] - 1;
127 | for (i = first; i <= last; i++) {
128 | /* extra shufflable descr not representing a real object */
129 | if (!OBJ_NAME(objects[i])) continue;
130 |
131 | if (!strcmpi(OBJ_NAME(objects[i]), nm))
132 | goto found;
133 | if (!strcmpi(OBJ_DESCR(objects[i]), nm)) {
134 | by_descr = TRUE;
135 | goto found;
136 | }
137 | }
138 |
139 | There("is no such %s!", typeword);
140 | return 1;
141 | found:
142 |
143 | if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) {
144 | You_cant("write that!");
145 | pline("It's obscene!");
146 | return 1;
147 | } else if (i == SPE_BOOK_OF_THE_DEAD) {
148 | pline("No mere dungeon adventurer could write that.");
149 | return 1;
150 | } else if (by_descr && paper->oclass == SPBOOK_CLASS &&
151 | !objects[i].oc_name_known) {
152 | /* can't write unknown spellbooks by description */
153 | pline(
154 | "Unfortunately you don't have enough information to go on.");
155 | return 1;
156 | }
157 |
158 | /* KMH, conduct */
159 | u.uconduct.literate++;
160 |
161 | new_obj = mksobj(i, FALSE, FALSE);
162 | new_obj->bknown = (paper->bknown && pen->bknown);
163 |
164 | /* shk imposes a flat rate per use, not based on actual charges used */
165 | check_unpaid(pen);
166 |
167 | /* see if there's enough ink */
168 | basecost = cost(new_obj);
169 | if(pen->spe < basecost/2) {
170 | Your("marker is too dry to write that!");
171 | obfree(new_obj, (struct obj *) 0);
172 | return(1);
173 | }
174 |
175 | /* we're really going to write now, so calculate cost
176 | */
177 | actualcost = rn1(basecost/2,basecost/2);
178 | curseval = bcsign(pen) + bcsign(paper);
179 | exercise(A_WIS, TRUE);
180 | /* dry out marker */
181 | if(pen->spe < actualcost) {
182 | Your("marker dries out!");
183 | /* scrolls disappear, spellbooks don't */
184 | if (paper->oclass == SPBOOK_CLASS)
185 | pline_The(
186 | "spellbook is left unfinished and your writing fades.");
187 | else {
188 | pline_The("scroll is now useless and disappears!");
189 | useup(paper);
190 | }
191 | pen->spe = 0;
192 | obfree(new_obj, (struct obj *) 0);
193 | return(1);
194 | }
195 | pen->spe -= actualcost;
196 |
197 | /* can't write if we don't know it - unless we're lucky */
198 | if(!(objects[new_obj->otyp].oc_name_known) &&
199 | !(objects[new_obj->otyp].oc_uname) &&
200 | (rnl(Role_if(PM_WIZARD) ? 3 : 15))) {
201 | You("%s to write that!", by_descr ? "fail" : "don't know how");
202 | /* scrolls disappear, spellbooks don't */
203 | if (paper->oclass == SPBOOK_CLASS)
204 | You(
205 | "write in your best handwriting: \"My Diary\", but it quickly fades.");
206 | else {
207 | if (by_descr) {
208 | Strcpy(namebuf, OBJ_DESCR(objects[new_obj->otyp]));
209 | wipeout_text(namebuf, (6+MAXULEV - u.ulevel)/6, 0);
210 | } else
211 | Sprintf(namebuf, "%s was here!", plname);
212 | You("write \"%s\" and the scroll disappears.", namebuf);
213 | useup(paper);
214 | }
215 | obfree(new_obj, (struct obj *) 0);
216 | return(1);
217 | }
218 |
219 | /* useup old scroll / spellbook */
220 | useup(paper);
221 |
222 | /* success */
223 | if (new_obj->oclass == SPBOOK_CLASS) {
224 | /* acknowledge the change in the object's description... */
225 | pline_The("spellbook warps strangely, then turns %s.",
226 | OBJ_DESCR(objects[new_obj->otyp]));
227 | }
228 | new_obj->blessed = (curseval > 0);
229 | new_obj->cursed = (curseval < 0);
230 | #ifdef MAIL
231 | if (new_obj->otyp == SCR_MAIL) new_obj->spe = 1;
232 | #endif
233 | new_obj = hold_another_object(new_obj, "Oops! %s out of your grasp!",
234 | The(aobjnam(new_obj, "slip")),
235 | (const char *)0);
236 | return(1);
237 | }
238 |
239 | /*write.c*/