1 /*
2  * PROPRIETARY INFORMATION.  This software is proprietary to POWDER
3  * Development, and is not to be reproduced, transmitted, or disclosed
4  * in any way without written permission.
5  *
6  * Produced by:	Jeff Lait
7  *
8  *      	POWDER Development
9  *
10  * NAME:        item.cpp ( POWDER Library, C++ )
11  *
12  * COMMENTS:
13  *	Implementation of the item manipulation routines
14  */
15 
16 #include <mygba.h>
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include "assert.h"
21 #include "artifact.h"
22 #include "item.h"
23 #include "itemstack.h"
24 #include "creature.h"
25 #include "gfxengine.h"
26 #include "msg.h"
27 #include "map.h"
28 #include "sramstream.h"
29 #include "mobref.h"
30 #include "victory.h"
31 #include "piety.h"
32 #include "encyc_support.h"
33 
34 //
35 // ITEM defintions
36 //
37 
38 // Global data:
39 
40 // This is a list of what true magic item each mundane item will correspond
41 // to.  What type it refers to varies depending on the item's type, ie:
42 // potions will refer to POTION_.
43 u8		glb_magicitem[NUM_ITEMS];
44 // This tracks if each given item type has been ided.  This is different from
45 // a specic item has been ided.  A generically ided item will properly
46 // index its glb_magicitem class to give its type (acid potion rather than
47 // purple potion), a specific id will do this and its own state (bless vs curse)
48 bool		glb_itemid[NUM_ITEMS];
49 
50 // This is the overloaded name someone has given this dude.
51 // It has been strduped so should be freed.
52 char		*glb_itemnames[NUM_ITEMS];
53 
54 int 		 glbItemCount = 0;
55 
56 // This is for the callback to track who did the zapping.
57 MOBREF		 ITEM::ourZapper;
58 
59 void
item_init()60 item_init()
61 {
62     memset(glb_itemnames, 0, sizeof(char *) * NUM_ITEMS);
63 }
64 
ITEM()65 ITEM::ITEM()
66 {
67     myNext = 0;
68     myName.setName(0);
69     glbItemCount++;
70 }
71 
~ITEM()72 ITEM::~ITEM()
73 {
74     MOB		*mob;
75 
76     mob = myCorpseMob.getMob();
77 
78     if (mob)
79     {
80 	// This MUST be safe, as we own it!
81 	// We want to punish the owner if we are a familiar.
82 	// This will catch the case of corpses decaying...
83 	// (Or being eaten!)
84 	// One problem is I think double jeapordy for smashing a statue
85 	// of your familiar.  But such evil scum that do that deserve
86 	// to be punished.
87 	if (mob->hasIntrinsic(INTRINSIC_FAMILIAR))
88 	{
89 	    MOB		*master;
90 	    master = mob->getMaster();
91 	    if (master)
92 	    {
93 		master->systemshock();
94 
95 		master->formatAndReport("%U <feel> a great loss.");
96 	    }
97 	}
98 
99 	delete mob;
100     }
101 
102     glbItemCount--;
103 }
104 
105 void
item_randomizetype(MAGICTYPE_NAMES magictype,int num)106 item_randomizetype(MAGICTYPE_NAMES magictype, int num)
107 {
108     int			 i, j;
109     u8			*lut;
110 
111     lut = new u8[num];
112     for (i = 0; i < num; i++)
113     {
114 	lut[i] = i;
115     }
116     // Now, mix randomly...
117     rand_shuffle(lut, num);
118 
119     // Now, run through our items and assign the relevant type for each
120     // potion, asserting we have enough!
121     j = 0;
122     for (i = 0; i < NUM_ITEMS; i++)
123     {
124 	if (glb_itemdefs[i].magictype == magictype)
125 	{
126 	    glb_magicitem[i] = lut[j++];
127 	    UT_ASSERT(j <= num);
128 	}
129     }
130     delete [] lut;
131 
132     // Verify we gave away each item exactly once.
133     UT_ASSERT(j == num);
134 }
135 
136 void
init()137 ITEM::init()
138 {
139     int		 i;
140 
141     // Clear the item names.
142     for (i = 0; i < NUM_ITEMS; i++)
143     {
144 	if (glb_itemnames[i])
145 	    free(glb_itemnames[i]);
146 	glb_itemnames[i] = 0;
147     }
148 
149     // Build all the magic lookup tables...
150     memset(glb_magicitem, 0, NUM_ITEMS);
151 
152     // Clear out the id flags.
153     memset(glb_itemid, 0, NUM_ITEMS);
154 
155     // Now, for each of the special types, enumerate them...
156     item_randomizetype(MAGICTYPE_POTION, NUM_POTIONS);
157     item_randomizetype(MAGICTYPE_SCROLL, NUM_SCROLLS);
158     item_randomizetype(MAGICTYPE_RING, NUM_RINGS);
159     item_randomizetype(MAGICTYPE_HELM, NUM_HELMS);
160     item_randomizetype(MAGICTYPE_BOOTS, NUM_BOOTSS);
161     item_randomizetype(MAGICTYPE_AMULET, NUM_AMULETS);
162     item_randomizetype(MAGICTYPE_WAND, NUM_WANDS);
163     item_randomizetype(MAGICTYPE_SPELLBOOK, NUM_SPELLBOOKS);
164     item_randomizetype(MAGICTYPE_STAFF, NUM_STAFFS);
165 }
166 
167 ITEM *
createClone() const168 ITEM::createClone() const
169 {
170     ITEM	*clone;
171 
172     clone = ITEM::create((ITEM_NAMES) myDefinition);
173 
174     clone->myStackCount = myStackCount;
175     clone->myX = myX;
176     clone->myY = myY;
177     clone->myName = myName;
178     clone->myEnchantment = myEnchantment;
179     clone->myCharges = myCharges;
180     clone->myPoison = myPoison;
181     clone->myPoisonCharges = myPoisonCharges;
182     clone->myFlag1 = myFlag1;
183     clone->myCorpseMob.setMob(0);
184 
185     return clone;
186 }
187 
188 bool
petrify(MAP * map,MOB * petrifier)189 ITEM::petrify(MAP *map, MOB *petrifier)
190 {
191     // Mounds of flesh turn into boulders.
192     // Things made of flesh become stones.
193 
194     if (myDefinition == ITEM_MOUNDFLESH)
195     {
196 	myDefinition = ITEM_BOULDER;
197 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISBLOCKING);
198 	formatAndReport("The mound of flesh hardens into a boulder.");
199 	return true;
200     }
201 
202     if (getMaterial() == MATERIAL_FLESH)
203     {
204 
205 	if (defn().isquest)
206 	{
207 	    // No petrification of quest items!
208 	    formatAndReport("%U <resist> the petrification!");
209 	    return false;
210 	}
211 
212 	// This is made of flesh.  Should turn into a rock.
213 	formatAndReport("%U <harden> into a rock.");
214 
215 	myDefinition = ITEM_ROCK;
216 	return true;
217     }
218 
219     return false;
220 }
221 
222 bool
unpetrify(MAP * map,MOB * unpetrifier)223 ITEM::unpetrify(MAP *map, MOB *unpetrifier)
224 {
225     if (myDefinition == ITEM_STATUE)
226     {
227 	// This is at least possible
228 	MOB		*mob;
229 
230 	mob = myCorpseMob.getMob();
231 
232 	if (!mob)
233 	{
234 	    // Mobless statue.
235 	    formatAndReport("%U, being but a work of art, <collapse> into a meatball.");
236 	    myDefinition = ITEM_MEATBALL;
237 	    return true;
238 	}
239 
240 	// Bring back to life
241 	mob->clearIntrinsic(INTRINSIC_DEAD);
242 	// Register on the map.
243 	mob->move(getX(), getY(), true);
244 	map->registerMob(mob);
245 
246 	// We may have somehow been looted in the meantime.
247 	mob->rebuildAppearance();
248 	mob->rebuildWornIntrinsic();
249 
250 	mob->formatAndReport("The statue of %U comes to life!");
251 
252 	// Important so we don't delete ourselves :>
253 	myCorpseMob.setMob(0);
254 	map->dropItem(this);
255 	delete this;
256 
257 	return true;
258     }
259 
260     if (myDefinition == ITEM_BOULDER)
261     {
262 	// Becomes a mound of flesh.
263 	formatAndReport("%U <collapse> into a mound of flesh.");
264 	myDefinition = ITEM_MOUNDFLESH;
265 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISBLOCKING);
266 
267 	return true;
268     }
269 
270     if (getMaterial() == MATERIAL_STONE)
271     {
272 	if (defn().isquest)
273 	{
274 	    // No petrification of quest items!
275 	    formatAndReport("%U <remain> stony!");
276 	    return false;
277 	}
278 
279 	// Transforms into a meatball.
280 	formatAndReport("%U <collapse>...");
281 	myDefinition = ITEM_MEATBALL;
282 	formatAndReport("into %U.");
283 	return true;
284     }
285 
286     return false;
287 }
288 
289 ITEM *
polymorph(MOB * polyer)290 ITEM::polymorph(MOB *polyer)
291 {
292     // Flavour text...
293     formatAndReport(polyer, "A shimmering cloud engulfs %U.");
294 
295     // Check for poly-immune items.
296     if (defn().isquest || hasIntrinsic(INTRINSIC_UNCHANGING) || isArtifact())
297     {
298 	formatAndReport("%U <shudder>.");
299 	return 0;
300     }
301 
302     // Create a new item of the same type.
303     ITEMTYPE_NAMES		itemtype;
304 
305     itemtype = getItemType();
306 
307     // Note artifacts can never arise from polying.
308     ITEM	*newitem;
309 
310     newitem = ITEM::createRandomType(itemtype, false);
311 
312     newitem->formatAndReport(polyer, "The cloud dissipates revealing %U.");
313 
314     return newitem;
315 }
316 
317 bool
resurrect(MAP * map,MOB * resser,int x,int y)318 ITEM::resurrect(MAP *map, MOB *resser, int x, int y)
319 {
320     if (myDefinition == ITEM_BONES || myDefinition == ITEM_CORPSE)
321     {
322 	// This is at least possible
323 	MOB		*mob;
324 
325 	mob = myCorpseMob.getMob();
326 
327 	if (!mob)
328 	{
329 	    // This likely should be an assert: Why does a corpse/bones
330 	    // lack a mob?
331 	    resser->reportMessage("The spirit has travelled too far.");
332 
333 	    return false;
334 	}
335 
336 	// See if we can find room in which to resurrect the mob.
337 	// The closest valid square is used.
338 	// We or in STD_SWIM here as we want creatures brought back
339 	// inside water to stay in the water.
340 	if (!map->findCloseTile(x, y, (MOVE_NAMES) (mob->getMoveType() | MOVE_STD_SWIM)))
341 	{
342 	    formatAndReport("%U <twitch> feebily.");
343 	    return false;
344 	}
345 
346 	// Bring back to the verge of death.
347 	mob->setMinimalHP();
348 	if (mob->canResurrectFromCorpse())
349 	{
350 	    // Trolls get full hit points.
351 	    mob->setMaximalHP();
352 	}
353 	mob->clearIntrinsic(INTRINSIC_DEAD);
354 
355 	// Register on the map.
356 	mob->move(x, y, true);
357 	map->registerMob(mob);
358 
359 	// The mob may have been looted on death.  Thus, we rebuild
360 	// it's worn intrinisics.
361 	mob->rebuildWornIntrinsic();
362 	mob->rebuildAppearance();
363 
364 	mob->formatAndReport("%U <return> from the dead!");
365 
366 	// After being resurrected, one is, of course, thankful.
367 	mob->makeSlaveOf(resser);
368 
369 	// Important so we don't delete ourselves :>
370 	myCorpseMob.setMob(0);
371 
372 	// Drop back into whatever liquid we were in.  This is a bit
373 	// mean as pets that die in pits will insta die on resurrecting
374 	// as they will fall back into the pit.  However, you can easily
375 	// fix this by carrying the corpse out.
376 	map->dropMobs(mob->getX(), mob->getY(), true, resser);
377 
378 	return true;
379     }
380     return false;
381 }
382 
383 bool
raiseZombie(MAP * map,MOB * raiser)384 ITEM::raiseZombie(MAP *map, MOB *raiser)
385 {
386     if (myDefinition == ITEM_CORPSE)
387     {
388 	// This is at least possible
389 	MOB		*mob, *zombie;
390 
391 	// It doesn't matter if the mob is there, it just allows
392 	// us to get extra hits.
393 	mob = myCorpseMob.getMob();
394 
395 	// Note we don't clear out myCorpseMob which means that
396 	// if the mob is a familiar we will be punished by zombifying
397 	// it.
398 	// On reflection, I think this is appropriate.
399 
400 	zombie = MOB::create(MOB_ZOMBIE);
401 	zombie->destroyInventory();
402 	if (mob)
403 	{
404 	    zombie->forceHP(mob->getMaxHP());
405 	    zombie->setOrigDefinition(mob->getDefinition());
406 	}
407 
408 	// Register on the map.
409 	zombie->move(getX(), getY(), true);
410 	map->registerMob(zombie);
411 
412 	zombie->formatAndReport("%U <rise> from the dead!");
413 
414 	// The zombie is marked as tame...
415 	zombie->makeSlaveOf(raiser);
416 
417 	return true;
418     }
419     return false;
420 }
421 
422 bool
raiseSkeleton(MAP * map,MOB * raiser)423 ITEM::raiseSkeleton(MAP *map, MOB *raiser)
424 {
425     if (myDefinition == ITEM_BONES)
426     {
427 	// This is at least possible
428 	MOB		*mob, *skeleton;
429 
430 	// It doesn't matter if the mob is there, it just allows
431 	// us to get extra hits.
432 	mob = myCorpseMob.getMob();
433 
434 	skeleton = MOB::create(MOB_SKELETON);
435 	skeleton->destroyInventory();
436 	if (mob)
437 	{
438 	    skeleton->forceHP(mob->getMaxHP());
439 	    skeleton->setOrigDefinition(mob->getDefinition());
440 	}
441 
442 	// Register on the map.
443 	skeleton->move(getX(), getY(), true);
444 	map->registerMob(skeleton);
445 
446 	skeleton->formatAndReport("%U <rise> from the dead!");
447 
448 	// The skeleton is marked as tame...
449 	skeleton->makeSlaveOf(raiser);
450 
451 	return true;
452     }
453     return false;
454 }
455 
456 bool
doBreak(int dc,MOB * breaker,MOB * owner,MAP * map,int x,int y)457 ITEM::doBreak(int dc, MOB *breaker, MOB *owner, MAP *map, int x, int y)
458 {
459     bool		shouldbreak = false;
460     bool		deleteself = false;
461 
462     // Determine if this DC is enough to break the item...
463 
464     // For now, potions break...
465     if (getItemType() == ITEMTYPE_POTION)
466     {
467 	shouldbreak = true;
468     }
469 
470     if (getDefinition() == ITEM_BOTTLE)
471 	shouldbreak = true;
472 
473     if (getDefinition() == ITEM_MINDACIDHAND)
474     {
475 	deleteself = true;
476 	shouldbreak = true;
477     }
478 
479     // TODO: Build break chance into item properties,
480     // can have Glass Swords then.
481     if (getDefinition() == ITEM_ARROW || getDefinition() == ITEM_FIREARROW)
482     {
483 	// Blessed arrows much less likely to break than cursed.
484 	int		chance;
485 
486 	chance = 10;
487 	if (isCursed())
488 	    chance = 50;
489 	if (isBlessed())
490 	    chance = 1;
491 
492 	// A bit more likely to break...
493 	if (getDefinition() == ITEM_FIREARROW)
494 	    chance *= 2;
495 
496 	// If the breaker is a ranger, we don't break!
497 	if (breaker && breaker->hasIntrinsic(INTRINSIC_DRESSED_RANGER))
498 	    chance = 0;
499 
500 	if (rand_chance(chance))
501 	{
502 	    deleteself = true;
503 	    shouldbreak = true;
504 	}
505     }
506 
507     // Exit early if there is no breakage.
508     if (!shouldbreak)
509 	return false;
510 
511     // Stash this before piety as piety may kill us.
512     ourZapper.setMob(breaker);
513 
514     // Provide the breaker with piety...
515     if (breaker)
516 	breaker->pietyBreak(this);
517 
518     // Switch on type & hence effect.
519     switch (getItemType())
520     {
521 	case ITEMTYPE_MISC:
522 	{
523 	    if (getDefinition() == ITEM_BOTTLE)
524 	    {
525 		// Empty bottles grenade...
526 		// FALL THROUGH
527 	    }
528 	    else
529 		break;
530 	}
531 
532 	case ITEMTYPE_POTION:
533 	{
534 	    // Potions are always fully destroyed
535 	    deleteself = true;
536 
537 	    // Give the appropriate dialog...
538 	    formatAndReport("%U <shatter>.");
539 
540 	    if (map)
541 	    {
542 		map->fireBall(x, y, 1 + isBlessed() - isCursed(), true,
543 				grenadeCallbackStatic,
544 				this);
545 	    }
546 
547 	    break;
548 	}
549 
550 	case ITEMTYPE_AMULET:
551 	case ITEMTYPE_WEAPON:
552 	case ITEMTYPE_ARMOUR:
553 	case ITEMTYPE_RING:
554 	case ITEMTYPE_SCROLL:
555 	case ITEMTYPE_SPELLBOOK:
556 	case ITEMTYPE_WAND:
557 	case ITEMTYPE_STAFF:
558 	case NUM_ITEMTYPES:
559 	case ITEMTYPE_NONE:
560 	case ITEMTYPE_ANY:
561 	case ITEMTYPE_ARTIFACT:
562 	    break;
563     }
564 
565 
566     // Destroy our self if required.
567     if (deleteself)
568     {
569 	// If we are stacked, we can escape actually breaking...
570 	if (getStackCount() > 1)
571 	{
572 	    ITEM		*top;
573 
574 	    // This is very round about.  The theory goes we may
575 	    // do something zany in splitStack or delete...
576 	    top = splitStack();
577 	    delete top;
578 
579 	    // Well, it broke, but the ITEM * is still valid...
580 	    return false;
581 	}
582 
583 	if (owner)
584 	{
585 	    owner->dropItem(getX(), getY());
586 	    owner->rebuildAppearance();
587 	    owner->rebuildWornIntrinsic();
588 	}
589 	delete this;
590     }
591 
592     // Breakage occurred!
593     return true;
594 }
595 
596 void
renameType(const char * newname)597 ITEM::renameType(const char *newname)
598 {
599     if (glb_itemnames[myDefinition])
600 	free(glb_itemnames[myDefinition]);
601     if (newname && newname[0])
602     {
603 	glb_itemnames[myDefinition] = strdup(newname);
604     }
605     else
606     {
607 	glb_itemnames[myDefinition] = 0;
608     }
609 }
610 
611 void
rename(const char * newname)612 ITEM::rename(const char *newname)
613 {
614     myName.setName(newname);
615 }
616 
617 void
rename(BUF buf)618 ITEM::rename(BUF buf)
619 {
620     rename(buf.buffer());
621 }
622 
623 const char *
getPersonalName() const624 ITEM::getPersonalName() const
625 {
626     return myName.getName();
627 }
628 
629 ITEM *
create(ITEM_NAMES definition,bool allowartifact,bool nocurse)630 ITEM::create(ITEM_NAMES definition, bool allowartifact, bool nocurse)
631 {
632     ITEM		*item;
633 
634     item = new ITEM();
635 
636     item->myDefinition = definition;
637     item->myStackCount = rand_dice(glb_itemdefs[item->myDefinition].stacksize);
638     item->myX = item->myY = 0;
639     item->myFlag1 = (ITEMFLAG1_NAMES)glb_itemdefs[item->myDefinition].flag1;
640     item->myNext = 0;
641     item->myEnchantment = 0;
642     item->myCharges = 0;
643 
644     item->myPoison = POISON_NONE;
645     item->myPoisonCharges = 0;
646 
647     // Determine cursed state...
648     CURSECHANCE_NAMES	cursechance;
649 
650     cursechance = (CURSECHANCE_NAMES)
651 		    glb_itemdefs[item->myDefinition].cursechance;
652     // Do indirection on special magic types...
653     switch ((MAGICTYPE_NAMES) glb_itemdefs[item->myDefinition].magictype)
654     {
655 	case MAGICTYPE_POTION:
656 	    cursechance = (CURSECHANCE_NAMES) glb_potiondefs[glb_magicitem[item->myDefinition]].cursechance;
657 	    break;
658 	case MAGICTYPE_SCROLL:
659 	    cursechance = (CURSECHANCE_NAMES) glb_scrolldefs[glb_magicitem[item->myDefinition]].cursechance;
660 	    break;
661 	case MAGICTYPE_RING:
662 	    cursechance = (CURSECHANCE_NAMES) glb_ringdefs[glb_magicitem[item->myDefinition]].cursechance;
663 	    break;
664 	case MAGICTYPE_HELM:
665 	    cursechance = (CURSECHANCE_NAMES) glb_helmdefs[glb_magicitem[item->myDefinition]].cursechance;
666 	    break;
667 	case MAGICTYPE_BOOTS:
668 	    cursechance = (CURSECHANCE_NAMES) glb_bootsdefs[glb_magicitem[item->myDefinition]].cursechance;
669 	    break;
670 	case MAGICTYPE_AMULET:
671 	    cursechance = (CURSECHANCE_NAMES) glb_amuletdefs[glb_magicitem[item->myDefinition]].cursechance;
672 	    break;
673 	case MAGICTYPE_WAND:
674 	    cursechance = (CURSECHANCE_NAMES) glb_wanddefs[glb_magicitem[item->myDefinition]].cursechance;
675 	    break;
676 	case MAGICTYPE_SPELLBOOK:
677 	    cursechance = (CURSECHANCE_NAMES) glb_spellbookdefs[glb_magicitem[item->myDefinition]].cursechance;
678 	    break;
679 	case MAGICTYPE_STAFF:
680 	    cursechance = (CURSECHANCE_NAMES) glb_staffdefs[glb_magicitem[item->myDefinition]].cursechance;
681 	    break;
682 	case MAGICTYPE_NONE:
683 	    break;
684 
685 	case NUM_MAGICTYPES:
686 	    UT_ASSERT(!"Unknown magic type!");
687 	    break;
688     }
689 
690     // Probabilities of each.
691     int		curse, normal, bless;
692 
693     curse = glb_cursechancedefs[cursechance].curse;
694     normal = glb_cursechancedefs[cursechance].normal;
695     bless = glb_cursechancedefs[cursechance].bless;
696 
697     UT_ASSERT(curse + normal + bless == 100);
698     int		percent;
699     percent = rand_choice(100);
700     if (!nocurse)
701     {
702 	if (percent < curse)
703 	    item->myFlag1 = (ITEMFLAG1_NAMES) (item->myFlag1 | ITEMFLAG1_ISCURSED);
704 	else if (percent < curse + bless)
705 	    item->myFlag1 = (ITEMFLAG1_NAMES) (item->myFlag1 | ITEMFLAG1_ISBLESSED);
706     }
707 
708     // Determine enchantment.  Only certain types of items will
709     // have a default enchantment.
710     // You can enchant anything, however.
711     if (item->isBoots() || item->isHelmet() || item->isShield() ||
712 	item->isJacket() || item->isWeapon())
713     {
714 	// Armour enchant or weapon
715 	// We have a 10% chance of +/-, 50-50 for each.
716 	// This gives 1% for +2 or -2, 18% chance for +1 and 18% chance for -1.
717 	// Bah, not very good.  This makes 40% of items enchanted...
718 	// Thus, we hard code:
719 	// 1% +2
720 	// 9% +1
721 	// 9% -1
722 	// 1% -2
723 	// This is also silly, as we get limitted to +/-2.
724 	// Instead, just use a power distribution and have 10% less chance
725 	// for every bonus.
726 	// The major flaw with this is that we go from a 20% enchanted
727 	// to a 10% enchanted.  Thus, we encompsass the first test
728 	// with a 20% check.
729 
730 	// Randomly determine if we will increase or decrease the enchantment.
731 	int			enchantdir;
732 	if (rand_choice(2))
733 	    enchantdir = 1;
734 	else
735 	    enchantdir = -1;
736 
737 	item->myEnchantment = 0;
738 
739 	if (rand_chance(20))
740 	{
741 	    item->enchant(enchantdir);
742 
743 	    // Each additional level of enchantment has 10% chance of going
744 	    // through.
745 	    // This loop will terminate.  I hope.
746 	    // Call me paranoid...
747 	    int		maxenchant = 50;
748 	    while (rand_chance(10))
749 	    {
750 		item->enchant(enchantdir);
751 		maxenchant--;
752 		if (!maxenchant)
753 		{
754 		    UT_ASSERT(!"Excessive enchantment!");
755 		    break;
756 		}
757 	    }
758 	}
759 
760 	// If the enchantment was negative, we get an extra 30% chance
761 	// of it being (more) cursed.
762 	if (item->myEnchantment < 0 && rand_chance(30))
763 	    item->makeCursed();
764 	// Otherwise, if it is positive, there is a chance for blessed.
765 	if (item->myEnchantment > 0 && rand_chance(30))
766 	    item->makeBlessed();
767     }
768 
769     // Add in charges...
770     if (item->getMagicType() == MAGICTYPE_WAND)
771     {
772 	item->myCharges = rand_dice(glb_wanddefs[item->getMagicClass()].charges);
773     }
774 
775     if (item->getMagicType() == MAGICTYPE_SPELLBOOK)
776     {
777 	item->myCharges = rand_dice(glb_spellbookdefs[item->getMagicClass()].charges);
778     }
779 
780     // One in a hundred mundanes is a real artifact!  Woot!
781     if (allowartifact && rand_chance(1))
782 	item->makeArtifact();
783 
784     return item;
785 }
786 
787 ITEM_NAMES
lookupMagicItem(MAGICTYPE_NAMES magictype,int magicclass)788 ITEM::lookupMagicItem(MAGICTYPE_NAMES magictype, int magicclass)
789 {
790     int		itemtype;
791 
792     for (itemtype = 0; itemtype < NUM_ITEMS; itemtype++)
793     {
794 	if (glb_itemdefs[itemtype].magictype == magictype)
795 	{
796 	    if (glb_magicitem[itemtype] == magicclass)
797 	    {
798 		return (ITEM_NAMES) itemtype;
799 	    }
800 	}
801     }
802 
803     return ITEM_NONE;
804 }
805 
806 ITEM *
createMagicItem(MAGICTYPE_NAMES magictype,int magicclass,bool allowartifact,bool nocurse)807 ITEM::createMagicItem(MAGICTYPE_NAMES magictype, int magicclass,
808 		      bool allowartifact,
809 		      bool nocurse)
810 {
811     ITEM_NAMES	item;
812 
813     item = lookupMagicItem(magictype, magicclass);
814     if (item != ITEM_NONE)
815         return ITEM::create(item, allowartifact, nocurse);
816 
817     return 0;
818 }
819 
820 ITEM *
createRandom(bool allowartifact)821 ITEM::createRandom(bool allowartifact)
822 {
823     int		table[NUM_ITEMS];
824     int		i, max;
825     int		prob;
826 
827     max = 0;
828     for (i = 0; i < NUM_ITEMS; i++)
829     {
830 	if (glb_itemdefs[i].magictype == MAGICTYPE_SCROLL)
831 	    prob = glb_scrolldefs[glb_magicitem[i]].rarity;
832 	else
833 	    prob = glb_itemdefs[i].rarity;
834 
835 	prob *= ((int)glb_itemtypedefs[glb_itemdefs[i].itemtype].rarity);
836 	table[i] = prob;
837 	max += prob;
838     }
839 
840     return createRandomFromTable(table, max, allowartifact);
841 }
842 
843 ITEM *
createRandomType(ITEMTYPE_NAMES type,bool allowartifact)844 ITEM::createRandomType(ITEMTYPE_NAMES type, bool allowartifact)
845 {
846     int		table[NUM_ITEMS];
847     int		i, max;
848     int		prob;
849 
850     // Special case item types.
851     if (type == ITEMTYPE_ANY)
852 	return ITEM::createRandom(allowartifact);
853 
854     if (type == ITEMTYPE_ARTIFACT)
855     {
856 	ITEM		*item;
857 
858 	item = ITEM::createRandom(false);
859 	item->makeArtifact();
860 	return item;
861     }
862 
863     max = 0;
864     for (i = 0; i < NUM_ITEMS; i++)
865     {
866 	if (glb_itemdefs[i].itemtype == type)
867 	{
868 	    if (glb_itemdefs[i].magictype == MAGICTYPE_SCROLL)
869 		prob = glb_scrolldefs[glb_magicitem[i]].rarity;
870 	    else
871 		prob = glb_itemdefs[i].rarity;
872 	}
873 	else
874 	    prob = 0;
875 
876 	table[i] = prob;
877 	max += prob;
878     }
879 
880     return createRandomFromTable(table, max, allowartifact);
881 }
882 
883 ITEM *
createRandomFromTable(int * table,int max_prob,bool allowartifact)884 ITEM::createRandomFromTable(int *table, int max_prob, bool allowartifact)
885 {
886     int		item, i;
887 
888     if (!max_prob)
889     {
890 	UT_ASSERT(!"No such items.");
891 	return 0;
892     }
893 
894     item = rand_choice(max_prob);
895     for (i = 0; i < NUM_ITEMS; i++)
896     {
897 	item -= table[i];
898 	if (item < 0)
899 	    return create((ITEM_NAMES) i, allowartifact);
900     }
901 
902     UT_ASSERT(!"Could not find item!");
903     return 0;
904 }
905 
906 ITEM *
createCorpse(MOB * mob)907 ITEM::createCorpse(MOB *mob)
908 {
909     ITEM		*item;
910 
911     item = ITEM::create(ITEM_CORPSE, false);
912     item->myCorpseMob.setMob(mob);
913 
914     item->myCharges = 20;
915 
916     // Boneless critters get extra time as corpses as they have
917     // no skeleton state.
918     if (mob->isBoneless())
919 	item->myCharges += 20;
920 
921     return item;
922 }
923 
924 ITEM *
createStatue(MOB * mob)925 ITEM::createStatue(MOB *mob)
926 {
927     ITEM		*item;
928 
929     item = ITEM::create(ITEM_STATUE, false);
930     item->myCorpseMob.setMob(mob);
931 
932     return item;
933 }
934 
935 void
setPos(int x,int y)936 ITEM::setPos(int x, int y)
937 {
938     myX = x;
939     myY = y;
940 }
941 
942 void
enchant(int delta)943 ITEM::enchant(int delta)
944 {
945     int		newval;
946 
947     newval = myEnchantment + delta;
948 
949     if (newval < -99)
950 	newval = -99;
951     if (newval > 99)
952 	newval = 99;
953 
954     myEnchantment = newval;
955 }
956 
957 void
makeArtifact(const char * name)958 ITEM::makeArtifact(const char *name)
959 {
960     myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISARTIFACT);
961 
962     if (!name)
963 	rename(artifact_buildname(getDefinition()));
964     else
965 	rename(name);
966 }
967 
968 void
makeVanilla()969 ITEM::makeVanilla()
970 {
971     // Ensure it isn't artifact.
972     myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISARTIFACT);
973     rename(0);
974     makePoisoned(POISON_NONE, 0);
975     myEnchantment = 0;
976     myCharges = 0;
977 
978     // Ensure neither bless nor cursed.
979     myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISBLESSED);
980     myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISCURSED);
981 }
982 
983 bool
doHeartbeat(MAP * map,MOB * owner)984 ITEM::doHeartbeat(MAP *map, MOB *owner)
985 {
986     // Determine if we are in a proper phase.
987     if (!speed_isheartbeatphase())
988 	return true;
989 
990     // Run mind acid decay...
991     if (myDefinition == ITEM_MINDACIDHAND)
992     {
993 	if (myCharges)
994 	    myCharges--;
995 	else
996 	{
997 	    // Has fully decayed...
998 	    // The owner is confused.
999 	    if (owner)
1000 	    {
1001 		owner->formatAndReport("Mind-acid soaks into %R skin.");
1002 
1003 		owner->setTimedIntrinsic(owner, INTRINSIC_CONFUSED,
1004 					rand_dice(3, 5, 10));
1005 	    }
1006 
1007 	    // Request deletion.
1008 	    return false;
1009 	}
1010     }
1011 
1012     // Run decay...
1013     if (myDefinition == ITEM_CORPSE ||
1014 	myDefinition == ITEM_BONES)
1015     {
1016 	// Check for the "preserved" bit...
1017 	if (myCharges == 255)
1018 	    return true;
1019 
1020 	if (myCharges)
1021 	    myCharges--;
1022 	else
1023 	{
1024 	    // Has fully decayed...
1025 	    if (myDefinition == ITEM_CORPSE)
1026 	    {
1027 		// We may want to resurrect ourselves.
1028 		MOB		*mob;
1029 
1030 		mob = myCorpseMob.getMob();
1031 		if (mob)
1032 		{
1033 		    if (mob->canResurrectFromCorpse())
1034 		    {
1035 			// Trigger resurrection on self.
1036 			if (owner)
1037 			{
1038 			    if (resurrect(glbCurLevel, mob,
1039 					    owner->getX(), owner->getY()))
1040 			    {
1041 				return false;
1042 			    }
1043 			}
1044 			else
1045 			{
1046 			    if (resurrect(glbCurLevel, mob,
1047 					    getX(), getY()))
1048 			    {
1049 				return false;
1050 			    }
1051 			}
1052 		    }
1053 
1054 		    if (mob->isBoneless())
1055 		    {
1056 			// Don't create bones...
1057 			return false;
1058 		    }
1059 		}
1060 
1061 		myDefinition = ITEM_BONES;
1062 		myCharges = 20;
1063 	    }
1064 	    else
1065 	    {
1066 		// Erase.
1067 		return false;
1068 	    }
1069 	}
1070     }
1071 
1072     return true;
1073 }
1074 
1075 MATERIAL_NAMES
getMaterial() const1076 ITEM::getMaterial() const
1077 {
1078     // If we are a corpse, inherit from our base type.
1079     MOB		*corpse;
1080 
1081     corpse = getCorpseMob();
1082     if (corpse)
1083     {
1084 	return corpse->getMaterial();
1085     }
1086     return (MATERIAL_NAMES) glb_itemdefs[myDefinition].material;
1087 }
1088 
1089 ATTACK_NAMES
getAttackName() const1090 ITEM::getAttackName() const
1091 {
1092     return (ATTACK_NAMES) glb_itemdefs[myDefinition].attack;
1093 }
1094 
1095 ATTACK_NAMES
getThrownAttackName() const1096 ITEM::getThrownAttackName() const
1097 {
1098     return (ATTACK_NAMES) glb_itemdefs[myDefinition].thrownattack;
1099 }
1100 
1101 SKILL_NAMES
getAttackSkill() const1102 ITEM::getAttackSkill() const
1103 {
1104     return (SKILL_NAMES) glb_itemdefs[myDefinition].attackskill;
1105 }
1106 
1107 SKILL_NAMES
getSpecialSkill() const1108 ITEM::getSpecialSkill() const
1109 {
1110     return (SKILL_NAMES) glb_itemdefs[myDefinition].specialskill;
1111 }
1112 
1113 const ATTACK_DEF *
getAttack() const1114 ITEM::getAttack() const
1115 {
1116     const ARTIFACT	*art;
1117 
1118     art = getArtifact();
1119 
1120     if (art && art->hasattack)
1121     {
1122 	return &art->attack;
1123     }
1124 
1125     return &glb_attackdefs[glb_itemdefs[myDefinition].attack];
1126 }
1127 
1128 const ATTACK_DEF *
getThrownAttack() const1129 ITEM::getThrownAttack() const
1130 {
1131     const ARTIFACT	*art;
1132 
1133     art = getArtifact();
1134 
1135     if (art && art->hasthrownattack)
1136     {
1137 	return &art->thrownattack;
1138     }
1139 
1140     return &glb_attackdefs[glb_itemdefs[myDefinition].thrownattack];
1141 }
1142 
1143 bool
requiresLauncher() const1144 ITEM::requiresLauncher() const
1145 {
1146     if (glb_itemdefs[myDefinition].launcher == ITEM_NONE)
1147 	return false;
1148 
1149     return true;
1150 }
1151 
1152 bool
canLaunchThis(ITEM * launcher) const1153 ITEM::canLaunchThis(ITEM *launcher) const
1154 {
1155     if (!launcher)
1156 	return false;
1157 
1158     if (launcher->getDefinition() == glb_itemdefs[myDefinition].launcher)
1159 	return true;
1160 
1161     return false;
1162 }
1163 
1164 SIZE_NAMES
getSize() const1165 ITEM::getSize() const
1166 {
1167     return (SIZE_NAMES) glb_itemdefs[myDefinition].size;
1168 }
1169 
1170 int
getNoiseLevel() const1171 ITEM::getNoiseLevel() const
1172 {
1173     return glb_itemdefs[myDefinition].noise;
1174 }
1175 
1176 MOB *
getCorpseMob() const1177 ITEM::getCorpseMob() const
1178 {
1179     if (myDefinition != ITEM_CORPSE &&
1180 	myDefinition != ITEM_BONES)
1181 	return 0;
1182     return myCorpseMob.getMob();
1183 }
1184 
1185 MOB *
getStatueMob() const1186 ITEM::getStatueMob() const
1187 {
1188     if (myDefinition != ITEM_STATUE)
1189 	return 0;
1190 
1191     return myCorpseMob.getMob();
1192 }
1193 
1194 int
calcAverageDamage() const1195 ITEM::calcAverageDamage() const
1196 {
1197     ATTACK_NAMES	 same;
1198     int			 dam = 0;
1199     const ATTACK_DEF	*attack, *sameattack;
1200 
1201     attack = getAttack();
1202     while (attack)
1203     {
1204 	sameattack = attack;
1205 
1206 	while (sameattack)
1207 	{
1208 	    dam += (sameattack->damage.myNumdie *
1209 			(1 + sameattack->damage.mySides)) / 2;
1210 	    dam += sameattack->damage.myBonus;
1211 	    dam += getEnchantment();
1212 
1213 	    // Non physical attacks are always cooler.
1214 	    if (sameattack->element != ELEMENT_PHYSICAL)
1215 		dam += 2;
1216 
1217 	    same = (ATTACK_NAMES)sameattack->sameattack;
1218 	    if (same == ATTACK_NONE)
1219 		sameattack = 0;
1220 	    else
1221 		sameattack = &glb_attackdefs[same];
1222 	}
1223 	if (attack->nextattack == ATTACK_NONE)
1224 	    attack = 0;
1225 	else
1226 	    attack = &glb_attackdefs[attack->nextattack];
1227     }
1228 
1229     // Extra stuff: bonus for poisoned.
1230     if (isPoisoned())
1231     {
1232 	dam += 4;
1233     }
1234 
1235     // Being made of silver is just cool.
1236     if (getMaterial() == MATERIAL_SILVER)
1237     {
1238 	dam += 4;
1239     }
1240     return dam;
1241 }
1242 
1243 ITEMTYPE_NAMES
getItemType() const1244 ITEM::getItemType() const
1245 {
1246     return (ITEMTYPE_NAMES) glb_itemdefs[getDefinition()].itemtype;
1247 }
1248 
1249 bool
isCarryIntrinsic() const1250 ITEM::isCarryIntrinsic() const
1251 {
1252     const ARTIFACT		*art;
1253 
1254     // Artifacts may have carry intrinsics...
1255     art = getArtifact();
1256     if (art && art->iscarryintrinsic)
1257 	return true;
1258 
1259     return glb_itemdefs[myDefinition].iscarryintrinsic;
1260 }
1261 
1262 bool
isFullyIdentified() const1263 ITEM::isFullyIdentified() const
1264 {
1265     return isIdentified() && isKnownCursed() &&
1266 	   isKnownEnchant() && isKnownCharges() &&
1267 	   isKnownPoison();
1268 }
1269 
1270 bool
isIdentified() const1271 ITEM::isIdentified() const
1272 {
1273     return glb_itemid[myDefinition];
1274 }
1275 
1276 bool
isKnownCursed() const1277 ITEM::isKnownCursed() const
1278 {
1279     return (myFlag1 & ITEMFLAG1_ISKNOWCURSE) ? true : false;
1280 }
1281 
1282 bool
isKnownNotCursed() const1283 ITEM::isKnownNotCursed() const
1284 {
1285     return (myFlag1 & ITEMFLAG1_ISKNOWNOTCURSE) ? true : false;
1286 }
1287 
1288 bool
isKnownEnchant() const1289 ITEM::isKnownEnchant() const
1290 {
1291     return (myFlag1 & ITEMFLAG1_ISKNOWENCHANT) ? true : false;
1292 }
1293 
1294 bool
isKnownCharges() const1295 ITEM::isKnownCharges() const
1296 {
1297     return (myFlag1 & ITEMFLAG1_ISKNOWCHARGES) ? true : false;
1298 }
1299 
1300 bool
isKnownPoison() const1301 ITEM::isKnownPoison() const
1302 {
1303     return (myFlag1 & ITEMFLAG1_ISKNOWPOISON) ? true : false;
1304 }
1305 
1306 bool
isKnownClass() const1307 ITEM::isKnownClass() const
1308 {
1309     if (glb_itemid[myDefinition])
1310 	return true;
1311     return false;
1312 }
1313 
1314 bool
isInventory() const1315 ITEM::isInventory() const
1316 {
1317     return (myFlag1 & ITEMFLAG1_ISINVENTORY) ? true : false;
1318 }
1319 
1320 bool
isArtifact() const1321 ITEM::isArtifact() const
1322 {
1323     return (myFlag1 & ITEMFLAG1_ISARTIFACT) ? true : false;
1324 }
1325 
1326 const ARTIFACT *
getArtifact() const1327 ITEM::getArtifact() const
1328 {
1329     if (!isArtifact())
1330 	return 0;
1331 
1332     return artifact_buildartifact(myName.getName(), getDefinition());
1333 }
1334 
1335 void
setInventory(bool isinventory)1336 ITEM::setInventory(bool isinventory)
1337 {
1338     if (isinventory)
1339 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISINVENTORY);
1340     else
1341 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISINVENTORY);
1342 }
1343 
1344 void
markIdentified(bool silent)1345 ITEM::markIdentified(bool silent)
1346 {
1347     markEnchantKnown();
1348     markCursedKnown();
1349     markChargesKnown();
1350     markPoisonKnown();
1351 
1352     markClassKnown(silent);
1353 }
1354 
1355 void
markClassKnown(bool silent)1356 ITEM::markClassKnown(bool silent)
1357 {
1358     // Avatar gets piety for this.
1359     if (!glb_itemid[myDefinition])
1360     {
1361 	MOB		*avatar;
1362 
1363 	avatar = MOB::getAvatar();
1364 	if (avatar)
1365 	{
1366 	    // Only spam for interesting class changes.
1367 	    if (!silent && getMagicType() != MAGICTYPE_NONE)
1368 		avatar->formatAndReport("%U <learn> that %IU <I:be> %Ii.", this);
1369 	    avatar->pietyIdentify((ITEM_NAMES) myDefinition);
1370 	}
1371     }
1372 
1373     glb_itemid[myDefinition] = 1;
1374 }
1375 
1376 void
markEnchantKnown()1377 ITEM::markEnchantKnown()
1378 {
1379     myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISKNOWENCHANT);
1380 }
1381 
1382 void
markCursedKnown()1383 ITEM::markCursedKnown()
1384 {
1385     myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISKNOWCURSE);
1386 }
1387 
1388 void
markNotCursedKnown(bool newknown)1389 ITEM::markNotCursedKnown(bool newknown)
1390 {
1391     if (newknown)
1392 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISKNOWNOTCURSE);
1393     else
1394 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISKNOWNOTCURSE);
1395 }
1396 
1397 void
markChargesKnown()1398 ITEM::markChargesKnown()
1399 {
1400     myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISKNOWCHARGES);
1401 }
1402 
1403 void
clearChargesKnown()1404 ITEM::clearChargesKnown()
1405 {
1406     myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & (~ITEMFLAG1_ISKNOWCHARGES));
1407 }
1408 
1409 void
markPoisonKnown()1410 ITEM::markPoisonKnown()
1411 {
1412     myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISKNOWPOISON);
1413 }
1414 
1415 void
makeCursed()1416 ITEM::makeCursed()
1417 {
1418     if (myFlag1 & ITEMFLAG1_ISBLESSED)
1419 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISBLESSED);
1420     else
1421 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISCURSED);
1422 
1423     // Regardless, anyone's theories about this are now wrong.
1424     // One could argue we should not clear this flag as if they
1425     // cursing was obvious we usually do a markCursedKnown, so if
1426     // that is not done it is truly the avatar that doesn't know
1427     // the change, and hence the player shouldn't as well.
1428     // For now, I consider that logic too mean.
1429     markNotCursedKnown(false);
1430 }
1431 
1432 void
makeBlessed()1433 ITEM::makeBlessed()
1434 {
1435     if (myFlag1 & ITEMFLAG1_ISCURSED)
1436 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISCURSED);
1437     else
1438 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISBLESSED);
1439 }
1440 
1441 void
makePoisoned(POISON_NAMES poison,int charges)1442 ITEM::makePoisoned(POISON_NAMES poison, int charges)
1443 {
1444     myPoison = poison;
1445     myPoisonCharges = charges;
1446 }
1447 
1448 bool
isPoisoned() const1449 ITEM::isPoisoned() const
1450 {
1451     if (myPoison != POISON_NONE && myPoisonCharges)
1452 	return true;
1453     return false;
1454 }
1455 
1456 void
applyPoison(MOB * src,MOB * target,bool force)1457 ITEM::applyPoison(MOB *src, MOB *target, bool force)
1458 {
1459     if (!force && rand_choice(glb_poisondefs[myPoison].modulus))
1460 	return;
1461 
1462     if (!isPoisoned())
1463 	return;
1464 
1465     // Is this a sensible time?
1466     target->setTimedIntrinsic( src, (INTRINSIC_NAMES)
1467 				glb_poisondefs[myPoison].intrinsic,
1468 				rand_dice(3, 3, 0) );
1469 
1470     myPoisonCharges--;
1471 }
1472 
1473 bool
isCursed() const1474 ITEM::isCursed() const
1475 {
1476     return (myFlag1 & ITEMFLAG1_ISCURSED) ? true : false;
1477 }
1478 
1479 bool
isBlessed() const1480 ITEM::isBlessed() const
1481 {
1482     return (myFlag1 & ITEMFLAG1_ISBLESSED) ? true : false;
1483 }
1484 
1485 bool
isQuivered() const1486 ITEM::isQuivered() const
1487 {
1488     return (myFlag1 & ITEMFLAG1_ISQUIVERED) ? true : false;
1489 }
1490 
1491 void
markQuivered(bool newquiver)1492 ITEM::markQuivered(bool newquiver)
1493 {
1494     if (newquiver)
1495 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISQUIVERED);
1496     else
1497 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISQUIVERED);
1498 
1499 }
1500 
1501 bool
isFavorite() const1502 ITEM::isFavorite() const
1503 {
1504     return (myFlag1 & ITEMFLAG1_ISFAVORITE) ? true : false;
1505 }
1506 
1507 void
markFavorite(bool newfavorite)1508 ITEM::markFavorite(bool newfavorite)
1509 {
1510     if (newfavorite)
1511 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISFAVORITE);
1512     else
1513 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISFAVORITE);
1514 
1515 }
1516 
1517 bool
isMapped() const1518 ITEM::isMapped() const
1519 {
1520     return (myFlag1 & ITEMFLAG1_ISMAPPED) ? true : false;
1521 }
1522 
1523 void
markMapped(bool val)1524 ITEM::markMapped(bool val)
1525 {
1526     if (val)
1527 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISMAPPED);
1528     else
1529 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISMAPPED);
1530 }
1531 
1532 bool
isBelowGrade() const1533 ITEM::isBelowGrade() const
1534 {
1535     return (myFlag1 & ITEMFLAG1_ISBELOWGRADE) ? true : false;
1536 }
1537 
1538 void
markBelowGrade(bool val)1539 ITEM::markBelowGrade(bool val)
1540 {
1541     if (val)
1542 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 | ITEMFLAG1_ISBELOWGRADE);
1543     else
1544 	myFlag1 = (ITEMFLAG1_NAMES) (myFlag1 & ~ITEMFLAG1_ISBELOWGRADE);
1545 }
1546 
1547 bool
isWeapon() const1548 ITEM::isWeapon() const
1549 {
1550     // Not the simplest of computation as we can equip anything...
1551     if (getAttackName() != ATTACK_MISUSED)
1552 	return true;
1553     return false;
1554 }
1555 
1556 bool
isArmor() const1557 ITEM::isArmor() const
1558 {
1559     return (myFlag1 & ITEMFLAG1_ARMORSLOTMASK) ? true : false;
1560 }
1561 
1562 bool
isBoots() const1563 ITEM::isBoots() const
1564 {
1565     return (myFlag1 & ITEMFLAG1_ARMORSLOTMASK) == ITEMFLAG1_ISBOOTS;
1566 }
1567 
1568 bool
isHelmet() const1569 ITEM::isHelmet() const
1570 {
1571     return (myFlag1 & ITEMFLAG1_ARMORSLOTMASK) == ITEMFLAG1_ISHELMET;
1572 }
1573 
1574 bool
isJacket() const1575 ITEM::isJacket() const
1576 {
1577     return (myFlag1 & ITEMFLAG1_ARMORSLOTMASK) == ITEMFLAG1_ISJACKET;
1578 }
1579 
1580 bool
isShield() const1581 ITEM::isShield() const
1582 {
1583     return (myFlag1 & ITEMFLAG1_ARMORSLOTMASK) == ITEMFLAG1_ISSHIELD;
1584 }
1585 
1586 bool
isRing() const1587 ITEM::isRing() const
1588 {
1589     return (myFlag1 & ITEMFLAG1_ARMORSLOTMASK) == ITEMFLAG1_ISRING;
1590 }
1591 
1592 bool
isAmulet() const1593 ITEM::isAmulet() const
1594 {
1595     return (myFlag1 & ITEMFLAG1_ARMORSLOTMASK) == ITEMFLAG1_ISAMULET;
1596 }
1597 
1598 bool
isPassable() const1599 ITEM::isPassable() const
1600 {
1601     return !(myFlag1 & ITEMFLAG1_ISBLOCKING);
1602 }
1603 
1604 int
getStackOrder() const1605 ITEM::getStackOrder() const
1606 {
1607     // This is used to force the sorting of items.  We want users
1608     // to quickly see if there are interesting drops so put corpses
1609     // on the bottom.  Likewise, impassable objects need to be known
1610     // or people won't know why they can't move there - this currently
1611     // only means boulders.
1612     // Finally, artifacts are put on the top to draw attention to them
1613     // as they are cool.
1614     if (myDefinition == ITEM_CORPSE ||
1615 	myDefinition == ITEM_BONES)
1616     {
1617 	return 0;
1618     }
1619 
1620     if (!isPassable())
1621 	return 3;
1622 
1623     if (isArtifact())
1624 	return 2;
1625 
1626     // Default level.
1627     return 1;
1628 }
1629 
1630 const char *
getItemName(ITEM_NAMES item,bool forceid)1631 ITEM::getItemName(ITEM_NAMES item, bool forceid)
1632 {
1633     const char		*rawname = 0;
1634 
1635     if (forceid || glb_itemid[item])
1636     {
1637 	switch ((MAGICTYPE_NAMES) glb_itemdefs[item].magictype)
1638 	{
1639 	    case NUM_MAGICTYPES:
1640 	    case MAGICTYPE_NONE:
1641 		rawname = glb_itemdefs[item].name;
1642 		break;
1643 
1644 	    case MAGICTYPE_POTION:
1645 		rawname = glb_potiondefs[glb_magicitem[item]].name;
1646 		break;
1647 
1648 	    case MAGICTYPE_SCROLL:
1649 		rawname = glb_scrolldefs[glb_magicitem[item]].name;
1650 		break;
1651 
1652 	    case MAGICTYPE_RING:
1653 		rawname = glb_ringdefs[glb_magicitem[item]].name;
1654 		break;
1655 
1656 	    case MAGICTYPE_HELM:
1657 		rawname = glb_helmdefs[glb_magicitem[item]].name;
1658 		break;
1659 
1660 	    case MAGICTYPE_BOOTS:
1661 		rawname = glb_bootsdefs[glb_magicitem[item]].name;
1662 		break;
1663 
1664 	    case MAGICTYPE_AMULET:
1665 		rawname = glb_amuletdefs[glb_magicitem[item]].name;
1666 		break;
1667 
1668 	    case MAGICTYPE_WAND:
1669 		rawname = glb_wanddefs[glb_magicitem[item]].name;
1670 		break;
1671 
1672 	    case MAGICTYPE_SPELLBOOK:
1673 		rawname = glb_spellbookdefs[glb_magicitem[item]].name;
1674 		break;
1675 
1676 	    case MAGICTYPE_STAFF:
1677 		rawname = glb_staffdefs[glb_magicitem[item]].name;
1678 		break;
1679 	}
1680     }
1681     else
1682     {
1683 	rawname = glb_itemdefs[item].name;
1684     }
1685 
1686     return rawname;
1687 }
1688 
1689 const char *
getRawName(bool idclass) const1690 ITEM::getRawName(bool idclass) const
1691 {
1692     const char		*rawname = 0;
1693 
1694     rawname = ITEM::getItemName(getDefinition(), idclass);
1695 
1696     return rawname;
1697 }
1698 
1699 BUF
getName(bool article,bool shortname,bool neverpronoun,bool idclass,bool forcesingle) const1700 ITEM::getName(bool article, bool shortname, bool neverpronoun, bool idclass, bool forcesingle) const
1701 {
1702     BUF			 rawname;
1703     bool		 ignorecurse = false;
1704     BUF			 result;
1705 
1706     rawname.reference(getRawName(idclass));
1707 
1708     // In some cases, the actual name comes from what mob it actually is.
1709     if (myDefinition == ITEM_BONES || myDefinition == ITEM_CORPSE ||
1710 	myDefinition == ITEM_STATUE)
1711     {
1712 	MOB		*mob;
1713 
1714 	mob = myCorpseMob.getMob();
1715 	if (mob)
1716 	{
1717 	    BUF		buf, mobname;
1718 
1719 	    mobname = mob->getName(false, false, true);
1720 
1721 	    buf.sprintf("%s%s %s",
1722 			(myCharges == 255 ? "preserved " : ""),
1723 			mobname.buffer(), rawname.buffer());
1724 	    rawname = buf;
1725 	}
1726     }
1727 
1728     // We have a special case off the front here.  We don't want blessed
1729     // bottles of water to be "a holy bottle of water", but rather be
1730     // "a bottle of holy water".  This is because it is the water that
1731     // is affected, not the bottle.
1732     if (myDefinition == ITEM_WATER)
1733     {
1734 	if (isKnownCursed())
1735 	{
1736 	    if (isCursed())
1737 		rawname.reference("bottle of unholy water");
1738 	    if (isBlessed())
1739 		rawname.reference("bottle of holy water");
1740 
1741 	    ignorecurse = true;
1742 	}
1743     }
1744 
1745     // NB: This must handle every case which causes further tmp buffers
1746     // to be needed.
1747     if (!article &&
1748 	(forcesingle || (getStackCount() == 1)) &&
1749 	(shortname ||
1750 		((!isKnownCursed() || ignorecurse) &&
1751 		 !isKnownEnchant() && !isKnownCharges() &&
1752 		 !isKnownPoison() && !glb_itemnames[myDefinition] &&
1753 		 !myName.getName())))
1754     {
1755 	return rawname;
1756     }
1757 
1758     BUF			buf;
1759 
1760     if (shortname ||
1761 	    ((!isKnownCursed() || ignorecurse) && !isKnownEnchant() && !isKnownCharges() && !isKnownPoison() && !glb_itemnames[myDefinition] && !myName.getName()))
1762     {
1763 	// We require an article, but that is it.
1764 	return gram_createcount(rawname, forcesingle ? 1 : getStackCount(), article);
1765     }
1766     else
1767     {
1768 	// We first build the name without the article, as the prefix
1769 	// may alter what the proper article is.  Eg: an evil sword.
1770 	// The problem with this are cases where there should
1771 	// be no article - in these cases, the presence of the prefix
1772 	// may trick us into adding an unnecessary article, Eg:
1773 	// an evil Baezl'bub's black heart.
1774 	BUF		nonarticle;
1775 
1776 	nonarticle.clear();
1777 
1778 	if (isKnownCursed() && !ignorecurse)
1779 	{
1780 	    if (isCursed())
1781 		nonarticle.strcat("evil ");
1782 	    if (isBlessed())
1783 		nonarticle.strcat("holy ");
1784 	}
1785 
1786 	if (isKnownPoison() && isPoisoned())
1787 	{
1788 	    nonarticle.strcat("poisoned ");
1789 	}
1790 
1791 	if (isKnownEnchant())
1792 	{
1793 	    // Don't waste space on +0 unless something where that
1794 	    // counts.
1795 	    if (getEnchantment() != 0 ||
1796 		isBoots() || isHelmet() || isShield() ||
1797 		isJacket() || isWeapon())
1798 	    {
1799 		BUF		tmp;
1800 
1801 		tmp.sprintf("%+d ", getEnchantment());
1802 		nonarticle.strcat(tmp);
1803 	    }
1804 	}
1805 
1806 	nonarticle.strcat(rawname);
1807 
1808 	if (article && isArtifact() && (forcesingle || (getStackCount() == 1)))
1809 	{
1810 	    buf.strcpy("the ");
1811 	    buf.strcat(nonarticle);
1812 	}
1813 	else
1814 	{
1815 	    buf = gram_createcount(nonarticle, forcesingle ? 1 : getStackCount(), article);
1816 	}
1817 
1818 	// Now, we append the charge count if we know it, and the magictype
1819 	// is something with charges.  Currently, that means wands or
1820 	// spellbooks.
1821 	if (isKnownCharges() &&
1822 	    (getMagicType() == MAGICTYPE_WAND ||
1823 	     getMagicType() == MAGICTYPE_SPELLBOOK ||
1824 	     getDefinition() == ITEM_LIGHTNINGRAPIER))
1825 	{
1826 	    BUF			tmp;
1827 
1828 	    tmp.sprintf(" (%d)", myCharges);
1829 	    buf.strcat(tmp);
1830 	}
1831 
1832 	if (myName.getName())
1833 	{
1834 	    // User named items are called.  Artifact items
1835 	    // just *are* that name.  Ie: the long sword foobar.
1836 	    if (isArtifact())
1837 		buf.strcat(" ");
1838 	    else
1839 		buf.strcat(" called ");
1840 	    buf.strcat(myName.getName());
1841 	}
1842 	else if (glb_itemnames[myDefinition])
1843 	{
1844 	    buf.strcat(" named ");
1845 	    buf.strcat(glb_itemnames[myDefinition]);
1846 	}
1847     }
1848 
1849     return buf;
1850 }
1851 
1852 void
formatAndReport(const char * str)1853 ITEM::formatAndReport(const char *str)
1854 {
1855     formatAndReport(0, str);
1856 }
1857 
1858 void
formatAndReport(MOB * owner,const char * str)1859 ITEM::formatAndReport(MOB *owner, const char *str)
1860 {
1861     BUF		buf;
1862 
1863     if (!str)
1864 	return;
1865 
1866     // Ignore if we are loading so we don't spam about re-wetting
1867     // sunk treasure.
1868     if (MAP::isLoading())
1869 	return;
1870 
1871     buf = MOB::formatToString(str, 0, this, 0, 0);
1872 
1873     if (!owner && !isInventory())
1874     {
1875 	// Spam our report to the map
1876 	glbCurLevel->reportMessage(buf, getX(), getY());
1877     }
1878     else
1879     {
1880 	if (owner)
1881 	    owner->reportMessage(buf);
1882 	else if (MOB::getAvatar())
1883 	    MOB::getAvatar()->reportMessage(buf);
1884     }
1885 }
1886 
1887 void
viewDiscoveries()1888 ITEM::viewDiscoveries()
1889 {
1890     ITEM_NAMES		item;
1891     int			num = 0;
1892 
1893     // Written while waiting for C967 to show up in the line
1894     // at the passport office.
1895     gfx_pager_addtext("Your discoveries:");
1896     gfx_pager_newline();
1897     gfx_pager_separator();
1898 
1899     FOREACH_ITEM(item)
1900     {
1901 	// Check to see if this is a meaningful id
1902 	// Unlike nethack, I don't think iding longswords is interesting.
1903 	const char *basename, *idname;
1904 
1905 	idname = ITEM::getItemName(item);
1906 	basename = glb_itemdefs[item].name;
1907 	// No need for strcmp here since we are using the
1908 	// prebuilt tables.
1909 	if (idname != basename)
1910 	{
1911 	    BUF		buf;
1912 
1913 	    buf.sprintf("%s:", basename);
1914 	    gfx_pager_addtext(gram_capitalize(buf));
1915 	    gfx_pager_newline();
1916 	    buf.sprintf("  %s", idname);
1917 	    gfx_pager_addtext(gram_capitalize(buf));
1918 	    gfx_pager_newline();
1919 	    num++;
1920 	}
1921     }
1922 
1923     if (!num)
1924     {
1925 	gfx_pager_addtext("You have learned nothing.");
1926 	gfx_pager_newline();
1927     }
1928 
1929     gfx_pager_display();
1930 }
1931 
1932 void
viewDescription() const1933 ITEM::viewDescription() const
1934 {
1935     pageDescription(false);
1936 
1937     gfx_pager_display();
1938 }
1939 
1940 BUF
buildAttackName(const ATTACK_DEF * attack)1941 ITEM::buildAttackName(const ATTACK_DEF *attack)
1942 {
1943     BUF buf;
1944 
1945     buf.strcpy("");
1946     while (attack)
1947     {
1948 	BUF		section;
1949 	bool		skipbonus = false;
1950 
1951 	if (attack->damage.myNumdie)
1952 	{
1953 	    if (attack->damage.mySides < 2)
1954 	    {
1955 		// Constant damage.  Fold in the bonus damage
1956 		// and report just this.
1957 		section.sprintf("%d",
1958 			    attack->damage.myNumdie + attack->damage.myBonus);
1959 		skipbonus = true;
1960 		buf.strcat(section);
1961 	    }
1962 	    else
1963 	    {
1964 		section.sprintf("%d",
1965 			attack->damage.myNumdie);
1966 		buf.strcat(section);
1967 		section.sprintf("d%d",
1968 			attack->damage.mySides);
1969 		buf.strcat(section);
1970 	    }
1971 	}
1972 	if (!skipbonus && attack->damage.myBonus)
1973 	{
1974 	    section.sprintf("%+d",
1975 		attack->damage.myBonus);
1976 	    buf.strcat(section);
1977 	}
1978 	if (attack->bonustohit)
1979 	{
1980 	    section.sprintf("[%+d]", attack->bonustohit);
1981 	    buf.strcat(section);
1982 	}
1983 	section.sprintf(" (%s)", glb_elementdefs[attack->element].name);
1984 	buf.strcat(section);
1985 
1986 	if (attack->nextattack != ATTACK_NONE)
1987 	{
1988 	    buf.strcat(", {");
1989 
1990 	    section = buildAttackName(&glb_attackdefs[attack->nextattack]);
1991 	    buf.strcat(section);
1992 
1993 	    buf.strcat("}");
1994 	}
1995 
1996 	if (attack->sameattack != ATTACK_NONE)
1997 	{
1998 	    buf.strcat(", ");
1999 	    attack = &glb_attackdefs[attack->sameattack];
2000 	}
2001 	else
2002 	    attack = 0;
2003     }
2004 
2005     return buf;
2006 }
2007 
2008 void
pageDescription(bool brief) const2009 ITEM::pageDescription(bool brief) const
2010 {
2011     BUF			buf;
2012     int			skilllevel;
2013 
2014     gfx_pager_addtext(gram_capitalize(getName()));
2015     gfx_pager_newline();
2016 
2017     // Add the identify info.
2018     const ARTIFACT		*art = getArtifact();
2019     if ((isIdentified() && !art) ||
2020 	(isFullyIdentified() && art))
2021     {
2022 	bool		hasany = false;
2023 	INTRINSIC_NAMES	intrinsic;
2024 	const char 	*prequel;
2025 
2026 	if (!brief)
2027 	{
2028 	    gfx_pager_separator();
2029 	}
2030 
2031 	if (art)
2032 	    prequel = "This artifact grants ";
2033 	else
2034 	    prequel = "This item grants ";
2035 
2036 	for (intrinsic = INTRINSIC_NONE; intrinsic < NUM_INTRINSICS;
2037 		intrinsic = (INTRINSIC_NAMES) (intrinsic + 1))
2038 	{
2039 	    if (hasIntrinsic(intrinsic))
2040 	    {
2041 		if (!hasany)
2042 		{
2043 		    gfx_pager_addtext(prequel);
2044 		    hasany = true;
2045 		}
2046 		else
2047 		    gfx_pager_addtext(", ");
2048 
2049 		gfx_pager_addtext(glb_intrinsicdefs[intrinsic].name);
2050 	    }
2051 	}
2052 
2053 	// Light radius:
2054 	if (isLight())
2055 	{
2056 	    if (!hasany)
2057 	    {
2058 		gfx_pager_addtext(prequel);
2059 		hasany = true;
2060 	    }
2061 	    else
2062 		gfx_pager_addtext(", ");
2063 
2064 	    buf.sprintf("light radius %d", getLightRadius());
2065 	    gfx_pager_addtext(buf);
2066 	}
2067 
2068 	// Amour class
2069 	if (getAC())
2070 	{
2071 	    if (!hasany)
2072 	    {
2073 		gfx_pager_addtext(prequel);
2074 		hasany = true;
2075 	    }
2076 	    else
2077 		gfx_pager_addtext(", ");
2078 
2079 	    buf.sprintf("armour %d", getAC());
2080 	    gfx_pager_addtext(buf);
2081 	}
2082 
2083 	// Finish off the special stuff list, and go to mandatory list.
2084 	if (hasany)
2085 	{
2086 	    gfx_pager_addtext(".  ");
2087 	    gfx_pager_newline();
2088 	}
2089 
2090 	if (isCarryIntrinsic())
2091 	{
2092 	    gfx_pager_addtext("Intrinsics are granted by carrying this item.");
2093 	    gfx_pager_newline();
2094 	}
2095 
2096 	const ATTACK_DEF	*attack;
2097 
2098 	gfx_pager_addtext("Melee: ");
2099 	buf = buildAttackName(getAttack());
2100 	gfx_pager_addtext(buf);
2101 	gfx_pager_newline();
2102 
2103 	gfx_pager_addtext("Thrown ");
2104 	attack = getThrownAttack();
2105 
2106 	buf.sprintf("%d: ", attack->range);
2107 	gfx_pager_addtext(buf);
2108 
2109 	buf = buildAttackName(attack);
2110 	gfx_pager_addtext(buf);
2111 
2112 	gfx_pager_newline();
2113     }
2114 
2115     // Skip out here if brief.
2116     if (brief)
2117 	return;
2118 
2119     // Add the boring stats.
2120     gfx_pager_separator();
2121 
2122     buf.strcpy("Size: ");
2123     buf.strcat(gram_capitalize(glb_sizedefs[getSize()].name));
2124     gfx_pager_addtext(buf);
2125     gfx_pager_newline();
2126 
2127     buf.strcpy("Material: ");
2128     buf.strcat(gram_capitalize(glb_materialdefs[getMaterial()].name));
2129     gfx_pager_addtext(buf);
2130     gfx_pager_newline();
2131 
2132     buf.sprintf("Weight: %d",
2133 	    glb_itemdefs[getDefinition()].weight);
2134     gfx_pager_addtext(buf);
2135     gfx_pager_newline();
2136 
2137     const char *noisetext;
2138     switch (getNoiseLevel())
2139     {
2140 	case 0:
2141 	    noisetext = "Silent";
2142 	    break;
2143 	case 1:
2144 	    noisetext = "Quiet";
2145 	    break;
2146 	case 2:
2147 	    noisetext = "Average";
2148 	    break;
2149 	case 3:
2150 	    noisetext = "Loud";
2151 	    break;
2152 	default:
2153 	case 4:
2154 	    noisetext = "Very Loud";
2155 	    break;
2156     }
2157 
2158     buf.sprintf("Noise: %s", noisetext);
2159     gfx_pager_addtext(buf);
2160     gfx_pager_newline();
2161 
2162     gfx_pager_addtext("Attack Style: ");
2163     buf.strcpy(glb_skilldefs[getAttackSkill()].name);
2164     // Remove first space.
2165     {
2166 	char	*c;
2167 	for (c = buf.evildata(); *c && !isspace(*c); c++);
2168 	*c = '\0';
2169     }
2170     gfx_pager_addtext(buf);
2171     gfx_pager_newline();
2172 
2173     // Special skill, if any.
2174     if (getSpecialSkill() != SKILL_NONE)
2175     {
2176 	gfx_pager_addtext("Special Skill: ");
2177 	gfx_pager_addtext(glb_skilldefs[getSpecialSkill()].name);
2178 	gfx_pager_newline();
2179     }
2180 
2181     // Calculate your attack ability.
2182     skilllevel = MOB::getAvatar()->getWeaponSkillLevel(this, ATTACKSTYLE_MELEE);
2183     if (skilllevel)
2184     {
2185 	gfx_pager_addtext("Melee Skill: ");
2186 	while (skilllevel--)
2187 	{
2188 	    gfx_pager_addtext("*");
2189 	}
2190 	gfx_pager_newline();
2191     }
2192 
2193     skilllevel = MOB::getAvatar()->getWeaponSkillLevel(this, ATTACKSTYLE_THROWN);
2194     if (skilllevel)
2195     {
2196 	gfx_pager_addtext("Thrown Skill: ");
2197 	while (skilllevel--)
2198 	{
2199 	    gfx_pager_addtext("*");
2200 	}
2201 	gfx_pager_newline();
2202     }
2203 
2204     skilllevel = MOB::getAvatar()->getArmourSkillLevel(this);
2205     if (skilllevel)
2206     {
2207 	gfx_pager_addtext("Armour Skill: ");
2208 	while (skilllevel--)
2209 	{
2210 	    gfx_pager_addtext("*");
2211 	}
2212 	gfx_pager_newline();
2213     }
2214 
2215     // Add encyclopedia description.
2216     if (encyc_hasentry("ITEM", getDefinition()))
2217     {
2218 	gfx_pager_separator();
2219 	encyc_pageentry("ITEM", getDefinition());
2220     }
2221 
2222     // Add the magical encylopedia entry
2223     if (isIdentified() && getMagicType() != MAGICTYPE_NONE)
2224     {
2225 	if (encyc_hasentry(glb_magictypedefs[getMagicType()].cycname, getMagicClass()))
2226 	{
2227 	    gfx_pager_separator();
2228 	    encyc_pageentry(glb_magictypedefs[getMagicType()].cycname, getMagicClass());
2229 	}
2230     }
2231 }
2232 
2233 const char *
getPronoun() const2234 ITEM::getPronoun() const
2235 {
2236     return gram_getpronoun(getPerson());
2237 }
2238 
2239 const char *
getPossessive() const2240 ITEM::getPossessive() const
2241 {
2242     return gram_getpossessive(getPerson());
2243 }
2244 
2245 const char *
getReflexive() const2246 ITEM::getReflexive() const
2247 {
2248     return gram_getreflexive(getPerson());
2249 }
2250 
2251 const char *
getAccusative() const2252 ITEM::getAccusative() const
2253 {
2254     return gram_getaccusative(getPerson());
2255 }
2256 
2257 BUF
conjugate(const char * infinitive,bool past) const2258 ITEM::conjugate(const char *infinitive, bool past) const
2259 {
2260     return gram_conjugate(infinitive, getPerson(), past);
2261 }
2262 
2263 VERB_PERSON
getPerson() const2264 ITEM::getPerson() const
2265 {
2266     // Determine our plurality...
2267     if (myStackCount > 1)
2268     {
2269 	// We are stacked, we are plural no matter what...
2270 	return VERB_THEY;
2271     }
2272 
2273     const char		*name;
2274 
2275     // *cries*
2276     // Guess who called getPronoun inside of getName?
2277     name = getRawName();
2278 
2279     if (gram_isnameplural(name))
2280     {
2281 	return VERB_THEY;
2282     }
2283     return VERB_IT;
2284 }
2285 
2286 bool
isLight() const2287 ITEM::isLight() const
2288 {
2289     if (glb_itemdefs[myDefinition].lightradius)
2290 	return true;
2291 
2292     // Check for ring of light...
2293     if (getMagicType() == MAGICTYPE_RING &&
2294 	getMagicClass() == RING_LIGHT)
2295     {
2296 	return true;
2297     }
2298 
2299     const ARTIFACT 	*art;
2300     art = getArtifact();
2301 
2302     if (art && art->lightradius)
2303 	return true;
2304 
2305     return false;
2306 }
2307 
2308 int
getLightRadius() const2309 ITEM::getLightRadius() const
2310 {
2311     int		radius;
2312 
2313     radius = glb_itemdefs[myDefinition].lightradius;
2314 
2315     // Check for ring of light...
2316     if (getMagicType() == MAGICTYPE_RING &&
2317 	getMagicClass() == RING_LIGHT)
2318     {
2319 	if (radius < 3)
2320 	    radius = 3;
2321     }
2322 
2323     const ARTIFACT		*art;
2324 
2325     art = getArtifact();
2326     if (art)
2327     {
2328 	if (radius < art->lightradius)
2329 	    radius = art->lightradius;
2330     }
2331 
2332     return radius;
2333 }
2334 
2335 TILE_NAMES
getTile() const2336 ITEM::getTile() const
2337 {
2338     return (TILE_NAMES) glb_itemdefs[myDefinition].tile;
2339 }
2340 
2341 MINI_NAMES
getMiniTile() const2342 ITEM::getMiniTile() const
2343 {
2344     return (MINI_NAMES) glb_itemdefs[myDefinition].minitile;
2345 }
2346 
2347 //
2348 // Stack Routines
2349 //
2350 
2351 bool
canMerge(ITEM * item) const2352 ITEM::canMerge(ITEM *item) const
2353 {
2354     // Verify we match on all particulars.
2355     if (item->myDefinition != myDefinition)
2356 	return false;
2357 
2358     // If either of our items have a name, we can't merge.
2359     if (item->myName.getName() || myName.getName())
2360     {
2361 	// However, if both have a name
2362 	if (item->myName.getName() && myName.getName())
2363 	{
2364 	    // And the names match
2365 	    if (!strcmp(item->myName.getName(), myName.getName()))
2366 	    {
2367 		// We can merge!
2368 	    }
2369 	    else
2370 		return false;
2371 	}
2372 	else
2373 	    return false;
2374     }
2375 
2376     // Prohibit merging of artifacts unless both are artifacts.
2377     // Otherwise, naming an item the same as an artifact would allow
2378     // the creation of artifacts.
2379     if (item->isArtifact() != isArtifact())
2380 	return false;
2381 
2382     // Prohibit merging of corpses!
2383     // This is required as we keep the mob * underneath them.
2384     // We also don't want to merge statues for the same reason.
2385     // Thus, if either item has a non-zero corpsemob, it is illegal.
2386     if (!item->myCorpseMob.isNull() || !myCorpseMob.isNull())
2387 	return false;
2388 
2389     if (item->myEnchantment != myEnchantment)
2390 	return false;
2391 
2392     if (item->myCharges != myCharges)
2393 	return false;
2394 
2395     if (item->myPoison != myPoison)
2396 	return false;
2397 
2398     if (item->myPoisonCharges != myPoisonCharges)
2399 	return false;
2400 
2401     // Flags are a bit trickier, as we only care about some of them.
2402 
2403     if (item->isBlessed() != isBlessed())
2404 	return false;
2405     if (item->isCursed() != isCursed())
2406 	return false;
2407 
2408     // We don't want to reveal curse states by merging, so known items
2409     // won't merge with unknown.
2410     if (item->isKnownCursed() != isKnownCursed())
2411 	return false;
2412     // We only care about enchantment amounts where it is armour or
2413     // weapon.
2414     if (getItemType() == ITEMTYPE_ARMOUR ||
2415 	getItemType() == ITEMTYPE_WEAPON)
2416     {
2417 	if (item->isKnownEnchant() != isKnownEnchant())
2418 	    return false;
2419     }
2420     // We only care about charges with books and wands...
2421     if (getItemType() == ITEMTYPE_SPELLBOOK ||
2422 	getItemType() == ITEMTYPE_WAND)
2423     {
2424 	if (item->isKnownCharges() != isKnownCharges())
2425 	    return false;
2426     }
2427     // We only care about poison if there is poison.  This does
2428     // let people id non-poisoned things but this is less of an
2429     // issue than the pain of detect curse not letting stuff stack.
2430     if (myPoisonCharges)
2431 	if (item->isKnownPoison() != isKnownPoison())
2432 	    return false;
2433 
2434     // Make sure a merge would not overflow our stack count.
2435     if (myStackCount + item->myStackCount > 99)
2436 	return false;
2437 
2438     // These items are indistinguishable, merge them!
2439     return true;
2440 }
2441 
2442 void
mergeStack(ITEM * item)2443 ITEM::mergeStack(ITEM *item)
2444 {
2445     UT_ASSERT(canMerge(item));
2446     UT_ASSERT(myStackCount + item->myStackCount <= 99);
2447 
2448     myStackCount += item->myStackCount;
2449 
2450     // Make sure we have the union of knowledge.
2451     // We don't want to lose any knowledge as a result of a merge,
2452     // even if that knowledge is deemed useless.
2453     if (item->isKnownCharges())
2454 	markChargesKnown();
2455     if (item->isKnownEnchant())
2456 	markEnchantKnown();
2457     if (item->isKnownPoison())
2458 	markPoisonKnown();
2459 }
2460 
2461 ITEM *
splitStack(int count)2462 ITEM::splitStack(int count)
2463 {
2464     UT_ASSERT(count > 0);
2465     UT_ASSERT(count < myStackCount);
2466 
2467     ITEM		*item;
2468 
2469     item = createClone();
2470     item->myStackCount = count;
2471     myStackCount -= count;
2472 
2473     return item;
2474 }
2475 
2476 void
splitAndDeleteStack(int count)2477 ITEM::splitAndDeleteStack(int count)
2478 {
2479     ITEM		*split;
2480 
2481     split = splitStack(count);
2482     delete split;
2483 }
2484 
2485 int
getAC() const2486 ITEM::getAC() const
2487 {
2488     int		ac;
2489 
2490     ac = glb_itemdefs[myDefinition].ac;
2491 
2492     // Enchantments...  Only counts if it is armour
2493     if (isBoots() || isHelmet() || isJacket() || isShield() || isAmulet())
2494     {
2495 	ac += getEnchantment();
2496     }
2497 
2498     // Add in the artifact bonus.
2499     const ARTIFACT		*art;
2500 
2501     art = getArtifact();
2502     if (art)
2503 	ac += art->acbonus;
2504 
2505     return ac;
2506 }
2507 
2508 int
getCoolness() const2509 ITEM::getCoolness() const
2510 {
2511     int		cool = 0;
2512 
2513     // Find coolness from magic type.
2514     switch (getMagicType())
2515     {
2516 	case MAGICTYPE_RING:
2517 	    cool += glb_ringdefs[getMagicClass()].coolness;
2518 	    break;
2519 	case MAGICTYPE_AMULET:
2520 	    cool += glb_amuletdefs[getMagicClass()].coolness;
2521 	    break;
2522 	default:
2523 	    break;
2524     }
2525 
2526     return cool;
2527 }
2528 
2529 int
getWeight() const2530 ITEM::getWeight() const
2531 {
2532     int		weight;
2533 
2534     weight = glb_itemdefs[myDefinition].weight;
2535 
2536     return weight;
2537 }
2538 
2539 int
getCharges() const2540 ITEM::getCharges() const
2541 {
2542     int		charges;
2543 
2544     charges = myCharges;
2545     return charges;
2546 }
2547 
2548 void
addCharges(int add)2549 ITEM::addCharges(int add)
2550 {
2551     int		charges;
2552 
2553     // Divide the charges among the number of items.
2554     add += getStackCount() / 2;
2555     add /= getStackCount();
2556     // Because I am nice, always restore one charge
2557     if (add < 1)
2558 	add = 1;
2559 
2560     charges = myCharges;
2561     charges += add;
2562 
2563     if (charges < 0)
2564 	charges = 0;
2565     if (charges > 99)
2566 	charges = 99;
2567 
2568     myCharges = charges;
2569 }
2570 
2571 void
useCharge()2572 ITEM::useCharge()
2573 {
2574     if (myCharges)
2575 	myCharges--;
2576 }
2577 
2578 void
setAsPreserved()2579 ITEM::setAsPreserved()
2580 {
2581     myCharges = 255;
2582 }
2583 
2584 MAGICTYPE_NAMES
getMagicType() const2585 ITEM::getMagicType() const
2586 {
2587     return (MAGICTYPE_NAMES) glb_itemdefs[myDefinition].magictype;
2588 }
2589 
2590 int
getMagicClass() const2591 ITEM::getMagicClass() const
2592 {
2593     return glb_magicitem[myDefinition];
2594 }
2595 
2596 void
buildIntrinsicTable(INTRINSIC * & intrinsic) const2597 ITEM::buildIntrinsicTable(INTRINSIC *&intrinsic) const
2598 {
2599     if (glb_itemdefs[myDefinition].intrinsic[0])
2600     {
2601 	if (!intrinsic)
2602 	    intrinsic = new INTRINSIC;
2603 	intrinsic->mergeFromString(glb_itemdefs[myDefinition].intrinsic);
2604     }
2605 
2606     // Try the artifact class.
2607     const ARTIFACT		*art;
2608 
2609     art = getArtifact();
2610     if (art && art->intrinsics)
2611     {
2612 	if (!intrinsic)
2613 	    intrinsic = new INTRINSIC;
2614 	intrinsic->mergeFromString(art->intrinsics);
2615     }
2616 
2617     // Try the magic item type...
2618     switch ((MAGICTYPE_NAMES) getMagicType())
2619     {
2620 	case MAGICTYPE_RING:
2621 	    if (glb_ringdefs[getMagicClass()].intrinsic[0])
2622 	    {
2623 		if (!intrinsic)
2624 		    intrinsic = new INTRINSIC;
2625 		intrinsic->mergeFromString(
2626 			glb_ringdefs[getMagicClass()].intrinsic);
2627 	    }
2628 	    break;
2629 	case MAGICTYPE_HELM:
2630 	    if (glb_helmdefs[getMagicClass()].intrinsic[0])
2631 	    {
2632 		if (!intrinsic)
2633 		    intrinsic = new INTRINSIC;
2634 		intrinsic->mergeFromString(
2635 			glb_helmdefs[getMagicClass()].intrinsic);
2636 	    }
2637 	    break;
2638 	case MAGICTYPE_BOOTS:
2639 	    if (glb_bootsdefs[getMagicClass()].intrinsic[0])
2640 	    {
2641 		if (!intrinsic)
2642 		    intrinsic = new INTRINSIC;
2643 		intrinsic->mergeFromString(
2644 			glb_bootsdefs[getMagicClass()].intrinsic);
2645 	    }
2646 	    break;
2647 	case MAGICTYPE_AMULET:
2648 	    if (glb_amuletdefs[getMagicClass()].intrinsic[0])
2649 	    {
2650 		if (!intrinsic)
2651 		    intrinsic = new INTRINSIC;
2652 		intrinsic->mergeFromString(
2653 			glb_amuletdefs[getMagicClass()].intrinsic);
2654 	    }
2655 	    break;
2656 	case MAGICTYPE_STAFF:
2657 	    if (glb_staffdefs[getMagicClass()].intrinsic[0])
2658 	    {
2659 		if (!intrinsic)
2660 		    intrinsic = new INTRINSIC;
2661 		intrinsic->mergeFromString(
2662 			glb_staffdefs[getMagicClass()].intrinsic);
2663 	    }
2664 	    break;
2665 	case MAGICTYPE_NONE:
2666 	case MAGICTYPE_POTION:
2667 	case MAGICTYPE_SPELLBOOK:
2668 	case MAGICTYPE_SCROLL:
2669 	case MAGICTYPE_WAND:
2670 	    break;
2671 
2672 	case NUM_MAGICTYPES:
2673 	    UT_ASSERT(!"Unhandled MAGICTYPE");
2674 	    break;
2675     }
2676 }
2677 
2678 bool
hasIntrinsic(INTRINSIC_NAMES intrinsic) const2679 ITEM::hasIntrinsic(INTRINSIC_NAMES intrinsic) const
2680 {
2681     // Check base item type...
2682     if (INTRINSIC::hasIntrinsic(glb_itemdefs[myDefinition].intrinsic,
2683 				intrinsic))
2684 	return true;
2685 
2686     // Try the artifact class.
2687     const ARTIFACT		*art;
2688 
2689     art = getArtifact();
2690     if (art)
2691     {
2692 	if (INTRINSIC::hasIntrinsic(art->intrinsics, intrinsic))
2693 	    return true;
2694     }
2695 
2696     // Try the magic item type...
2697     switch ((MAGICTYPE_NAMES) getMagicType())
2698     {
2699 	case MAGICTYPE_RING:
2700 	{
2701 	    if (INTRINSIC::hasIntrinsic(glb_ringdefs[getMagicClass()].intrinsic,
2702 					intrinsic) )
2703 		return true;
2704 	    break;
2705 	}
2706 	case MAGICTYPE_HELM:
2707 	{
2708 	    if (INTRINSIC::hasIntrinsic(glb_helmdefs[getMagicClass()].intrinsic,
2709 					intrinsic) )
2710 		return true;
2711 	    break;
2712 	}
2713 	case MAGICTYPE_BOOTS:
2714 	{
2715 	    if (INTRINSIC::hasIntrinsic(glb_bootsdefs[getMagicClass()].intrinsic,
2716 					intrinsic) )
2717 		return true;
2718 	    break;
2719 	}
2720 	case MAGICTYPE_AMULET:
2721 	{
2722 	    if (INTRINSIC::hasIntrinsic(glb_amuletdefs[getMagicClass()].intrinsic,
2723 					intrinsic) )
2724 		return true;
2725 	    break;
2726 	}
2727 	case MAGICTYPE_STAFF:
2728 	{
2729 	    if (INTRINSIC::hasIntrinsic(glb_staffdefs[getMagicClass()].intrinsic,
2730 					intrinsic) )
2731 		return true;
2732 	    break;
2733 	}
2734 	case MAGICTYPE_NONE:
2735 	case MAGICTYPE_POTION:
2736 	case MAGICTYPE_SPELLBOOK:
2737 	case MAGICTYPE_SCROLL:
2738 	case MAGICTYPE_WAND:
2739 	{
2740 	    // These guys all have no built in intrinsics
2741 	    return false;
2742 	}
2743 
2744 	case NUM_MAGICTYPES:
2745 	{
2746 	    UT_ASSERT(!"Unhandled MAGICTYPE");
2747 	    return false;
2748 	}
2749     }
2750     return false;
2751 }
2752 
2753 bool
dissolve(MOB * dissolver,bool * interesting)2754 ITEM::dissolve(MOB *dissolver, bool *interesting)
2755 {
2756     if (interesting)
2757 	*interesting = true;
2758     if (canDissolve())
2759     {
2760 	formatAndReport(dissolver, "%U <dissolve> in the acid!");
2761 	return true;
2762     }
2763     if (interesting)
2764 	*interesting = false;
2765 
2766     return false;
2767 }
2768 
2769 bool
canDissolve() const2770 ITEM::canDissolve() const
2771 {
2772     bool		dodissolve = false;
2773     MATERIAL_NAMES	material;
2774 
2775     material = getMaterial();
2776     dodissolve = glb_materialdefs[material].soluble;
2777 
2778     // If we have resistance to acid, we never dissolve
2779     // If we have vulnerability, we always dissolve.
2780     // If we have both, it is as normal.
2781     if (hasIntrinsic(INTRINSIC_RESISTACID))
2782     {
2783 	if (!hasIntrinsic(INTRINSIC_VULNACID))
2784 	{
2785 	    dodissolve = false;
2786 	}
2787     }
2788     else if (hasIntrinsic(INTRINSIC_VULNACID))
2789     {
2790 	dodissolve = true;
2791     }
2792 
2793     // Check for quest flag.  We don't want to dissolve those!
2794     if (glb_itemdefs[getDefinition()].isquest)
2795 	dodissolve = false;
2796 
2797     return dodissolve;
2798 }
2799 
2800 bool
ignite(MOB * igniter,bool * interesting)2801 ITEM::ignite(MOB *igniter, bool *interesting)
2802 {
2803     if (interesting)
2804 	*interesting = true;
2805 
2806     // If we dip a sword, it becomes a flaming sword.
2807     if (getDefinition() == ITEM_LONGSWORD)
2808     {
2809 	formatAndReport(igniter, "%U <catch> on fire!");
2810 
2811 	myDefinition = ITEM_FLAMESWORD;
2812 	return false;
2813     }
2814 
2815     if (getDefinition() == ITEM_ICEMACE)
2816     {
2817 	formatAndReport(igniter, "%U <return> to room temperature.");
2818 	myDefinition = ITEM_MACE;
2819 	return false;
2820     }
2821 
2822     if (getDefinition() == ITEM_ARROW)
2823     {
2824 	formatAndReport(igniter, "%U <catch> on fire!");
2825 	myDefinition = ITEM_FIREARROW;
2826 	return false;
2827     }
2828 
2829     // If we dip a club, it becomes a torch.
2830     if (getDefinition() == ITEM_CLUB)
2831     {
2832 	formatAndReport(igniter, "%U <catch> on fire!");
2833 
2834 	myDefinition = ITEM_TORCH;
2835 	// Set our shield flag.
2836 	myFlag1 = (ITEMFLAG1_NAMES)
2837 	    (myFlag1 | glb_itemdefs[ITEM_TORCH].flag1);
2838 	return false;
2839     }
2840 
2841     // Check for burning up
2842     if (canBurn())
2843     {
2844 	formatAndReport(igniter, "%U <burn> up.");
2845 	return true;
2846     }
2847 
2848     // Got here, nothing interesting happened.
2849     if (interesting)
2850 	*interesting = false;
2851     return false;
2852 }
2853 
2854 bool
electrify(int points,MOB * shocker,bool * interesting)2855 ITEM::electrify(int points, MOB *shocker, bool *interesting)
2856 {
2857     if (interesting)
2858 	*interesting = true;
2859 
2860     // Energize rapiers.
2861     if (getDefinition() == ITEM_RAPIER)
2862     {
2863 	formatAndReport(shocker, "%U <be> filled with electricity!");
2864 
2865 	myDefinition = ITEM_LIGHTNINGRAPIER;
2866 	addCharges(points);
2867 	clearChargesKnown();
2868 	return false;
2869     }
2870 
2871     if (getDefinition() == ITEM_LIGHTNINGRAPIER)
2872     {
2873 	formatAndReport(shocker, "%U <drink> deeply from the electric current!");
2874 
2875 	addCharges(points*2);
2876 	clearChargesKnown();
2877 	return false;
2878     }
2879 
2880     // Got here, nothing interesting happened.
2881     if (interesting)
2882 	*interesting = false;
2883     return false;
2884 }
2885 
2886 bool
canBurn() const2887 ITEM::canBurn() const
2888 {
2889     bool		doburn = false;
2890     MATERIAL_NAMES	material;
2891 
2892     material = getMaterial();
2893     doburn = glb_materialdefs[material].burnable;
2894 
2895     // If we have resistance to fire, we never burn
2896     // If we have vulnerability, we always burn.
2897     // If we have both, it is as normal.
2898     if (hasIntrinsic(INTRINSIC_RESISTFIRE))
2899     {
2900 	if (!hasIntrinsic(INTRINSIC_VULNFIRE))
2901 	{
2902 	    doburn = false;
2903 	}
2904     }
2905     else if (hasIntrinsic(INTRINSIC_VULNFIRE))
2906     {
2907 	doburn = true;
2908     }
2909 
2910     // Check for quest flag.  We don't want to burn those!
2911     if (glb_itemdefs[getDefinition()].isquest)
2912 	doburn = false;
2913 
2914     return doburn;
2915 }
2916 
2917 // This was factored out in White Rock BC.
2918 bool
douse(MOB * douser,bool * interesting)2919 ITEM::douse(MOB *douser, bool *interesting)
2920 {
2921     if (interesting)
2922 	*interesting = true;
2923 
2924     // If the dipped item is a flaming sword, it goes out.
2925     if (getDefinition() == ITEM_FLAMESWORD)
2926     {
2927 	formatAndReport(douser, "%U <be> extinguished.");
2928 	myDefinition = ITEM_LONGSWORD;
2929     }
2930     else if (getDefinition() == ITEM_FIREARROW)
2931     {
2932 	formatAndReport(douser, "%U <be> extinguished.");
2933 	myDefinition = ITEM_ARROW;
2934     }
2935     // As do torches.
2936     else if (getDefinition() == ITEM_TORCH)
2937     {
2938 	formatAndReport(douser, "%U <be> extinguished.");
2939 	myDefinition = ITEM_CLUB;
2940 	// Clear out the isshield flag.
2941 	myFlag1 = (ITEMFLAG1_NAMES)
2942 	    (myFlag1 & ~glb_itemdefs[ITEM_TORCH].flag1);
2943     }
2944     // Empty bottles fill.  This may seem odd as smashing one bottle may
2945     // fill ten, but the same happens with dipping.
2946     else if (getDefinition() == ITEM_BOTTLE)
2947     {
2948 	formatAndReport(douser, "%U <be> filled.");
2949 	myDefinition = ITEM_WATER;
2950     }
2951     else
2952     {
2953 	formatAndReport(douser, "%U <get> wet.");
2954 	if (interesting)
2955 	    *interesting = false;
2956     }
2957 
2958     // Water destroys nothing right now.
2959     return false;
2960 }
2961 
2962 bool
actionDip(MOB * dipper,ITEM * dippee,ITEM * & newpotion,ITEM * & newitem)2963 ITEM::actionDip(MOB *dipper, ITEM *dippee,
2964 		ITEM *&newpotion, ITEM *&newitem)
2965 {
2966     bool		consumed = false;
2967     bool		possible = false;
2968     BUF			buf;
2969 
2970     UT_ASSERT(dippee != this);
2971     // This should already be unlinked.
2972     UT_ASSERT(!getNext());
2973     UT_ASSERT(!dippee->getNext());
2974 
2975     newpotion = this;
2976     newitem = dippee;
2977 
2978     // Check for magic type potion...
2979     switch ((MAGICTYPE_NAMES) getMagicType())
2980     {
2981 	case MAGICTYPE_POTION:
2982 	{
2983 	    switch ((POTION_NAMES) getMagicClass())
2984 	    {
2985 		case POTION_GREEKFIRE:
2986 		{
2987 		    bool interesting = false;
2988 
2989 		    possible = true;
2990 		    consumed = true;
2991 
2992 		    buf = MOB::formatToString("%MU <M:dip> %IU into %U.",
2993 				0, this, dipper, dippee);
2994 		    dipper->reportMessage(buf);
2995 		    if (dippee->ignite(dipper, &interesting))
2996 		    {
2997 			// Burned up...
2998 			delete dippee;
2999 			newitem = 0;
3000 			newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3001 			// Id it...
3002 			markIdentified();
3003 			// Delete self
3004 			delete this;
3005 
3006 			break;
3007 		    }
3008 		    else if (interesting)
3009 		    {
3010 			// Something happened.
3011 			newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3012 			// Id it...
3013 			markIdentified();
3014 			// Delete self
3015 			delete this;
3016 
3017 			break;
3018 		    }
3019 		    else
3020 		    {
3021 			dipper->formatAndReport("Nothing happens.");
3022 		    }
3023 		    break;
3024 		}
3025 
3026 		case POTION_HEAL:
3027 		case POTION_BLIND:
3028 		case POTION_SMOKE:
3029 		    buf = MOB::formatToString("%MU <M:dip> %IU into %U.  Nothing happens.",
3030 				0, this, dipper, dippee);
3031 		    dipper->reportMessage(buf);
3032 		    possible = true;
3033 		    consumed = true;
3034 		    break;
3035 
3036 		case POTION_MANA:
3037 		    buf = MOB::formatToString("%MU <M:dip> %IU into %U.",
3038 				0, this, dipper, dippee);
3039 		    dipper->reportMessage(buf);
3040 
3041 		    if (dippee->getMagicType() == MAGICTYPE_WAND)
3042 		    {
3043 			// Dipping a wand into a mana potion recharges it.
3044 			dipper->formatAndReport("%IU hungrily <I:drink> the liquid!", dippee);
3045 
3046 			newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3047 
3048 			int		netnewcharges;
3049 
3050 			netnewcharges = rand_dice(1,
3051 						  6 - isCursed()*3,
3052 						  isBlessed()*3);
3053 
3054 			// Charge the wand.
3055 			dippee->addCharges(netnewcharges);
3056 			// New number of charges is not known.
3057 			dippee->clearChargesKnown();
3058 
3059 			// Id it...
3060 			markIdentified();
3061 			// Delete self
3062 			delete this;
3063 
3064 			possible = true;
3065 			consumed = true;
3066 		    }
3067 		    else if (dippee->getMagicType() == MAGICTYPE_SPELLBOOK)
3068 		    {
3069 			// Dipping a spellbook into a mana potion recharges it.
3070 			dipper->formatAndReport("The pages of %IU swiftly absorb the liquid!", dippee);
3071 
3072 			newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3073 
3074 			int		netnewcharges;
3075 
3076 			netnewcharges = rand_dice(1,
3077 						  3 - isCursed()*2,
3078 						  isBlessed());
3079 
3080 			// Charge the spellbook.
3081 			dippee->addCharges(netnewcharges);
3082 			// New number of charges is not known.
3083 			dippee->clearChargesKnown();
3084 
3085 			// Id it...
3086 			markIdentified();
3087 			// Delete self
3088 			delete this;
3089 
3090 			possible = true;
3091 			consumed = true;
3092 		    }
3093 		    else
3094 		    {
3095 			// Fail the dip.
3096 			dipper->reportMessage("Nothing happens.");
3097 			possible = true;
3098 			consumed = true;
3099 		    }
3100 		    break;
3101 
3102 		case POTION_CURE:
3103 		    if (dippee->isPoisoned())
3104 		    {
3105 			dippee->makePoisoned(POISON_NONE, 0);
3106 
3107 			// If the user knew it was poisoned, they get
3108 			// a message.  Otherwise, no visible effect.
3109 			// Well, the potion is removed that is a bit
3110 			// of a give away...
3111 			if (dippee->isKnownPoison())
3112 			{
3113 			    buf = MOB::formatToString("%MU <M:dip> %IU into %U.",
3114 					0, this, dipper, dippee);
3115 			    dipper->reportMessage(buf);
3116 
3117 			    buf = MOB::formatToString("The poison on %U is neutralized by %IU.",
3118 				    0, dippee, 0, this);
3119 			    dipper->reportMessage(buf);
3120 			}
3121 			else
3122 			{
3123 			    buf = MOB::formatToString("%MU <M:dip> %IU into %U.  Nothing happens.",
3124 					0, this, dipper, dippee);
3125 			    dipper->reportMessage(buf);
3126 			}
3127 
3128 			newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3129 
3130 			// Id it...
3131 			markIdentified();
3132 			// Delete self
3133 			delete this;
3134 
3135 			possible = true;
3136 			consumed = true;
3137 		    }
3138 		    else
3139 		    {
3140 			// Fail the dip.
3141 			buf = MOB::formatToString("%MU <M:dip> %IU into %U.  Nothing happens.",
3142 				    0, this, dipper, dippee);
3143 			dipper->reportMessage(buf);
3144 			possible = true;
3145 			consumed = true;
3146 		    }
3147 		    break;
3148 
3149 		case POTION_ENLIGHTENMENT:
3150 		    if (dippee->isFullyIdentified())
3151 		    {
3152 			// No id, no effect.
3153 			buf = MOB::formatToString("%MU <M:dip> %IU into %U.  Nothing happens.",
3154 				    0, this, dipper, dippee);
3155 			dipper->reportMessage(buf);
3156 			possible = true;
3157 			consumed = true;
3158 		    }
3159 		    else
3160 		    {
3161 			buf = MOB::formatToString("%MU <M:dip> %IU into %U.",
3162 				    0, this, dipper, dippee);
3163 			dipper->reportMessage(buf);
3164 
3165 			// Identify the dippee.
3166 			if (dipper->isAvatar())
3167 			    dippee->markIdentified();
3168 			dipper->formatAndReport("%U <gain> insight into the nature of %IU.", dippee);
3169 
3170 			newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3171 
3172 			// Id it...
3173 			markIdentified();
3174 			// Delete self
3175 			delete this;
3176 
3177 			possible = true;
3178 			consumed = true;
3179 		    }
3180 		    break;
3181 
3182 		case POTION_POISON:
3183 		{
3184 		    POISON_NAMES		poison;
3185 
3186 		    buf = MOB::formatToString("%MU <M:dip> %IU into %U.",
3187 				0, this, dipper, dippee);
3188 		    dipper->reportMessage(buf);
3189 
3190 
3191 		    if (dippee->hasIntrinsic(INTRINSIC_RESISTPOISON))
3192 		    {
3193 			// Fail the dip.
3194 			dipper->reportMessage("Nothing happens.");
3195 			possible = true;
3196 			consumed = true;
3197 			break;
3198 		    }
3199 
3200 		    buf.sprintf("A thick slime coats %s.",
3201 			    dippee->getAccusative());
3202 		    dipper->reportMessage(buf);
3203 
3204 		    if (isCursed())
3205 			poison = POISON_MILD;
3206 		    else if (isBlessed())
3207 			poison = POISON_STRONG;
3208 		    else
3209 			poison = POISON_NORMAL;
3210 
3211 		    dippee->makePoisoned(poison, rand_dice(1, 3, 0));
3212 		    if (dipper == MOB::getAvatar())
3213 			dippee->markPoisonKnown();
3214 
3215 		    newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3216 		    // Id it...
3217 		    markIdentified();
3218 		    // Delete self
3219 		    delete this;
3220 
3221 		    possible = true;
3222 		    consumed = true;
3223 		    break;
3224 		}
3225 
3226 		case POTION_ACID:
3227 		{
3228 		    buf = MOB::formatToString("%MU <M:dip> %IU into %U.",
3229 				0, this, dipper, dippee);
3230 		    dipper->reportMessage(buf);
3231 
3232 		    if (dippee->dissolve(dipper))
3233 		    {
3234 			newitem = 0;
3235 			newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3236 			// Id it...
3237 			markIdentified();
3238 			delete dippee;
3239 			// Delete self
3240 			delete this;
3241 		    }
3242 		    else
3243 		    {
3244 			dipper->reportMessage("Nothing happens.");
3245 		    }
3246 
3247 		    possible = true;
3248 		    consumed = true;
3249 		    break;
3250 		}
3251 
3252 		case NUM_POTIONS:
3253 		{
3254 		    UT_ASSERT(0);
3255 		    buf.sprintf("Unknown potion type %d", getMagicClass());
3256 		    dipper->reportMessage(buf);
3257 		    break;
3258 		}
3259 	    }
3260 	    break;
3261 	}
3262 
3263 	    // Other magic types do nothing:
3264 	case MAGICTYPE_NONE:
3265 	case MAGICTYPE_HELM:
3266 	case MAGICTYPE_BOOTS:
3267 	case MAGICTYPE_WAND:
3268 	case MAGICTYPE_SCROLL:
3269 	case MAGICTYPE_AMULET:
3270 	case MAGICTYPE_RING:
3271 	case MAGICTYPE_SPELLBOOK:
3272 	case MAGICTYPE_STAFF:
3273 	case NUM_MAGICTYPES:
3274 	    break;
3275     }
3276 
3277     // Check for specific items...
3278     // Only do this if previous checks failed.
3279     if (!consumed)
3280     {
3281 	switch ((ITEM_NAMES) myDefinition)
3282 	{
3283 	    case ITEM_WATER:
3284 	    {
3285 		// If the potion is holy, make new guy holy.
3286 		// If potion evil, make new guy evil.
3287 		// If potion plain, just wet new guy.
3288 		if (isCursed())
3289 		{
3290 		    dipper->formatAndReport("%IU <I:glow> black.", dippee);
3291 		    dippee->makeCursed();
3292 		    if (dipper->isAvatar())
3293 			dippee->markCursedKnown();
3294 		    possible = true;
3295 		    consumed = true;
3296 		    newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3297 		    delete this;
3298 		}
3299 		else if (isBlessed())
3300 		{
3301 		    dipper->formatAndReport("%IU <I:glow> blue.", dippee);
3302 		    dippee->makeBlessed();
3303 		    if (dipper->isAvatar())
3304 			dippee->markCursedKnown();
3305 		    possible = true;
3306 		    consumed = true;
3307 		    newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3308 		    delete this;
3309 		}
3310 		else
3311 		{
3312 		    bool		interesting;
3313 		    if (dippee->douse(dipper, &interesting))
3314 		    {
3315 			newitem = 0;
3316 			delete dippee;
3317 			newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3318 			delete this;
3319 		    }
3320 		    else if (interesting)
3321 		    {
3322 			newpotion = ITEM::create(ITEM_BOTTLE, false, true);
3323 			delete this;
3324 		    }
3325 
3326 		    possible = true;
3327 		    consumed = true;
3328 		}
3329 	    }
3330 	    default:
3331 		break;
3332 	}
3333     }
3334 
3335     if (!possible)
3336     {
3337 	// No one managed to do anything...
3338 	buf = MOB::formatToString("%MU cannot figure out how to dip %IU into %U.",
3339 				0, this, dipper, dippee);
3340 	dipper->reportMessage(buf);
3341     }
3342 
3343     return consumed;
3344 }
3345 
3346 bool
actionZap(MOB * zapper,int dx,int dy,int dz)3347 ITEM::actionZap(MOB *zapper, int dx, int dy, int dz)
3348 {
3349     bool		consumed = false;
3350     bool		possible = false;
3351     bool		targetself = false;
3352     const char		*directionflavour = 0;
3353     bool		destroythis = false;
3354     bool		doid = false;
3355     bool		forceid = false;
3356     BUF			buf;
3357     // Zapper position.
3358     int			zx, zy;
3359 
3360     zx = zapper->getX();
3361     zy = zapper->getY();
3362     if (!dx && !dy && !dz)
3363     {
3364 	targetself = true;
3365 	directionflavour = zapper->getReflexive();
3366     }
3367     if (dz)
3368     {
3369 	if (dz < 0)
3370 	    directionflavour = "the floor";
3371 	else
3372 	    directionflavour = "the ceiling";
3373     }
3374 
3375     // Try the magic type.
3376     switch ((MAGICTYPE_NAMES)getMagicType())
3377     {
3378 	case MAGICTYPE_WAND:
3379 	{
3380 	    // Print prequel message..
3381 	    zapper->formatAndReport("%U <zap> %IU%B1%B2.",
3382 		    this,
3383 		    directionflavour ? " at " : "",
3384 		    directionflavour ? directionflavour : "");
3385 
3386 	    // Determine if we have enough charges...
3387 	    if (myCharges == 0)
3388 	    {
3389 		// Check for wrest-last-charge
3390 		// 1 in 20 to be nice as it is much harder UI wise
3391 		// than in Nethack.
3392 		// I have since reduced this even farther as the goal
3393 		// is to make it not a tactical decision.
3394 		if (!rand_choice(7))
3395 		{
3396 		    zapper->formatAndReport("%U <wrest> one last charge.");
3397 		    destroythis = true;
3398 		}
3399 		else
3400 		{
3401 		    zapper->reportMessage("Nothing happens.");
3402 		    possible = true;
3403 		    consumed = true;
3404 		    // To be nice, we record the wand is out of charges.
3405 		    markChargesKnown();
3406 		    // EARLY EXIT:
3407 		    break;
3408 		}
3409 	    }
3410 
3411 
3412 	    // Getting here implies we successfully zapped.
3413 	    if (myCharges)
3414 		myCharges--;
3415 
3416 	    if (!destroythis && !isKnownCharges())
3417 	    {
3418 		if (zapper->isAvatar())
3419 		{
3420 		    if (!rand_choice(10))
3421 		    {
3422 			markChargesKnown();
3423 			buf = MOB::formatToString("%U <know> %r %Iu better.  ",
3424 				zapper, 0, 0, this);
3425 			// This is important enough to be broadcast.
3426 			msg_announce(gram_capitalize(buf));
3427 		    }
3428 		}
3429 	    }
3430 
3431 	    // Check to see if it is cursed and fizzled on the user.
3432 	    if (isCursed() && rand_chance(10))
3433 	    {
3434 		doid = false;
3435 		// This is a pretty simple wand to do...
3436 		zapper->formatAndReport("%IU <I:fizzle>.", this);
3437 		if (zapper->isAvatar())
3438 		{
3439 		    // We now know it is cursed
3440 		    markCursedKnown();
3441 		}
3442 		possible = true;
3443 		consumed = true;
3444 		break;
3445 	    }
3446 
3447 	    // Apply any of our artifact based powers.
3448 	    if (isArtifact())
3449 	    {
3450 		const ARTIFACT	*art;
3451 		MOB		*target;
3452 
3453 		target = glbCurLevel->getMob(zx + dx,
3454 					     zy + dy);
3455 		if (target)
3456 		{
3457 		    art = getArtifact();
3458 
3459 		    const char	*intrinsics;
3460 
3461 		    intrinsics = art->intrinsics;
3462 		    while (intrinsics && *intrinsics)
3463 		    {
3464 			target->setTimedIntrinsic(zapper,
3465 				    (INTRINSIC_NAMES) *intrinsics,
3466 				    rand_dice(3+isBlessed()-isCursed(), 50, 100));
3467 			intrinsics++;
3468 		    }
3469 		}
3470 	    }
3471 
3472 	    switch ((WAND_NAMES) getMagicClass())
3473 	    {
3474 		case WAND_NOTHING:
3475 		{
3476 		    doid = false;
3477 		    // This is a pretty simple wand to do...
3478 		    zapper->reportMessage("Nothing happens.");
3479 		    possible = true;
3480 		    consumed = true;
3481 		    break;
3482 		}
3483 		case WAND_CREATEMONSTER:
3484 		{
3485 		    doid = false;
3486 		    possible = true;
3487 		    consumed = true;
3488 
3489 		    if (glbCurLevel->getMob(zx + dx,
3490 					    zy + dy))
3491 		    {
3492 			zapper->reportMessage("Nothing happens.");
3493 			break;
3494 		    }
3495 
3496 		    MOB		*mob;
3497 
3498 		    mob = MOB::createNPC(100);
3499 
3500 		    if (!mob->canMove(zx + dx,
3501 				      zy + dy,
3502 				      true))
3503 		    {
3504 			zapper->reportMessage("Nothing happens.");
3505 			delete mob;
3506 			break;
3507 		    }
3508 
3509 		    mob->move(zx + dx,
3510 			      zy + dy,
3511 			      true);
3512 		    glbCurLevel->registerMob(mob);
3513 
3514 		    mob->formatAndReport("%U <appear> out of thin air!");
3515 
3516 		    // We have a chance of getting a tamed creature
3517 		    // based on the BUC of the wand.
3518 		    int		tamechance = 5;
3519 		    int		hostilechance = 0;
3520 		    if (isBlessed())
3521 			tamechance += 15;
3522 		    if (isCursed())
3523 		    {
3524 			tamechance = 1;
3525 			hostilechance = 20;
3526 		    }
3527 
3528 		    if (rand_chance(tamechance))
3529 		    {
3530 			mob->makeSlaveOf(zapper);
3531 		    }
3532 		    else if (rand_chance(hostilechance))
3533 		    {
3534 			// The creature turns on the zapper!
3535 			mob->setAITarget(zapper);
3536 		    }
3537 
3538 		    // Imbue the created creature with our wands
3539 		    // abilities.
3540 		    if (isArtifact())
3541 		    {
3542 			const ARTIFACT	*art;
3543 			art = getArtifact();
3544 
3545 			const char	*intrinsics;
3546 
3547 			intrinsics = art->intrinsics;
3548 			while (intrinsics && *intrinsics)
3549 			{
3550 			    mob->setTimedIntrinsic(zapper,
3551 					(INTRINSIC_NAMES) *intrinsics,
3552 					rand_dice(3+isBlessed()-isCursed(), 50, 100));
3553 			    intrinsics++;
3554 			}
3555 		    }
3556 
3557 		    zapper->pietyZapWand(this);
3558 
3559 		    doid = true;
3560 		    break;
3561 		}
3562 
3563 		case WAND_CREATETRAP:
3564 		{
3565 		    possible = true;
3566 		    consumed = true;
3567 		    doid = glbCurLevel->createTrap(zx + dx,
3568 						    zy + dy,
3569 						    zapper);
3570 		    if (doid)
3571 		    {
3572 			zapper->formatAndReport("%U <create> a hidden surprise.");
3573 			zapper->pietyZapWand(this);
3574 		    }
3575 		    else
3576 			zapper->reportMessage("Nothing happens.");
3577 		    break;
3578 		}
3579 		case WAND_LIGHT:
3580 		{
3581 		    MOB		*target;
3582 		    doid = true;
3583 		    possible = true;
3584 		    consumed = true;
3585 		    ourZapper.setMob(zapper);
3586 		    zapper->formatAndReport("A lit field surrounds %U.");
3587 		    glbCurLevel->applyFlag(SQUAREFLAG_LIT,
3588 			    zx + dx,
3589 			    zy + dy,
3590 			    5, false, true);
3591 		    zapper->pietyZapWand(this);
3592 
3593 		    // Blind the target, if any.
3594 		    if (!dz)
3595 		    {
3596 			zapper = ourZapper.getMob();
3597 
3598 			target = glbCurLevel->getMob(zx+dx, zy+dy);
3599 			if (target)
3600 			{
3601 			    // Wands always apply damage...
3602 			    target->receiveDamage(ATTACK_LIGHTWAND,
3603 				    zapper,
3604 				    this, 0,
3605 				    ATTACKSTYLE_WAND);
3606 			}
3607 		    }
3608 
3609 		    zapper = ourZapper.getMob();
3610 		    break;
3611 		}
3612 
3613 		case WAND_TELEPORT:
3614 		{
3615 		    MOB		*tele = 0;
3616 
3617 		    possible = true;
3618 		    consumed = true;
3619 
3620 		    // If it went vertical, nothing happens..
3621 		    if (!dz)
3622 		    {
3623 			tele = glbCurLevel->getMob(zx + dx,
3624 					    zy + dy);
3625 		    }
3626 		    if (tele)
3627 		    {
3628 			// Teleport the monster
3629 			ourZapper.setMob(zapper);
3630 			tele->actionTeleport();
3631 			zapper = ourZapper.getMob();
3632 			if (zapper)
3633 			    zapper->pietyZapWand(this);
3634 			doid = true;
3635 		    }
3636 		    // Tracked down a bug here.
3637 		    // Bug was: "TODO: Teleport items"
3638 		    // :>
3639 		    // Still in the airport lounge enjoying free beer.
3640 		    // Fear this code!
3641 		    // No doubt as a result of aforementioned free beer,
3642 		    // I foolishly dereferenced zapper->getX() to get the
3643 		    // tile location.  Zapper might be tele in which case
3644 		    // it might very well be dead.  In any case, this
3645 		    // would end up teleporting items at your destination
3646 		    // square rather than source square!
3647 		    ITEMSTACK		stack;
3648 		    glbCurLevel->getItemStack(stack, zx + dx,
3649 						     zy + dy);
3650 		    if (stack.entries())
3651 		    {
3652 			ITEM			*item;
3653 
3654 			doid = true;
3655 			// We don't want to double count this zap.
3656 			if (zapper && !tele)
3657 			    zapper->pietyZapWand(this);
3658 
3659 			for (int i = 0; i < stack.entries(); i++)
3660 			{
3661 			    item = stack(i);
3662 			    item->randomTeleport(glbCurLevel, true, zapper);
3663 			}
3664 		    }
3665 
3666 		    if (!doid && zapper)
3667 		    {
3668 			zapper->reportMessage("Nothing happens.");
3669 		    }
3670 		    break;
3671 		}
3672 
3673 		case WAND_POLYMORPH:
3674 		{
3675 		    MOB		*poly = 0;
3676 		    ITEM	*item = 0;
3677 
3678 		    possible = true;
3679 		    consumed = true;
3680 
3681 		    // If it went vertical, nothing happens..
3682 		    if (!dz)
3683 		    {
3684 			poly = glbCurLevel->getMob(zx + dx,
3685 					    zy + dy);
3686 		    }
3687 		    if (poly)
3688 		    {
3689 			MOBREF		zapmobref;
3690 
3691 			zapmobref.setMob(zapper);
3692 
3693 			// Polymorph the monster
3694 			// If the monster was us, zapper may now point
3695 			// to the base object rather than the top object.
3696 			// Thus we track the ref.
3697 			poly->actionPolymorph();
3698 			zapper = zapmobref.getMob();
3699 			doid = true;
3700 		    }
3701 		    // Zapping the ground means polying on the ground.
3702 		    // (doid here means did something)
3703 		    if (dz <= 0 && !doid)
3704 		    {
3705 			item = glbCurLevel->getItem(zx + dx,
3706 						zy + dy);
3707 		    }
3708 		    if (item)
3709 		    {
3710 			ITEM		*newitem;
3711 
3712 			newitem = item->polymorph(zapper);
3713 
3714 			if (newitem)
3715 			{
3716 			    if (item->getStackCount() > 1)
3717 				item = item->splitStack(1);
3718 			    else
3719 				glbCurLevel->dropItem(item);
3720 
3721 			    glbCurLevel->acquireItem(newitem,
3722 						zx + dx,
3723 						zy + dy,
3724 						zapper);
3725 			    delete item;
3726 			}
3727 
3728 			doid = true;
3729 		    }
3730 		    if (!doid && zapper)
3731 		    {
3732 			zapper->reportMessage("Nothing happens.");
3733 		    }
3734 		    else if (zapper)
3735 		    {
3736 			zapper->pietyZapWand(this);
3737 		    }
3738 		    break;
3739 		}
3740 
3741 		case WAND_INVISIBLE:
3742 		{
3743 		    MOB		*invis = 0;
3744 		    bool	 getpiety = false;
3745 
3746 		    possible = true;
3747 		    consumed = true;
3748 
3749 
3750 		    // If it went vertical, nothing happens..
3751 		    if (!dz)
3752 		    {
3753 			invis = glbCurLevel->getMob(zx + dx,
3754 					    zy + dy);
3755 		    }
3756 		    if (invis)
3757 		    {
3758 			// Invisible the monster
3759 			// We notice something if the monster
3760 			// is not already invisible.
3761 			bool quietchange = false;
3762 			if (!invis->hasIntrinsic(INTRINSIC_INVISIBLE))
3763 			{
3764 			    if (invis != MOB::getAvatar())
3765 			    {
3766 				invis->formatAndReport("%U <disappear> from sight.");
3767 			    }
3768 			    doid = true;
3769 
3770 			    // We must determine if we can see the monster
3771 			    // *before* we make it invisible.  If we wait
3772 			    // for normal doid check, the monster may
3773 			    // be invisible which prevents us from
3774 			    // iding the wand.
3775 			    if (zapper == MOB::getAvatar() ||
3776 				(MOB::getAvatar() &&
3777 				 MOB::getAvatar()->canSense(zapper)))
3778 			    {
3779 				forceid = true;
3780 			    }
3781 			}
3782 			else
3783 			{
3784 			    quietchange = true;
3785 			}
3786 			invis->setTimedIntrinsic(zapper,
3787 				INTRINSIC_INVISIBLE,
3788 				rand_dice(3+isBlessed()-isCursed(), 50, 100),
3789 				quietchange);
3790 			getpiety = true;
3791 		    }
3792 		    SQUARE_NAMES		tile;
3793 
3794 		    tile = glbCurLevel->getTileSafe(zx+dx, zy+dy);
3795 
3796 		    // Check to see if we can make a door invisible
3797 		    switch (tile)
3798 		    {
3799 			// Open doors need to be closed first to avoid
3800 			// this nerfing the knock spell.
3801 			case SQUARE_DOOR:
3802 			case SQUARE_BLOCKEDDOOR:
3803 			    doid = true;
3804 			    if (zapper == MOB::getAvatar() ||
3805 				glbCurLevel->hasFOV(zx+dx, zy+dy))
3806 			    {
3807 				forceid = true;
3808 			    }
3809 			    glbCurLevel->reportMessage("The door fades into the wall.", zx+dx, zy+dy);
3810 			    glbCurLevel->setTile(zx+dx, zy+dy, SQUARE_SECRETDOOR);
3811 			    getpiety = true;
3812 			    break;
3813 			case SQUARE_FLOORSMOKEVENT:
3814 			case SQUARE_PATHSMOKEVENT:
3815 			case SQUARE_FLOORPOISONVENT:
3816 			case SQUARE_PATHPOISONVENT:
3817 			case SQUARE_FLOORTELEPORTER:
3818 			case SQUARE_PATHTELEPORTER:
3819 			case SQUARE_FLOORHOLE:
3820 			case SQUARE_PATHHOLE:
3821 			case SQUARE_FLOORPIT:
3822 			case SQUARE_PATHPIT:
3823 			case SQUARE_FLOORSPIKEDPIT:
3824 			case SQUARE_PATHSPIKEDPIT:
3825 			{
3826 			    BUF		buf;
3827 
3828 			    doid = true;
3829 			    if (zapper == MOB::getAvatar() ||
3830 				glbCurLevel->hasFOV(zx+dx, zy+dy))
3831 			    {
3832 				forceid = true;
3833 			    }
3834 
3835 			    buf.sprintf("%s fades into the ground.",
3836 					glb_squaredefs[tile].description);
3837 			    glbCurLevel->reportMessage(buf, zx+dx, zy+dy);
3838 			    glbCurLevel->setTile(zx+dx, zy+dy, (SQUARE_NAMES) glb_squaredefs[tile].invissquare);
3839 			    getpiety = true;
3840 			    break;
3841 			}
3842 
3843 			default:
3844 			    // Do nothing
3845 			    break;
3846 		    }
3847 		    if (!doid)
3848 		    {
3849 			zapper->reportMessage("Nothing happens.");
3850 		    }
3851 		    if (getpiety)
3852 			zapper->pietyZapWand(this);
3853 		    break;
3854 		}
3855 
3856 		case WAND_SPEED:
3857 		{
3858 		    MOB		*speed = 0;
3859 
3860 		    possible = true;
3861 		    consumed = true;
3862 
3863 		    // If it went vertical, nothing happens..
3864 		    if (!dz)
3865 		    {
3866 			speed = glbCurLevel->getMob(zx + dx,
3867 					    zy + dy);
3868 		    }
3869 		    if (speed)
3870 		    {
3871 			// Quicken the monster
3872 			// We notice something if the monster
3873 			// is not already quick.
3874 			if (!speed->hasIntrinsic(INTRINSIC_QUICK))
3875 			{
3876 			    doid = true;
3877 			}
3878 			speed->setTimedIntrinsic(zapper,
3879 				INTRINSIC_QUICK,
3880 				rand_dice(3+isBlessed()-isCursed(), 50, 100));
3881 			zapper->pietyZapWand(this);
3882 		    }
3883 		    if (!doid)
3884 		    {
3885 			zapper->reportMessage("Nothing happens.");
3886 		    }
3887 		    break;
3888 		}
3889 
3890 		case WAND_SLOW:
3891 		{
3892 		    MOB		*slow = 0;
3893 
3894 		    possible = true;
3895 		    consumed = true;
3896 
3897 		    // If it went vertical, nothing happens..
3898 		    if (!dz)
3899 		    {
3900 			slow = glbCurLevel->getMob(zx + dx,
3901 					    zy + dy);
3902 		    }
3903 		    if (slow)
3904 		    {
3905 			// Quicken the monster
3906 			// We notice something if the monster
3907 			// is not already quick.
3908 			if (!slow->hasIntrinsic(INTRINSIC_SLOW))
3909 			{
3910 			    doid = true;
3911 			}
3912 			slow->setTimedIntrinsic(zapper,
3913 				INTRINSIC_SLOW,
3914 				rand_dice(3+isBlessed()-isCursed(), 50, 100));
3915 			zapper->pietyZapWand(this);
3916 		    }
3917 		    if (!doid)
3918 		    {
3919 			zapper->reportMessage("Nothing happens.");
3920 		    }
3921 		    break;
3922 		}
3923 
3924 		case WAND_FIRE:
3925 		case WAND_ICE:
3926 		{
3927 		    possible = true;
3928 		    consumed = true;
3929 		    doid = true;		// This is pretty obvious.
3930 
3931 		    ourZapper.setMob(zapper);
3932 		    zapper->pietyZapWand(this);
3933 		    if (targetself || dz)
3934 		    {
3935 			bool		dosquareeffect = false;
3936 
3937 			// While underwater, always works.
3938 			if (zapper->hasIntrinsic(INTRINSIC_SUBMERGED))
3939 			    dosquareeffect = true;
3940 
3941 			if (dz && !dosquareeffect)
3942 			{
3943 			    // Shot downwards? affect square
3944 			    if (dz < 0)
3945 				dosquareeffect = true;
3946 			    zapper->reportMessage("The ray bounces.");
3947 			}
3948 			// Affect the square.
3949 			if (dosquareeffect &&
3950 			    (WAND_NAMES) getMagicClass() == WAND_ICE)
3951 			{
3952 			    glbCurLevel->freezeSquare(zx, zy, zapper);
3953 			}
3954 			if (dosquareeffect &&
3955 			    (WAND_NAMES) getMagicClass() == WAND_FIRE)
3956 			{
3957 			    glbCurLevel->burnSquare(zx, zy, zapper);
3958 			}
3959 			// Apply to self..
3960 			zapCallback(zx, zy);
3961 		    }
3962 		    else
3963 		    {
3964 			glbCurLevel->fireRay(zx, zy,
3965 				dx, dy,
3966 				6,
3967 				MOVE_STD_FLY, true,
3968 				zapCallbackStatic,
3969 				this);
3970 
3971 		    }
3972 		    zapper = ourZapper.getMob();
3973 		    break;
3974 		}
3975 
3976 		case WAND_SLEEP:
3977 		{
3978 		    possible = true;
3979 		    consumed = true;
3980 		    doid = true;		// This is pretty obvious.
3981 
3982 		    ourZapper.setMob(zapper);
3983 		    zapper->pietyZapWand(this);
3984 		    if (targetself || dz)
3985 		    {
3986 			if (dz)
3987 			{
3988 			    zapper->reportMessage("The ray bounces.");
3989 			}
3990 
3991 			// Apply to self..
3992 			zapCallback(zx, zy);
3993 		    }
3994 		    else
3995 		    {
3996 			glbCurLevel->fireRay(zx, zy,
3997 				dx, dy,
3998 				6,
3999 				MOVE_STD_FLY, true,
4000 				zapCallbackStatic,
4001 				this);
4002 
4003 		    }
4004 		    zapper = ourZapper.getMob();
4005 		    break;
4006 		}
4007 
4008 		case WAND_DIGGING:
4009 		{
4010 		    possible = true;
4011 		    consumed = true;
4012 		    doid = true;		// Wands of digging autoid.
4013 
4014 		    ourZapper.setMob(zapper);
4015 		    zapper->pietyZapWand(this);
4016 		    zapper->actionDig(dx, dy, dz, 6, true);
4017 		    zapper = ourZapper.getMob();
4018 
4019 		    break;
4020 		}
4021 
4022 		case NUM_WANDS:
4023 		{
4024 		    UT_ASSERT(!"Unhandled wand type!");
4025 		    break;
4026 		}
4027 	    }
4028 	}
4029 
4030 	// Other MAGICTYPES that, of course, do nothing...
4031 	case MAGICTYPE_NONE:
4032 	case MAGICTYPE_POTION:
4033 	case MAGICTYPE_SPELLBOOK:
4034 	case MAGICTYPE_SCROLL:
4035 	case MAGICTYPE_RING:
4036 	case MAGICTYPE_HELM:
4037 	case MAGICTYPE_BOOTS:
4038 	case MAGICTYPE_AMULET:
4039 	case MAGICTYPE_STAFF:
4040 	case NUM_MAGICTYPES:
4041 	    break;
4042     }
4043 
4044     // Try the definition.
4045     if (!possible)
4046     {
4047 	switch ((ITEM_NAMES) myDefinition)
4048 	{
4049 	    case ITEM_LIGHTNINGRAPIER:
4050 	    {
4051 		possible = true;
4052 		consumed = true;
4053 		doid = false;		// Already ided.
4054 
4055 		ourZapper.setMob(zapper);
4056 		// Rapiers still count as wands in terms of piety.
4057 		zapper->pietyZapWand(this);
4058 
4059 		zapper = ourZapper.getMob();
4060 
4061 		// Electrocution by lighting rapiers
4062 		// only occurs if fired while submerged,
4063 		// not if merely fired at the ground.
4064 		if (zapper && zapper->hasIntrinsic(INTRINSIC_SUBMERGED))
4065 		{
4066 		    // Drain our charges..
4067 		    zapper->formatAndReport("%R %Iu violently <I:discharge>.", this);
4068 		    myCharges = 0;
4069 		    setDefinition(ITEM_RAPIER);
4070 		    zapper->rebuildAppearance();
4071 		    // Affect the square.
4072 		    glbCurLevel->electrocuteSquare(zx, zy, zapper);
4073 
4074 		    // All done, your targetting has no effect
4075 		    break;
4076 		}
4077 		zapper = ourZapper.getMob();
4078 
4079 		// Getting here implies we successfully zapped.
4080 		if (myCharges > 10)
4081 		    myCharges -= 10;
4082 		else
4083 		    myCharges = 0;
4084 		if (!myCharges)
4085 		{
4086 		    if (zapper)
4087 			zapper->formatAndReport("%R %Iu <I:power> down.", this);
4088 		    setDefinition(ITEM_RAPIER);
4089 		    if (zapper)
4090 			zapper->rebuildAppearance();
4091 		}
4092 
4093 		if (myCharges && !isKnownCharges())
4094 		{
4095 		    if (zapper && zapper->isAvatar())
4096 		    {
4097 			if (!rand_choice(10))
4098 			{
4099 			    markChargesKnown();
4100 			    buf = MOB::formatToString("%U <know> %r %Iu better.  ",
4101 				    zapper, 0, 0, this);
4102 			    // This is important enough to be broadcast.
4103 			    msg_announce(gram_capitalize(buf));
4104 			}
4105 		    }
4106 		}
4107 		if (targetself || dz)
4108 		{
4109 		    if (dz && zapper)
4110 		    {
4111 			zapper->reportMessage("The ray bounces.");
4112 		    }
4113 		    // Apply to self..
4114 		    zapCallback(zx, zy);
4115 		}
4116 		else
4117 		{
4118 		    glbCurLevel->fireRay(zx, zy,
4119 			    dx, dy,
4120 			    6,
4121 			    MOVE_STD_FLY, true,
4122 			    zapCallbackStatic,
4123 			    this);
4124 
4125 		}
4126 		zapper = ourZapper.getMob();
4127 		break;
4128 	    }
4129 	    default:
4130 		// Nothing...
4131 		break;
4132 	}
4133     }
4134 
4135     // Check if zapper is dead.
4136     if (zapper)
4137     {
4138 	if (zapper->hasIntrinsic(INTRINSIC_DEAD))
4139 	{
4140 	    zapper = 0;
4141 	}
4142     }
4143 
4144     if (!possible && zapper)
4145     {
4146 	// Noone figured out how to zap it.
4147 	zapper->formatAndReport("%U cannot figure out how to zap %IU.",
4148 				this);
4149     }
4150 
4151     // Check if we should id this...
4152     // Ideally you could id a wand by a creature killing itself with it,
4153     // but that makes the canSense call rather difficult.
4154     if (doid && zapper)
4155     {
4156 	if (forceid ||
4157 	    zapper == MOB::getAvatar() ||
4158 	    (MOB::getAvatar() && MOB::getAvatar()->canSense(zapper)))
4159 	{
4160 	    // We only id type, not the particulars!
4161 	    markClassKnown();
4162 	}
4163     }
4164 
4165     // If we are to destroy this, do so...
4166     // Wands that crumble to dust with the same charge that kills their
4167     // owner get a saving throw.
4168     // (By saving throw, I mean that they don't get destroyed :>)
4169     if (destroythis && zapper)
4170     {
4171 	ITEM		*drop;
4172 
4173 	zapper->formatAndReport("%IU <I:crumble> to dust.", this);
4174 
4175 	drop = zapper->dropItem(getX(), getY());
4176 	UT_ASSERT(drop == this);
4177 	delete this;
4178     }
4179 
4180     return consumed;
4181 }
4182 
4183 bool
grenadeCallbackStatic(int x,int y,bool final,void * data)4184 ITEM::grenadeCallbackStatic(int x, int y, bool final, void *data)
4185 {
4186     return ((ITEM *)data)->grenadeCallback(x, y);
4187 }
4188 
4189 bool
grenadeCallback(int x,int y)4190 ITEM::grenadeCallback(int x, int y)
4191 {
4192     MOB		*victim;
4193     BUF		 buf;
4194 
4195     // Get the mob at this location.
4196     victim = glbCurLevel->getMob(x, y);
4197 
4198     // Magic potions..
4199     if (getMagicType() == MAGICTYPE_POTION)
4200     {
4201 	POTION_NAMES		potion;
4202 
4203 	potion = (POTION_NAMES) getMagicClass();
4204 
4205 	switch (potion)
4206 	{
4207 	    case POTION_HEAL:
4208 	    {
4209 		if (!victim)
4210 		    break;
4211 
4212 		int		heal;
4213 
4214 		if (isBlessed())
4215 		    heal = rand_dice(1, 10, 10);
4216 		else if (isCursed())
4217 		    heal = rand_dice(1, 10, 0);
4218 		else
4219 		    heal = rand_dice(1, 20, 0);
4220 
4221 		if (victim->receiveHeal(heal, ourZapper.getMob()))
4222 		{
4223 		    victim->formatAndReport("%U <look> healthier.");
4224 
4225 		    if (victim->isAvatar() ||
4226 			(MOB::getAvatar() &&
4227 			 MOB::getAvatar()->canSense(victim)))
4228 			markIdentified();
4229 		}
4230 		break;
4231 	    }
4232 
4233 	    case POTION_MANA:
4234 	    {
4235 		if (!victim)
4236 		    break;
4237 
4238 		int		magic;
4239 
4240 		if (isBlessed())
4241 		    magic = rand_dice(1, 20, 20);
4242 		else if (isCursed())
4243 		    magic = rand_dice(1, 20, 0);
4244 		else
4245 		    magic = rand_dice(1, 40, 0);
4246 
4247 		if (victim->receiveMana(magic, ourZapper.getMob()))
4248 		{
4249 		    victim->formatAndReport("%U <look> recharged.");
4250 
4251 		    if (victim->isAvatar() ||
4252 			(MOB::getAvatar() &&
4253 			 MOB::getAvatar()->canSense(victim)))
4254 			markIdentified();
4255 		}
4256 		break;
4257 	    }
4258 
4259 	    case POTION_ACID:
4260 	    {
4261 		// Check to see if we upconvert smoke into acid.
4262 		if (glbCurLevel->getSmoke(x, y) == SMOKE_SMOKE)
4263 		{
4264 		    glbCurLevel->reportMessage("The smoke is acidified.", x, y);
4265 		    if (MOB::getAvatar() &&
4266 			glbCurLevel->hasLOS(MOB::getAvatar()->getX(),
4267 				    MOB::getAvatar()->getY(),
4268 				    x, y))
4269 		    {
4270 			markIdentified();
4271 		    }
4272 		    glbCurLevel->setSmoke(x, y, SMOKE_ACID, ourZapper.getMob());
4273 		}
4274 		if (!victim)
4275 		    break;
4276 
4277 		// Do identify if the avatar can sense this square.
4278 		if (glbCurLevel->hasFOV(x, y))
4279 		    markIdentified();
4280 
4281 		victim->receiveDamage(ATTACK_ACIDPOTION, ourZapper.getMob(), this, 0,
4282 					ATTACKSTYLE_MISC);
4283 		break;
4284 	    }
4285 
4286 	    case POTION_GREEKFIRE:
4287 	    {
4288 		// Check for burning squares.  We identify if the
4289 		// avatar witnesses this.
4290 		if (glbCurLevel->burnSquare(x, y, ourZapper.getMob()))
4291 		{
4292 		    if (glbCurLevel->hasFOV(x, y))
4293 			markIdentified();
4294 		}
4295 
4296 		// Burning the square may kill our victim,
4297 		// so we refetch.
4298 		victim = glbCurLevel->getMob(x, y);
4299 		if (!victim)
4300 		    break;
4301 
4302 		// Do identify if the avatar can sense this square.
4303 		if (glbCurLevel->hasFOV(x, y))
4304 		    markIdentified();
4305 
4306 		victim->receiveDamage(ATTACK_GREEKFIREPOTION,
4307 				      ourZapper.getMob(), this, 0,
4308 				      ATTACKSTYLE_MISC);
4309 		break;
4310 	    }
4311 
4312 	    case POTION_SMOKE:
4313 	    {
4314 		// We can only put smoke where things can fly.
4315 		if (!(glb_squaredefs[glbCurLevel->getTile(x, y)].movetype &
4316 		      MOVE_STD_FLY))
4317 		    break;
4318 
4319 		// Do identify if the avatar can sense this.
4320 		if (glbCurLevel->hasFOV(x, y))
4321 		    markIdentified();
4322 
4323 		// Make this square smokey.
4324 		// If the smoke potion is poisoned, act accordinly
4325 		if (isPoisoned())
4326 		    glbCurLevel->setSmoke(x, y, SMOKE_POISON, ourZapper.getMob());
4327 		else
4328 		    glbCurLevel->setSmoke(x, y, SMOKE_SMOKE, ourZapper.getMob());
4329 		break;
4330 	    }
4331 
4332 	    case POTION_BLIND:
4333 	    {
4334 		if (!victim)
4335 		    break;
4336 
4337 		int		turns;
4338 
4339 		// You get 3d20 turns of blindness.
4340 		if (isBlessed())
4341 		    turns = rand_dice(3, 10, 30);
4342 		else if (isCursed())
4343 		    turns = rand_dice(3, 10, 0);
4344 		else
4345 		    turns = rand_dice(3, 20, 0);
4346 
4347 		// Determine if we notice anything...
4348 		if (victim->isAvatar() ||
4349 		    (MOB::getAvatar() &&
4350 		     MOB::getAvatar()->canSense(victim)))
4351 		{
4352 		    markIdentified();
4353 		}
4354 
4355 		victim->setTimedIntrinsic(ourZapper.getMob(),
4356 					    INTRINSIC_BLIND, turns);
4357 		break;
4358 	    }
4359 
4360 	    case POTION_POISON:
4361 	    {
4362 		// Check to see if we upconvert smoke into poison.
4363 		if (glbCurLevel->getSmoke(x, y) == SMOKE_SMOKE)
4364 		{
4365 		    glbCurLevel->reportMessage("The smoke is poisoned.", x, y);
4366 		    if (MOB::getAvatar() &&
4367 			glbCurLevel->hasLOS(MOB::getAvatar()->getX(),
4368 				    MOB::getAvatar()->getY(),
4369 				    x, y))
4370 		    {
4371 			markIdentified();
4372 		    }
4373 		    glbCurLevel->setSmoke(x, y, SMOKE_POISON, ourZapper.getMob());
4374 		}
4375 
4376 		if (!victim)
4377 		    break;
4378 
4379 		int			turns;
4380 		POISON_NAMES	poison;
4381 
4382 		turns = rand_dice(4, 5, 0);
4383 		if (isBlessed())
4384 		    poison = POISON_STRONG;
4385 		else if (isCursed())
4386 		    poison = POISON_MILD;
4387 		else
4388 		    poison = POISON_NORMAL;
4389 
4390 		victim->setTimedIntrinsic(ourZapper.getMob(), (INTRINSIC_NAMES)
4391 				  glb_poisondefs[poison].intrinsic,
4392 				  turns);
4393 		// The avatar is exempt as the permament intrinsic
4394 		// will duplicate this.
4395 		if (!victim->isAvatar())
4396 		{
4397 		    victim->formatAndReport("%U <be> poisoned.");
4398 		}
4399 
4400 		// Determine if we notice anything...
4401 		if (victim->isAvatar() ||
4402 		    (MOB::getAvatar() &&
4403 		     MOB::getAvatar()->canSense(victim)))
4404 		{
4405 		    markIdentified();
4406 		}
4407 
4408 		break;
4409 	    }
4410 
4411 	    case POTION_CURE:
4412 	    {
4413 		// Check to see if we downconvert poison smoke into smoke.
4414 		if (glbCurLevel->getSmoke(x, y) == SMOKE_POISON)
4415 		{
4416 		    glbCurLevel->reportMessage("The poisoned smoke is neutralized.", x, y);
4417 		    if (MOB::getAvatar() &&
4418 			glbCurLevel->hasLOS(MOB::getAvatar()->getX(),
4419 				    MOB::getAvatar()->getY(),
4420 				    x, y))
4421 		    {
4422 			markIdentified();
4423 		    }
4424 
4425 		    glbCurLevel->setSmoke(x, y, SMOKE_SMOKE, ourZapper.getMob());
4426 		}
4427 
4428 		if (!victim)
4429 		    break;
4430 
4431 		if (victim->receiveCure())
4432 		{
4433 		    victim->formatAndReport(
4434 			    "The poison is expunged from %R veins.");
4435 
4436 		    if (victim->isAvatar() ||
4437 			(MOB::getAvatar() &&
4438 			 MOB::getAvatar()->canSense(victim)))
4439 			markIdentified();
4440 		}
4441 		break;
4442 	    }
4443 
4444 	    case POTION_ENLIGHTENMENT:
4445 	    {
4446 		if (!victim)
4447 		    break;
4448 
4449 		glbShowIntrinsic(victim);
4450 		markIdentified();
4451 		break;
4452 	    }
4453 
4454 	    case NUM_POTIONS:
4455 		UT_ASSERT(!"Unknown potion class!");
4456 		break;
4457 	}
4458     }
4459     else
4460     {
4461 	// Regular stuff...
4462 	switch (getDefinition())
4463 	{
4464 	    case ITEM_WATER:
4465 	    {
4466 		glbCurLevel->douseSquare(x, y, isBlessed(), ourZapper.getMob());
4467 
4468 		break;
4469 	    }
4470 	    case ITEM_BOTTLE:
4471 	    {
4472 		if (!victim)
4473 		    break;
4474 
4475 		// Do normal piercing damage
4476 		victim->receiveDamage(ATTACK_GLASSFRAGMENTS, ourZapper.getMob(), this,
4477 					0, ATTACKSTYLE_THROWN);
4478 		break;
4479 	    }
4480 
4481 	    default:
4482 		// Do nothing!
4483 		// Not handled currently.
4484 		UT_ASSERT(!"Unknown grenade!");
4485 		break;
4486 	}
4487     }
4488 
4489     return true;
4490 }
4491 
4492 bool
zapCallbackStatic(int x,int y,bool final,void * data)4493 ITEM::zapCallbackStatic(int x, int y, bool final, void *data)
4494 {
4495     if (final) return false;
4496     return ((ITEM *)data)->zapCallback(x, y);
4497 }
4498 
4499 bool
zapCallback(int x,int y)4500 ITEM::zapCallback(int x, int y)
4501 {
4502     MOB			*mob;
4503     ATTACK_NAMES	 attack = ATTACK_NONE;
4504 
4505     mob = glbCurLevel->getMob(x, y);
4506     if (mob)
4507     {
4508 	if (getMagicType() == MAGICTYPE_WAND)
4509 	{
4510 	    switch ((WAND_NAMES) getMagicClass())
4511 	    {
4512 		case WAND_FIRE:
4513 		    attack = ATTACK_FIREWAND;
4514 		    break;
4515 		case WAND_ICE:
4516 		    attack = ATTACK_ICEWAND;
4517 		    break;
4518 		case WAND_DIGGING:
4519 		    if (mob->getDefinition() == MOB_EARTHELEMENTAL)
4520 		    {
4521 			attack = ATTACK_DIGEARTHELEMENTAL;
4522 		    }
4523 		    break;
4524 		case WAND_SLEEP:
4525 		    attack = ATTACK_SLEEPWAND;
4526 		    break;
4527 		default:
4528 		    break;
4529 	    }
4530 	}
4531 	switch (getDefinition())
4532 	{
4533 	    case ITEM_LIGHTNINGRAPIER:
4534 		// note it is very important that this can't charge lightning
4535 		// rapiers!
4536 		attack = ATTACK_ZAPLIGHTNINGRAPIER;
4537 		break;
4538 	    default:
4539 		// No, I am not going to list all the items here to take
4540 		// advantage of enumeration warnings.
4541 		break;
4542 	}
4543 	if (attack != ATTACK_NONE)
4544 	{
4545 	    mob->receiveDamage(attack, ourZapper.getMob(), this,
4546 				0, ATTACKSTYLE_WAND);
4547 	}
4548     }
4549 
4550     // Special square related stuff...
4551     if (getMagicType() == MAGICTYPE_WAND && getMagicClass() == WAND_DIGGING)
4552     {
4553 	SQUARE_NAMES		tile;
4554 
4555 	tile = (SQUARE_NAMES) glbCurLevel->getTile(x, y);
4556 	switch (tile)
4557 	{
4558 	    case SQUARE_EMPTY:
4559 	    case SQUARE_WALL:
4560 	    {
4561 		glbCurLevel->setTile(x, y, SQUARE_CORRIDOR);
4562 		break;
4563 	    }
4564 
4565 	    case SQUARE_DOOR:
4566 	    case SQUARE_BLOCKEDDOOR:
4567 	    case SQUARE_SECRETDOOR:
4568 	    {
4569 		// Can't tunnel through these!
4570 		return false;
4571 	    }
4572 
4573 	    default:
4574 		break;
4575 	}
4576     }
4577 
4578     if (getMagicType() == MAGICTYPE_WAND && getMagicClass() == WAND_ICE)
4579     {
4580 	// On successful freeze, fizzle out wand.
4581 	if (glbCurLevel->freezeSquare(x, y, ourZapper.getMob()))
4582 	    return false;
4583     }
4584 
4585     if (getMagicType() == MAGICTYPE_WAND && getMagicClass() == WAND_FIRE)
4586     {
4587 	// Fire wands keep burning :>
4588 	glbCurLevel->burnSquare(x, y, ourZapper.getMob());
4589     }
4590 
4591     return true;
4592 }
4593 
4594 bool
randomTeleport(MAP * map,bool mapownsitem,MOB * teleporter)4595 ITEM::randomTeleport(MAP *map, bool mapownsitem, MOB *teleporter)
4596 {
4597     // Check for tele fixed items.
4598     if (hasIntrinsic(INTRINSIC_TELEFIXED))
4599     {
4600 	formatAndReport("%U <shudder>.");
4601 	return false;
4602     }
4603     bool teleported = false;
4604     int x, y;
4605     if (map->findRandomLoc(x, y, MOVE_WALK,
4606 				true,
4607 				false, false,
4608 				false, false,
4609 				false))
4610     {
4611 	// Teleport the item
4612 	formatAndReport("%U <teleport>.");
4613 	// We lose our mapping information.
4614 	markMapped(false);
4615 	if (mapownsitem)
4616 	    map->dropItem(this);
4617 	// This ensures our item maps are updated
4618 	// and it drops in lava, etc.
4619 	map->acquireItem(this, x, y, teleporter);
4620 	teleported = true;
4621     }
4622     return teleported;
4623 }
4624 
4625 bool
fallInHole(MAP * curLevel,bool mapownsitem,MOB * dropper)4626 ITEM::fallInHole(MAP *curLevel, bool mapownsitem, MOB *dropper)
4627 {
4628     MAP		*nextmap;
4629     int		 x, y;
4630 
4631     nextmap = curLevel->getMapDown();
4632     if (!nextmap)
4633     {
4634 	formatAndReport("%R fall <be> stopped by an invisible barrier.");
4635 	return false;
4636     }
4637 
4638     if (!nextmap->findRandomLoc(x, y, MOVE_WALK,
4639 				true,
4640 				false, false,
4641 				false, false,
4642 				false))
4643     {
4644 	formatAndReport("%U <land> on the edge of a hole.");
4645 	return false;
4646     }
4647 
4648     formatAndReport("%U <fall> into a hole.");
4649 
4650     // We no longer know where it is
4651     markMapped(false);
4652 
4653     if (mapownsitem)
4654 	curLevel->dropItem(this);
4655     nextmap->acquireItem(this, x, y, dropper);
4656 
4657     return true;
4658 }
4659 
4660 ITEM *
load(SRAMSTREAM & is)4661 ITEM::load(SRAMSTREAM &is)
4662 {
4663     ITEM	*me;
4664     int		 val;
4665 
4666     me = new ITEM();
4667 
4668     is.uread(val, 8);
4669     me->myDefinition = val;
4670     me->myName.load(is);
4671     is.uread(val, 8);
4672     val ^= 1;
4673     me->myStackCount = val;
4674     is.uread(val, 8);
4675     me->myX = val;
4676     is.uread(val, 8);
4677     me->myY = val;
4678     is.read(val, 8);
4679     me->myEnchantment = val;
4680     is.uread(val, 8);
4681     me->myCharges = val;
4682     is.uread(val, 8);
4683     me->myPoison = val;
4684     is.uread(val, 8);
4685     me->myPoisonCharges = val;
4686     is.uread(val, 32);
4687     val ^= glb_itemdefs[me->myDefinition].flag1;
4688     me->myFlag1 = (ITEMFLAG1_NAMES) val;
4689 
4690     // Read in the corpse mob.
4691     me->myCorpseMob.load(is);
4692     if (!me->myCorpseMob.isNull())
4693     {
4694 	MOB		*mob;
4695 
4696 	mob = MOB::load(is);
4697 	// myCorpseMob will already point to mob, but might as well
4698 	// assert.
4699 	UT_ASSERT(mob == me->myCorpseMob.getMob());
4700     }
4701 
4702     return me;
4703 }
4704 
4705 void
save(SRAMSTREAM & os)4706 ITEM::save(SRAMSTREAM &os)
4707 {
4708     os.write(myDefinition, 8);
4709     myName.save(os);
4710     os.write(myStackCount ^ 1, 8);
4711     os.write(myX, 8);
4712     os.write(myY, 8);
4713     os.write(myEnchantment, 8);
4714     os.write(myCharges, 8);
4715     os.write(myPoison, 8);
4716     os.write(myPoisonCharges, 8);
4717 
4718     os.write(myFlag1 ^ glb_itemdefs[myDefinition].flag1, 32);
4719 
4720     // Save our corpse mob.
4721     // If it is non-zero, we also will save the mob itself.
4722     MOB		*mob;
4723     mob = myCorpseMob.getMob();
4724 
4725     myCorpseMob.save(os);
4726     if (mob)
4727 	mob->save(os);
4728 
4729     // TODO: Save the name???
4730 }
4731 
4732 bool
verifyMob() const4733 ITEM::verifyMob() const
4734 {
4735     MOB		*mob;
4736     mob = myCorpseMob.getMob();
4737     if (mob)
4738 	return mob->verifyMob();
4739     return true;
4740 }
4741 
4742 bool
verifyCounterGone(INTRINSIC_COUNTER * counter) const4743 ITEM::verifyCounterGone(INTRINSIC_COUNTER *counter) const
4744 {
4745     MOB		*mob;
4746     mob = myCorpseMob.getMob();
4747     if (mob)
4748 	return mob->verifyCounterGone(counter);
4749     return true;
4750 }
4751 
4752 void
loadGlobal(SRAMSTREAM & is)4753 ITEM::loadGlobal(SRAMSTREAM &is)
4754 {
4755     int		i, val;
4756 
4757     for (i = 0; i < NUM_ITEMS; i++)
4758     {
4759 	is.uread(val, 8);
4760 	glb_magicitem[i] = val;
4761     }
4762 
4763     for (i = 0; i < NUM_ITEMS; i++)
4764     {
4765 	is.uread(val, 8);
4766 	glb_itemid[i] = val ? true : false;
4767     }
4768 
4769     for (i = 0; i < NUM_ITEMS; i++)
4770     {
4771 	char	buf[100];
4772 	is.readString(buf, 100);
4773 	if (glb_itemnames[i])
4774 	    free(glb_itemnames[i]);
4775 	if (buf[0])
4776 	    glb_itemnames[i] = strdup(buf);
4777 	else
4778 	    glb_itemnames[i] = 0;
4779     }
4780 }
4781 
4782 void
saveGlobal(SRAMSTREAM & is)4783 ITEM::saveGlobal(SRAMSTREAM &is)
4784 {
4785     int		i, val;
4786 
4787     for (i = 0; i < NUM_ITEMS; i++)
4788     {
4789 	val = glb_magicitem[i];
4790 	is.write(val, 8);
4791     }
4792 
4793     for (i = 0; i < NUM_ITEMS; i++)
4794     {
4795 	val = glb_itemid[i];
4796 	is.write(val, 8);
4797     }
4798     for (i = 0; i < NUM_ITEMS; i++)
4799     {
4800 	is.writeString(glb_itemnames[i], 100);
4801     }
4802 }
4803