Blindfold removal fix
[slashemextended.git] / src / write.c
blobb79f5b3da9b646f6c6df6e885da0593634084e1f
1 /* SCCS Id: @(#)write.c 3.4 2001/11/29 */
2 /* NetHack may be freely redistributed. See license for details. */
4 #include "hack.h"
6 /* it would have been too much to ask to simply have a function that checks write costs for base items without requiring
7 * an actual dummy item to exist... --Amy */
8 int
9 writecostohmygod(type)
10 int type;
12 int writecostbah = 1;
14 register struct obj *pseudo = mksobj(SCR_BLANK_PAPER, FALSE, 2, FALSE);
15 pseudo->otyp = type;
16 writecostbah = writecost(pseudo);
18 obfree(pseudo, (struct obj *)0); /* now, get rid of it */
20 return writecostbah;
24 * returns basecost of a scroll or a spellbook
26 int
27 writecost(otmp)
28 register struct obj *otmp;
31 if (otmp->oclass == SPBOOK_CLASS)
32 return(10 * objects[otmp->otyp].oc_level);
34 /* KMH, balance patch -- restoration of marker charges */
35 switch (otmp->otyp) {
36 # ifdef MAIL
37 case SCR_MAIL:
38 return(2);
39 # endif
40 case SCR_STANDARD_ID:
41 case SCR_WOUNDS:
42 case SCR_RUMOR:
43 case SCR_MESSAGE:
44 return(5);
45 case SCR_HEALING:
46 case SCR_LIGHT:
47 case SCR_GOLD_DETECTION:
48 case SCR_FOOD_DETECTION:
49 case SCR_TRAP_DETECTION:
50 case SCR_MAGIC_MAPPING:
51 case SCR_AMNESIA:
52 case SCR_INSTANT_AMNESIA:
53 case SCR_FIRE:
54 case SCR_SLEEP:
55 case SCR_EARTH:
56 case SCR_CURE_BLINDNESS:
57 case SCR_ROOT_PASSWORD_DETECTION:
58 case SCR_GRASSLAND:
59 return(8);
60 case SCR_MANA:
61 case SCR_DESTROY_ARMOR:
62 case SCR_DESTROY_WEAPON:
63 case SCR_BAD_EFFECT:
64 case SCR_CREATE_MONSTER:
65 case SCR_CREATE_VICTIM:
66 case SCR_SUMMON_UNDEAD:
67 case SCR_PUNISHMENT:
68 case SCR_NASTINESS:
69 case SCR_SYMMETRY:
70 case SCR_CREATE_CREATE_SCROLL:
71 case SCR_PROOF_ARMOR:
72 case SCR_PROOF_WEAPON:
73 case SCR_CRYPT:
74 case SCR_PAVING:
75 case SCR_NAME:
76 case SCR_INFERIOR_MATERIAL:
77 return(10);
78 case SCR_CONFUSE_MONSTER:
79 case SCR_PHASE_DOOR:
80 case SCR_PROOF_TOOL:
81 case SCR_PROOF_ACCESSORY:
82 return(12);
83 case SCR_IDENTIFY:
84 case SCR_STONING:
85 case SCR_BULLSHIT:
86 case SCR_SCARE_MONSTER:
87 case SCR_SNOW:
88 case SCR_SAND:
89 case SCR_NETHER:
90 return(14);
91 case SCR_ASH:
92 case SCR_BUBBLE_BOBBLE:
93 case SCR_RAIN:
94 case SCR_TAMING:
95 case SCR_TELEPORTATION:
96 case SCR_FLOOD:
97 case SCR_LAVA:
98 case SCR_GRAVE:
99 case SCR_DIVING:
100 case SCR_CRYSTALLIZATION:
101 case SCR_QUICKSAND:
102 case SCR_STYX:
103 case SCR_URINE:
104 case SCR_MOORLAND:
105 case SCR_TUNNELS:
106 case SCR_FARMING:
107 case SCR_BARRHING:
108 case SCR_STALACTITE:
109 case SCR_GROWTH:
110 case SCR_ICE:
111 case SCR_ILLUSION:
112 case SCR_VISIBLE_ITEM:
113 case SCR_FEMINISM:
114 case SCR_EVIL_VARIANT:
115 case SCR_ENRAGE:
116 case SCR_FROST:
117 case SCR_CLOUDS:
118 case SCR_DETECT_WATER:
119 case SCR_CHAOS_TERRAIN:
120 case SCR_TELE_LEVEL:
121 case SCR_WARPING:
122 case SCR_IMMOBILITY:
123 case SCR_MASS_MURDER:
124 case SCR_TRAP_CREATION:
125 case SCR_CREATE_TRAP:
126 case SCR_GROUP_SUMMONING:
127 case SCR_UNDO_GENOCIDE:
128 case SCR_RANDOM_ENCHANTMENT:
129 case SCR_BAD_EQUIPMENT:
130 case SCR_COURSE_TRAVELING:
131 case SCR_HEAL_OTHER:
132 case SCR_REGULAR_MATERIAL:
133 case SCR_RETURN:
134 return(20);
135 /* KMH, balance patch -- more useful scrolls cost more */
136 case SCR_STINKING_CLOUD:
137 case SCR_ENCHANT_ARMOR:
138 case SCR_REMOVE_CURSE:
139 case SCR_ENCHANT_WEAPON:
140 case SCR_CHARGING:
141 case SCR_GIRLINESS:
142 case SCR_FLOODING:
143 case SCR_EGOISM:
144 case SCR_ERASURE:
145 case SCR_ANTIMATTER:
146 case SCR_MEGALOAD:
147 case SCR_WONDER:
148 case SCR_GEOLYSIS:
149 case SCR_OFFLEVEL_ITEM:
150 case SCR_REPAIR_ITEM:
151 case SCR_EXTRA_HEALING:
152 case SCR_MOUNTAINS:
153 case SCR_HIGHWAY:
154 case SCR_SYMBIOSIS:
155 return(24);
156 case SCR_RESISTANCE:
157 case SCR_GENOCIDE:
158 case SCR_CURE:
159 case SCR_SIN:
160 case SCR_ARMOR_SPECIALIZATION:
161 case SCR_SUMMON_BOSS:
162 case SCR_SUMMON_ELM:
163 case SCR_DEMONOLOGY:
164 case SCR_ELEMENTALISM:
165 case SCR_TRAP_DISARMING:
166 case SCR_FLOOD_TIDE:
167 case SCR_EBB_TIDE:
168 case SCR_MATERIAL_CHANGE:
169 case SCR_CREATE_FACILITY:
170 case SCR_SUMMON_GHOST:
171 case SCR_GREATER_MANA_RESTORATION:
172 case SCR_NASTY_CURSE:
173 case SCR_TERRAFORMING:
174 case SCR_ALLY:
175 case SCR_SKILL_GROWTH:
176 return(30);
177 case SCR_GAIN_MANA:
178 case SCR_LOCKOUT:
179 case SCR_WARD:
180 case SCR_CREATE_ALTAR:
181 case SCR_WARDING:
182 case SCR_RELOCATION:
183 case SCR_VILENESS:
184 case SCR_CREATE_FAMILIAR:
185 case SCR_ITEM_GENOCIDE:
186 case SCR_POWER_HEALING:
187 case SCR_REVERSE_IDENTIFY:
188 case SCR_SUPERIOR_MATERIAL:
189 case SCR_BRANCH_TELEPORT:
190 return(40);
191 case SCR_CONSECRATION:
192 case SCR_BOSS_COMPANION:
193 case SCR_ANTIMAGIC:
194 case SCR_SECURE_CURSE_REMOVAL:
195 case SCR_INVENTORY_ID:
196 case SCR_SKILL_UP:
197 case SCR_SECURE_IDENTIFY:
198 case SCR_ALTER_REALITY:
199 case SCR_HYBRIDIZATION:
200 case SCR_GREATER_ENCHANT_WEAPON:
201 case SCR_GREATER_ENCHANT_ARMOR:
202 case SCR_POWER_CHARGING:
203 return(50);
204 case SCR_RAGNAROK:
205 return(64);
206 case SCR_WORLD_FALL:
207 case SCR_ASTRALCENSION: /* more expensive than the max # of charges in a marker on purpose --Amy */
208 case SCR_EXTRA_SKILL_POINT:
209 return(150);
210 case SCR_BLANK_PAPER:
211 case SCR_COPYING:
212 case SCR_WISHING:
213 case SCR_ARTIFACT_CREATION:
214 case SCR_MISSING_CODE:
215 case SCR_ARTIFACT_JACKPOT:
216 case SCR_RESURRECTION:
217 case SCR_ACQUIREMENT:
218 case SCR_ENTHRONIZATION:
219 case SCR_WELL_BUILDING:
220 case SCR_DRIVING:
221 case SCR_TABLE_FURNITURE:
222 case SCR_EMBEDDING:
223 case SCR_MATTRESS_SLEEPING:
224 case SCR_MAKE_PENTAGRAM:
225 case SCR_FOUNTAIN_BUILDING:
226 case SCR_SINKING:
227 case SCR_CREATE_SINK:
228 case SCR_WC:
229 default:
230 /*impossible*/pline("You can't write such a weird scroll!");
232 return(1000);
235 static NEARDATA const char write_on[] = { SCROLL_CLASS, SPBOOK_CLASS, 0 };
238 dowrite(pen)
239 register struct obj *pen;
241 register struct obj *paper;
242 char namebuf[BUFSZ], *nm, *bp;
243 register struct obj *new_obj;
244 int basecost, actualcost;
245 int curseval;
246 char qbuf[QBUFSZ];
247 int first, last, i;
248 boolean by_descr = FALSE;
249 const char *typeword;
251 int oldspe, oldrecharged, oldartifact; /* for spellbooks */
252 boolean oldknown;
254 if (nohands(youmonst.data) && !Race_if(PM_TRANSFORMER) ) {
255 You("need hands to be able to write!");
256 if (yn("Attempt it anyway?") == 'y') {
257 if (rn2(3) && !polyskillchance()) {
258 drain_en(rnz(monster_difficulty() + 1) );
259 pline("You lose Mana");
260 if (!rn2(20)) badeffect();
261 return 1;
265 else return 0;
267 if (IsGlib) {
268 pline("%s from your %s.",
269 Tobjnam(pen, "slip"), makeplural(body_part(FINGER)));
270 dropx(pen);
271 return 1;
274 /* get paper to write on */
275 paper = getobj(write_on,"write on");
276 if(!paper)
277 return(0);
278 typeword = (paper->oclass == SPBOOK_CLASS) ? "spellbook" : "scroll";
279 if(Blind && !paper->dknown) {
280 You("don't know if that %s is blank or not!", typeword);
281 return(1);
283 paper->dknown = 1;
284 if(paper->otyp != SCR_BLANK_PAPER && paper->otyp != SPE_BLANK_PAPER) {
285 pline("That %s is not blank!", typeword);
286 exercise(A_WIS, FALSE);
287 return(1);
290 /* what to write */
291 sprintf(qbuf, "What type of %s do you want to write?", typeword);
292 getlin(qbuf, namebuf);
293 (void)mungspaces(namebuf); /* remove any excess whitespace */
294 if(namebuf[0] == '\033' || !namebuf[0])
295 return(1);
296 nm = namebuf;
297 if (!strncmpi(nm, "scroll ", 7)) nm += 7;
298 else if (!strncmpi(nm, "spellbook ", 10)) nm += 10;
299 if (!strncmpi(nm, "of ", 3)) nm += 3;
301 if ((bp = strstri(nm, " armour")) != 0) {
302 (void)strncpy(bp, " armor ", 7); /* won't add '\0' */
303 (void)mungspaces(bp + 1); /* remove the extra space */
306 first = bases[(int)paper->oclass];
307 last = bases[(int)paper->oclass + 1] - 1;
308 for (i = first; i <= last; i++) {
309 /* extra shufflable descr not representing a real object */
310 if (!OBJ_NAME(objects[i])) continue;
312 if (!strcmpi(OBJ_NAME(objects[i]), nm))
313 goto found;
314 if (!strcmpi(OBJ_DESCR(objects[i]), nm)) {
315 by_descr = TRUE;
316 goto found;
320 There("is no such %s!", typeword);
321 return 1;
322 found:
324 if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) {
325 You_cant("write that!");
326 pline("It's obscene!");
327 return 1;
328 } else if (i == SPE_BOOK_OF_THE_DEAD) {
329 pline("No mere dungeon adventurer could write that.");
330 return 1;
331 } else if (i == SCR_COPYING) {
332 You("don't know how to break copy protect.");
333 if(FunnyHallu)
334 pline("(I know it, but not tell to you.)");
335 return 1;
336 } else if (i == SCR_WISHING || i == SCR_ARTIFACT_CREATION || i == SCR_MISSING_CODE || i == SCR_ARTIFACT_JACKPOT || i == SCR_RESURRECTION || i == SCR_ACQUIREMENT || i == SCR_ENTHRONIZATION || i == SCR_MAKE_PENTAGRAM || i == SCR_WELL_BUILDING || i == SCR_DRIVING || i == SCR_TABLE_FURNITURE || i == SCR_EMBEDDING || i == SCR_MATTRESS_SLEEPING || i == SCR_FOUNTAIN_BUILDING || i == SCR_SINKING || i == SCR_CREATE_SINK || i == SCR_WC) {
337 pline("This scroll refuses to be written.");
338 return 1;
339 } else if (by_descr && paper->oclass == SPBOOK_CLASS &&
340 !objects[i].oc_name_known) {
341 /* can't write unknown spellbooks by description */
342 pline(
343 "Unfortunately you don't have enough information to go on.");
344 return 1;
347 if (Race_if(PM_PLAYABLE_NEANDERTHAL)) {
348 pline("Apparently you forgot that you're illiterate. Anyway, your attempt to write fails.");
349 return 1;
352 /* KMH, conduct */
353 u.uconduct.literate++;
355 new_obj = mksobj(i, FALSE, FALSE, FALSE);
356 if (!new_obj) {
357 pline("Scroll creation failed!");
358 return(1);
360 new_obj->bknown = (paper->bknown && pen->bknown);
361 new_obj->oinvis = paper->oinvis;
362 new_obj->oinvisreal = paper->oinvisreal;
364 /* shk imposes a flat rate per use, not based on actual charges used */
365 check_unpaid(pen);
367 /* see if there's enough ink */
368 basecost = writecost(new_obj);
370 if (basecost >= 1000) { /* impossible! */
371 return(0);
374 if (!(objects[new_obj->otyp].oc_name_known)) {
375 pline("That item isn't type-identified. If it also isn't type-named, writing it may fail depending on your luck.");
376 if (yn("Try anyway?") != 'y') {
377 obfree(new_obj, (struct obj *) 0);
378 return(0);
380 } else {
381 pline("Writing that will cost up to %d ink.", basecost);
382 if (yn("Do you want to give it a try?") != 'y') {
383 obfree(new_obj, (struct obj *) 0);
384 return(0);
389 if(pen->spe < basecost/2 && (objects[new_obj->otyp].oc_name_known) ) {
390 Your("marker is too dry to write that!");
391 obfree(new_obj, (struct obj *) 0);
392 return(1);
395 /* we're really going to write now, so calculate cost
397 actualcost = rn1(basecost/2,basecost/2);
398 if (isfriday && !rn2(10)) actualcost *= 2;
399 if (pen->oartifact == ART_WRITE_THE_UNKNOWN && paper->oclass == SCROLL_CLASS) actualcost *= (2 + rnd(2));
401 if (!(PlayerCannotUseSkills)) {
402 switch (P_SKILL(P_DEVICES)) {
403 default: break;
404 case P_BASIC: actualcost = (actualcost * 14 / 15); break;
405 case P_SKILLED: actualcost = (actualcost * 13 / 15); break;
406 case P_EXPERT: actualcost = (actualcost * 12 / 15); break;
407 case P_MASTER: actualcost = (actualcost * 11 / 15); break;
408 case P_GRAND_MASTER: actualcost = (actualcost * 10 / 15); break;
409 case P_SUPREME_MASTER: actualcost = (actualcost * 9 / 15); break;
413 curseval = bcsign(pen) + bcsign(paper);
414 exercise(A_WIS, TRUE);
415 /* dry out marker */
416 if (pen->spe < actualcost) {
417 pen->spe -= rnd(pen->spe);
418 if (issoviet) pen->spe = 0;
419 if (!pen->spe && !issoviet) Your("marker dries out!");
420 if (issoviet) pline("Medved' khar khar, Sovet reshil, chto markery stanovyatsya pustymi, eto zdorovo. Poproshchaytes' s nim!");
421 else pline("Unfortunately, after writing for a bit you notice that there's not enough ink left. You stop writing to salvage at least some of the precious ink.");
422 /* scrolls disappear, spellbooks don't */
423 if (paper->oclass == SPBOOK_CLASS) {
424 pline_The(
425 "spellbook is left unfinished and your writing fades.");
426 update_inventory(); /* pen charges */
427 } else {
429 if (!(paper->oartifact == ART_SCRIBE_WHAT_YOU_WANT_TO_SC)) {
430 pline_The("scroll is now useless and disappears!");
431 useup(paper);
434 obfree(new_obj, (struct obj *) 0);
435 return(1);
437 pen->spe -= actualcost;
439 /* can't write if we don't know it - unless we're lucky */
440 if(!(objects[new_obj->otyp].oc_name_known) &&
441 !(objects[new_obj->otyp].oc_uname) &&
442 !(pen->oartifact == ART_WRITE_THE_UNKNOWN && paper->oclass == SCROLL_CLASS) &&
443 (rnl(Role_if(PM_WIZARD) ? 3 : Role_if(PM_SAGE) ? 2 : Role_if(PM_SOFTWARE_ENGINEER) ? 11 : 15))) {
444 You("%s to write that!", by_descr ? "fail" : "don't know how");
445 /* scrolls disappear, spellbooks don't */
446 if (paper->oclass == SPBOOK_CLASS) {
447 You(
448 "write in your best handwriting: \"My Diary\", but it quickly fades.");
449 update_inventory(); /* pen charges */
450 } else {
451 if (by_descr) {
452 strcpy(namebuf, OBJ_DESCR(objects[new_obj->otyp]));
453 wipeout_text(namebuf, (6+MAXULEV - u.ulevel)/6, 0);
454 } else
455 sprintf(namebuf, "%s was here!", playeraliasname);
457 if (paper->oartifact == ART_SCRIBE_WHAT_YOU_WANT_TO_SC) You("write \"%s\" on the scroll, which doesn't actually have any effect.", namebuf);
458 else You("write \"%s\" and the scroll disappears.", namebuf);
460 if (!(paper->oartifact == ART_SCRIBE_WHAT_YOU_WANT_TO_SC)) {
461 useup(paper);
464 obfree(new_obj, (struct obj *) 0);
465 return(1);
468 /* useup old scroll / spellbook */
470 oldspe = paper->spe;
471 oldrecharged = (int)paper->recharged; /* for spellbooks */
472 oldknown = paper->known;
473 oldartifact = -1;
474 if (paper->oartifact) oldartifact = paper->oartifact;
476 useup(paper);
477 use_skill(P_DEVICES,10);
478 if (Race_if(PM_FAWN)) {
479 use_skill(P_DEVICES,10);
481 if (Race_if(PM_SATRE)) {
482 use_skill(P_DEVICES,10);
483 use_skill(P_DEVICES,10);
485 u.cnd_markercount++;
487 if (pen->oartifact == ART_SEEP_INTO_THE_SOUL) {
489 Your("intelligence seeps out of your brain and into your soul...");
491 if (ABASE(A_INT) < 2) {
492 u.youaredead = 1;
493 pline("Your last thought fades away.");
494 killer = "being too stupid to write";
495 killer_format = KILLED_BY;
496 done(DIED);
497 /* lifesaved */
498 pline("Unfortunately, your brain is still gone.");
499 killer = "being too stupid to write";
500 killer_format = KILLED_BY;
501 done(DIED);
502 /* lifesaved again */
503 You_feel("like a scarecrow.");
504 u.youaredead = 0;
505 } else {
506 ABASE(A_INT)--;
507 AMAX(A_INT)--;
508 flags.botl = TRUE;
510 gain_alla(actualcost);
513 if (evilfriday && !rn2(3)) { /* EPI that was talked about in #hardfought by several people */
514 if (!rn2(10)) {
515 if (ABASE(A_INT) < 2) {
516 u.youaredead = 1;
517 pline("Your last thought fades away.");
518 killer = "being too stupid to write";
519 killer_format = KILLED_BY;
520 done(DIED);
521 /* lifesaved */
522 pline("Unfortunately, your brain is still gone.");
523 killer = "being too stupid to write";
524 killer_format = KILLED_BY;
525 done(DIED);
526 /* lifesaved again */
527 You_feel("like a scarecrow.");
528 u.youaredead = 0;
530 } else if (Race_if(PM_SUSTAINER) && rn2(50)) {
531 pline("The stat drain doesn't seem to affect you.");
532 } else if (Role_if(PM_ASTRONAUT) && rn2(2)) {
533 pline("Your steeled body prevents the stat loss!");
534 } else {
536 u.cnd_permstatdamageamount++;
538 pline("Your intelligence seeps into the thing you wrote, and you feel stupid!");
539 ABASE(A_INT) -= 1;
540 AMAX(A_INT) -= 1;
541 flags.botl = 1;
544 } else {
545 pline("Your act of writing transfers some of your intelligence to the paper...");
546 adjattrib(A_INT, -1, FALSE, TRUE);
550 /* success */
551 if (new_obj->oclass == SPBOOK_CLASS) {
552 /* acknowledge the change in the object's description... */
553 pline_The("spellbook warps strangely, then turns %s.",
554 OBJ_DESCR(objects[new_obj->otyp]));
556 /* for some reason the charges weren't being used at all!!! --Amy */
557 new_obj->spe = oldspe;
558 new_obj->recharged = oldrecharged;
560 /* can't simply make a blank spellbook with dozens of charges and write a hard-to-recharge book, you cheater */
561 if ((new_obj->otyp == SPE_TIME || new_obj->otyp == SPE_GAIN_LEVEL || new_obj->otyp == SPE_MAP_LEVEL || new_obj->otyp == SPE_INERTIA || new_obj->otyp == SPE_CHARGING || new_obj->otyp == SPE_GENOCIDE || new_obj->otyp == SPE_GODMODE || new_obj->otyp == SPE_CHARACTER_RECURSION || new_obj->otyp == SPE_PETRIFY || new_obj->otyp == SPE_ACQUIREMENT || new_obj->otyp == SPE_THRONE_GAMBLE || new_obj->otyp == SPE_WISHING || new_obj->otyp == SPE_WORLD_FALL || new_obj->otyp == SPE_REROLL_ARTIFACT || new_obj->otyp == SPE_ATTUNE_MAGIC || new_obj->otyp == SPE_GAIN_SPACT || new_obj->otyp == SPE_CLONE_MONSTER || new_obj->otyp == SPE_TIME_STOP || new_obj->otyp == SPE_ALTER_REALITY || new_obj->otyp == SPE_AULE_SMITHING) && new_obj->spe > 1) new_obj->spe = 1;
563 if (oldknown == TRUE) new_obj->known = TRUE;
566 if (oldartifact > 0) {
568 if (oldartifact == ART_PAGAN_POETRY) {
569 artilist[ART_PAGAN_POETRY].otyp = new_obj->otyp;
570 new_obj = onameX(new_obj, artiname(oldartifact));
571 artilist[ART_PAGAN_POETRY].otyp = SPE_BLANK_PAPER;
574 if (oldartifact == ART_SCRIBE_WHAT_YOU_WANT_TO_SC) {
575 artilist[ART_SCRIBE_WHAT_YOU_WANT_TO_SC].otyp = new_obj->otyp;
576 new_obj = onameX(new_obj, artiname(oldartifact));
577 artilist[ART_SCRIBE_WHAT_YOU_WANT_TO_SC].otyp = SCR_BLANK_PAPER;
582 new_obj->blessed = (curseval > 0);
583 new_obj->cursed = (curseval < 0);
585 if (pen && pen->oartifact == ART_PEN_OF_RANDOMNESS) {
586 new_obj->blessed = 0;
587 new_obj->cursed = 0;
588 if (!rn2(3)) new_obj->blessed = 1;
589 else if (!rn2(2)) new_obj->cursed = 1;
591 new_obj->selfmade = TRUE;
592 #ifdef MAIL
593 if (new_obj->otyp == SCR_MAIL) new_obj->spe = 1;
594 #endif
595 new_obj = hold_another_object(new_obj, "Oops! %s out of your grasp!",
596 The(aobjnam(new_obj, "slip")),
597 (const char *)0);
598 return(1);
601 /*write.c*/