/* Generic commands. Copyright (C) 1998-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. */ /* The commands in this file are the same for all interfaces. They typically consist of direct operations on units, or complicated command-line-type commands. */ #include "conq.h" #include "kpublic.h" #include "imf.h" #include "ui.h" int autofinish_start; int autofinish_count; static void notify_relationships(Side *side); static int parse_advance_spec(char *str); static int do_one_auto(Side *side, Unit *unit); static int do_one_clear_plan(Side *side, Unit *unit); static int do_one_delay(Side *side, Unit *unit); static int do_one_detach(Side *side, Unit *unit); static int do_one_detonate(Side *side, Unit *unit); static int do_one_disband(Side *side, Unit *unit); static int do_one_disembark(Side *side, Unit *unit); static int do_one_embark(Side *side, Unit *unit); static int do_one_give(Side *side, Unit *unit); static int do_one_idle(Side *side, Unit *unit); static int do_one_reserve(Side *side, Unit *unit); static int do_one_return(Side *side, Unit *unit); static int do_one_sleep(Side *side, Unit *unit); static int do_one_take(Side *side, Unit *unit); static int do_one_wake(Side *side, Unit *unit); static int do_one_wake_all(Side *side, Unit *unit); /* The command table is an array of all the commands. */ typedef struct cmdtab { char fchar; /* character to match against */ char *name; /* Full name of command */ void (*fn)(Side *side); /* Pointer to command's function */ char *help; /* short documentation string */ } CmdTab; #define C(c) ((c)-0x40) #undef DEF_CMD #define DEF_CMD(LETTER,NAME,FN,HELP) { LETTER, NAME, FN, HELP }, /* Define the table of commands. */ CmdTab commands[] = { #include "cmd.def" { 0, NULL, /* NULL, */ NULL, NULL } }; /* This is the actual key typed, for use if several keyboard commands share a single function. */ char tmpkey; /* If the command was typed as a command-line sort of thing, then this global will point to whatever came after the name of the command. */ char *cmdargstr; /* Help nodes that list all the commands, both single-char and long. */ HelpNode *key_commands_help_node; HelpNode *long_commands_help_node; /* Search in command table and execute function if found, complaining if the command is not recognized. */ void execute_command(Side *side, int ch) { CmdTab *cmd; void (*fn)(Side *side); cmdargstr = NULL; for (cmd = commands; cmd->name != NULL; ++cmd) { if (ch == cmd->fchar) { fn = cmd->fn; if (fn == NULL) { run_warning("no command function for %s (0x%x)?", cmd->name, ch); return; } tmpkey = ch; (*fn)(side); /* Whatever might have happened, we *did* find the command. */ return; } } cmd_error(side, "unrecognized command key '%c'", ch); } /* Given a string, find and interpret a long-name command in it. */ void execute_long_command(Side *side, char *cmdstr) { int prefix; char *cmdname; CmdTab *cmd; void (*fn)(Side *side); /* (should do something with prefix, which is presently ignored) */ parse_long_name_command(cmdstr, &prefix, &cmdname, &cmdargstr, copy_string(cmdstr)); if (empty_string(cmdname)) { /* Treat this is a deliberate cancellation, not an error. */ notify(side, "No command."); return; } for (cmd = commands; cmd->name != NULL; ++cmd) { if (strcmp(cmdname, cmd->name) == 0) { fn = cmd->fn; if (fn == NULL) { run_warning("no command function for %s?", cmd->name); return; } tmpkey = cmd->fchar; (*fn)(side); /* Whatever might have happened, we *did* find the command. */ return; } } cmd_error(side, "unrecognized command name \"%s\"", cmdname); } /* Collect a command name and an argument string from the given string, discarding excess whitespace. */ void parse_long_name_command(char *cmdstr, int *prefixp, char **namep, char **argp, char *buf) { int j, prefixarg = -1; char *cmdname, *cmdarg; if (empty_string(cmdstr)) { *namep = *argp = NULL; return; } strcpy(buf, cmdstr); /* Look for the first nonwhite char, make it start of command name. */ cmdname = buf; while ((*cmdname == ' ' || *cmdname == '\t') && *cmdname != '\0') ++cmdname; /* If this is a digit, then it's a prefix arg; extract it. */ if (isdigit(*cmdname)) { prefixarg = *cmdname - '0'; ++cmdname; while (isdigit(*cmdname)) { prefixarg = prefixarg * 10 + (*cmdname - '0'); ++cmdname; } /* Skip over any space between prefix arg and cmdname. */ while ((*cmdname == ' ' || *cmdname == '\t') && *cmdname != '\0') ++cmdname; } /* Scan over command name, which is delimited by whitespace or end of line. */ for (j = 0; cmdname[j] != ' ' && cmdname[j] != '\t' && cmdname[j] != '\n' && cmdname[j] != '\0'; ++j) ; /* If there's more than just the command name, extract an argument. */ if (cmdname[j] != '\0') { cmdarg = cmdname + j + 1; while ((*cmdarg == ' ' || *cmdname == '\t' || *cmdname == '\n') && *cmdarg != '\0') ++cmdarg; if (*cmdarg == '\0') cmdarg = NULL; } else { cmdarg = NULL; } /* Terminate the command name. */ cmdname[j] = '\0'; /* Remove trailing whitespace from the argument. */ if (!empty_string(cmdarg)) { for (j = strlen(cmdarg) - 1; j >= 0 && (cmdarg[j] == ' ' || cmdarg[j] == '\t' || cmdarg[j] == '\n'); --j) ; cmdarg[j + 1] = '\0'; } DGprintf("Command is \"%s\", argument is \"%s\", prefix is %d\n", (cmdname != NULL ? cmdname : ""), (cmdarg != NULL ? cmdarg : ""), prefixarg); *prefixp = prefixarg; *namep = cmdname; *argp = cmdarg; } /* Describe all the single-key commands for help. */ void describe_key_commands(int arg, char *key, TextBuffer *buf) { CmdTab *cmd; for (cmd = commands; cmd->name != NULL; ++cmd) { describe_command(cmd->fchar, cmd->name, cmd->help, TRUE, buf); } } /* Describe all the long-name commands for help. */ void describe_long_commands(int arg, char *key, TextBuffer *buf) { CmdTab *cmd; for (cmd = commands; cmd->name != NULL; ++cmd) { describe_command (cmd->fchar, cmd->name, cmd->help, FALSE, buf); } } static int apply_to_all_selected_units(Side *side, int (*fn)(Side *side, Unit *unit)) { int i, rslt, numcould = 0, numfail = 0; Unit *unit; UnitVector *selvec; if (fn == NULL) /* (should be a fatal error?) */ return 0; /* Scan all the selected units. Note that we assume that the list (unit vector) doesn't change while we're scanning, which means that we should be checking each unit, in case a command caused later units in the list to disappear (for instance a detonation). */ selvec = get_selected_units(side); for (i = 0; i < selvec->numunits; ++i) { unit = unit_in_vector(selvec, i); if (in_play(unit) && side_controls_unit(side, unit)) { ++numcould; rslt = (*fn)(side, unit); if (!rslt) ++numfail; } } /* Return true if everything went OK, false if the function failed on some units. */ return ((numcould > 0) ? (numfail == 0) : TRUE); } /* Generic command functions. These are the command functions that behave identically for all interfaces. */ #define DURING_GAME_ONLY(side) \ if (endofgame) { \ cmd_error((side), "Cannot do after game is over!"); \ return; \ } void do_add_player(Side *side) { DURING_GAME_ONLY(side); net_request_additional_side(cmdargstr); } void do_agreement_draft(Side *side) { char *title, titlebuf[20]; Agreement *ag; DURING_GAME_ONLY(side); /* (should have a net_create_agreement) */ ag = create_agreement(0); if (!empty_string(cmdargstr)) { title = cmdargstr; } else { sprintf(titlebuf, "#%d", ag->id); title = copy_string(titlebuf); } ag->name = title; /* The creating side is by definition one of the drafters. */ ag->drafters = add_side_to_set(side, ag->drafters); } void do_agreement_drafter(Side *side) { DURING_GAME_ONLY(side); } void do_agreement_propose(Side *side) { DURING_GAME_ONLY(side); } void do_agreement_proposer(Side *side) { DURING_GAME_ONLY(side); } void do_agreement_sign(Side *side) { DURING_GAME_ONLY(side); } void do_agreement_signer(Side *side) { DURING_GAME_ONLY(side); } void do_agreement_term(Side *side) { int agid, agterm; char *arg, *rest, *term; Agreement *ag; DURING_GAME_ONLY(side); rest = get_next_arg(cmdargstr, tmpbuf, &arg); if (empty_string(arg)) { cmd_error(side, "no agreement id"); return; } agid = strtol(arg, NULL, 10); agterm = 0; if (isdigit(*rest)) { rest = get_next_arg(rest, tmpbuf, &arg); agterm = strtol(arg, NULL, 10); } term = copy_string(rest); ag = find_agreement(agid); if (ag == NULL) { cmd_error(side, "no agreement #%d", agid); return; } /* (should be kernel function) */ ag->terms = cons(new_string(term), ag->terms); } /* Set which AI is to run the side's play. */ void do_ai_side(Side *side) { char *arg, *rest, *aitypename = NULL; DURING_GAME_ONLY(side); /* Look at the optional command argument, extract options and/or AI type name from it. */ if (!empty_string(cmdargstr)) { rest = get_next_arg(cmdargstr, tmpbuf, &arg); if (strcmp(arg, "help") == 0 || strcmp(arg, "?") == 0) { aitypename = next_ai_type_name(NULL); while (aitypename != NULL) { notify(side, " %s - %s", aitypename, ai_type_help(find_ai_type(aitypename))); aitypename = next_ai_type_name(aitypename); } return; } else if (strcmp(arg, "+") == 0) { /* Note that this flag is used by local AIs only, so don't need to synchronize kernels here. */ side->ai_may_resign = TRUE; notify(side, "AI may decide to draw or resign."); return; } else if (strcmp(arg, "-") == 0) { side->ai_may_resign = FALSE; notify(side, "AI may only recommend whether to draw or resign."); return; } aitypename = arg; } if (empty_string(aitypename)) { /* Toggle AI between mplayer and NULL. */ /* (should toggle between "preferred AI" for the side) */ if (side->player->aitypename == NULL) { aitypename = "mplayer"; } else { aitypename = NULL; } } else if (strcmp(aitypename, "none") == 0) { /* Special case to handle command "AI None" in Side menu. */ aitypename = NULL; } /* Feed back to user. Note that we say "want to have" because we haven't gotten feedback from remote programs yet. */ if (!empty_string(aitypename)) { notify(side, "Want to have AI %s running this side.", aitypename); } else { notify(side, "Want to have no AI running this side."); } net_set_side_ai(side, aitypename); } void do_auto(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_auto); } static int do_one_auto(Side *side, Unit *unit) { int newval; if (unit->plan == NULL) return FALSE; if (side->prefixarg < 0) newval = !unit->plan->aicontrol; else if (side->prefixarg == 0) newval = FALSE; else newval = TRUE; net_set_unit_ai_control(side, unit, newval, FALSE); net_force_replan(side, unit, FALSE); return TRUE; } void do_c_rate(Side *side) { int m = NONMTYPE, m1, m2, n, tot, pct; char *str, *reststr; char tbuf[BUFSIZE]; DURING_GAME_ONLY(side); /* For now, assume only one m. */ for_all_material_types(m1) { for_all_material_types(m2) { if (mm_conversion(m1, m2) > 0) { m = m1; break; } } } if (m == NONMTYPE) return; if (side->c_rates == NULL) side->c_rates = (short *) xmalloc(nummtypes * sizeof(short)); if (!empty_string(cmdargstr)) { str = cmdargstr; for_all_material_types(m2) { if (mm_conversion(m, m2) > 0) { n = strtol(str, &reststr, 10); str = reststr; /* (should use a net_ routine) */ side->c_rates[m2] = n; } } } tot = 0; for_all_material_types(m2) { if (mm_conversion(m, m2) > 0) { tot += side->c_rates[m2]; } } tbuf[0] = '\0'; for_all_material_types(m2) { if (mm_conversion(m, m2) > 0) { pct = (tot > 0 ? ((side->c_rates[m2] * 100) / tot) : 0); sprintf(tbuf+strlen(tbuf), " %s %d%%", m_type_name(m2), pct); } } notify(side, "%s conversion rates: %s", m_type_name(m), tbuf); } void do_clear_plan(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_clear_plan); } static int do_one_clear_plan(Side *side, Unit *unit) { if (unit->plan == NULL) return FALSE; net_set_unit_plan_type(side, unit, PLAN_NONE); net_clear_task_agenda(side, unit); return TRUE; } void do_delay(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_delay); } static int do_one_delay(Side *side, Unit *unit) { if (unit->plan == NULL) return FALSE; net_delay_unit(unit, TRUE); return TRUE; #if 0 /* add this case from tkcmd.c? */ unit = find_next_awake_mover(side, map->curunit); if (unit != map->curunit) { set_current_unit(map, unit); } else { cmd_error(side, "No next awake mover found."); } #endif } void do_detach(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_detach); } static int do_one_detach(Side *side, Unit *unit) { int rslt; if (!completed(unit)) { cmd_error(side, "%s is incomplete; cannot detach", unit_handle(side, unit)); return FALSE; } rslt = check_transfer_part_action(unit, unit, unit->hp / 2, NULL); if (valid(rslt)) { net_prep_transfer_part_action(unit, unit, unit->hp / 2, NULL); } else { notify(side, "can't detach for some reason?"); } return TRUE; } void do_detonate(Side *side) { DURING_GAME_ONLY(side); /* (should add Mac version's choice of where to detonate?) */ apply_to_all_selected_units(side, do_one_detonate); } static int do_one_detonate(Side *side, Unit *unit) { int rslt; rslt = check_detonate_action(unit, unit, unit->x, unit->y, unit->z); if (valid(rslt)) { net_prep_detonate_action(unit, unit, unit->x, unit->y, unit->z); return TRUE; } else { notify(side, "can't detonate for some reason?"); return FALSE; } } /* Get rid of a unit. */ void do_disband(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_disband); } static int do_one_disband(Side *side, Unit *unit) { /* (should have more feedback?) */ net_disband_unit(side, unit); return TRUE; } void do_disembark(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_disembark); } static int do_one_disembark(Side *side, Unit *unit) { Unit *transport; transport = unit->transport; if (transport == NULL) { cmd_error(side, "Not in a transport"); return FALSE; } if (!in_play(transport)) { cmd_error(side, "Transport is nonsensical?"); return FALSE; } /* Try moving into the transport's transport, if there is one. */ if (transport->transport != NULL && can_occupy(unit, transport->transport)) { net_prep_enter_action(unit, unit, transport->transport); /* (should be able to set up task if can't do action immedly) */ return TRUE; } /* Try moving into the open in the cell. */ if (can_occupy_cell(unit, unit->x, unit->y) || can_occupy_conn(unit, unit->x, unit->y, unit->z)) { net_prep_move_action(unit, unit, unit->x, unit->y, unit->z); /* (should be able to set up task if can't do action immedly) */ return TRUE; } cmd_error(side, "Can't disembark here!"); return FALSE; } void do_distrust(Side *side) { Side *side2; DURING_GAME_ONLY(side); if (empty_string(cmdargstr)) { notify_relationships(side); return; } side2 = parse_side_spec(cmdargstr); if (side2 == NULL) { cmd_error(side, "No side matching \"%s\"", cmdargstr); return; } if (side2 == side) { cmd_error(side, "We're not confused about trusting ourselves!"); return; } net_set_trust(side, side2, 0); } void notify_relationships(Side *side) { char *buf, buf1[1000], buf2[1000], buf3[1000], buf4[1000]; Side *side2; /* List the status of all other sides wrt us. */ buf1[0] = buf2[0] = buf3[0] = buf4[0] = '\0'; for_all_sides(side2) { if (side2 != side) { /* Choose which of four possible buckets the side falls into. */ if (trusted_side(side, side2)) { if (trusted_side(side2, side)) { buf = buf1; } else { buf = buf2; } } else { if (trusted_side(side2, side)) { buf = buf3; } else { buf = buf4; } } /* Add the side's title to the chosen bucket. */ if (strlen(buf) > 0) strcat(buf, ", "); strcat(buf, short_side_title(side2)); } } /* Describe each bucket. */ if (strlen(buf1) > 0) notify(side, "We trust them, and vice versa: %s.", buf1); if (strlen(buf2) > 0) notify(side, "We trust them, but they don't trust us: %s.", buf2); if (strlen(buf3) > 0) notify(side, "They trust us, but we don't trust them: %s.", buf3); if (strlen(buf4) > 0) notify(side, "We don't trust them, and vice versa: %s.", buf4); } void do_doctrine(Side *side) { DURING_GAME_ONLY(side); if (!empty_string(cmdargstr)) { if (strcmp(cmdargstr, "set") == 0) { notify(side, "Set what?"); } else if (strncmp(cmdargstr, "set ", 4) == 0) { net_set_doctrine(side, cmdargstr + 4); } else if (strcmp(cmdargstr, "help") == 0 || strcmp(cmdargstr, "?") == 0) { notify(side, "doctrine set "); notify(side, "\"doctrine\" alone to see current settings"); } return; } notify_doctrine(side, cmdargstr); } void do_down(Side *side) { cmd_error(side, "not yet implemented"); } void do_draw_willingness(Side *side) { DURING_GAME_ONLY(side); if (side->prefixarg < 0) side->prefixarg = 1; net_set_willing_to_draw(side, (side->prefixarg ? 1 : 0)); } void do_embark(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_embark); } static int do_one_embark(Side *side, Unit *unit) { Unit *transport; transport = embarkation_unit(unit); if (transport != NULL) { net_prep_enter_action(unit, unit, transport); return TRUE; } cmd_error(side, "Nothing for %s to enter!", unit_handle(side, unit)); return FALSE; } /* Command to end the side's activity for the turn. */ void do_end_turn(Side *side) { DURING_GAME_ONLY(side); net_finish_turn(side); } void do_force_global_replan(Side *side) { Unit *unit; DURING_GAME_ONLY(side); for_all_side_units(side, unit) { if (in_play(unit) && unit->plan != NULL) { net_force_replan(side, unit, FALSE); } } } void do_give(Side *side) { DURING_GAME_ONLY(side); if (nummtypes == 0) { cmd_error(side, "No materials in this game!"); return; } apply_to_all_selected_units(side, do_one_give); } static int do_one_give(Side *side, Unit *unit) { short m, amts[MAXMTYPES], rslts[MAXMTYPES]; Unit *unit2; for_all_material_types(m) amts[m] = side->prefixarg; unit2 = give_supplies(unit, amts, rslts); report_give(side, unit, unit2, rslts); return TRUE; } /* Tell the unit to sit around for a given number of turns. */ void do_idle(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_idle); } static int do_one_idle(Side *side, Unit *unit) { if (side->prefixarg < 0) side->prefixarg = 9999; net_set_sentry_task(unit, side->prefixarg); return TRUE; } /* Release a controlled side to act independently. */ void do_release(Side *side) { Side *side2; DURING_GAME_ONLY(side); if (empty_string(cmdargstr)) { cmd_error(side, "No side given to release!"); return; } side2 = parse_side_spec(cmdargstr); if (side2 == NULL) { cmd_error(side, "Can't get a side from \"%s\"!", cmdargstr); return; } if (side2 == side) { cmd_error(side, "Can't release ourselves!?"); return; } if (side2->controlled_by != side) { cmd_error(side, "You don't control %s!", short_side_title(side2)); return; } /* Modify the controllee's bit, not the controller's. */ net_set_controlled_by(side2, side, FALSE); } /* Set a side's current research topic. */ void do_research(Side *side) { int a; DURING_GAME_ONLY(side); if (numatypes == 0) { cmd_error(side, "No research in this game."); return; } if (!empty_string(cmdargstr)) { if (!g_side_can_research()) { cmd_error(side, "Side cannot do research."); return; } if (strcmp(cmdargstr, "nothing") == 0) { notify(side, "Your wise men will rest now."); net_set_side_research(side, NONATYPE); return; } a = parse_advance_spec(cmdargstr); if (a == -1) { cmd_error(side, "Not a valid advance: \"%s\"", cmdargstr); return; } else if (a == -2) { cmd_error(side, "Ambiguous: \"%s\"", cmdargstr); return; } notify(side, "Your wise men will search for the secret of %s.", a_type_name(a)); net_set_side_research(side, a); return; } else { int i = 0; char abuf[BUFSIZE]; if (g_side_can_research()) { a = side->research_topic; if (a == NOADVANCE) { notify(side, "Your wise men are waiting for a research area."); } else if (a == NONATYPE) { notify(side, "Your wise men are resting."); } else { notify(side, "Your wise men are %d/%d of the way to achieving %s.", side->advance[a], a_rp(a), a_type_name(a)); } } /* List the available advances. */ /* (should be a separate function perhaps) */ strcpy(abuf, "Next advances: "); for_all_advance_types(a) { if (side_can_research(side, a)) { if (i > 0) strcat(abuf, ", "); strcat(abuf, a_type_name(a)); ++i; if (i == 4) { notify(side, "%s", abuf); abuf[0] = '\0'; i = 0; } } } if (i > 0) notify(side, "%s", abuf); } } /* Given a string, find an advance whose name at least partially matches. */ int parse_advance_spec(char *str) { int a, rslt = -1; for_all_advance_types(a) { if (strstr(a_type_name(a), str)) { if (rslt >= 0) { return -2; } rslt = a; } } return rslt; } /* Make the selected units sleep just for the remainder of the current turn. */ void do_reserve(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_reserve); } static int do_one_reserve(Side *side, Unit *unit) { net_set_unit_reserve(side, unit, TRUE, TRUE /* is this right??? */); return TRUE; } /* Set up tasks to resupply the selected units. */ /* (should warn if task is likely to fail) */ void do_return(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_return); } static int do_one_return(Side *side, Unit *unit) { /* (should doublecheck range and error out if no chance) */ net_set_resupply_task(unit, NONMTYPE); return TRUE; } /* Auto-finish turns, for the given number of turns. */ void do_run(Side *side) { int turns; DURING_GAME_ONLY(side); if (!empty_string(cmdargstr)) turns = atoi(cmdargstr); else turns = side->prefixarg; if (turns < 0) turns = 0; notify(side, "Running free for %d turn%s.", turns, (turns == 1 ? "" : "s")); if (turns > 0) { net_set_autofinish(side, TRUE); autofinish_start = g_turn(); autofinish_count = turns; } } /* Set the rate at which AIs move their units. */ void do_set_rate(Side *side) { int slow, fast; char *reststr; DURING_GAME_ONLY(side); if (!empty_string(cmdargstr)) { slow = strtol(cmdargstr, &reststr, 10); fast = strtol(reststr, &reststr, 10); set_play_rate(slow, fast); } } /* Put a unit to sleep, which means it is inactive each turn until it is woken up, either by some alarm going off (such as low supply) or by explicit player action. */ void do_sleep(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_sleep); } static int do_one_sleep(Side *side, Unit *unit) { net_set_unit_asleep(side, unit, TRUE, TRUE /* is this right??? */); return TRUE; } /* Submit to (become controlled by) the specified side. */ void do_submit(Side *side) { Side *side2; DURING_GAME_ONLY(side); if (side->controlled_by != NULL) { cmd_error(side, "You are already controlled by %s!", short_side_title(side->controlled_by)); } if (empty_string(cmdargstr)) { cmd_error(side, "No side given to submit to!"); return; } side2 = parse_side_spec(cmdargstr); if (side2 == NULL) { cmd_error(side, "Can't get a side from \"%s\"!", cmdargstr); return; } if (side2 == side) { cmd_error(side, "Can't submit to ourselves!?"); return; } net_set_controlled_by(side, side2, TRUE); /* (should draw emblem inverted underneath controller's emblem) */ } /* Take supplies from transport. */ void do_take(Side *side) { DURING_GAME_ONLY(side); if (nummtypes == 0) { cmd_error(side, "No materials in this game!"); return; } apply_to_all_selected_units(side, do_one_take); } static int do_one_take(Side *side, Unit *unit) { short m, amts[MAXMTYPES], rslts[MAXMTYPES], needed; for_all_material_types(m) amts[m] = side->prefixarg; needed = take_supplies(unit, amts, rslts); report_take(side, unit, needed, rslts); return TRUE; } void do_trust(Side *side) { Side *side2; DURING_GAME_ONLY(side); if (empty_string(cmdargstr)) { notify_relationships(side); return; } side2 = parse_side_spec(cmdargstr); if (side2 == NULL) { cmd_error(side, "No side matching \"%s\"", cmdargstr); return; } if (side2 == side) { cmd_error(side, "We're not confused about trusting ourselves!"); return; } net_set_trust(side, side2, 1); } void do_wake(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_wake); } static int do_one_wake(Side *side, Unit *unit) { net_wake_unit(side, unit, FALSE); /* If an argument was given, apply to all "top-level" units within the radius specified by the argument. */ if (side->prefixarg >= 0) net_wake_area(side, unit->x, unit->y, side->prefixarg, FALSE); return 1; } void do_wake_all(Side *side) { DURING_GAME_ONLY(side); apply_to_all_selected_units(side, do_one_wake_all); } static int do_one_wake_all(Side *side, Unit *unit) { net_wake_unit(side, unit, TRUE); /* If an argument was given, apply to all units and occs within the radius specified by the argument. */ if (side->prefixarg >= 0) net_wake_area(side, unit->x, unit->y, side->prefixarg, TRUE); return 1; } void do_warning_log(Side *side) { warnings_logged = !warnings_logged; if (warnings_logged) notify_all("Warnings now being logged in \"Xconq.Warnings\".\n"); else notify_all("Warnings will not be logged.\n"); } #ifdef DESIGNERS void do_gdl(Side *side) { /* (should check designer status?) */ if (!empty_string(cmdargstr)) interp_form(NULL, read_form_from_string(cmdargstr, NULL, NULL, NULL)); /* (should broadcast to all?) */ } #endif /* DESIGNERS */ #ifdef DEBUGGING /* Debugging-related commands. */ /* General debugging toggles. */ void do_debug(Side *side) { #ifndef Debug toggle_debugging(&Debug); #endif notify_all("Debugging: %d", Debug); update_everything(); } void do_debugg(Side *side) { #ifndef DebugG toggle_debugging(&DebugG); #endif notify_all("Graphics debugging: %d", DebugG); update_everything(); } void do_debugm(Side *side) { #ifndef DebugM toggle_debugging(&DebugM); #endif notify_all("Machine play/AI debugging: %d", DebugM); update_everything(); } #endif /* DEBUGGING */