Skip to content

Commit

Permalink
Parse arguments with argp.
Browse files Browse the repository at this point in the history
This is a much more elegant means of handling things than rolling
our own argument parser. The current arguments should take care of
basically all player needs.

This commit also renames explore mode to practice mode, which both
fits the theme of the game better and also avoids confusion with
the explore action.
  • Loading branch information
Kestrel Gregorich-Trevor committed Jan 18, 2024
1 parent 82e176c commit ac4eb8d
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 46 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.23.0)
set(CMAKE_C_STANDARD 99)
set(PROJECT_NAME zenzizenzizenzic_ncurses)
set(PROJECT_VENDOR Kestrel Gregorich-Trevor)
set(PROJECT_DESCRIPTION A roguelike about fighting games.)
set(PROJECT_DESCRIPTION "A roguelike about fighting games.")
set(ZZZZZZ_DESKTOP_DIR /usr/share/applications)
set(VERSION_MAJOR 0)
set(VERSION_MINOR 1)
Expand Down
29 changes: 11 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ A traditional roguelike with mechanics that mimic those found in fighting games.

![Screenshot](/img/screenshot.png)

## Command Line Options
| Syntax | Example | Purpose |
| ------------|---------|-------------------|
| -u\[User\] | -uBob | Specify the user.
| -D | -D | Enter debug mode. In debug mode, the high score list is disabled, but the user has access to special debug functionality.
| -X | -X | Enter explore mode. In explore mode, the high scorel list is disabled, but the user can elect not to die.
## Combat Basics

An attack can be one or more of four types: Low, Mid, High, or Grab. Conversely, a character can be in one of three stances: Crouch, Stand, or Tech. The way an attack interacts with a target depends on the stance that the target is in, as shown in the following table.

| | Low | Mid | High | Tech |
|----------|-------|-------|-------|-------|
|**Crouch**| Block | Block | Hit | Hit |
|**Stand**| Hit | Block | Block | Hit |
|**Tech** | Hit | Hit | Hit | Block |

If an attack hits, the target takes full damage and enters a stunned state. If an attack is blocked, the target takes only partial damage and is not stunned.

## Building from Source
Zenzizenzizenzic is built using CMake.
Expand All @@ -26,18 +31,6 @@ cmake --build build
The game binary and necessary data files will appear in the newly-created build
directory.

## Combat Basics

An attack can be one or more of four types: Low, Mid, High, or Grab. Conversely, a character can be in one of three stances: Crouch, Stand, or Tech. The way an attack interacts with a target depends on the stance that the target is in, as shown in the following table.

| | Low | Mid | High | Tech |
|----------|-------|-------|-------|-------|
|**Crouch**| Block | Block | Hit | Hit |
|**Stand**| Hit | Block | Block | Hit |
|**Tech** | Hit | Hit | Hit | Block |

If an attack hits, the target takes full damage and enters a stunned state. If an attack is blocked, the target takes only partial damage and is not stunned.

## FAQ

### Is this Playable Yet?
Expand Down
2 changes: 1 addition & 1 deletion include/register.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ typedef struct global {
int goal_x, goal_y; /* Traveling */
/* Persistent flags */
unsigned int debug : 1;
unsigned int explore : 1;
unsigned int practice : 1;
/* 5 free bits */
} global;

Expand Down
4 changes: 3 additions & 1 deletion include/version.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@
/* Release, Debug, Test, etc. */
#define RELEASE_TYPE "${RELEASE_TYPE}"
/* Report Repo */
#define REPO_URL "https://github.com/NullCGT/Zenzizenzizenzic-RL"
#define REPO_URL "https://github.com/NullCGT/Zenzizenzizenzic-RL"
/* Short Description */
#define SHORT_DESC "${PROJECT_DESCRIPTION}"
2 changes: 1 addition & 1 deletion src/combat.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ int do_attack(struct actor *aggressor, struct actor *target, int multiplier) {
if (target == g.player && target->hp <= 0) {
g.target = aggressor;
logma(BRIGHT_RED, "%s is KO'd...", actor_name(target, NAME_CAP | NAME_THE));
if ((g.explore || g.debug) && !yn_prompt("Stay knocked out?", 0)) {
if ((g.practice || g.debug) && !yn_prompt("Stay knocked out?", 0)) {
logm("%s randomly regains consciousness.", actor_name(target, NAME_CAP | NAME_THE));
g.player->hp = g.player->hpmax;
return cost;
Expand Down
84 changes: 61 additions & 23 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <execinfo.h>
#include <unistd.h>
#include <string.h>
#include <argp.h>

#include "ai.h"
#include "invent.h"
Expand All @@ -35,7 +36,7 @@
void handle_exit(void);
void handle_sigwinch(int);
void new_game(void);
void parse_args(int, const char *[]);
error_t parse_args(int, char *, struct argp_state *);

/**
* @brief Called whenever the program exits. Cleans up the screen and
Expand Down Expand Up @@ -105,8 +106,8 @@ void handle_sigsegv(int sig) {
void new_game(void) {
json_to_monster_list("data/creature/creatures.json");
json_to_item_list("data/item/weapons.json");
if (f.mode_explore || g.debug) {
logm_warning("The high score list is disabled due to the game mode.");
if (g.practice || g.debug) {
logm("The high score list is disabled due to the game mode.");
}
/* Spawn player */
if (g.player == NULL) {
Expand All @@ -124,22 +125,51 @@ void new_game(void) {
logma(CYAN, "Welcome, Team %s! Let's rock!", g.userbuf);
}

/**
* @brief Parse the given arguments
*
* @param argc Number of arguments
* @param argv Argument array
*/
void parse_args(int argc, const char *argv[]) {
for (int i = 1; i < argc; i++) {
if (!strncmp(argv[i], "-X", 2)) {
g.explore = 1;
} else if (!strncmp(argv[i], "-D", 2)) {
static char doc[] = SHORT_DESC;
static struct argp_option options[] = {
{ "team", 't', "TEAMNAME", 0, "Set a default name for the player team.", 0},
{ "version", 'v', 0, 0, "Display version information.", 0},
{ "debug", 'd', 0, 0, "Activates debug mode. Debug mode enables debug commands and makes losing optional. Disables the high score list.", 0},
{ "practice", 'p', 0, 0, "Activates practice mode. Practice mode makes losing optional. Disables the high score list.", 0},
{0}
};

struct arguments
{
char *args[2];
char *team;
int debug, practice;
};
static struct argp argp = { options, parse_args, 0, doc, 0, 0, 0 };

error_t parse_args(int key, char *arg, struct argp_state *state) {
struct arguments *arguments = state->input;

switch (key) {
case 'd':
g.debug = 1;
} else if (!strncmp(argv[i], "-u", 2)) {
snprintf(g.userbuf, sizeof(g.userbuf), "%s", argv[i] + 2);
}
break;
case 'p':
g.practice = 1;
break;
case 'v':
printf("v%d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, RELEASE_TYPE);
exit(0);
break;
case 't':
snprintf(g.userbuf, sizeof(g.userbuf), "%s", arg);
break;
case ARGP_KEY_ARG:
if (state->arg_num >= 5)
argp_usage(state);
arguments->args[state->arg_num] = arg;
break;
default:
return ARGP_ERR_UNKNOWN;
exit(1);
break;
}
return 0;
}

/**
Expand All @@ -149,19 +179,27 @@ void parse_args(int argc, const char *argv[]) {
* @param argv Argument array
* @return int 0
*/
int main(int argc, const char *argv[]) {
int main(int argc, char **argv) {
struct actor *cur_actor;
char buf[MAX_USERSZ + 4] = { '\0' };

// Parse args
struct arguments arguments;
arguments.debug = 0;
arguments.practice = 0;
arguments.team = '\0';
argp_parse(&argp, argc, argv, 0, 0, &arguments);
if (g.userbuf[0] == '\0')
getlogin_r(g.userbuf, sizeof(g.userbuf));
if (g.userbuf[0] == ' ')
snprintf(g.userbuf, sizeof(g.userbuf), "Lion");
if (g.userbuf[0] > 'Z')
g.userbuf[0] = g.userbuf[0] - 32;

/* handle exits and resizes */
atexit(handle_exit);
signal(SIGWINCH, handle_sigwinch);
signal(SIGSEGV, handle_sigsegv);

// Parse args
parse_args(argc, argv);
if (g.userbuf[0] == '\0')
getlogin_r(g.userbuf, sizeof(g.userbuf));

/* Build savefile name */
snprintf(buf, sizeof(buf), "%s.sav", g.userbuf);
Expand Down
2 changes: 1 addition & 1 deletion vcpkg.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "zenzizenzizenzic",
"version": "1.0.0",
"description": "A traditional roguelike about fighting games.",
"description": "A roguelike about fighting games.",
"dependencies": [
"cjson",
"ncurses"
Expand Down

0 comments on commit ac4eb8d

Please sign in to comment.