Mercurial > hg > early-roguelike
view arogue7/command.c @ 235:2dcf10d45d5b
Rogue V4: add two more function declarations.
Though it was called with different numbers of arguments, add_line()
does not need to be a variadic function. Making the second argument
mandatory is a better solution.
author | John "Elwin" Edwards |
---|---|
date | Mon, 07 Mar 2016 19:26:08 -0500 |
parents | f9ef86cf22b2 |
children | e52a8a7ad4c5 |
line wrap: on
line source
/* * command.c - Read and execute the user commands * * Advanced Rogue * Copyright (C) 1984, 1985, 1986 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. */ /* * Read and execute the user commands * */ #include "curses.h" #include <ctype.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include "mach_dep.h" #include "rogue.h" #ifdef PC7300 #include "sys/window.h" extern struct uwdata wdata; #endif void display(void); void help(void); void identify(char ch); void d_level(void); void u_level(void); void shell(void); void nameit(void); void namemonst(void); void count_gold(void); /* * command: * Process the user commands */ void command(void) { unsigned char ch; struct linked_list *item; unsigned char countch, direction, 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("The sun rises above the horizon"); else msg("The sun sinks below 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 = (char) 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 = CCHAR( 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 = readchar(); if (mpos != 0 && !running) /* Erase message if its there */ msg(""); } /* * check for prefixes */ if (isdigit(ch)) { count = 0; newcount = TRUE; while (isdigit(ch)) { count = count * 10 + (ch - '0'); if (count > 255) count = 255; ch = readchar(); } 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 = readchar(); 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 && player.t_action == A_NIL) count--; switch (ch) { case '!' : shell(); 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_PICKUP: player.t_action = A_NIL; if (add_pack(NULL, FALSE, NULL)) { char tch; tch = CCHAR( 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_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_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 'Q' : after = FALSE; quit(0); when 'i' : after = FALSE; inventory(pack, ALL); when 'I' : after = FALSE; picky_inven(); when C_DROP : player.t_action = C_DROP; drop(NULL); when '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 C_COUNT : count_gold(); when C_QUAFF : quaff(-1, 0, 0, TRUE); when C_READ : read_scroll(-1, 0, TRUE); when C_EAT : eat(); when C_WIELD : wield(); when C_WEAR : wear(); when C_TAKEOFF : take_off(); when 'o' : option(); when CTRL('N') : nameit(); when '=' : after = FALSE; display(); when 'm' : nameitem(NULL, TRUE); when '>' : after = FALSE; d_level(); when '<' : after = FALSE; u_level(); when '?' : after = FALSE; help(); when '/' : after = FALSE; identify(0); when C_USE : use_mm(-1); 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 C_DIP : dip_it(); when 'G' : if (player.t_action == A_NIL) { player.t_action = 'G'; player.t_no_move = movement(&player); } else { gsense(); player.t_action = A_NIL; } 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 = 5 * movement(&player); } else { search(FALSE, FALSE); player.t_action = A_NIL; } when C_ZAP : if (!player_zap(0, FALSE)) after=FALSE; when C_PRAY : pray(); when C_CHANT : chant(); when C_CAST : cast(); when 'a' : if (player.t_action == A_NIL) { if (get_dir(&player.t_newpos)) { player.t_action = 'a'; player.t_no_move = 2 * movement(&player); } else after = FALSE; } else { affect(); player.t_action = A_NIL; } when 'v' : after = FALSE; msg("Advanced Rogue Version %s.", release); when CTRL('L') : after = FALSE; clearok(curscr, TRUE); touchwin(cw); /* MMMMMMMMMM */ when CTRL('R') : after = FALSE; msg(huh); when 'S' : after = FALSE; if (save_game()) { wclear(cw); draw(cw); endwin(); #ifdef PC7300 endhardwin(); #endif exit(0); } when '.' : player.t_no_move = movement(&player); /* Rest */ player.t_action = A_NIL; when ' ' : after = FALSE; /* Do Nothing */ #ifdef WIZARD when CTRL('P') : after = FALSE; if (wizard) { wizard = FALSE; trader = 0; msg("Not wizard any more"); } else { if (waswizard || passwd()) { msg("Welcome, oh mighty wizard."); wizard = waswizard = TRUE; } else msg("Sorry"); } #endif when ESCAPE : /* 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; otherwise : after = FALSE; #ifdef WIZARD if (wizard) switch (ch) { case 'M' : create_obj(TRUE, 0, 0); when CTRL('W') : wanderer(); when CTRL('I') : inventory(lvl_obj, ALL); when CTRL('Z') : whatis(NULL); when CTRL('D') : level++; new_level(NORMLEV); when CTRL('F') : overlay(stdscr,cw); when CTRL('X') : overlay(mw,cw); when CTRL('J') : teleport(); when CTRL('E') : msg("food left: %d\tfood level: %d", food_left, foodlev); when CTRL('A') : activity(); when CTRL('C') : { int tlev; prbuf[0] = 0; msg("Which level? "); if(get_str(prbuf,msgw) == NORM) { tlev = atoi(prbuf); if(tlev < 1) { mpos = 0; msg("Illegal level."); } else if (tlev > 199) { levtype = MAZELEV; level = tlev - 200 + 1; } else if (tlev > 99) { levtype = POSTLEV; level = tlev - 100 + 1; } else { levtype = NORMLEV; level = tlev; } new_level(levtype); } } 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; 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) { item = spec_item(WEAPON, TWOSWORD, 5, 5); add_pack(item, TRUE, NULL); cur_weapon = OBJPTR(item); (OBJPTR(item))->o_flags |= (ISKNOW|ISPROT); } /* * And his suit of armor */ if (player.t_ctype != C_MONK) { item = spec_item(ARMOR, PLATE_ARMOR, 10, 0); obj = OBJPTR(item); if (player.t_ctype == C_THIEF) obj->o_which = STUDDED_LEATHER; obj->o_flags |= (ISKNOW | ISPROT); obj->o_weight = armors[PLATE_ARMOR].a_wght; cur_armor = obj; add_pack(item, TRUE, NULL); } purse += 20000; } otherwise : msg("Illegal command '%s'.", unctrl(ch)); count = 0; } else #endif { 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)) { if ((pstats.s_hpt -= infest_dam) <= 0) death(D_INFESTATION); } /* * The eye of Vecna is a constant drain on the player */ if (cur_relic[EYE_VECNA]) { if ((--pstats.s_hpt) <= 0) death(D_RELIC); } /* * if player has body rot then take off five hits */ if (on(player, DOROT)) { if ((pstats.s_hpt -= 5) <= 0) 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); #ifdef NEEDLOOK /* Shall we take a look? */ if (player.t_no_move <= 1 && !((running || count) && jump)) look(FALSE, FALSE); #endif if (++segment > 10) segment = 1; t_free_list(monst_dead); } } /* * display * tell the player what is at a certain coordinates assuming * it can be seen. */ void display(void) { 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. */ void quit(int sig) { /* * Reset the signal in case we got here via an interrupt */ if (signal(SIGINT, quit) != quit) mpos = 0; msg("Really quit? <yes or no> "); 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); #ifdef PC7300 endhardwin(); #endif exit(0); } else { signal(SIGINT, quit); wmove(cw, 0, 0); wclrtoeol(cw); status(FALSE); draw(cw); mpos = 0; count = 0; running = FALSE; } } /* * bugkill: * killed by a program bug instead of voluntarily. */ void bugkill(int sig) { signal(sig, quit); /* If we get it again, give up */ death(D_SIGNAL); /* Killed by a bug */ } /* * search: * Player gropes about him to find hidden things. */ void search(bool is_thief, bool door_chime) { register int x, y; register char ch, /* The trap or door character */ sch, /* Trap or door character (as seen on screen) */ mch; /* Monster, if a monster is on the trap or door */ register struct linked_list *item; register struct thing *mp; /* Status on surrounding monster */ /* * Look all around the hero, if there is something hidden there, * give him a chance to find it. If its found, display it. */ if (on(player, ISBLIND)) return; for (x = hero.x - 1; x <= hero.x + 1; x++) for (y = hero.y - 1; y <= hero.y + 1; y++) { if (y==hero.y && x==hero.x) continue; /* Mch and ch will be the same unless there is a monster here */ mch = CCHAR( winat(y, x) ); ch = CCHAR( mvwinch(stdscr, y, x) ); sch = CCHAR( mvwinch(cw, y, x) ); /* What's on the screen */ if (door_chime == FALSE && isatrap(ch)) { register struct trap *tp; /* Is there a monster on the trap? */ if (mch != ch && (item = find_mons(y, x)) != NULL) { mp = THINGPTR(item); if (sch == mch) sch = mp->t_oldch; } else mp = NULL; /* * is this one found already? */ if (isatrap(sch)) continue; /* give him chance for other traps */ tp = trap_at(y, x); /* * if the thief set it then don't display it. * if its not a thief he has 50/50 shot */ if((tp->tr_flags&ISTHIEFSET) || (!is_thief && rnd(100)>50)) continue; /* give him chance for other traps */ tp->tr_flags |= ISFOUND; /* Let's update the screen */ if (mp != NULL && mvwinch(cw, y, x) == mch) mp->t_oldch = ch; /* Will change when monst moves */ else mvwaddch(cw, y, x, ch); count = 0; running = FALSE; /* Stop what we were doing */ player.t_no_move = movement(&player); player.t_action = A_NIL; player.t_using = NULL; if (fight_flush) md_flushinp(); msg(tr_name(tp->tr_type)); } else if (ch == SECRETDOOR) { if (door_chime == TRUE || (!is_thief && rnd(100) < 20)) { struct room *rp; coord cp; /* Is there a monster on the door? */ if (mch != ch && (item = find_mons(y, x)) != NULL) { mp = THINGPTR(item); /* Screen will change when monster moves */ if (sch == mch) mp->t_oldch = ch; } mvaddch(y, x, DOOR); count = 0; /* * if its the entrance to a treasure room, wake it up */ cp.y = y; cp.x = x; rp = roomin(&cp); if (rp->r_flags & ISTREAS) wake_room(rp); /* Make sure we don't shoot into the room */ if (door_chime == FALSE) { count = 0; running = FALSE; /* Stop what we were doing */ player.t_no_move = movement(&player); player.t_action = A_NIL; player.t_using = NULL; } } } } } /* * help: * Give single character help, or the whole mess if he wants it */ void help(void) { register struct h_list *strp = helpstr; #ifdef WIZARD struct h_list *wizp = wiz_help; #endif register char helpch; register int cnt; msg("Character you want help for (* for all): "); helpch = readchar(); mpos = 0; /* * If its not a *, print the right help string * or an error if he typed a funny character. */ if (helpch != '*') { wmove(msgw, 0, 0); while (strp->h_ch) { if (strp->h_ch == helpch) { msg("%s%s", unctrl(strp->h_ch), strp->h_desc); return; } strp++; } #ifdef WIZARD if (wizard) { while (wizp->h_ch) { if (wizp->h_ch == helpch) { msg("%s%s", unctrl(wizp->h_ch), wizp->h_desc); return; } wizp++; } } #endif msg("Unknown character '%s'", unctrl(helpch)); return; } /* * Here we print help for everything. * Then wait before we return to command mode */ wclear(hw); cnt = 0; while (strp->h_ch) { mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(strp->h_ch)); waddstr(hw, strp->h_desc); strp++; if (++cnt >= 46 && strp->h_ch) { wmove(hw, lines-1, 0); wprintw(hw, morestr); draw(hw); wait_for(' '); wclear(hw); cnt = 0; } } #ifdef WIZARD if (wizard) { while (wizp->h_ch) { mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(wizp->h_ch)); waddstr(hw, wizp->h_desc); wizp++; if (++cnt >= 46 && wizp->h_ch) { wmove(hw, lines-1, 0); wprintw(hw, morestr); draw(hw); wait_for(' '); wclear(hw); cnt = 0; } } } #endif wmove(hw, lines-1, 0); wprintw(hw, spacemsg); draw(hw); wait_for(' '); wclear(hw); draw(hw); wmove(cw, 0, 0); wclrtoeol(cw); status(FALSE); touchwin(cw); } /* * identify: * Tell the player what a certain thing is. */ void identify(char ch) { register char *str; if (ch == 0) { msg("What do you want identified? "); ch = readchar(); mpos = 0; if (ch == ESCAPE) { msg(""); return; } } if (isalpha(ch)) str = monsters[id_monst(ch)].m_name; else switch(ch) { case '|': case '-': str = (levtype == OUTSIDE) ? "boundary of sector" : "wall of a room"; when GOLD: str = "gold"; when STAIRS : str = (levtype == OUTSIDE) ? "entrance to a dungeon" : "passage leading down"; when DOOR: str = "door"; when FLOOR: str = (levtype == OUTSIDE) ? "meadow" : "room floor"; when VPLAYER: str = "the hero of the game ---> you"; when IPLAYER: str = "you (but invisible)"; when PASSAGE: str = "passage"; when POST: str = "trading post"; when POOL: str = (levtype == OUTSIDE) ? "lake" : "a shimmering pool"; when TRAPDOOR: str = "trapdoor"; when ARROWTRAP: str = "arrow trap"; when SLEEPTRAP: str = "sleeping gas trap"; when BEARTRAP: str = "bear trap"; when TELTRAP: str = "teleport trap"; when DARTTRAP: str = "dart trap"; when MAZETRAP: str = "entrance to a maze"; when FOREST: str = "forest"; when POTION: str = "potion"; when SCROLL: str = "scroll"; when FOOD: str = "food"; when WEAPON: str = "weapon";