Mercurial > hg > early-roguelike
view xrogue/command.c @ 140:856017d63519
xrogue: don't segfault when backstabbing while empty-handed.
The code for backstabbing checked the weapon's properties without
making sure it was not NULL.
author | John "Elwin" Edwards |
---|---|
date | Tue, 05 May 2015 12:12:20 -0400 |
parents | 0d151573bdb0 |
children | 9aa9b9a2e159 |
line wrap: on
line source
/* command.c - Read and execute the user commands XRogue: Expeditions into the Dungeons of Doom Copyright (C) 1991 Robert Pietkivitch All rights reserved. Based on "Advanced Rogue" Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T All rights reserved. Based on "Rogue: Exploring the Dungeons of Doom" Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman All rights reserved. See the file LICENSE.TXT for full copyright and licensing information. */ #include <curses.h> #include <ctype.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include "mach_dep.h" #include "rogue.h" /* * command: * Process the user commands */ command() { unsigned int ch; struct linked_list *item; unsigned int countch = 0, direction = 0, newcount = FALSE; int segment = 1; int monst_limit, monst_current; monst_limit = monst_current = 1; while (playing) { /* * Let the daemons start up, but only do them once a round * (round = 10 segments). */ if (segment >= 10) { do_daemons(BEFORE); do_fuses(BEFORE); } after = TRUE; do { /* One more tick of the clock. */ if (segment >= 10 && after && (++turns % DAYLENGTH) == 0) { daytime ^= TRUE; if (levtype == OUTSIDE) { if (daytime) msg("A bright star flares above the horizon."); else msg("The bright star travels beyond the horizon."); } light(&hero); } /* * Don't bother with these updates unless the player's going * to do something. */ if (player.t_action == A_NIL && player.t_no_move <= 1) { look(after, FALSE); lastscore = purse; wmove(cw, hero.y, hero.x); if (!((running || count) && jump)) { status(FALSE); } } /* Draw the screen */ if (!((running || count) && jump)) { wmove(cw, hero.y, hero.x); draw(cw); } after = TRUE; /* * Read command or continue run */ if (--player.t_no_move <= 0) { take = 0; /* Nothing here to start with */ player.t_no_move = 0; /* Be sure we don't go too negative */ if (!running) door_stop = FALSE; /* Was the player being held? */ if (player.t_action == A_FREEZE) { player.t_action = A_NIL; msg("You can move again."); } if (player.t_action != A_NIL) ch = player.t_action; else if (running) { char scratch; /* If in a corridor or maze, if we are at a turn with * only one way to go, turn that way. */ scratch = winat(hero.y, hero.x); if ((scratch==PASSAGE||scratch==DOOR||levtype==MAZELEV) && off(player, ISHUH) && off(player, ISBLIND)) { int y, x; if (getdelta(runch, &y, &x) == TRUE) { corr_move(y, x); } } ch = runch; } else if (count) ch = countch; else { ch = wgetch(cw); if (mpos != 0 && !running) /* Erase message if its there */ msg(""); } /* * check for prefixes */ if (isascii(ch) && isdigit(ch)) { count = 0; newcount = TRUE; while (isascii(ch) && isdigit(ch)) { count = count * 10 + (ch - '0'); ch = wgetch(cw); } countch = ch; /* * turn off count for commands which don't make sense * to repeat */ switch (ch) { case 'h': case 'j': case 'k': case 'l': case 'y': case 'u': case 'b': case 'n': case 'H': case 'J': case 'K': case 'L': case 'Y': case 'U': case 'B': case 'N': case C_SEARCH: case '.': break; default: count = 0; } } /* Save current direction */ if (!running) { /* If running, it is already saved */ switch (ch) { case 'h': case 'j': case 'k': case 'l': case 'y': case 'u': case 'b': case 'n': case 'H': case 'J': case 'K': case 'L': case 'Y': case 'U': case 'B': case 'N': runch = tolower(ch); } } /* Perform the action */ switch (ch) { case 'f': if (!on(player, ISBLIND)) { door_stop = TRUE; firstmove = TRUE; } if (count && !newcount) ch = direction; else ch = wgetch(cw); switch (ch) { case 'h': case 'j': case 'k': case 'l': case 'y': case 'u': case 'b': case 'n': ch = toupper(ch); } direction = ch; } newcount = FALSE; /* * execute a command */ if (count && !running) count--; switch (ch) { case '!' : shell(); case KEY_LEFT : do_move(0, -1); when KEY_DOWN : do_move(1, 0); when KEY_UP : do_move(-1, 0); when KEY_RIGHT : do_move(0, 1); when KEY_HOME : do_move(-1, -1); when KEY_A1 : do_move(-1, -1); when KEY_PPAGE : do_move(-1, 1); when KEY_A3 : do_move(-1, 1); when KEY_END : do_move(1, -1); when KEY_C1 : do_move(1, -1); when KEY_NPAGE : do_move(1, 1); when KEY_C3 : do_move(1, 1); #ifdef CTL_RIGHT when CTL_RIGHT : do_run('l'); when CTL_LEFT : do_run('h'); when CTL_UP : do_run('k'); when CTL_DOWN : do_run('j'); when CTL_HOME : do_run('y'); when CTL_PGUP : do_run('u'); when CTL_END : do_run('b'); when CTL_PGDN : do_run('n'); #endif when 'h' : do_move(0, -1); when 'j' : do_move(1, 0); when 'k' : do_move(-1, 0); when 'l' : do_move(0, 1); when 'y' : do_move(-1, -1); when 'u' : do_move(-1, 1); when 'b' : do_move(1, -1); when 'n' : do_move(1, 1); when 'H' : do_run('h'); when 'J' : do_run('j'); when 'K' : do_run('k'); when 'L' : do_run('l'); when 'Y' : do_run('y'); when 'U' : do_run('u'); when 'B' : do_run('b'); when 'N' : do_run('n'); when A_ATTACK: /* Is our attackee still there? */ if (isalpha(winat(player.t_newpos.y, player.t_newpos.x))) { /* Our friend is still here */ player.t_action = A_NIL; fight(&player.t_newpos, cur_weapon, FALSE); } else { /* Our monster has moved */ player.t_action = A_NIL; } when A_PICKUP: player.t_action = A_NIL; if (add_pack((struct linked_list *)NULL, FALSE)) { char tch; tch = mvwinch(stdscr, hero.y, hero.x); if (tch != FLOOR && tch != PASSAGE) { player.t_action = A_PICKUP; /*get more */ player.t_no_move += 2 * movement(&player); } } when A_THROW: if (player.t_action == A_NIL) { item = get_item(pack, "throw", ALL, FALSE, FALSE); if (item != NULL && get_dir(&player.t_newpos)) { player.t_action = A_THROW; player.t_using = item; player.t_no_move = 2 * movement(&player); } else after = FALSE; } else { missile(player.t_newpos.y, player.t_newpos.x, player.t_using, &player); player.t_action = A_NIL; player.t_using = 0; } when 'a' : if (player.t_action == A_NIL) { if (get_dir(&player.t_newpos)) { player.t_action = 'a'; player.t_no_move = 1 + movement(&player); } else after = FALSE; } else { affect(); player.t_action = A_NIL; } when 'A' : choose_qst(); when 'F' : /* frighten a monster */ if (player.t_action == A_NIL) { player.t_action = 'F'; player.t_no_move = 2*movement(&player); } else { after = FALSE; player.t_action = A_NIL; fright(); } when 'g' : /* Give command: give slime-molds to monsters */ if (player.t_action == A_NIL) { player.t_action = 'g'; player.t_no_move = 2*movement(&player); } else { after = FALSE; player.t_action = A_NIL; give(); } when 'G' : if (player.t_action == A_NIL) { player.t_action = 'G'; player.t_no_move = movement(&player); } else { player.t_action = A_NIL; gsense(); } when 'i' : after = FALSE; inventory(pack, ALL); when 'I' : after = FALSE; picky_inven(); when 'm' : nameitem((struct linked_list *)NULL, TRUE); when 'o' : option(); when 'O' : msg("Charactor type: %s Quest item: %s", char_class[char_type].name, rel_magic[quest_item].mi_name); when ',' : case 'P' : if (levtype != POSTLEV) { /* We charge 2 movement units per item */ player.t_no_move = 2 * grab(hero.y, hero.x) * movement(&player); } else { /* Let's quote the wise guy a price */ buy_it(); after = FALSE; } when 'Q' : after = FALSE; quit(0); when 'S' : after = FALSE; if (save_game()) exit_game(EXIT_CLS | EXIT_ENDWIN); when 'v' : after = FALSE; msg("Advanced xrogue, Version %s ", release); when 'X' : /* trap sense */ after = FALSE; if (player.t_action == A_NIL) { player.t_action = 'X'; player.t_no_move = movement(&player); } else { xsense(); player.t_action = A_NIL; } when '.' : player.t_no_move = movement(&player); /* Rest */ player.t_action = A_NIL; when ' ' : after = FALSE; /* Do Nothing */ when '>' : after = FALSE; d_level(); when '<' : after = FALSE; u_level(); when '=' : after = FALSE; display(); when '?' : after = FALSE; help(); /* no character descriptions yet until updated (help.c) */ /* when '\\' : after = FALSE; ident_hero(); */ when '\\' : msg("Charon (the Boatman) looks at you... "); when '/' : after = FALSE; identify(NULL); when C_COUNT : count_gold(); when C_DIP : dip_it(); when C_DROP : player.t_action = C_DROP; drop((struct linked_list *)NULL); when C_EAT : eat(); when C_QUAFF : quaff(-1, NULL, NULL, TRUE); when C_READ : read_scroll(-1, NULL, TRUE); when C_SETTRAP : set_trap(&player, hero.y, hero.x); when C_SEARCH : if (player.t_action == A_NIL) { player.t_action = C_SEARCH; player.t_no_move = 2 + movement(&player); } else { search(FALSE, FALSE); player.t_action = A_NIL; } when C_TAKEOFF : take_off(); when C_USE : use_mm(-1); when C_WEAR : wear(); when C_WIELD : wield(); when C_ZAP : if (!player_zap(NULL, FALSE)) after=FALSE; when C_CAST : cast(); when C_CHANT : chant(); when C_PRAY : pray(); when CTRL('B') : msg("Current score: %d", pstats.s_exp + (long) purse); when CTRL('E') : msg("Current food level: %d(2000)", food_left); when CTRL('L') : after = FALSE; clearok(curscr, TRUE); touchwin(cw); when CTRL('N') : nameit(); when CTRL('O') : after = FALSE; opt_player(); when CTRL('R') : after = FALSE; msg(huh); when CTRL('T') : if (player.t_action == A_NIL) { if (get_dir(&player.t_newpos)) { player.t_action = CTRL('T'); player.t_no_move = 2 * movement(&player); } else after = FALSE; } else { steal(); player.t_action = A_NIL; } when ESC : /* Escape */ door_stop = FALSE; count = 0; after = FALSE; when '#': if (levtype == POSTLEV) /* buy something */ buy_it(); after = FALSE; when '$': if (levtype == POSTLEV) /* price something */ price_it(); after = FALSE; when '%': if (levtype == POSTLEV) /* sell something */ sell_it(); after = FALSE; when '+': /* instant karma! */ switch (rnd(100)) { case 0: msg("You waste some time. "); when 5: msg("An oak tree in the garden. "); when 10: msg("Character is what you become in the dark. "); when 15: msg("May you live all the days of your life. "); when 20: msg("A hero is no braver than an ordinary man, but he is brave five minutes longer. "); when 25: msg("Get down! "); when 30: msg("Go back to sleep. "); when 35: msg("Be here now. "); when 40: msg("Choose the rock that feels right to you. "); when 45: msg("Wait... "); when 50: msg("You take a break (yawn)... "); when 55: msg("Without danger there is no pleasure. "); when 60: msg("Define meaningless? "); when 65: msg("Don't push your luck! "); when 70: msg("Gung ho. "); when 75: msg("You are inside a computer. "); when 80: msg("Directive is now required... "); when 85: msg("Charon (the Boatman) awaits you... "); when 95: msg(nothing); otherwise: msg(""); } after = FALSE; when CTRL('P') : #ifdef WIZARD after = FALSE; if (wizard) { wizard = FALSE; trader = 0; msg("Not wizard any more"); } else { if (waswizard || passwd()) { msg("Welcome, O Mighty Wizard! "); wizard = waswizard = TRUE; } else msg("Sorry"); } #else msg("Sorry"); #endif otherwise : after = FALSE; if (wizard) switch (ch) { case 'M' : create_obj(TRUE, 0, 0); when 'V' : msg("vlevel = %d turns = %d", vlevel, turns); when CTRL('A') : activity(); when CTRL('C') : do_teleport(); when CTRL('D') : level++; take_with(); new_level(NORMLEV); when CTRL('F') : overlay(stdscr,cw); when CTRL('G') : { item=get_item(pack,"charge",STICK,FALSE,FALSE); if (item != NULL) { (OBJPTR(item))->o_charges=10000; } } when CTRL('H') : { register int i, j; register struct object *obj; for (i = 0; i < 9; i++) raise_level(); /* * Give the rogue a sword */ if (cur_weapon==NULL || cur_weapon->o_type != RELIC) { if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || player.t_ctype == C_MONK) item = spec_item(WEAPON, BASWORD, 20, 20); else item = spec_item(WEAPON,TWOSWORD, 20, 20); if (add_pack(item, TRUE)) { cur_weapon = OBJPTR(item); (OBJPTR(item))->o_flags |= (ISKNOW|ISPROT); } else o_discard(item); /* * And his suit of armor */ if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN || player.t_ctype == C_MONK) j = PADDED_ARMOR; else j = PLATE_ARMOR; item = spec_item(ARMOR, j, 20, 0); obj = OBJPTR(item); obj->o_flags |= (ISKNOW | ISPROT); obj->o_weight = armors[j].a_wght; if (add_pack(item, TRUE)) cur_armor = obj; else o_discard(item); } purse += 20000; } when CTRL('I') : inventory(lvl_obj, ALL); when CTRL('J') : teleport(); when CTRL('K') : whatis((struct linked_list *)NULL); when CTRL('W') : wanderer(); when CTRL('X') : overlay(mw,cw); when CTRL('Y') : msg("food left: %d\tfood level: %d", food_left, foodlev); otherwise : msg("Illegal wizard command '%s'.", unctrl(ch)); count = 0; } else { msg("Illegal command '%s'.", unctrl(ch)); count = 0; after = FALSE; } } /* * If he ran into something to take, let him pick it up. * unless it's a trading post */ if (auto_pickup && take != 0 && levtype != POSTLEV) { /* get ready to pick it up */ player.t_action = A_PICKUP; player.t_no_move += 2 * movement(&player); } } /* If he was fighting, let's stop (for now) */ if (player.t_quiet < 0) player.t_quiet = 0; if (!running) door_stop = FALSE; if (after && segment >= 10) { /* * Kick off the rest if the daemons and fuses */ /* * If player is infested, take off a hit point */ if (on(player, HASINFEST)) { pstats.s_hpt -= infest_dam; if (pstats.s_hpt == 50 || pstats.s_hpt == 25) msg("You feel yourself withering away... "); if (pstats.s_hpt < 1) { msg("You die a festering mass. --More--"); wait_for(' '); pstats.s_hpt = -1; death(D_INFESTATION); } } /* * The eye of Vecna is a constant drain on the player */ if (cur_relic[EYE_VECNA]) { pstats.s_hpt -= 1; if (pstats.s_hpt == 50 || pstats.s_hpt == 25) msg("You feel Vecna's eye looking about. "); if (pstats.s_hpt <= 10 && pstats.s_hpt >= 3) msg("Vecna's eye moves about very quickly. "); if (pstats.s_hpt < 1) { msg("Vecna's curse is upon you! --More--"); wait_for(' '); pstats.s_hpt = -1; death(D_RELIC); } } /* * if player has body rot then take off three hits */ if (on(player, DOROT)) { pstats.s_hpt -= rnd(3)+1; if (pstats.s_hpt == 50 || pstats.s_hpt == 25) msg("Something really begins to stink and smell! "); if (pstats.s_hpt < 1) { msg("You keel over with rot. --More--"); wait_for(' '); pstats.s_hpt = -1; death(D_ROT); } } do_daemons(AFTER); do_fuses(AFTER); } } while (after == FALSE); /* Make the monsters go */ if (--monst_current <= 0) monst_current = monst_limit = runners(monst_limit); if (++segment > 10) segment = 1; reap(); /* bury all the dead monsters */ } } /* * display * tell the player what is at a certain coordinates assuming * it can be seen. */ display() { coord c; struct linked_list *item; struct thing *tp; int what; msg("What do you want to display (* for help)?"); c = get_coordinates(); mpos = 0; if (!cansee(c.y, c.x)) { msg("You can't see what is there."); return; } what = mvwinch(cw, c.y, c.x); if (isalpha(what)) { item = find_mons(c.y, c.x); tp = THINGPTR(item); msg("%s", monster_name(tp)); return; } if ((item = find_obj(c.y, c.x)) != NULL) { msg("%s", inv_name(OBJPTR(item), FALSE)); return; } identify(what); } /* * quit: * Have player make certain, then exit. */ /*UNUSED*/ void quit(sig) int sig; { register int oy, ox; NOOP(sig); /* * Reset the signal in case we got here via an interrupt */ if ((VOID(*)())signal(SIGINT, quit) != (VOID(*)())quit) mpos = 0; getyx(cw, oy, ox); if (level < 1) { /* if not down in the dungeon proper; exit the game */ wclear(hw); wmove(hw, lines-1, 0); draw(hw); wmove(hw, 12, 30); wprintw(hw, "Good-bye!"); draw(hw); exit_game(EXIT_ENDWIN); } msg("Really quit? <yes or no> "); /* otherwise ask about quitting */ draw(cw); prbuf[0] = '\0'; if ((get_str(prbuf, msgw) == NORM) && strcmp(prbuf, "yes") == 0) { clear(); move(lines-1, 0); draw(stdscr); writelog(pstats.s_exp + (long) purse, CHICKEN, 0); score(pstats.s_exp + (long) purse, CHICKEN, 0); exit_game(EXIT_ENDWIN); } else { signal(SIGINT, quit); wmove(msgw, 0, 0); wclrtoeol(msgw); draw(msgw); status(FALSE); wmove(cw, oy, ox); draw(cw); mpos = 0; count = 0; running = FALSE; } } /* * bugkill: * killed by a program bug instead of voluntarily. */ bugkill(sig) int sig; { signal(sig, quit); /* If we get it again, give up */