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
cost(otmp)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
dowrite(pen)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*/
240