/* * 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: Ui * Description: - */ /* * Information screens i.e. object info, character info, etc. */ #define Uses_Util #define Uses_Random #define Uses_ProgramManager #define Uses_Career #define Uses_Stats #define Uses_Psychic #define Uses_Perks #define Uses_Terrain #define Uses_Object #define Uses_Character #define Uses_Equipment #define Uses_Faction #define Uses_Area #define Uses_World #include "mheader.h" #include "ui.h" static void render_career_exits_at(SCREEN_COORD, SCREEN_COORD, const CAREER * ); static void render_trappings_at(SCREEN_COORD, SCREEN_COORD, const CAREER * ); static void render_equipment_at(SCREEN_COORD, SCREEN_COORD, const CHARACTER * ); static void render_perks_at(SCREEN_COORD, SCREEN_COORD, SCREEN_COORD, const bool * ); static void render_advance_scheme_at(SCREEN_COORD, SCREEN_COORD, const CAREER * ); static void render_psy_powers(SCREEN_ID, const CHARACTER *); static void render_object_screen_ccw(const OBJECT *, SCREEN_COORD, SCREEN_COORD ); static void render_object_screen_rcw(const OBJECT *, SCREEN_COORD, SCREEN_COORD ); static void render_firing_mode_at(COLOUR, SCREEN_COORD, SCREEN_COORD, const OBJECT * ); static void render_object_attributes_at(SCREEN_COORD, SCREEN_COORD, const OBJECT_DATA * ); #define WORLD_MAP_MIN_Y 3 #define WORLD_MAP_MIN_X GAME_SCREEN_MIN_X #define WORLD_MAP_MAX_Y GAME_SCREEN_MAX_Y #define WORLD_MAP_MAX_X GAME_SCREEN_MIN_X + 68 #define WORLD_INFO_MIN_Y WORLD_MAP_MIN_Y #define WORLD_INFO_MIN_X WORLD_MAP_MAX_X + 4 #define WORLD_INFO_MAX_X WORLD_MAP_MAX_X + 28 #define WORLD_POSITION_Y GAME_SCREEN_MAX_Y - 5 /* * renders the world map */ void render_world_map_screen(const WORLD_POINT *current_position, const CHARACTER *character ) { SCREEN_COORD x, y; WORLD_POINT p; render_background(); /* message window */ clear_text_window( GAME_SCREEN_MESSAGE_ROW, GAME_SCREEN_MIN_X, GAME_SCREEN_MESSAGE_ROW, GAME_SCREEN_MAX_X ); /* map screen */ clear_text_window(WORLD_MAP_MIN_Y, WORLD_MAP_MIN_X, WORLD_MAP_MAX_Y, WORLD_MAP_MAX_X ); /* world name */ clear_text_window(WORLD_INFO_MIN_Y, WORLD_INFO_MIN_X, WORLD_INFO_MIN_Y, WORLD_INFO_MAX_X ); render_text_at(C_FIELD_VALUE, WORLD_INFO_MIN_Y, WORLD_INFO_MIN_X, world()->name ); /* world description */ clear_text_window(WORLD_INFO_MIN_Y + 2, WORLD_INFO_MIN_X, WORLD_POSITION_Y - 2, WORLD_INFO_MAX_X ); render_long_text(C_TEXT, WORLD_INFO_MIN_Y + 2, WORLD_INFO_MIN_X, world()->description, WORLD_INFO_MAX_X ); /* location */ clear_text_window(WORLD_POSITION_Y, WORLD_INFO_MIN_X, WORLD_POSITION_Y, WORLD_INFO_MAX_X ); render_text_at(C_FIELD_VALUE, WORLD_POSITION_Y, WORLD_INFO_MIN_X, "%d, %d", current_position->y, current_position->x ); clear_text_window(WORLD_POSITION_Y + 2, WORLD_INFO_MIN_X, WORLD_POSITION_Y + 2, WORLD_INFO_MAX_X ); render_text_at(C_FIELD_VALUE, WORLD_POSITION_Y + 2, WORLD_INFO_MIN_X, world_tile_data(current_position)->name ); p.z = current_position->z; for (p.y = 0, y = SEC_SCREEN_MIN_Y; p.y < WORLD_HEIGHT; p.y++, y++) { for (p.x = 0, x = SEC_SCREEN_MIN_X; p.x < WORLD_WIDTH; p.x++, x++) { const WORLD_TILE_DATA *tile_data; tile_data = world_tile_data(&p); render_char_at(tile_data->colour, y, x, tile_data->symbol); } } y = SEC_SCREEN_MIN_Y + current_position->y; x = SEC_SCREEN_MIN_X + current_position->x; render_char_at(character->colour, y, x, character->symbol); } /* * renders the career screen */ void render_career_screen(const CAREER *career) { render_secondary_screen("-== Career ==-"); render_text_at(C_FIELD_NAME, SEC_SCREEN_MIN_Y, SEC_SCREEN_MIN_X, "Name: " ); render_text(C_FIELD_VALUE, "%s", career->name); render_text_at(C_FIELD_NAME, SEC_SCREEN_MIN_Y + 1, SEC_SCREEN_MIN_X, "Type: " ); render_text(C_FIELD_VALUE, "%s", career_type_name(career->type)); render_advance_scheme_at(SEC_SCREEN_MIN_Y + 3, SEC_SCREEN_MIN_X, career); render_trappings_at(SEC_SCREEN_MIN_Y + 13, SEC_SCREEN_MIN_X, career); render_text_at(C_HEADER, SEC_SCREEN_MIN_Y, SEC_SCREEN_MAX_X / 2, "[Available Perks]" ); render_perks_at(SEC_SCREEN_MIN_Y + 1, SEC_SCREEN_MAX_X / 2, SEC_SCREEN_MIN_Y + 21, career->perk ); render_career_exits_at(SEC_SCREEN_MIN_Y + 13, SEC_SCREEN_MAX_X / 2, career ); render_text_at(C_HEADER, SEC_SCREEN_MIN_Y + 24, SEC_SCREEN_MIN_X, "[Description]" ); render_long_text(C_TEXT, SEC_SCREEN_MIN_Y + 25, SEC_SCREEN_MIN_X, career->description, SEC_SCREEN_MAX_X ); } /* * renders the character screen basics */ void render_character_screen_basics(const CHARACTER *character) { const char *description; SCREEN_COORD row; render_secondary_screen("-== Character ==-"); row = SEC_SCREEN_MIN_Y; render_text_at(C_FIELD_NAME, row++, SEC_SCREEN_MIN_X, "Name : "); render_text(C_FIELD_VALUE, character->name); render_text_at(C_FIELD_NAME, row++, SEC_SCREEN_MIN_X, "Career : "); if (character->career == CAREER_NIL) { render_text(C_FIELD_VALUE, "-"); } else { render_text(C_FIELD_VALUE, get_career_pointer(character->career)->name ); } render_text_at(C_FIELD_NAME, row++, SEC_SCREEN_MIN_X, "Power Rating: "); render_text(C_FIELD_VALUE, "%d", character_power_rating(character)); render_stats_at(character, ++row, SEC_SCREEN_MIN_X); row += 10; render_text_at(C_HEADER, row, SEC_SCREEN_MIN_X,"[Status]"); place_cursor_at(++row, SEC_SCREEN_MIN_X); render_character_status(character, SEC_SCREEN_MAX_Y - 1, true); row = SEC_SCREEN_MIN_Y + 14; render_text_at(C_HEADER, row, SEC_SCREEN_MAX_X / 2,"[Perks]"); ++row; render_perks_at(row, SEC_SCREEN_MAX_X / 2, row + 10, character->perk ); render_equipment_at(SEC_SCREEN_MIN_Y, SEC_SCREEN_MAX_X / 2, character ); render_text_at(C_HEADER, SEC_SCREEN_MIN_Y + 24, SEC_SCREEN_MIN_X, "[Description]" ); description = character_description(character); if (description == NULL) return; render_long_text(C_TEXT, SEC_SCREEN_MIN_Y + 25, SEC_SCREEN_MIN_X, description, SEC_SCREEN_MAX_X ); } /* * renders the character flag screen */ void render_character_flag_screen(CHARACTER_FLAG flag) { char description[DESCRIPTION_SIZE]; render_secondary_screen("-== Character Flag ==-"); render_text_at(C_FIELD_NAME, SEC_SCREEN_MIN_Y, SEC_SCREEN_MIN_X, "Name: " ); render_text(C_FIELD_VALUE, "%s", character_flag_name(flag)); render_text_at(C_HEADER, SEC_SCREEN_MIN_Y + 2, SEC_SCREEN_MIN_X, "[Description]" ); render_long_text(C_TEXT, SEC_SCREEN_MIN_Y + 3, SEC_SCREEN_MIN_X, character_flag_description(description, flag), SEC_SCREEN_MAX_X ); } /* * renders the object screen */ void render_object_screen(const OBJECT *object) { SCREEN_COORD row, col; const OBJECT_DATA *object_data; render_secondary_screen("-== Object ==-"); row = SEC_SCREEN_MIN_Y; col = SEC_SCREEN_MIN_X; object_data = object_static_data(object); render_text_at(C_FIELD_NAME, row, col, "Name : "); render_text(C_FIELD_VALUE, object_data->name); render_text_at(C_FIELD_NAME, ++row, col, "Type : "); render_text(C_FIELD_VALUE, object_type_name(object_data->type)); if (object_data->subtype != OSTYPE_NIL) { render_text_at(C_FIELD_NAME, ++row, col, "Subtype : "); render_text(C_FIELD_VALUE, object_subtype_name(object_data->subtype) ); } if (object->condition != CONDITION_INDESTRUCTABLE) { render_text_at(C_FIELD_NAME, ++row, col, "Condition: "); render_text(C_FIELD_VALUE, "%d/%d", object->condition, object_data->condition_max ); } if (object_data->weight != WEIGHT_NIL) { render_text_at(C_FIELD_NAME, ++row, col, "Weight : "); render_text(C_FIELD_VALUE, "%d", object_data->weight); } if (object_data->value != VALUE_NIL) { render_text_at(C_FIELD_NAME, ++row, col, "Value : "); render_text(C_FIELD_VALUE, "%dc", object_data->value); } else if (object_data->type == OTYPE_MONEY) { render_text_at(C_FIELD_NAME, ++row, col, "Value : "); render_text(C_FIELD_VALUE, "%dc", object->charge); } switch (object_data->type) { case OTYPE_RANGED_COMBAT_WEAPON: render_object_screen_rcw(object, ++row, col); break; case OTYPE_CLOSE_COMBAT_WEAPON: render_object_screen_ccw(object, ++row, col); break; case OTYPE_ARMOUR: render_text_at(C_FIELD_NAME, row += 2, col, "%-15s: ", "Armour Value" ); render_text(C_FIELD_VALUE, "%d", object_data->armour_value); break; default: /* DO NOTHING */ ; } row = SEC_SCREEN_MIN_Y; col = SEC_SCREEN_MAX_X / 2 + SEC_SCREEN_MIN_X; render_object_attributes_at(row, col, object_data); render_text_at(C_HEADER, SEC_SCREEN_MAX_Y / 2 + 5, SEC_SCREEN_MIN_X, "[Description]" ); render_long_text(C_TEXT, SEC_SCREEN_MAX_Y / 2 + 6, SEC_SCREEN_MIN_X, object_static_data(object)->description, SEC_SCREEN_MAX_X ); } /* * renders the object attribute screen */ void render_object_attribute_screen(OBJECT_ATTRIBUTE attribute) { char description[DESCRIPTION_SIZE]; render_secondary_screen("-== Object Attribute ==-"); render_text_at(C_FIELD_NAME, SEC_SCREEN_MIN_Y, SEC_SCREEN_MIN_X, "Name: " ); render_text(C_FIELD_VALUE, "%s", object_attribute_name(attribute)); render_text_at(C_HEADER, SEC_SCREEN_MIN_Y + 2, SEC_SCREEN_MIN_X, "[Description]" ); render_long_text(C_TEXT, SEC_SCREEN_MIN_Y + 3, SEC_SCREEN_MIN_X, object_attribute_description(description, attribute), SEC_SCREEN_MAX_X ); } /* * renders the terrain screen */ void render_terrain_screen(const TERRAIN *terrain) { SCREEN_COORD row, col; const TERRAIN_DATA *terrain_data; TERRAIN_ATTRIBUTE i; render_secondary_screen("-== Terrain ==-"); terrain_data = terrain_static_data(terrain); row = SEC_SCREEN_MIN_Y; col = SEC_SCREEN_MIN_X; render_text_at(C_FIELD_NAME, row, col, "Name : "); render_text(C_FIELD_VALUE, terrain_data->name); row = SEC_SCREEN_MIN_Y; col = SEC_SCREEN_MAX_X / 2 + SEC_SCREEN_MIN_X; render_text_at(C_HEADER, row, col, "[Attributes]"); for (i = 0; i < MAX_TERRAIN_ATTRIBUTES; i++) { if (!terrain_data->attribute[i]) { continue; } render_text_at(C_TEXT, ++row, col, terrain_attribute_name(i) ); } render_text_at(C_HEADER, SEC_SCREEN_MAX_Y / 2 + 4, SEC_SCREEN_MIN_X, "[Description]" ); render_long_text(C_TEXT, SEC_SCREEN_MAX_Y / 2 + 5, SEC_SCREEN_MIN_X, terrain_static_data(terrain)->description, SEC_SCREEN_MAX_X ); } /* * renders the terrain attribute screen */ void render_terrain_attribute_screen(TERRAIN_ATTRIBUTE attribute) { char description[DESCRIPTION_SIZE]; render_secondary_screen("-== Terrain Attribute ==-"); render_text_at(C_FIELD_NAME, SEC_SCREEN_MIN_Y, SEC_SCREEN_MIN_X, "Name: " ); render_text(C_FIELD_VALUE, "%s", terrain_attribute_name(attribute)); render_text_at(C_HEADER, SEC_SCREEN_MIN_Y + 2, SEC_SCREEN_MIN_X, "[Description]" ); render_long_text(C_TEXT, SEC_SCREEN_MIN_Y + 3, SEC_SCREEN_MIN_X, terrain_attribute_description(description, attribute), SEC_SCREEN_MAX_X ); } /* * renders the psychic powers screen */ void render_psy_powers_screen(const CHARACTER *character) { render_secondary_screen("-== Psychic Powers ==-"); render_psy_powers(SID_CHARACTER, character); } /* * renders the psychic power screen */ void render_psy_power_screen(PSY_POWER power) { char description[DESCRIPTION_SIZE]; SCREEN_COORD y, x; render_secondary_screen("-== Psychic Power ==-"); y = SEC_SCREEN_MIN_Y; x = SEC_SCREEN_MIN_X; render_text_at(C_FIELD_NAME, y, x, "Name : "); render_text(C_FIELD_VALUE, "%s", psy_power_name(power)); render_text_at(C_FIELD_NAME, ++y, x, "Discipline: "); render_text(C_FIELD_VALUE, "%s", psy_discipline_name( psy_power_discipline(power) )); render_text_at(C_FIELD_NAME, ++y, x, "Difficulty: "); render_text(C_FIELD_VALUE, "%d", psy_power_difficulty(NULL, power)); y += 2; render_text_at(C_HEADER, y, x, "[Description]"); render_long_text(C_TEXT, ++y, x, psy_power_description(description, power), SEC_SCREEN_MAX_X ); } /* * renders the perk screen */ void render_perk_screen(PERK perk) { char description[DESCRIPTION_SIZE]; render_secondary_screen("-== Perk ==-"); render_text_at(C_FIELD_NAME, SEC_SCREEN_MIN_Y, SEC_SCREEN_MIN_X, "Name: " ); render_text(C_FIELD_VALUE, "%s", perk_name(perk)); render_text_at(C_HEADER, SEC_SCREEN_MIN_Y + 2, SEC_SCREEN_MIN_X, "[Description]" ); render_long_text(C_TEXT, SEC_SCREEN_MIN_Y + 3, SEC_SCREEN_MIN_X, perk_description(description, perk), SEC_SCREEN_MAX_X ); } /* * renders the additional information screen */ void render_additional_information_screen(void) { render_secondary_screen("-== Additional Information ==-"); } /* * additional information screen menu */ COMMAND additional_information_menu(MENU *menu) { SCREEN_AREA menu_area = { SEC_SCREEN_MIN_Y, MENU_AUTO, SEC_SCREEN_MIN_X, MENU_AUTO }; menu_set_appearance(menu, &menu_area); return menu_execute(menu, &menu_area); } /* * renders an entity info list screen */ void render_entity_info_list_screen(const char *title) { render_secondary_screen("-== %s ==-", title); } /* * entity info list menu */ COMMAND entity_info_list_menu(MENU *menu) { SCREEN_AREA menu_area = { SEC_SCREEN_MIN_Y, SEC_SCREEN_MAX_Y, SEC_SCREEN_MIN_X, MENU_AUTO }; menu_set_appearance(menu, &menu_area); return menu_execute(menu, &menu_area); } /* * renders the list of career exits */ static void render_career_exits_at(SCREEN_COORD y, SCREEN_COORD x, const CAREER *career ) { CAREER_EXIT_INDEX i; render_text_at(C_HEADER, y, x, "[Career Exits]"); place_cursor_at(++y, x); for (i = 0; i < MAX_CAREER_EXITS; i++) { if (is_empty_string(career->exit[i])) { break; } render_text_at(C_TEXT, y, x, career->exit[i]); ++y; } } /* * renders the career trappings */ static void render_trappings_at(SCREEN_COORD y, SCREEN_COORD x, const CAREER *career ) { OBJECT *object; LIST_NODE *node; render_text_at(C_HEADER, y, x, "[Trappings]"); for (node = career->trappings->head; node != NULL; node = node->next) { object = (OBJECT *)node->data; render_text_at(C_TEXT, ++y, x, "%s", object_static_data(object)->name ); } } /* * renders equipment */ static void render_equipment_at(SCREEN_COORD y, SCREEN_COORD x, const CHARACTER *character ) { LIST_NODE *node; render_text_at(C_HEADER, y, x, "[Equipment]"); for (node = character->inventory->head; node != NULL; node = node->next) { OBJECT *object; object = (OBJECT *)node->data; if (!object_in_use(character, object)) { continue; } ++y; place_cursor_at(y, x); render_inventory_object(C_TEXT, character, object, false ); } } /* * renders perks */ static void render_perks_at(SCREEN_COORD start_y, SCREEN_COORD start_x, SCREEN_COORD max_y, const bool *perk ) { SCREEN_COORD y, x; PERK i; y = start_y; x = start_x; for (i = 0; i < MAX_PERKS; i++) { if (!perk[i]) { continue; } if (y == max_y) { y = start_y; x = start_x + PERK_NAME_SIZE + 1; } render_text_at(C_TEXT, y, x, perk_name(i)); ++y; } } /* * renders an advance scheme */ static void render_advance_scheme_at(SCREEN_COORD y, SCREEN_COORD x, const CAREER *career ) { int i; for (i = 0; i < MAX_STATS; i++) { render_text_at(C_FIELD_NAME, y++, x, "%-13s: ", stat_long_name(i) ); if (career->max_stat_advance[i] > 0) { render_text(C_FIELD_VALUE, "+%d", career->max_stat_advance[i] ); } } } /* * renders psychic powers */ static void render_psy_powers(SCREEN_ID screen_id, const CHARACTER *character) { SCREEN_COORD row, col; int i; if (screen_id != SID_CHARACTER) { die("*** CORE ERROR *** invalid render mode (pp)"); } row = SEC_SCREEN_MIN_Y; col = SEC_SCREEN_MIN_X; for (i = 0; i < MAX_PSY_POWERS; i++) { if (!character->psy_power[i]) continue; render_text_at(C_TEXT, row++, col, "%s", psy_power_name(i) ); } } /* * renders the close combat weapon specific parts of an object screen */ static void render_object_screen_ccw(const OBJECT *object, SCREEN_COORD row, SCREEN_COORD col ) { const OBJECT_DATA *object_data; object_data = object_static_data(object); render_text_at(C_FIELD_NAME, ++row, col, "Damage : "); render_dice_roll(C_FIELD_VALUE, &object_data->damage); render_text_at(C_FIELD_NAME, ++row, col, "Reach : "); render_text(C_FIELD_VALUE, "%d", object_data->reach); if (!object_has_attribute(object, OA_NO_PARRY)) { render_text_at(C_FIELD_NAME, ++row, col, "Parry Penalty: "); render_text(C_FIELD_VALUE, "%d", object_data->parry_penalty); } } /* * renders the ranged combat weapon specific parts of an object screen */ static void render_object_screen_rcw(const OBJECT *object, SCREEN_COORD row, SCREEN_COORD col ) { const OBJECT_DATA *object_data; object_data = object_static_data(object); render_text_at(C_FIELD_NAME, ++row, col, "Damage : "); render_dice_roll(C_FIELD_VALUE, &object_data->damage); render_text_at(C_FIELD_NAME, ++row, col, "Shots : "); render_text(C_FIELD_VALUE, "%d/%d", object->charge, object_data->charge_max ); render_text_at(C_FIELD_NAME, ++row, col, "Reload : "); render_text(C_FIELD_VALUE, "%d", object_data->reload); render_text_at(C_FIELD_NAME, ++row, col, "Firing Mode : "); render_firing_mode_at(C_FIELD_VALUE, cursor_y(), cursor_x(), object ); if (object_data->firing_mode.accuracy != 0) { render_text_at(C_FIELD_NAME, ++row, col, "Accuracy Mod.: "); if (object_data->firing_mode.accuracy > 0) { render_char(C_FIELD_VALUE, '+'); } render_text(C_FIELD_VALUE, "%d", object_data->firing_mode.accuracy ); } } /* * renders a firing mode */ static void render_firing_mode_at(COLOUR colour, SCREEN_COORD y, SCREEN_COORD x, const OBJECT *object ) { const FIRING_MODE_DATA *firing_mode; int n_modes = 0; place_cursor_at(y, x); firing_mode = &(object_static_data(object)->firing_mode); if (firing_mode->has[FMODE_S]) { render_text(colour, firing_mode_name(FMODE_S)); ++n_modes; } if (firing_mode->has[FMODE_SA]) { if (n_modes > 0) render_char(colour, ','); render_text(colour, "SA"); if (firing_mode->min_sa_shots == firing_mode->max_sa_shots) { render_text(colour, "(%d)", firing_mode->max_sa_shots ); } else { render_text(colour, "(%d/%d)", firing_mode->min_sa_shots, firing_mode->max_sa_shots ); } ++n_modes; } if (firing_mode->has[FMODE_A]) { if (n_modes > 0) { render_char(colour, ','); } render_text(colour, "A(%d)", firing_mode->a_shots ); } } /* * renders the attributes of an object */ static void render_object_attributes_at(SCREEN_COORD row, SCREEN_COORD col, const OBJECT_DATA *object_data ) { OBJECT_ATTRIBUTE i; render_text_at(C_HEADER, row, col, "[Attributes]"); for (i = 0; i < MAX_OBJECT_ATTRIBUTES; i++) { if (!object_data->attribute[i]) { continue; } render_text_at(C_TEXT, ++row, col, object_attribute_name(i) ); } }