Logo Search packages:      
Sourcecode: xconq version File versions  Download package

ccmd.c

/* Commands for the curses interface to Xconq.
   Copyright (C) 1986-1989, 1991-2000 Stanley T. Shebs.

Xconq is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.  See the file COPYING.  */

#include "conq.h"
#include "kpublic.h"
#include "cconq.h"
extern int drawlinear;
extern char linear_char;
extern char bord_char;
extern char conn_char;

static void impl_build(Side *side, Unit *unit, int u2, int n);
static void resize_map(int n);

#if 0 /* (should preserve in help somewhere) */
    tbcat(buf, "To move a unit, use [hjklyubn]\n");
    tbcat(buf, "[HJKLYUBN] moves unit repeatedly in that direction\n");
    tbcat(buf, "To look at another unit, use survey mode ('z')\n");
    tbcat(buf, "and use [hjklyubnHJKLYUBN] to move the cursor\n");
#endif

/* Use this macro in any command if it requires a current unit. */

#define REQUIRE_UNIT()  \
  if (!in_play(curunit)) {  \
    curunit = NULL;  \
    cmd_error(side, "No current unit to command!");  \
    return;  \
  }

Unit *lastactor = NULL;

Unit *
find_next_and_look()
{
    Unit *nextunit;

    nextunit = find_next_actor(dside, curunit);
    if (nextunit != NULL) {
      make_current(nextunit);
      show_cursor();
    }
    return nextunit;
}

static UnitVector *selvec;

UnitVector *
get_selected_units(Side *side)
{
    if (selvec == NULL)
      selvec = make_unit_vector(2);
    clear_unit_vector(selvec);
    if (in_play(curunit))
      selvec = add_unit_to_vector(selvec, curunit, 0);
    return selvec;
}

void
do_add_terrain(Side *side)
{
    int u, t, dir;

    REQUIRE_UNIT();
    u = curunit->type;
    if (ask_direction("Add terrain to where?", &dir)) {
      for_all_terrain_types(t) {
          if (ut_acp_to_add_terrain(u, t) > 0
            && curunit->act
            && curunit->act->acp >= ut_acp_to_add_terrain(u, t)) {
            if (0 <= ut_alter_range(curunit->type, t)) {
                if (net_prep_add_terrain_action(curunit, curunit,
                                    curunit->x, curunit->y,
                                    dir, t))
                  ;
                else
                  xbeep();
            }
          }
      }
    }
}

void
do_attack(Side *side)
{
    int x, y;
    Unit *other;

    REQUIRE_UNIT();
    if (ask_position("Attack where?", &x, &y)) {
      for_all_stack(x, y, other) {
          if (!unit_trusts_unit(curunit, other)) {
            if (valid(check_attack_action(curunit, curunit, other, 100))) {
                net_prep_attack_action(curunit, curunit, other, 100);
                return;
            }
            /* (should try other types of actions?) */
          }
      }
      cmd_error(side, "Nothing for %s to attack at %d,%d!",
              unit_handle(dside, curunit), x, y);
    }
}

void
do_build(Side *side)
{
    short possibles[MAXUTYPES];
    int u, u2, numtypes, ufirst;

    REQUIRE_UNIT();
    u = curunit->type;
    if (!can_build(curunit)) {
      cmd_error(side, "%s can't build anything!", unit_handle(dside, curunit));
      return;
    }
#if 0
    if (!u_occproduce(curunit->type) && curunit->transport != NULL) {
      cmd_error(side, "%s can't build anything while inside another unit!",
              unit_handle(dside, curunit));
      return;
    }
#endif
    numtypes = 0;
    for_all_unit_types(u2) {
      if (uu_acp_to_create(u, u2) > 0 && type_allowed_on_side(u, dside)) {
          possibles[u2] = TRUE;
          ++numtypes;
          ufirst = u2;
      } else {
          possibles[u2] = FALSE;
      }
    }
    switch (numtypes) {
      case 0:
      cmd_error(side, "Nothing to build!");
      break;
      case 1:
      /* Only one type to build - just do it. */
      impl_build(dside, curunit, ufirst, prefixarg);
      break;
      default:
      /* Player has to choose a type to build. */
      u2 = ask_unit_type("Type to build:", possibles);
      if (u2 != NONUTYPE) {
          impl_build(dside, curunit, u2, prefixarg);
      } else {
          /* should clear toplines */
      }
      break;
    }
}

static void
impl_build(Side *side, Unit *unit, int u2, int n)
{
    if (n < 0)
      n = 99;
    notify(side, "%s will build %d %s",
         unit_handle(side, unit), n, u_type_name(u2));
    net_push_build_task(unit, u2, n, 0, 0);
}

/* (should reindent) */
void
do_collect(Side *side)
{
    int mtocollect;
    char *arg, *rest;

    REQUIRE_UNIT();
    mtocollect = NONMTYPE;
    if (nummtypes == 0) {
      cmd_error(side, "No materials to collect");
      return;
    }
    if (!empty_string(cmdargstr)) {
      rest = get_next_arg(cmdargstr, tmpbuf, &arg);
      mtocollect = mtype_from_name(arg);
    } else {
      cmd_error(side, "No material name given");
      return;
    }
    if (!is_material_type(mtocollect)) {
      cmd_error(side, "`%s' is not a recognized material name", arg);
      return;
    }
    if (curunit->plan)
      net_set_collect_task(curunit, mtocollect, curunit->x, curunit->y);
}

void
do_copying(Side *side)
{
    cur_help_node = copying_help_node;
    do_help(side);
}

/* Supposedly you could only get to these by typing the full command names. */

void
do_dir(Side *side)
{
    int ndirs, dir1, dir2, modif;

    ndirs = char_to_dir(tmpkey, &dir1, &dir2, &modif);
    if (ndirs >= 1) {
      do_dir_2(dir1, prefixarg);
    } else {
      xbeep();
      return;
    }
}

void
do_dir_multiple(Side *side)
{
    cmd_error(side, "use the single-character commands instead");
}

/* Determine how far away another point is.  */

void
do_distance(Side *side)
{
    int x, y;

    if (ask_position("Distance to where?", &x, &y)) {
      notify(dside, "Distance is %d cells.", distance(curx, cury, x, y));
    }
}

void
do_escape(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

/* Command to fire at a specified unit or location. */

void
do_fire(Side *side)
{
    int x, y;
    Unit *unit2;
    UnitView *uview;

    REQUIRE_UNIT();
    sprintf(spbuf, "Fire %s at where?", unit_handle(dside, curunit));
    /* (should have some sort of range feedback) */
    if (ask_position(spbuf, &x, &y)) {
      for_all_view_stack(dside, x, y, uview) {
          unit2 = view_unit(uview);
          /* (should avoid shooting at allies too) */
          if (unit2 != NULL
            && unit2->side != curunit->side
            && uview->date == g_turn()) {
            net_prep_fire_at_action(curunit, curunit, unit2, -1);
            return;
          }
      }
      notify(dside, "No target unit seen, firing blindly");
      net_prep_fire_into_action(curunit, curunit, x, y, 0, -1);
    }
}

void
do_fire_into(Side *side)
{
    int x, y;

    REQUIRE_UNIT();
    sprintf(spbuf, "Fire %s at where?", unit_handle(dside, curunit));
    /* (should have some sort of range feedback) */
    if (ask_position(spbuf, &x, &y)) {
      net_prep_fire_into_action(curunit, curunit, x, y, 0, -1);
    }
}

void
do_flash(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

/* Toggle the action following flag. */

void
do_follow_action(Side *side)
{
    follow_action = !follow_action;
    if (follow_action) {
      notify(dside, "Following the action.");
    } else {
      notify(dside, "Not following the action.");
    }
}

/* Give a unit to another side or "to" independence. */

void
do_give_unit(Side *side)
{
    REQUIRE_UNIT();
#ifdef DESIGNERS
    if (dside->designer) {
      net_designer_change_side(curunit, side_n(prefixarg));
      return;
    }
#endif /* DESIGNERS */
    if (1) { /* (should test both temporary and permanent invalidity) */
      net_prep_change_side_action(curunit, curunit, side_n(prefixarg));
    } else {
      cmd_error(side, "You can't just give away the %s!", unit_handle(dside, curunit));
    }
}

/* Bring up help info. */

void
do_help(Side *side)
{
    /* Switch to help mode, saving current mode first. */
    prevmode = mode;
    mode = HELP;
    show_help();
    refresh();
}

/* Set the display of various kinds of data. */

void
do_map(Side *side)
{
    int value;
    char *str, *str2, tmpbuf[BUFSIZE];

    if (cmdargstr) {
      str = cmdargstr;
      while (*str != '\0') {
          /* Collect the next whitespace-separated token from the
               arg string. */
          while (*str != '\0' && *str == ' ')
            ++str;
          str2 = tmpbuf;
          while (*str != '\0' && *str != ' ')
            *str2++ = *str++;
          *str2 = '\0';
          str2 = tmpbuf;
          value = TRUE;
          /* See if it is prefixed with a "-" or "no". */
          if (*str2 == '-') {
            value = FALSE;
            ++str2;
          } else if (*str2 == 'n' && *(str2+1) == 'o') {
            value = FALSE;
            str2 += 2;
          }
          if (strcmp(str2, "terrain") == 0 || strcmp(str2, "t") == 0) {
            drawterrain = value;
          } else if (strcmp(str2, "unit") == 0 || strcmp(str2, "u") == 0) {
            drawunits = value;
          } else if (strcmp(str2, "name") == 0 || strcmp(str2, "n") == 0) {
            drawnames = value;
          } else if (strcmp(str2, "people") == 0 || strcmp(str2, "p") == 0) {
            drawpeople = value;
          } else if (strcmp(str2, "cover") == 0 || strcmp(str2, "c") == 0) {
            draw_cover = value;
          } else if (strcmp(str2, "one") == 0 || strcmp(str2, "1") == 0) {
            use_both_chars = !value;
          } else if (strcmp(str2, "two") == 0 || strcmp(str2, "2") == 0) {
            use_both_chars = value;
          } else if (strncmp(str2, "lin", 3) == 0) {
            drawlinear = value;
            if (value && str2[3] == '=' && str2[4] != '\0') {
                linear_char = str2[4];
            }
          } else if (strcmp(str2, ">") == 0) {
            if (prefixarg < 0)
              prefixarg = 5;
            if (lw <= 5 && prefixarg > 0) {
                cmd_error(side, "list side must be at least 5");
                return;
            }
            if (lw - prefixarg < 5)
              prefixarg = lw - 5;
            resize_map(prefixarg);
            return;
          } else if (strcmp(str2, "<") == 0) {
            if (prefixarg < 0)
              prefixarg = 5;
            if (mw <= 10 && prefixarg > 0) {
                cmd_error(side, "map side must be at least 10");
                return;
            }
            if (mw - prefixarg < 10)
              prefixarg = mw - 10;
            resize_map(0 - prefixarg);
            return;
          } else if (strcmp(str2, "_") == 0) {
            if (prefixarg < 0)
              prefixarg = 5;
            if (prefixarg < 1)
              prefixarg = 1;
            if (prefixarg > 10)
              prefixarg = 10;
            infoh = prefixarg;
            mh = LINES - 2 - infoh - 1;
            closeupwin->h = infoh;
            mapwin->y = 2 + infoh;
            mapwin->h = mh + 1;
            /* Update the screen to reflect the changes. */
            set_scroll();
            redraw();
          } else if (strcmp(str2, "v") == 0) {
            if (prefixarg < 0) {
                cycle_list_type();
            } else if (prefixarg == 0) {
                cycle_list_filter();
            } else if (prefixarg == 1) {
                cycle_list_order();
            }
            show_list();
            refresh();
          } else {
            cmd_error(side, "\"%s\" not recognized", tmpbuf);
          }
      }
    } else {
      notify(dside, "Nothing to do.");
    }
    show_map();
    refresh();
}

static void
resize_map(int n)
{
    /* Resize the left-hand-side windows. */
    mw += n;
    closeupwin->w += n;
    mapwin->w += n;
    /* Move and resize the right-hand-side windows. */
    lw -= n;
    sideswin->x += n;
    sideswin->w -= n;
    listwin->x += n;
    listwin->w -= n;
    /* Update the screen to reflect the changes. */
    set_scroll();
    redraw();
}

/* Send a short message to another side. */

void
do_message(Side *side)
{
    char *msg;
    Side *side2;
    SideMask sidemask;

    if (prefixarg == 0) {
      /* (should ask who to send to) */
    }
    side2 = side_n(prefixarg);
    if (ask_string("Message:", "", &msg)) {
      if (empty_string(msg) || (prefixarg >= 0 && side2 == NULL)) {
          notify(dside, "You keep your mouth shut.");
          sidemask = NOSIDES;
      } else if (prefixarg < 0) {
          notify(dside, "You made the announcement \"%s\"", msg);
          sidemask = ALLSIDES;
      } else if (side2 != NULL) {
          notify(dside, "Your message was sent.");
          sidemask = add_side_to_set(side2, NOSIDES);
      }
      if (!empty_string(msg) && sidemask != NOSIDES)
        net_send_message(dside, sidemask, msg);
    }
}

/* Set unit to move to a given location.  Designers do a teleport. */

void
do_move_to(Side *side)
{
    int x, y;

    REQUIRE_UNIT();
    sprintf(spbuf, "Move %s to where?", unit_handle(dside, curunit));
    if (ask_position(spbuf, &x, &y)) {
#ifdef DESIGNERS
      if (dside->designer) {
          net_designer_teleport(curunit, x, y, NULL);
          make_current(curunit);
          return;
      }
#endif /* DESIGNERS */
      net_set_move_to_task(curunit, x, y, 0);
    }
}

/* Command to name or rename the current unit or a given side. */

void
do_name(Side *side)
{
    char *newname;

    REQUIRE_UNIT();
    if (ask_string("New name for unit:", curunit->name, &newname)) {
      if (empty_string(newname))
        newname = NULL;
      net_set_unit_name(dside, curunit, newname);
    }
}

void
do_new_map(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

void
do_occupant(Side *side)
{
    Unit *nextocc;

    if (curunit == NULL) {
      make_current_at(curx, cury);
    }
    REQUIRE_UNIT();
    nextocc = find_next_occupant(curunit);
    if (nextocc != curunit)
      make_current(nextocc);
}

void
do_orders_popup(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

void
do_other(Side *side)
{
    char *cmd;

    if (ask_string("Command:", NULL, &cmd)) {
      if (empty_string(cmd)) {
          cmd_error(side, "No command");
      } else if (strcmp(cmd, "?") == 0) {
          cur_help_node = long_commands_help_node;
          do_help(side);
      } else {
          execute_long_command(side, cmd);
      }
    }
}

void
do_print_view(Side *side)
{
    dump_text_view(dside, use_both_chars);
}

void
do_produce(Side *side)
{
    int m, n;
    Unit *unit = curunit;

    REQUIRE_UNIT();
    if (!can_produce(unit)) {
      cmd_error(side, "cannot do active production");
    }
    n = 9999;
    if (prefixarg > 0)
      n = prefixarg;
    /* Find the first produceable type and set up to produce it. */
    for_all_material_types(m) {
      if (um_acp_to_produce(unit->type, m) > 0) {
          net_push_produce_task(unit, m, n);
          return;
      }
    }
}

/* Command to get out of a game, one way or another. */

void
do_quit(Side *side)
{
    if (endofgame || !dside->ingame) {
      exit_cconq();
      return;
    }
    /* Confirm the saving of any state. */
    if (!gamestatesafe) {
      if (ask_bool("Do you want to save the game?", TRUE)) {
          if (all_others_willing_to_save(dside)) {
            do_save(side);
            exit_cconq();
            return;
          } else {
            net_set_willing_to_save(dside, TRUE);
            notify(dside, "Other sides not willing to save.");
          }
      }
    }
    if (all_others_willing_to_quit(dside)) {
      if (ask_bool("Do you really want to declare a draw?", FALSE)) {
          net_set_willing_to_draw(dside, TRUE);
      } else {
          notify(dside, "Not willing to draw.");
      }
      return;
    } else {
      if (ask_bool("You must resign to get out; do you want to resign?", FALSE)) {
          do_resign(side);
      } else {
          notify(dside, "Not resigning.");
      }
    }
}

/* Move the current location as close to the center of the display as
   possible, and redraw everything. */

void
do_recenter(Side *side)
{
    set_view_focus(mvp, curx, cury);
    center_on_focus(mvp);
    set_map_viewport();
    show_map();
    refresh();
}

/* Redraw everything using the same code as when windows need a redraw. */

void
do_refresh(Side *side)
{
    redraw();
}

void
do_remove_terrain(Side *side)
{
    int t, dir;

    REQUIRE_UNIT();
    if (ask_direction("Remove terrain from where?", &dir)) {
      for_all_terrain_types(t) {
      if (ut_acp_to_remove_terrain(curunit->type, t) > 0
          && curunit->act
          && curunit->act->acp >= ut_acp_to_remove_terrain(curunit->type, t)) {
          if (0 <= ut_alter_range(curunit->type, t)) {
            if (net_prep_remove_terrain_action(curunit, curunit, curunit->x, curunit->y, dir, t))
              ;
            else
              xbeep();
          }
      }
      }
    }
}

void
do_repair(Side *side)
{
    cmd_error(side, "repair command not implemented");
}

void
do_resign(Side *side)
{
    Side *side2;

    if (endofgame) {
      cmd_error(side, "Game is already over.");
    } else if (!dside->ingame) {
      cmd_error(side, "You are already out of the game.");
    } else if (ask_bool("Do you really want to resign?", FALSE)) {
      side2 = NULL;
      if (numsides > 2) {
          side2 = ask_side("Who do you want to inherit?", NULL);
          if (side2 == dside) {
            cmd_error(side, "You can't inherit your own units! (not giving to anybody)");
            side2 = NULL;
          }
      }
      net_resign_game(dside, side2);
    }
}

/* Stuff game state into a file.  By default, it goes into the current
   directory.  If building a scenario, we can specify just which parts
   of the game state are to be written. */

void
do_save(Side *side)
{
    char *rawcontents;
    Module *module;
    Obj *contents;

#ifdef DESIGNERS
    if (dside->designer) {
      if (ask_string("Data to write?", "everything", &rawcontents)) {
          /* (should be in a designer_create_module?) */
          /* need to be able to get this name from somewhere */
          module = create_game_module("random.scn");
          /* need something better to turn contents into a Lisp object */
          contents = intern_symbol(rawcontents);
          /*      interpret_content_spec(module, contents);  */
          notify(dside, "Module will be written to \"%s\" ...", module->filename);
          if (write_game_module(module)) {
            notify(dside, "Done writing to \"%s\".", module->filename);
          } else {
            cmd_error(side, "Can't open file \"%s\"!", module->filename);
          }
          return;
      } else {
          return;
      }
    }
#endif /* DESIGNERS */
    if (0 /* checkpointing not allowed */) {
      if (ask_bool("You really want to save and exit?", FALSE)) {
          notify(dside, "Game will be saved to \"%s\" ...", saved_game_filename());
          if (write_entire_game_state(saved_game_filename())) {
            close_displays();
            /* this should be conditional? */
            exit(0);
          } else {
            cmd_error(side, "Can't open file \"%s\"!", saved_game_filename());
          }
      }
    } else {
      notify(dside, "Saving...");
      if (write_entire_game_state(saved_game_filename())) {
          notify(dside, "Game saved.");
      } else {
          cmd_error(side, "Couldn't save to \"%s\"!", saved_game_filename());
      }         
    }
}

void
do_set_formation(Side *side)
{
    Unit *leader;

    REQUIRE_UNIT();
    sprintf(spbuf, "Which unit to follow?");
    if (ask_unit(spbuf, &leader)) {
      if (!in_play(leader)) {
          cmd_error(side, "No unit to follow!");
      } else if (leader == curunit) {
          cmd_error(side, "Unit can't follow itself!");
      } else if (leader->side != dside /* or "trusted side"? */) {
          cmd_error(side, "Can't follow somebody else's unit!");
      } else {
          net_set_formation(curunit, leader, curunit->x - leader->x, curunit->y - leader->y, 1, 1);
      }
    }
}

void
do_set_view_angle(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

void
do_side_closeup(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

void
do_standing_orders(Side *side)
{
    int rslt;

    if (cmdargstr) {
      rslt = parse_standing_order(dside, cmdargstr);
      if (rslt < 0)
        xbeep();
    } else
      xbeep();
}

/* Command to toggle between interaction modes. */

void
do_survey(Side *side)
{
    if (mode == MOVE) {
      lastactor = curunit;
      mode = SURVEY;
    } else {
      mode = MOVE;
      /* If we weren't looking at a unit when we switched modes,
         go back to the last unit that was being moved. */
      if (curunit == NULL && in_play(lastactor)) {
          make_current(lastactor);
      }
    }
    show_map();
    refresh();
}

void
do_unit_closeup(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

void
do_up(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

/* Display the program version. */

void
do_version(Side *side)
{
    notify(dside, "Curses Xconq version %s", version_string());
    notify(dside, "(c) %s", copyright_string());
}

void
do_warranty(Side *side)
{
    cur_help_node = warranty_help_node;
    do_help(side);
}

void
do_world_map(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

void
do_zoom_in(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

void
do_zoom_out(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

#ifdef DESIGNERS

void
do_design(Side *side)
{
    if (!dside->designer) {
      net_become_designer(dside);
    } else {
      net_become_nondesigner(dside);
    }
}

#endif /* DESIGNERS */

#ifdef DEBUGGING

void
do_profile(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

void
do_trace(Side *side)
{
    cmd_error(side, "No curses version of this command.");
}

#endif /* DEBUGGING */

/* Generic command error routine just does a notify. */

void
cmd_error(Side *side, char *fmt, ...)
{
    char tmpnbuf[BUFSIZE];
    va_list ap;

    if (!empty_string(fmt)) {

      va_start(ap, fmt);
      vsprintf(tmpnbuf, fmt, ap);
      va_end(ap);

      low_notify(dside, tmpnbuf);
    }
    xbeep();
}

Generated by  Doxygen 1.6.0   Back to index