1/*	SCCS Id: @(#)write.c	3.4	2001/11/29	*/
2/* NetHack may be freely redistributed.  See license for details. */
3
4#include "hack.h"
5
6STATIC_DCL int FDECL(cost,(struct obj *));
7
8/*
9 * returns basecost of a scroll or a spellbook
10 */
11STATIC_OVL int
12cost(otmp)
13register 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
67static NEARDATA const char write_on[] = { SCROLL_CLASS, SPBOOK_CLASS, 0 };
68
69int
70dowrite(pen)
71register 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	    pline("%s from your %s.",
88		  Tobjnam(pen, "slip"), makeplural(body_part(FINGER)));
89	    dropx(pen);
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;
141found:
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		pen->spe = 0;
183		Your("marker dries out!");
184		/* scrolls disappear, spellbooks don't */
185		if (paper->oclass == SPBOOK_CLASS) {
186			pline_The(
187		       "spellbook is left unfinished and your writing fades.");
188			update_inventory();	/* pen charges */
189		} else {
190			pline_The("scroll is now useless and disappears!");
191			useup(paper);
192		}
193		obfree(new_obj, (struct obj *) 0);
194		return(1);
195	}
196	pen->spe -= actualcost;
197
198	/* can't write if we don't know it - unless we're lucky */
199	if(!(objects[new_obj->otyp].oc_name_known) &&
200	   !(objects[new_obj->otyp].oc_uname) &&
201	   (rnl(Role_if(PM_WIZARD) ? 3 : 15))) {
202		You("%s to write that!", by_descr ? "fail" : "don't know how");
203		/* scrolls disappear, spellbooks don't */
204		if (paper->oclass == SPBOOK_CLASS) {
205			You(
206       "write in your best handwriting:  \"My Diary\", but it quickly fades.");
207			update_inventory();	/* pen charges */
208		} else {
209			if (by_descr) {
210			    Strcpy(namebuf, OBJ_DESCR(objects[new_obj->otyp]));
211			    wipeout_text(namebuf, (6+MAXULEV - u.ulevel)/6, 0);
212			} else
213			    Sprintf(namebuf, "%s was here!", plname);
214			You("write \"%s\" and the scroll disappears.", namebuf);
215			useup(paper);
216		}
217		obfree(new_obj, (struct obj *) 0);
218		return(1);
219	}
220
221	/* useup old scroll / spellbook */
222	useup(paper);
223
224	/* success */
225	if (new_obj->oclass == SPBOOK_CLASS) {
226		/* acknowledge the change in the object's description... */
227		pline_The("spellbook warps strangely, then turns %s.",
228		      OBJ_DESCR(objects[new_obj->otyp]));
229	}
230	new_obj->blessed = (curseval > 0);
231	new_obj->cursed = (curseval < 0);
232#ifdef MAIL
233	if (new_obj->otyp == SCR_MAIL) new_obj->spe = 1;
234#endif
235	new_obj = hold_another_object(new_obj, "Oops!  %s out of your grasp!",
236					       The(aobjnam(new_obj, "slip")),
237					       (const char *)0);
238	return(1);
239}
240
241/*write.c*/
242