comparison urogue/trader.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children 0250220d8cdd
comparison
equal deleted inserted replaced
253:d9badb9c0179 256:c495a4f288c6
1 /*
2 trader.c - Anything to do with trading posts
3
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom
5 Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
6 All rights reserved.
7
8 Based on "Advanced Rogue"
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
10 All rights reserved.
11
12 Based on "Rogue: Exploring the Dungeons of Doom"
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
14 All rights reserved.
15
16 See the file LICENSE.TXT for full copyright and licensing information.
17 */
18
19 #include <string.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22 #include "rogue.h"
23
24 #define EFFECTIVE_PURSE ((player.t_ctype==C_PALADIN)?(9 * purse / 10) : purse)
25
26 /*
27 do_post()
28 Buy and sell things in a trading post
29 */
30
31 void
32 display_postinfo(void)
33 {
34 wclear(hw);
35 wstandout(hw);
36 mvwaddstr(hw, 0, COLS / 2 - 30,
37 "Welcome to Friendly Fiend's Flea Market" );
38 wstandend(hw);
39 wclrtoeol(hw);
40 trans_line();
41 }
42
43 void
44 do_post(void)
45 {
46 int bad_letter = FALSE;
47
48 player.t_trans = 0;
49
50 for (;;)
51 {
52 if (!open_market())
53 return;
54
55 display_postinfo();
56
57 if (bad_letter)
58 {
59 bad_letter = FALSE;
60 wstandout(hw);
61 mvwaddstr(hw, 7, 0, "Type 'i' or 'I' to inventory, "
62 "'l' to leave, 'b' to buy, or 's' to sell");
63 wstandend(hw);
64 }
65
66 mvwaddstr(hw, 6, 0, "Do you wish to buy, sell, inventory, or leave?");
67 wrefresh(hw);
68
69 switch(readcharw(hw))
70 {
71 case 'b':
72 mvwaddstr(hw, 7, 0,
73 "Lets go into the buying section of the store...");
74 touchwin(hw);
75 wrefresh(hw);
76 buy_it('\0', ISNORMAL);
77 break;
78
79 case 's':
80 mvwaddstr(hw, 7, 0,
81 "Lets go into the selling section of the store...");
82 touchwin(hw);
83 wrefresh(hw);
84 sell_it();
85 break;
86
87 case 'i':
88 inventory(pack, '*');
89 break;
90
91 case 'I':
92 wclear(hw);
93 wrefresh(hw);
94 inventory(pack, 0);
95 msg(" ");
96 msg("");
97 break;
98
99 case 'l':
100 wclear(hw);
101 wrefresh(hw);
102 return;
103
104 default:
105 bad_letter = TRUE;
106 break;
107 }
108 }
109 }
110
111 void
112 buy_it(char itemtype, int flags)
113 {
114 int i;
115 int blessed = flags & ISBLESSED;
116 int cursed = flags & ISCURSED;
117 int is_spell = flags & SCR_MAGIC;
118 int array_size; /* # of items within type */
119 int which_type = 0; /* Which type to buy */
120 int which_one; /* Which one within type */
121 int plus_or_minus = 0; /* for magic items */
122 const struct magic_item *magic_array = NULL;
123 struct linked_list *item;
124 struct object *obj;
125 char buf[2 * LINELEN];
126
127 buy_more:
128
129 display_postinfo();
130
131 do
132 {
133 array_size = 0;
134
135 if (itemtype == '\0')
136 {
137 mpos = 0;
138 wmove(hw,10,0);
139 wclrtoeol(hw);
140 mvwaddstr(hw, 11, 0, "WHAT\tTYPE\n! Potion\n? Scroll\n"
141 "= Ring\n/ Stick\n] Armor\n) Weapon\n: Food");
142
143 if (wizard)
144 mvwaddstr(hw, 19, 0, ", Artifact");
145
146 mvwaddstr(hw, 9, 0, "What type of item do you want? ");
147 wclrtoeol(hw);
148 touchwin(hw);
149 wrefresh(hw);
150 itemtype = readcharw(hw);
151 }
152
153 switch(itemtype)
154 {
155 case POTION:
156 which_type = TYP_POTION;
157 array_size = maxpotions;
158 magic_array = p_magic;
159 break;
160
161 case SCROLL:
162 which_type = TYP_SCROLL;
163 array_size = maxscrolls;
164 magic_array = s_magic;
165 break;
166
167 case FOOD:
168 which_type = TYP_FOOD;
169 array_size = maxfoods;
170 magic_array = fd_data;
171 break;
172
173 case WEAPON:
174 which_type = TYP_WEAPON;
175 array_size = maxweapons;
176 break;
177
178 case ARMOR:
179 which_type = TYP_ARMOR;
180 array_size = maxarmors;
181 break;
182
183 case RING:
184 which_type = TYP_RING;
185 array_size = maxrings;
186 magic_array = r_magic;
187 break;
188
189 case STICK:
190 which_type = TYP_STICK;
191 array_size = maxsticks;
192 magic_array = ws_magic;
193 break;
194
195 case ARTIFACT:
196 if (!wizard)
197 {
198 itemtype = '\0';
199 continue;
200 }
201
202 which_type = TYP_ARTIFACT;
203 array_size = maxartifact;
204 break;
205
206 case ESCAPE:
207 return;
208
209 default:
210 wstandout(hw);
211 mvwaddstr(hw, 10, 0, "We don't stock any of those.");
212 wstandend(hw);
213 itemtype = '\0';
214 continue;
215 }
216 }
217 while (array_size == 0);
218
219 which_one = array_size;
220
221 do
222 {
223 const struct magic_item *m_item;
224
225 display_postinfo();
226
227 mpos = 0;
228 sprintf(buf, "Which kind of %s do you wish to have (* for list)? ",
229 things[which_type].mi_name);
230
231 mvwaddstr(hw, 9, 0, buf);
232
233 touchwin(hw);
234 wrefresh(hw);
235 buf[0] = '\0';
236
237 switch (get_string(buf, hw))
238 {
239 case QUIT:
240 case ESCAPE:
241 itemtype = '\0';
242 goto buy_more;
243 }
244
245 if (buf[0] == '*') /* print list */
246 {
247 add_line(" ID BASECOST NAME");
248
249 switch (which_type)
250 {
251 case TYP_RING:
252 case TYP_POTION:
253 case TYP_STICK:
254 case TYP_SCROLL:
255 case TYP_FOOD:
256
257 for(i=0,m_item=magic_array; i < array_size; i++, m_item++)
258 if (!is_spell && m_item->mi_worth > 0)
259 {
260 sprintf(buf, "%3d) %8d %s", i, m_item->mi_worth,
261 m_item->mi_name);
262 add_line(buf);
263 }
264 break;
265
266 case TYP_ARMOR:
267 for (i = 0; i < array_size; i++)
268 if (!is_spell && armors[i].a_worth > 0)
269 {
270 sprintf(buf, "%3d) %8d %s", i, armors[i].a_worth,
271 armors[i].a_name);
272
273 add_line(buf);
274 }
275 break;
276
277 case TYP_WEAPON:
278 for (i = 0; i < array_size; i++)
279 if (!is_spell && weaps[i].w_worth > 0)
280 {
281 sprintf(buf, "%3d) %8d %s", i, weaps[i].w_worth,
282 weaps[i].w_name);
283 add_line(buf);
284 }
285 break;
286
287 case TYP_ARTIFACT:
288 for (i = 0; i < array_size; i++)
289 {
290 sprintf(buf, "%3d) %8d %s", i, arts[i].ar_worth,
291 arts[i].ar_name);
292 add_line(buf);
293 }
294 break;
295
296 default:
297 add_line("What a strange type.");
298 }
299
300 end_line();
301 touchwin(hw);
302 wrefresh(hw);
303 continue;
304 }
305
306 if (isdigit(buf[0]))
307 which_one = atoi(buf);
308 else
309 switch (which_type)
310 {
311 case TYP_RING:
312 case TYP_POTION:
313 case TYP_STICK:
314 case TYP_SCROLL:
315 case TYP_FOOD:
316 for (i=0,m_item=magic_array; i < array_size; i++, m_item++)
317 if (strcmp(buf, m_item->mi_name) == 0)
318 which_one = i;
319 break;
320
321 case TYP_ARMOR:
322 for (i = 0; i < array_size; i++)
323 if (strcmp(buf, armors[i].a_name) == 0)
324 which_one = i;
325 break;
326
327 case TYP_WEAPON:
328 for (i = 0; i < array_size; i++)
329 if (strcmp(buf, weaps[i].w_name) == 0)
330 which_one = i;
331 break;
332
333 case TYP_ARTIFACT:
334 for (i = 0; i < array_size; i++)
335 if (strcmp(buf, arts[i].ar_name) == 0)
336 which_one = i;
337 break;
338
339 default:
340 msg("What a strange type.");
341 }
342
343 if (which_one < 0 || which_one >= array_size)
344 {
345 wstandout(hw);
346 mvwaddstr(hw, 10, 0, "Type the name or an ID number.");
347 wstandend(hw);
348 }
349 }
350 while (which_one < 0 || which_one >= array_size);
351
352 item = new_item(sizeof *obj);
353 obj = OBJPTR(item);
354
355 if (which_type == TYP_ARTIFACT)
356 {
357 new_artifact(which_one, obj);
358 add_pack(item, NOMESSAGE);
359 itemtype = '\0';
360 goto buy_more;
361 }
362
363 obj->o_type = itemtype;
364 obj->o_which = which_one;
365 obj->o_mark[0] = '\0';
366 obj->o_group = 0;
367 obj->o_count = 1;
368 obj->o_weight = 0;
369 obj->o_dplus = obj->o_hplus = 0;
370 obj->o_worth = 0;
371
372 if (!is_spell)
373 {
374 plus_or_minus = -100;
375
376 do
377 {
378 mvwaddstr(hw, 10, 0, "Do you want the cursed, blessed, or normal"
379 " version? (c, b, n) [n]");
380 touchwin(hw);
381 wrefresh(hw);
382
383 blessed = cursed = FALSE;
384 switch (readcharw(hw))
385 {
386 case ESCAPE:
387 discard(item);
388 itemtype = '\0';
389 goto buy_more;
390
391 case 'c':
392 cursed = TRUE;
393 plus_or_minus = 0;
394 break;
395
396 case 'b':
397 blessed = TRUE;
398 plus_or_minus = 0;
399 break;
400
401 case 'n':
402 case ' ':
403 plus_or_minus = 0;
404 break;
405
406 default:
407 wstandout(hw);
408 mvwaddstr(hw,11,0,"Type 'c' for cursed, 'b' for blessed, "
409 "or 'n' for normal");
410 wstandend(hw);
411 }
412 }
413 while (plus_or_minus == -100);
414 }
415
416 /* else used blessed, cursed from flags parameter */
417
418 if (which_type == TYP_WEAPON)
419 init_weapon(obj, which_one);
420
421 obj->o_flags |= ISKNOW;
422
423 if (cursed)
424 {
425 plus_or_minus = -(rnd(2) + 1);
426 obj->o_flags |= ISCURSED;
427 }
428 else if (blessed)
429 {
430 plus_or_minus = (rnd(3) + 1);
431 obj->o_flags |= ISBLESSED;
432 }
433 else
434 {
435 plus_or_minus = 0;
436 obj->o_flags |= ISNORMAL;
437 }
438
439 switch (which_type)
440 {
441 case TYP_WEAPON:
442 obj->o_hplus += plus_or_minus;
443 obj->o_dplus += plus_or_minus;
444 break;
445
446 case TYP_ARMOR:
447 obj->o_weight = armors[which_one].a_wght;
448 obj->o_ac = armors[which_one].a_class - plus_or_minus;
449 break;
450
451 case TYP_STICK:
452 fix_stick(obj);
453 break;
454
455 case TYP_RING:
456 obj->o_ac = plus_or_minus;
457 break;
458
459 case TYP_SCROLL:
460 case TYP_POTION:
461 obj->o_weight = things[which_type].mi_wght;
462 break;
463
464 case TYP_FOOD:
465 break;
466
467 default:
468 msg("That's a strange thing to try to own.");
469 discard(item);
470 itemtype = '\0';
471 goto buy_more;
472 }
473
474 obj->o_worth = get_worth(obj) * (luck + level / 15 + 1);
475 describe_it(obj);
476
477 if (!wizard && obj->o_worth > EFFECTIVE_PURSE)
478 {
479 wstandout(hw);
480 mvwaddstr(hw, 12, 0, "Unfortunately, you can't afford it.");
481 wstandend(hw);
482 wclrtoeol(hw);
483 touchwin(hw);
484 wrefresh(hw);
485 wait_for(' ');
486 discard(item);
487 itemtype = '\0';
488 goto buy_more;
489 }
490
491 mvwaddstr(hw, 12, 0, "Do you want it? [y] ");
492 wclrtoeol(hw);
493 touchwin(hw);
494 wrefresh(hw);
495
496 switch (readcharw(hw))
497 {
498 case ESCAPE:
499 case 'n':
500 msg("");
501 discard(item);
502 itemtype = '\0';
503 goto buy_more;
504 }
505
506 /* The hero bought the item here */
507
508 mpos = 0;
509
510 if (add_pack(item, NOMESSAGE) && !is_spell)
511 {
512 if (!wizard)
513 {
514 purse -= obj->o_worth; /* take his money */
515 ++player.t_trans;
516 }
517
518 trans_line(); /* show remaining deals */
519
520 switch(which_type)
521 {
522 case TYP_RING:
523 case TYP_STICK:
524 case TYP_SCROLL:
525 case TYP_POTION:
526 know_items[which_type][which_one] = TRUE;
527 }
528 }
529 }
530
531 /*
532 sell_it()
533 Sell an item to the trading post
534 */
535
536 void
537 sell_it(void)
538 {
539 struct object *obj;
540 struct linked_list *item;
541 char buf[2 * LINELEN];
542
543 wclear(cw);
544
545 if ((item = get_item("sell", 0)) == NULL)
546 return;
547
548 obj = OBJPTR(item);
549 msg("");
550 display_postinfo();
551 touchwin(hw);
552 wrefresh(hw);
553
554 if ((obj->o_type == ARTIFACT) || (obj->o_worth = get_worth(obj)) == 0)
555 {
556 mpos = 0;
557 msg("We don't buy those.");
558
559 if (is_wearing(R_ADORNMENT) && rnd(10) < 4)
560 msg("How about that %s ring instead?", r_stones[R_ADORNMENT]);
561
562 return;
563 }
564
565 describe_it(obj);
566 mvwaddstr(hw, 12, 0, "Do you want to sell it? [n] ");
567 touchwin(hw);
568 wrefresh(hw);
569
570 switch( readcharw(hw) )
571 {
572 case 'y':
573 break;
574 default:
575 msg("");
576 if (is_wearing(R_ADORNMENT))
577 msg("How about that %s ring instead?",
578 r_stones[R_ADORNMENT]);
579 return;
580 }
581
582 rem_pack(obj);
583 purse += obj->o_worth; /* give him his money */
584 ++player.t_trans;
585
586 sprintf(buf, "Sold %s. Hit space to continue.",
587 inv_name(obj, LOWERCASE));
588 discard(item);
589
590 mvwaddstr(hw, 13, 0, buf);
591 touchwin(hw);
592 wrefresh(hw);
593 wait_for(' ');
594 }
595
596 /*
597 describe_it()
598 Laud or condemn the object
599 */
600
601 extern char *inv_name();
602
603 void
604 describe_it(struct object *obj)
605 {
606 static char *cursed_d[] =
607 {
608 "worthless hunk of junk",
609 "shoddy piece of trash",
610 "piece of rusty garbage",
611 "example of terrible workmanship",
612 "cheap hack"
613 };
614
615 static char *normal_d[] =
616 {
617 "journeyman's piece",
618 "fine deal",
619 "great bargain",
620 "good find",
621 "real value",
622 "piece of honest workmanship",
623 "steal",
624 "purchase worth making",
625 "inexpensive product"
626 };
627
628 static char *blessed_d[] =
629 {
630 "magnificant masterpiece",
631 "quality product",
632 "exceptional find",
633 "unbeatable value",
634 "rare beauty",
635 "superior product",
636 "well-crafted item"
637 };
638
639 char *charp;
640 char buf[2 * LINELEN];
641
642 if (obj->o_flags & ISBLESSED)
643 charp = blessed_d[rnd(sizeof(blessed_d) / sizeof(char *))];
644 else if (obj->o_flags & ISCURSED)
645 charp = cursed_d[rnd(sizeof(cursed_d) / sizeof(char *))];
646 else
647 charp = normal_d[rnd(sizeof(normal_d) / sizeof(char *))];
648
649 sprintf(buf, "It's a%s %s worth %d pieces of gold.",
650 vowelstr(charp), charp, obj->o_worth);
651
652 mvwaddstr(hw, 10, 0, inv_name(obj, TRUE));
653 mvwaddstr(hw, 11, 0, buf);
654 wclrtoeol(hw);
655 }
656
657 /*
658 open_market()
659 Retruns TRUE when ok do to transacting
660 */
661
662 int
663 open_market(void)
664 {
665 int maxtrans = is_wearing(R_ADORNMENT) ? MAXPURCH + 4 : MAXPURCH;
666
667 if (wizard || player.t_trans < maxtrans || (level == 0))
668 return(TRUE);
669 else
670 {
671 msg("The market is closed. The stairs are that-a-way.");
672 return(FALSE);
673 }
674 }
675
676 /*
677 get_worth()
678 Calculate an objects worth in gold
679 */
680
681 int
682 get_worth(struct object *obj)
683 {
684 long worth = 0;
685 int wh = obj->o_which;
686 int blessed = obj->o_flags & ISBLESSED;
687 int cursed = obj->o_flags & ISCURSED;
688
689 switch (obj->o_type)
690 {
691 case FOOD:
692 if (wh < maxfoods)
693 {
694 worth = obj->o_count * fd_data[wh].mi_worth;
695 if (blessed)
696 worth *= 2;
697 }
698 break;
699
700 case WEAPON:
701 if (wh < maxweapons)
702 {
703 worth = weaps[wh].w_worth;
704 worth *= obj->o_count * (2 +
705 (4 * obj->o_hplus +
706 4 * obj->o_dplus));
707
708 if (obj->o_flags & ISSILVER)
709 worth *= 2;
710
711 if (obj->o_flags & ISPOISON)
712 worth *= 2;
713
714 if (obj->o_flags & ISZAPPED)
715 worth += 20 * obj->o_charges;
716 }
717 break;
718
719 case ARMOR:
720 if (wh < maxarmors)
721 {
722 int plusses = armors[wh].a_class - obj->o_ac;
723
724 worth = armors[wh].a_worth;
725
726 if (plusses > 0)
727 worth *= (1 + (10 *
728 (armors[wh].a_class - obj->o_ac)));
729 }
730 break;
731
732 case SCROLL:
733 if (wh < maxscrolls)
734 worth = s_magic[wh].mi_worth;
735 break;
736
737 case POTION:
738 if (wh < maxpotions)
739 worth = p_magic[wh].mi_worth;
740 break;
741
742 case RING:
743 if (wh < maxrings)
744 {
745 worth = r_magic[wh].mi_worth;
746 worth += obj->o_ac * 40;
747 }
748 break;
749
750 case STICK:
751 if (wh < maxsticks)
752 {
753 worth = ws_magic[wh].mi_worth;
754 worth += 20 * obj->o_charges;
755 }
756 break;
757
758 case ARTIFACT:
759 if (wh < maxartifact)
760 worth = arts[wh].ar_worth;
761 break;
762
763 default:
764 worth = 0;
765 }
766
767 if (obj->o_flags & ISPROT) /* 300% more for protected */
768 worth *= 3;
769
770 if (blessed) /* 250% more for blessed */
771 worth = 5 * worth / 2;
772 else if (cursed) /* half for cursed */
773 worth /= 2;
774
775 if (obj->o_flags & (CANRETURN | ISOWNED))
776 worth *= 4;
777 else if (obj->o_flags & CANRETURN)
778 worth *= 2;
779 else if (obj->o_flags & ISLOST)
780 worth /= 3;
781
782 return(max(0, worth)); /* anything is worth at least one gold piece */
783 }
784
785 /*
786 trans_line()
787 Show how many transactions the hero has left
788 */
789
790 void
791 trans_line(void)
792 {
793 char buf[2 * LINELEN];
794 int adorned = is_wearing(R_ADORNMENT);
795
796 if (level == 0 && purse > 0)
797 sprintf(buf, "You still have %d pieces of gold left.", purse);
798 else if (purse == 0)
799 sprintf(buf, "You have no money left.");
800 else if (!wizard)
801 sprintf(buf, "You have %d transactions and %d gold pieces remaining.",
802 max(0, (adorned ? MAXPURCH + 4 : MAXPURCH) - player.t_trans),
803 EFFECTIVE_PURSE);
804 else
805 sprintf(buf, "You have infinite transactions remaining.");
806
807 mvwaddstr(hw, LINES - 2, 0, buf);
808 }