/* * Copyright (C) 2002-2007 The Warp Rogue Team * Part of the Warp Rogue Project * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License. * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY. * * See the license.txt file for more details. */ /* * Module Name: CharacterGeneration * Description: - */ #define Uses_Ui #define Uses_Character #define Uses_CharacterAdvancement #define Uses_Race #define Uses_Career #define Uses_Stats #define Uses_Inventory #define Uses_Random #define Uses_Object #define Uses_Equipment #define Uses_Party #define Uses_Util #define Uses_Perks #define Uses_Psychic #define Uses_ProgramManager #include "mheader.h" #include "chargen.h" static void choose_gender(CHARACTER *); static void roll_stats_screen(CHARACTER *); static void roll_gender(CHARACTER *); static void roll_stats(const DICE_ROLL *, CHARACTER *); static void roll_career(CHARACTER *); static void roll_advances(CHARACTER *); static void roll_perks(CHARACTER *); static void roll_psy_powers(CHARACTER *); /* * player character creation */ void create_player_character(void) { CHARACTER *character; character = character_new(); character->symbol = player_race()->symbol; character->type = CT_PC; character->is_hostile = false; character_set_flag(character, CF_UNIQUE); choose_gender(character); new_career_path(character, true); roll_stats_screen(character); increase_stat(character, true); career_give_trappings(character); equip_objects(character); roll_name(character); set_player_character(character); set_player_controlled_character(character); party_join(character); } /* * generates a random NPC who belongs the player characters's race * his attributes will based on the race profile + career data */ CHARACTER * create_random_npc(void) { CHARACTER *character; character = character_new(); character->symbol = player_race()->symbol; character->is_hostile = false; character_set_flag(character, CF_UNIQUE); strcpy(character->script, "rand_npc.wca"); roll_gender(character); roll_name(character); roll_stats(player_race()->profile, character); roll_career(character); roll_advances(character); roll_perks(character); roll_psy_powers(character); career_give_trappings(character); equip_objects(character); return character; } /* * rolls the passed character's name */ void roll_name(CHARACTER *character) { NAME_SET chosen_set; if (character->gender == GENDER_MALE) { chosen_set = NAME_SET_HUMAN_MALE; } else if (character->gender == GENDER_FEMALE) { chosen_set = NAME_SET_HUMAN_FEMALE; } else { die("*** CORE ERROR *** roll_name() bug"); /* NEVER REACHED */ return; } strcpy(character->name, random_name(chosen_set)); } /* * the choose gender screen */ static void choose_gender(CHARACTER *character) { MENU *menu; LIST *items; items = list_new(); list_add(items, "Male"); list_add(items, "Female"); menu = menu_create(items); do { command_bar_set(3, CM_UP, CM_DOWN, CM_OK); render_choose_gender_screen(); update_screen(); choose_gender_screen_menu(menu); if (menu->entered_command == CM_OK) { character->gender = (GENDER)menu->highlighted; } } while (menu->entered_command != CM_OK); menu_free(menu); } /* * the roll stats screen */ static void roll_stats_screen(CHARACTER *character) { COMMAND entered_command; entered_command = CM_REROLL; while (entered_command == CM_REROLL) { roll_stats(player_race()->profile, character); command_bar_set(2, CM_OK, CM_REROLL); render_roll_stats_screen(character); update_screen(); entered_command = command_bar_get_command(); } } /* * rolls the passed character's gender */ static void roll_gender(CHARACTER *character) { if (random_choice(MALE_CHARACTER_PROBABILITY)) { character->gender = GENDER_MALE; } else { character->gender = GENDER_FEMALE; } } /* * (re)rolls the stats of the passed character based on the * passed profile */ static void roll_stats(const DICE_ROLL *profile, CHARACTER *character) { STAT i; for (i = 0; i < MAX_STATS; i++) { CHARACTER_STAT *stat; const DICE_ROLL *stat_roll; stat = &character->stat[i]; stat_roll = &profile[i]; stat->current = stat->total = dice(stat_roll->n_dice, stat_roll->n_sides) + stat_roll->modifier; } } /* * rolls the passed character's career */ static void roll_career(CHARACTER *character) { CAREER_INDEX career_index; career_index = random_int(0, get_n_careers() - 1); career_set(character, career_index); } /* * rolls the passed character's stat advances */ static void roll_advances(CHARACTER *character) { const CAREER *career; STAT i; career = get_career_pointer(character->career); for (i = 0; i < MAX_STATS; i++) { int n_advances; n_advances = random_int(0, career->max_stat_advance[i] / 10 ); while (n_advances-- > 0) { stat_advance(character, i); } } } /* * rolls the passed character's perks */ static void roll_perks(CHARACTER *character) { LIST *available_perks; PERK i; N_PERKS n_perks; const CAREER *career; career = get_career_pointer(character->career); available_perks = list_new(); for (i = 0; i < MAX_PERKS; i++) { if (career->perk[i] && !character->perk[i]) { list_add(available_perks, (void *)perk_name(i)); } } if (available_perks->n_nodes > 0) { n_perks = random_int(0, available_perks->n_nodes); if (n_perks > MAX_CHARACTER_PERKS) { n_perks = MAX_CHARACTER_PERKS; } } else { n_perks = 0; } while (n_perks > 0) { int r; PERK perk; LIST_NODE *perk_node; r = random_int(0, available_perks->n_nodes - 1); perk_node = list_node_at(available_perks, r); perk = name_to_perk(perk_node->data); /* * make sure that the character gets the psychic * perk before getting other psyker perks */ if (!character->perk[PK_PSYCHIC] && career->perk[PK_PSYCHIC] && is_psyker_perk(perk)) { perk_node = list_node_of(available_perks, perk_name(PK_PSYCHIC) ); perk = PK_PSYCHIC; } give_perk(character, perk); list_remove_node(available_perks, perk_node); --n_perks; } list_free(available_perks); } /* * rolls the passed character's psychic powers */ static void roll_psy_powers(CHARACTER *character) { LIST *available_powers; PSY_POWER i; N_PSY_POWERS n_powers; if (!character->perk[PK_PSYCHIC]) { return; } available_powers = list_new(); for (i = 0; i < MAX_PSY_POWERS; i++) { if (!character->psy_power[i] && psy_power_implemented(i)) { list_add(available_powers, (void *)psy_power_name(i) ); } } if (available_powers->n_nodes > 0) { n_powers = random_int(1, available_powers->n_nodes); if (n_powers > MAX_CHARACTER_PSY_POWERS) { n_powers = MAX_CHARACTER_PSY_POWERS; } } else { n_powers = 0; } while (n_powers > 0) { LIST_NODE_INDEX r; PSY_POWER power; LIST_NODE *power_node; r = random_int(0, available_powers->n_nodes - 1); power_node = list_node_at(available_powers, r); power = name_to_psy_power(power_node->data); character->psy_power[power] = true; list_remove_node(available_powers, power_node); --n_powers; } list_free(available_powers); }