diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dedb92..4d23055 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set (PROJECT_SOURCES src/main.c src/interface.c src/map.c - src/action.c + src/command.c src/key.c src/msg.c src/game.c diff --git a/include/action.h b/include/command.h similarity index 60% rename from include/action.h rename to include/command.h index 5e14b19..3523802 100644 --- a/include/action.h +++ b/include/command.h @@ -1,6 +1,6 @@ /* - * include/action.h - * Declare the interface to handle user input + * include/command.c + * Declare the interface for taking and executing commands * * Copyright (C) 2017 Utkarsh Mahshwari * @@ -18,14 +18,23 @@ * along with this program. If not, see . */ -#ifndef ACTION_H_D9AS6ZWN -#define ACTION_H_D9AS6ZWN +#ifndef COMMAND_H_0TNF49V3 +#define COMMAND_H_0TNF49V3 + + +/** + * Ask user for input and build the command + * @return The pointer to the command + */ +command_t * command_get(); + /** - * Take a key as input and update the map checking if the move is valid or not - * @param The map to update - * @return The command entered by the user + * Execute the command on the given map + * @param The pointer to the map + * @patam The pointer to the command */ -command_t action_make_move(const map_t *map); +void command_exec(const map_t *, const command_t *); + -#endif /* end of include guard: ACTION_H_D9AS6ZWN */ +#endif /* end of include guard: COMMAND_H_0TNF49V3 */ diff --git a/include/datatypes.h b/include/datatypes.h index 54ee089..dab3c81 100644 --- a/include/datatypes.h +++ b/include/datatypes.h @@ -165,11 +165,16 @@ typedef struct { typedef struct { enum { COMMAND_NOP, - COMMAND_MOTION, COMMAND_HELP, COMMAND_QUIT, + COMMAND_OTHER, } type; - char value; + int count; + struct { + int count; + int value; + } motion; + int oper; } command_t; diff --git a/include/interface.h b/include/interface.h index 2d44e86..b4ab058 100644 --- a/include/interface.h +++ b/include/interface.h @@ -90,6 +90,13 @@ void interface_display_status(game_status_t); input_key_t interface_input_key(); +/** + * Put the key back to the input queue + * @param The key to put back + */ +void interface_input_key_undo(input_key_t); + + /** * Keep taking input till the user presses enter * @return The line terminated by '\0' diff --git a/src/action.c b/src/action.c deleted file mode 100644 index 0a862ab..0000000 --- a/src/action.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * src/action.c - * Define the module to handle user input - * - * Copyright (C) 2017 Utkarsh Mahshwari - * - * This program 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 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include /* for strcmp(), strcat() */ -#include /* for free() */ - -#include "datatypes.h" -#include "action.h" -#include "map.h" -#include "interface.h" -#include "key.h" - - -command_t input_command(); - - -command_t action_make_move(const map_t *map) -{ - point_t point; - int loop = 1; - int multiplier = 0; - input_key_t key; - command_t command; - - /* calculate the update */ - point.x = map -> cursor.x; - point.y = map -> cursor.y; - - /* get key and check if it's unlocked */ - key = interface_input_key(); - - while (loop) { - - /* 1 if the real x of cursor is touched and thus has to be changed. - * a successful change of x by a key can do that */ - int touched = 0; - map_tile_t tile; - point_t *temp_point; - - if (!key_unlocked(key)) { - key = interface_input_key(); - continue; - } else { - loop--; - } - - switch (key) { - case 'j': - point.y += 1; - point.x = map -> real_x; - command.type = COMMAND_MOTION; - break; - case 'k': - point.y -= 1; - point.x = map -> real_x; - command.type = COMMAND_MOTION; - break; - case 'l': - point.x += 1; - touched = 1; - command.type = COMMAND_MOTION; - break; - case 'h': - point.x -= 1; - touched = 1; - command.type = COMMAND_MOTION; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - multiplier = (multiplier) * 10 + key - '0'; - /* loop it multiplier number of times */ - loop = multiplier; - key = interface_input_key(); - break; - - case 'w': - tile = map_get_tile(map -> cursor); - if (tile.type != TILE_TEXT) break; - tile.type = TILE_TEXT; - tile.value = ' '; - if ((temp_point = map_search_tile(tile, 1)) != NULL) { - point.x = temp_point -> x + 1; - point.y = temp_point -> y; - free(temp_point); - } - break; - - case ':': - return input_command(); - } - - /* if the point is out of bounds, illegal move */ - if (point.y >= map -> size.y || point.x >= map -> size.x) { - continue; - } - - /* if the line was not changed and the tile is not free, invalid move */ - if (point.y == map -> cursor.y && !map_is_free(point)) { - continue; - } - - /* if line was changed and we can find a point which is before the - * desired point, move to it */ - while (point.x && !map_is_free(point)) { - point.x--; - } - - /* if point is 0, no place to put cursor, invalid move */ - if (point.x == 0) continue; - - /* update cursor */ - map_set_cursor(point); - - /* if x was touched, this is now the real x */ - if (touched) map_set_real_cursor(); - } - - return command; -} - -command_t input_command() -{ - command_t command; - char *line; - - line = interface_input_command(); - - if (!strcmp(line, "quit") || !strcmp(line, "q")) { - command.type = COMMAND_QUIT; - interface_display_command("quit"); - - } else if (!strcmp(line, "help") || !strcmp(line, "h")) { - command.type = COMMAND_HELP; - interface_display_command("help"); - - } else { - command.type = COMMAND_NOP; - interface_display_command("command not found"); - } - - free(line); - return command; -} diff --git a/src/command.c b/src/command.c new file mode 100644 index 0000000..753f54c --- /dev/null +++ b/src/command.c @@ -0,0 +1,189 @@ +/* + * src/command.c + * Defile the module for taking and executing commands + * + * Copyright (C) 2017 Utkarsh Mahshwari + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include /* for malloc(), NULL */ +#include /* for strcmp() */ + +#include "datatypes.h" +#include "command.h" +#include "interface.h" +#include "map.h" + + +int get_count() +{ + int count = 0; + + while (1) { + input_key_t key = interface_input_key(); + + /* if first key for count is zero, then it is be the '0' motion key */ + if (count == 0 && key == '0') { + interface_input_key_undo(key); + return 1; + + /* if key is a number add it */ + } else if (key >= '0' && key <= '9') { + count = count * 10 + (key - '0'); + + /* if key is not a number, it is a command */ + } else { + interface_input_key_undo(key); + if (!count) count = 1; + break; + } + } + + return count; +} + +int get_oper() +{ + input_key_t key = interface_input_key(); + switch (key) { + case 'd': + case 'c': + case 'y': + return key; + default: + interface_input_key_undo(key); + return 0; + } +} + +int get_motion() +{ + input_key_t key = interface_input_key(); + return key; +} + +point_t * exec_motion(const map_t *map, const command_t *command) +{ + point_t temp = { .y = map -> cursor.y, .x = map -> real_x }; + + switch (command -> motion.value) { + case 'j': + temp.y += 1; + break; + case 'k': + temp.y -= 1; + break; + case 'l': + temp.x = map -> cursor.x + 1; + break; + case 'h': + temp.x = map -> cursor.x - 1; + break; + } + + if (temp.y == map -> cursor.y && !map_is_free(temp)) { + return NULL; + } + + while (temp.y != map -> cursor.y && temp.x && !map_is_free(temp)) + temp.x--; + + if (map_is_free(temp)) { + point_t *point = (point_t *) malloc(sizeof(point_t)); + point -> y = temp.y; + point -> x = temp.x; + return point; + + } else { + return NULL; + } +} + +command_t * get_command_line() +{ + command_t *command = NULL; + char *line; + + input_key_t key = interface_input_key(); + if (key != ':') { + interface_input_key_undo(key); + return NULL; + } + + command = (command_t *) malloc(sizeof(command_t)); + line = interface_input_command(); + + if (!strcmp(line, "quit") || !strcmp(line, "q")) { + command -> type = COMMAND_QUIT; + interface_display_command("quit"); + + } else if (!strcmp(line, "help") || !strcmp(line, "h")) { + command -> type = COMMAND_HELP; + interface_display_command("help"); + + } else { + command -> type = COMMAND_NOP; + interface_display_command("command not found"); + } + + free(line); + return command; +} + +command_t * command_get() +{ + command_t *command; + + /* check if it's a command line */ + if ((command = get_command_line()) != NULL) + return command; + + /* else build the command */ + command = (command_t *) malloc(sizeof(command_t)); + command -> type = COMMAND_OTHER; + command -> count = get_count(); + command -> oper = get_oper(); + command -> motion.count = get_count(); + command -> motion.value = get_motion(); + + return command; +} + +void command_exec(const map_t *map, const command_t *command) +{ + int count = command -> count; + + if (command -> type == COMMAND_NOP) { + return; + } + + while (count--) { + + int count2 = command -> motion.count; + while (count2--) { + + point_t *end = exec_motion(map, command); + if (end) { + if (end -> y == map -> cursor.y + && end -> x != map -> cursor.x) { + map_set_cursor(*end); + map_set_real_cursor(); + } + map_set_cursor(*end); + free(end); + } + } + } +} diff --git a/src/game.c b/src/game.c index 82e7c56..da3d0f8 100644 --- a/src/game.c +++ b/src/game.c @@ -18,11 +18,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include /* for free() */ #include "datatypes.h" #include "game.h" #include "interface.h" -#include "action.h" +#include "command.h" #include "key.h" #include "map.h" #include "msg.h" @@ -85,9 +86,15 @@ int play(const map_t *map) if (!acquire_tile(map)) break; - command_t command = action_make_move(map); - if (command.type == COMMAND_QUIT) + command_t *command = command_get(map); + + if (command -> type == COMMAND_QUIT) { + free(command); return 0; + } + + command_exec(map, command); + free(command); } return 1; diff --git a/src/interface.c b/src/interface.c index 07be21d..2c8bb42 100644 --- a/src/interface.c +++ b/src/interface.c @@ -261,6 +261,11 @@ input_key_t interface_input_key() return getch(); } +void interface_input_key_undo(input_key_t key) +{ + ungetch(key); +} + char * interface_input_command() { char *line = NULL; diff --git a/src/map.c b/src/map.c index c52cad2..d92cc8f 100644 --- a/src/map.c +++ b/src/map.c @@ -70,6 +70,7 @@ void map_close() boolean map_is_free(point_t point) { int pos = convert_point_to_linear(point); + if (pos == -1) return B_FALSE; if (map -> data[pos].type == TILE_GRASS || map -> data[pos].type == TILE_DOOR