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.
17 #include <json-c/json.h>
23 #include "isscrolls.h"
26 cmd_enter_the_fray(char *cmd)
28 struct character *curchar = get_current_character();
29 char stat[MAX_STAT_LEN];
30 int ival[2] = { -1, -1 };
33 if (curchar == NULL) {
34 printf("No character loaded. Use 'cd' to load a character\n");
38 ret = get_args_from_cmd(cmd, stat, &ival[1]);
41 printf("\nPlease specify the stat you'd like to use in this move\n\n");
42 printf("heart\t- You are facing off against your foe\n");
43 printf("shadow \t- You are moving into position against or strike without warning\n");
44 printf("wits\t- You are ambushed\n");
45 printf("Example: enterthefray wits\n\n");
47 } else if (ret <= -20) {
51 if (strcasecmp(stat, "wits") == 0) {
52 ival[0] = curchar->wits;
53 } else if (strcasecmp(stat, "shadow") == 0) {
54 ival[0] = curchar->shadow;
55 } else if (strcasecmp(stat, "heart") == 0) {
56 ival[0] = curchar->heart;
60 if (curchar->fight_active == 0) {
61 ask_for_fight_difficulty();
62 curchar->fight_active = 1;
64 printf("You are already in a fight\n");
68 ret = action_roll(ival);
70 change_char_value("momentum", INCREASE, 2);
72 printf("You have initiative\n");
73 } else if (ret == 4) {
74 printf("You may choose one boost -> Rulebook\n");
76 printf("Pay the price -> Rulebook\n");
82 cmd_end_the_fight(char *cmd)
84 struct character *curchar = get_current_character();
85 double dval[2] = { -1.0, -1.0 };
88 if (curchar == NULL) {
89 printf("No character loaded. Use 'cd' to load a character\n");
93 if (curchar->fight_active == 0) {
94 printf("You are not in a fight. Enter one with enterthefray\n");
98 dval[0] = curchar->fight->progress;
99 dval[1] = get_int_from_cmd(cmd);
100 ret = progress_roll(dval);
102 printf("The foe is no longer in the fight -> Rulebook\n");
103 } else if (ret == 4) {
104 printf("The foe is no longer in the fight, but you must chose one option -> Rulebook\n");
106 printf("You lost the fight. Pay the price -> Rulebook\n");
108 curchar->fight_active = 0;
109 curchar->fight->progress = 0;
110 delete_fight(curchar->id);
115 cmd_endure_harm(char *cmd)
117 struct character *curchar = get_current_character();
118 int ival[2] = { -1, -1 };
121 if (curchar == NULL) {
122 printf("No character loaded. Use 'cd' to load a character\n");
128 /* We are in a fight, so we can suffer harm equal to our foe's rank */
129 if (curchar->fight_active == 1) {
130 hr = curchar->health - curchar->fight->difficulty;
131 suffer = curchar->fight->difficulty;
133 /* We are not in a fight, so the player can specify the amount of
135 ival[1] = get_int_from_cmd(cmd);
137 /* We are not in a fight and there is not argument provided */
138 printf("Please specify the amount of harm you want to suffer\n\n");
139 printf("Example: endureharm 2\n");
143 hr = curchar->health - ival[1];
145 log_debug("Arg provided %d, hr: %d\n", ival[1], hr);
146 /* Reset ival[1] since we don't need a bonus */
151 curchar->health -= suffer;
152 printf("You suffer %d harm and your health is down to %d\n",
153 suffer, curchar->health);
155 /* Health is 0, so suffer -momentum equal to remaining health */
156 log_debug("hr < 0: %d\n", hr);
158 curchar->momentum -= (hr * (-1));
159 printf("You suffer %d harm and since your health is %d, your "\
160 "momentum is down to %d\n",
161 suffer, curchar->health,
165 ival[0] = curchar->iron;
166 if (curchar->heart > curchar->iron) {
167 ival[0] = curchar->heart;
170 ret = action_roll(ival);
172 printf("You need to choose one option -> Rulebook\n");
173 } else if (ret == 4) {
174 printf("You press on\n");
176 change_char_value("momentum", DECREASE, 1);
177 if (curchar->health == 0)
178 printf("Mark either maimed or wounded or on the oracle table -> Rulebook\n");
183 cmd_strike(char *cmd)
185 struct character *curchar = get_current_character();
186 char stat[MAX_STAT_LEN];
187 int ival[2] = { -1, -1 };
190 if (curchar == NULL) {
191 printf("No character loaded. Use 'cd' to load a character\n");
195 if (curchar->fight_active == 0) {
196 printf("You are not in a fight. Enter one with enterthefray\n");
200 ret = get_args_from_cmd(cmd, stat, &ival[1]);
203 printf("Please specify the stat you'd like to use in this move\n\n");
204 printf("iron\t- You attack in close quarters\n");
205 printf("edge\t- You attack at range\n");
206 printf("Example: strike iron\n");
208 } else if (ret <= -20)
211 if (strcasecmp(stat, "iron") == 0) {
212 ival[0] = curchar->iron;
213 } else if (strcasecmp(stat, "edge") == 0) {
214 ival[0] = curchar->edge;
218 ret = action_roll(ival);
220 printf("You inflict +1 harm and retain initiative\n");
222 mark_fight_progress();
223 mark_fight_progress();
224 } else if (ret == 4) {
225 printf("You inflict harm and lose initiative\n");
227 mark_fight_progress();
229 printf("Pay the price -> Rulebook\n");
238 struct character *curchar = get_current_character();
239 char stat[MAX_STAT_LEN];
240 int ival[2] = { -1, -1 };
243 if (curchar == NULL) {
244 printf("No character loaded. Use 'cd' to load a character\n");
248 if (curchar->fight_active == 0) {
249 printf("You are not in a fight. Enter one with enterthefray\n");
253 ret = get_args_from_cmd(cmd, stat, &ival[1]);
256 printf("Please specify the stat you'd like to use in this move\n\n");
257 printf("iron\t- You fight in close quarters\n");
258 printf("edge\t- You fight at range\n");
259 printf("Example: clash iron\n");
261 } else if (ret <= -20)
264 if (strcasecmp(stat, "iron") == 0) {
265 ival[0] = curchar->iron;
266 } else if (strcasecmp(stat, "edge") == 0) {
267 ival[0] = curchar->edge;
271 ret = action_roll(ival);
273 printf("You inflict harm, regain initiative and can choose one option -> Rulebook\n");
275 mark_fight_progress();
276 } else if (ret == 4) {
277 printf("You inflict harm and lose initiative. Pay the price -> Rulebook\n");
279 mark_fight_progress();
281 printf("Pay the price -> Rulebook\n");
288 cmd_battle(char *cmd)
290 struct character *curchar = get_current_character();
291 char stat[MAX_STAT_LEN];
292 int ival[2] = { -1, -1 };
295 if (curchar == NULL) {
296 printf("No character loaded. Use 'cd' to load a character\n");
300 if (curchar->fight_active == 0) {
301 printf("You are not in a fight. Enter one with enterthefray\n");
305 ret = get_args_from_cmd(cmd, stat, &ival[1]);
308 printf("Please specify the stat you'd like to use in this move\n\n");
309 printf("edge\t- Fight at range, or using your speed and the terrain\n");
310 printf("heart\t- Fight depending on your courage, allies, or companions\n");
311 printf("iron\t- Fight in close to overpower your opponents\n");
312 printf("shadow\t- Fight using trickery to befuddle your opponents\n");
313 printf("wits\t- Fight using careful tactics to outsmart your opponents\n\n");
314 printf("Example: battle iron\n");
316 } else if (ret <= -20)
319 if (strcasecmp(stat, "iron") == 0) {
320 ival[0] = curchar->iron;
321 } else if (strcasecmp(stat, "wits") == 0) {
322 ival[0] = curchar->wits;
323 } else if (strcasecmp(stat, "edge") == 0) {
324 ival[0] = curchar->edge;
325 } else if (strcasecmp(stat, "shadow") == 0) {
326 ival[0] = curchar->shadow;
327 } else if (strcasecmp(stat, "heart") == 0) {
328 ival[0] = curchar->heart;
332 ret = action_roll(ival);
334 change_char_value("momentum", INCREASE, 2);
335 printf("You achieve your objective unconditionally\n");
336 } else if (ret == 4) /* weak hit */
337 printf("You achieve your objective, but not without a cost -> Rulebook\n");
339 printf("Pay the price -> Rulebook\n");
343 set_initiative(int what)
345 struct character *curchar = get_current_character();
347 if (curchar == NULL) {
348 log_debug("No character loaded. Cannot set initiative\n");
352 if (curchar->fight_active == 0) {
353 printf("You need start a fight before you can mark progress\n");
358 curchar->fight->initiative = 1;
360 curchar->fight->initiative = 0;
364 mark_fight_progress()
366 struct character *curchar = get_current_character();
368 if (curchar == NULL) {
369 log_debug("No character loaded. Cannot calculate progress\n");
373 if (curchar->fight_active == 0) {
374 printf("You need start a fight before you can mark progress\n");
378 switch (curchar->fight->difficulty) {
380 curchar->fight->progress += 3;
383 curchar->fight->progress += 2;
386 curchar->fight->progress += 1;
389 curchar->fight->progress += 0.5;
392 curchar->fight->progress += 0.25;
395 curchar->fight->difficulty = 1;
396 log_errx(1, "Unknown difficulty. This should not happen. Set to 1\n");
399 if (curchar->fight->progress > 10) {
400 printf("Your fight is successful. Consider ending it\n");
401 curchar->fight->progress = 10;
410 struct character *curchar = get_current_character();
411 char path[_POSIX_PATH_MAX];
412 json_object *root, *items, *id;
415 if (curchar == NULL) {
416 log_debug("No character loaded. No fight to save.\n");
420 if (curchar->fight_active == 0) {
421 log_debug("No active fight to save.\n");
425 json_object *cobj = json_object_new_object();
426 json_object_object_add(cobj, "id", json_object_new_int(curchar->id));
427 json_object_object_add(cobj, "difficulty", json_object_new_int(curchar->fight->difficulty));
428 json_object_object_add(cobj, "progress", json_object_new_double(curchar->fight->progress));
429 json_object_object_add(cobj, "initiative", json_object_new_int(curchar->fight->initiative));
431 snprintf(path, sizeof(path), "%s/fight.json", get_isscrolls_dir());
432 if ((root = json_object_from_file(path)) == NULL) {
433 log_debug("No fight JSON file found\n");
434 root = json_object_new_object();
436 log_errx(1, "Cannot create fight JSON object\n");
438 items = json_object_new_array();
439 json_object_array_add(items, cobj);
440 json_object_object_add(root, "fight", items);
442 /* Get existing character array from JSON */
443 if (!json_object_object_get_ex(root, "fight", &items)) {
444 log_debug("Cannot find a [fight] array in %s. Create one\n", path);
445 items = json_object_new_array();
446 json_object_object_add(root, "fight", items);
449 temp_n = json_object_array_length(items);
450 for (i = 0; i < temp_n; i++) {
451 json_object *temp = json_object_array_get_idx(items, i);
452 json_object_object_get_ex(temp, "id", &id);
453 if (curchar->id == json_object_get_int(id)) {
454 log_debug("Update fight entry for %s\n", curchar->name);
455 json_object_array_del_idx(items, i, 1);
456 json_object_array_add(items, cobj);
460 log_debug("No fight entry for %s found, adding new one\n", curchar->name);
461 json_object_array_add(items, cobj);
465 if (json_object_to_file(path, root))
466 printf("Error saving %s\n", path);
468 log_debug("Successfully saved %s\n", path);
470 json_object_put(root);
476 char path[_POSIX_PATH_MAX];
477 json_object *root, *lid;
480 snprintf(path, sizeof(path), "%s/fight.json", get_isscrolls_dir());
481 if ((root = json_object_from_file(path)) == NULL) {
482 log_debug("No fight JSON file found\n");
487 if (!json_object_object_get_ex(root, "fight", &fight)) {
488 log_debug("Cannot find a [fight] array in %s\n", path);
492 temp_n = json_object_array_length(fight);
493 for (i = 0; i < temp_n; i++) {
494 json_object *temp = json_object_array_get_idx(fight, i);
495 json_object_object_get_ex(temp, "id", &lid);
496 if (id == json_object_get_int(lid)) {
497 json_object_array_del_idx(fight, i, 1);
498 log_debug("Deleted fight entry for %d\n", id);
502 if (json_object_to_file(path, root))
503 printf("Error saving %s\n", path);
505 log_debug("Successfully saved %s\n", path);
507 json_object_put(root);
513 struct character *curchar = get_current_character();
514 char path[_POSIX_PATH_MAX];
515 json_object *root, *lid;
518 if (curchar == NULL) {
519 log_debug("No character loaded\n");
523 snprintf(path, sizeof(path), "%s/fight.json", get_isscrolls_dir());
524 if ((root = json_object_from_file(path)) == NULL) {
525 log_debug("No fight JSON file found\n");
530 if (!json_object_object_get_ex(root, "fight", &fight)) {
531 log_debug("Cannot find a [fight] array in %s\n", path);
535 temp_n = json_object_array_length(fight);
536 for (i=0; i < temp_n; i++) {
537 json_object *temp = json_object_array_get_idx(fight, i);
538 json_object_object_get_ex(temp, "id", &lid);
539 if (id == json_object_get_int(lid)) {
540 log_debug("Loading fight for id: %d\n", json_object_get_int(lid));
543 json_object_object_get_ex(temp, "difficulty", &cval);
544 curchar->fight->difficulty = json_object_get_int(cval);
545 json_object_object_get_ex(temp, "progress", &cval);
546 curchar->fight->progress = json_object_get_double(cval);
547 json_object_object_get_ex(temp, "initiative", &cval);
548 curchar->fight->initiative = json_object_get_int(cval);
552 json_object_put(root);
556 ask_for_fight_difficulty()
558 struct character *curchar = get_current_character();
560 if (curchar == NULL) {
561 log_debug("No character loaded\n");
565 printf("Please set a difficulty for your fight\n\n");
566 printf("1\t - Troublesome foe (3 progress per harm)\n");
567 printf("2\t - Dangerous foe (2 progress per harm)\n");
568 printf("3\t - Formidable foe (2 progress per harm)\n");
569 printf("4\t - Extreme foe (2 ticks per harm)\n");
570 printf("5\t - Epic foe (1 tick per harm)\n\n");
572 curchar->fight->difficulty = ask_for_value("Enter a value between 1 and 5: ", 5);