home *** CD-ROM | disk | FTP | other *** search
- /* SCCS Id: @(#)engrave.c 3.1 92/06/16 */
- /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
- /* NetHack may be freely redistributed. See license for details. */
-
- #include "hack.h"
- #include "lev.h"
- #include <ctype.h>
-
- STATIC_VAR NEARDATA struct engr *head_engr;
-
- STATIC_DCL void FDECL(del_engr, (struct engr *));
-
- #ifdef OVLB
- /* random engravings */
- const char *random_mesg[] = {
- "Elbereth", "ad ae?ar um",
- "?la? ?as he??",
- /* take-offs and other famous engravings */
- "Owlbreath", "?ala??iel",
- "?ilroy wa? h?re",
- "A.S. ->", "<- A.S.", /* Journey to the Center of the Earth */
- "Y?u won t get i? up ?he ste?s", /* Adventure */
- "Lasc?ate o?ni sp?ranz? o vo? c?'en?rate", /* Inferno */
- "Well Come", /* Prisoner */
- "W? ap?l???ze for t?e inc?nve??e?ce", /* So Long... */
- "S?e you n?xt Wed?esd?y", /* Thriller */
- "Fo? a ?ood time c?ll 8?7-53?9",
- };
-
- const char *
- random_engraving()
- {
- char *rumor, *s;
-
- /* a random engraving may come from the "rumors" file, or from the
- list above */
- rumor = getrumor(0);
- if (rn2(4) && *rumor) {
- for (s = rumor; *s; s++)
- if (!rn2(7) && *s != ' ') *s = '?';
- if (s[-1] == '.') s[-1] = 0;
- return (const char *)rumor;
- }
- else
- return random_mesg[rn2(SIZE(random_mesg))];
- }
- #endif /* OVLB */
- #ifdef OVL0
-
- const char *
- surface(x, y)
- register int x, y;
- {
- register struct rm *lev = &levl[x][y];
-
- if (IS_AIR(lev->typ))
- return "air";
- else if (is_pool(x,y))
- return "water";
- else if (is_ice(x,y))
- return "ice";
- else if (is_lava(x,y))
- return "lava";
- else if (lev->typ == DRAWBRIDGE_DOWN)
- return "bridge";
- else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) ||
- IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR)
- return "floor";
- else
- return "ground";
- }
-
- struct engr *
- engr_at(x,y) register xchar x,y; {
- register struct engr *ep = head_engr;
- while(ep) {
- if(x == ep->engr_x && y == ep->engr_y)
- return(ep);
- ep = ep->nxt_engr;
- }
- return((struct engr *) 0);
- }
-
- #ifdef ELBERETH
- int
- sengr_at(s,x,y)
- register const char *s;
- register xchar x,y;
- {
- register struct engr *ep = engr_at(x,y);
- register char *t;
- register int n;
-
- if(ep && ep->engr_time <= moves) {
- t = ep->engr_txt;
- /*
- if(!strcmp(s,t)) return(1);
- */
- n = strlen(s);
- while(*t) {
- if(!strncmp(s,t,n)) return(1);
- t++;
- }
- }
- return(0);
- }
- #endif
-
- #endif /* OVL0 */
- #ifdef OVL2
-
- void
- u_wipe_engr(cnt)
- register int cnt;
- {
- if(!u.uswallow && !Levitation)
- wipe_engr_at(u.ux, u.uy, cnt);
- }
-
- #endif /* OVL2 */
- #ifdef OVL1
-
- void
- wipe_engr_at(x,y,cnt) register xchar x,y,cnt; {
- register struct engr *ep = engr_at(x,y);
- register int lth,pos;
- char ch;
- if(ep){
- if(ep->engr_type != BURN) {
- if(ep->engr_type != DUST && ep->engr_type != BLOOD) {
- cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1;
- }
- lth = strlen(ep->engr_txt);
- if(lth && cnt > 0 ) {
- while(cnt--) {
- pos = rn2(lth);
- if((ch = ep->engr_txt[pos]) == ' ')
- continue;
- ep->engr_txt[pos] = (ch != '?') ? '?' : ' ';
- }
- }
- while(lth && ep->engr_txt[lth-1] == ' ')
- ep->engr_txt[--lth] = 0;
- while(ep->engr_txt[0] == ' ')
- ep->engr_txt++;
- if(!ep->engr_txt[0]) del_engr(ep);
- }
- }
- }
-
- #endif /* OVL1 */
- #ifdef OVL2
-
- void
- read_engr_at(x,y)
- register int x,y;
- {
- register struct engr *ep = engr_at(x,y);
- register int sensed = 0;
-
- if(ep && ep->engr_txt[0]) {
- switch(ep->engr_type) {
- case DUST:
- if(!Blind) {
- sensed = 1;
- pline("Something is written here in the %s.",
- is_ice(x,y) ? "frost" : "dust");
- }
- break;
- case ENGRAVE:
- if(!Blind || !Levitation) {
- sensed = 1;
- pline("Something is engraved here on the %s.",
- surface(x,y));
- }
- break;
- case BURN:
- if(!Blind || !Levitation) {
- sensed = 1;
- pline("Some text has been %s into the %s here.",
- is_ice(x,y) ? "melted" : "burned",
- surface(x,y));
- }
- break;
- case MARK:
- if(!Blind) {
- sensed = 1;
- pline("There's some graffiti on the %s here.",
- surface(x,y));
- }
- break;
- case BLOOD:
- /* "It's a message! Scrawled in blood!"
- * "What's it say?"
- * "It says... `See you next Wednesday.'" -- Thriller
- */
- if(!Blind) {
- sensed = 1;
- You("see a message scrawled in blood here.");
- }
- break;
- default:
- impossible("Something is written in a very strange way.");
- sensed = 1;
- }
- if (sensed) {
- You("%s: \"%s\".",
- (Blind) ? "feel the words" : "read", ep->engr_txt);
- if(flags.run > 1) nomul(0);
- }
- }
- }
-
- #endif /* OVL2 */
- #ifdef OVLB
-
- void
- make_engr_at(x,y,s,e_time,e_type)
- register int x,y;
- register const char *s;
- register long e_time;
- register xchar e_type;
- {
- register struct engr *ep;
-
- if ((ep = engr_at(x,y)) != 0)
- del_engr(ep);
- ep = newengr(strlen(s) + 1);
- ep->nxt_engr = head_engr;
- head_engr = ep;
- ep->engr_x = x;
- ep->engr_y = y;
- ep->engr_txt = (char *)(ep + 1);
- Strcpy(ep->engr_txt, s);
- if(strcmp(s, "Elbereth")) exercise(A_WIS, TRUE);
- ep->engr_time = e_time;
- ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE);
- ep->engr_lth = strlen(s) + 1;
- }
-
- /* delete any engraving at location <x,y> */
- void
- del_engr_at(x, y)
- int x, y;
- {
- register struct engr *ep = engr_at(x, y);
-
- if (ep) del_engr(ep);
- }
-
- /*
- * freehand - returns true if player has a free hand
- */
- int
- freehand()
- {
- return(!uwep || !welded(uwep) ||
- (!bimanual(uwep) && (!uarms || !uarms->cursed)));
- /* if ((uwep && bimanual(uwep)) ||
- (uwep && uarms))
- return(0);
- else
- return(1);*/
- }
-
- static NEARDATA const char styluses[] =
- { ALL_CLASSES, ALLOW_NONE, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS,
- GEM_CLASS, RING_CLASS, 0 };
-
- /* Mohs' Hardness Scale:
- * 1 - Talc 6 - Orthoclase
- * 2 - Gypsum 7 - Quartz
- * 3 - Calcite 8 - Topaz
- * 4 - Fluorite 9 - Corundum
- * 5 - Apatite 10 - Diamond
- *
- * Since granite is a igneous rock hardness ~ 7, anything >= 8 should
- * probably be able to scratch the rock.
- * Devaluation of less hard gems is not easily possible because obj struct
- * does not contain individual oc_cost currently. 7/91
- *
- * dilithium - ?? * jade - 5-6 (nephrite)
- * diamond - 10 * turquoise - 5-6
- * ruby - 9 (corundum) * opal - 5-6
- * sapphire - 9 (corundum) * iron - 4-5
- * topaz - 8 * fluorite - 4
- * emerald - 7.5-8 (beryl) * brass - 3-4
- * aquamarine - 7.5-8 (beryl) * gold - 2.5-3
- * garnet - 7.25 (var. 6.5-8) * silver - 2.5-3
- * agate - 7 (quartz) * copper - 2.5-3
- * amethyst - 7 (quartz) * amber - 2-2.5
- * jasper - 7 (quartz) *
- * onyx - 7 (quartz) * steel - 5-8.5 (usu. weapon)
- * moonstone - 6 (orthoclase) *
- */
-
- static NEARDATA const short hard_gems[] =
- { DIAMOND, RUBY, SAPPHIRE, TOPAZ, EMERALD, AQUAMARINE, GARNET, 0 };
-
- static NEARDATA const char *hard_ring_names[] =
- {"diamond", "ruby", "sapphire", "emerald", "topaz", ""};
-
- /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
- int
- doengrave()
- {
- boolean dengr = FALSE; /* TRUE if we wipe out the current engraving */
- boolean doblind = FALSE;/* TRUE if engraving blinds the player */
- boolean doknown = FALSE;/* TRUE if we identify the stylus */
- boolean eow = FALSE; /* TRUE if we are overwriting oep */
- boolean jello = FALSE; /* TRUE if we are engraving in slime */
- boolean ptext = TRUE; /* TRUE if we must prompt for engrave text */
- boolean teleengr =FALSE;/* TRUE if we move the old engraving */
- boolean zapwand = FALSE;/* TRUE if we remove a wand charge */
- xchar type = DUST; /* Type of engraving made */
- char buf[BUFSZ]; /* Buffer for final/poly engraving text */
- char ebuf[BUFSZ]; /* Buffer for initial engraving text */
- char qbuf[QBUFSZ]; /* Buffer for query text */
- char post_engr_text[BUFSZ]; /* Text displayed after engraving prompt */
- const char *everb; /* Present tense of engraving type */
- const char *eloc; /* Where the engraving is (ie dust/floor/...) */
- register char *sp; /* Place holder for space count of engr text */
- register int len; /* # of nonspace chars of new engraving text */
- register int maxelen; /* Max allowable length of new engraving text */
- register int spct; /* # of spaces in new engraving text */
- register struct engr *oep = engr_at(u.ux,u.uy);
- /* The current engraving */
- register struct obj *otmp; /* Object selected with which to engrave */
-
-
- multi = 0; /* moves consumed */
- nomovemsg = (char *)0; /* occupation end message */
-
- buf[0] = (char)0;
- ebuf[0] = (char)0;
- post_engr_text[0] = (char)0;
- maxelen = BUFSZ - 1;
-
- /* Can the adventurer engrave at all? */
-
- if(u.uswallow) {
- if (is_animal(u.ustuck->data)) {
- pline("What would you write? \"Jonah was here\"?");
- return(0);
- } else if (is_whirly(u.ustuck->data)) {
- You("can't reach the %s.", surface(u.ux,u.uy));
- return(0);
- } else
- jello = TRUE;
- } else if (is_lava(u.ux, u.uy)) {
- You("can't write on the lava!");
- return(0);
- } else if (is_pool(u.ux,u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
- You("can't write on the water!");
- return(0);
- }
- if(Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) {
- You("can't write in thin air!");
- return(0);
- }
- #ifdef POLYSELF
- if (cantwield(uasmon)) {
- You("can't even hold anything!");
- return(0);
- }
- #endif
- if (check_capacity(NULL)) return (0);
-
- /* One may write with finger, or weapon, or wand, or..., or...
- * Edited by GAN 10/20/86 so as not to change weapon wielded.
- */
-
- otmp = getobj(styluses, "write with");
- if(!otmp) return(0); /* otmp == zeroobj if fingers */
-
- /* There's no reason you should be able to write with a wand
- * while both your hands are tied up.
- */
- if (!freehand() && otmp != uwep && !otmp->owornmask) {
- You("have no free %s to write with!", body_part(HAND));
- return(0);
- }
-
- if (jello) {
- You("tickle %s with your %s.", mon_nam(u.ustuck),
- (otmp == &zeroobj) ? makeplural(body_part(FINGER)) :
- xname(otmp));
- Your("message dissolves...");
- return(0);
- }
- if(Levitation && otmp->oclass != WAND_CLASS){ /* riv05!a3 */
- You("can't reach the %s!", surface(u.ux,u.uy));
- return(0);
- }
-
- /* SPFX for items */
-
- switch (otmp->oclass) {
- default:
- case AMULET_CLASS:
- case CHAIN_CLASS:
- case POTION_CLASS:
- case GOLD_CLASS:
- break;
-
- case RING_CLASS:
- /* "diamond" rings and others should work */
- {
- register int i, j;
-
- for (i=0, j=strlen(hard_ring_names[i]); j; i++)
- if ( !strncmp(hard_ring_names[i],
- OBJ_DESCR(objects[otmp->otyp]),
- j=strlen(hard_ring_names[i])) ) {
- type = ENGRAVE;
- break;
- }
- }
- break;
-
- case GEM_CLASS:
- /* diamonds & other gems should work */
- {
- register int i;
-
- for (i=0; hard_gems[i]; i++)
- if (otmp->otyp == hard_gems[i]) {
- type = ENGRAVE;
- break;
- }
- }
- break;
-
- /* Objects too large to engrave with */
- case BALL_CLASS:
- case ROCK_CLASS:
- case ARMOR_CLASS:
- You("can't engrave with such a large object!");
- ptext = FALSE;
- break;
-
- /* Objects too silly to engrave with */
- case FOOD_CLASS:
- case SCROLL_CLASS:
- case SPBOOK_CLASS:
- Your("%s would get %s.", xname(otmp),
- is_ice(u.ux,u.uy) ? "all frosty" : "too dirty");
- ptext = FALSE;
- break;
-
- case RANDOM_CLASS: /* This should mean fingers */
- break;
-
- /* The charge is removed from the wand before prompting for
- * the engraving text, because all kinds of setup decisions
- * and pre-engraving messages are based upon knowing what type
- * of engraving the wand is going to do. Also, the player
- * will have potentially seen "You wrest .." message, and
- * therefore will know they are using a charge.
- */
- case WAND_CLASS:
- if (zappable(otmp)) {
- check_unpaid(otmp);
- zapwand = TRUE;
- if (Levitation) ptext = FALSE;
-
- switch (otmp->otyp) {
- /* DUST wands */
- default:
- break;
-
- /* NODIR wands */
- case WAN_LIGHT:
- case WAN_SECRET_DOOR_DETECTION:
- case WAN_CREATE_MONSTER:
- case WAN_WISHING:
- zapnodir(otmp);
- break;
-
- /* IMMEDIATE wands */
- /* If wand is "IMMEDIATE", remember to affect the
- * previous engraving even if turning to dust.
- */
- case WAN_STRIKING:
- Strcpy(post_engr_text,
- "The wand unsuccessfully fights your attempt to write!"
- );
- break;
- case WAN_SLOW_MONSTER:
- if (!Blind) {
- Sprintf(post_engr_text,
- "The bugs on the %s slow down!",
- surface(u.ux, u.uy));
- }
- break;
- case WAN_SPEED_MONSTER:
- if (!Blind) {
- Sprintf(post_engr_text,
- "The bugs on the %s speed up!",
- surface(u.ux, u.uy));
- }
- break;
- case WAN_POLYMORPH:
- if(oep) {
- if (!Blind) {
- type = (xchar)0; /* random */
- Strcpy(buf,random_engraving());
- }
- dengr = TRUE;
- }
- break;
- case WAN_NOTHING:
- case WAN_UNDEAD_TURNING:
- case WAN_OPENING:
- case WAN_LOCKING:
- case WAN_PROBING:
- break;
-
- /* RAY wands */
- case WAN_MAGIC_MISSILE:
- ptext = TRUE;
- if (!Blind) {
- Sprintf(post_engr_text,
- "The %s is riddled by bullet holes!",
- surface(u.ux, u.uy));
- }
- break;
-
- /* can't tell sleep from death - Eric Backus */
- case WAN_SLEEP:
- case WAN_DEATH:
- if (!Blind) {
- Sprintf(post_engr_text,
- "The bugs on the %s stop moving!",
- surface(u.ux, u.uy));
- }
- break;
-
- case WAN_COLD:
- if (!Blind)
- Strcpy(post_engr_text,
- "A few ice cubes drop from the wand.");
- if(!oep || (oep->engr_type != BURN))
- break;
- case WAN_CANCELLATION:
- case WAN_MAKE_INVISIBLE:
- if(oep) {
- if (!Blind)
- pline("The engraving on the %s vanishes!",
- surface(u.ux,u.uy));
- dengr = TRUE;
- }
- break;
- case WAN_TELEPORTATION:
- if (oep) {
- if (!Blind)
- pline("The engraving on the %s vanishes!",
- surface(u.ux,u.uy));
- teleengr = TRUE;
- }
- break;
-
- /* type = ENGRAVE wands */
- case WAN_DIGGING:
- ptext = TRUE;
- type = ENGRAVE;
- if(!objects[otmp->otyp].oc_name_known) {
- if (flags.verbose)
- pline("This %s is a wand of digging!",
- xname(otmp));
- doknown = TRUE;
- }
- if (!Blind)
- Strcpy(post_engr_text,
- is_ice(u.ux,u.uy) ?
- "Ice chips fly up from the ice surface!" :
- "Gravel flies up from the floor.");
- else
- Strcpy(post_engr_text, "You hear drilling!");
- break;
-
- /* type = BURN wands */
- case WAN_FIRE:
- ptext = TRUE;
- type = BURN;
- if(!objects[otmp->otyp].oc_name_known) {
- if (flags.verbose)
- pline("This %s is a wand of fire!", xname(otmp));
- doknown = TRUE;
- }
- Strcpy(post_engr_text,
- Blind ? "You feel the wand heat up." :
- "Flames fly from the wand.");
- break;
- case WAN_LIGHTNING:
- ptext = TRUE;
- type = BURN;
- if(!objects[otmp->otyp].oc_name_known) {
- if (flags.verbose)
- pline("This %s is a wand of lightning!",
- xname(otmp));
- doknown = TRUE;
- }
- if (!Blind) {
- Strcpy(post_engr_text,
- "Lightning arcs from the wand.");
- doblind = TRUE;
- } else
- Strcpy(post_engr_text, "You hear crackling!");
- break;
-
- /* type = MARK wands */
- /* type = BLOOD wands */
- }
- } else /* end if zappable */
- if (Levitation) {
- You("can't reach the %s!", surface(u.ux,u.uy));
- return(0);
- }
- break;
-
- case WEAPON_CLASS:
- if(is_blade(otmp))
- if ((int)otmp->spe > -3)
- type = ENGRAVE;
- else
- Your("%s too dull for engraving.", aobjnam(otmp,"are"));
- break;
-
- case TOOL_CLASS:
- if(otmp == ublindf) {
- pline(
- "That is a bit difficult to engrave with, don't you think?");
- return(0);
- }
- switch (otmp->otyp) {
- case MAGIC_MARKER:
- if (otmp->spe <= 0)
- Your("marker has dried out.");
- else
- type = MARK;
- break;
- case TOWEL:
- /* Can't really engrave with a towel */
- ptext = FALSE;
- if (oep)
- if ((oep->engr_type == DUST ) ||
- (oep->engr_type == BLOOD) ||
- (oep->engr_type == MARK )) {
- if (!Blind)
- You("wipe out the message here.");
- else
- Your("%s gets %s.", xname(otmp),
- is_ice(u.ux,u.uy) ?
- "frosty" : "dusty");
- dengr = TRUE;
- } else
- Your("%s can't wipe out this engraving.",
- xname(otmp));
- else
- Your("%s gets %s.", xname(otmp),
- is_ice(u.ux,u.uy) ? "frosty" : "dusty");
- break;
- default:
- break;
- }
- break;
-
- case VENOM_CLASS:
- #ifdef WIZARD
- if (wizard) {
- pline("Writing a poison pen letter??");
- break;
- }
- #endif
- case ILLOBJ_CLASS:
- impossible("You're engraving with an illegal object!");
- break;
- }
-
- /* End of implement setup */
-
- /* Identify stylus */
- if (doknown) {
- makeknown(otmp->otyp);
- more_experienced(0,10);
- }
-
- if (teleengr) {
- register int tx,ty;
-
- do {
- tx = rn1(COLNO-3,2);
- ty = rn2(ROWNO);
- } while(!goodpos(tx,ty, (struct monst *)0, (struct permonst *)0));
-
- oep->engr_x