2 * Copyright (c) 2021 Matthias Schmidt <xhr@giessen.ccc.de>
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.
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.
24 #include "isscrolls.h"
28 static const char *odds[] = {
38 cmd_gather_information(char *cmd)
40 struct character *curchar = get_current_character();
41 int ival[2] = { -1, -1 };
44 if (curchar == NULL) {
45 printf("No character loaded. Use 'cd' to load a character\n");
49 ival[0] = curchar->wits;
50 ival[1] = get_int_from_cmd(cmd);
52 ret = action_roll(ival);
53 if (ret == 8) { /* strong hit */
54 change_char_value("momentum", INCREASE, 2);
55 } else if (ret == 4) { /* weak hit */
56 change_char_value("momentum", INCREASE, 1);
58 printf("Pay the price -> Rulebook\n");
62 cmd_sojourn(char *cmd)
64 struct character *curchar = get_current_character();
65 int ival[2] = { -1, -1 };
68 if (curchar == NULL) {
69 printf("No character loaded. Use 'cd' to load a character\n");
73 ival[0] = curchar->heart;
74 ival[1] = get_int_from_cmd(cmd);
76 ret = action_roll(ival);
77 if (ret == 8) { /* strong hit */
78 printf("You may choose two optionsresults -> Rulebook\n");
79 } else if (ret == 4) { /* weak hit */
80 printf("You may choose one result -> Rulebook\n");
82 printf("Pay the price -> Rulebook\n");
86 cmd_draw_the_circle(char *cmd)
88 struct character *curchar = get_current_character();
89 int ival[2] = { -1, -1 };
92 if (curchar == NULL) {
93 printf("No character loaded. Use 'cd' to load a character\n");
97 ival[0] = curchar->heart;
98 ival[1] = get_int_from_cmd(cmd);
100 ret = action_roll(ival);
102 change_char_value("momentum", INCREASE, 1);
103 printf("You may choose even more boasts -> Rulebook\n");
104 } else if (ret == 4) {
105 printf("You may choose one boasts -> Rulebook\n");
107 printf("Pay the price -> Rulebook\n");
111 cmd_swear_an_iron_vow(char *cmd)
113 struct character *curchar = get_current_character();
114 int ival[2] = { -1, -1 };
117 if (curchar == NULL) {
118 printf("No character loaded. Use 'cd' to load a character\n");
122 ival[0] = curchar->heart;
123 ival[1] = get_int_from_cmd(cmd);
125 ret = action_roll(ival);
127 change_char_value("momentum", INCREASE, 2);
128 printf("You are emboldened and know what you must do next\n");
129 } else if (ret == 4) {
130 change_char_value("momentum", INCREASE, 1);
131 printf("You are determined but begin your quest with questions\n");
133 printf("You face a significant obstacle -> Rulebook\n");
137 cmd_forge_a_bond(char *cmd)
139 struct character *curchar = get_current_character();
140 int ival[2] = { -1, -1 };
143 if (curchar == NULL) {
144 printf("No character loaded. Use 'cd' to load a character\n");
148 ival[0] = curchar->heart;
149 ival[1] = get_int_from_cmd(cmd);
151 ret = action_roll(ival);
153 printf("You forge a bind and choose one option -> Rulebook\n");
154 curchar->bonds += 0.25;
155 } else if (ret == 4) {
156 printf("They ask something from you first -> Rulebook\n");
158 printf("You are refused. Pay the price -> Rulebook\n");
162 cmd_test_your_bond(char *cmd)
164 struct character *curchar = get_current_character();
165 int ival[2] = { -1, -1 };
168 if (curchar == NULL) {
169 printf("No character loaded. Use 'cd' to load a character\n");
173 if (curchar->bonds == 0) {
174 printf("You have no bonds forged. Please do so first\n");
178 ival[0] = curchar->heart;
179 ival[1] = get_int_from_cmd(cmd);
181 ret = action_roll(ival);
183 printf("You may choose one boost -> Rulebook\n");
184 } else if (ret == 4) {
185 printf("Your bond is fragile -> Rulebook\n");
187 printf("Your bond is cleared. Pay the price -> Rulebook\n");
188 curchar->bonds -= 0.25;
193 cmd_endure_stress(char *cmd)
195 struct character *curchar = get_current_character();
196 int ival[2] = { -1, -1 };
199 if (curchar == NULL) {
200 printf("No character loaded. Use 'cd' to load a character\n");
204 ival[1] = get_int_from_cmd(cmd);
206 printf("Please provide a number as argument\n\n");
207 printf("The number is the amount of stress you suffer\n");
208 printf("Example: endurestress 2\n");
212 hr = curchar->spirit - ival[1];
214 curchar->spirit -= ival[1];
215 printf("You suffer -%d spirit and it is down to %d\n",
216 ival[1], curchar->spirit);
218 /* Spirit is 0, so suffer -momentum equal to remaining health */
219 log_debug("hr < 0: %d\n", hr);
221 curchar->momentum -= (hr * (-1));
222 printf("You suffer -%d spirt and since your spirit is 0, your "\
223 "momentum is down to %d\n", ival[1], curchar->momentum);
226 /* Reset ival[1] since we need no bonus for the roll */
228 ival[0] = curchar->heart;
229 if (curchar->spirit > curchar->heart) {
230 ival[0] = curchar->spirit;
233 ret = action_roll(ival);
235 printf("You need to choose one option -> Rulebook\n");
236 } else if (ret == 4) {
237 printf("You press on\n");
239 change_char_value("momentum", DECREASE, 1);
240 if (curchar->health == 0)
241 printf("Mark either shaken or corrupted or roll on the oracle table -> Rulebook\n");
246 cmd_face_death(char *cmd)
248 struct character *curchar = get_current_character();
249 int ival[2] = { -1, -1 };
252 if (curchar == NULL) {
253 printf("No character loaded. Use 'cd' to load a character\n");
257 ival[0] = curchar->heart;
258 ival[1] = get_int_from_cmd(cmd);
260 ret = action_roll(ival);
262 printf("Death rejects you.\n");
263 } else if (ret == 4) {
264 printf("Your must choose one option -> Rulebook\n");
266 printf("You are dead\n");
274 struct character *curchar = get_current_character();
275 int ival[2] = { -1, -1 };
278 if (curchar == NULL) {
279 printf("No character loaded. Use 'cd' to load a character\n");
283 if (strlen(who) == 0) {
285 printf("Please specify who to heal\n\n");
286 printf("me\t- heal yourself (roll against Iron or Wits (whatever is lower))\n");
287 printf("others\t- heal others (roll against Wits)\n\n");
288 printf("Example: heal me\n");
292 if (strcasecmp(who, "me") == 0) {
293 if (curchar->iron < curchar->wits)
294 ival[0] = curchar->iron;
295 else if (curchar->iron > curchar->wits)
296 ival[0] = curchar->wits;
298 ival[0] = curchar->wits;
299 } else if (strcasecmp(who, "others") == 0) {
300 ival[0] = curchar->wits;
304 ret = action_roll(ival);
305 if (ret == 8) { /* strong hit */
306 change_char_value("health", INCREASE, 2);
307 } else if (ret == 4) { /* weak hit */
308 change_char_value("health", INCREASE, 1);
309 change_char_value("momentum", DECREASE, 1);
311 printf("Pay the price -> Rulebook\n");
315 cmd_roll_action_dice(char *cmd)
318 char *tokens[MAXTOKENS];
322 int ival[2] = { -1, -1 };
324 if (cmd == NULL || strlen(cmd) == 0) {
325 printf("Please provide at least one attribute value\n\n");
326 printf("> action <attribute value> [bonus value]\n\n");
327 printf("Examples:\n");
328 printf("> action 3\t- Add 3 to the D6 die\n");
329 printf("> action 4 1\t- Add 4 and additionally 1 to the D6 die\n\n");
334 log_debug("cmd: %s\n", cmd);
336 /* Parse the argument line into 2 tokens, separated by space */
337 for ((p = strtok_r(cmd, " ", &last)); p;
338 (p = strtok_r(NULL, " ", &last))) {
339 if (i < MAXTOKENS - 1)
344 for (i=0; tokens[i] != NULL; i++) {
345 log_debug("token %d: %s\n", i, tokens[i]);
348 lval[i] = strtol(tokens[i], &ep, 10);
349 if (cmd[0] == '\0' || *ep != '\0') {
350 printf("Please provide a number as argument\n");
353 if ((errno == ERANGE || lval[i] <= 0 || lval[i] > 10)) {
354 printf("Please provide a number between 1 and 10\n");
364 cmd_resupply(char *cmd)
366 struct character *curchar = get_current_character();
367 int ival[2] = { -1, -1 };
370 if (curchar == NULL) {
371 printf("No character loaded. Use 'cd' to load a character\n");
375 ival[0] = curchar->wits;
376 ival[1] = get_int_from_cmd(cmd);
378 ret = action_roll(ival);
379 if (ret == 8) { /* strong hit */
380 change_char_value("momentum", INCREASE, 2);
381 } else if (ret == 4) { /* weak hit */
382 printf("Take up to +2 supply, but suffer -1 momentum for each\n");
384 printf("Pay the price -> Rulebook\n");
389 cmd_make_camp(char *cmd)
391 struct character *curchar = get_current_character();
392 int ival[2] = { -1, -1 };
395 if (curchar == NULL) {
396 printf("No character loaded. Use 'cd' to load a character\n");
400 ival[0] = curchar->supply;
401 ival[1] = get_int_from_cmd(cmd);
403 ret = action_roll(ival);
405 printf("Choose two options-> Rulebook\n");
407 printf("Choose one option-> Rulebook\n");
409 printf("Pay the price -> Rulebook\n");
413 cmd_face_danger(char *stat)
415 struct character *curchar = get_current_character();
416 int ival[2] = { -1, -1 };
419 if (curchar == NULL) {
420 printf("No character loaded. Use 'cd' to load a character\n");
424 if (strlen(stat) == 0) {
426 printf("Please specify the stat you'd like to use in this move\n\n");
427 printf("edge\t- Act with speed, agility, or precision\n");
428 printf("heart\t- Act with charm, loyalty, or courage\n");
429 printf("iron\t- Act with aggressive action, forceful defense, strength\n");
430 printf("shadow\t- Act with deception, stealth, or trickery\n");
431 printf("wits\t- Act with expertise, insight, or observation\n\n");
432 printf("Example: facedanger iron\n");
436 if (strcasecmp(stat, "iron") == 0) {
437 ival[0] = curchar->iron;
438 } else if (strcasecmp(stat, "wits") == 0) {
439 ival[0] = curchar->wits;
440 } else if (strcasecmp(stat, "edge") == 0) {
441 ival[0] = curchar->edge;
442 } else if (strcasecmp(stat, "shadow") == 0) {
443 ival[0] = curchar->shadow;
444 } else if (strcasecmp(stat, "heart") == 0) {
445 ival[0] = curchar->heart;
449 ret = action_roll(ival);
450 if (ret == 8) /* strong hit */
451 change_char_value("momentum", INCREASE, 1);
452 else if (ret == 4) /* weak hit */
453 printf("Face a troublesome cost -> Rulebook\n");
455 printf("Pay the price -> Rulebook\n");
459 cmd_compel(char *cmd)
461 struct character *curchar = get_current_character();
462 char stat[MAX_STAT_LEN];
463 int ival[2] = { -1, -1 };
466 if (curchar == NULL) {
467 printf("No character loaded. Use 'cd' to load a character\n");
471 ret = get_args_from_cmd(cmd, stat, &ival[1]);
474 printf("Please specify the stat you'd like to use in this move\n\n");
475 printf("heart\t- You charm, pacify, barter, or convince\n");
476 printf("iron\t- You threaten or incite\n");
477 printf("shadow\t- You lie or swindle\n");
478 printf("Example: compel iron\n");
480 } else if (ret <= -20)
483 if (strcasecmp(stat, "iron") == 0) {
484 ival[0] = curchar->iron;
485 } else if (strcasecmp(stat, "shadow") == 0) {
486 ival[0] = curchar->shadow;
487 } else if (strcasecmp(stat, "heart") == 0) {
488 ival[0] = curchar->heart;
492 ret = action_roll(ival);
494 change_char_value("momentum", INCREASE, 1);
495 printf("You might get +1 for your next move -> Rulebook\n");
496 } else if (ret == 4) {
497 change_char_value("momentum", INCREASE, 1);
498 printf("You might be asked for something in return -> Rulebook\n");
500 printf("Pay the price -> Rulebook\n");
504 cmd_secure_an_advantage(char *cmd)
506 struct character *curchar = get_current_character();
507 char stat[MAX_STAT_LEN];
508 int ival[2] = { -1, -1 };
511 if (curchar == NULL) {
512 printf("No character loaded. Use 'cd' to load a character\n");
516 ret = get_args_from_cmd(cmd, stat, &ival[1]);
519 printf("Please specify the stat you'd like to use in this move\n\n");
520 printf("edge\t- Act with speed, agility, or precision\n");
521 printf("heart\t- Act with charm, loyalty, or courage\n");
522 printf("iron\t- Act with aggressive action, forceful defense, strength\n");
523 printf("shadow\t- Act with deception, stealth, or trickery\n");
524 printf("wits\t- Act with expertise, insight, or observation\n\n");
525 printf("Example: secureanadvantage iron\n");
527 } else if (ret <= -20)
530 if (strcasecmp(stat, "iron") == 0) {
531 ival[0] = curchar->iron;
532 } else if (strcasecmp(stat, "wits") == 0) {
533 ival[0] = curchar->wits;
534 } else if (strcasecmp(stat, "edge") == 0) {
535 ival[0] = curchar->edge;
536 } else if (strcasecmp(stat, "shadow") == 0) {
537 ival[0] = curchar->shadow;
538 } else if (strcasecmp(stat, "heart") == 0) {
539 ival[0] = curchar->heart;
543 ret = action_roll(ival);
545 printf("Gain an advantage -> Rulebook\n");
547 change_char_value("momentum", INCREASE, 1);
549 printf("Pay the price -> Rulebook\n");
553 cmd_roll_challenge_die(__attribute__((unused)) char *unused)
555 printf("%ld\n", roll_challenge_die());
559 cmd_roll_oracle_die(__attribute__((unused)) char *unused)
561 printf("%ld\n", roll_oracle_die());
567 long ret = random() % 6;
569 return ret == 0 ? 6 : ret;
575 return random() % 10;
581 return random() % 100;
585 cmd_yes_or_no(char *args)
587 int num = atoi(args);
590 log_debug("Argument %d\n", num);
591 if (num <= 0 || num > 5) {
592 printf("Provide a number between 1-5 as argument, i.e. yesorno 2\n\n");
593 for (i=0; odds[i] != NULL; i++)
594 printf("%d - %s\n", i+1, odds[i]);
607 a1 = roll_challenge_die();
608 c2 = roll_challenge_die();
612 printf("W10: match %ld -> ", a1);
614 printf("W10: %ld, %ld -> ", a1, c2);
617 if (num == 1 && c1 >= 11)
619 else if (num == 2 && c1 >= 26)
621 else if (num == 3 && c1 >= 51)
623 else if (num == 4 && c1 >= 76)
625 else if (num == 5 && c1 >= 91)
632 action_roll(int args[2])
637 log_debug("Action args: %d, %d\n", args[0], args[1]);
640 log_errx(1, "No attribute value provided. This should not happen!");
643 a1 = b = roll_action_die();
644 /* Add attribute and maybe a bonus value */
650 printf("D6: %ld+%d=%ld ", a1, args[0], b);
652 printf("D6: %ld+%d+%d=%ld ", a1, args[0], args[1], b);
654 c1 = roll_challenge_die();
655 c2 = roll_challenge_die();
656 c1 = (c1 == 0 ? 10 : c1);
657 c2 = (c2 == 0 ? 10 : c2);
660 printf("D10: %ld match -> ", c1);
662 printf("D10: %ld, %ld -> ", c1, c2);
665 if (b <= c1 && b <= c2) {
668 } else if (b <= c1 || b <= c2) {
669 pm(YELLOW, "weak hit\n");
671 } else if (b > c1 && b > c2) {
672 pm(GREEN, "strong hit\n");
680 progress_roll(double args[2])
687 log_errx(1, "No attribute value provided. This should not happen!");
690 c1 = roll_challenge_die();
691 c2 = roll_challenge_die();
692 c1 = (c1 == 0 ? 10 : c1);
693 c2 = (c2 == 0 ? 10 : c2);
695 log_debug("args[0] %.2lf args[1] %.2lf\n", args[0], args[1]);
702 printf("D10: %ld match vs ", c1);
704 printf("D10: %ld, %ld vs ", c1, c2);
707 printf("Progress: %.2lf -> ", b);
709 if (b <= c1 && b <= c2) {
712 } else if (b <= c1 || b <= c2) {
713 pm(YELLOW, "weak hit\n");
715 } else if (b > c1 && b > c2) {
716 pm(GREEN, "strong hit\n");
724 get_int_from_cmd(const char *cmd)
730 if (strlen(cmd) > 0) {
732 lval = strtol(cmd, &ep, 10);
733 if (cmd[0] == '\0' || *ep != '\0') {
734 printf("Please provide a number as argument\n");
737 if ((errno == ERANGE || lval <= 0 || lval > 10)) {
738 printf("Please provide a number between 1 and 10\n");
743 log_debug("Arg provided %d\n", ival);
750 get_args_from_cmd(char *cmd, char *stat, int *ival)
752 char *tokens[MAXTOKENS];
758 /* Parse the argument line into max tokens, separated by space */
759 for ((p = strtok_r(cmd, " ", &last)); p;
760 (p = strtok_r(NULL, " ", &last))) {
761 if (i < MAXTOKENS - 1)
766 /* First token is a stat */
768 if (tokens[i] == NULL)
770 else if (strlen(tokens[i]) == 0)
773 log_debug("stat token: %s\n", tokens[i]);
774 snprintf(stat, MAX_STAT_LEN, "%s", tokens[i]);
776 /* Second token is a bonus value*/
779 /* It's OK to have no bonus, so the token can be NULL and we can return */
780 if (tokens[i] == NULL)
783 log_debug("bonus token: %s\n", tokens[i]);
785 lval = strtol(tokens[i], &ep, 10);
786 if (cmd[0] == '\0' || *ep != '\0') {
787 printf("Please provide a number as argument\n");
790 if ((errno == ERANGE || lval <= 0 || lval > 10)) {
791 printf("Please provide a number between 1 and 10\n");