Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- This code is hereby released to the public domain.
- ~aaaaaa123456789, 2015-03-30, last updated 2015-12-02
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #define DEFAULT_HP 10
- #define DEFAULT_POWER 10
- #define DEFAULT_BONUS 0
- #define DEFAULT_MIN_RANGE 50
- #define DEFAULT_MAX_RANGE 150
- #define ATTACK_ROUNDS 10
- #define DEFAULT_MASTERY 0
- // NOTE: don't even try using a C++ compiler here (unless it has a C mode). It will cry. A lot.
- struct player {
- char * name;
- unsigned power;
- int bonus;
- unsigned min;
- unsigned max;
- unsigned mastery;
- };
- struct battle {
- char * location;
- unsigned HP;
- struct player player1;
- struct player player2;
- };
- struct node {
- struct battle battle;
- struct node * next;
- };
- struct range {
- unsigned min;
- unsigned max;
- };
- unsigned randstate1 = 0, randstate2 = 0; // random number generator state
- int main(void);
- void init_RNG(void);
- unsigned get_RNG(void);
- char * get_line(void);
- unsigned get_number(unsigned);
- int get_signed_number(int);
- struct node * get_battle_set(void);
- struct node * get_battle(int *);
- void delete_last_battle(struct node **, struct node **);
- struct player get_player_info(const char *);
- void make_battles(FILE *, struct node *);
- void make_battle(FILE *, struct battle);
- struct range effective_range(struct player);
- unsigned roll(unsigned);
- // output routines
- void separator(FILE *);
- void header(FILE *, const char *);
- void player_info(FILE *, struct player, struct range);
- void player_separator(FILE *);
- void battle_header(FILE *, const char *, const char *);
- void attack(FILE *, unsigned, unsigned, unsigned, unsigned, unsigned);
- void battle_footer(FILE *);
- void footer(FILE *, const char *, const char *, const char *, unsigned, unsigned);
- int main (void) {
- srand(time(NULL));
- init_RNG();
- struct node * battles = get_battle_set();
- if (!battles) return 0;
- puts("");
- printf("%s", "File to write [default: output to console]: ");
- char * filename = get_line();
- FILE * file;
- if (*filename)
- file = fopen(filename, "w");
- else
- file = stdout;
- if (!file) {
- fprintf(stderr, "Error opening %s for writing\n", filename);
- return 1;
- }
- make_battles(file, battles);
- return 0;
- }
- void init_RNG (void) {
- unsigned char count;
- unsigned num, result = 0;
- for (count = 0; count < 4; count ++) {
- num = (rand() >> 5) & 255;
- result |= num << (8 * count);
- }
- randstate1 = randstate2;
- randstate2 = result;
- if (!(randstate1 && randstate2) || (randstate1 == 0x464fffff) || (randstate2 == 0x9068ffff)) init_RNG();
- }
- unsigned get_RNG (void) {
- // George Marsaglia's MWC. Better than rand() for most cases.
- randstate2 = (36969 * (randstate2 & 65535) + (randstate2 >> 16)) & 0xffffffffu;
- randstate1 = (18000 * (randstate1 & 65535) + (randstate1 >> 16)) & 0xffffffffu;
- return ((randstate2 << 16) + randstate1) & 0xffffffffu;
- }
- char * get_line (void) {
- char * line = NULL;
- unsigned length = 0;
- int newchar;
- for (newchar = getchar(); (newchar != EOF) && (newchar != '\n'); newchar = getchar()) {
- line = realloc(line, ++ length);
- line[length - 1] = newchar;
- }
- line = realloc(line, length + 1);
- line[length] = 0;
- return line;
- }
- unsigned get_number (unsigned default_value) {
- char * line = NULL;
- char * end;
- unsigned number, attempted = 0;
- while (1) {
- if (attempted) {
- free(line);
- printf("%s", "That is not a valid number. Please enter a number: ");
- } else
- attempted = 1;
- line = get_line();
- if (!(line && *line)) return default_value;
- number = strtoul(line, &end, 10);
- if (*end) continue;
- free(line);
- return number;
- }
- }
- int get_signed_number (int default_value) {
- char * line = NULL;
- char * end;
- int number, attempted = 0;
- while (1) {
- if (attempted) {
- free(line);
- printf("%s", "That is not a valid number. Please enter a number: ");
- } else
- attempted = 1;
- line = get_line();
- if (!(line && *line)) return default_value;
- number = strtol(line, &end, 10);
- if (*end) continue;
- free(line);
- return number;
- }
- }
- struct node * get_battle_set (void) {
- int x = 0;
- struct node * result = get_battle(&x);
- struct node * current = result;
- struct node * new_node;
- while (1) {
- x = result != NULL;
- new_node = get_battle(&x);
- if (x) {
- if (!new_node) break;
- if (result)
- current = current -> next = new_node;
- else
- result = current = new_node;
- } else
- delete_last_battle(&result, ¤t);
- }
- return result;
- }
- struct node * get_battle (int * status) {
- if (*status)
- printf("%s", "Enter coordinates [<empty input>: stop, delete: delete last]: ");
- else
- printf("%s", "Enter coordinates [empty input to stop]: ");
- char * coords = get_line();
- if (!(coords && *coords)) {
- free(coords);
- *status = 1;
- return NULL;
- }
- if (!strcmp(coords, "delete")) {
- free(coords);
- if (!*status) {
- puts("Nothing to delete.");
- return get_battle(status);
- }
- *status = 0;
- return NULL;
- }
- struct battle battle = {.location = coords};
- printf("Enter the HP of cell %s [default: %u]: ", coords, DEFAULT_HP);
- battle.HP = get_number(DEFAULT_HP);
- battle.player1 = get_player_info("Attacker");
- battle.player2 = get_player_info("Defender");
- puts("");
- struct node * new = malloc(sizeof(struct node));
- new -> battle = battle;
- new -> next = NULL;
- *status = 1;
- return new;
- }
- void delete_last_battle (struct node ** list, struct node ** pointer) {
- if (!*list) return; // you're drunk, go home
- if (*list == *pointer) {
- free(*list);
- *list = *pointer = NULL;
- return;
- }
- struct node * previous;
- for (previous = *list; previous -> next != *pointer; previous = previous -> next);
- *pointer = previous;
- free(previous -> next);
- previous -> next = NULL;
- }
- struct player get_player_info (const char * player) {
- printf("%s data:\n", player);
- printf("%s", "Name: ");
- char * name = get_line();
- while (!(name && *name)) {
- free(name);
- printf("%s", "The name must not be blank. Name: ");
- name = get_line();
- }
- struct player result = {.name = name};
- printf("Base power [default: %u]: ", DEFAULT_POWER);
- result.power = get_number(DEFAULT_POWER);
- printf("Bonus %% [default: %d]: ", DEFAULT_BONUS);
- result.bonus = get_signed_number(DEFAULT_BONUS);
- printf("Min. range %% [default: %u]: ", DEFAULT_MIN_RANGE);
- result.min = get_number(DEFAULT_MIN_RANGE);
- printf("Max. range %% [default: %u]: ", DEFAULT_MAX_RANGE);
- result.max = get_number(DEFAULT_MAX_RANGE);
- printf("Mastery %% [default: %u]: ", DEFAULT_MASTERY);
- result.mastery = get_number(DEFAULT_MASTERY);
- return result;
- }
- void make_battles (FILE * output, struct node * battles) {
- make_battle(output, battles -> battle);
- for (battles = battles -> next; battles; battles = battles -> next) {
- separator(output);
- make_battle(output, battles -> battle);
- }
- }
- void make_battle (FILE * output, struct battle battle) {
- header(output, battle.location);
- struct range range1 = effective_range(battle.player1), range2 = effective_range(battle.player2);
- player_info(output, battle.player1, range1);
- player_separator(output);
- player_info(output, battle.player2, range2);
- battle_header(output, battle.player1.name, battle.player2.name);
- unsigned char attacks = 0, wins = 0;
- while ((attacks < ATTACK_ROUNDS) && (wins < battle.HP)) {
- unsigned roll1 = roll(range1.max - range1.min), roll2 = roll(range2.max - range2.min);
- unsigned char result = ((range1.min + roll1) > (range2.min + roll2)) ? 1 : ((range2.min + roll2) > (range1.min + roll1)) ? 2 : 0;
- attacks ++;
- if (result == 1) wins ++;
- attack(output, range1.min, roll1, range2.min, roll2, result);
- }
- battle_footer(output);
- footer(output, battle.player1.name, battle.player2.name, battle.location, wins, battle.HP - wins);
- }
- struct range effective_range (struct player player) {
- unsigned long long base = player.power * (100 + player.bonus);
- unsigned long long min = base * player.min, max = base * player.max;
- return (struct range) {.min = (min * 100 + (max - min) * player.mastery) / 1000000, .max = max / 10000};
- }
- unsigned roll (unsigned max_roll) {
- if (!max_roll) return 0;
- unsigned limit = max_roll + 1;
- unsigned result = -1;
- while ((result + limit - (result % limit)) < result) result = get_RNG();
- return result % limit;
- }
- // Output routines begin here. If the output format is to be changed, everything that should be changed starts here.
- void separator (FILE * output) {
- fputs("\n[hr]\n\n", output);
- }
- void header (FILE * output, const char * coordinate) {
- fprintf(output, "[b]Battle at %s[/b]\n", coordinate);
- fputs("[spoiler][center][b]", output);
- }
- void player_info (FILE * output, struct player player, struct range range) {
- fprintf(output, "%s's Power: %u\n", player.name, player.power);
- fprintf(output, "%s's Bonuses: %+d%%\n", player.name, player.bonus);
- fprintf(output, "%s's Mastery: %u%%\n", player.name, player.mastery);
- unsigned range_integer = player.min * 100 + (player.max - player.min) * player.mastery;
- unsigned char range_fraction = range_integer % 100;
- range_integer /= 100;
- if (range_fraction)
- fprintf(output, "%s's Range: %u.%02hhu%% - %u%%\n", player.name, range_integer, range_fraction, player.max);
- else
- fprintf(output, "%s's Range: %u%% - %u%%\n", player.name, range_integer, player.max);
- fprintf(output, "%s's Effective Range: %u - %u\n", player.name, range.min, range.max);
- }
- void player_separator (FILE * output) {
- fputs("\nVS\n\n", output);
- }
- void battle_header (FILE * output, const char * attacker, const char * defender) {
- fputs("\n[table=width: 400px; margin: auto]\n[tr]\n", output);
- fprintf(output, "[td]%s[/td]\n", attacker);
- fprintf(output, "[td]%s[/td]\n", defender);
- fputs("[td]Result[/td]\n", output);
- fputs("[/tr]\n", output);
- }
- void attack (FILE * output, unsigned min1, unsigned roll1, unsigned min2, unsigned roll2, unsigned result) {
- if (result > 2) return;
- fputs("[tr]\n", output);
- fprintf(output, "[td]%u + %u = %u[/td]\n", min1, roll1, min1 + roll1);
- fprintf(output, "[td]%u + %u = %u[/td]\n", min2, roll2, min2 + roll2);
- fprintf(output, "[td][color=%s]%s[/color][/td]\n",
- result[(const char * []) {"#000000", "#008000", "#ff0000"}],
- result[(const char * []) {"Draw", "Win", "Lose"}]
- );
- fputs("[/tr]\n", output);
- }
- void battle_footer (FILE * output) {
- fputs("[/table]\n[/b][/center][/spoiler]\n\n", output);
- }
- void footer (FILE * output, const char * attacker, const char * defender, const char * coordinate, unsigned wins, unsigned remaining) {
- fputs("[b]", output);
- if (wins) {
- fprintf(output, "[color=#008000]%s wins %u %s.[/color]\n\n", attacker, wins, (wins == 1) ? "fight" : "fights");
- fprintf(output, "%s loses %uHP.\n", defender, wins);
- } else
- fprintf(output, "[color=#ff0000]%s wins no fights.[/color]\n\n", attacker);
- if (remaining)
- fprintf(output, "%s has %uHP remaining.", coordinate, remaining);
- else
- fprintf(output, "%s falls to %s.", coordinate, attacker);
- fputs("[/b]\n", output);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement