Blob


1 /*
2 * Copyright (c) 2021 Matthias Schmidt <xhr@giessen.ccc.de>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include <sys/queue.h>
19 #include <errno.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #include <json-c/json.h>
26 #include <readline/readline.h>
27 #include <readline/history.h>
29 #include "isscrolls.h"
31 static struct character *curchar = NULL;
32 struct listhead *headp;
33 LIST_HEAD(listhead, entry) head = LIST_HEAD_INITIALIZER(head);
35 void
36 cmd_create_character(char *name)
37 {
38 struct entry *e;
39 struct character *c;
40 char p[MAX_PROMPT_LEN];
42 /* There is already a character loaded, so save and free it */
43 if (curchar != NULL) {
44 save_character();
45 free_character();
46 curchar = NULL;
47 }
49 if (character_exists(name) == 0) {
50 printf("Sorry, there is already a character named %s\n", name);
51 return;
52 }
54 log_debug("Attempt to create a character named %s\n", name);
55 if ((c = create_character(name)) != NULL) {
56 curchar = c;
57 print_character();
58 snprintf(p, sizeof(p), "%s > ", c->name);
59 set_prompt(p);
61 if ((e = malloc(sizeof(struct entry))) == NULL)
62 log_errx(1, "cannot allocate memory\n");
64 e->id = c->id;
65 snprintf(e->name, sizeof(e->name), "%s", c->name);
66 LIST_INSERT_HEAD(&head, e, entries);
67 }
68 }
70 void
71 cmd_ls(__attribute__((unused)) char *unused)
72 {
73 struct entry *np;
75 LIST_FOREACH(np, &head, entries) {
76 printf("%s\n", np->name);
77 }
78 }
80 void
81 cmd_delete_character(__attribute__((unused)) char *unused)
82 {
83 struct entry *np = NULL;
85 if (curchar == NULL) {
86 printf("No character loaded. Use 'cd' to load a character\n");
87 return;
88 }
90 /* Save list entry of the to be deleted char in np */
91 LIST_FOREACH(np, &head, entries) {
92 if (np->id == curchar->id)
93 break;
94 }
96 delete_saved_character(curchar->id);
98 free_character();
99 curchar = NULL;
101 if (np != NULL) {
102 LIST_REMOVE(np, entries);
103 free(np);
104 } else
105 log_debug("Found a list entry but cannot delete it\n");
107 set_prompt("> ");
110 void
111 cmd_cd(char *character)
113 int id = -1;
115 if (character == NULL)
116 return;
118 if (strlen(character) == 0 && curchar != NULL) {
119 /* We got no argument and there is a character loaded */
120 log_debug("Switch to ~ and save character %s\n", character);
121 set_prompt("> ");
122 save_character();
123 free_character();
124 curchar = NULL;
125 } else if (strlen(character) == 0 && curchar == NULL) {
126 /* We got no argument and there is no character loaded */
127 printf("Provide the name of a character as argument\n\n");
128 printf("Example: cd Delkash - load the character named Delkash\n");
129 return;
130 } else if (strlen(character) != 0 && curchar == NULL) {
131 /* We got an argument and there is no character loaded */
132 id = return_character_id(character);
133 if (id != -1) {
134 if (load_character(id) == -1) {
135 log_debug("No character object for %s with ID %d\n", character, id);
136 return;
138 } else
139 printf("No character named %s found.\n", character);
140 } else if (strlen(character) != 0 && curchar != NULL) {
141 /* We got an argument and there is a character loaded */
142 id = return_character_id(character);
143 if (id != -1) {
144 save_character();
145 free_character();
146 curchar = NULL;
148 if (load_character(id) == -1) {
149 log_debug("No character object for %s with ID %d\n", character, id);
150 return;
152 } else
153 printf("No character named %s found.\n", character);
157 void
158 cmd_increase_value(char *value)
160 change_char_value(value, INCREASE, 1);
163 void
164 cmd_decrease_value(char *value)
166 change_char_value(value, DECREASE, 1);
169 void
170 cmd_toogle(char *value)
172 if (curchar == NULL) {
173 printf("No character loaded. Use 'cd' to load a character\n");
174 return;
177 if (value == NULL || strlen(value) == 0) {
178 printf("Please specify the stat you want to toogle\n");
179 printf("\nExample: toggle wounded\n");
180 printf("\nYou can toggle the following values:\n\n");
181 printf("-Wounded\n-Unprepared\n-Shaken\n-Encumbered\n-Maimed\n-Cursed\n");
182 printf("-Corrupted\n-Tormented\n");
183 return;
186 if (strcasecmp(value, "wounded") == 0) {
187 toggle_value(value, &curchar->wounded);
188 } else if (strcasecmp(value, "unprepared") == 0) {
189 toggle_value(value, &curchar->unprepared);
190 } else if (strcasecmp(value, "shaken") == 0) {
191 toggle_value(value, &curchar->shaken);
192 } else if (strcasecmp(value, "encumbered") == 0) {
193 toggle_value(value, &curchar->encumbered);
194 } else if (strcasecmp(value, "maimed") == 0) {
195 if (curchar->maimed == 1) {
196 printf("Maimed is a permanent bane and cannot be changed\n");
197 return;
199 toggle_value(value, &curchar->maimed);
200 } else if (strcasecmp(value, "cursed") == 0) {
201 toggle_value(value, &curchar->cursed);
202 } else if (strcasecmp(value, "corrupted") == 0) {
203 if (curchar->corrupted == 1) {
204 printf("Corrupted is a permanent bane and cannot be changed\n");
205 return;
207 toggle_value(value, &curchar->corrupted);
208 } else if (strcasecmp(value, "tormented") == 0) {
209 toggle_value(value, &curchar->tormented);
212 set_max_momentum();
216 void
217 update_prompt()
219 char p[MAX_PROMPT_LEN];
220 char j[MAX_PROMPT_LEN];
221 char f[MAX_PROMPT_LEN];
222 char i[5];
224 if (curchar == NULL) {
225 printf("No character loaded. Use 'cd' to load a character\n");
226 return;
229 memset(j, 0, sizeof(j));
230 memset(f, 0, sizeof(f));
231 memset(i, 0, sizeof(i));
233 if (curchar->journey_active == 1) {
234 if (curchar->j->difficulty < 4)
235 snprintf(j, sizeof(j), "Journey %.0f/10 > ",
236 curchar->j->progress);
237 else
238 snprintf(j, sizeof(j), "Journey %.2f/10 > ",
239 curchar->j->progress);
242 if (curchar->fight_active == 1) {
243 if (curchar->fight->initiative == 1)
244 snprintf(i, 5, "%s", " [I]");
246 if (curchar->fight->difficulty < 4)
247 snprintf(f, sizeof(f), "Fight %.0f/10%s > ",
248 curchar->fight->progress, i);
249 else
250 snprintf(f, sizeof(f), "Fight %.2f/10%s > ",
251 curchar->fight->progress, i);
254 snprintf(p, sizeof(p), "%s > %s%s", curchar->name, j, f);
256 set_prompt(p);
259 void
260 toggle_value(const char *desc, int *value)
262 int new = !(*value);
264 if (curchar == NULL) {
265 printf("No character loaded. Use 'cd' to load a character\n");
266 return;
269 printf("Toggle %s from %d to %d\n", desc, *value, new);
270 *value = new;
273 void
274 set_max_momentum()
276 int mm;
278 if (curchar == NULL)
279 return;
281 /* Max momentum is 10 minus all the debilities */
282 mm = 10 - curchar->wounded - curchar->unprepared - curchar->shaken -
283 curchar->encumbered - curchar->maimed -
284 curchar->cursed - curchar->corrupted - curchar->tormented;
286 if (mm != curchar->max_momentum) {
287 printf("Your max momentum changed from %d to %d\n",
288 curchar->max_momentum, mm);
289 curchar->max_momentum = mm;
292 /* Reset momentum is +2 and reduced by 1 for each debility. It cannot fall
293 * lower than 0
294 */
295 mm = 2 - curchar->wounded - curchar->unprepared - curchar->shaken -
296 curchar->encumbered - curchar->maimed -
297 curchar->cursed - curchar->corrupted - curchar->tormented;
299 if (mm < 0)
300 mm = 0;
301 if (mm != curchar->momentum_reset) {
302 printf("Your reset momentum changed from %d to %d\n",
303 curchar->momentum_reset, mm);
304 curchar->momentum_reset = mm;
309 void
310 change_char_value(const char *value, int what, int howmany)
312 const char *event[2] = { "increase", "decrease" };
314 if (curchar == NULL) {
315 printf("No character loaded. Use 'cd' to load a character\n");
316 return;
319 if (value == NULL || strlen(value) == 0) {
320 printf("Please specify the stat you want to %s\n", event[what]);
321 printf("\nExample: %s wits\t- %s 'wits' by 1\n", event[what], event[what]);
322 printf("\nYou can change the following values:\n\n");
323 printf("-Edge\n-Heart\n-Iron\n-Shadow\n-Wits\n-Momentum\n-Health\n-Spirit\n");
324 printf("-Supply\n-Exp\n");
325 return;
328 if (strcasecmp(value, "edge") == 0) {
329 modify_value(value, &curchar->edge, 4, 0, howmany, what);
330 return;
331 } else if (strcasecmp(value, "heart") == 0) {
332 modify_value(value, &curchar->heart, 4, 0, howmany, what);
333 return;
334 } else if (strcasecmp(value, "iron") == 0) {
335 modify_value(value, &curchar->iron, 4, 0, howmany, what);
336 return;
337 } else if (strcasecmp(value, "shadow") == 0) {
338 modify_value(value, &curchar->shadow, 4, 0, howmany, what);
339 return;
340 } else if (strcasecmp(value, "wits") == 0) {
341 modify_value(value, &curchar->wits, 4, 0, howmany, what);
342 return;
343 } else if (strcasecmp(value, "exp") == 0) {
344 modify_value(value, &curchar->exp, 30, 0, howmany, what);
345 return;
346 } else if (strcasecmp(value, "momentum") == 0) {
347 modify_value(value, &curchar->momentum, curchar->max_momentum, -6,
348 howmany, what);
349 return;
350 } else if (strcasecmp(value, "health") == 0) {
351 if (curchar->wounded == 1) {
352 printf("You are wounded, you cannot increase health\n");
353 return;
355 modify_value(value, &curchar->health, 5, 0, howmany, what);
356 return;
357 } else if (strcasecmp(value, "spirit") == 0) {
358 if (curchar->shaken == 1) {
359 printf("You are shaken, you cannot increase spirit\n");
360 return;
362 modify_value(value, &curchar->spirit, 5, 0, howmany, what);
363 return;
364 } else if (strcasecmp(value, "supply") == 0) {
365 if (curchar->unprepared == 1) {
366 printf("You are unprepared, you cannot increase supply\n");
367 return;
369 modify_value(value, &curchar->supply, 5, 0, howmany, what);
370 return;
371 } else {
372 printf("Unknown value\n");
373 return;
378 void
379 modify_value(const char *str, int *value, int max, int min, int howmany,
380 int what)
382 if (what == 0) {
383 if (*value >= max) {
384 return;
386 *value += howmany;
387 printf("Increasing %s from %d to %d\n", str, *value - howmany, *value);
388 } else {
389 if (*value <= min) {
390 return;
392 *value -= howmany;
393 printf("Decreasing %s from %d to %d\n", str, *value + howmany, *value);
397 int
398 return_character_id(const char *name)
400 struct entry *np;
401 int id = -1;
403 LIST_FOREACH(np, &head, entries) {
404 if (strcasecmp(np->name, name) == 0) {
405 id = np->id;
409 return id;
412 void
413 save_current_character()
415 save_character();
418 void
419 save_character()
421 char path[_POSIX_PATH_MAX];
422 json_object *root, *items;
423 int temp_n, i;
425 if (curchar == NULL) {
426 log_debug("Nothing to save here\n");
427 return;
430 save_journey();
431 save_fight();
433 json_object *cobj = json_object_new_object();
434 json_object_object_add(cobj, "name", json_object_new_string(curchar->name));
435 json_object_object_add(cobj, "id", json_object_new_int(curchar->id));
436 json_object_object_add(cobj, "edge", json_object_new_int(curchar->edge));
437 json_object_object_add(cobj, "heart", json_object_new_int(curchar->heart));
438 json_object_object_add(cobj, "iron", json_object_new_int(curchar->iron));
439 json_object_object_add(cobj, "shadow", json_object_new_int(curchar->shadow));
440 json_object_object_add(cobj, "wits", json_object_new_int(curchar->wits));
441 json_object_object_add(cobj, "exp", json_object_new_int(curchar->exp));
442 json_object_object_add(cobj, "momentum",
443 json_object_new_int(curchar->momentum));
444 json_object_object_add(cobj, "max_momentum",
445 json_object_new_int(curchar->max_momentum));
446 json_object_object_add(cobj, "momentum_reset",
447 json_object_new_int(curchar->momentum_reset));
448 json_object_object_add(cobj, "health", json_object_new_int(curchar->health));
449 json_object_object_add(cobj, "spirit", json_object_new_int(curchar->spirit));
450 json_object_object_add(cobj, "supply", json_object_new_int(curchar->supply));
451 json_object_object_add(cobj, "wounded",
452 json_object_new_int(curchar->wounded));
453 json_object_object_add(cobj, "unprepared",
454 json_object_new_int(curchar->unprepared));
455 json_object_object_add(cobj, "shaken",
456 json_object_new_int(curchar->shaken));
457 json_object_object_add(cobj, "encumbered",
458 json_object_new_int(curchar->encumbered));
459 json_object_object_add(cobj, "maimed", json_object_new_int(curchar->maimed));
460 json_object_object_add(cobj, "cursed", json_object_new_int(curchar->cursed));
461 json_object_object_add(cobj, "dead", json_object_new_int(curchar->dead));
462 json_object_object_add(cobj, "corrupted",
463 json_object_new_int(curchar->corrupted));
464 json_object_object_add(cobj, "tormented",
465 json_object_new_int(curchar->tormented));
466 json_object_object_add(cobj, "exp_used",
467 json_object_new_int(curchar->exp_used));
468 json_object_object_add(cobj, "bonds",
469 json_object_new_double(curchar->bonds));
470 json_object_object_add(cobj, "journey_active",
471 json_object_new_int(curchar->journey_active));
472 json_object_object_add(cobj, "fight_active",
473 json_object_new_int(curchar->fight_active));
475 snprintf(path, sizeof(path), "%s/characters.json", get_isscrolls_dir());
476 if ((root = json_object_from_file(path)) == NULL) {
477 log_debug("No character JSON file found\n");
478 root = json_object_new_object();
479 if (!root)
480 log_errx(1, "Cannot create JSON object\n");
482 items = json_object_new_array();
483 json_object_array_add(items, cobj);
484 json_object_object_add(root, "characters", items);
485 } else {
486 /* Get existing character array from JSON */
487 if (!json_object_object_get_ex(root, "characters", &items)) {
488 log_debug("Cannot find a [characters] array in %s\n", path);
489 items = json_object_new_array();
490 json_object_object_add(root, "characters", items);
493 temp_n = json_object_array_length(items);
494 for (i = 0; i < temp_n; i++) {
495 json_object *temp = json_object_array_get_idx(items, i);
496 json_object *id;
497 json_object_object_get_ex(temp, "id", &id);
498 if (curchar->id == json_object_get_int(id)) {
499 log_debug("Update character entry for %s\n", curchar->name);
500 json_object_array_del_idx(items, i, 1);
501 json_object_array_add(items, cobj);
502 goto out;
505 log_debug("No entry for %s found, adding new one\n", curchar->name);
506 json_object_array_add(items, cobj);
509 out:
510 if (json_object_to_file(path, root))
511 printf("Error saving %s\n", path);
512 else
513 log_debug("Successfully saved %s\n", path);
515 json_object_put(root);
518 void
519 delete_saved_character(int id)
521 char path[_POSIX_PATH_MAX];
522 json_object *root, *lid;
523 int temp_n, i;
525 LIST_INIT(&head);
527 snprintf(path, sizeof(path), "%s/characters.json", get_isscrolls_dir());
528 if ((root = json_object_from_file(path)) == NULL) {
529 log_debug("No character JSON file found\n");
530 return;
533 json_object *characters;
534 if (!json_object_object_get_ex(root, "characters", &characters)) {
535 log_debug("Cannot find a [characters] array in %s\n", path);
536 return;
539 temp_n = json_object_array_length(characters);
540 for (i = 0; i < temp_n; i++) {
541 json_object *temp = json_object_array_get_idx(characters, i);
542 json_object_object_get_ex(temp, "id", &lid);
543 if (id == json_object_get_int(lid)) {
544 json_object_array_del_idx(characters, i, 1);
545 log_debug("Deleted character entry for %d\n", id);
549 if (json_object_to_file(path, root))
550 printf("Error saving %s\n", path);
551 else
552 log_debug("Successfully saved %s\n", path);
554 json_object_put(root);
557 void
558 load_characters_list()
560 struct entry *e;
561 char path[_POSIX_PATH_MAX];
562 json_object *root;
563 json_object *lid, *name;
564 int temp_n, i;
566 LIST_INIT(&head);
568 snprintf(path, sizeof(path), "%s/characters.json", get_isscrolls_dir());
569 if ((root = json_object_from_file(path)) == NULL) {
570 log_debug("No character JSON file found\n");
571 return;
574 json_object *characters;
575 if (!json_object_object_get_ex(root, "characters", &characters)) {
576 log_debug("Cannot find a [characters] array in %s\n", path);
577 return;
579 temp_n = json_object_array_length(characters);
580 for (i=0; i < temp_n; i++) {
581 json_object *temp = json_object_array_get_idx(characters, i);
582 json_object_object_get_ex(temp, "id", &lid);
583 json_object_object_get_ex(temp, "name", &name);
584 log_debug("Add %s to list with id: %d\n", json_object_get_string(name), json_object_get_int(lid));
586 if ((e = malloc(sizeof(struct entry))) == NULL)
587 log_errx(1, "cannot allocate memory\n");
589 e->id = json_object_get_int(lid);
590 snprintf(e->name, sizeof(e->name), "%s", json_object_get_string(name));
591 LIST_INSERT_HEAD(&head, e, entries);
594 json_object_put(root);
597 int
598 load_character(int id)
600 struct character *c;
601 char path[_POSIX_PATH_MAX];
602 json_object *root, *lid, *name;
603 int temp_n, i;
605 if (id <= 0)
606 return -1;
608 snprintf(path, sizeof(path), "%s/characters.json", get_isscrolls_dir());
609 if ((root = json_object_from_file(path)) == NULL) {
610 log_debug("No character JSON file found\n");
611 return -1;
614 if ((c = calloc(1, sizeof(struct character))) == NULL)
615 log_errx(1, "calloc");
617 if ((c->name = calloc(1, MAX_CHAR_LEN)) == NULL)
618 log_errx(1, "calloc");
620 if ((c->j = calloc(1, sizeof(struct journey))) == NULL)
621 log_errx(1, "calloc");
623 if ((c->fight = calloc(1, sizeof(struct fight))) == NULL)
624 log_errx(1, "calloc");
626 json_object *characters;
627 if (!json_object_object_get_ex(root, "characters", &characters)) {
628 log_debug("Cannot find a [characters] array in %s\n", path);
629 return -1;
632 temp_n = json_object_array_length(characters);
633 for (i=0; i < temp_n; i++) {
634 json_object *temp = json_object_array_get_idx(characters, i);
635 json_object_object_get_ex(temp, "id", &lid);
636 if (id == json_object_get_int(lid)) {
637 json_object_object_get_ex(temp, "name", &name);
639 log_debug("Loading character %s, id: %d\n", json_object_get_string(name),
640 json_object_get_int(lid));
642 snprintf(c->name, MAX_CHAR_LEN, "%s", json_object_get_string(name));
643 c->id = id;
644 json_object *cval;
645 json_object_object_get_ex(temp, "edge", &cval);
646 c->edge = json_object_get_int(cval);
647 json_object_object_get_ex(temp, "heart", &cval);
648 c->heart = json_object_get_int(cval);
649 json_object_object_get_ex(temp, "iron", &cval);
650 c->iron = json_object_get_int(cval);
651 json_object_object_get_ex(temp, "shadow", &cval);
652 c->shadow = json_object_get_int(cval);
653 json_object_object_get_ex(temp, "wits", &cval);
654 c->wits = json_object_get_int(cval);
655 json_object_object_get_ex(temp, "exp", &cval);
656 c->exp = json_object_get_int(cval);
657 json_object_object_get_ex(temp, "health", &cval);
658 c->health = json_object_get_int(cval);
659 json_object_object_get_ex(temp, "spirit", &cval);
660 c->spirit = json_object_get_int(cval);
661 json_object_object_get_ex(temp, "supply", &cval);
662 c->supply = json_object_get_int(cval);
663 json_object_object_get_ex(temp, "wounded", &cval);
664 c->wounded = json_object_get_int(cval);
665 json_object_object_get_ex(temp, "shaken", &cval);
666 c->shaken = json_object_get_int(cval);
667 json_object_object_get_ex(temp, "maimed", &cval);
668 c->maimed = json_object_get_int(cval);
669 json_object_object_get_ex(temp, "cursed", &cval);
670 c->cursed = json_object_get_int(cval);
671 json_object_object_get_ex(temp, "dead", &cval);
672 c->dead = json_object_get_int(cval);
673 json_object_object_get_ex(temp, "bonds", &cval);
674 c->bonds = json_object_get_double(cval);
675 json_object_object_get_ex(temp, "corrupted", &cval);
676 c->corrupted = json_object_get_int(cval);
677 json_object_object_get_ex(temp, "tormented", &cval);
678 c->tormented = json_object_get_int(cval);
679 json_object_object_get_ex(temp, "exp_used", &cval);
680 c->exp_used = json_object_get_int(cval);
681 json_object_object_get_ex(temp, "unprepared", &cval);
682 c->unprepared= json_object_get_int(cval);
683 json_object_object_get_ex(temp, "momentum", &cval);
684 c->momentum = json_object_get_int(cval);
685 json_object_object_get_ex(temp, "encumbered", &cval);
686 c->encumbered = json_object_get_int(cval);
687 json_object_object_get_ex(temp, "max_momentum", &cval);
688 c->max_momentum = json_object_get_int(cval);
689 json_object_object_get_ex(temp, "momentum_reset", &cval);
690 c->momentum_reset = json_object_get_int(cval);
691 json_object_object_get_ex(temp, "journey_active", &cval);
692 c->journey_active = json_object_get_int(cval);
693 json_object_object_get_ex(temp, "fight_active", &cval);
694 c->fight_active = json_object_get_int(cval);
698 curchar = c;
700 load_journey(c->id);
701 load_fight(c->id);
702 update_prompt();
703 print_character();
705 json_object_put(root);
707 return 0;
710 void
711 cmd_print_current_character(__attribute__((unused)) char *unused)
713 if (curchar == NULL) {
714 printf("No character loaded. Use 'cd' to load a character\n");
715 } else
716 print_character();
719 void
720 print_character()
722 if (curchar == NULL) {
723 log_debug("Nothing to print here\n");
724 return;
727 log_debug("Character ID: %d\n", curchar->id);
728 printf("Name: %s (Exp: %d/30) Saved exp: %d ", curchar->name,
729 curchar->exp, curchar->exp_used);
730 if (curchar->dead == 1)
731 printf("[DECEASED]\n");
732 else
733 printf("\n");
735 printf("\nEdge: %d Heart: %d Iron: %d Shadow: %d Wits %d\n\n",
736 curchar->edge, curchar->heart, curchar->iron, curchar->shadow, curchar->wits);
737 printf("Momentum: %d/%d [%d] Health: %d/5 Spirit: %d/5 Supply: %d/5\n",
738 curchar->momentum, curchar-> max_momentum, curchar->momentum_reset,
739 curchar->health, curchar->spirit, curchar->supply);
741 printf("\nWounded:\t%d Unprepared:\t%d Encumbered:\t%d Shaken:\t%d\n",
742 curchar->wounded, curchar->unprepared, curchar->encumbered, curchar->shaken);
743 printf("Corrupted:\t%d Tormented:\t%d Corrupted:\t%d Maimed:\t%d\n",
744 curchar->corrupted, curchar->tormented, curchar->corrupted, curchar->maimed);
746 printf("\nBonds: %.2f\n", curchar->bonds);
748 if (curchar->journey_active == 1) {
749 printf("\nActive Journey: Difficulty: %d Progress: %.2f/10\n",
750 curchar->j->difficulty, curchar->j->progress);
752 if (curchar->fight_active == 1) {
753 printf("\nActive Fight: Difficulty: %d Progress: %.2f/10\n",
754 curchar->fight->difficulty, curchar->fight->progress);
758 void
759 ask_for_journey_difficulty()
761 if (curchar == NULL) {
762 log_debug("No character loaded\n");
763 return;
766 printf("Please set a difficulty for your journey\n\n");
767 printf("1\t - Troublesome journey (3 progress per waypoint)\n");
768 printf("2\t - Dangerous journey (2 progress per waypoint)\n");
769 printf("3\t - Formidable journey (2 progress per waypoint)\n");
770 printf("4\t - Extreme journey (2 ticks per waypoint)\n");
771 printf("5\t - Epic journey (1 tick per waypoint)\n\n");
773 curchar->j->difficulty = ask_for_value("Enter a value between 1 and 5: ", 5);
776 int
777 validate_range(int temp, int max)
779 if (temp < 1 || temp > max) {
780 printf("Invalid range. The value has to be between 1 and %d\n", max);
781 return -1;
784 return 0;
787 void
788 free_character()
790 if (curchar == NULL) {
791 log_debug("No character loaded\n");
792 return;
795 if (curchar->name != NULL) {
796 free(curchar->name);
797 curchar->name = NULL;
799 if (curchar->j != NULL) {
800 free(curchar->j);
801 curchar->j = NULL;
803 if (curchar->fight != NULL) {
804 free(curchar->fight);
805 curchar->fight = NULL;
807 if (curchar != NULL) {
808 free(curchar);
809 curchar = NULL;
813 int
814 ask_for_value(const char *attribute, int max)
816 char *line;
817 int temp = -1;
819 again:
820 line = readline(attribute);
821 temp = atoi(line);
822 if (validate_range(temp, max) == -1) {
823 goto again;
826 free(line);
827 return temp;
830 int
831 character_exists(const char *name)
833 struct entry *np;
835 if (strlen(name) == 0)
836 return -1;
838 LIST_FOREACH(np, &head, entries) {
839 if (strcasecmp(name, np->name) == 0) {
840 return 0;
844 return -1;
847 struct character *
848 create_character(const char *name)
850 struct character *c;
852 c = init_character_struct();
854 if (strlen(name) == 0) {
855 printf("Enter a name for your character: ");
856 c->name = readline(NULL);
857 if (strlen(c->name) == 0) {
858 printf("Please provide a longer name\n");
859 free_character();
860 return NULL;
862 if (character_exists(c->name) == 0) {
863 printf("Sorry, there is already a character named %s\n", c->name);
864 free_character();
865 return NULL;
867 } else {
868 if ((c->name = calloc(1, MAX_CHAR_LEN)) == NULL)
869 log_errx(1, "calloc");
870 snprintf(c->name, MAX_CHAR_LEN, "%s", name);
871 printf("Creating a character named %s\n", c->name);
874 printf("Now distribute the following values to your attributes: 3,2,2,1,1\n");
876 c->edge = ask_for_value("Edge : ", 4);
877 c->heart = ask_for_value("Heart : ", 4);
878 c->iron = ask_for_value("Iron : ", 4);
879 c->wits = ask_for_value("Wits : ", 4);
880 c->shadow = ask_for_value("Shadow : ", 4);
882 return c;
885 struct character *
886 init_character_struct()
888 struct character *c;
890 if ((c = calloc(1, sizeof(struct character))) == NULL)
891 log_errx(1, "calloc");
893 if ((c->j = calloc(1, sizeof(struct journey))) == NULL)
894 log_errx(1, "calloc");
896 if ((c->fight = calloc(1, sizeof(struct fight))) == NULL)
897 log_errx(1, "calloc");
899 c->id = random();
900 c->name = NULL;
901 c->edge = c->heart = c->iron = c->shadow = c->wits = c->exp = 0;
902 c->momentum = c->momentum_reset = 2;
903 c->max_momentum = 10;
904 c->health = c->spirit = c->supply = 5;
905 c->wounded = c->unprepared = c->shaken = c->encumbered = c->maimed = 0;
906 c->cursed = c->corrupted = c->tormented = c->exp_used = c->bonds = 0;
907 c->dead = 0;
909 c->j->id = c->id;
910 c->j->difficulty = -1;
911 c->j->progress = 0.0;
912 c->journey_active = 0;
914 c->fight->id = c->id;
915 c->fight->difficulty = -1;
916 c->fight->progress = 0.0;
917 c->fight->initiative = 0;
918 c->fight_active = 0;
920 return c;
923 struct character *
924 get_current_character()
926 return curchar;