Work
Tweaks and improvements. Added a few sprites for battle. Some setup for battle.
This commit is contained in:
parent
dc54aa3209
commit
1fdd0d7ae6
12 changed files with 287 additions and 37 deletions
|
@ -19,7 +19,7 @@ normal = Vector2(-1, 0)
|
|||
|
||||
[node name="DungeonEntrance" type="Sprite2D" parent="."]
|
||||
texture_filter = 1
|
||||
position = Vector2(2, -784)
|
||||
position = Vector2(0, -784)
|
||||
scale = Vector2(1.995, 1.995)
|
||||
texture = ExtResource("1_vo6aq")
|
||||
|
||||
|
@ -32,7 +32,7 @@ polygon = PackedVector2Array(-160, 127, -159, -129, 160, -126, 161, 127, 21, 127
|
|||
|
||||
[node name="DungeonGuard" type="Sprite2D" parent="."]
|
||||
texture_filter = 1
|
||||
position = Vector2(2, -552)
|
||||
position = Vector2(0, -552)
|
||||
scale = Vector2(1.71, 1.71)
|
||||
texture = ExtResource("2_nujkm")
|
||||
|
||||
|
@ -50,7 +50,7 @@ position = Vector2(-307, -1)
|
|||
shape = SubResource("WorldBoundaryShape2D_ocep5")
|
||||
|
||||
[node name="CollisionShape2D2" type="CollisionShape2D" parent="StaticBody2D"]
|
||||
position = Vector2(0, 210)
|
||||
position = Vector2(0, 243)
|
||||
shape = SubResource("WorldBoundaryShape2D_gq7j0")
|
||||
|
||||
[node name="CollisionShape2D3" type="CollisionShape2D" parent="StaticBody2D"]
|
||||
|
@ -59,8 +59,8 @@ shape = SubResource("WorldBoundaryShape2D_xvl4y")
|
|||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
z_index = 5
|
||||
offset_left = -111.0
|
||||
offset_top = 152.0
|
||||
offset_right = 111.0
|
||||
offset_bottom = 175.0
|
||||
offset_left = -110.0
|
||||
offset_top = 208.0
|
||||
offset_right = 112.0
|
||||
offset_bottom = 231.0
|
||||
text = "The Dungeon is to the north!"
|
||||
|
|
143
MainLogic.gd
143
MainLogic.gd
|
@ -12,7 +12,7 @@ extends Node2D
|
|||
|
||||
@onready var camera = $Camera2D
|
||||
|
||||
const camera_move_speed = 80.0
|
||||
const camera_move_speed = 1.5
|
||||
|
||||
const text_speed = 0.08
|
||||
|
||||
|
@ -21,8 +21,8 @@ const start_text = "You seek the elementals?\nProve your worth!\nShow the elemen
|
|||
const intro_text_00 = "The name's Gander Schwartz.\nBut my friends call me the \"Wandering Gander\"."
|
||||
const intro_text_01 = "I'm what most would call a \"third-rate summoner\",\nbut there's a reason for that.\nI summon \"items\", not \"beasts\"."
|
||||
const intro_text_02 = "Most summoners summon beasts to fight for them.\nI summon items to fight with, or even tools to solve puzzles in dungeons."
|
||||
const intro_text_03 = "There is one dungeon I've been itching to conquer.\nThe elemental dungeon!"
|
||||
const intro_text_04 = "If I beat the elemental dungeon,\nI'll be able to enhance my summons with elemental properties!"
|
||||
const intro_text_03 = "There is one dungeon I've been itching to conquer.\nThe Elemental Dungeon!"
|
||||
const intro_text_04 = "If I beat the Elemental Dungeon,\nI'll be able to enhance my summons with elemental properties!"
|
||||
const intro_text_05 = "No longer would I need to light an oil lantern with flint and steel,\nor keep lugging around leather skins for water!"
|
||||
const intro_text_06 = "But the dungeon is a challenge.\nA challenge I hope to best with my wits and my item summoning!"
|
||||
|
||||
|
@ -56,20 +56,27 @@ enum StateT {
|
|||
Dungeon_Entrance_Battle,
|
||||
}
|
||||
|
||||
enum BattleMenu {
|
||||
MainMenu,
|
||||
}
|
||||
|
||||
static var state_dict = {}
|
||||
|
||||
var tween_volume
|
||||
var tween_text
|
||||
var tween_scene
|
||||
|
||||
var diamonds_gone = false
|
||||
|
||||
var music_file
|
||||
|
||||
var gander
|
||||
|
||||
var level
|
||||
var level_guard = null
|
||||
|
||||
var level_cached_pos = null
|
||||
|
||||
var viewport_size
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
if not state_dict.has("state"):
|
||||
|
@ -81,6 +88,11 @@ func _ready():
|
|||
"angle" : 0.0
|
||||
}
|
||||
music_player.play()
|
||||
viewport_size = get_viewport().size
|
||||
get_viewport().size_changed.connect(func():
|
||||
viewport_size = get_viewport().size
|
||||
state_dict["battle_refresh_gui"] = true
|
||||
)
|
||||
|
||||
func update_text(text, next_state):
|
||||
if state_dict["timer"] > text_speed:
|
||||
|
@ -113,9 +125,7 @@ func _process(delta):
|
|||
main_label.text = ""
|
||||
lower_label.text = ""
|
||||
music_player.volume_db = 0.0
|
||||
music_player.stream = AudioStreamMP3.new()
|
||||
music_file = FileAccess.open("res://audio/LD55_1.mp3", FileAccess.READ)
|
||||
music_player.stream.data = music_file.get_buffer(music_file.get_length())
|
||||
music_player.stream = load("res://audio/LD55_1.mp3")
|
||||
music_player.stream.loop = true
|
||||
music_player.play()
|
||||
var gander_scene = preload("res://gander_schwartz.tscn")
|
||||
|
@ -125,6 +135,8 @@ func _process(delta):
|
|||
gander.position.y = 50
|
||||
gander.velocity.x = -gander.SPEED
|
||||
gander.auto_control_action = "walking_left"
|
||||
tween_scene = get_tree().create_tween()
|
||||
tween_scene.tween_method(func(c): RenderingServer.set_default_clear_color(c), Color(0.13, 0.13, 0.13, 1.0), Color(0.3, 0.4, 0.1, 1.0), 4)
|
||||
StateT.Introduction_00:
|
||||
update_stop_diamonds(delta)
|
||||
update_text(intro_text_00, StateT.Introduction_00_post)
|
||||
|
@ -174,11 +186,8 @@ func _process(delta):
|
|||
lower_label.text = ""
|
||||
lower_label.self_modulate = Color(1, 1, 1, 1)
|
||||
)
|
||||
music_file.close()
|
||||
music_player.volume_db = 0.0
|
||||
music_player.stream = AudioStreamMP3.new()
|
||||
music_file = FileAccess.open("res://audio/LD55_2.mp3", FileAccess.READ)
|
||||
music_player.stream.data = music_file.get_buffer(music_file.get_length())
|
||||
music_player.stream = load("res://audio/LD55_2.mp3")
|
||||
music_player.stream.loop = true
|
||||
music_player.play()
|
||||
StateT.Dungeon_Entrance:
|
||||
|
@ -188,6 +197,33 @@ func _process(delta):
|
|||
if level_guard != null and gander.last_collided_id == level_guard.get_instance_id():
|
||||
print("collided with guard.")
|
||||
gander.last_collided_id = null
|
||||
music_player.stop()
|
||||
music_player.stream = preload("res://audio/LD55_3.mp3")
|
||||
music_player.stream.loop = true
|
||||
music_player.play()
|
||||
level.find_child("DungeonGuardCollider").set_deferred("disabled", true)
|
||||
gander.find_child("CollisionShape2D").set_deferred("disabled", true)
|
||||
gander.player_controlled = false
|
||||
gander.current_scene_type = gander.GanderSceneT.Battle
|
||||
tween_scene = get_tree().create_tween()
|
||||
level_cached_pos = level.find_child("DungeonEntrance").position
|
||||
var battle_pos = level_cached_pos + Vector2(0.0, 500.0)
|
||||
tween_scene.set_parallel()
|
||||
tween_scene.tween_property(level.find_child("DungeonGuard"), "position", battle_pos - Vector2(200.0, 30.0), 2.0)
|
||||
tween_scene.tween_property(gander, "position", battle_pos + Vector2(200.0, 0.0), 2.0)
|
||||
gander.auto_control_action = "walking_right"
|
||||
tween_scene.set_parallel(false)
|
||||
tween_scene.tween_callback(func():
|
||||
gander.auto_control_action = "facing_left"
|
||||
state_dict["state"] = StateT.Dungeon_Entrance_Battle
|
||||
state_dict["battle_state"] = BattleMenu.MainMenu
|
||||
state_dict["battle_menu_setup"] = false
|
||||
state_dict["battle_refresh_gui"] = false
|
||||
state_dict["battle_item"] = null
|
||||
)
|
||||
StateT.Dungeon_Entrance_Battle:
|
||||
camera_to_target(delta, level_cached_pos + Vector2(0.0, 500.0))
|
||||
setup_battle_menu()
|
||||
_:
|
||||
pass
|
||||
if gander is MainCharacter and not gander.player_controlled and gander.current_scene_type == gander.GanderSceneT.Introduction:
|
||||
|
@ -198,7 +234,9 @@ func _process(delta):
|
|||
|
||||
|
||||
func _unhandled_input(event):
|
||||
if event.is_pressed() and event.is_action("Confirm"):
|
||||
if state_dict["state"] == StateT.Dungeon_Entrance_Battle:
|
||||
handle_battle_input(event)
|
||||
elif event.is_pressed() and event.is_action("Confirm"):
|
||||
match state_dict["state"]:
|
||||
StateT.Start:
|
||||
main_label.text = start_text
|
||||
|
@ -335,12 +373,75 @@ func update_stop_diamonds(delta):
|
|||
diamond_position_update()
|
||||
|
||||
func camera_to_gander(delta):
|
||||
var diff = gander.position - camera.position
|
||||
if diff.length() > 0.04:
|
||||
var move_vec = diff.normalized() * camera_move_speed * delta
|
||||
if diff.length() < move_vec.length():
|
||||
camera.position = gander.position
|
||||
camera_to_target(delta, gander.position)
|
||||
|
||||
func camera_to_target(delta, vec2):
|
||||
var diff = vec2 - camera.position
|
||||
camera.position += diff * delta * camera_move_speed
|
||||
|
||||
func setup_battle_menu():
|
||||
match state_dict["battle_state"]:
|
||||
BattleMenu.MainMenu:
|
||||
if not state_dict["battle_menu_setup"] or state_dict["battle_refresh_gui"]:
|
||||
state_dict["battle_menu_setup"] = true
|
||||
state_dict["battle_refresh_gui"] = false
|
||||
var battle_arrow = camera.find_child("BattleArrow")
|
||||
if battle_arrow == null:
|
||||
battle_arrow = Sprite2D.new()
|
||||
battle_arrow.set_name(&"BattleArrow")
|
||||
battle_arrow.texture = load("res://gimp/arrow.png")
|
||||
camera.add_child(battle_arrow, true)
|
||||
battle_arrow.set_owner(camera)
|
||||
var battle_menu_item_0 = camera.find_child("BattleMenuItem0")
|
||||
if battle_menu_item_0 == null:
|
||||
battle_menu_item_0 = Label.new()
|
||||
battle_menu_item_0.set_name(&"BattleMenuItem0")
|
||||
camera.add_child(battle_menu_item_0, true)
|
||||
battle_menu_item_0.set_owner(camera)
|
||||
var battle_menu_item_1 = camera.find_child("BattleMenuItem1")
|
||||
if battle_menu_item_1 == null:
|
||||
battle_menu_item_1 = Label.new()
|
||||
battle_menu_item_1.set_name(&"BattleMenuItem1")
|
||||
camera.add_child(battle_menu_item_1, true)
|
||||
battle_menu_item_1.set_owner(camera)
|
||||
if state_dict["battle_item"] == null:
|
||||
battle_menu_item_0.text = "Summon Item"
|
||||
battle_menu_item_1.text = ""
|
||||
var arrow_rect = battle_arrow.get_rect()
|
||||
battle_arrow.position.x = (arrow_rect.size.x - viewport_size.x) / 2.0
|
||||
battle_arrow.position.y = (viewport_size.y - arrow_rect.size.y) / 2.0
|
||||
battle_menu_item_0.position.x = arrow_rect.size.x - viewport_size.x / 2.0
|
||||
battle_menu_item_0.position.y = battle_arrow.position.y
|
||||
state_dict["battle_selection"] = 0
|
||||
state_dict["battle_options"] = ["summon"]
|
||||
else:
|
||||
camera.position += move_vec
|
||||
else:
|
||||
camera.position = gander.position
|
||||
battle_menu_item_0.text = "Attack with Item"
|
||||
battle_menu_item_1.text = "Summon new Item"
|
||||
var arrow_rect = battle_arrow.get_rect()
|
||||
battle_arrow.position.x = (arrow_rect.size.x - viewport_size.x) / 2.0
|
||||
battle_arrow.position.y = (viewport_size.y - arrow_rect.size.y * 3.0) / 2.0
|
||||
battle_menu_item_0.position.x = arrow_rect.size.x - viewport_size.x / 2.0
|
||||
battle_menu_item_0.position.y = battle_arrow.position.y
|
||||
battle_menu_item_1.position.x = arrow_rect.size.x - viewport_size.x / 2.0
|
||||
battle_menu_item_1.position.y = battle_arrow.position.y + arrow_rect.size.y
|
||||
state_dict["battle_selection"] = 0
|
||||
state_dict["battle_options"] = ["attack", "summon"]
|
||||
|
||||
func handle_battle_input(event: InputEvent):
|
||||
if event.is_pressed():
|
||||
if event.is_action("Down"):
|
||||
state_dict["battle_selection"] += 1
|
||||
if state_dict["battle_selection"] >= state_dict["battle_options"].size():
|
||||
state_dict["battle_selection"] = 0
|
||||
battle_arrow_positioning()
|
||||
elif event.is_action("Up"):
|
||||
state_dict["battle_selection"] -= 1
|
||||
if state_dict["battle_selection"] < 0:
|
||||
state_dict["battle_selection"] = state_dict["battle_options"].size() - 1
|
||||
battle_arrow_positioning()
|
||||
|
||||
func battle_arrow_positioning():
|
||||
var battle_arrow: Sprite2D = camera.find_child("BattleArrow")
|
||||
if battle_arrow != null:
|
||||
var arrow_rect = battle_arrow.get_rect()
|
||||
battle_arrow.position.y = (viewport_size.y + arrow_rect.size.y) / 2.0 - (arrow_rect.size.y * (state_dict["battle_options"].size() - state_dict["battle_selection"]))
|
||||
|
|
39
export_presets.cfg
Normal file
39
export_presets.cfg
Normal file
|
@ -0,0 +1,39 @@
|
|||
[preset.0]
|
||||
|
||||
name="Linux/X11"
|
||||
platform="Linux/X11"
|
||||
runnable=true
|
||||
dedicated_server=false
|
||||
custom_features=""
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter=""
|
||||
export_path="../../GodotExported/LD55/LD55.x86_64"
|
||||
encryption_include_filters=""
|
||||
encryption_exclude_filters=""
|
||||
encrypt_pck=false
|
||||
encrypt_directory=false
|
||||
|
||||
[preset.0.options]
|
||||
|
||||
custom_template/debug=""
|
||||
custom_template/release=""
|
||||
debug/export_console_wrapper=1
|
||||
binary_format/embed_pck=false
|
||||
texture_format/bptc=true
|
||||
texture_format/s3tc=true
|
||||
texture_format/etc=false
|
||||
texture_format/etc2=false
|
||||
binary_format/architecture="x86_64"
|
||||
ssh_remote_deploy/enabled=false
|
||||
ssh_remote_deploy/host="user@host_ip"
|
||||
ssh_remote_deploy/port="22"
|
||||
ssh_remote_deploy/extra_args_ssh=""
|
||||
ssh_remote_deploy/extra_args_scp=""
|
||||
ssh_remote_deploy/run_script="#!/usr/bin/env bash
|
||||
export DISPLAY=:0
|
||||
unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
|
||||
\"{temp_dir}/{exe_name}\" {cmd_args}"
|
||||
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
|
||||
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
|
||||
rm -rf \"{temp_dir}\""
|
|
@ -6,6 +6,7 @@ var player_controlled = false
|
|||
enum GanderSceneT {
|
||||
Introduction,
|
||||
Gameplay,
|
||||
Battle,
|
||||
}
|
||||
var current_scene_type = GanderSceneT.Introduction
|
||||
var auto_control_action = "facing_front"
|
||||
|
@ -13,7 +14,6 @@ var auto_control_action = "facing_front"
|
|||
var last_collided_id = null
|
||||
|
||||
@onready var animated = $AnimatedSprite2D
|
||||
@onready var guard = $DungeonGuard
|
||||
|
||||
const SPEED = 150.0
|
||||
const ANIM_DEADZONE = 0.3
|
||||
|
@ -60,6 +60,7 @@ func _physics_process(delta):
|
|||
elif animated.animation != auto_control_action:
|
||||
animated.play(auto_control_action)
|
||||
|
||||
if current_scene_type != GanderSceneT.Battle:
|
||||
move_and_slide()
|
||||
var last_collision = get_last_slide_collision()
|
||||
if last_collision != null:
|
||||
|
|
BIN
gimp/arrow.png
Normal file
BIN
gimp/arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 793 B |
34
gimp/arrow.png.import
Normal file
34
gimp/arrow.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c7ey8ay7etot7"
|
||||
path="res://.godot/imported/arrow.png-1ff2c1793b6898e6750b81c11b16be86.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://gimp/arrow.png"
|
||||
dest_files=["res://.godot/imported/arrow.png-1ff2c1793b6898e6750b81c11b16be86.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
BIN
gimp/hammer.png
Normal file
BIN
gimp/hammer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 684 B |
34
gimp/hammer.png.import
Normal file
34
gimp/hammer.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b6ci7lm15okhr"
|
||||
path="res://.godot/imported/hammer.png-430b8e98de82f10ad08a61167ab515de.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://gimp/hammer.png"
|
||||
dest_files=["res://.godot/imported/hammer.png-430b8e98de82f10ad08a61167ab515de.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
BIN
gimp/sword.png
Normal file
BIN
gimp/sword.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 644 B |
34
gimp/sword.png.import
Normal file
34
gimp/sword.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bemf77dxebgw1"
|
||||
path="res://.godot/imported/sword.png-10267e2e65de70563df10750bee7e827.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://gimp/sword.png"
|
||||
dest_files=["res://.godot/imported/sword.png-10267e2e65de70563df10750bee7e827.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=7 format=3 uid="uid://ch52ervf073wd"]
|
||||
[gd_scene load_steps=8 format=3 uid="uid://ch52ervf073wd"]
|
||||
|
||||
[ext_resource type="Script" path="res://MainLogic.gd" id="1_43no1"]
|
||||
[ext_resource type="Texture2D" uid="uid://varqu7luxowf" path="res://gimp/earth_diamond.png" id="2_hlcsm"]
|
||||
|
@ -6,6 +6,7 @@
|
|||
[ext_resource type="Texture2D" uid="uid://djwgnisoid4co" path="res://gimp/water_diamond.png" id="4_u6w6s"]
|
||||
[ext_resource type="Texture2D" uid="uid://d2mxjcl50laoa" path="res://gimp/wind_diamond.png" id="5_3irym"]
|
||||
[ext_resource type="AudioStream" uid="uid://2epey2fmmtb2" path="res://audio/LD55_0.mp3" id="6_3kpot"]
|
||||
[ext_resource type="Texture2D" uid="uid://bemf77dxebgw1" path="res://gimp/sword.png" id="7_v3xw4"]
|
||||
|
||||
[node name="Node2D" type="Node2D"]
|
||||
script = ExtResource("1_43no1")
|
||||
|
@ -44,3 +45,7 @@ texture = ExtResource("5_3irym")
|
|||
|
||||
[node name="MusicPlayer" type="AudioStreamPlayer" parent="."]
|
||||
stream = ExtResource("6_3kpot")
|
||||
|
||||
[node name="Sword" type="Sprite2D" parent="."]
|
||||
position = Vector2(-669, 382)
|
||||
texture = ExtResource("7_v3xw4")
|
||||
|
|
|
@ -13,7 +13,9 @@ config_version=5
|
|||
config/name="LD55"
|
||||
run/main_scene="res://main_scene.tscn"
|
||||
config/features=PackedStringArray("4.2", "GL Compatibility")
|
||||
boot_splash/bg_color=Color(0.141176, 0.141176, 0.141176, 1)
|
||||
config/icon="res://icon.svg"
|
||||
boot_splash/minimum_display_time=1000
|
||||
|
||||
[input]
|
||||
|
||||
|
|
Loading…
Reference in a new issue