Blindfold removal fix
[slashemextended.git] / src / gypsy.c
blob87263b82d9f2a4af91524e8a429cd6db31484860
1 /*** gypsy.c ***/
3 #include "hack.h"
4 #include "egyp.h"
5 #include "qtext.h"
8 /* To do:
9 * fortune_lev()
10 * Fourtunes for suited cards
11 * On-line help
15 /*** Money-related functions ***/
17 static void
18 gypsy_charge (mtmp, amount)
19 struct monst *mtmp;
20 long amount;
22 #ifdef GOLDOBJ
23 struct obj *gypgold;
24 #endif
26 /* Take from credit first */
27 if (amount > EGYP(mtmp)->credit) {
28 /* Do in several steps, for broken compilers */
29 amount -= EGYP(mtmp)->credit;
30 EGYP(mtmp)->credit = 0;
31 #ifdef GOLDOBJ
32 money2mon(mtmp, amount);
33 #else
34 u.ugold -= amount;
35 #endif
36 flags.botl = 1;
37 } else
38 EGYP(mtmp)->credit -= amount;
40 /* The gypsy never carries cash; it might get stolen! */
41 #ifdef GOLDOBJ
42 gypgold = findgold(mtmp->minvent);
43 if (gypgold)
44 m_useup(mtmp, gypgold);
45 #endif
46 return;
49 static boolean
50 gypsy_offer (mtmp, cost, txt)
51 struct monst *mtmp;
52 long cost;
53 char *txt;
55 #ifdef GOLDOBJ
56 long umoney;
57 umoney = money_cnt(invent);
58 #endif
59 verbalize("For %ld credit I will %s!", cost, txt);
60 if (EGYP(mtmp)->credit >= cost) {
61 if (yn("Accept this offer?") == 'y') {
62 EGYP(mtmp)->credit -= cost;
63 return (TRUE);
65 #ifndef GOLDOBJ
66 } else if (EGYP(mtmp)->credit + u.ugold >= cost)
67 verbalize("What a pity that I can't accept gold!");
68 #else
69 } else if (EGYP(mtmp)->credit + umoney >= cost)
70 verbalize("What a pity that I can't accept money!");
71 #endif
72 /* Maybe you could try gambling some of it for credit... */
73 else
74 verbalize("What a pity that you don't have enough!");
75 return (FALSE);
78 static long
79 gypsy_bet (mtmp, minimum)
80 struct monst *mtmp;
81 long minimum;
83 char prompt[BUFSZ], buf[BUFSZ];
84 long bet = 0L;
85 #ifdef GOLDOBJ
86 long umoney;
87 umoney = money_cnt(invent);
88 #endif
90 if (minimum > EGYP(mtmp)->credit +
91 #ifndef GOLDOBJ
92 u.ugold) {
93 #else
94 umoney) {
95 #endif
96 You("don't have enough money for the minimum bet.");
97 return (0L);
100 /* Prompt for an amount */
101 sprintf(prompt, "Bet how much (%ld to %ld)?", minimum,
102 EGYP(mtmp)->credit +
103 #ifndef GOLDOBJ
104 u.ugold);
105 #else
106 umoney);
107 #endif
108 getlin(prompt, buf);
109 (void) sscanf(buf, "%ld", &bet);
111 /* Validate the amount */
112 if (bet == 0L) {
113 pline("Never mind.");
114 if (FailureEffects || u.uprops[FAILURE_EFFECTS].extrinsic || have_failurestone()) {
115 pline("Oh wait, actually I do mind...");
116 badeffect();
118 return (0L);
120 if (bet < minimum) {
121 You("must bet at least %ld.", minimum);
122 return (0L);
124 if (bet > EGYP(mtmp)->credit +
125 #ifndef GOLDOBJ
126 u.ugold) {
127 #else
128 umoney) {
129 #endif
130 You("don't have that much money to bet!");
131 return (0L);
133 return (bet);
137 /*** Card-related functions ***/
139 static const char *suits[CARD_SUITS] =
140 { "swords", "wands", "shields", "rings" }; /* Special */
141 /* swords wands/rods roses/cups pentacles/disks/coins Tarot */
142 /* spade bastoni coppe denari Italian */
143 /* swords batons cups coins (translated) */
144 /* spades clubs hearts diamonds French */
147 static const char *ranks[CARD_RANKS] =
148 { "ace", "2", "3", "4", "5", "6", "7", "8", "9", "10",
149 /*none*/ "jack", "queen", "king" }; /* French */
150 /* page/princess knight/prince queen king Tarot */
153 static const char *trumps[CARD_TRUMPS] =
154 { "the Fool", /* This is NOT a Joker */
155 "the Magician", /* same as the Magus */
156 "the High Priestess", /* sometimes placed after the Emperor */
157 #if 0
158 "the Empress", /* not included here */
159 "the Emperor", /* not included here */
160 #endif
161 "the Oracle", /* same as the Hierophant */
162 "the Lovers",
163 "the Chariot",
164 "Strength", /* sometimes Adjustment */
165 "the Hermit",
166 "the Wheel of Fortune", /* sometimes Fortune */
167 "Justice", /* sometimes Lust */
168 "Punishment", /* replaces the Hanged Man */
169 "the Devil", /* normally #15 */
170 "Sorcery", /* replaces Art or Temperance */
171 "Death", /* swapped with the Devil so it remains #13 */
172 "the Tower", /* really! */
173 "the Star",
174 "the Moon",
175 "the Sun",
176 "Judgement", /* sometimes Aeon */
177 "Infinity" /* replaces the World or the Universe */
181 static void
182 card_shuffle (mtmp)
183 struct monst *mtmp;
185 xchar *cards = &EGYP(mtmp)->cards[0];
186 int i, j, k;
189 pline("%s shuffles the cards.", Monnam(mtmp));
190 for (i = 0; i < CARD_TOTAL; i++)
191 /* Initialize the value */
192 cards[i] = i;
193 for (i = 0; i < CARD_TOTAL; i++) {
194 /* Swap this value with another randomly chosen one */
195 j = rn2(CARD_TOTAL);
196 k = cards[j];
197 cards[j] = cards[i];
198 cards[i] = k;
200 EGYP(mtmp)->top = CARD_TOTAL;
203 static xchar
204 card_draw (mtmp)
205 struct monst *mtmp;
207 if (EGYP(mtmp)->top <= 0)
208 /* The deck is empty */
209 return (-1);
210 return (EGYP(mtmp)->cards[--EGYP(mtmp)->top]);
213 static void
214 card_name (num, buf)
215 xchar num;
216 char *buf;
218 int r, s;
221 if (!buf) return;
222 if (Hallucination) num = rn2(CARD_TOTAL);
223 if (num < 0 || num >= CARD_TOTAL) {
224 /* Invalid card */
225 impossible("no such card %d", num);
226 strcpy(buf, "a card");
227 } else if (card_istrump(num)) {
228 /* Handle trump cards */
229 r = card_trump(num);
230 if (!r)
231 sprintf(buf, "the zero of trumps (%s)", trumps[r]);
232 else
233 sprintf(buf, "the %d of trumps (%s)", r, trumps[r]);
234 } else {
235 /* Handle suited cards */
236 r = card_rank(num);
237 s = card_suit(num);
238 sprintf(buf, "the %s of %s", ranks[r], suits[s]);
240 return;
244 /*** Fortunes ***/
246 #define FORTUNE_COST 50 /* Cost to play */
248 static short birthstones[12] =
250 /* Jan */ GARNET, /* Feb */ AMETHYST,
251 /* Mar */ AQUAMARINE, /* Apr */ DIAMOND,
252 /* May */ EMERALD, /* Jun */ OPAL,
253 /* Jul */ RUBY, /* Aug */ CHRYSOBERYL,
254 /* Sep */ SAPPHIRE, /* Oct */ BLACK_OPAL,
255 /* Nov */ TOPAZ, /* Dec */ TURQUOISE
259 static void
260 fortune_lev (mtmp, name, txt)
261 struct monst *mtmp;
262 char *name, *txt;
264 /*** FIXME -- still very buggy ***/
265 /* d_level *lev;*/
266 schar dep;
269 dep = lev_by_name(name);
270 if (!dep) {
271 /* Perhaps the level doesn't exist? */
272 verbalize("The vision is hazy.");
273 return;
276 if (dep == depth(&u.uz))
277 verbalize("I see %s here.", txt);
278 else {
279 verbalize("I see %s on level %d.", txt, (int)dep);
280 /* if (gypsy_offer(mtmp, 5000L, "teleport you there"))
283 return;
286 static void
287 fortune (mtmp)
288 struct monst *mtmp;
290 xchar card;
291 char buf[BUFSZ];
292 short otyp;
293 struct obj *otmp;
296 /* Shuffle the deck, if neccessary, and draw a card */
297 gypsy_charge(mtmp, FORTUNE_COST);
298 if (EGYP(mtmp)->top <= 0)
299 card_shuffle(mtmp);
300 card = card_draw(mtmp);
301 #ifdef WIZARD
302 if (wizard) {
303 long t = -1;
305 getlin("Which trump?", buf);
306 (void) sscanf(buf, "%ld", &t);
307 if (t >= 0) card = t + CARD_SUITED;
309 #endif
310 card_name(card, buf);
311 verbalize("You have drawn %s.", buf);
313 if (card_istrump(card))
314 switch (card_trump(card)) {
315 case 0: /* the Fool */
316 adjattrib(A_WIS, -1, 0, TRUE);
317 change_luck(-3);
318 break;
319 case 1: /* the Magician */
320 if (u.uevent.udemigod)
321 resurrect();
322 else
323 fortune_lev(mtmp, "fakewiz1",
324 "an entrance to the Wizard's tower");
325 /*fortune_lev(mtmp, &portal_level);*/
326 break;
327 case 2: /* the High Priestess */
328 if (u.uhave.amulet)
329 verbalize("I see a high altar in the heavens.");
330 /* Can only get there by ascending... */
331 else
332 verbalize("I see a high altar on level %d.",
333 depth(&sanctum_level));
334 /* Can only get there by invocation... */
335 break;
336 case 3: /* the Oracle */
337 fortune_lev(mtmp, "oracle", "the Oracle");
338 /*fortune_lev(mtmp, &oracle_level);*/
339 break;
340 case 4: /* the Lovers */
341 makemon(&mons[flags.female ? PM_INCUBUS : PM_SUCCUBUS],
342 u.ux, u.uy, 0);
343 break;
344 case 5: /* the Chariot */
345 if (gypsy_offer(mtmp, 5000L,
346 "teleport you to a level of your choosing")) {
347 incr_itimeout(&HTeleport_control, 1);
348 if (!playerlevelportdisabled()) level_tele();
349 else pline("But unfortunately you aren't allowed to level teleport.");
351 break;
352 case 6: /* Strength */
353 adjattrib(A_STR, 1, 0, TRUE);
354 incr_itimeout(&HHalf_physical_damage, rn1(500, 500));
355 break;
356 case 7: /* the Hermit */
357 You_feel("like hiding!");
358 incr_itimeout(&HTeleportation, rn1(300, 300));
359 incr_itimeout(&HInvis, rn1(500, 500));
360 newsym(u.ux, u.uy);
361 break;
362 case 8: /* the Wheel of Fortune */
363 if (FunnyHallu)
364 pline("Where is Vanna?");
365 else
366 You_feel("lucky!");
367 if (u.uluck < 0)
368 u.uluck = 0;
369 else
370 change_luck(3);
371 break;
372 case 9: /* Justice */
373 makemon(&mons[PM_ERINYS], u.ux, u.uy, 0);
374 break;
375 case 10: /* Punishment */
376 if (!Punished)
377 punish((struct obj *)0);
378 else
379 rndcurse();
380 break;
381 case 11: /* the Devil */
382 summon_minion(A_NONE, TRUE);
383 break;
384 case 12: /* Sorcery */
385 adjattrib(urole.spelstat, 1, 0, TRUE);
386 incr_itimeout(&HHalf_spell_damage, rn1(500, 500));
387 break;
388 case 13: /* Death */
389 if (nonliving(youmonst.data) || is_demon(youmonst.data) || PlayerResistsDeathRays)
390 shieldeff(u.ux, u.uy);
391 else if(Hallucination)
392 You("have an out of body experience.");
393 else {
394 u.youaredead = 1;
395 killer_format = KILLED_BY;
396 killer = "the card of Death";
397 done(DIED);
398 u.youaredead = 0;
400 break;
401 case 14: /* the Tower */
402 fortune_lev(mtmp, "vlad\'s tower", "Vlad the Impaler");
403 /* fortune_lev(mtmp, &vlad_level); */
404 break;
405 case 15: /* the Star */
406 if (rn2(3)) break; /* greatly reduce player's farming ability --Amy */
407 otyp = birthstones[getmonth()];
408 makeknown(otyp);
409 if ((otmp = mksobj(otyp, TRUE, FALSE, TRUE)) != (struct obj *)0) {
410 pline("%s reaches behind your %s and pulls out %s.",
411 Monnam(mtmp), body_part(HEAD), doname(otmp));
412 if (pickup_object(otmp, otmp->quan, FALSE, FALSE) <= 0) {
413 obj_extract_self(otmp);
414 place_object(otmp, u.ux, u.uy);
415 newsym(u.ux, u.uy);
418 break;
419 case 16: /* the Moon */
420 /* Reset the old moonphase */
421 if (flags.moonphase == FULL_MOON)
422 change_luck(-1);
423 if (flags.moonphase == NEW_MOON)
424 adjalign(+3);
426 /* Set the new moonphase */
427 flags.moonphase = phase_of_the_moon();
428 switch (flags.moonphase) {
429 case NEW_MOON:
430 pline("Be careful! New moon tonight.");
431 adjalign(-3);
432 break;
433 case 1: case 2: case 3:
434 pline_The("moon is waxing tonight.");
435 break;
436 case FULL_MOON:
437 You(FunnyHallu ? "are on the moon tonight!" : "are lucky! Full moon tonight.");
438 change_luck(1);
439 break;
440 case 5: case 6: case 7:
441 pline_The("moon is waning tonight.");
442 break;
443 default:
444 impossible("wierd moonphase %d", flags.moonphase);
445 break;
447 break;
448 case 17: /* the Sun */
449 if (midnight())
450 verbalize("It is the witching hour. Beware of the undead!");
451 else if (night())
452 verbalize("It is nighttime. Beware of creatures of the night!");
453 else
454 verbalize("It is daytime. Shouldn't you be working?");
455 break;
456 case 18: /* Judgement */
457 fortune_lev(mtmp, "portal to quest",
458 "a portal to a quest");
459 /* fortune_lev(mtmp, &quest_level); */
460 break;
461 case 19: /* Infinity */
462 if (mtmp->mcan || rn2(5) ) { /* tone down abuse potential --Amy */
463 verbalize("I wish I wasn't here!");
464 mongone(mtmp);
465 } else if (gypsy_offer(mtmp, 10000L, "grant you a wish")) {
466 mtmp->mcan = TRUE;
467 makewish(TRUE);
469 break;
470 default:
471 impossible("unknown trump %d", card_trump(card));
472 break;
473 } /* End trumps */
474 else
475 /* Suited card */
476 com_pager(QT_GYPSY + card);
478 return;
482 /*** Three-card monte ***/
484 #define MONTE_COST 1 /* Minimum bet */
485 #define MONTE_MAX 10 /* Maximum value of monteluck */
488 static void
489 monte (mtmp)
490 struct monst *mtmp;
492 long bet, n;
493 char buf[BUFSZ];
494 winid win;
495 anything any;
496 menu_item *selected;
497 int delta;
500 /* Get the bet */
501 bet = gypsy_bet(mtmp, MONTE_COST);
502 if (!bet) return;
504 /* Shuffle and pick */
505 if (flags.verbose)
506 pline("%s places three cards and rearranges them.", Monnam(mtmp));
507 any.a_void = 0; /* zero out all bits */
508 win = create_nhwindow(NHW_MENU);
509 start_menu(win);
510 any.a_char = 'l';
511 add_menu(win, NO_GLYPH, &any , 'l', 0, ATR_NONE,
512 "Left card", MENU_UNSELECTED);
513 any.a_char = 'c';
514 add_menu(win, NO_GLYPH, &any , 'c', 0, ATR_NONE,
515 "Center card", MENU_UNSELECTED);
516 any.a_char = 'r';
517 add_menu(win, NO_GLYPH, &any , 'r', 0, ATR_NONE,
518 "Right card", MENU_UNSELECTED);
519 end_menu(win, "Pick a card:");
520 while (select_menu(win, PICK_ONE, &selected) != 1) ;
521 destroy_nhwindow(win);
523 /* Calculate the change in odds for next time */
524 /* Start out easy, but get harder once the player is suckered */
525 delta = rnl(4) - 3; /* Luck helps */
526 if (u.umontelast == selected[0].item.a_char)
527 /* Only suckers keep picking the same card */
528 delta++;
529 u.umontelast = selected[0].item.a_char;
530 for (n = bet; n > 0; n /= 10L)
531 /* Penalize big bets */
532 delta++;
533 /* pline("luck = %d; delta = %d", u.umonteluck, delta);*/
535 /* Did we win? */
536 if (u.umonteluck <= rn2(MONTE_MAX) && rn2(2) ) { /* no longer automatically win --Amy */
537 if (u.umonteluck == 0)
538 verbalize("You win! Wasn't that easy?");
539 else
540 verbalize("You win!");
541 EGYP(mtmp)->credit += bet;
543 /* Make it harder for next time */
544 if (delta > 0) u.umonteluck += delta;
545 if (u.umonteluck > MONTE_MAX) u.umonteluck = MONTE_MAX;
546 } else {
547 card_name(rn1(2, 1), buf);
548 verbalize("Sorry, you picked %s. Try again.", buf);
549 gypsy_charge(mtmp, bet);
551 /* Make it a little easier for next time */
552 if (delta < 0) u.umonteluck += delta;
553 if (u.umonteluck < 0) u.umonteluck = 0;
555 return;
559 /*** Ninety-nine ***/
561 #define NINETYNINE_COST 1 /* Minimum bet */
562 #define NINETYNINE_HAND 3 /* Number of cards in hand */
563 #define NINETYNINE_GOAL 99 /* Limit of the total */
565 static boolean
566 nn_playable (card, total)
567 xchar card;
568 int total;
570 if (card_istrump(card))
571 /* The fool always loses; other trumps are always playable */
572 return (card != CARD_SUITED);
573 switch (card_rank(card)+1) {
574 case 11: /* Jack */
575 case 12: /* Queen */
576 return (total >= 10);
577 case 13: /* King */
578 return (TRUE);
579 default: /* Ace through 10 */
580 return ((total + card_rank(card) + 1) <= NINETYNINE_GOAL);
584 static int
585 nn_play (card, total)
586 xchar card;
587 int total;
589 if (card_istrump(card)) {
590 if (card == CARD_SUITED)
591 /* The Fool always loses */
592 return (NINETYNINE_GOAL+1);
593 else
594 /* Other trumps leave the total unchanged */
595 return (total);
597 switch (card_rank(card)+1) {
598 case 11: /* Jack */
599 case 12: /* Queen */
600 return (total - 10);
601 case 13: /* King */
602 return (NINETYNINE_GOAL);
603 default: /* Ace through 10 */
604 return (total + card_rank(card) + 1);
608 static int
609 nn_pref (card)
610 xchar card;
612 /* Computer's preferences for playing cards:
613 * 3. Get rid of Ace through 10 whenever we can. Highest priority.
614 * 2. King will challenge the player. High priority.
615 * 1. Jack and queen may help us, or the hero. Low priority.
616 * 0. Trumps can always be played (except the fool). Lowest priority.
618 if (card_istrump(card))
619 /* The fool always loses; other trumps are always playable */
620 return (0);
621 switch (card_rank(card)+1) {
622 case 11: /* Jack */
623 case 12: /* Queen */
624 return (1);
625 case 13: /* King */
626 return (2);
627 default: /* Ace through 10 */
628 return (3);
633 static void
634 ninetynine (mtmp)
635 struct monst *mtmp;
637 long bet;
638 int i, n, which, total = 0;
639 xchar uhand[NINETYNINE_HAND], ghand[NINETYNINE_HAND];
640 char buf[BUFSZ];
641 winid win;
642 anything any;
643 menu_item *selected;
646 /* Get the bet */
647 bet = gypsy_bet(mtmp, NINETYNINE_COST);
648 if (!bet) return;
650 /* Shuffle the deck and deal */
651 card_shuffle(mtmp);
652 for (i = 0; i < NINETYNINE_HAND; i++) {
653 uhand[i] = card_draw(mtmp);
654 ghand[i] = card_draw(mtmp);
657 while (1) {
658 /* Let the user pick a card */
659 any.a_void = 0; /* zero out all bits */
660 win = create_nhwindow(NHW_MENU);
661 start_menu(win);
662 for (i = 0; i < NINETYNINE_HAND; i++) {
663 any.a_int = (nn_playable(uhand[i], total) ? i+1 : 0);
664 card_name(uhand[i], buf);
665 add_menu(win, NO_GLYPH, &any , 0, 0, ATR_NONE,
666 buf, MENU_UNSELECTED);
668 any.a_int = NINETYNINE_HAND + 1;
669 add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
670 "Forfeit", MENU_UNSELECTED);
671 end_menu(win, "Play a card:");
672 while (select_menu(win, PICK_ONE, &selected) != 1) ;
673 destroy_nhwindow(win);
675 /* Play the card */
676 which = selected[0].item.a_int-1;
677 if (which >= NINETYNINE_HAND) {
678 You("forfeit.");
679 gypsy_charge(mtmp, bet);
680 return;
682 card_name(uhand[which], buf);
683 total = nn_play(uhand[which], total);
684 You("play %s for a total of %d.", buf, total);
685 if (total < 0 || total > NINETYNINE_GOAL) {
686 You("lose!");
687 gypsy_charge(mtmp, bet);
688 return;
691 /* Draw a new card */
692 uhand[which] = card_draw(mtmp);
693 if (uhand[which] < 0) {
694 pline_The("deck is empty. You win!");
695 EGYP(mtmp)->credit += bet;
696 return;
699 /* Let the gypsy pick a card */
700 n = 0;
701 for (i = 0; i < NINETYNINE_HAND; i++)
702 if (nn_playable(ghand[i], total)) {
703 /* The card is playable, but is it the best? */
704 if (!n++ || nn_pref(ghand[i]) > nn_pref(ghand[which]))
705 which = i;
707 if (!n) {
708 /* No playable cards */
709 pline("%s forfeits. You win!", Monnam(mtmp));
710 EGYP(mtmp)->credit += bet;
711 return;
714 /* Play the card */
715 card_name(ghand[which], buf);
716 total = nn_play(ghand[which], total);
717 pline("%s plays %s for a total of %d.", Monnam(mtmp), buf, total);
719 /* Draw a new card */
720 ghand[which] = card_draw(mtmp);
721 if (ghand[which] < 0) {
722 pline_The("deck is empty. You win!");
723 EGYP(mtmp)->credit += bet;
724 return;
728 return;
733 /*** Pawn gems ***/
735 STATIC_OVL NEARDATA const char pawnables[] = { ALLOW_COUNT, GEM_CLASS, 0 };
737 static void
738 pawn (mtmp)
739 struct monst *mtmp;
741 struct obj *otmp;
742 long value;
745 /* Prompt for an item */
746 otmp = getobj((const char *)pawnables, "pawn");
748 /* Is the item valid? */
749 if (!otmp) return;
750 if (!objects[otmp->otyp].oc_name_known) {
751 /* Reject unknown objects */
752 verbalize("Is this merchandise authentic?");
753 return;
755 if (otmp->otyp < DILITHIUM_CRYSTAL || otmp->otyp > LAST_GEM) {
756 /* Reject glass */
757 verbalize("Don\'t bother with that junk!");
758 return;
761 if (otmp->objwassold) { /* filthy exploit exploiter --Amy */
762 verbalize("It was sold once already! I don't want it!");
763 return;
766 /* Give the credit */
767 value = otmp->quan * objects[otmp->otyp].oc_cost;
768 pline("%s gives you %ld zorkmid%s credit.", Monnam(mtmp),
769 value, plur(value));
770 EGYP(mtmp)->credit += value;
772 /* Gypsies don't keep merchandise; it could get stolen! */
773 otmp->quan = 1L;
774 useup(otmp);
775 return;
779 /*** Yendorian Tarocchi ***/
781 #define TAROCCHI_COST 500 /* Cost to play */
782 #define TAROCCHI_HAND 10 /* Number of cards in hand */
784 static void
785 tarocchi (mtmp)
786 struct monst *mtmp;
788 int turn;
790 /* Shuffle the deck and deal */
791 gypsy_charge(mtmp, TAROCCHI_COST);
792 card_shuffle(mtmp);
794 /* Play the given number of turns */
795 for (turn = TAROCCHI_HAND; turn > 0; turn--) {
798 return;
802 /*** Monster-related functions ***/
804 void
805 gypsy_init (mtmp)
806 struct monst *mtmp;
808 mtmp->isgyp = TRUE;
809 mtmp->mpeaceful = TRUE;
810 mtmp->msleeping = 0;
811 /*mtmp->mtrapseen = ~0;*/ /* traps are known */
812 EGYP(mtmp)->credit = 0L;
813 EGYP(mtmp)->top = 0;
814 return;
818 void
819 gypsy_chat (mtmp)
820 struct monst *mtmp;
822 long money;
823 winid win;
824 anything any;
825 menu_item *selected;
826 #ifdef GOLDOBJ
827 long umoney;
828 #endif
829 int n;
831 #ifdef GOLDOBJ
832 umoney = money_cnt(invent);
833 #endif
835 /* Sanity checks */
836 if (!mtmp || !mtmp->mpeaceful || !mtmp->isgyp ||
837 !humanoid(mtmp->data))
838 return;
840 /* Add up your available money */
841 You("have %ld zorkmid%s credit and are carrying %ld zorkmid%s.",
842 EGYP(mtmp)->credit, plur(EGYP(mtmp)->credit),
843 #ifndef GOLDOBJ
844 u.ugold, plur(u.ugold));
845 #else
846 umoney, plur(umoney));
847 #endif
848 money = EGYP(mtmp)->credit +
849 #ifndef GOLDOBJ
850 u.ugold;
851 #else
852 umoney;
853 #endif
855 /* Create the menu */
856 any.a_void = 0; /* zero out all bits */
857 win = create_nhwindow(NHW_MENU);
858 start_menu(win);
860 /* Fortune */
861 any.a_char = 'f';
862 if (money >= FORTUNE_COST)
863 add_menu(win, NO_GLYPH, &any , 'f', 0, ATR_NONE,
864 "Read your fortune", MENU_UNSELECTED);
866 /* Three-card monte */
867 any.a_char = 'm';
868 if (money >= MONTE_COST)
869 add_menu(win, NO_GLYPH, &any , 'm', 0, ATR_NONE,
870 "Three-card monte", MENU_UNSELECTED);
872 /* Ninety-nine */
873 any.a_char = 'n';
874 if (money >= NINETYNINE_COST)
875 add_menu(win, NO_GLYPH, &any , 'n', 0, ATR_NONE,
876 "Ninety-nine", MENU_UNSELECTED);
878 /* Pawn gems (always available) */
879 any.a_char = 'p';
880 add_menu(win, NO_GLYPH, &any , 'p', 0, ATR_NONE,
881 "Pawn gems", MENU_UNSELECTED);
883 /* Yendorian Tarocchi */
884 any.a_char = 't';
885 /* if (money >= TAROCCHI_COST)
886 add_menu(win, NO_GLYPH, &any , 't', 0, ATR_NONE,
887 "Yendorian Tarocchi", MENU_UNSELECTED);*/
889 /* Help */
890 any.a_char = '?';
891 add_menu(win, NO_GLYPH, &any , '?', 0, ATR_NONE,
892 "Help", MENU_UNSELECTED);
894 /* Display the menu */
895 end_menu(win, "Play which game?");
896 n = select_menu(win, PICK_ONE, &selected);
897 destroy_nhwindow(win);
898 if (n > 0) switch (selected[0].item.a_char) {
899 case 'f':
900 fortune(mtmp);
901 break;
902 case 'm':
903 monte(mtmp);
904 break;
905 case 'n':
906 ninetynine(mtmp);
907 break;
908 case 'p':
909 pawn(mtmp);
910 break;
911 case 't':
912 tarocchi(mtmp);
913 break;
914 case '?':
915 display_file_area(FILE_AREA_SHARE, "gypsy.txt", TRUE);
916 break;
919 return;
922 /* draw a card for blackjack minigame; unlike the real Black Jack game, there is no 'deck', and there's both an ace
923 * and a 1 point card, however if someone's first two cards are both an ace, the second ace automatically turns into
924 * a 1 point card because busting with less than 3 cards is supposed to be impossible
925 * we don't disambiguate between 10, jack, queen and king; if the starting hand is 21, there's simply an 80% chance
926 * for it to be a black jack (four, not five 10 point cards existing notwithstanding) */
928 blackjack_card()
930 int blackjackcard = rnd(14); /* "suits" don't exist here because there's no deck to be aware of; a typical Black Jack deck would have 52 cards, 13 for each suit, but since we also have a 1 point card, there's actually 14 cards for each suit */
931 if (blackjackcard >= 12) blackjackcard = 10;
932 return blackjackcard;
935 /* blackjack minigame by Amy: the more often you win, the more likely the dealer will disappear
936 * returns at least 1 if the player decided to play
937 * returns 2 if the dealer will disappear
938 * rules are slightly different from the real Black Jack game, and the dealer can cheat
939 * the player's luck stat can slightly affect the chance that the dealer cheats
940 * heavily inspired by Elona, but the implementation is my own --Amy */
942 play_blackjack(forfree)
943 boolean forfree; /* if this is true, you don't have to pay; for artifact invokes etc. */
945 int dealercheatchance = 10;
946 int playerblackjackwins = 0;
947 int disappearchance = 10;
948 struct obj *blackjackreward;
950 if (forfree) {
951 You("start a round of blackjack at Fortune Cookie Casino.");
952 } else if (u.casinochips) {
953 if (yn("Play blackjack? (use a casino chip)") != 'y') {
954 return 0;
956 u.casinochips--;
957 if (u.casinochips < 0) u.casinochips = 0; /* fail safe */
958 You("use a casino chip and have %d remaining.", u.casinochips);
959 } else {
960 if (yn("Play blackjack? (2000 zorkmids)") != 'y') {
961 return 0;
963 if (u.ugold < 2000) {
964 verbalize("Sorry sir, you don't seem to have enough money to buy a casino chip.");
965 return 0;
967 u.ugold -= 2000;
970 int playercards = 0;
971 int dealercards = 0;
972 int dealerfirstcard = 0;
973 int playerhand = 0;
974 int dealerhand = 0;
975 int dealervisiblehand = 0;
976 int tempcardvar = 0;
978 newblackjackrun:
979 playercards = 0;
980 dealercards = 0;
981 dealerfirstcard = 0;
982 playerhand = 0;
983 dealerhand = 0;
984 dealervisiblehand = 0;
985 tempcardvar = 0;
986 dealercheatchance = (10 - Luck + (playerblackjackwins * 5)); /* dealer becomes increasingly more difficult to defeat the more often you win in a row, making it almost impossible to get the later rewards */
988 /* the dealer's first card is upside down so you don't know what it is */
989 dealerfirstcard = blackjack_card();
990 dealerhand += dealerfirstcard;
991 tempcardvar = blackjack_card();
992 if (dealerhand == 11 && tempcardvar == 11) tempcardvar = 1; /* can't bust on first turn */
993 if (dealerhand >= 10 && (rn2(100) < dealercheatchance)) { /* dealer can cheat to automatically get a black jack */
994 pline("Tough luck! The dealer has a black jack, and you automatically lose.");
995 u.cnd_blackjackdealercheat++;
996 goto blackjackgameover;
998 dealerhand += tempcardvar;
999 dealervisiblehand += tempcardvar;
1000 dealercards = 2;
1001 if (dealerhand == 21 && rn2(5)) {
1002 pline("Tough luck! The dealer has a black jack, and you automatically lose.");
1003 goto blackjackgameover;
1005 /* it is not a bug that you don't get to roll for your own black jack, because this game favors the dealer;
1006 * if he has a black jack, you autolose regardless of your own hand */
1008 /* dealer has to draw on 15 and stand on 16; this is probably different from RL blackjack */
1009 while (dealercards < 5 && dealerhand < 16) {
1010 tempcardvar = blackjack_card();
1011 if (dealerhand > 21 && (rn2(100) < dealercheatchance)) { /* dealer can cheat to ensure he doesn't bust */
1012 tempcardvar = rnd(21 - dealerhand);
1013 u.cnd_blackjackdealercheat++;
1015 dealerhand += tempcardvar;
1016 dealervisiblehand += tempcardvar;
1017 dealercards++;
1019 pline("The dealer's visible hand is %d with %d cards drawn.", dealervisiblehand, dealercards);
1021 tempcardvar = blackjack_card();
1022 playerhand += tempcardvar;
1023 tempcardvar = blackjack_card();
1024 if (playerhand == 11 && tempcardvar == 11) tempcardvar = 1; /* can't bust on first turn */
1025 if (playerhand == 10 && tempcardvar == 11 && (rn2(100) < dealercheatchance)) { /* dealer can cheat to make you not get a black jack */
1026 tempcardvar = rnd(10);
1027 u.cnd_blackjackdealercheat++;
1029 if (playerhand == 11 && tempcardvar == 10 && (rn2(100) < dealercheatchance)) {
1030 tempcardvar = rnd(9);
1031 u.cnd_blackjackdealercheat++;
1033 playerhand += tempcardvar;
1034 playercards = 2;
1035 if (playerhand == 21 && rn2(5)) {
1036 pline("Yeah! You scored a black jack and automatically win!");
1037 goto blackjackwin;
1038 /* we know by this point that the dealer doesn't have a black jack */
1040 pline("Your hand is %d with %d cards drawn.", playerhand, playercards);
1042 while (playercards < 5) {
1043 if (yn("Draw a card?") != 'y') {
1044 goto blackjackevaluate;
1046 tempcardvar = blackjack_card();
1047 if (playerhand >= 11 && (rn2(100) < dealercheatchance)) { /* dealer can cheat to make you bust */
1048 tempcardvar = 11;
1049 u.cnd_blackjackdealercheat++;
1051 playerhand += tempcardvar;
1052 playercards++;
1053 if (playerhand > 21) {
1054 pline("You busted. Your hand is %d with %d cards. Game over!", playerhand, playercards);
1055 goto blackjackgameover;
1056 /* it doesn't matter if the dealer busted as well, because once again this game favors the dealer; even though it would probably be a draw in real life, here you autolose if you bust */
1058 pline("Your hand is %d with %d cards drawn.", playerhand, playercards);
1059 pline("The dealer's visible hand is %d with %d cards drawn.", dealervisiblehand, dealercards);
1062 blackjackevaluate:
1063 if ((playerhand > dealerhand) && dealerhand < 21 && dealerfirstcard < 11 && (rn2(100) < dealercheatchance)) { /* dealer can cheat to change his first card so that he doesn't lose */
1064 while (dealerhand < 21 && dealerhand <= playerhand && dealerfirstcard < 11) {
1065 dealerfirstcard++;
1066 dealerhand++;
1068 u.cnd_blackjackdealercheat++;
1070 pline("The dealer's first card is revealed to be worth %d.", dealerfirstcard);
1071 pline("Your hand is %d with %d cards. The dealer's hand is %d with %d cards.", playerhand, playercards, dealerhand, dealercards);
1073 if (dealerhand > 21) {
1074 pline("The dealer has busted. You win. To the next round.");
1075 goto blackjackwin;
1076 } else if (playerhand > dealerhand) {
1077 pline("Congratulations, you win. To the next round.");
1078 goto blackjackwin;
1079 } else if (playerhand == dealerhand) {
1080 pline("The match is a draw. To the next round.");
1081 goto newblackjackrun;
1082 } else {
1083 pline("You lose. Game over.");
1084 goto blackjackgameover;
1087 blackjackwin:
1088 playerblackjackwins++;
1090 /* every win gives a random weapon or armor piece */
1091 blackjackreward = mkobj(rn2(2) ? ARMOR_CLASS : WEAPON_CLASS, TRUE, FALSE);
1092 if (blackjackreward) {
1093 /* unlike Elona, where you get one single such reward piece of equipment with its quality scaling with the
1094 * amount of consecutive wins, here you get an item for every win, but the enchantment value can randomly be
1095 * higher the more consecutive wins you scored --Amy */
1096 blackjackreward->spe += rn2(playerblackjackwins + 1);
1097 dropy(blackjackreward);
1100 /* rewards for winning streaks: 4 wins in a row give a potion of cure insanity, 8 wins give a scroll of consecration, 12 wins give a scroll of skill up, 16 wins give a scroll of alter reality and 20 wins give a random artifact */
1101 if (playerblackjackwins == 4) {
1102 blackjackreward = mksobj(POT_CURE_INSANITY, TRUE, TRUE, FALSE);
1103 if (blackjackreward) {
1104 blackjackreward->quan = 1;
1105 blackjackreward->owt = weight(blackjackreward);
1106 dropy(blackjackreward);
1107 stackobj(blackjackreward);
1110 if (playerblackjackwins == 8) {
1111 blackjackreward = mksobj(SCR_CONSECRATION, TRUE, TRUE, FALSE);
1112 if (blackjackreward) {
1113 blackjackreward->quan = 1;
1114 blackjackreward->owt = weight(blackjackreward);
1115 dropy(blackjackreward);
1116 stackobj(blackjackreward);
1119 if (playerblackjackwins == 12) {
1120 blackjackreward = mksobj(SCR_SKILL_UP, TRUE, TRUE, FALSE);
1121 if (blackjackreward) {
1122 blackjackreward->quan = 1;
1123 blackjackreward->owt = weight(blackjackreward);
1124 dropy(blackjackreward);
1125 stackobj(blackjackreward);
1128 if (playerblackjackwins == 16) {
1129 blackjackreward = mksobj(SCR_ALTER_REALITY, TRUE, TRUE, FALSE);
1130 if (blackjackreward) {
1131 blackjackreward->quan = 1;
1132 blackjackreward->owt = weight(blackjackreward);
1133 dropy(blackjackreward);
1134 stackobj(blackjackreward);
1137 if (playerblackjackwins == 20) {
1138 boolean havegifts = u.ugifts;
1140 if (!havegifts) u.ugifts++;
1142 blackjackreward = mk_artifact((struct obj *)0, !rn2(3) ? A_CHAOTIC : rn2(2) ? A_NEUTRAL : A_LAWFUL, TRUE);
1143 if (blackjackreward) {
1144 dropy(blackjackreward);
1146 int blackjackskill = get_obj_skill(blackjackreward, TRUE);
1148 if (P_MAX_SKILL(blackjackskill) == P_ISRESTRICTED) {
1149 unrestrict_weapon_skill(blackjackskill);
1150 } else if (P_MAX_SKILL(blackjackskill) == P_UNSKILLED) {
1151 unrestrict_weapon_skill(blackjackskill);
1152 P_MAX_SKILL(blackjackskill) = P_BASIC;
1153 } else if (rn2(2) && P_MAX_SKILL(blackjackskill) == P_BASIC) {
1154 P_MAX_SKILL(blackjackskill) = P_SKILLED;
1155 } else if (!rn2(4) && P_MAX_SKILL(blackjackskill) == P_SKILLED) {
1156 P_MAX_SKILL(blackjackskill) = P_EXPERT;
1157 } else if (!rn2(10) && P_MAX_SKILL(blackjackskill) == P_EXPERT) {
1158 P_MAX_SKILL(blackjackskill) = P_MASTER;
1159 } else if (!rn2(100) && P_MAX_SKILL(blackjackskill) == P_MASTER) {
1160 P_MAX_SKILL(blackjackskill) = P_GRAND_MASTER;
1161 } else if (!rn2(200) && P_MAX_SKILL(blackjackskill) == P_GRAND_MASTER) {
1162 P_MAX_SKILL(blackjackskill) = P_SUPREME_MASTER;
1164 if (Race_if(PM_RUSMOT)) {
1165 if (P_MAX_SKILL(blackjackskill) == P_ISRESTRICTED) {
1166 unrestrict_weapon_skill(blackjackskill);
1167 } else if (P_MAX_SKILL(blackjackskill) == P_UNSKILLED) {
1168 unrestrict_weapon_skill(blackjackskill);
1169 P_MAX_SKILL(blackjackskill) = P_BASIC;
1170 } else if (rn2(2) && P_MAX_SKILL(blackjackskill) == P_BASIC) {
1171 P_MAX_SKILL(blackjackskill) = P_SKILLED;
1172 } else if (!rn2(4) && P_MAX_SKILL(blackjackskill) == P_SKILLED) {
1173 P_MAX_SKILL(blackjackskill) = P_EXPERT;
1174 } else if (!rn2(10) && P_MAX_SKILL(blackjackskill) == P_EXPERT) {
1175 P_MAX_SKILL(blackjackskill) = P_MASTER;
1176 } else if (!rn2(100) && P_MAX_SKILL(blackjackskill) == P_MASTER) {
1177 P_MAX_SKILL(blackjackskill) = P_GRAND_MASTER;
1178 } else if (!rn2(200) && P_MAX_SKILL(blackjackskill) == P_GRAND_MASTER) {
1179 P_MAX_SKILL(blackjackskill) = P_SUPREME_MASTER;
1184 if (!havegifts) u.ugifts--;
1186 pline("Reward items have been dropped on the ground.");
1187 pline("Your winning streak has reached %d wins in a row now.", playerblackjackwins);
1188 u.cnd_blackjackwins++;
1190 /* add reward here */
1191 goto newblackjackrun;
1193 blackjackgameover:
1194 disappearchance += (playerblackjackwins * 4);
1195 if (playerblackjackwins >= 20) disappearchance = 100;
1197 if (practicantterror) {
1198 pline("%s thunders: 'Gambling is strictly forbidden! Since you already gambled away those precious zorkmids and therefore can't pay them to me anymore, you pay 100 stones to me instead.'", noroelaname());
1199 fineforpracticant(0, 100, 0);
1202 if (rn2(100) < disappearchance) return 2;
1204 return 1;