Attempt to decompile hovercarTick
This commit is contained in:
parent
ff5084680d
commit
eb6de85cc2
|
|
@ -27499,6 +27499,367 @@ glabel var7f1aa6e4
|
|||
/* f07df70: 00000000 */ nop
|
||||
);
|
||||
|
||||
//#define HOVVALUE() (active ? 15.0f : 5.0f)
|
||||
|
||||
// Mismatch: float regalloc
|
||||
//void hovercarTick(struct prop *prop)
|
||||
//{
|
||||
// s32 stopping; // 274
|
||||
// struct pad pad; // 220
|
||||
// struct coord sp214;
|
||||
// s16 sp210[2];
|
||||
// struct hovercarobj *hovercar = (struct hovercarobj *)prop->obj;
|
||||
// struct defaultobj *obj = &hovercar->base;
|
||||
// u32 stack;
|
||||
// f32 sp200 = hovercar->roty;
|
||||
// f32 sp1fc = hovercar->rotx;
|
||||
// u32 active = obj->flags & OBJFLAG_80000000; // 1f8
|
||||
// f32 sp1f4 = active ? 5 : 10;
|
||||
// struct prop *doorprop; // 1f0
|
||||
// struct coord sp1e4;
|
||||
// struct coord sp1d8;
|
||||
// s16 sp1d6;
|
||||
// u32 stack2;
|
||||
// u32 stack3;
|
||||
// struct coord sp1c0; // 1c0
|
||||
// s16 sp1b0[8]; // 1b0
|
||||
// f32 tmp2;
|
||||
// f32 tmp3;
|
||||
// f32 tmp4;
|
||||
// struct doorobj *door; // 1a0
|
||||
// struct coord sp194;
|
||||
// f32 sp190;
|
||||
// f32 sp18c;
|
||||
// f32 sp188;
|
||||
// f32 sp184;
|
||||
// f32 sp180;
|
||||
// f32 sp15c[9];
|
||||
// struct coord sp150;
|
||||
// s16 sp140[8];
|
||||
// f32 tmp;
|
||||
// f32 sp138;
|
||||
// struct coord sp12c;
|
||||
// f32 spec[16];
|
||||
// f32 spac[16];
|
||||
// f32 sp6c[16];
|
||||
// f32 dist;
|
||||
// s32 *padnum;
|
||||
//
|
||||
// doorprop = NULL;
|
||||
//
|
||||
// // 23c
|
||||
// if (active && hovercar->deadtimer60 < 0) {
|
||||
// // Exploding
|
||||
// tmp = func0f0667bc(func0f068aa8(hovercar->base.model));
|
||||
// sp1d6 = prop->rooms[0];
|
||||
//
|
||||
// sp1d8.x = hovercar->base.realrot[3];
|
||||
// sp1d8.y = hovercar->base.realrot[4];
|
||||
// sp1d8.z = hovercar->base.realrot[5];
|
||||
//
|
||||
// sp1e4.x = hovercar->base.realrot[3] * tmp + prop->pos.x;
|
||||
// sp1e4.y = hovercar->base.realrot[4] * tmp + prop->pos.y;
|
||||
// sp1e4.z = hovercar->base.realrot[5] * tmp + prop->pos.z;
|
||||
//
|
||||
// func0f0926bc(prop, 1, 0xffff);
|
||||
// explosionCreate(NULL, &prop->pos, prop->rooms, EXPLOSIONTYPE_7, g_Vars.currentplayernum, true, &sp1e4, sp1d6, &sp1d8);
|
||||
// hovercar->base.hidden |= OBJHFLAG_00000004;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 320
|
||||
// if (hovercar->dead) {
|
||||
// // 334
|
||||
// if (active) {
|
||||
// hovercar->deadtimer60 -= g_Vars.lvupdate240_60;
|
||||
// hovercar->sparkstimer60 -= g_Vars.lvupdate240_60;
|
||||
//
|
||||
// if (hovercar->sparkstimer60 < 0) {
|
||||
// hovercar->sparkstimer60 = 50;
|
||||
//
|
||||
// // Play damage sound
|
||||
// func0f0939f8(NULL, prop, 0x64, -1,
|
||||
// -1, 1024, 0, 0, 0, -1, 0, -1, -1, -1, -1);
|
||||
//
|
||||
// // Create sparks
|
||||
// func0f12f9f0(prop->rooms[0], prop, &prop->pos, NULL, 0, 0);
|
||||
// }
|
||||
// } else {
|
||||
// // 3e8
|
||||
// if (hovercar->speedtime60 == 0) {
|
||||
// // 404
|
||||
// hovercar->speed += 6;
|
||||
//
|
||||
// sp1c0.x = prop->pos.x;
|
||||
// sp1c0.y = prop->pos.y - hovercar->speed;
|
||||
// sp1c0.z = prop->pos.z;
|
||||
//
|
||||
// if (sp1c0.y < hovercar->speedaim) {
|
||||
// sp1c0.y = hovercar->speedaim;
|
||||
// hovercar->speedtime60 = 1;
|
||||
// }
|
||||
//
|
||||
// func0f065e74(&prop->pos, prop->rooms, &sp1c0, sp1b0);
|
||||
//
|
||||
// prop->pos.x = sp1c0.x;
|
||||
// prop->pos.y = sp1c0.y;
|
||||
// prop->pos.z = sp1c0.z;
|
||||
//
|
||||
// func0f065c44(prop);
|
||||
// roomsCopy(sp1b0, prop->rooms);
|
||||
// func0f069c70(&hovercar->base, false, true);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 4bc
|
||||
// chraiExecute(obj, PROPTYPE_OBJ);
|
||||
// stopping = false;
|
||||
//
|
||||
// if (hovercar->path) {
|
||||
// padnum = &hovercar->path->pads[hovercar->nextstep];
|
||||
// padUnpack(*padnum, PADFIELD_POS | PADFIELD_ROOM, &pad);
|
||||
//
|
||||
// sp214.x = pad.pos.x;
|
||||
//
|
||||
// if (active) {
|
||||
// sp210[0] = pad.room;
|
||||
// sp210[1] = -1;
|
||||
//
|
||||
// sp214.y = func0002a330(&pad.pos, 5, sp210, NULL, 0) + 35;
|
||||
// } else {
|
||||
// sp214.y = pad.pos.y;
|
||||
// }
|
||||
//
|
||||
// sp214.z = pad.pos.z;
|
||||
//
|
||||
// if ((hovercar->base.flags & OBJFLAG_20000000)
|
||||
// && func0f0446e0(&prop->pos, &prop->pos, &sp214, sp1f4)) {
|
||||
// func0f072774(obj);
|
||||
// padnum = &hovercar->path->pads[hovercar->nextstep];
|
||||
// padUnpack(*padnum, PADFIELD_POS, &pad);
|
||||
// }
|
||||
//
|
||||
// sp200 = func0f096750(sp214.x - prop->pos.x, sp214.z - prop->pos.z);
|
||||
// sp1fc = func0f096750(sp214.y - prop->pos.y,
|
||||
// sqrtf((sp214.x - prop->pos.x) * (sp214.x - prop->pos.x) + (sp214.z - prop->pos.z) * (sp214.z - prop->pos.z)));
|
||||
//
|
||||
// // 630
|
||||
// if (hovercar->base.flags & OBJFLAG_20000000) {
|
||||
// hovercar->roty = sp200;
|
||||
// hovercar->rotx = sp1fc;
|
||||
// obj->flags &= ~OBJFLAG_20000000;
|
||||
//
|
||||
// if (active) {
|
||||
// prop->pos.y = sp214.y;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (active) {
|
||||
// if (func0002d7c0(&prop->pos, prop->rooms, &sp214, 0x5000, 0, 0, 0) == 0) {
|
||||
// doorprop = func00024eb0();
|
||||
// }
|
||||
//
|
||||
// if (doorprop) {
|
||||
// door = (struct doorobj *)doorprop->obj;
|
||||
// dist = (doorprop->pos.x - prop->pos.x) * (doorprop->pos.x - prop->pos.x)
|
||||
// + (doorprop->pos.z - prop->pos.z) * (doorprop->pos.z - prop->pos.z);
|
||||
//
|
||||
// if (dist < 200 * 200) {
|
||||
// func0f0900c0(prop, door);
|
||||
// doorActivate(door, DOORMODE_OPENING);
|
||||
// }
|
||||
//
|
||||
// if (dist < 195 * 195) {
|
||||
// stopping = !doorIsOpen(door);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // 750
|
||||
// if (hovercar->base.flags & OBJFLAG_20000000) {
|
||||
// hovercar->roty = func0f096750(hovercar->base.realrot[6], hovercar->base.realrot[8]);
|
||||
// hovercar->rotx = func0f096750(hovercar->base.realrot[7], sqrtf(hovercar->base.realrot[8] * hovercar->base.realrot[8] + hovercar->base.realrot[6] * hovercar->base.realrot[6]));
|
||||
// hovercar->base.flags &= ~OBJFLAG_20000000;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 7ac
|
||||
// if (hovercar->speedtime60 >= 0) {
|
||||
// if (hovercar->speedtime60 <= g_Vars.lvupdate240freal) {
|
||||
// hovercar->speed = hovercar->speedaim;
|
||||
// } else {
|
||||
// hovercar->speed += (hovercar->speedaim - hovercar->speed) * g_Vars.lvupdate240freal / hovercar->speedtime60;
|
||||
// }
|
||||
//
|
||||
// hovercar->speedtime60 -= g_Vars.lvupdate240freal;
|
||||
// }
|
||||
//
|
||||
// // 818
|
||||
// if (active) {
|
||||
// if (hovercar->turnyspeed60 > 0) {
|
||||
// hovercar->speed -= hovercar->speedaim * (1.0f / 24.0f) * g_Vars.lvupdate240f;
|
||||
//
|
||||
// if (hovercar->speed < 0) {
|
||||
// hovercar->speed = 0.1f;
|
||||
// }
|
||||
// } else {
|
||||
// if (hovercar->speed < hovercar->speedaim) {
|
||||
// hovercar->speed += hovercar->speedaim * (1.0f / 24.0f) * g_Vars.lvupdate240f;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (stopping) {
|
||||
// hovercar->speed -= 50.0f / 240.f * g_Vars.lvupdate240f;
|
||||
//
|
||||
// if (hovercar->speed < 0) {
|
||||
// hovercar->speed = 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 900
|
||||
// if (hovercar->speed > 0) {
|
||||
// sp190 = hovercar->roty;
|
||||
// sp18c = hovercar->rotx;
|
||||
// sp188 = hovercar->rotz;
|
||||
//
|
||||
// sp184 = hovercar->turnyspeed60;
|
||||
// sp180 = hovercar->turnxspeed60;
|
||||
//
|
||||
// // 94c
|
||||
// sp194.x = sinf(hovercar->roty) * cosf(hovercar->rotx);
|
||||
// sp194.y = sinf(hovercar->rotx);
|
||||
// sp194.z = cosf(hovercar->rotx) * cosf(hovercar->roty);
|
||||
//
|
||||
// if (func0f0445c4(&prop->pos, &sp194, &sp214, sp1f4)) {
|
||||
// sp200 = hovercar->roty;
|
||||
// sp1fc = hovercar->rotx;
|
||||
// }
|
||||
//
|
||||
// // 9c8
|
||||
// // The multipliers below:
|
||||
// // val * 0.013087885454297f = val * M_BADPI / 240
|
||||
// // val * 0.00021813141938765f = val * M_BADPI / 240 / 60
|
||||
// tmp2 = HOVVALUE();
|
||||
// tmp3 = HOVVALUE();
|
||||
// tmp4 = HOVVALUE();
|
||||
// func0f06db00(&sp190, sp200, &sp184,
|
||||
// tmp2 * 0.00021813141938765f,
|
||||
// tmp3 * 0.00021813141938765f + tmp3 * 0.00021813141938765f,
|
||||
// tmp4 * 0.013087885454297f);
|
||||
//
|
||||
// // a64
|
||||
// if (sp190 == sp200) {
|
||||
// tmp2 = HOVVALUE() * 0.00021813141938765f;
|
||||
// if (tmp2 + tmp2 >= sp184) {
|
||||
// tmp2 = -(HOVVALUE() * 0.00021813141938765f);
|
||||
// if (tmp2 + tmp2 <= sp184) {
|
||||
// sp184 = 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // b04
|
||||
// tmp2 = HOVVALUE();
|
||||
// tmp3 = HOVVALUE();
|
||||
// tmp4 = HOVVALUE();
|
||||
// func0f06db00(&sp18c, sp1fc, &sp180,
|
||||
// tmp2 * 0.00021813141938765f,
|
||||
// tmp3 * 0.00021813141938765f + tmp3 * 0.00021813141938765f,
|
||||
// tmp4 * 0.013087885454297f);
|
||||
//
|
||||
// // b90
|
||||
// if (sp18c == sp1fc) {
|
||||
// tmp2 = HOVVALUE() * 0.00021813141938765f;
|
||||
// if (tmp2 + tmp2 >= sp180) {
|
||||
// tmp2 = -(HOVVALUE() * 0.00021813141938765f);
|
||||
// if (tmp2 + tmp2 <= sp180) {
|
||||
// sp180 = 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // c34
|
||||
// if (hovercar->base.flags & OBJFLAG_80000000) {
|
||||
// sp188 = 0;
|
||||
// } else {
|
||||
// sp188 += (-sp184 * 120 - sp188) * 0.1f;
|
||||
// }
|
||||
//
|
||||
// // c84
|
||||
// sp12c.x = active ? M_BADTAU - sp18c : 0;
|
||||
// sp12c.y = sp190;
|
||||
// sp12c.z = 0;
|
||||
//
|
||||
// // cb4
|
||||
// if (sp188 >= 0) {
|
||||
// func00016400(sp188, sp6c);
|
||||
// } else {
|
||||
// func00016400(sp188 + M_BADTAU, sp6c);
|
||||
// }
|
||||
//
|
||||
// // cf0
|
||||
// func0001648c(&sp12c, spac);
|
||||
// func00015f04(hovercar->base.model->unk14, spac);
|
||||
// func00015a00(spac, sp6c, spec);
|
||||
// func00015da0(spec, sp15c);
|
||||
// func00015cd8(sp15c, hovercar->base.realrot);
|
||||
//
|
||||
// sp138 = cosf(sp18c);
|
||||
//
|
||||
// // d50
|
||||
// sp194.x = sinf(sp190) * sp138;
|
||||
// sp194.y = active ? sinf(sp1fc) : sinf(sp18c);
|
||||
// sp194.z = cosf(sp190) * sp138;
|
||||
//
|
||||
// sp150.x = prop->pos.x + sp194.x * (hovercar->speed * g_Vars.lvupdate240freal);
|
||||
// sp150.y = prop->pos.y + sp194.y * (hovercar->speed * g_Vars.lvupdate240freal);
|
||||
// sp150.z = prop->pos.z + sp194.z * (hovercar->speed * g_Vars.lvupdate240freal);
|
||||
//
|
||||
// func0f065e74(&prop->pos, prop->rooms, &sp150, sp140);
|
||||
//
|
||||
// // e08
|
||||
// if (active) {
|
||||
// sp150.y = func0002a330(&sp150, 5, sp140, NULL, 0) + 35;
|
||||
//
|
||||
// if (sp150.y < -100000) {
|
||||
// sp150.y = prop->pos.y + sp194.y * (hovercar->speed * g_Vars.lvupdate240freal);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // e68
|
||||
// prop->pos.x = sp150.x;
|
||||
// prop->pos.y = sp150.y;
|
||||
// prop->pos.z = sp150.z;
|
||||
//
|
||||
// func0f065c44(prop);
|
||||
// roomsCopy(sp140, prop->rooms);
|
||||
//
|
||||
// hovercar->roty = sp190;
|
||||
// hovercar->rotx = sp18c;
|
||||
// hovercar->rotz = sp188;
|
||||
// hovercar->turnyspeed60 = sp184;
|
||||
// hovercar->turnxspeed60 = sp180;
|
||||
//
|
||||
// if (hovercar->path) {
|
||||
// if (hovercar->path->pads[hovercar->nextstep + 1] >= 0) {
|
||||
// if (func0f0446e0(&prop->pos, &sp150, &sp214, hovercar->speed * sp1f4)) {
|
||||
// func0f072774(obj);
|
||||
// }
|
||||
// } else {
|
||||
// if (func0f0446e0(&prop->pos, &sp150, &sp214, hovercar->speed * sp1f4)) {
|
||||
// func0f072774(obj);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func0f069c70(&hovercar->base, false, true);
|
||||
// }
|
||||
//}
|
||||
|
||||
void hoverpropTick(struct prop *prop, bool arg1)
|
||||
{
|
||||
struct hoverpropobj *obj = (struct hoverpropobj *)prop->obj;
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ s32 func0f148f18(s32 qty, f32 arg1, struct prop *prop, struct splat *arg3, struc
|
|||
spe4[j] = (rand * var8007f8a8 + rand * var8007f8a8 - var8007f8a8) * 0.017453292384744f;
|
||||
}
|
||||
|
||||
func0001648c(spe4, spa4);
|
||||
func0001648c((struct coord *)spe4, spa4);
|
||||
func00015b14(spa4, spfc, &splat->unk028);
|
||||
func00015b14(spa4, spf0, &splat->unk00c);
|
||||
func0f177164(&splat->unk028, &splat->unk028, 403, "splat.c");
|
||||
|
|
|
|||
|
|
@ -590,6 +590,7 @@
|
|||
#define EXPLOSIONTYPE_0 0
|
||||
#define EXPLOSIONTYPE_3 3
|
||||
#define EXPLOSIONTYPE_5 5
|
||||
#define EXPLOSIONTYPE_7 7
|
||||
#define EXPLOSIONTYPE_8 8
|
||||
#define EXPLOSIONTYPE_12 12
|
||||
#define EXPLOSIONTYPE_14 14
|
||||
|
|
@ -2121,6 +2122,7 @@
|
|||
#define OBJFLAG_40000000 0x40000000
|
||||
#define OBJFLAG_DOOR_KEEPOPEN 0x40000000 // Editor: "Door open by default/Empty weapon"
|
||||
#define OBJFLAG_LIFT_TRIGGERDISABLE 0x40000000
|
||||
#define OBJFLAG_80000000 0x80000000
|
||||
#define OBJFLAG_CHOPPER_INACTIVE 0x80000000 // Or lift disabled, or hovercar something
|
||||
|
||||
// obj->flags2
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ void propPrintDangerous(void);
|
|||
void chrTickThrowGrenade(struct chrdata *chr);
|
||||
s32 func0f043f2c(struct chrdata *chr, struct coord *runpos, s32 arg2, f32 *arg3);
|
||||
void chrTickAttackWalk(struct chrdata *chr);
|
||||
u32 func0f0445c4(void);
|
||||
bool func0f0445c4(struct coord *arg0, struct coord *arg1, struct coord *arg2, f32 arg3);
|
||||
bool func0f0446e0(struct coord *prevpos, struct coord *curpos, struct coord *targetpos, f32 arg3);
|
||||
bool func0f044808(struct coord *prevpos, struct coord *curpos, struct coord *targetpos, f32 arg3);
|
||||
void chrTickRunPos(struct chrdata *chr);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ u32 func0f066640(void);
|
|||
u32 func0f0666cc(void);
|
||||
u32 func0f0667ac(void);
|
||||
u32 func0f0667b4(void);
|
||||
u32 func0f0667bc(void);
|
||||
f32 func0f0667bc(u32 arg0);
|
||||
u32 func0f0667c4(void);
|
||||
u32 func0f0667cc(void);
|
||||
u32 func0f0667d4(void);
|
||||
|
|
@ -67,7 +67,7 @@ u32 func0f0687e4(void);
|
|||
u32 func0f0688f4(void);
|
||||
f32 *func0f06896c(void *modelfiledata);
|
||||
u32 func0f068998(void);
|
||||
u32 func0f068aa8(void);
|
||||
u32 func0f068aa8(struct model *model);
|
||||
u32 func0f068ad4(void);
|
||||
struct model08thing *func0f068af4(struct defaultobj *obj);
|
||||
u32 func0f068b14(void);
|
||||
|
|
@ -106,7 +106,7 @@ u32 func0f06c8ac(void);
|
|||
u32 func0f06cd00(void);
|
||||
u32 func0f06d37c(void);
|
||||
void func0f06d90c(f32 *frac, f32 maxfrac, f32 *fracspeed, f32 accel, f32 decel, f32 maxspeed);
|
||||
u32 func0f06db00(void);
|
||||
void func0f06db00(f32 *arg0, f32 arg1, f32 *arg2, f32 arg3, f32 arg4, f32 arg5);
|
||||
u32 func0f06dbd8(void);
|
||||
u32 func0f06e87c(void);
|
||||
u32 func0f06e9cc(void);
|
||||
|
|
@ -140,7 +140,7 @@ void hoverpropSetTurnAngle(struct defaultobj *obj, f32 angle);
|
|||
u32 func0f072144(void);
|
||||
u32 func0f072650(void);
|
||||
u32 func0f0726ec(void);
|
||||
u32 func0f072774(void);
|
||||
void func0f072774(struct defaultobj *obj);
|
||||
u32 func0f0727d4(void);
|
||||
void func0f072adc(struct hoverbikeobj *hoverbike, f32 arg1, f32 arg2, f32 arg3);
|
||||
u32 func0f0732d4(void);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ void func00016248(struct coord *coord, f32 angle, f32 *matrix);
|
|||
void func000162e8(f32 angle, f32 *matrix);
|
||||
void func00016374(f32 angle, f32 *matrix);
|
||||
void func00016400(f32 angle, f32 *matrix);
|
||||
void func0001648c(f32 *src, f32 *dest);
|
||||
void func0001648c(struct coord *coord, f32 *dest);
|
||||
u32 func000165d8(void);
|
||||
u32 func000166a4(void);
|
||||
void func000166dc(struct coord *pos, f32 *matrix);
|
||||
|
|
|
|||
|
|
@ -1530,6 +1530,10 @@ struct hovercarobj { // objtype 0x37
|
|||
/*0x84*/ f32 rotz;
|
||||
/*0x88*/ struct path *path;
|
||||
/*0x8c*/ s32 nextstep;
|
||||
/*0x90*/ s16 status;
|
||||
/*0x92*/ s16 dead;
|
||||
/*0x94*/ s16 deadtimer60;
|
||||
/*0x96*/ s16 sparkstimer60;
|
||||
};
|
||||
|
||||
struct padeffectobj { // objtype 0x38
|
||||
|
|
|
|||
|
|
@ -225,14 +225,14 @@ void func00016400(f32 angle, f32 *matrix)
|
|||
matrix[15] = 1;
|
||||
}
|
||||
|
||||
void func0001648c(f32 *src, f32 *dest)
|
||||
void func0001648c(struct coord *src, f32 *dest)
|
||||
{
|
||||
f32 xcos = cosf(src[0]);
|
||||
f32 xsin = sinf(src[0]);
|
||||
f32 ycos = cosf(src[1]);
|
||||
f32 ysin = sinf(src[1]);
|
||||
f32 zcos = cosf(src[2]);
|
||||
f32 zsin = sinf(src[2]);
|
||||
f32 xcos = cosf(src->x);
|
||||
f32 xsin = sinf(src->x);
|
||||
f32 ycos = cosf(src->y);
|
||||
f32 ysin = sinf(src->y);
|
||||
f32 zcos = cosf(src->z);
|
||||
f32 zsin = sinf(src->z);
|
||||
f32 a = xsin * zsin;
|
||||
f32 b = xcos * zsin;
|
||||
f32 c = xsin * zcos;
|
||||
|
|
|
|||
Loading…
Reference in New Issue