Add scripts file for C64 verisons, ready for future changes.
svn-id: r18151
This commit is contained in:
parent
50abcb6683
commit
a8106f8c16
4 changed files with 416 additions and 1 deletions
|
@ -376,6 +376,30 @@ protected:
|
||||||
byte VAR_BACKUP_VERB;
|
byte VAR_BACKUP_VERB;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Engine for version 2 SCUMM games.
|
||||||
|
*/
|
||||||
|
class ScummEngine_c64 : public ScummEngine_v2 {
|
||||||
|
protected:
|
||||||
|
typedef void (ScummEngine_c64::*OpcodeProcC64)();
|
||||||
|
struct OpcodeEntryC64 {
|
||||||
|
OpcodeProcC64 proc;
|
||||||
|
const char *desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
const OpcodeEntryC64 *_opcodesC64;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScummEngine_c64(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16]);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setupOpcodes();
|
||||||
|
virtual void executeOpcode(byte i);
|
||||||
|
virtual const char *getOpcodeDesc(byte i);
|
||||||
|
|
||||||
|
/* Version 2 script opcodes */
|
||||||
|
};
|
||||||
|
|
||||||
class ScummEngine_v6 : public ScummEngine {
|
class ScummEngine_v6 : public ScummEngine {
|
||||||
friend class Insane;
|
friend class Insane;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ MODULE_OBJS := \
|
||||||
scumm/room.o \
|
scumm/room.o \
|
||||||
scumm/saveload.o \
|
scumm/saveload.o \
|
||||||
scumm/script.o \
|
scumm/script.o \
|
||||||
|
scumm/script_c64.o \
|
||||||
scumm/script_v2.o \
|
scumm/script_v2.o \
|
||||||
scumm/script_v5.o \
|
scumm/script_v5.o \
|
||||||
scumm/script_v6.o \
|
scumm/script_v6.o \
|
||||||
|
|
382
scumm/script_c64.cpp
Normal file
382
scumm/script_c64.cpp
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001 Ludvig Strigeus
|
||||||
|
* Copyright (C) 2001-2005 The ScummVM project
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "scumm/actor.h"
|
||||||
|
#include "scumm/charset.h"
|
||||||
|
#include "scumm/intern.h"
|
||||||
|
#include "scumm/object.h"
|
||||||
|
#include "scumm/scumm.h"
|
||||||
|
#include "scumm/util.h"
|
||||||
|
#include "scumm/verbs.h"
|
||||||
|
|
||||||
|
namespace Scumm {
|
||||||
|
|
||||||
|
#define OPCODE(x) _OPCODE(ScummEngine_c64, x)
|
||||||
|
|
||||||
|
void ScummEngine_c64::setupOpcodes() {
|
||||||
|
static const OpcodeEntryC64 opcodes[256] = {
|
||||||
|
/* 00 */
|
||||||
|
OPCODE(o5_stopObjectCode),
|
||||||
|
OPCODE(o2_putActor),
|
||||||
|
OPCODE(o5_startMusic),
|
||||||
|
OPCODE(o5_getActorRoom),
|
||||||
|
/* 04 */
|
||||||
|
OPCODE(o2_isGreaterEqual),
|
||||||
|
OPCODE(o2_drawObject),
|
||||||
|
OPCODE(o2_getActorElevation),
|
||||||
|
OPCODE(o2_setState08),
|
||||||
|
/* 08 */
|
||||||
|
OPCODE(o5_isNotEqual),
|
||||||
|
OPCODE(o5_faceActor),
|
||||||
|
OPCODE(o2_assignVarWordIndirect),
|
||||||
|
OPCODE(o2_setObjPreposition),
|
||||||
|
/* 0C */
|
||||||
|
OPCODE(o2_resourceRoutines),
|
||||||
|
OPCODE(o5_walkActorToActor),
|
||||||
|
OPCODE(o2_putActorAtObject),
|
||||||
|
OPCODE(o2_ifNotState08),
|
||||||
|
/* 10 */
|
||||||
|
OPCODE(o5_getObjectOwner),
|
||||||
|
OPCODE(o2_animateActor),
|
||||||
|
OPCODE(o2_panCameraTo),
|
||||||
|
OPCODE(o2_actorOps),
|
||||||
|
/* 14 */
|
||||||
|
OPCODE(o5_print),
|
||||||
|
OPCODE(o2_actorFromPos),
|
||||||
|
OPCODE(o5_getRandomNr),
|
||||||
|
OPCODE(o2_clearState02),
|
||||||
|
/* 18 */
|
||||||
|
OPCODE(o5_jumpRelative),
|
||||||
|
OPCODE(o2_doSentence),
|
||||||
|
OPCODE(o5_move),
|
||||||
|
OPCODE(o2_setBitVar),
|
||||||
|
/* 1C */
|
||||||
|
OPCODE(o5_startSound),
|
||||||
|
OPCODE(o2_ifClassOfIs),
|
||||||
|
OPCODE(o2_walkActorTo),
|
||||||
|
OPCODE(o2_ifState02),
|
||||||
|
/* 20 */
|
||||||
|
OPCODE(o5_stopMusic),
|
||||||
|
OPCODE(o2_putActor),
|
||||||
|
OPCODE(o5_saveLoadGame),
|
||||||
|
OPCODE(o2_getActorY),
|
||||||
|
/* 24 */
|
||||||
|
OPCODE(o2_loadRoomWithEgo),
|
||||||
|
OPCODE(o2_drawObject),
|
||||||
|
OPCODE(o5_setVarRange),
|
||||||
|
OPCODE(o2_setState04),
|
||||||
|
/* 28 */
|
||||||
|
OPCODE(o5_equalZero),
|
||||||
|
OPCODE(o2_setOwnerOf),
|
||||||
|
OPCODE(o2_addIndirect),
|
||||||
|
OPCODE(o5_delayVariable),
|
||||||
|
/* 2C */
|
||||||
|
OPCODE(o2_assignVarByte),
|
||||||
|
OPCODE(o5_putActorInRoom),
|
||||||
|
OPCODE(o2_delay),
|
||||||
|
OPCODE(o2_ifNotState04),
|
||||||
|
/* 30 */
|
||||||
|
OPCODE(o2_setBoxFlags),
|
||||||
|
OPCODE(o2_getBitVar),
|
||||||
|
OPCODE(o2_setCameraAt),
|
||||||
|
OPCODE(o2_roomOps),
|
||||||
|
/* 34 */
|
||||||
|
OPCODE(o5_getDist),
|
||||||
|
OPCODE(o2_findObject),
|
||||||
|
OPCODE(o2_walkActorToObject),
|
||||||
|
OPCODE(o2_setState01),
|
||||||
|
/* 38 */
|
||||||
|
OPCODE(o2_isLessEqual),
|
||||||
|
OPCODE(o2_doSentence),
|
||||||
|
OPCODE(o2_subtract),
|
||||||
|
OPCODE(o2_waitForActor),
|
||||||
|
/* 3C */
|
||||||
|
OPCODE(o5_stopSound),
|
||||||
|
OPCODE(o2_setActorElevation),
|
||||||
|
OPCODE(o2_walkActorTo),
|
||||||
|
OPCODE(o2_ifNotState01),
|
||||||
|
/* 40 */
|
||||||
|
OPCODE(o2_cutscene),
|
||||||
|
OPCODE(o2_putActor),
|
||||||
|
OPCODE(o2_startScript),
|
||||||
|
OPCODE(o2_getActorX),
|
||||||
|
/* 44 */
|
||||||
|
OPCODE(o2_isLess),
|
||||||
|
OPCODE(o2_drawObject),
|
||||||
|
OPCODE(o5_increment),
|
||||||
|
OPCODE(o2_clearState08),
|
||||||
|
/* 48 */
|
||||||
|
OPCODE(o5_isEqual),
|
||||||
|
OPCODE(o5_faceActor),
|
||||||
|
OPCODE(o2_chainScript),
|
||||||
|
OPCODE(o2_setObjPreposition),
|
||||||
|
/* 4C */
|
||||||
|
OPCODE(o2_waitForSentence),
|
||||||
|
OPCODE(o5_walkActorToActor),
|
||||||
|
OPCODE(o2_putActorAtObject),
|
||||||
|
OPCODE(o2_ifState08),
|
||||||
|
/* 50 */
|
||||||
|
OPCODE(o2_pickupObject),
|
||||||
|
OPCODE(o2_animateActor),
|
||||||
|
OPCODE(o5_actorFollowCamera),
|
||||||
|
OPCODE(o2_actorOps),
|
||||||
|
/* 54 */
|
||||||
|
OPCODE(o5_setObjectName),
|
||||||
|
OPCODE(o2_actorFromPos),
|
||||||
|
OPCODE(o5_getActorMoving),
|
||||||
|
OPCODE(o2_setState02),
|
||||||
|
/* 58 */
|
||||||
|
OPCODE(o2_beginOverride),
|
||||||
|
OPCODE(o2_doSentence),
|
||||||
|
OPCODE(o2_add),
|
||||||
|
OPCODE(o2_setBitVar),
|
||||||
|
/* 5C */
|
||||||
|
OPCODE(o2_dummy),
|
||||||
|
OPCODE(o2_ifClassOfIs),
|
||||||
|
OPCODE(o2_walkActorTo),
|
||||||
|
OPCODE(o2_ifNotState02),
|
||||||
|
/* 60 */
|
||||||
|
OPCODE(o2_cursorCommand),
|
||||||
|
OPCODE(o2_putActor),
|
||||||
|
OPCODE(o2_stopScript),
|
||||||
|
OPCODE(o5_getActorFacing),
|
||||||
|
/* 64 */
|
||||||
|
OPCODE(o2_loadRoomWithEgo),
|
||||||
|
OPCODE(o2_drawObject),
|
||||||
|
OPCODE(o5_getClosestObjActor),
|
||||||
|
OPCODE(o2_clearState04),
|
||||||
|
/* 68 */
|
||||||
|
OPCODE(o5_isScriptRunning),
|
||||||
|
OPCODE(o2_setOwnerOf),
|
||||||
|
OPCODE(o2_subIndirect),
|
||||||
|
OPCODE(o2_dummy),
|
||||||
|
/* 6C */
|
||||||
|
OPCODE(o2_getObjPreposition),
|
||||||
|
OPCODE(o5_putActorInRoom),
|
||||||
|
OPCODE(o2_dummy),
|
||||||
|
OPCODE(o2_ifState04),
|
||||||
|
/* 70 */
|
||||||
|
OPCODE(o2_lights),
|
||||||
|
OPCODE(o5_getActorCostume),
|
||||||
|
OPCODE(o5_loadRoom),
|
||||||
|
OPCODE(o2_roomOps),
|
||||||
|
/* 74 */
|
||||||
|
OPCODE(o5_getDist),
|
||||||
|
OPCODE(o2_findObject),
|
||||||
|
OPCODE(o2_walkActorToObject),
|
||||||
|
OPCODE(o2_clearState01),
|
||||||
|
/* 78 */
|
||||||
|
OPCODE(o2_isGreater),
|
||||||
|
OPCODE(o2_doSentence),
|
||||||
|
OPCODE(o2_verbOps),
|
||||||
|
OPCODE(o2_getActorWalkBox),
|
||||||
|
/* 7C */
|
||||||
|
OPCODE(o5_isSoundRunning),
|
||||||
|
OPCODE(o2_setActorElevation),
|
||||||
|
OPCODE(o2_walkActorTo),
|
||||||
|
OPCODE(o2_ifState01),
|
||||||
|
/* 80 */
|
||||||
|
OPCODE(o5_breakHere),
|
||||||
|
OPCODE(o2_putActor),
|
||||||
|
OPCODE(o5_startMusic),
|
||||||
|
OPCODE(o5_getActorRoom),
|
||||||
|
/* 84 */
|
||||||
|
OPCODE(o2_isGreaterEqual),
|
||||||
|
OPCODE(o2_drawObject),
|
||||||
|
OPCODE(o2_getActorElevation),
|
||||||
|
OPCODE(o2_setState08),
|
||||||
|
/* 88 */
|
||||||
|
OPCODE(o5_isNotEqual),
|
||||||
|
OPCODE(o5_faceActor),
|
||||||
|
OPCODE(o2_assignVarWordIndirect),
|
||||||
|
OPCODE(o2_setObjPreposition),
|
||||||
|
/* 8C */
|
||||||
|
OPCODE(o2_resourceRoutines),
|
||||||
|
OPCODE(o5_walkActorToActor),
|
||||||
|
OPCODE(o2_putActorAtObject),
|
||||||
|
OPCODE(o2_ifNotState08),
|
||||||
|
/* 90 */
|
||||||
|
OPCODE(o5_getObjectOwner),
|
||||||
|
OPCODE(o2_animateActor),
|
||||||
|
OPCODE(o2_panCameraTo),
|
||||||
|
OPCODE(o2_actorOps),
|
||||||
|
/* 94 */
|
||||||
|
OPCODE(o5_print),
|
||||||
|
OPCODE(o2_actorFromPos),
|
||||||
|
OPCODE(o5_getRandomNr),
|
||||||
|
OPCODE(o2_clearState02),
|
||||||
|
/* 98 */
|
||||||
|
OPCODE(o2_restart),
|
||||||
|
OPCODE(o2_doSentence),
|
||||||
|
OPCODE(o5_move),
|
||||||
|
OPCODE(o2_setBitVar),
|
||||||
|
/* 9C */
|
||||||
|
OPCODE(o5_startSound),
|
||||||
|
OPCODE(o2_ifClassOfIs),
|
||||||
|
OPCODE(o2_walkActorTo),
|
||||||
|
OPCODE(o2_ifState02),
|
||||||
|
/* A0 */
|
||||||
|
OPCODE(o5_stopObjectCode),
|
||||||
|
OPCODE(o2_putActor),
|
||||||
|
OPCODE(o5_saveLoadGame),
|
||||||
|
OPCODE(o2_getActorY),
|
||||||
|
/* A4 */
|
||||||
|
OPCODE(o2_loadRoomWithEgo),
|
||||||
|
OPCODE(o2_drawObject),
|
||||||
|
OPCODE(o5_setVarRange),
|
||||||
|
OPCODE(o2_setState04),
|
||||||
|
/* A8 */
|
||||||
|
OPCODE(o5_notEqualZero),
|
||||||
|
OPCODE(o2_setOwnerOf),
|
||||||
|
OPCODE(o2_addIndirect),
|
||||||
|
OPCODE(o2_switchCostumeSet),
|
||||||
|
/* AC */
|
||||||
|
OPCODE(o2_drawSentence),
|
||||||
|
OPCODE(o5_putActorInRoom),
|
||||||
|
OPCODE(o2_waitForMessage),
|
||||||
|
OPCODE(o2_ifNotState04),
|
||||||
|
/* B0 */
|
||||||
|
OPCODE(o2_setBoxFlags),
|
||||||
|
OPCODE(o2_getBitVar),
|
||||||
|
OPCODE(o2_setCameraAt),
|
||||||
|
OPCODE(o2_roomOps),
|
||||||
|
/* B4 */
|
||||||
|
OPCODE(o5_getDist),
|
||||||
|
OPCODE(o2_findObject),
|
||||||
|
OPCODE(o2_walkActorToObject),
|
||||||
|
OPCODE(o2_setState01),
|
||||||
|
/* B8 */
|
||||||
|
OPCODE(o2_isLessEqual),
|
||||||
|
OPCODE(o2_doSentence),
|
||||||
|
OPCODE(o2_subtract),
|
||||||
|
OPCODE(o2_waitForActor),
|
||||||
|
/* BC */
|
||||||
|
OPCODE(o5_stopSound),
|
||||||
|
OPCODE(o2_setActorElevation),
|
||||||
|
OPCODE(o2_walkActorTo),
|
||||||
|
OPCODE(o2_ifNotState01),
|
||||||
|
/* C0 */
|
||||||
|
OPCODE(o2_endCutscene),
|
||||||
|
OPCODE(o2_putActor),
|
||||||
|
OPCODE(o2_startScript),
|
||||||
|
OPCODE(o2_getActorX),
|
||||||
|
/* C4 */
|
||||||
|
OPCODE(o2_isLess),
|
||||||
|
OPCODE(o2_drawObject),
|
||||||
|
OPCODE(o5_decrement),
|
||||||
|
OPCODE(o2_clearState08),
|
||||||
|
/* C8 */
|
||||||
|
OPCODE(o5_isEqual),
|
||||||
|
OPCODE(o5_faceActor),
|
||||||
|
OPCODE(o2_chainScript),
|
||||||
|
OPCODE(o2_setObjPreposition),
|
||||||
|
/* CC */
|
||||||
|
OPCODE(o5_pseudoRoom),
|
||||||
|
OPCODE(o5_walkActorToActor),
|
||||||
|
OPCODE(o2_putActorAtObject),
|
||||||
|
OPCODE(o2_ifState08),
|
||||||
|
/* D0 */
|
||||||
|
OPCODE(o2_pickupObject),
|
||||||
|
OPCODE(o2_animateActor),
|
||||||
|
OPCODE(o5_actorFollowCamera),
|
||||||
|
OPCODE(o2_actorOps),
|
||||||
|
/* D4 */
|
||||||
|
OPCODE(o5_setObjectName),
|
||||||
|
OPCODE(o2_actorFromPos),
|
||||||
|
OPCODE(o5_getActorMoving),
|
||||||
|
OPCODE(o2_setState02),
|
||||||
|
/* D8 */
|
||||||
|
OPCODE(o5_printEgo),
|
||||||
|
OPCODE(o2_doSentence),
|
||||||
|
OPCODE(o2_add),
|
||||||
|
OPCODE(o2_setBitVar),
|
||||||
|
/* DC */
|
||||||
|
OPCODE(o2_dummy),
|
||||||
|
OPCODE(o2_ifClassOfIs),
|
||||||
|
OPCODE(o2_walkActorTo),
|
||||||
|
OPCODE(o2_ifNotState02),
|
||||||
|
/* E0 */
|
||||||
|
OPCODE(o2_cursorCommand),
|
||||||
|
OPCODE(o2_putActor),
|
||||||
|
OPCODE(o2_stopScript),
|
||||||
|
OPCODE(o5_getActorFacing),
|
||||||
|
/* E4 */
|
||||||
|
OPCODE(o2_loadRoomWithEgo),
|
||||||
|
OPCODE(o2_drawObject),
|
||||||
|
OPCODE(o5_getClosestObjActor),
|
||||||
|
OPCODE(o2_clearState04),
|
||||||
|
/* E8 */
|
||||||
|
OPCODE(o5_isScriptRunning),
|
||||||
|
OPCODE(o2_setOwnerOf),
|
||||||
|
OPCODE(o2_subIndirect),
|
||||||
|
OPCODE(o2_dummy),
|
||||||
|
/* EC */
|
||||||
|
OPCODE(o2_getObjPreposition),
|
||||||
|
OPCODE(o5_putActorInRoom),
|
||||||
|
OPCODE(o2_dummy),
|
||||||
|
OPCODE(o2_ifState04),
|
||||||
|
/* F0 */
|
||||||
|
OPCODE(o2_lights),
|
||||||
|
OPCODE(o5_getActorCostume),
|
||||||
|
OPCODE(o5_loadRoom),
|
||||||
|
OPCODE(o2_roomOps),
|
||||||
|
/* F4 */
|
||||||
|
OPCODE(o5_getDist),
|
||||||
|
OPCODE(o2_findObject),
|
||||||
|
OPCODE(o2_walkActorToObject),
|
||||||
|
OPCODE(o2_clearState01),
|
||||||
|
/* F8 */
|
||||||
|
OPCODE(o2_isGreater),
|
||||||
|
OPCODE(o2_doSentence),
|
||||||
|
OPCODE(o2_verbOps),
|
||||||
|
OPCODE(o2_getActorWalkBox),
|
||||||
|
/* FC */
|
||||||
|
OPCODE(o5_isSoundRunning),
|
||||||
|
OPCODE(o2_setActorElevation),
|
||||||
|
OPCODE(o2_walkActorTo),
|
||||||
|
OPCODE(o2_ifState01)
|
||||||
|
};
|
||||||
|
|
||||||
|
_opcodesC64 = opcodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SENTENCE_SCRIPT 2
|
||||||
|
|
||||||
|
#define PARAM_1 0x80
|
||||||
|
#define PARAM_2 0x40
|
||||||
|
#define PARAM_3 0x20
|
||||||
|
|
||||||
|
void ScummEngine_c64::executeOpcode(byte i) {
|
||||||
|
OpcodeProcC64 op = _opcodesC64[i].proc;
|
||||||
|
(this->*op) ();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ScummEngine_c64::getOpcodeDesc(byte i) {
|
||||||
|
return _opcodesC64[i].desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef PARAM_1
|
||||||
|
#undef PARAM_2
|
||||||
|
#undef PARAM_3
|
||||||
|
|
||||||
|
} // End of namespace Scumm
|
|
@ -1266,6 +1266,10 @@ ScummEngine_v2::ScummEngine_v2(GameDetector *detector, OSystem *syst, const Scum
|
||||||
: ScummEngine_v3old(detector, syst, gs, md5sum) {
|
: ScummEngine_v3old(detector, syst, gs, md5sum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScummEngine_c64::ScummEngine_c64(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16])
|
||||||
|
: ScummEngine_v2(detector, syst, gs, md5sum) {
|
||||||
|
}
|
||||||
|
|
||||||
ScummEngine_v6::ScummEngine_v6(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16])
|
ScummEngine_v6::ScummEngine_v6(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16])
|
||||||
: ScummEngine(detector, syst, gs, md5sum) {
|
: ScummEngine(detector, syst, gs, md5sum) {
|
||||||
_blastObjectQueuePos = 0;
|
_blastObjectQueuePos = 0;
|
||||||
|
@ -2874,7 +2878,11 @@ Engine *Engine_SCUMM_create(GameDetector *detector, OSystem *syst) {
|
||||||
switch (game.version) {
|
switch (game.version) {
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
engine = new ScummEngine_v2(detector, syst, game, md5sum);
|
// Limit to C64 MM?
|
||||||
|
if (game.platform == Common::kPlatformC64)
|
||||||
|
engine = new ScummEngine_c64(detector, syst, game, md5sum);
|
||||||
|
else
|
||||||
|
engine = new ScummEngine_v2(detector, syst, game, md5sum);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (game.features & GF_OLD_BUNDLE)
|
if (game.features & GF_OLD_BUNDLE)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue