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*/