Main Menu and AI

- Mostly finished the settings menu
- Got basic AI working on easy difficulty
- Changed when animations are loaded
- Music now changes when you hit play
- Changed how AI will work. All enemies should only need the combatant script now
This commit is contained in:
nc543 2024-05-12 00:22:34 -04:00
parent 9f6e16961d
commit 5079a77296
25 changed files with 6764 additions and 105 deletions

View File

@ -22,7 +22,7 @@ allow_system_fallback=true
force_autohinter=false force_autohinter=false
hinting=1 hinting=1
subpixel_positioning=1 subpixel_positioning=1
oversampling=0.0 oversampling=8.0
Fallbacks=null Fallbacks=null
fallbacks=[] fallbacks=[]
Compress=null Compress=null

View File

@ -4,4 +4,4 @@
[resource] [resource]
script = ExtResource("1_kyxgb") script = ExtResource("1_kyxgb")
music = Array[String](["res://Sound/Music/Achievement.mp3", "res://Sound/Music/pirate-tavern-full-version-167990.mp3", "res://Sound/Music/fight-for-your-rights-13529.mp3"]) music = Array[String](["res://Sound/Music/pirate-tavern-full-version-167990.mp3", "res://Sound/Music/fight-for-your-rights-13529.mp3"])

View File

@ -4,4 +4,4 @@
[resource] [resource]
script = ExtResource("1_4ivkm") script = ExtResource("1_4ivkm")
music = Array[String](["res://Sound/Music/Wanderer.ogg", "res://Sound/Music/Borgar.ogg"]) music = Array[String](["res://Sound/Music/Wanderer.ogg"])

View File

@ -1,16 +1,15 @@
[gd_resource type="Resource" script_class="Spellbook" load_steps=6 format=3 uid="uid://bxtiv2esuer8v"] [gd_resource type="Resource" script_class="Spellbook" load_steps=5 format=3 uid="uid://bxtiv2esuer8v"]
[ext_resource type="Script" path="res://Resources/spellbook.gd" id="1_t8h8m"] [ext_resource type="Script" path="res://Resources/spellbook.gd" id="1_t8h8m"]
[ext_resource type="Resource" uid="uid://1xbik4qndtkh" path="res://Resources/Spells/firebolt.tres" id="2_ln222"] [ext_resource type="Resource" uid="uid://1xbik4qndtkh" path="res://Resources/Spells/firebolt.tres" id="2_ln222"]
[ext_resource type="Resource" uid="uid://dl6nv6lp460n3" path="res://Resources/Spells/rockThrow.tres" id="3_ocgmh"] [ext_resource type="Resource" uid="uid://dl6nv6lp460n3" path="res://Resources/Spells/rockThrow.tres" id="3_ocgmh"]
[ext_resource type="Resource" uid="uid://bmpu6k55bckdv" path="res://Resources/Spells/fireball.tres" id="4_kv0hs"] [ext_resource type="Resource" uid="uid://bmpu6k55bckdv" path="res://Resources/Spells/fireball.tres" id="4_kv0hs"]
[ext_resource type="Resource" uid="uid://c6mwbnutxm3vb" path="res://Resources/Spells/icyWind.tres" id="5_05vnn"]
[resource] [resource]
script = ExtResource("1_t8h8m") script = ExtResource("1_t8h8m")
name = "Old Book" name = "Old Book"
description = "An old spellbook you found on the side of the road" description = "An old spellbook you found on the side of the road"
spells = Array[Resource("res://Resources/spell.gd")]([ExtResource("2_ln222"), ExtResource("3_ocgmh"), ExtResource("4_kv0hs"), ExtResource("5_05vnn")]) spells = Array[Resource("res://Resources/spell.gd")]([ExtResource("2_ln222"), ExtResource("3_ocgmh"), ExtResource("4_kv0hs")])
damageMod = 1.0 damageMod = 1.0
defenseMod = 1.0 defenseMod = 1.0
element = 0 element = 0

View File

@ -1,12 +1,13 @@
[gd_resource type="Resource" script_class="Spellbook" load_steps=2 format=3 uid="uid://g86hap7s43n8"] [gd_resource type="Resource" script_class="Spellbook" load_steps=3 format=3 uid="uid://g86hap7s43n8"]
[ext_resource type="Script" path="res://Resources/spellbook.gd" id="1_pn4te"] [ext_resource type="Script" path="res://Resources/spellbook.gd" id="1_pn4te"]
[ext_resource type="Resource" uid="uid://dl6nv6lp460n3" path="res://Resources/Spells/rockThrow.tres" id="2_ofx8j"]
[resource] [resource]
script = ExtResource("1_pn4te") script = ExtResource("1_pn4te")
name = "Wizard Spellbook" name = "Wizard Spellbook"
description = "A spellbook used by wizards" description = "A spellbook used by wizards"
spells = Array[Resource("res://Resources/spell.gd")]([null, null, null, null, null, null]) spells = Array[Resource("res://Resources/spell.gd")]([ExtResource("2_ofx8j")])
damageMod = 1.2 damageMod = 1.2
defenseMod = 1.2 defenseMod = 1.2
element = 0 element = 0

View File

@ -8,7 +8,7 @@ script = ExtResource("2_ccu2m")
icon = ExtResource("1_67qon") icon = ExtResource("1_67qon")
name = "Firebolt" name = "Firebolt"
description = "Cast a small line of fire at your opponent" description = "Cast a small line of fire at your opponent"
animation = "" animation = "res://Scenes/Animations/fireboltAnim.tscn"
damage = 1.0 damage = 1.0
backfireStrength = 1.0 backfireStrength = 1.0
castCombo = Array[String](["up", "down", "down"]) castCombo = Array[String](["up", "down", "down"])

13
Scenes/UI/fpsMonitor.tscn Normal file
View File

@ -0,0 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://b7s5qx8fhk0pg"]
[ext_resource type="Script" path="res://Scripts/fpsMonitor.gd" id="1_u3gh0"]
[node name="FPSMonitor" type="RichTextLabel"]
offset_right = 360.0
offset_bottom = 51.0
scale = Vector2(0.5, 0.5)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 5
theme_override_font_sizes/normal_font_size = 30
text = "FPS: "
script = ExtResource("1_u3gh0")

File diff suppressed because one or more lines are too long

View File

@ -58,6 +58,3 @@ offset_left = 1177.0
offset_top = 204.5 offset_top = 204.5
offset_right = 1177.0 offset_right = 1177.0
offset_bottom = 204.5 offset_bottom = 204.5
[connection signal="healthChanged" from="Wizard" to="Wizard/HealthBar" method="healthChanged"]
[connection signal="healthChanged" from="Wizard2" to="Wizard2/HealthBar" method="healthChanged"]

View File

@ -1,9 +1,10 @@
[gd_scene load_steps=6 format=3 uid="uid://bix346il46rme"] [gd_scene load_steps=7 format=3 uid="uid://bix346il46rme"]
[ext_resource type="PackedScene" uid="uid://c8ni0t7brphc7" path="res://Scenes/musicPlayer.tscn" id="1_60q85"] [ext_resource type="PackedScene" uid="uid://c8ni0t7brphc7" path="res://Scenes/musicPlayer.tscn" id="1_60q85"]
[ext_resource type="PackedScene" uid="uid://d2owoq5q27v8q" path="res://Scenes/data.tscn" id="2_ba8tb"] [ext_resource type="PackedScene" uid="uid://d2owoq5q27v8q" path="res://Scenes/data.tscn" id="2_ba8tb"]
[ext_resource type="PackedScene" uid="uid://cme8avdi3w0sg" path="res://Scenes/UI/mainMenu.tscn" id="3_vjpnb"] [ext_resource type="PackedScene" uid="uid://cme8avdi3w0sg" path="res://Scenes/UI/mainMenu.tscn" id="3_vjpnb"]
[ext_resource type="Resource" uid="uid://bxtiv2esuer8v" path="res://Resources/Spellbooks/oldBook.tres" id="4_vnce4"] [ext_resource type="Resource" uid="uid://bxtiv2esuer8v" path="res://Resources/Spellbooks/oldBook.tres" id="4_vnce4"]
[ext_resource type="PackedScene" uid="uid://b7s5qx8fhk0pg" path="res://Scenes/UI/fpsMonitor.tscn" id="5_qao58"]
[sub_resource type="AudioStream" id="AudioStream_ibb28"] [sub_resource type="AudioStream" id="AudioStream_ibb28"]
@ -16,3 +17,6 @@ stream = SubResource("AudioStream_ibb28")
[node name="Data" parent="." instance=ExtResource("2_ba8tb")] [node name="Data" parent="." instance=ExtResource("2_ba8tb")]
spellbook = ExtResource("4_vnce4") spellbook = ExtResource("4_vnce4")
[node name="FPSMonitor" parent="." instance=ExtResource("5_qao58")]
visible = false

30
Scenes/tavern.tscn Normal file
View File

@ -0,0 +1,30 @@
[gd_scene load_steps=2 format=3 uid="uid://drhhwv5jh0n7k"]
[ext_resource type="Texture2D" uid="uid://bp2htek76abbm" path="res://Sprites/Backgrounds/Mountain Pack by CaptainSkeleto/Mountain Pack5.png" id="1_b0ksa"]
[node name="Tavern" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Background" type="TextureRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("1_b0ksa")
expand_mode = 2
stretch_mode = 6
[node name="HBoxContainer" type="HBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

View File

@ -36,6 +36,10 @@ func _process(delta):
if timer > explodeDur: if timer > explodeDur:
self.free() self.free()
func setProgress(target: float, final: float = finalProg) -> void:
targetProg = target
finalProg = final
func explode() -> void: func explode() -> void:
ballofayr.hide() ballofayr.hide()
particles.emitting = true particles.emitting = true

View File

@ -11,6 +11,9 @@ func _ready():
if !inverted: if !inverted:
path = $Path2D/PathFollow2D path = $Path2D/PathFollow2D
failPath = $Path2D/PathFollow2D/Path2D/PathFollow2D failPath = $Path2D/PathFollow2D/Path2D/PathFollow2D
else:
path = $Path2D/PathFollow2D
failPath = $Path2D/PathFollow2D/Path2D/PathFollow2D
# Called every frame. 'delta' is the elapsed time since the previous frame. # Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta): func _process(delta):

51
Scripts/Settings.gd Normal file
View File

@ -0,0 +1,51 @@
extends Control
@onready var data: Data = $/root/Root/Data
@onready var titleScreen: Control = $/root/Root/MainMenu/TitleScreen
@onready var fpsMonitor: RichTextLabel = $/root/Root/FPSMonitor
@onready var mainBus: int = AudioServer.get_bus_index("Master")
@onready var musicBus: int = AudioServer.get_bus_index("Music")
@onready var effectsBus: int = AudioServer.get_bus_index("Effects")
func home():
self.hide()
titleScreen.show()
func changeDifficulty(i: int):
data.difficulty = i
func changeVolMaster(i: float):
AudioServer.set_bus_volume_db(mainBus, linear_to_db(i))
func changeVolMusic(i: float):
AudioServer.set_bus_volume_db(musicBus, linear_to_db(i))
func changeVolEffects(i: float):
AudioServer.set_bus_volume_db(effectsBus, linear_to_db(i))
func windowModeChanged(index: int):
match index:
0: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
1: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
2: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_EXCLUSIVE_FULLSCREEN)
func vsyncChanged(index: int):
match index:
0: DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
1: DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED)
2: DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ADAPTIVE)
3: DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_MAILBOX)
func toggleFPSMonitor(toggled_on: bool):
fpsMonitor.visible = toggled_on
func fpsChanged(index: int):
match index:
0: Engine.max_fps = 24
1: Engine.max_fps = 30
2: Engine.max_fps = 60
3: Engine.max_fps = 90
4: Engine.max_fps = 120
5: Engine.max_fps = 144
6: Engine.max_fps = 240
7: Engine.max_fps = 0

View File

@ -11,6 +11,11 @@ extends Control
@onready var quit: TextureButton = $Buttons/Quit @onready var quit: TextureButton = $Buttons/Quit
@onready var about: TextureButton = $Buttons/About @onready var about: TextureButton = $Buttons/About
@onready var settingsMenu: Control = $"../Settings"
@onready var musicPlayer: MusicPlayer = $/root/Root/MusicPlayer
@export var arena: String
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready(): func _ready():
pass # Replace with function body. pass # Replace with function body.
@ -20,16 +25,28 @@ func _process(delta):
pass pass
func _on_play_pressed(): func _on_play_pressed():
print("Play") var a: Node2D = load(arena).instantiate()
$/root/Root.add_child(a)
$/root/Root/MainMenu.queue_free()
musicPlayer.setLoc(Data.Location.ARENA)
func _on_credits_pressed(): func _on_credits_pressed():
print("Credits") print("Credits")
func _on_settings_pressed(): func _on_settings_pressed():
print("Settings") self.hide()
settingsMenu.show()
func _on_about_pressed(): func _on_about_pressed():
print("About") print("About")
func _on_quit_pressed(): func _on_quit_pressed():
get_tree().quit() get_tree().quit()

View File

@ -11,6 +11,9 @@ signal healthChanged(health: float)
@export var health: float = maxHealth @export var health: float = maxHealth
@export var player: bool = false @export var player: bool = false
var spell: Spell
var spellIndex: int
var anim: AnimationBase
var casting: bool = false var casting: bool = false
var castCooldown: float = 0 var castCooldown: float = 0
@ -21,45 +24,98 @@ func _ready():
spellbook.initCooldowns() spellbook.initCooldowns()
healthbar.maxHealth = maxHealth healthbar.maxHealth = maxHealth
if !player: if !player:
for spel: Spell in spellbook.spells:
if (spel == null): continue
if !data.animations.has(spel.animation):
data.animations[spel.animation] = load(spel.animation)
data.opponent = self data.opponent = self
renderer.flip_h = true renderer.flip_h = true
healthbar.position.x *= -1 healthbar.position.x *= -1
match data.difficulty: _finishedCasting()
Data.Difficulty.EASY: castCooldown = 3
Data.Difficulty.NORMAL: castCooldown = 1
Data.Difficulty.HARD: castCooldown = 0.5
Data.Difficulty.GAMER: castCooldown = 0
else: else:
data.player = self data.player = self
# Called every frame. 'delta' is the elapsed time since the previous frame. # Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta): func _process(delta):
if !player: if !player && !casting:
match data.difficulty: timing(delta)
Data.Difficulty.EASY: _easyAI(delta)
Data.Difficulty.NORMAL: _normalAI(delta)
Data.Difficulty.HARD: _hardAI(delta)
Data.Difficulty.GAMER: _gamerAI(delta)
func _easyAI(delta) -> void:
pass
func _normalAI(delta) -> void:
pass
func _hardAI(delta) -> void:
pass
func _gamerAI(delta) -> void:
pass
func _finishedCasting() -> void: func _finishedCasting() -> void:
pass casting = false
match data.difficulty:
Data.Difficulty.EASY: castCooldown = randf_range(2.7, 3.3)
Data.Difficulty.NORMAL: castCooldown = randf_range(0.8, 1.3)
Data.Difficulty.HARD: castCooldown = randf_range(0.3, 0.7)
Data.Difficulty.GAMER: castCooldown = 0
func timing(delta) -> void: func timing(delta) -> void:
castCooldown -= delta castCooldown -= delta
if castCooldown <= 0: if castCooldown <= 0:
pass print("Attempt cast")
cast()
func cast() -> void:
casting = true
match data.difficulty:
Data.Difficulty.EASY:
spellIndex = randi_range(0, spellbook.spells.size() - 1)
spell = spellbook.spells[spellIndex]
anim = data.animations[spell.animation].instantiate()
anim.setProgress(0, spell.castCombo.size())
anim.inverted = true
get_node("/root").add_child(anim)
attemptCast()
Data.Difficulty.NORMAL:
pass
Data.Difficulty.HARD:
pass
Data.Difficulty.GAMER:
pass
func attemptCast():
match data.difficulty:
Data.Difficulty.EASY:
print("Awaiting")
await get_tree().create_timer(randf_range(0.5, 1.5)).timeout
print("Awaited")
if randi_range(1, 100) < 85:
spell.castProgress += 1
anim.setProgress(spell.castProgress)
if spell.castProgress == spell.castCombo.size():
casting = false
spell.castProgress = 0
renderer.play("attack1")
spellbook.cooldowns[spellIndex] = spell.cooldown
data.player.alterHealth(-spell.damage, false)
_finishedCasting()
else:
attemptCast()
else:
alterHealth(-spell.backfireStrength, true)
casting = false
anim.castFailed()
spell.castProgress = 0
spellbook.cooldowns[spellIndex] = spell.cooldown * (float(spell.castProgress) / float(spell.castCombo.size()))
_finishedCasting()
Data.Difficulty.NORMAL:
await get_tree().create_timer(randf_range(0.5, 1.5)).timeout
if randi_range(1, 100) < 50:
pass #Success
else:
pass #fail
Data.Difficulty.HARD:
await get_tree().create_timer(randf_range(0.5, 1.5)).timeout
if randi_range(1, 100) < 50:
pass #Success
else:
pass #fail
Data.Difficulty.GAMER:
await get_tree().create_timer(randf_range(0.5, 1.5)).timeout
if randi_range(1, 100) < 50:
pass #Success
else:
pass #fail
func alterHealth(change: float, stun: bool) -> void: func alterHealth(change: float, stun: bool) -> void:
health += change health += change

5
Scripts/fpsMonitor.gd Normal file
View File

@ -0,0 +1,5 @@
extends RichTextLabel
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta):
text = "FPS: " + str(Engine.get_frames_per_second())

View File

@ -1,4 +1,4 @@
extends AudioStreamPlayer class_name MusicPlayer extends AudioStreamPlayer
@onready var data: Data = get_node("/root/Root/Data") @onready var data: Data = get_node("/root/Root/Data")
var mainMenuPlaylist: Playlist = load("res://Resources/Playlists/mainMenu.tres") var mainMenuPlaylist: Playlist = load("res://Resources/Playlists/mainMenu.tres")

View File

@ -12,6 +12,10 @@ var anim: AnimationBase
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready(): func _ready():
data.spellbook.initCooldowns() data.spellbook.initCooldowns()
for spel: Spell in data.spellbook.spells:
if (spel == null): continue
if !data.animations.has(spel.animation):
data.animations[spel.animation] = load(spel.animation)
# Called every frame. 'delta' is the elapsed time since the previous frame. # Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta): func _process(delta):
@ -23,13 +27,9 @@ func _process(delta):
spellIndex = i spellIndex = i
castIndicator.show() castIndicator.show()
castIndicator.setDirs(spell.castCombo[0], spell.castCombo[1]) castIndicator.setDirs(spell.castCombo[0], spell.castCombo[1])
if spell.animation != null: anim = data.animations[spell.animation].instantiate()
if !data.animations.has(spell.animation): anim.setProgress(0, spell.castCombo.size())
print("Loading Animation") get_node("/root").add_child(anim)
data.animations[spell.animation] = load(spell.animation)
anim = data.animations[spell.animation].instantiate()
anim.setProgress(0, spell.castCombo.size())
get_node("/root").add_child(anim)
timer = 0 timer = 0
else: else:
@ -49,7 +49,7 @@ func _process(delta):
avatar.renderer.play("attack1") avatar.renderer.play("attack1")
data.spellbook.cooldowns[spellIndex] = spell.cooldown data.spellbook.cooldowns[spellIndex] = spell.cooldown
castIndicator.hide() castIndicator.hide()
data.opponent.alterHealth(-1, false) data.opponent.alterHealth(-spell.damage, false)
elif (timer >= spell.timeout || Input.is_action_just_pressed("up") || Input.is_action_just_pressed("down") || Input.is_action_just_pressed("left") || Input.is_action_just_pressed("right")): elif (timer >= spell.timeout || Input.is_action_just_pressed("up") || Input.is_action_just_pressed("down") || Input.is_action_just_pressed("left") || Input.is_action_just_pressed("right")):
avatar.alterHealth(-spell.backfireStrength, true) avatar.alterHealth(-spell.backfireStrength, true)
casting = false casting = false
@ -57,7 +57,7 @@ func _process(delta):
spell.castProgress = 0 spell.castProgress = 0
data.spellbook.cooldowns[spellIndex] = spell.cooldown * (float(spell.castProgress) / float(spell.castCombo.size())) data.spellbook.cooldowns[spellIndex] = spell.cooldown * (float(spell.castProgress) / float(spell.castCombo.size()))
castIndicator.hide() castIndicator.hide()
for i in range(data.spellbook.cooldowns.size()): for i in range(data.spellbook.cooldowns.size()):
data.spellbook.cooldowns[i] -= delta data.spellbook.cooldowns[i] -= delta
if data.spellbook.cooldowns[i] < 0: data.spellbook.cooldowns[i] = 0 if data.spellbook.cooldowns[i] < 0: data.spellbook.cooldowns[i] = 0

Binary file not shown.

View File

@ -1,19 +0,0 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://d3f5ohpbcciip"
path="res://.godot/imported/Borgar.ogg-db00fbff923965ab1a902d7a9caf7b1b.oggvorbisstr"
[deps]
source_file="res://Sound/Music/Borgar.ogg"
dest_files=["res://.godot/imported/Borgar.ogg-db00fbff923965ab1a902d7a9caf7b1b.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dlno82yt8s8ps"
path="res://.godot/imported/Checked.png-176d1cdad276e5a2215362a0026d73de.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Sprites/UI/Edinnu_UI_asset_pack/Marks/Checked.png"
dest_files=["res://.godot/imported/Checked.png-176d1cdad276e5a2215362a0026d73de.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

View File

@ -5,7 +5,7 @@ bus/1/name = &"Music"
bus/1/solo = false bus/1/solo = false
bus/1/mute = false bus/1/mute = false
bus/1/bypass_fx = false bus/1/bypass_fx = false
bus/1/volume_db = -3.32444 bus/1/volume_db = 0.0
bus/1/send = &"Master" bus/1/send = &"Master"
bus/2/name = &"Effects" bus/2/name = &"Effects"
bus/2/solo = false bus/2/solo = false

View File

@ -17,6 +17,7 @@ config/icon="res://icon.svg"
[display] [display]
window/size/mode=3
window/stretch/mode="canvas_items" window/stretch/mode="canvas_items"
window/stretch/aspect="keep_width" window/stretch/aspect="keep_width"
mouse_cursor/custom_image_hotspot=Vector2(64, 128) mouse_cursor/custom_image_hotspot=Vector2(64, 128)
@ -95,3 +96,4 @@ Spell7={
[rendering] [rendering]
textures/canvas_textures/default_texture_filter=0 textures/canvas_textures/default_texture_filter=0
renderer/rendering_method="gl_compatibility"