mirror of https://github.com/bgiraudr/Adoranda.git
Teleporter
This commit is contained in:
parent
a12fb2e47f
commit
6cb8167eba
|
@ -21,6 +21,7 @@ add_custom_command(
|
|||
COMMAND find | grep .*.tmx | sed 's/.tmx//g' | xargs -l bash -c 'tiled --export-map json $$0.tmx $$0.json'
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/assets-cg/maps/
|
||||
DEPENDS assets-cg/maps/testCarte.tmx
|
||||
assets-cg/maps/1.tmx
|
||||
assets-cg/tileset.png
|
||||
assets-cg/maps/tileset.tsx
|
||||
assets-cg/converters.py
|
||||
|
@ -44,6 +45,7 @@ set(SOURCES
|
|||
set(ASSETS_cg
|
||||
assets-cg/tileset.png
|
||||
assets-cg/maps/testCarte.json
|
||||
assets-cg/maps/1.json
|
||||
assets-cg/maps/inside/1.json
|
||||
assets-cg/maps/inside/2.json
|
||||
assets-cg/maps/inside/3.json
|
||||
|
|
|
@ -15,8 +15,10 @@ def convert_map(input, output, params, target):
|
|||
TILE_DOOR_IN = 2
|
||||
TILE_DOOR_OUT = 3
|
||||
TILE_TALKABLE = 4
|
||||
TILE_TELEPORTER = 5
|
||||
|
||||
DIALOG_LAYOUT = "dialog"
|
||||
TELEPORTER_LAYOUT = "teleporter"
|
||||
|
||||
data = json.load(open(input, "r"))
|
||||
|
||||
|
@ -51,6 +53,8 @@ def convert_map(input, output, params, target):
|
|||
value = TILE_TALKABLE
|
||||
elif type == "bridge":
|
||||
value = TILE_BRIDGE
|
||||
elif type == "teleporter":
|
||||
value = TILE_TELEPORTER
|
||||
else:
|
||||
value = TILE_AIR
|
||||
|
||||
|
@ -64,19 +68,25 @@ def convert_map(input, output, params, target):
|
|||
objectLayers = data["layers"][nbTilelayer:len(data["layers"])]
|
||||
|
||||
nbDialog = 0
|
||||
nbTelep = 0
|
||||
structMap = fxconv.Structure()
|
||||
dialogs = fxconv.Structure()
|
||||
teleporter = fxconv.Structure()
|
||||
|
||||
for layer in objectLayers:
|
||||
if layer.get("name") == DIALOG_LAYOUT:
|
||||
nbDialog = len(layer["objects"])
|
||||
dialogs = parseDialog(layer)
|
||||
elif layer.get("name") == TELEPORTER_LAYOUT:
|
||||
nbTelep = len(layer["objects"])
|
||||
teleporter = parseTeleporter(layer)
|
||||
else:
|
||||
print("UNKNOWN LAYOUT FOUND : " + layer.get("name"))
|
||||
|
||||
structMap += fxconv.u32(w) + fxconv.u32(h) + fxconv.u32(nbTilelayer) + fxconv.u32(nbDialog)
|
||||
structMap += fxconv.u32(w) + fxconv.u32(h) + fxconv.u32(nbTilelayer) + fxconv.u32(nbDialog) + fxconv.u32(nbTelep)
|
||||
structMap += fxconv.ref(f"img_{nameTilesetFree}")
|
||||
structMap += fxconv.ptr(dialogs)
|
||||
structMap += fxconv.ptr(teleporter)
|
||||
|
||||
#generation of the collision map (take the maximum of the layer except for bridges)
|
||||
#bridges are always walkable
|
||||
|
@ -126,4 +136,23 @@ def parseDialog(layer):
|
|||
except KeyError:
|
||||
dialogs += fxconv.string("default name")
|
||||
dialogs += fxconv.string("default text")
|
||||
return dialogs
|
||||
return dialogs
|
||||
|
||||
def parseTeleporter(layer):
|
||||
teleporter = fxconv.Structure()
|
||||
for i in layer["objects"]:
|
||||
teleporter += fxconv.u32(int(i["x"]/i["width"]))
|
||||
#Tiled seem to start at the bottom y of the object
|
||||
teleporter += fxconv.u32(int(i["y"]/i["width"])-1)
|
||||
|
||||
try:
|
||||
if len(i["properties"]) < 2:
|
||||
raise Exception("parseTeleporter() : Un téléporteur est mal configuré")
|
||||
if len(i["properties"]) == 2:
|
||||
print("parseTeleporter() : passage automatique idMap = -1 sur téléporteur x = " + str(i["properties"][0]["value"]) + ", y = " + str(i["properties"][1]["value"]))
|
||||
teleporter += fxconv.u32(-1);
|
||||
for j in i["properties"]:
|
||||
teleporter += fxconv.u32(j["value"])
|
||||
except KeyError :
|
||||
raise Exception("parseTeleporter() : Un téléporteur est mal configuré")
|
||||
return teleporter
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="12" height="10" tilewidth="16" tileheight="16" infinite="0" nextlayerid="13" nextobjectid="40">
|
||||
<editorsettings>
|
||||
<export target="interior_1.json" format="json"/>
|
||||
</editorsettings>
|
||||
<tileset firstgid="1" source="tileset.tsx"/>
|
||||
<layer id="5" name="1" width="12" height="10">
|
||||
<data encoding="csv">
|
||||
79,80,141,141,80,141,141,80,80,80,141,81,
|
||||
113,4,30,1,2,3,3,34,3,2,2,111,
|
||||
113,31,34,2,1,146,148,35,32,1,1,111,
|
||||
108,3,2,2,146,149,150,148,30,32,4,111,
|
||||
113,109,3,4,204,205,205,206,4,3,2,111,
|
||||
108,37,32,3,4,2,4,3,3,3,1,110,
|
||||
113,240,242,3,3,2,2,30,30,2,3,111,
|
||||
108,269,244,242,2,3,2,33,4,2,4,110,
|
||||
113,298,299,300,4,30,33,2,4,1,4,110,
|
||||
137,83,83,138,138,138,138,83,138,138,138,139
|
||||
</data>
|
||||
</layer>
|
||||
<layer id="1" name="2" width="12" height="10">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,320,321,322,
|
||||
0,0,0,0,0,0,0,0,0,349,350,351,
|
||||
0,0,0,0,0,28,26,0,0,378,379,380,
|
||||
0,0,0,0,0,57,55,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,239,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="10" name="dialog">
|
||||
<object id="36" gid="267" x="80" y="64" width="16" height="16">
|
||||
<properties>
|
||||
<property name="name" value="Inconnu"/>
|
||||
<property name="text" value="Bienvenue dans un monde différent"/>
|
||||
</properties>
|
||||
</object>
|
||||
</objectgroup>
|
||||
<objectgroup id="12" name="teleporter">
|
||||
<object id="39" gid="238" x="144" y="112" width="16" height="16">
|
||||
<properties>
|
||||
<property name="idMap" type="int" value="0"/>
|
||||
<property name="x" type="int" value="25"/>
|
||||
<property name="y" type="int" value="33"/>
|
||||
</properties>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
|
@ -1,3 +1,6 @@
|
|||
testCarte.json:
|
||||
custom-type: map
|
||||
name: map_1
|
||||
1.json:
|
||||
custom-type: map
|
||||
name: map_2
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="12" height="10" tilewidth="16" tileheight="16" infinite="0" nextlayerid="12" nextobjectid="35">
|
||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="12" height="10" tilewidth="16" tileheight="16" infinite="0" nextlayerid="12" nextobjectid="36">
|
||||
<editorsettings>
|
||||
<export target="interior_1.json" format="json"/>
|
||||
</editorsettings>
|
||||
|
@ -46,7 +46,4 @@
|
|||
</properties>
|
||||
</object>
|
||||
</objectgroup>
|
||||
<objectgroup id="11" name="test">
|
||||
<object id="34" gid="267" x="80" y="64" width="16" height="16"/>
|
||||
</objectgroup>
|
||||
</map>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="20" height="15" tilewidth="16" tileheight="16" infinite="0" nextlayerid="5" nextobjectid="5">
|
||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="20" height="15" tilewidth="16" tileheight="16" infinite="0" nextlayerid="6" nextobjectid="13">
|
||||
<editorsettings>
|
||||
<export target="3.json" format="json"/>
|
||||
</editorsettings>
|
||||
<tileset firstgid="1" source="../tileset.tsx"/>
|
||||
<layer id="1" name="1" width="20" height="15">
|
||||
<data encoding="csv">
|
||||
|
@ -31,10 +34,10 @@
|
|||
0,0,620,0,0,0,0,0,0,740,742,649,0,0,0,0,0,0,0,0,
|
||||
682,683,649,683,683,683,684,0,0,0,0,0,0,682,683,683,683,683,683,684,
|
||||
711,712,0,712,712,712,713,0,0,0,0,0,0,711,712,712,712,712,712,713,
|
||||
740,701,0,741,741,701,742,0,0,0,0,0,0,740,741,741,741,741,741,742,
|
||||
740,701,0,741,741,701,742,0,0,239,0,0,0,740,741,741,741,741,741,742,
|
||||
0,730,0,0,0,730,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,702,703,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,239,0,0,0,0,702,703,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,731,732,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</data>
|
||||
|
@ -72,4 +75,18 @@
|
|||
</properties>
|
||||
</object>
|
||||
</objectgroup>
|
||||
<objectgroup id="5" name="teleporter">
|
||||
<object id="11" gid="238" x="144" y="160" width="16" height="16">
|
||||
<properties>
|
||||
<property name="x" type="int" value="19"/>
|
||||
<property name="y" type="int" value="3"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="12" gid="238" x="176" y="208" width="16" height="16">
|
||||
<properties>
|
||||
<property name="x" type="int" value="0"/>
|
||||
<property name="y" type="int" value="14"/>
|
||||
</properties>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="100" height="38" tilewidth="16" tileheight="16" infinite="0" nextlayerid="11" nextobjectid="48">
|
||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="100" height="38" tilewidth="16" tileheight="16" infinite="0" nextlayerid="12" nextobjectid="52">
|
||||
<editorsettings>
|
||||
<export target="testCarte.json" format="json"/>
|
||||
</editorsettings>
|
||||
|
@ -80,8 +80,8 @@
|
|||
0,0,0,0,0,0,0,0,0,294,294,0,0,0,0,0,0,0,0,0,294,0,0,0,0,294,0,0,0,0,0,751,752,753,754,0,0,41,42,0,0,0,0,0,294,294,0,0,0,0,29,0,0,0,137,138,138,138,139,0,0,0,280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,284,285,286,287,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,48,
|
||||
0,0,0,0,0,0,0,0,0,294,294,56,0,0,0,0,0,0,294,294,294,0,0,0,0,294,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,294,294,0,0,0,0,58,0,0,0,0,0,0,0,0,0,0,0,280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,284,285,286,287,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,294,294,294,0,0,0,0,0,0,0,0,0,0,0,0,0,294,294,0,0,0,0,0,0,252,253,253,0,28,0,253,253,254,0,0,294,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,284,285,286,287,0,0,0,0,0,0,0,0,0,12,13,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,320,321,322,294,294,0,0,0,0,0,0,0,0,0,0,0,0,0,294,294,0,0,0,0,0,0,0,0,0,0,57,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,313,314,315,316,0,0,0,656,657,658,659,0,0,41,42,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,349,350,351,56,294,0,0,0,0,0,0,0,0,0,0,0,0,0,294,294,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,342,343,344,345,0,0,0,685,686,687,688,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,320,321,322,294,294,0,0,0,0,0,0,0,0,0,0,0,0,0,294,294,0,239,0,0,0,0,0,0,0,0,57,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,313,314,315,316,0,0,0,656,657,658,659,0,0,41,42,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,349,350,351,56,294,0,0,0,0,0,0,0,0,0,0,0,0,0,294,294,0,0,0,239,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,342,343,344,345,0,0,0,685,686,687,688,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,378,379,380,294,294,0,0,320,321,322,0,0,0,0,0,0,0,0,294,0,0,0,0,0,0,0,339,340,340,340,340,340,340,340,341,0,0,0,0,0,0,0,320,321,322,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,714,715,716,717,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
294,0,0,0,0,0,0,0,0,0,0,0,0,0,349,350,351,0,0,294,294,294,294,294,294,294,323,324,325,323,324,325,323,324,325,0,0,0,0,0,0,0,0,0,0,0,0,0,0,349,350,351,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,13,0,0,0,0,0,0,0,0,28,0,743,744,745,746,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
294,0,0,0,0,0,0,0,0,0,0,0,0,0,378,379,380,0,0,0,294,294,294,294,0,0,352,353,354,352,353,354,352,353,354,0,0,0,0,0,0,0,0,0,0,0,0,0,0,378,379,380,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,0,0,0,0,0,0,0,0,57,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
|
@ -180,4 +180,19 @@
|
|||
</properties>
|
||||
</object>
|
||||
</objectgroup>
|
||||
<objectgroup id="11" name="teleporter">
|
||||
<object id="50" gid="238" x="448" y="528" width="16" height="16">
|
||||
<properties>
|
||||
<property name="x" type="int" value="29"/>
|
||||
<property name="y" type="int" value="29"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="51" gid="238" x="480" y="544" width="16" height="16">
|
||||
<properties>
|
||||
<property name="idMap" type="int" value="1"/>
|
||||
<property name="x" type="int" value="5"/>
|
||||
<property name="y" type="int" value="5"/>
|
||||
</properties>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
||||
|
|
|
@ -63,7 +63,8 @@
|
|||
<tile id="234" type="solid"/>
|
||||
<tile id="235" type="solid"/>
|
||||
<tile id="236" type="solid"/>
|
||||
<tile id="237" type="air"/>
|
||||
<tile id="237" type="teleporter"/>
|
||||
<tile id="238" type="teleporter"/>
|
||||
<tile id="239" type="solid"/>
|
||||
<tile id="240" type="solid"/>
|
||||
<tile id="241" type="solid"/>
|
||||
|
@ -119,6 +120,7 @@
|
|||
<tile id="297" type="solid"/>
|
||||
<tile id="298" type="solid"/>
|
||||
<tile id="299" type="solid"/>
|
||||
<tile id="301" type="solid"/>
|
||||
<tile id="302" type="solid"/>
|
||||
<tile id="303" type="solid"/>
|
||||
<tile id="304" type="solid"/>
|
||||
|
@ -189,6 +191,7 @@
|
|||
<tile id="666" type="solid"/>
|
||||
<tile id="674" type="solid"/>
|
||||
<tile id="675" type="solid"/>
|
||||
<tile id="676" type="air"/>
|
||||
<tile id="677" type="solid"/>
|
||||
<tile id="681" type="solid"/>
|
||||
<tile id="682" type="solid"/>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
@ -2,13 +2,20 @@
|
|||
#include <gint/display.h>
|
||||
#include "engine.h"
|
||||
|
||||
struct Teleporter {
|
||||
int x, y;
|
||||
int idMap;
|
||||
int x2, y2;
|
||||
};
|
||||
|
||||
struct Map {
|
||||
/*width, height and the number of layer of the map (max 2)*/
|
||||
int w, h, nb_layers, dialog_count;
|
||||
/*width, height and the number of layer of the map*/
|
||||
int w, h, nb_layers, dialog_count, teleporter_count;
|
||||
/*the tileset to use*/
|
||||
bopti_image_t *tileset;
|
||||
/*list of all the dialog*/
|
||||
struct Talkable *dialogs;
|
||||
struct Teleporter *teleporters;
|
||||
/*state of each tile on the map (solid, air ...)*/
|
||||
short *info_map;
|
||||
/*list of all the tiles*/
|
||||
|
@ -21,6 +28,7 @@ enum map_state {
|
|||
TILE_DOOR_IN = 2,
|
||||
TILE_DOOR_OUT = 3,
|
||||
TILE_TALKABLE = 4,
|
||||
TILE_TELEPORTER = 5,
|
||||
};
|
||||
|
||||
/*check if a tile is walkable*/
|
||||
|
@ -32,4 +40,6 @@ void generate_interior_map(struct Game *game);
|
|||
|
||||
void set_map(struct Game *game, int id);
|
||||
|
||||
struct Vec2 locate_tile(struct Map const *map, int tile);
|
||||
struct Vec2 locate_tile(struct Map const *map, int tile);
|
||||
|
||||
struct Teleporter get_teleporter_xy(struct Map *map, struct Vec2 pos);
|
10
src/engine.c
10
src/engine.c
|
@ -136,6 +136,7 @@ void engine_check_position(struct Game *game) {
|
|||
old_map = game->map;
|
||||
old_pos = game->player->pos;
|
||||
generate_interior_map(game);
|
||||
engine_center_camera(game);
|
||||
}
|
||||
if(player_curr_tile == TILE_DOOR_OUT) {
|
||||
game->map = old_map;
|
||||
|
@ -144,6 +145,15 @@ void engine_check_position(struct Game *game) {
|
|||
game->player->anim.dir = DIR_DOWN;
|
||||
engine_center_camera(game);
|
||||
}
|
||||
if(player_curr_tile == TILE_TELEPORTER) {
|
||||
struct Teleporter teleporter = get_teleporter_xy(game->map, game->player->pos);
|
||||
game->player->pos.x = teleporter.x2;
|
||||
game->player->pos.y = teleporter.y2;
|
||||
if(teleporter.idMap != -1) {
|
||||
set_map(game, teleporter.idMap);
|
||||
}
|
||||
engine_center_camera(game);
|
||||
}
|
||||
}
|
||||
|
||||
void engine_center_camera(struct Game *game) {
|
||||
|
|
15
src/map.c
15
src/map.c
|
@ -1,14 +1,16 @@
|
|||
#include <gint/std/stdlib.h>
|
||||
|
||||
#include <gint/keyboard.h>
|
||||
#include "map.h"
|
||||
#include "player.h"
|
||||
#include "define.h"
|
||||
#include "util.h"
|
||||
|
||||
extern struct Map map_1;
|
||||
extern struct Map map_2;
|
||||
|
||||
struct Map *maps[] = {
|
||||
&map_1,
|
||||
&map_2,
|
||||
};
|
||||
|
||||
/*check if a tile is walkable*/
|
||||
|
@ -41,13 +43,11 @@ void generate_interior_map(struct Game *game) {
|
|||
|
||||
game->map = interiors[rand_range(0,NB_INTERIORS)];
|
||||
game->player->pos = locate_tile(game->map, TILE_DOOR_OUT);
|
||||
engine_center_camera(game);
|
||||
}
|
||||
|
||||
/*may be useful later*/
|
||||
void set_map(struct Game *game, int id) {
|
||||
game->map = maps[id];
|
||||
game->camera.pos = vec2f_lerp(game->camera.pos, *game->camera.target, 1);
|
||||
}
|
||||
|
||||
/*locate the first occurence of a tile in a specified map*/
|
||||
|
@ -61,4 +61,13 @@ struct Vec2 locate_tile(struct Map const *map, int tile) {
|
|||
}
|
||||
}
|
||||
return VEC2(0,0);
|
||||
}
|
||||
|
||||
struct Teleporter get_teleporter_xy(struct Map *map, struct Vec2 pos) {
|
||||
int i = 0;
|
||||
while(i < map->teleporter_count) {
|
||||
if(map->teleporters[i].x == pos.x && map->teleporters[i].y == pos.y) return map->teleporters[i];
|
||||
i++;
|
||||
}
|
||||
return map->teleporters[0];
|
||||
}
|
Loading…
Reference in New Issue