mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 20:58:07 +03:00
tr1/stats: change the detailed stats option to three modes
Resolves #2658. The three stat options include: minimal: kills, pickups, secrets, time detailed: minimal and max pickup and max kill count full: detailed and ammo hits/used, health packs used, distance
This commit is contained in:
parent
9424083dd8
commit
66d1b59330
12 changed files with 95 additions and 50 deletions
|
@ -5,10 +5,11 @@
|
||||||
- added support for `-s`/`--save` argument to immediately start a saved game
|
- added support for `-s`/`--save` argument to immediately start a saved game
|
||||||
- added support for custom levels to use `disable_floor` in the gameflow, similar to TR2's Floating Islands (#2541)
|
- added support for custom levels to use `disable_floor` in the gameflow, similar to TR2's Floating Islands (#2541)
|
||||||
- added drawing of object mesh spheres to the `/debug` console command
|
- added drawing of object mesh spheres to the `/debug` console command
|
||||||
- added TR2+ stats if the detailed stats option is enabled (#2561):
|
- added TR2+ stats if the full stat detail mode option is enabled (#2561):
|
||||||
- ammo hits / used
|
- ammo hits / used
|
||||||
- health packs used
|
- health packs used
|
||||||
- distance travelled
|
- distance travelled
|
||||||
|
- added a TR2+ style bordered stat box to the end of level stats if the full stat detail mode option is enabled (#2658)
|
||||||
- changed the Controls screen to hide the reset and unbind texts when changing a key (#2103)
|
- changed the Controls screen to hide the reset and unbind texts when changing a key (#2103)
|
||||||
- changed injections to a new file format with a smaller footprint and improved applicability tests (#1967)
|
- changed injections to a new file format with a smaller footprint and improved applicability tests (#1967)
|
||||||
- changed the `/pos` command to show `Demo` and `Cutscene` instead of `Level` when relevant
|
- changed the `/pos` command to show `Demo` and `Cutscene` instead of `Level` when relevant
|
||||||
|
|
|
@ -507,6 +507,7 @@ Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for det
|
||||||
- ammo hits / used
|
- ammo hits / used
|
||||||
- health packs used
|
- health packs used
|
||||||
- distance travelled
|
- distance travelled
|
||||||
|
- added an optional TR2+ style bordered stat box to the end of level stats
|
||||||
|
|
||||||
#### Visuals
|
#### Visuals
|
||||||
- added quadrilateral texture correction
|
- added quadrilateral texture correction
|
||||||
|
|
|
@ -3,7 +3,7 @@ CFG_BOOL(g_Config, gameplay.disable_medpacks, false)
|
||||||
CFG_BOOL(g_Config, gameplay.disable_magnums, false)
|
CFG_BOOL(g_Config, gameplay.disable_magnums, false)
|
||||||
CFG_BOOL(g_Config, gameplay.disable_uzis, false)
|
CFG_BOOL(g_Config, gameplay.disable_uzis, false)
|
||||||
CFG_BOOL(g_Config, gameplay.disable_shotgun, false)
|
CFG_BOOL(g_Config, gameplay.disable_shotgun, false)
|
||||||
CFG_BOOL(g_Config, gameplay.enable_detailed_stats, true)
|
CFG_ENUM(g_Config, gameplay.stat_detail_mode, SDM_FULL, STAT_DETAIL_MODE)
|
||||||
CFG_BOOL(g_Config, gameplay.enable_deaths_counter, true)
|
CFG_BOOL(g_Config, gameplay.enable_deaths_counter, true)
|
||||||
CFG_BOOL(g_Config, gameplay.enable_enhanced_look, true)
|
CFG_BOOL(g_Config, gameplay.enable_enhanced_look, true)
|
||||||
CFG_BOOL(g_Config, visuals.enable_gun_lighting, true)
|
CFG_BOOL(g_Config, visuals.enable_gun_lighting, true)
|
||||||
|
|
|
@ -99,12 +99,19 @@ static DECLARE_GF_EVENT_HANDLER(M_HandleLevelStats)
|
||||||
if (seq_ctx != GFSC_NORMAL) {
|
if (seq_ctx != GFSC_NORMAL) {
|
||||||
return gf_cmd;
|
return gf_cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if TR_VERSION == 1
|
||||||
|
const bool use_bare_style = g_Config.gameplay.stat_detail_mode != SDM_FULL;
|
||||||
|
#else
|
||||||
|
const bool use_bare_style = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
PHASE *const phase = Phase_Stats_Create((PHASE_STATS_ARGS) {
|
PHASE *const phase = Phase_Stats_Create((PHASE_STATS_ARGS) {
|
||||||
.background_type =
|
.background_type =
|
||||||
(TR_VERSION == 1 || Game_IsInGym()) ? BK_TRANSPARENT : BK_OBJECT,
|
(TR_VERSION == 1 || Game_IsInGym()) ? BK_TRANSPARENT : BK_OBJECT,
|
||||||
.level_num = -1,
|
.level_num = -1,
|
||||||
.show_final_stats = false,
|
.show_final_stats = false,
|
||||||
.use_bare_style = TR_VERSION == 1,
|
.use_bare_style = use_bare_style,
|
||||||
});
|
});
|
||||||
gf_cmd = PhaseExecutor_Run(phase);
|
gf_cmd = PhaseExecutor_Run(phase);
|
||||||
Phase_Stats_Destroy(phase);
|
Phase_Stats_Destroy(phase);
|
||||||
|
|
|
@ -63,6 +63,12 @@ typedef enum {
|
||||||
UI_STYLE_PC,
|
UI_STYLE_PC,
|
||||||
} UI_STYLE;
|
} UI_STYLE;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SDM_MINIMAL,
|
||||||
|
SDM_DETAILED,
|
||||||
|
SDM_FULL,
|
||||||
|
} STAT_DETAIL_MODE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool loaded;
|
bool loaded;
|
||||||
|
|
||||||
|
@ -148,7 +154,7 @@ typedef struct {
|
||||||
bool enable_eidos_logo;
|
bool enable_eidos_logo;
|
||||||
bool enable_loading_screens;
|
bool enable_loading_screens;
|
||||||
bool enable_cine;
|
bool enable_cine;
|
||||||
bool enable_detailed_stats;
|
STAT_DETAIL_MODE stat_detail_mode;
|
||||||
bool enable_walk_to_items;
|
bool enable_walk_to_items;
|
||||||
bool enable_enhanced_saves;
|
bool enable_enhanced_saves;
|
||||||
bool enable_jump_twists;
|
bool enable_jump_twists;
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
|
|
||||||
#define ROW_HEIGHT_BARE 25
|
#define ROW_HEIGHT_BARE 25
|
||||||
#define ROW_HEIGHT_BORDERED 18
|
#define ROW_HEIGHT_BORDERED 18
|
||||||
#define ROW_WIDTH_BORDERED 315
|
#define ROW_WIDTH_BORDERED 200
|
||||||
|
#define ROW_WIDTH_BORDERED_FULL 315
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
M_ROW_KILLS,
|
M_ROW_KILLS,
|
||||||
|
@ -119,8 +120,11 @@ static void M_AddRow(
|
||||||
UI_STACK_LAYOUT_HORIZONTAL, UI_STACK_AUTO_SIZE, row_height);
|
UI_STACK_LAYOUT_HORIZONTAL, UI_STACK_AUTO_SIZE, row_height);
|
||||||
} else {
|
} else {
|
||||||
row_height = ROW_HEIGHT_BORDERED;
|
row_height = ROW_HEIGHT_BORDERED;
|
||||||
row->stack = UI_Stack_Create(
|
const int32_t row_width = g_Config.gameplay.stat_detail_mode == SDM_FULL
|
||||||
UI_STACK_LAYOUT_HORIZONTAL, ROW_WIDTH_BORDERED, row_height);
|
? ROW_WIDTH_BORDERED_FULL
|
||||||
|
: ROW_WIDTH_BORDERED;
|
||||||
|
row->stack =
|
||||||
|
UI_Stack_Create(UI_STACK_LAYOUT_HORIZONTAL, row_width, row_height);
|
||||||
UI_Stack_SetHAlign(row->stack, UI_STACK_H_ALIGN_DISTRIBUTE);
|
UI_Stack_SetHAlign(row->stack, UI_STACK_H_ALIGN_DISTRIBUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,9 +148,10 @@ static void M_AddRowFromRole(
|
||||||
const STATS_COMMON *const stats, const GAME_INFO *const game_info)
|
const STATS_COMMON *const stats, const GAME_INFO *const game_info)
|
||||||
{
|
{
|
||||||
char buf[50];
|
char buf[50];
|
||||||
const char *const num_fmt = g_Config.gameplay.enable_detailed_stats
|
const char *const num_fmt =
|
||||||
? GS(STATS_DETAIL_FMT)
|
g_Config.gameplay.stat_detail_mode == SDM_MINIMAL
|
||||||
: GS(STATS_BASIC_FMT);
|
? GS(STATS_BASIC_FMT)
|
||||||
|
: GS(STATS_DETAIL_FMT);
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case M_ROW_KILLS:
|
case M_ROW_KILLS:
|
||||||
|
@ -207,36 +212,31 @@ static void M_AddCommonRows(
|
||||||
UI_STATS_DIALOG *const self, const STATS_COMMON *const stats,
|
UI_STATS_DIALOG *const self, const STATS_COMMON *const stats,
|
||||||
const GAME_INFO *const game_info)
|
const GAME_INFO *const game_info)
|
||||||
{
|
{
|
||||||
if (g_Config.gameplay.enable_detailed_stats) {
|
if (g_Config.gameplay.stat_detail_mode == SDM_MINIMAL) {
|
||||||
M_AddRowFromRole(self, M_ROW_TIMER, stats, game_info);
|
|
||||||
M_AddRowFromRole(self, M_ROW_SECRETS, stats, game_info);
|
|
||||||
M_AddRowFromRole(self, M_ROW_PICKUPS, stats, game_info);
|
|
||||||
M_AddRowFromRole(self, M_ROW_KILLS, stats, game_info);
|
M_AddRowFromRole(self, M_ROW_KILLS, stats, game_info);
|
||||||
M_AddRowFromRole(self, M_ROW_AMMO, stats, game_info);
|
M_AddRowFromRole(self, M_ROW_PICKUPS, stats, game_info);
|
||||||
M_AddRowFromRole(self, M_ROW_MEDIPACKS_USED, stats, game_info);
|
M_AddRowFromRole(self, M_ROW_SECRETS, stats, game_info);
|
||||||
M_AddRowFromRole(self, M_ROW_DISTANCE_TRAVELLED, stats, game_info);
|
M_AddRowFromRole(self, M_ROW_TIMER, stats, game_info);
|
||||||
if (g_Config.gameplay.enable_deaths_counter
|
|
||||||
&& game_info->death_count >= 0) {
|
|
||||||
// Always use sum of all levels for the deaths.
|
|
||||||
// Deaths get stored in the resume info for the level they happen
|
|
||||||
// on, so if the player dies in Vilcabamba and reloads Caves, they
|
|
||||||
// should still see an incremented death counter.
|
|
||||||
M_AddRowFromRole(self, M_ROW_DEATHS, stats, game_info);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
M_AddRowFromRole(self, M_ROW_KILLS, stats, game_info);
|
|
||||||
M_AddRowFromRole(self, M_ROW_PICKUPS, stats, game_info);
|
|
||||||
M_AddRowFromRole(self, M_ROW_SECRETS, stats, game_info);
|
|
||||||
M_AddRowFromRole(self, M_ROW_TIMER, stats, game_info);
|
M_AddRowFromRole(self, M_ROW_TIMER, stats, game_info);
|
||||||
if (g_Config.gameplay.enable_deaths_counter
|
M_AddRowFromRole(self, M_ROW_SECRETS, stats, game_info);
|
||||||
&& game_info->death_count >= 0) {
|
M_AddRowFromRole(self, M_ROW_PICKUPS, stats, game_info);
|
||||||
// Always use sum of all levels for the deaths.
|
M_AddRowFromRole(self, M_ROW_KILLS, stats, game_info);
|
||||||
// Deaths get stored in the resume info for the level they happen
|
if (g_Config.gameplay.stat_detail_mode == SDM_FULL) {
|
||||||
// on, so if the player dies in Vilcabamba and reloads Caves, they
|
M_AddRowFromRole(self, M_ROW_AMMO, stats, game_info);
|
||||||
// should still see an incremented death counter.
|
M_AddRowFromRole(self, M_ROW_MEDIPACKS_USED, stats, game_info);
|
||||||
M_AddRowFromRole(self, M_ROW_DEATHS, stats, game_info);
|
M_AddRowFromRole(self, M_ROW_DISTANCE_TRAVELLED, stats, game_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_Config.gameplay.enable_deaths_counter
|
||||||
|
&& game_info->death_count >= 0) {
|
||||||
|
// Always use sum of all levels for the deaths.
|
||||||
|
// Deaths get stored in the resume info for the level they happen
|
||||||
|
// on, so if the player dies in Vilcabamba and reloads Caves, they
|
||||||
|
// should still see an incremented death counter.
|
||||||
|
M_AddRowFromRole(self, M_ROW_DEATHS, stats, game_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void M_AddLevelStatsRows(UI_STATS_DIALOG *const self)
|
static void M_AddLevelStatsRows(UI_STATS_DIALOG *const self)
|
||||||
|
|
|
@ -33,3 +33,7 @@ ENUM_MAP_DEFINE(TARGET_LOCK_MODE, TLM_NONE, "no-lock")
|
||||||
ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_NEVER, "never")
|
ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_NEVER, "never")
|
||||||
ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_NON_AMBIENT, "non-ambient")
|
ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_NON_AMBIENT, "non-ambient")
|
||||||
ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_ALWAYS, "always")
|
ENUM_MAP_DEFINE(MUSIC_LOAD_CONDITION, MUSIC_LOAD_ALWAYS, "always")
|
||||||
|
|
||||||
|
ENUM_MAP_DEFINE(STAT_DETAIL_MODE, SDM_MINIMAL, "minimal")
|
||||||
|
ENUM_MAP_DEFINE(STAT_DETAIL_MODE, SDM_DETAILED, "detailed")
|
||||||
|
ENUM_MAP_DEFINE(STAT_DETAIL_MODE, SDM_FULL, "full")
|
||||||
|
|
|
@ -58,6 +58,11 @@
|
||||||
"never": "Never",
|
"never": "Never",
|
||||||
"non-ambient": "Non-ambient",
|
"non-ambient": "Non-ambient",
|
||||||
"always": "Always"
|
"always": "Always"
|
||||||
|
},
|
||||||
|
"stat_mode": {
|
||||||
|
"minimal": "Minimal",
|
||||||
|
"detailed": "Detailed",
|
||||||
|
"full": "Full"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
@ -229,9 +234,9 @@
|
||||||
"Title": "Level statistics in compass",
|
"Title": "Level statistics in compass",
|
||||||
"Description": "Enables showing level statistics when the compass is selected."
|
"Description": "Enables showing level statistics when the compass is selected."
|
||||||
},
|
},
|
||||||
"enable_detailed_stats": {
|
"stat_detail_mode": {
|
||||||
"Title": "Show detailed stats",
|
"Title": "Stat detail mode",
|
||||||
"Description": "Enables showing the maximum pickup count and kill count on each level, ammo hits, ammo used, health packs used, and distance travelled."
|
"Description": "Allows various levels of stat detail.\n- Minimal: shows kills, pickups, secrets, and time taken.\n- Detailed: shows all stats from minimal as well as the maximum pickup count and kill count of each level.\n- Full: shows all stats from detailed as well as ammo hits, ammo used, health packs used, and distance travelled."
|
||||||
},
|
},
|
||||||
"enable_cine": {
|
"enable_cine": {
|
||||||
"Title": "Enable cutscenes",
|
"Title": "Enable cutscenes",
|
||||||
|
|
|
@ -69,6 +69,11 @@
|
||||||
"never": "Nunca",
|
"never": "Nunca",
|
||||||
"non-ambient": "No ambiental",
|
"non-ambient": "No ambiental",
|
||||||
"always": "Siempre"
|
"always": "Siempre"
|
||||||
|
},
|
||||||
|
"stat_mode": {
|
||||||
|
"minimal": "Mínimo",
|
||||||
|
"detailed": "Detallado",
|
||||||
|
"full": "Completo"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
@ -164,9 +169,9 @@
|
||||||
"Title": "Habilitar modo de demostración",
|
"Title": "Habilitar modo de demostración",
|
||||||
"Description": "Habilita las demostraciones que se muestran en el menú principal."
|
"Description": "Habilita las demostraciones que se muestran en el menú principal."
|
||||||
},
|
},
|
||||||
"enable_detailed_stats": {
|
"stat_detail_mode": {
|
||||||
"Title": "Mostrar total de objetos y muertes",
|
"Title": "Modo de estadísticas detalladas",
|
||||||
"Description": "Permite mostrar el recuento máximo de recogidas y muertes en cada nivel, los impactos de munición, la munición utilizada, los paquetes de salud utilizados y la distancia recorrida."
|
"Description": "Permite varios niveles de detalle de estadísticas.\n- Mínimo: muestra muertes, recogidas, secretos y tiempo empleado.\n- Detallado: muestra todas las estadísticas de mínimo así como el recuento máximo de recogidas y muertes de cada nivel.\n- Completo: muestra todas las estadísticas de detailed así como impactos de munición, munición usada, paquetes de salud usados y distancia recorrida."
|
||||||
},
|
},
|
||||||
"enemy_healthbar_show_mode": {
|
"enemy_healthbar_show_mode": {
|
||||||
"Title": "Mostrar barra de salud enemiga",
|
"Title": "Mostrar barra de salud enemiga",
|
||||||
|
|
|
@ -69,6 +69,11 @@
|
||||||
"never": "Jamais",
|
"never": "Jamais",
|
||||||
"non-ambient": "Non ambiant",
|
"non-ambient": "Non ambiant",
|
||||||
"always": "Toujours"
|
"always": "Toujours"
|
||||||
|
},
|
||||||
|
"stat_mode": {
|
||||||
|
"minimal": "Minime",
|
||||||
|
"detailed": "Détaillée",
|
||||||
|
"full": "Complet"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
@ -240,9 +245,9 @@
|
||||||
"Title": "Statistiques de niveau dans la boussole",
|
"Title": "Statistiques de niveau dans la boussole",
|
||||||
"Description": "Active l'affichage des statistiques de niveau lorsque la boussole est sélectionnée."
|
"Description": "Active l'affichage des statistiques de niveau lorsque la boussole est sélectionnée."
|
||||||
},
|
},
|
||||||
"enable_detailed_stats": {
|
"stat_detail_mode": {
|
||||||
"Title": "Afficher le nombre total de victimes et de collectibles",
|
"Title": "Mode détail Stat",
|
||||||
"Description": "Permet d'afficher le nombre maximum de ramassages et de tués à chaque niveau, le nombre de munitions, les munitions utilisées, les trousses de santé utilisées et la distance parcourue."
|
"Description": "Permet différents niveaux de détail des statistiques.\n- Minime: indique les tués, les ramassages, les secrets et le temps passé.\n- Détaillée: indique toutes les statistiques de nu ainsi que le nombre maximum de ramassages et de tués pour chaque niveau.\n- Complet: indique toutes les statistiques de détaillé ainsi que les munitions touchées, les munitions utilisées, les trousses de santé utilisées et la distance parcourue."
|
||||||
},
|
},
|
||||||
"enable_cine": {
|
"enable_cine": {
|
||||||
"Title": "Activer les cutscenes",
|
"Title": "Activer les cutscenes",
|
||||||
|
|
|
@ -69,6 +69,11 @@
|
||||||
"never": "Mai",
|
"never": "Mai",
|
||||||
"non-ambient": "Non ambientale",
|
"non-ambient": "Non ambientale",
|
||||||
"always": "Sempre"
|
"always": "Sempre"
|
||||||
|
},
|
||||||
|
"stat_mode": {
|
||||||
|
"minimal": "Minimo",
|
||||||
|
"detailed": "Dettagliato",
|
||||||
|
"full": "Completo"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Properties": {
|
"Properties": {
|
||||||
|
@ -240,9 +245,9 @@
|
||||||
"Title": "Statistiche del livello nella bussola",
|
"Title": "Statistiche del livello nella bussola",
|
||||||
"Description": "Abilita la visualizzazione delle statistiche del livello quando è selezionata la bussola."
|
"Description": "Abilita la visualizzazione delle statistiche del livello quando è selezionata la bussola."
|
||||||
},
|
},
|
||||||
"enable_detailed_stats": {
|
"stat_detail_mode": {
|
||||||
"Title": "Mostra il numero totale di uccisioni e oggetti",
|
"Title": "Modalità di visualizzazione delle statistiche",
|
||||||
"Description": "Consente di visualizzare il numero massimo di prelievi e di uccisioni in ogni livello, i colpi delle munizioni, le munizioni utilizzate, i pacchetti salute utilizzati e la distanza percorsa."
|
"Description": "Consente di scegliere tra vari livelli di dettaglio per la visualizzazione delle statistiche.\n- Minimo: mostra le uccisioni, gli oggetti raccolti, i segreti e il tempo impiegato per completare il livello.\n- Dettagliato: mostra tutte le statistiche della modalità 'Minimo' e, in aggiunta, il numero massimo di uccisioni e di oggetti recuperabili di ogni livello.\n- Completo: mostra tutte le statistiche della modalità 'Dettagliato' e, in aggiunta, i colpi andati a segno, le munizioni utilizzate, i kit medici adoperati e la distanza percorsa."
|
||||||
},
|
},
|
||||||
"enable_cine": {
|
"enable_cine": {
|
||||||
"Title": "Abilita le scene di intermezzo",
|
"Title": "Abilita le scene di intermezzo",
|
||||||
|
|
|
@ -62,6 +62,11 @@
|
||||||
"never",
|
"never",
|
||||||
"non-ambient",
|
"non-ambient",
|
||||||
"always"
|
"always"
|
||||||
|
],
|
||||||
|
"stat_mode": [
|
||||||
|
"minimal",
|
||||||
|
"detailed",
|
||||||
|
"full"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"CategorisedProperties": [
|
"CategorisedProperties": [
|
||||||
|
@ -303,9 +308,10 @@
|
||||||
"DefaultValue": true
|
"DefaultValue": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Field": "enable_detailed_stats",
|
"Field": "stat_detail_mode",
|
||||||
"DataType": "Bool",
|
"DataType": "Enum",
|
||||||
"DefaultValue": true
|
"EnumKey": "stat_mode",
|
||||||
|
"DefaultValue": "full"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Field": "enable_cine",
|
"Field": "enable_cine",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue