1 /**
2 * \file cmd-core.c
3 * \brief Handles the queueing of game commands.
4 *
5 * Copyright (c) 2008-9 Antony Sidwell
6 * Copyright (c) 2014 Andi Sidwell
7 *
8 * This work is free software; you can redistribute it and/or modify it
9 * under the terms of either:
10 *
11 * a) the GNU General Public License as published by the Free Software
12 * Foundation, version 2, or
13 *
14 * b) the "Angband licence":
15 * This software may be copied and distributed for educational, research,
16 * and not for profit purposes provided that this copyright and statement
17 * are included in all such copies. Other copyrights may also apply.
18 */
19
20 #include "angband.h"
21 #include "cmds.h"
22 #include "cmd-core.h"
23 #include "game-input.h"
24 #include "obj-chest.h"
25 #include "obj-desc.h"
26 #include "obj-tval.h"
27 #include "obj-util.h"
28 #include "player-attack.h"
29 #include "player-birth.h"
30 #include "player-calcs.h"
31 #include "player-spell.h"
32 #include "player-timed.h"
33 #include "player-util.h"
34 #include "store.h"
35 #include "target.h"
36
37 errr (*cmd_get_hook)(cmd_context c);
38
39 /**
40 * ------------------------------------------------------------------------
41 * A simple list of commands and their handling functions.
42 * ------------------------------------------------------------------------ */
43 struct command_info
44 {
45 cmd_code cmd;
46 const char *verb;
47 cmd_handler_fn fn;
48 bool repeat_allowed;
49 int auto_repeat_n;
50 };
51
52 static const struct command_info game_cmds[] =
53 {
54 { CMD_LOADFILE, "load a savefile", NULL, false, 0 },
55 { CMD_NEWGAME, "start a new game", NULL, false, 0 },
56
57 { CMD_BIRTH_INIT, "start the character birth process", do_cmd_birth_init, false, 0 },
58 { CMD_BIRTH_RESET, "go back to the beginning", do_cmd_birth_reset, false, 0 },
59 { CMD_CHOOSE_RACE, "select race", do_cmd_choose_race, false, 0 },
60 { CMD_CHOOSE_CLASS, "select class", do_cmd_choose_class, false, 0 },
61 { CMD_BUY_STAT, "buy points in a stat", do_cmd_buy_stat, false, 0 },
62 { CMD_SELL_STAT, "sell points in a stat", do_cmd_sell_stat, false, 0 },
63 { CMD_RESET_STATS, "reset stats", do_cmd_reset_stats, false, 0 },
64 { CMD_ROLL_STATS, "roll new stats", do_cmd_roll_stats, false, 0 },
65 { CMD_PREV_STATS, "use previously rolled stats", do_cmd_prev_stats, false, 0 },
66 { CMD_NAME_CHOICE, "choose name", do_cmd_choose_name, false, 0 },
67 { CMD_HISTORY_CHOICE, "write history", do_cmd_choose_history, false, 0 },
68 { CMD_ACCEPT_CHARACTER, "accept character", do_cmd_accept_character, false, 0 },
69
70 { CMD_GO_UP, "go up stairs", do_cmd_go_up, false, 0 },
71 { CMD_GO_DOWN, "go down stairs", do_cmd_go_down, false, 0 },
72 { CMD_WALK, "walk", do_cmd_walk, true, 0 },
73 { CMD_RUN, "run", do_cmd_run, true, 0 },
74 { CMD_JUMP, "jump", do_cmd_jump, false, 0 },
75 { CMD_OPEN, "open", do_cmd_open, true, 99 },
76 { CMD_CLOSE, "close", do_cmd_close, true, 99 },
77 { CMD_TUNNEL, "tunnel", do_cmd_tunnel, true, 99 },
78 { CMD_HOLD, "stay still", do_cmd_hold, true, 0 },
79 { CMD_DISARM, "disarm", do_cmd_disarm, true, 99 },
80 { CMD_ALTER, "alter", do_cmd_alter, true, 99 },
81 { CMD_STEAL, "steal", do_cmd_steal, false, 0 },
82 { CMD_REST, "rest", do_cmd_rest, false, 0 },
83 { CMD_SLEEP, "sleep", do_cmd_sleep, false, 0 },
84 { CMD_PATHFIND, "walk", do_cmd_pathfind, false, 0 },
85 { CMD_PICKUP, "pickup", do_cmd_pickup, false, 0 },
86 { CMD_AUTOPICKUP, "autopickup", do_cmd_autopickup, false, 0 },
87 { CMD_WIELD, "wear or wield", do_cmd_wield, false, 0 },
88 { CMD_TAKEOFF, "take off", do_cmd_takeoff, false, 0 },
89 { CMD_DROP, "drop", do_cmd_drop, false, 0 },
90 { CMD_UNINSCRIBE, "un-inscribe", do_cmd_uninscribe, false, 0 },
91 { CMD_AUTOINSCRIBE, "autoinscribe", do_cmd_autoinscribe, false, 0 },
92 { CMD_EAT, "eat", do_cmd_eat_food, false, 0 },
93 { CMD_QUAFF, "quaff", do_cmd_quaff_potion, false, 0 },
94 { CMD_USE_ROD, "zap", do_cmd_zap_rod, false, 0 },
95 { CMD_USE_STAFF, "use", do_cmd_use_staff, false, 0 },
96 { CMD_USE_WAND, "aim", do_cmd_aim_wand, false, 0 },
97 { CMD_READ_SCROLL, "read", do_cmd_read_scroll, false, 0 },
98 { CMD_ACTIVATE, "activate", do_cmd_activate, false, 0 },
99 { CMD_REFILL, "refuel with", do_cmd_refill, false, 0 },
100 { CMD_FIRE, "fire", do_cmd_fire, false, 0 },
101 { CMD_THROW, "throw", do_cmd_throw, false, 0 },
102 { CMD_INSCRIBE, "inscribe", do_cmd_inscribe, false, 0 },
103 { CMD_STUDY, "study", do_cmd_study, false, 0 },
104 { CMD_CAST, "cast", do_cmd_cast, false, 0 },
105 { CMD_SELL, "sell", do_cmd_sell, false, 0 },
106 { CMD_STASH, "stash", do_cmd_stash, false, 0 },
107 { CMD_BUY, "buy", do_cmd_buy, false, 0 },
108 { CMD_RETRIEVE, "retrieve", do_cmd_retrieve, false, 0 },
109 { CMD_USE, "use", do_cmd_use, false, 0 },
110 { CMD_SUICIDE, "kill character", do_cmd_suicide, false, 0 },
111 { CMD_HELP, "help", NULL, false, 0 },
112 { CMD_REPEAT, "repeat", NULL, false, 0 },
113
114 { CMD_COMMAND_MONSTER, "make a monster act", do_cmd_mon_command, false, 0 },
115 };
116
cmd_verb(cmd_code cmd)117 const char *cmd_verb(cmd_code cmd)
118 {
119 size_t i;
120 for (i = 0; i < N_ELEMENTS(game_cmds); i++) {
121 if (game_cmds[i].cmd == cmd)
122 return game_cmds[i].verb;
123 }
124 return NULL;
125 }
126
127 /**
128 * Return the index of the given command in the command array.
129 */
cmd_idx(cmd_code code)130 static int cmd_idx(cmd_code code)
131 {
132 size_t i;
133
134 for (i = 0; i < N_ELEMENTS(game_cmds); i++)
135 if (game_cmds[i].cmd == code)
136 return i;
137
138 return CMD_ARG_NOT_PRESENT;
139 }
140
141
142 /**
143 * ------------------------------------------------------------------------
144 * The command queue.
145 * ------------------------------------------------------------------------ */
146
147 #define CMD_QUEUE_SIZE 20
148 #define prev_cmd_idx(idx) ((idx + CMD_QUEUE_SIZE - 1) % CMD_QUEUE_SIZE)
149
150 static int cmd_head = 0;
151 static int cmd_tail = 0;
152 static struct command cmd_queue[CMD_QUEUE_SIZE];
153
154 static bool repeat_prev_allowed = false;
155 static bool repeating = false;
156
cmdq_peek(void)157 struct command *cmdq_peek(void)
158 {
159 return &cmd_queue[prev_cmd_idx(cmd_head)];
160 }
161
162
163 /**
164 * Insert the given command into the command queue.
165 */
cmdq_push_copy(struct command * cmd)166 errr cmdq_push_copy(struct command *cmd)
167 {
168 /* If queue full, return error */
169 if (cmd_head + 1 == cmd_tail) return 1;
170 if (cmd_head + 1 == CMD_QUEUE_SIZE && cmd_tail == 0) return 1;
171
172 /* Insert command into queue. */
173 if (cmd->code != CMD_REPEAT) {
174 cmd_queue[cmd_head] = *cmd;
175 } else {
176 int cmd_prev = cmd_head - 1;
177
178 if (!repeat_prev_allowed) return 1;
179
180 /* If we're repeating a command, we duplicate the previous command
181 in the next command "slot". */
182 if (cmd_prev < 0) cmd_prev = CMD_QUEUE_SIZE - 1;
183
184 if (cmd_queue[cmd_prev].code != CMD_NULL)
185 cmd_queue[cmd_head] = cmd_queue[cmd_prev];
186 }
187
188 /* Advance point in queue, wrapping around at the end */
189 cmd_head++;
190 if (cmd_head == CMD_QUEUE_SIZE) cmd_head = 0;
191
192 return 0;
193 }
194
195 /**
196 * Process a game command from the UI or the command queue and carry out
197 * whatever actions go along with it.
198 */
process_command(cmd_context ctx,struct command * cmd)199 void process_command(cmd_context ctx, struct command *cmd)
200 {
201 int oldrepeats = cmd->nrepeats;
202 int idx = cmd_idx(cmd->code);
203
204 /* Hack - command a monster */
205 if (player->timed[TMD_COMMAND]) {
206 idx = (int) N_ELEMENTS(game_cmds) - 1;
207 }
208
209 /* Reset so that when selecting items, we look in the default location */
210 player->upkeep->command_wrk = 0;
211
212 if (idx == -1) return;
213
214 /* Command repetition */
215 if (game_cmds[idx].repeat_allowed) {
216 /* Auto-repeat only if there isn't already a repeat length. */
217 if (game_cmds[idx].auto_repeat_n > 0 && cmd->nrepeats == 0)
218 cmd_set_repeat(game_cmds[idx].auto_repeat_n);
219 } else {
220 cmd->nrepeats = 0;
221 repeating = false;
222 }
223
224 /* The command gets to unset this if it isn't appropriate for
225 * the user to repeat it. */
226 repeat_prev_allowed = true;
227
228 cmd->context = ctx;
229
230 /* Actually execute the command function */
231 if (game_cmds[idx].fn) {
232 /* Occasional attack instead for bloodlust-affected characters */
233 if (randint0(200) < player->timed[TMD_BLOODLUST]) {
234 if (player_attack_random_monster(player)) return;
235 }
236 game_cmds[idx].fn(cmd);
237 }
238
239 /* If the command hasn't changed nrepeats, count this execution. */
240 if (cmd->nrepeats > 0 && oldrepeats == cmd_get_nrepeats())
241 cmd_set_repeat(oldrepeats - 1);
242 }
243
244 /**
245 * Get the next game command from the queue and process it.
246 */
cmdq_pop(cmd_context c)247 bool cmdq_pop(cmd_context c)
248 {
249 struct command *cmd;
250
251 /* If we're repeating, just pull the last command again. */
252 if (repeating) {
253 cmd = &cmd_queue[prev_cmd_idx(cmd_tail)];
254 } else if (cmd_head != cmd_tail) {
255 /* If we have a command ready, set it. */
256 cmd = &cmd_queue[cmd_tail++];
257 if (cmd_tail == CMD_QUEUE_SIZE)
258 cmd_tail = 0;
259 } else {
260 /* Failure to get a command. */
261 return false;
262 }
263
264 /* Now process it */
265 process_command(c, cmd);
266 return true;
267 }
268
269 /**
270 * Inserts a command in the queue to be carried out, with the given
271 * number of repeats.
272 */
cmdq_push_repeat(cmd_code c,int nrepeats)273 errr cmdq_push_repeat(cmd_code c, int nrepeats)
274 {
275 struct command cmd = {
276 .context = CTX_INIT,
277 .code = CMD_NULL,
278 .nrepeats = 0,
279 .arg = { { 0 } }
280 };
281
282 if (cmd_idx(c) == -1)
283 return 1;
284
285 cmd.code = c;
286 cmd.nrepeats = nrepeats;
287
288 return cmdq_push_copy(&cmd);
289 }
290
291 /**
292 * Inserts a command in the queue to be carried out.
293 */
cmdq_push(cmd_code c)294 errr cmdq_push(cmd_code c)
295 {
296 return cmdq_push_repeat(c, 0);
297 }
298
299
300 /**
301 * Shorthand to execute all commands in the queue right now, no waiting
302 * for input.
303 */
cmdq_execute(cmd_context ctx)304 void cmdq_execute(cmd_context ctx)
305 {
306 while (cmdq_pop(ctx)) ;
307 }
308
309 /**
310 * Remove all commands from the queue.
311 */
cmdq_flush(void)312 void cmdq_flush(void)
313 {
314 cmd_tail = cmd_head;
315 }
316
317 /**
318 * Return true if the previous command used an item from the floor.
319 * Otherwise, return false.
320 */
cmdq_does_previous_use_floor_item(void)321 bool cmdq_does_previous_use_floor_item(void)
322 {
323 int cmd_prev = cmd_head - 1;
324
325 if (cmd_prev < 0) cmd_prev = CMD_QUEUE_SIZE - 1;
326 if (cmd_queue[cmd_prev].code != CMD_NULL) {
327 struct object *obj;
328
329 if (cmd_get_arg_item(&cmd_queue[cmd_prev], "item", &obj) == CMD_OK) {
330 return (obj->grid.x == 0 && obj->grid.y == 0) ? false : true;
331 }
332 }
333 return false;
334 }
335
336 /**
337 * ------------------------------------------------------------------------
338 * Handling of repeated commands
339 * ------------------------------------------------------------------------ */
340
341 /**
342 * Remove any pending repeats from the current command.
343 */
cmd_cancel_repeat(void)344 void cmd_cancel_repeat(void)
345 {
346 struct command *cmd = &cmd_queue[prev_cmd_idx(cmd_tail)];
347
348 if (cmd->nrepeats || repeating) {
349 /* Cancel */
350 cmd->nrepeats = 0;
351 repeating = false;
352
353 /* Redraw the state (later) */
354 player->upkeep->redraw |= (PR_STATE);
355 }
356 }
357
358 /**
359 * Update the number of repeats pending for the current command.
360 */
cmd_set_repeat(int nrepeats)361 void cmd_set_repeat(int nrepeats)
362 {
363 struct command *cmd = &cmd_queue[prev_cmd_idx(cmd_tail)];
364
365 cmd->nrepeats = nrepeats;
366 if (nrepeats) repeating = true;
367 else repeating = false;
368
369 /* Redraw the state (later) */
370 player->upkeep->redraw |= (PR_STATE);
371 }
372
373 /**
374 * Return the number of repeats pending for the current command.
375 */
cmd_get_nrepeats(void)376 int cmd_get_nrepeats(void)
377 {
378 struct command *cmd = &cmd_queue[prev_cmd_idx(cmd_tail)];
379 return cmd->nrepeats;
380 }
381
382 /**
383 * Do not allow the current command to be repeated by the user using the
384 * "repeat last command" command.
385 */
cmd_disable_repeat(void)386 void cmd_disable_repeat(void)
387 {
388 repeat_prev_allowed = false;
389 }
390
391 /**
392 * ------------------------------------------------------------------------
393 * Argument setting/getting generics
394 * ------------------------------------------------------------------------ */
395
396 /**
397 * Set an argument of name 'arg' to data 'data'
398 */
cmd_set_arg(struct command * cmd,const char * name,enum cmd_arg_type type,union cmd_arg_data data)399 static void cmd_set_arg(struct command *cmd, const char *name,
400 enum cmd_arg_type type, union cmd_arg_data data)
401 {
402 size_t i;
403
404 int first_empty = -1;
405 int idx = -1;
406
407 assert(name);
408 assert(name[0]);
409
410 /* Find an arg that either... */
411 for (i = 0; i < CMD_MAX_ARGS; i++) {
412 struct cmd_arg *arg = &cmd->arg[i];
413 if (!arg->name[0] && first_empty == -1)
414 first_empty = i;
415
416 if (streq(arg->name, name)) {
417 idx = i;
418 break;
419 }
420 }
421
422 assert(first_empty != -1 || idx != -1);
423
424 if (idx == -1)
425 idx = first_empty;
426
427 cmd->arg[idx].type = type;
428 cmd->arg[idx].data = data;
429 my_strcpy(cmd->arg[idx].name, name, sizeof cmd->arg[0].name);
430 }
431
432 /**
433 * Get an argument with name 'arg'
434 */
cmd_get_arg(struct command * cmd,const char * arg,enum cmd_arg_type type,union cmd_arg_data * data)435 static int cmd_get_arg(struct command *cmd, const char *arg,
436 enum cmd_arg_type type, union cmd_arg_data *data)
437 {
438 size_t i;
439
440 for (i = 0; i < CMD_MAX_ARGS; i++) {
441 if (streq(cmd->arg[i].name, arg)) {
442 if (cmd->arg[i].type != type)
443 return CMD_ARG_WRONG_TYPE;
444
445 *data = cmd->arg[i].data;
446 return CMD_OK;
447 }
448 }
449
450 return CMD_ARG_NOT_PRESENT;
451 }
452
453
454
455 /**
456 * ------------------------------------------------------------------------
457 * 'Choice' type
458 * ------------------------------------------------------------------------ */
459
460 /**
461 * XXX This type is a hack. The only places that use this are:
462 * - resting
463 * - birth choices
464 * - store items
465 * - spells
466 *
467 * Each of these should have its own type, which will allow for proper
468 * validity checking of data.
469 */
470
471 /**
472 * Set arg 'n' to 'choice'
473 */
cmd_set_arg_choice(struct command * cmd,const char * arg,int choice)474 void cmd_set_arg_choice(struct command *cmd, const char *arg, int choice)
475 {
476 union cmd_arg_data data;
477 data.choice = choice;
478 cmd_set_arg(cmd, arg, arg_CHOICE, data);
479 }
480
481 /**
482 * Retrive an argument 'n' if it's a choice
483 */
cmd_get_arg_choice(struct command * cmd,const char * arg,int * choice)484 int cmd_get_arg_choice(struct command *cmd, const char *arg, int *choice)
485 {
486 union cmd_arg_data data;
487 int err;
488
489 if ((err = cmd_get_arg(cmd, arg, arg_CHOICE, &data)) == CMD_OK)
490 *choice = data.choice;
491
492 return err;
493 }
494
495
496 /**
497 * Get a spell from the user, trying the command first but then prompting
498 */
cmd_get_spell(struct command * cmd,const char * arg,int * spell,const char * verb,item_tester book_filter,const char * error,bool (* spell_filter)(int spell))499 int cmd_get_spell(struct command *cmd, const char *arg, int *spell,
500 const char *verb, item_tester book_filter, const char *error,
501 bool (*spell_filter)(int spell))
502 {
503 struct object *book;
504
505 /* See if we've been provided with this one */
506 if (cmd_get_arg_choice(cmd, arg, spell) == CMD_OK) {
507 /* Ensure it passes the filter */
508 if (!spell_filter || spell_filter(*spell) == true)
509 return CMD_OK;
510 }
511
512 /* See if we've been given a book to look at */
513 if (cmd_get_arg_item(cmd, "book", &book) == CMD_OK)
514 *spell = get_spell_from_book(verb, book, error, spell_filter);
515 else
516 *spell = get_spell(verb, book_filter, cmd->code, error, spell_filter);
517
518 if (*spell >= 0) {
519 cmd_set_arg_choice(cmd, arg, *spell);
520 return CMD_OK;
521 }
522
523 return CMD_ARG_ABORTED;
524 }
525
526 /**
527 * ------------------------------------------------------------------------
528 * Strings
529 * ------------------------------------------------------------------------ */
530
531 /**
532 * Set arg 'n' to given string
533 */
cmd_set_arg_string(struct command * cmd,const char * arg,const char * str)534 void cmd_set_arg_string(struct command *cmd, const char *arg, const char *str)
535 {
536 union cmd_arg_data data;
537 data.string = string_make(str);
538 cmd_set_arg(cmd, arg, arg_STRING, data);
539 }
540
541 /**
542 * Retrieve arg 'n' if a string
543 */
cmd_get_arg_string(struct command * cmd,const char * arg,const char ** str)544 int cmd_get_arg_string(struct command *cmd, const char *arg, const char **str)
545 {
546 union cmd_arg_data data;
547 int err;
548
549 if ((err = cmd_get_arg(cmd, arg, arg_STRING, &data)) == CMD_OK)
550 *str = data.string;
551
552 return err;
553 }
554
555 /**
556 * Get a string, first from the command or failing that prompt the user
557 */
cmd_get_string(struct command * cmd,const char * arg,const char ** str,const char * initial,const char * title,const char * prompt)558 int cmd_get_string(struct command *cmd, const char *arg, const char **str,
559 const char *initial, const char *title, const char *prompt)
560 {
561 char tmp[80] = "";
562
563 if (cmd_get_arg_string(cmd, arg, str) == CMD_OK)
564 return CMD_OK;
565
566 /* Introduce */
567 msg("%s", title);
568 event_signal(EVENT_MESSAGE_FLUSH);
569
570 /* Prompt properly */
571 if (initial)
572 my_strcpy(tmp, initial, sizeof tmp);
573
574 if (get_string(prompt, tmp, sizeof tmp)) {
575 cmd_set_arg_string(cmd, arg, tmp);
576 if (cmd_get_arg_string(cmd, arg, str) == CMD_OK)
577 return CMD_OK;
578 }
579
580 return CMD_ARG_ABORTED;
581 }
582
583 /**
584 * ------------------------------------------------------------------------
585 * Directions
586 * ------------------------------------------------------------------------ */
587
588 /**
589 * Set arg 'n' to given direction
590 */
cmd_set_arg_direction(struct command * cmd,const char * arg,int dir)591 void cmd_set_arg_direction(struct command *cmd, const char *arg, int dir)
592 {
593 union cmd_arg_data data;
594 data.direction = dir;
595 cmd_set_arg(cmd, arg, arg_DIRECTION, data);
596 }
597
598 /**
599 * Retrieve arg 'n' if a direction
600 */
cmd_get_arg_direction(struct command * cmd,const char * arg,int * dir)601 int cmd_get_arg_direction(struct command *cmd, const char *arg, int *dir)
602 {
603 union cmd_arg_data data;
604 int err;
605
606 if ((err = cmd_get_arg(cmd, arg, arg_DIRECTION, &data)) == CMD_OK)
607 *dir = data.direction;
608
609 return err;
610 }
611
612 /**
613 * Get a direction, first from command or prompt otherwise
614 */
cmd_get_direction(struct command * cmd,const char * arg,int * dir,bool allow_5)615 int cmd_get_direction(struct command *cmd, const char *arg, int *dir,
616 bool allow_5)
617 {
618 if (cmd_get_arg_direction(cmd, arg, dir) == CMD_OK) {
619 /* Validity check */
620 if (*dir != DIR_NONE)
621 return CMD_OK;
622 }
623
624 /* We need to do extra work */
625 if (get_rep_dir(dir, allow_5)) {
626 cmd_set_arg_direction(cmd, arg, *dir);
627 return CMD_OK;
628 }
629
630 cmd_cancel_repeat();
631 return CMD_ARG_ABORTED;
632 }
633
634 /**
635 * ------------------------------------------------------------------------
636 * Targets
637 * ------------------------------------------------------------------------ */
638
639 /**
640 * XXX Should this be unified with the arg_DIRECTION type?
641 *
642 * XXX Should we abolish DIR_TARGET and instead pass a struct target which
643 * contains all relevant info?
644 */
645
646 /**
647 * Set arg 'n' to target
648 */
cmd_set_arg_target(struct command * cmd,const char * arg,int target)649 void cmd_set_arg_target(struct command *cmd, const char *arg, int target)
650 {
651 union cmd_arg_data data;
652 data.direction = target;
653 cmd_set_arg(cmd, arg, arg_TARGET, data);
654 }
655
656 /**
657 * Retrieve arg 'n' if it's a target
658 */
cmd_get_arg_target(struct command * cmd,const char * arg,int * target)659 int cmd_get_arg_target(struct command *cmd, const char *arg, int *target)
660 {
661 union cmd_arg_data data;
662 int err;
663
664 if ((err = cmd_get_arg(cmd, arg, arg_TARGET, &data)) == CMD_OK)
665 *target = data.direction;
666
667 return err;
668 }
669
670 /**
671 * Get a target, first from command or prompt otherwise
672 */
cmd_get_target(struct command * cmd,const char * arg,int * target)673 int cmd_get_target(struct command *cmd, const char *arg, int *target)
674 {
675 if (cmd_get_arg_target(cmd, arg, target) == CMD_OK) {
676 if (*target != DIR_UNKNOWN &&
677 (*target != DIR_TARGET || target_okay()))
678 return CMD_OK;
679 }
680
681 if (get_aim_dir(target)) {
682 cmd_set_arg_target(cmd, arg, *target);
683 return CMD_OK;
684 }
685
686 return CMD_ARG_ABORTED;
687 }
688
689 /**
690 * ------------------------------------------------------------------------
691 * Points (presently unused)
692 * ------------------------------------------------------------------------ */
693
694 /**
695 * Set argument 'n' to point grid
696 */
cmd_set_arg_point(struct command * cmd,const char * arg,struct loc grid)697 void cmd_set_arg_point(struct command *cmd, const char *arg, struct loc grid)
698 {
699 union cmd_arg_data data;
700 data.point = grid;
701 cmd_set_arg(cmd, arg, arg_POINT, data);
702 }
703
704 /**
705 * Retrieve argument 'n' if it's a point
706 */
cmd_get_arg_point(struct command * cmd,const char * arg,struct loc * grid)707 int cmd_get_arg_point(struct command *cmd, const char *arg, struct loc *grid)
708 {
709 union cmd_arg_data data;
710 int err;
711
712 if ((err = cmd_get_arg(cmd, arg, arg_POINT, &data)) == CMD_OK) {
713 *grid = data.point;
714 }
715
716 return err;
717 }
718
719 /**
720 * ------------------------------------------------------------------------
721 * Item arguments
722 * ------------------------------------------------------------------------ */
723
724 /**
725 * Set argument 'n' to 'item'
726 */
cmd_set_arg_item(struct command * cmd,const char * arg,struct object * obj)727 void cmd_set_arg_item(struct command *cmd, const char *arg, struct object *obj)
728 {
729 union cmd_arg_data data;
730 data.obj = obj;
731 cmd_set_arg(cmd, arg, arg_ITEM, data);
732 }
733
734 /**
735 * Retrieve argument 'n' as an item
736 */
cmd_get_arg_item(struct command * cmd,const char * arg,struct object ** obj)737 int cmd_get_arg_item(struct command *cmd, const char *arg, struct object **obj)
738 {
739 union cmd_arg_data data;
740 int err;
741
742 if ((err = cmd_get_arg(cmd, arg, arg_ITEM, &data)) == CMD_OK)
743 *obj = data.obj;
744
745 return err;
746 }
747
748 /**
749 * Get an item, first from the command or try the UI otherwise
750 */
cmd_get_item(struct command * cmd,const char * arg,struct object ** obj,const char * prompt,const char * reject,item_tester filter,int mode)751 int cmd_get_item(struct command *cmd, const char *arg, struct object **obj,
752 const char *prompt, const char *reject, item_tester filter,
753 int mode)
754 {
755 if ((cmd_get_arg_item(cmd, arg, obj) == CMD_OK) && (!filter|| filter(*obj)))
756 return CMD_OK;
757
758 /* Shapechanged players can only access the floor */
759 if (player_is_shapechanged(player)) {
760 mode &= ~(USE_EQUIP | USE_INVEN | USE_QUIVER);
761 }
762
763 if (get_item(obj, prompt, reject, cmd->code, filter, mode)) {
764 cmd_set_arg_item(cmd, arg, *obj);
765 return CMD_OK;
766 }
767
768 return CMD_ARG_ABORTED;
769 }
770
771 /**
772 * ------------------------------------------------------------------------
773 * Numbers, quantities
774 * ------------------------------------------------------------------------ */
775
776 /**
777 * Set argument 'n' to 'number'
778 */
cmd_set_arg_number(struct command * cmd,const char * arg,int amt)779 void cmd_set_arg_number(struct command *cmd, const char *arg, int amt)
780 {
781 union cmd_arg_data data;
782 data.number = amt;
783 cmd_set_arg(cmd, arg, arg_NUMBER, data);
784 }
785
786 /**
787 * Get argument 'n' as a number
788 */
cmd_get_arg_number(struct command * cmd,const char * arg,int * amt)789 int cmd_get_arg_number(struct command *cmd, const char *arg, int *amt)
790 {
791 union cmd_arg_data data;
792 int err;
793
794 if ((err = cmd_get_arg(cmd, arg, arg_NUMBER, &data)) == CMD_OK)
795 *amt = data.number;
796
797 return err;
798 }
799
800 /**
801 * Get argument 'n' as a number; failing that, prompt for input
802 */
cmd_get_quantity(struct command * cmd,const char * arg,int * amt,int max)803 int cmd_get_quantity(struct command *cmd, const char *arg, int *amt, int max)
804 {
805 if (cmd_get_arg_number(cmd, arg, amt) == CMD_OK)
806 return CMD_OK;
807
808 *amt = get_quantity(NULL, max);
809 if (*amt > 0) {
810 cmd_set_arg_number(cmd, arg, *amt);
811 return CMD_OK;
812 }
813
814 return CMD_ARG_ABORTED;
815 }
816