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