date and time created 88/10/19 15:33:10 by bostic
[unix-history] / usr / src / games / rogue / object.c
CommitLineData
b3afadef
KB
1/*
2 * object.c
3 *
4 * This source herein may be modified and/or distributed by anybody who
5 * so desires, with the following restrictions:
6 * 1.) No portion of this notice shall be removed.
7 * 2.) Credit shall not be taken for the creation of this source.
8 * 3.) This code is not to be traded, sold, or used for personal
9 * gain or profit.
10 *
11 */
12
13#ifndef lint
14static char sccsid[] = "@(#)object.c 5.1 (Berkeley) %G%";
15#endif /* not lint */
16
17#include "rogue.h"
18
19object level_objects;
20unsigned short dungeon[DROWS][DCOLS];
21short foods = 0;
22object *free_list = (object *) 0;
23char *fruit = (char *) 0;
24
25fighter rogue = {
26 INIT_AW, /* armor, weapon */
27 INIT_RINGS, /* rings */
28 INIT_HP, /* Hp current,max */
29 INIT_STR, /* Str current,max */
30 INIT_PACK, /* pack */
31 INIT_GOLD, /* gold */
32 INIT_EXP, /* exp level,points */
33 0, 0, /* row, col */
34 INIT_CHAR, /* char */
35 INIT_MOVES /* moves */
36};
37
38struct id id_potions[POTIONS] = {
39{100, "blue \0 ", "of increase strength ", 0},
40{250, "red \0 ", "of restore strength ", 0},
41{100, "green \0 ", "of healing ", 0},
42{200, "grey \0 ", "of extra healing ", 0},
43 {10, "brown \0 ", "of poison ", 0},
44{300, "clear \0 ", "of raise level ", 0},
45 {10, "pink \0 ", "of blindness ", 0},
46 {25, "white \0 ", "of hallucination ", 0},
47{100, "purple \0 ", "of detect monster ", 0},
48{100, "black \0 ", "of detect things ", 0},
49 {10, "yellow \0 ", "of confusion ", 0},
50 {80, "plaid \0 ", "of levitation ", 0},
51{150, "burgundy \0 ", "of haste self ", 0},
52{145, "beige \0 ", "of see invisible ", 0}
53};
54
55struct id id_scrolls[SCROLS] = {
56{505, " ", "of protect armor ", 0},
57{200, " ", "of hold monster ", 0},
58{235, " ", "of enchant weapon ", 0},
59{235, " ", "of enchant armor ", 0},
60{175, " ", "of identify ", 0},
61{190, " ", "of teleportation ", 0},
62 {25, " ", "of sleep ", 0},
63{610, " ", "of scare monster ", 0},
64{210, " ", "of remove curse ", 0},
65 {80, " ", "of create monster ",0},
66 {25, " ", "of aggravate monster ",0},
67{180, " ", "of magic mapping ", 0},
68 {90, " ", "of confuse monster ", 0}
69};
70
71struct id id_weapons[WEAPONS] = {
72 {150, "short bow ", "", 0},
73 {8, "darts ", "", 0},
74 {15, "arrows ", "", 0},
75 {27, "daggers ", "", 0},
76 {35, "shurikens ", "", 0},
77 {360, "mace ", "", 0},
78 {470, "long sword ", "", 0},
79 {580, "two-handed sword ", "", 0}
80};
81
82struct id id_armors[ARMORS] = {
83 {300, "leather armor ", "", (UNIDENTIFIED)},
84 {300, "ring mail ", "", (UNIDENTIFIED)},
85 {400, "scale mail ", "", (UNIDENTIFIED)},
86 {500, "chain mail ", "", (UNIDENTIFIED)},
87 {600, "banded mail ", "", (UNIDENTIFIED)},
88 {600, "splint mail ", "", (UNIDENTIFIED)},
89 {700, "plate mail ", "", (UNIDENTIFIED)}
90};
91
92struct id id_wands[WANDS] = {
93 {25, " ", "of teleport away ",0},
94 {50, " ", "of slow monster ", 0},
95 {8, " ", "of invisibility ",0},
96 {55, " ", "of polymorph ",0},
97 {2, " ", "of haste monster ",0},
98 {20, " ", "of magic missile ",0},
99 {20, " ", "of cancellation ",0},
100 {0, " ", "of do nothing ",0},
101 {35, " ", "of drain life ",0},
102 {20, " ", "of cold ",0},
103 {20, " ", "of fire ",0}
104};
105
106struct id id_rings[RINGS] = {
107 {250, " ", "of stealth ",0},
108 {100, " ", "of teleportation ", 0},
109 {255, " ", "of regeneration ",0},
110 {295, " ", "of slow digestion ",0},
111 {200, " ", "of add strength ",0},
112 {250, " ", "of sustain strength ",0},
113 {250, " ", "of dexterity ",0},
114 {25, " ", "of adornment ",0},
115 {300, " ", "of see invisible ",0},
116 {290, " ", "of maintain armor ",0},
117 {270, " ", "of searching ",0},
118};
119
120extern short cur_level, max_level;
121extern short party_room;
122extern char *error_file;
123extern boolean is_wood[];
124
125put_objects()
126{
127 short i, n;
128 object *obj;
129
130 if (cur_level < max_level) {
131 return;
132 }
133 n = coin_toss() ? get_rand(2, 4) : get_rand(3, 5);
134 while (rand_percent(33)) {
135 n++;
136 }
137 if (party_room != NO_ROOM) {
138 make_party();
139 }
140 for (i = 0; i < n; i++) {
141 obj = gr_object();
142 rand_place(obj);
143 }
144 put_gold();
145}
146
147put_gold()
148{
149 short i, j;
150 short row,col;
151 boolean is_maze, is_room;
152
153 for (i = 0; i < MAXROOMS; i++) {
154 is_maze = (rooms[i].is_room & R_MAZE) ? 1 : 0;
155 is_room = (rooms[i].is_room & R_ROOM) ? 1 : 0;
156
157 if (!(is_room || is_maze)) {
158 continue;
159 }
160 if (is_maze || rand_percent(GOLD_PERCENT)) {
161 for (j = 0; j < 50; j++) {
162 row = get_rand(rooms[i].top_row+1,
163 rooms[i].bottom_row-1);
164 col = get_rand(rooms[i].left_col+1,
165 rooms[i].right_col-1);
166 if ((dungeon[row][col] == FLOOR) ||
167 (dungeon[row][col] == TUNNEL)) {
168 plant_gold(row, col, is_maze);
169 break;
170 }
171 }
172 }
173 }
174}
175
176plant_gold(row, col, is_maze)
177short row, col;
178boolean is_maze;
179{
180 object *obj;
181
182 obj = alloc_object();
183 obj->row = row; obj->col = col;
184 obj->what_is = GOLD;
185 obj->quantity = get_rand((2 * cur_level), (16 * cur_level));
186 if (is_maze) {
187 obj->quantity += obj->quantity / 2;
188 }
189 dungeon[row][col] |= OBJECT;
190 (void) add_to_pack(obj, &level_objects, 0);
191}
192
193place_at(obj, row, col)
194object *obj;
195{
196 obj->row = row;
197 obj->col = col;
198 dungeon[row][col] |= OBJECT;
199 (void) add_to_pack(obj, &level_objects, 0);
200}
201
202object *
203object_at(pack, row, col)
204register object *pack;
205short row, col;
206{
207 object *obj = (object *) 0;
208
209 if (dungeon[row][col] & (MONSTER | OBJECT)) {
210 obj = pack->next_object;
211
212 while (obj && ((obj->row != row) || (obj->col != col))) {
213 obj = obj->next_object;
214 }
215 if (!obj) {
216 message("object_at(): inconsistent", 1);
217 }
218 }
219 return(obj);
220}
221
222object *
223get_letter_object(ch)
224{
225 object *obj;
226
227 obj = rogue.pack.next_object;
228
229 while (obj && (obj->ichar != ch)) {
230 obj = obj->next_object;
231 }
232 return(obj);
233}
234
235free_stuff(objlist)
236object *objlist;
237{
238 object *obj;
239
240 while (objlist->next_object) {
241 obj = objlist->next_object;
242 objlist->next_object =
243 objlist->next_object->next_object;
244 free_object(obj);
245 }
246}
247
248char *
249name_of(obj)
250object *obj;
251{
252 char *retstring;
253
254 switch(obj->what_is) {
255 case SCROL:
256 retstring = obj->quantity > 1 ? "scrolls " : "scroll ";
257 break;
258 case POTION:
259 retstring = obj->quantity > 1 ? "potions " : "potion ";
260 break;
261 case FOOD:
262 if (obj->which_kind == RATION) {
263 retstring = "food ";
264 } else {
265 retstring = fruit;
266 }
267 break;
268 case WAND:
269 retstring = is_wood[obj->which_kind] ? "staff " : "wand ";
270 break;
271 case WEAPON:
272 switch(obj->which_kind) {
273 case DART:
274 retstring=obj->quantity > 1 ? "darts " : "dart ";
275 break;
276 case ARROW:
277 retstring=obj->quantity > 1 ? "arrows " : "arrow ";
278 break;
279 case DAGGER:
280 retstring=obj->quantity > 1 ? "daggers " : "dagger ";
281 break;
282 case SHURIKEN:
283 retstring=obj->quantity > 1?"shurikens ":"shuriken ";
284 break;
285 default:
286 retstring = id_weapons[obj->which_kind].title;
287 }
288 break;
289 case ARMOR:
290 retstring = "armor ";
291 break;
292 case RING:
293 retstring = "ring ";
294 break;
295 case AMULET:
296 retstring = "amulet ";
297 break;
298 default:
299 retstring = "unknown ";
300 break;
301 }
302 return(retstring);
303}
304
305object *
306gr_object()
307{
308 object *obj;
309
310 obj = alloc_object();
311
312 if (foods < (cur_level / 3)) {
313 obj->what_is = FOOD;
314 foods++;
315 } else {
316 obj->what_is = gr_what_is();
317 }
318 switch(obj->what_is) {
319 case SCROL:
320 gr_scroll(obj);
321 break;
322 case POTION:
323 gr_potion(obj);
324 break;
325 case WEAPON:
326 gr_weapon(obj, 1);
327 break;
328 case ARMOR:
329 gr_armor(obj);
330 break;
331 case WAND:
332 gr_wand(obj);
333 break;
334 case FOOD:
335 get_food(obj, 0);
336 break;
337 case RING:
338 gr_ring(obj, 1);
339 break;
340 }
341 return(obj);
342}
343
344unsigned short
345gr_what_is()
346{
347 short percent;
348 unsigned short what_is;
349
350 percent = get_rand(1, 91);
351
352 if (percent <= 30) {
353 what_is = SCROL;
354 } else if (percent <= 60) {
355 what_is = POTION;
356 } else if (percent <= 64) {
357 what_is = WAND;
358 } else if (percent <= 74) {
359 what_is = WEAPON;
360 } else if (percent <= 83) {
361 what_is = ARMOR;
362 } else if (percent <= 88) {
363 what_is = FOOD;
364 } else {
365 what_is = RING;
366 }
367 return(what_is);
368}
369
370gr_scroll(obj)
371object *obj;
372{
373 short percent;
374
375 percent = get_rand(0, 91);
376
377 obj->what_is = SCROL;
378
379 if (percent <= 5) {
380 obj->which_kind = PROTECT_ARMOR;
381 } else if (percent <= 10) {
382 obj->which_kind = HOLD_MONSTER;
383 } else if (percent <= 20) {
384 obj->which_kind = CREATE_MONSTER;
385 } else if (percent <= 35) {
386 obj->which_kind = IDENTIFY;
387 } else if (percent <= 43) {
388 obj->which_kind = TELEPORT;
389 } else if (percent <= 50) {
390 obj->which_kind = SLEEP;
391 } else if (percent <= 55) {
392 obj->which_kind = SCARE_MONSTER;
393 } else if (percent <= 64) {
394 obj->which_kind = REMOVE_CURSE;
395 } else if (percent <= 69) {
396 obj->which_kind = ENCH_ARMOR;
397 } else if (percent <= 74) {
398 obj->which_kind = ENCH_WEAPON;
399 } else if (percent <= 80) {
400 obj->which_kind = AGGRAVATE_MONSTER;
401 } else if (percent <= 86) {
402 obj->which_kind = CON_MON;
403 } else {
404 obj->which_kind = MAGIC_MAPPING;
405 }
406}
407
408gr_potion(obj)
409object *obj;
410{
411 short percent;
412
413 percent = get_rand(1, 118);
414
415 obj->what_is = POTION;
416
417 if (percent <= 5) {
418 obj->which_kind = RAISE_LEVEL;
419 } else if (percent <= 15) {
420 obj->which_kind = DETECT_OBJECTS;
421 } else if (percent <= 25) {
422 obj->which_kind = DETECT_MONSTER;
423 } else if (percent <= 35) {
424 obj->which_kind = INCREASE_STRENGTH;
425 } else if (percent <= 45) {
426 obj->which_kind = RESTORE_STRENGTH;
427 } else if (percent <= 55) {
428 obj->which_kind = HEALING;
429 } else if (percent <= 65) {
430 obj->which_kind = EXTRA_HEALING;
431 } else if (percent <= 75) {
432 obj->which_kind = BLINDNESS;
433 } else if (percent <= 85) {
434 obj->which_kind = HALLUCINATION;
435 } else if (percent <= 95) {
436 obj->which_kind = CONFUSION;
437 } else if (percent <= 105) {
438 obj->which_kind = POISON;
439 } else if (percent <= 110) {
440 obj->which_kind = LEVITATION;
441 } else if (percent <= 114) {
442 obj->which_kind = HASTE_SELF;
443 } else {
444 obj->which_kind = SEE_INVISIBLE;
445 }
446}
447
448gr_weapon(obj, assign_wk)
449object *obj;
450int assign_wk;
451{
452 short percent;
453 short i;
454 short blessing, increment;
455
456 obj->what_is = WEAPON;
457 if (assign_wk) {
458 obj->which_kind = get_rand(0, (WEAPONS - 1));
459 }
460 if ((obj->which_kind == ARROW) || (obj->which_kind == DAGGER) ||
461 (obj->which_kind == SHURIKEN) | (obj->which_kind == DART)) {
462 obj->quantity = get_rand(3, 15);
463 obj->quiver = get_rand(0, 126);
464 } else {
465 obj->quantity = 1;
466 }
467 obj->hit_enchant = obj->d_enchant = 0;
468
469 percent = get_rand(1, 96);
470 blessing = get_rand(1, 3);
471
472 if (percent <= 16) {
473 increment = 1;
474 } else if (percent <= 32) {
475 increment = -1;
476 obj->is_cursed = 1;
477 }
478 if (percent <= 32) {
479 for (i = 0; i < blessing; i++) {
480 if (coin_toss()) {
481 obj->hit_enchant += increment;
482 } else {
483 obj->d_enchant += increment;
484 }
485 }
486 }
487 switch(obj->which_kind) {
488 case BOW:
489 case DART:
490 obj->damage = "1d1";
491 break;
492 case ARROW:
493 obj->damage = "1d2";
494 break;
495 case DAGGER:
496 obj->damage = "1d3";
497 break;
498 case SHURIKEN:
499 obj->damage = "1d4";
500 break;
501 case MACE:
502 obj->damage = "2d3";
503 break;
504 case LONG_SWORD:
505 obj->damage = "3d4";
506 break;
507 case TWO_HANDED_SWORD:
508 obj->damage = "4d5";
509 break;
510 }
511}
512
513gr_armor(obj)
514object *obj;
515{
516 short percent;
517 short blessing;
518
519 obj->what_is = ARMOR;
520 obj->which_kind = get_rand(0, (ARMORS - 1));
521 obj->class = obj->which_kind + 2;
522 if ((obj->which_kind == PLATE) || (obj->which_kind == SPLINT)) {
523 obj->class--;
524 }
525 obj->is_protected = 0;
526 obj->d_enchant = 0;
527
528 percent = get_rand(1, 100);
529 blessing = get_rand(1, 3);
530
531 if (percent <= 16) {
532 obj->is_cursed = 1;
533 obj->d_enchant -= blessing;
534 } else if (percent <= 33) {
535 obj->d_enchant += blessing;
536 }
537}
538
539gr_wand(obj)
540object *obj;
541{
542 obj->what_is = WAND;
543 obj->which_kind = get_rand(0, (WANDS - 1));
544 obj->class = get_rand(3, 7);
545}
546
547get_food(obj, force_ration)
548object *obj;
549boolean force_ration;
550{
551 obj->what_is = FOOD;
552
553 if (force_ration || rand_percent(80)) {
554 obj->which_kind = RATION;
555 } else {
556 obj->which_kind = FRUIT;
557 }
558}
559
560put_stairs()
561{
562 short row, col;
563
564 gr_row_col(&row, &col, (FLOOR | TUNNEL));
565 dungeon[row][col] |= STAIRS;
566}
567
568get_armor_class(obj)
569object *obj;
570{
571 if (obj) {
572 return(obj->class + obj->d_enchant);
573 }
574 return(0);
575}
576
577object *
578alloc_object()
579{
580 object *obj;
581
582 if (free_list) {
583 obj = free_list;
584 free_list = free_list->next_object;
585 } else if (!(obj = (object *) md_malloc(sizeof(object)))) {
586 message("cannot allocate object, saving game", 0);
587 save_into_file(error_file);
588 }
589 obj->quantity = 1;
590 obj->ichar = 'L';
591 obj->picked_up = obj->is_cursed = 0;
592 obj->in_use_flags = NOT_USED;
593 obj->identified = UNIDENTIFIED;
594 obj->damage = "1d1";
595 return(obj);
596}
597
598free_object(obj)
599object *obj;
600{
601 obj->next_object = free_list;
602 free_list = obj;
603}
604
605make_party()
606{
607 short n;
608
609 party_room = gr_room();
610
611 n = rand_percent(99) ? party_objects(party_room) : 11;
612 if (rand_percent(99)) {
613 party_monsters(party_room, n);
614 }
615}
616
617show_objects()
618{
619 object *obj;
620 short mc, rc, row, col;
621 object *monster;
622
623 obj = level_objects.next_object;
624
625 while (obj) {
626 row = obj->row;
627 col = obj->col;
628
629 rc = get_mask_char(obj->what_is);
630
631 if (dungeon[row][col] & MONSTER) {
632 if (monster = object_at(&level_monsters, row, col)) {
633 monster->trail_char = rc;
634 }
635 }
636 mc = mvinch(row, col);
637 if (((mc < 'A') || (mc > 'Z')) &&
638 ((row != rogue.row) || (col != rogue.col))) {
639 mvaddch(row, col, rc);
640 }
641 obj = obj->next_object;
642 }
643
644 monster = level_monsters.next_object;
645
646 while (monster) {
647 if (monster->m_flags & IMITATES) {
648 mvaddch(monster->row, monster->col, (int) monster->disguise);
649 }
650 monster = monster->next_monster;
651 }
652}
653
654put_amulet()
655{
656 object *obj;
657
658 obj = alloc_object();
659 obj->what_is = AMULET;
660 rand_place(obj);
661}
662
663rand_place(obj)
664object *obj;
665{
666 short row, col;
667
668 gr_row_col(&row, &col, (FLOOR | TUNNEL));
669 place_at(obj, row, col);
670}
671
672c_object_for_wizard()
673{
674 short ch, max, wk;
675 object *obj;
676 char buf[80];
677
678 if (pack_count((object *) 0) >= MAX_PACK_COUNT) {
679 message("pack full", 0);
680 return;
681 }
682 message("type of object?", 0);
683
684 while (r_index("!?:)]=/,\033", (ch = rgetchar()), 0) == -1) {
685 sound_bell();
686 }
687 check_message();
688
689 if (ch == '\033') {
690 return;
691 }
692 obj = alloc_object();
693
694 switch(ch) {
695 case '!':
696 obj->what_is = POTION;
697 max = POTIONS - 1;
698 break;
699 case '?':
700 obj->what_is = SCROL;
701 max = SCROLS - 1;
702 break;
703 case ',':
704 obj->what_is = AMULET;
705 break;
706 case ':':
707 get_food(obj, 0);
708 break;
709 case ')':
710 gr_weapon(obj, 0);
711 max = WEAPONS - 1;
712 break;
713 case ']':
714 gr_armor(obj);
715 max = ARMORS - 1;
716 break;
717 case '/':
718 gr_wand(obj);
719 max = WANDS - 1;
720 break;
721 case '=':
722 max = RINGS - 1;
723 obj->what_is = RING;
724 break;
725 }
726 if ((ch != ',') && (ch != ':')) {
727GIL:
728 if (get_input_line("which kind?", "", buf, "", 0, 1)) {
729 wk = get_number(buf);
730 if ((wk >= 0) && (wk <= max)) {
731 obj->which_kind = (unsigned short) wk;
732 if (obj->what_is == RING) {
733 gr_ring(obj, 0);
734 }
735 } else {
736 sound_bell();
737 goto GIL;
738 }
739 } else {
740 free_object(obj);
741 return;
742 }
743 }
744 get_desc(obj, buf);
745 message(buf, 0);
746 (void) add_to_pack(obj, &rogue.pack, 1);
747}