mirror of https://github.com/nmlgc/ReC98.git
[Decompilation] [th04/th05] Text popups
The bullet update function really needs this one declared in C land to link without a fixup overflow? Guess we'll have another technical debt push before then… Part of P0148, funded by [Anonymous].
This commit is contained in:
parent
e6e3c97eb3
commit
3a41604314
|
@ -0,0 +1,2 @@
|
|||
#define HUD_LEFT 56
|
||||
#define BAR_MAX 128
|
|
@ -6,6 +6,7 @@
|
|||
#include "th04/gaiji/bar.h"
|
||||
|
||||
typedef enum {
|
||||
g_NULL = '\0',
|
||||
g_EMPTY = 0x02,
|
||||
gaiji_bar(0x20),
|
||||
gaiji_bar_max(0x30),
|
||||
|
|
|
@ -5,6 +5,17 @@
|
|||
// Renders the "Enemy!!" caption and the HP bar, showing the given [bar_value]
|
||||
// between 0 and BAR_MAX.
|
||||
void pascal hud_hp_put(int bar_value);
|
||||
|
||||
#if (GAME == 5)
|
||||
// Prints [points] using the bold gaiji font, right-aligned at
|
||||
// ([left+8], [y]),
|
||||
// in white, using up to 7 digits (8 if the "continue" digit is included).
|
||||
// Larger numbers will overflow the most significant digit into the A-Z
|
||||
// range.
|
||||
void pascal hud_points_put(
|
||||
utram_x_t left, utram_y_t y, unsigned long points
|
||||
);
|
||||
#endif
|
||||
// ---------
|
||||
|
||||
// High-level
|
||||
|
|
|
@ -1,188 +1,7 @@
|
|||
public POPUP_UPDATE_AND_RENDER
|
||||
popup_update_and_render proc near
|
||||
|
||||
@@i = byte ptr -1
|
||||
|
||||
enter 2, 0
|
||||
mov al, _popup_id_new
|
||||
cmp al, _popup_id_cur
|
||||
jz short @@needs_init?
|
||||
cmp _popup_frame, 64
|
||||
jb short @@needs_init?
|
||||
call text_putsa pascal, (PLAYFIELD_TRAM_LEFT shl 16) + POPUP_TRAM_Y, _PLAYFIELD_BLANK_ROW, TX_WHITE
|
||||
call text_putsa pascal, (PLAYFIELD_TRAM_LEFT shl 16) + 23, _PLAYFIELD_BLANK_ROW, TX_WHITE
|
||||
mov _popup_frame, 0
|
||||
|
||||
@@needs_init?:
|
||||
cmp _popup_frame, 0
|
||||
jnz short @@done?
|
||||
mov al, _popup_id_new
|
||||
mov _popup_id_cur, al
|
||||
mov [bp+@@i], 0
|
||||
jmp short @@shiftbuf_init_more?
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
@@shiftbuf_init_loop:
|
||||
mov al, [bp+@@i]
|
||||
mov ah, 0
|
||||
mov bx, ax
|
||||
mov _popup_shiftbuf[bx], g_EMPTY
|
||||
inc [bp+@@i]
|
||||
|
||||
@@shiftbuf_init_more?:
|
||||
cmp [bp+@@i], POPUP_LEN
|
||||
jb short @@shiftbuf_init_loop
|
||||
mov al, _popup_id_cur
|
||||
mov ah, 0
|
||||
shl ax, 2
|
||||
mov bx, ax
|
||||
pushd _POPUP_STRINGS[bx]
|
||||
call _strlen
|
||||
add sp, 4
|
||||
mov _popup_gaiji_len, ax
|
||||
mov bx, _popup_gaiji_len
|
||||
mov _popup_shiftbuf[bx], 0
|
||||
add ax, ax
|
||||
mov dx, PLAYFIELD_TRAM_LEFT + PLAYFIELD_TRAM_W
|
||||
sub dx, ax
|
||||
mov _popup_cur_tram_x, dx
|
||||
cmp _popup_id_new, POPUP_ID_BONUS
|
||||
jz short @@enforce_bonus_text_width
|
||||
mov ax, PLAYFIELD_TRAM_LEFT + (PLAYFIELD_TRAM_W / 2)
|
||||
sub ax, _popup_gaiji_len
|
||||
mov _popup_dest_tram_x, ax
|
||||
jmp short @@finish_init
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
; Since we print the number of points separately...
|
||||
@@enforce_bonus_text_width:
|
||||
mov _popup_dest_tram_x, 16
|
||||
|
||||
@@finish_init:
|
||||
mov _popup_dest_reached, 0
|
||||
|
||||
@@done?:
|
||||
cmp _popup_frame, POPUP_DURATION
|
||||
jb short @@shift_needed?
|
||||
call text_putsa pascal, (PLAYFIELD_TRAM_LEFT shl 16) + POPUP_TRAM_Y, _PLAYFIELD_BLANK_ROW, TX_WHITE
|
||||
mov _popup_frame, 0
|
||||
mov _popup, offset nullfunc_near
|
||||
leave
|
||||
retn
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
@@shift_needed?:
|
||||
mov al, _popup_frame
|
||||
mov ah, 0
|
||||
mov dx, _popup_gaiji_len
|
||||
dec dx
|
||||
cmp ax, dx
|
||||
jge short @@use_unshifted_string
|
||||
mov [bp+@@i], 0
|
||||
jmp short @@shift_more?
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
@@shift_loop:
|
||||
mov al, [bp+@@i]
|
||||
mov ah, 0
|
||||
mov bx, ax
|
||||
mov al, _popup_shiftbuf[bx+1]
|
||||
mov dl, [bp+@@i]
|
||||
mov dh, 0
|
||||
mov bx, dx
|
||||
mov _popup_shiftbuf[bx], al
|
||||
inc [bp+@@i]
|
||||
|
||||
@@shift_more?:
|
||||
mov al, [bp+@@i]
|
||||
mov ah, 0
|
||||
mov dx, _popup_gaiji_len
|
||||
dec dx
|
||||
cmp ax, dx
|
||||
jl short @@shift_loop
|
||||
mov al, _popup_id_cur
|
||||
mov ah, 0
|
||||
shl ax, 2
|
||||
mov bx, ax
|
||||
les bx, _POPUP_STRINGS[bx]
|
||||
assume es:nothing
|
||||
mov al, _popup_frame
|
||||
mov ah, 0
|
||||
add bx, ax
|
||||
mov al, es:[bx]
|
||||
mov bx, offset _popup_shiftbuf
|
||||
dec bx
|
||||
add bx, _popup_gaiji_len
|
||||
mov [bx], al
|
||||
call gaiji_putsa pascal, _popup_cur_tram_x, POPUP_TRAM_Y, ds, offset _popup_shiftbuf, TX_WHITE
|
||||
jmp @@ret
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
@@use_unshifted_string:
|
||||
mov ax, _popup_cur_tram_x
|
||||
cmp ax, _popup_dest_tram_x
|
||||
jle short @@dest_reached
|
||||
push ax
|
||||
push 2
|
||||
mov al, _popup_id_cur
|
||||
mov ah, 0
|
||||
shl ax, 2
|
||||
mov bx, ax
|
||||
pushd _POPUP_STRINGS[bx]
|
||||
push TX_WHITE
|
||||
call gaiji_putsa
|
||||
mov ax, _popup_gaiji_len
|
||||
add ax, ax
|
||||
add ax, _popup_cur_tram_x
|
||||
cmp ax, PLAYFIELD_TRAM_LEFT + PLAYFIELD_TRAM_W - GAIJI_TRAM_W
|
||||
jg short @@still_shifting
|
||||
mov ax, _popup_gaiji_len
|
||||
add ax, ax
|
||||
add ax, _popup_cur_tram_x
|
||||
call text_putca pascal, ax, (POPUP_TRAM_Y shl 16) or ' ', TX_WHITE
|
||||
|
||||
@@still_shifting:
|
||||
sub _popup_cur_tram_x, GAIJI_TRAM_W
|
||||
jmp short @@ret
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
@@dest_reached:
|
||||
cmp _popup_dest_reached, 0
|
||||
jnz short @@put_regular
|
||||
mov _popup_dest_reached, 1
|
||||
call text_putsa pascal, (PLAYFIELD_TRAM_LEFT shl 16) + POPUP_TRAM_Y, _PLAYFIELD_BLANK_ROW, TX_WHITE
|
||||
|
||||
@@put_regular:
|
||||
push _popup_dest_tram_x
|
||||
push POPUP_TRAM_Y
|
||||
mov al, _popup_id_cur
|
||||
mov ah, 0
|
||||
shl ax, 2
|
||||
mov bx, ax
|
||||
pushd _POPUP_STRINGS[bx]
|
||||
push TX_WHITE
|
||||
call gaiji_putsa
|
||||
cmp _popup_id_cur, POPUP_ID_BONUS
|
||||
jnz short @@ret
|
||||
if GAME eq 5
|
||||
call hud_points_put pascal, ((PLAYFIELD_TRAM_LEFT + (PLAYFIELD_TRAM_W / 2)) shl 16) + 2, large [_popup_bonus]
|
||||
else
|
||||
call popup_points_put pascal, large [_popup_bonus]
|
||||
endif
|
||||
|
||||
@@ret:
|
||||
inc _popup_frame
|
||||
leave
|
||||
retn
|
||||
popup_update_and_render endp
|
||||
|
||||
|
||||
if GAME eq 4
|
||||
; Yes, specific to the bonus popup, due to the hardcoded position.
|
||||
|
||||
; void pascal near popup_points_put(unsigned long points);
|
||||
public POPUP_POINTS_PUT
|
||||
popup_points_put proc pascal near
|
||||
public POPUP_PUT_POINTS_TH04
|
||||
popup_put_points_th04 proc pascal near
|
||||
arg @@points:dword
|
||||
local @@digit:dword, @@divisor:dword, @@buf:byte:SCORE_DIGITS + 2 ; padding...
|
||||
|
||||
|
@ -240,5 +59,5 @@ popup_points_put proc pascal near
|
|||
pop di
|
||||
pop si
|
||||
ret
|
||||
popup_points_put endp
|
||||
popup_put_points_th04 endp
|
||||
endif
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "th04/main/playfld.hpp"
|
||||
#include "th04/main/tile/tile.hpp"
|
||||
#include "th04/main/scroll.hpp"
|
||||
#include "th04/main/hud/hud.h"
|
||||
#include "th04/main/hud/popup.hpp"
|
||||
#include "th04/main/stage/stage.hpp"
|
||||
#include "th04/main/item/items.hpp"
|
||||
|
@ -25,6 +26,13 @@ void pascal near tiles_invalidate_around(
|
|||
subpixel_t center_y, subpixel_t center_x
|
||||
);
|
||||
|
||||
// MODDERS: Keep this up-to-date!
|
||||
static const unsigned int POPUP_STRING_MAX_LEN = 8;
|
||||
|
||||
extern const gaiji_th04_t* POPUP_STRINGS[];
|
||||
|
||||
extern const char* PLAYFIELD_BLANK_ROW;
|
||||
|
||||
/// Stage and BGM titles
|
||||
/// --------------------
|
||||
extern unsigned char popup_dissolve_sprite;
|
||||
|
@ -50,6 +58,7 @@ extern const char gEXTRA_STAGE[12];
|
|||
#define STAGE_NUM_CENTER_Y 168
|
||||
#define STAGE_TITLE_CENTER_Y 200
|
||||
#define BGM_CENTER_Y 360
|
||||
static const tram_y_t POPUP_TRAM_Y = (PLAYFIELD_TRAM_TOP + 1);
|
||||
|
||||
#define POPUP_FRAMES_UNTIL_OUT_DISSOLVE 192
|
||||
|
||||
|
@ -62,7 +71,7 @@ extern const char gEXTRA_STAGE[12];
|
|||
|
||||
#define STAGE_NUM_TRAM_CENTER_Y (vram_y_to_tram(STAGE_NUM_CENTER_Y))
|
||||
#define STAGE_TITLE_TRAM_CENTER_Y (vram_y_to_tram(STAGE_TITLE_CENTER_Y))
|
||||
#define BGM_TRAM_CENTER_Y (vram_y_to_tram(BGM_CENTER_Y))
|
||||
#define BGM_TRAM_Y (vram_y_to_tram(BGM_CENTER_Y))
|
||||
#define BGM_TRAM_RIGHT (PLAYFIELD_TRAM_RIGHT - 1)
|
||||
|
||||
inline tram_x_t bgm_note_tram_left(int title_len)
|
||||
|
@ -127,8 +136,8 @@ inline void bgm_title_dissolve_put(const int& len)
|
|||
}
|
||||
|
||||
#define bgm_string_put(str, len) \
|
||||
gaiji_putca(bgm_note_tram_left(len), BGM_TRAM_CENTER_Y, 3, TX_YELLOW); \
|
||||
text_putsa(bgm_title_tram_left(len), BGM_TRAM_CENTER_Y, str, TX_WHITE);
|
||||
gaiji_putca(bgm_note_tram_left(len), BGM_TRAM_Y, 3, TX_YELLOW); \
|
||||
text_putsa(bgm_title_tram_left(len), BGM_TRAM_Y, str, TX_WHITE);
|
||||
|
||||
inline void titles_dissolve_put(const int& bgm_len)
|
||||
{
|
||||
|
@ -290,3 +299,127 @@ void pascal near popup_boss_bgm_update_and_render(void)
|
|||
#undef frames
|
||||
}
|
||||
/// --------------------
|
||||
|
||||
const unsigned char POPUP_DURATION = 128;
|
||||
|
||||
inline void popup_line_wipe(tram_y_t y) {
|
||||
text_putsa(PLAYFIELD_TRAM_LEFT, y, PLAYFIELD_BLANK_ROW, TX_WHITE);
|
||||
}
|
||||
|
||||
#define popup_put(left, y, str) \
|
||||
gaiji_putsa(left, y, reinterpret_cast<const char *>(str), TX_WHITE);
|
||||
|
||||
inline void near popup_put_points(const unsigned long &points) {
|
||||
#if (GAME == 5)
|
||||
hud_points_put(PLAYFIELD_TRAM_CENTER_X, POPUP_TRAM_Y, points);
|
||||
#else
|
||||
void pascal near popup_put_points_th04(unsigned long points);
|
||||
popup_put_points_th04(points);
|
||||
#endif
|
||||
}
|
||||
|
||||
void pascal near popup_update_and_render(void)
|
||||
{
|
||||
#define frame popup_frame
|
||||
#define gaiji_len popup_gaiji_len
|
||||
#define id_cur popup_id_cur
|
||||
#define dest_reached popup_dest_reached
|
||||
#define shiftbuf popup_shiftbuf
|
||||
#define cur_tram_left popup_cur_tram_left
|
||||
#define dest_tram_left popup_dest_tram_left
|
||||
|
||||
#define cur_tram_right() \
|
||||
(cur_tram_left + (gaiji_len * GAIJI_TRAM_W))
|
||||
|
||||
extern unsigned char frame;
|
||||
extern int gaiji_len;
|
||||
extern popup_id_t id_cur;
|
||||
extern bool dest_reached;
|
||||
|
||||
// Buffer used for shifting in the popup text from the right of the
|
||||
// playfield. Only used while the text isn't fully visible.
|
||||
extern gaiji_th04_t shiftbuf[POPUP_STRING_MAX_LEN + 1];
|
||||
|
||||
extern tram_x_t cur_tram_left;
|
||||
extern tram_x_t dest_tram_left;
|
||||
|
||||
unsigned char i;
|
||||
|
||||
// Make sure that the current popup is shown for at least 64 frames before
|
||||
// switching to a new one. Of course, it would have been cleaner to keep
|
||||
// popup events in a queue instead - with this approach, you only see the
|
||||
// last popup that happened within 64 frames, and any other potential
|
||||
// popups happening during that time are ignored.
|
||||
// Also note how the lack of a POPUP_NONE constant is the only reason why
|
||||
// this function has to be conditionally executed via the [popup] function
|
||||
// pointer...
|
||||
if((popup_id_new != id_cur) && (frame >= (POPUP_DURATION / 2))) {
|
||||
popup_line_wipe(POPUP_TRAM_Y);
|
||||
popup_line_wipe(BGM_TRAM_Y); // Why though?
|
||||
frame = 0; // Re-initialize
|
||||
}
|
||||
if(frame == 0) {
|
||||
id_cur = popup_id_new;
|
||||
for(i = 0; i < (sizeof(shiftbuf) - 1); i++) {
|
||||
shiftbuf[i] = g_EMPTY;
|
||||
}
|
||||
gaiji_len = strlen(
|
||||
reinterpret_cast<const char *>(POPUP_STRINGS[id_cur])
|
||||
);
|
||||
shiftbuf[gaiji_len] = g_NULL;
|
||||
cur_tram_left = (PLAYFIELD_TRAM_RIGHT - (gaiji_len * GAIJI_TRAM_W));
|
||||
if(popup_id_new != POPUP_ID_BONUS) {
|
||||
// Technically * (GAIJI_TRAM_W / 2), since the popup is centered.
|
||||
popup_dest_tram_left = (PLAYFIELD_TRAM_CENTER_X - gaiji_len);
|
||||
} else {
|
||||
// This one is off-center anyway, though.
|
||||
popup_dest_tram_left = (PLAYFIELD_TRAM_CENTER_X - 12);
|
||||
}
|
||||
dest_reached = false;
|
||||
}
|
||||
|
||||
if(frame >= POPUP_DURATION) {
|
||||
popup_line_wipe(POPUP_TRAM_Y);
|
||||
frame = 0;
|
||||
popup = nullfunc_near;
|
||||
return;
|
||||
}
|
||||
|
||||
if(frame < (gaiji_len - 1)) {
|
||||
// Shift in a new gaiji
|
||||
for(i = 0; i < (gaiji_len - 1); i++) {
|
||||
shiftbuf[i] = shiftbuf[i + 1];
|
||||
}
|
||||
shiftbuf[gaiji_len - 1] = POPUP_STRINGS[id_cur][frame];
|
||||
popup_put(cur_tram_left, POPUP_TRAM_Y, shiftbuf);
|
||||
} else if(cur_tram_left > dest_tram_left) {
|
||||
// (Should really be !=, but whatever.) Use the full, unshifted string
|
||||
popup_put(cur_tram_left, POPUP_TRAM_Y, POPUP_STRINGS[id_cur]);
|
||||
if(cur_tram_right() <= (PLAYFIELD_TRAM_RIGHT - GAIJI_TRAM_W)) {
|
||||
text_putca(cur_tram_right(), POPUP_TRAM_Y, ' ', TX_WHITE);
|
||||
}
|
||||
// "If I'd move at 1 TRAM column per frame, I'd have to clip the
|
||||
// overhanging second half of the last gaiji. Nah, let's just go twice
|
||||
// the speed :zunpet:"
|
||||
popup_cur_tram_left -= 2;
|
||||
} else {
|
||||
if(!dest_reached) {
|
||||
dest_reached = true;
|
||||
popup_line_wipe(POPUP_TRAM_Y);
|
||||
}
|
||||
popup_put(dest_tram_left, POPUP_TRAM_Y, POPUP_STRINGS[id_cur]);
|
||||
if(id_cur == POPUP_ID_BONUS) {
|
||||
popup_put_points(popup_bonus);
|
||||
}
|
||||
}
|
||||
frame++;
|
||||
|
||||
#undef cur_tram_right
|
||||
#undef dest_tram_left
|
||||
#undef cur_tram_left
|
||||
#undef shiftbuf
|
||||
#undef dest_reached
|
||||
#undef id_cur
|
||||
#undef gaiji_len
|
||||
#undef frame
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ enum popup_id_t {
|
|||
#if (GAME == 5)
|
||||
POPUP_ID_DREAMBONUS_MAX = 4,
|
||||
#endif
|
||||
|
||||
_popup_id_t_FORCE_UINT8 = 0xFF
|
||||
};
|
||||
|
||||
extern unsigned char bgm_title_id; // only used in TH04
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
POPUP_TRAM_Y = 2
|
||||
POPUP_LEN = 8
|
||||
POPUP_DURATION = 128
|
||||
|
||||
POPUP_ID_HISCORE_ENTRY = 0
|
||||
POPUP_ID_EXTEND = 1
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
POPUP_LEN = 8
|
||||
|
||||
public _stage_title_len, _stage_bgm_title_len, _boss_bgm_title_len
|
||||
_stage_title_len dw ?
|
||||
_stage_bgm_title_len dw ?
|
||||
|
@ -9,25 +11,22 @@ endif
|
|||
_boss_bgm_title_len dw ?
|
||||
|
||||
public _popup_gaiji_len, _popup_id_cur, _popup_dest_reached, _popup_shiftbuf
|
||||
public _popup_cur_tram_x, _popup_dest_tram_x, _bgm_title_id, _popup_id_new
|
||||
public _popup_cur_tram_left, _popup_dest_tram_left, _bgm_title_id, _popup_id_new
|
||||
public _overlay_text, _popup, _popup_titles_frame, _popup_bonus
|
||||
_popup_gaiji_len dw ?
|
||||
_popup_id_cur db ?
|
||||
_popup_dest_reached db ?
|
||||
|
||||
; Buffer used for shifting in the popup text from the right of the playfield.
|
||||
; Only used while the text isn't fully visible.
|
||||
_popup_shiftbuf db (POPUP_LEN + 1) dup(?)
|
||||
db ? ; (word alignment)
|
||||
evendata
|
||||
if GAME eq 5
|
||||
dd ? ;
|
||||
endif
|
||||
_popup_cur_tram_x dw ?
|
||||
_popup_dest_tram_x dw ?
|
||||
_popup_cur_tram_left dw ?
|
||||
_popup_dest_tram_left dw ?
|
||||
_bgm_title_id db ?
|
||||
_popup_id_new db ?
|
||||
_overlay_text dw ?
|
||||
_popup dw ?
|
||||
_popup_titles_frame db ?
|
||||
db ?
|
||||
evendata
|
||||
_popup_bonus dd ?
|
||||
|
|
|
@ -40,7 +40,6 @@ include th04/main/enemy/enemy.inc
|
|||
extern SCOPY@:proc
|
||||
extern _execl:proc
|
||||
extern _memcpy:proc
|
||||
extern _strlen:proc
|
||||
extern _tolower:proc
|
||||
extern __ctype:byte
|
||||
|
||||
|
@ -9779,9 +9778,9 @@ main_0_TEXT ends
|
|||
POPUP_TITLES_INVALIDATE procdesc near
|
||||
POPUP_TITLES_UPDATE_AND_RENDER procdesc near
|
||||
POPUP_BOSS_BGM_UPDATE_AND_RENDER procdesc near
|
||||
POPUP_UPDATE_AND_RENDER procdesc near
|
||||
|
||||
main_01_TEXT segment byte public 'CODE' use16
|
||||
|
||||
include th04/main/hud/popup.asm
|
||||
include th04/formats/bb_txt_load.asm
|
||||
|
||||
|
|
|
@ -24,11 +24,6 @@ hud_int_put endp
|
|||
nop
|
||||
|
||||
|
||||
; Prints [points] using the bold gaiji font, right-aligned at ([left+8], [y]),
|
||||
; in white, using up to 7 digits (8 if the "continue" digit is included).
|
||||
; Larger numbers will overflow the most significant digit into the A-Z range.
|
||||
|
||||
; void pascal far hud_points_put(utram_x_t left, utram_y_t y, unsigned long points);
|
||||
public HUD_POINTS_PUT
|
||||
hud_points_put proc far
|
||||
|
||||
|
|
|
@ -8313,10 +8313,9 @@ main_0_TEXT ends
|
|||
POPUP_TITLES_INVALIDATE procdesc near
|
||||
POPUP_TITLES_UPDATE_AND_RENDER procdesc near
|
||||
POPUP_BOSS_BGM_UPDATE_AND_RENDER procdesc near
|
||||
POPUP_UPDATE_AND_RENDER procdesc near
|
||||
|
||||
main_01_TEXT segment byte public 'CODE' use16
|
||||
|
||||
include th04/main/hud/popup.asm
|
||||
include th04/main/player/pos_update_and_clamp.asm
|
||||
|
||||
; =============== S U B R O U T I N E =======================================
|
||||
|
|
Loading…
Reference in New Issue