Inventar, Equipment, Klassensystem und Waffenschaden hinzugefügt
- CharacterClass mit Klassen (Krieger, Schurke, Magier) und unbewaffnetem Schaden - Equipment-System mit 7 Slots, Seltenheiten und Stats - Inventar-System mit 20 Slots und Gold - LootTable/LootEntry für Gegner-Drops - Character Panel (C) mit Stats und Equipment-Anzeige - Inventory Panel (I) mit Item-Grid und Tooltips - Klassenauswahl-Menü bei Spielstart - Waffenschaden in Equipment-Spalte, unbewaffnet klassenabhängig Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1616431d1c
commit
9ab6deddff
32 changed files with 1115 additions and 0 deletions
32
character_class.gd
Normal file
32
character_class.gd
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# CharacterClass.gd
|
||||
# Definiert Charakterklassen mit Grundstats und Main-Stat
|
||||
extends Resource
|
||||
class_name CharacterClass
|
||||
|
||||
enum MainStat { STRENGTH, AGILITY, INTELLIGENCE }
|
||||
|
||||
@export var class_name_de: String = "Krieger"
|
||||
@export var main_stat: MainStat = MainStat.STRENGTH
|
||||
|
||||
# Grund-Stats auf Level 1
|
||||
@export var base_strength: int = 10
|
||||
@export var base_agility: int = 10
|
||||
@export var base_intelligence: int = 10
|
||||
@export var base_stamina: int = 10 # Beeinflusst HP
|
||||
|
||||
# Stat-Zuwachs pro Level
|
||||
@export var strength_per_level: float = 2.0
|
||||
@export var agility_per_level: float = 2.0
|
||||
@export var intelligence_per_level: float = 2.0
|
||||
@export var stamina_per_level: float = 2.0
|
||||
|
||||
# Unbewaffneter Schaden (klassenabhängig)
|
||||
@export var unarmed_min_damage: int = 1
|
||||
@export var unarmed_max_damage: int = 2
|
||||
@export var unarmed_attack_speed: float = 2.0 # Langsamer als mit Waffe
|
||||
|
||||
# HP pro Stamina-Punkt
|
||||
const HP_PER_STAMINA = 10
|
||||
|
||||
# Schaden-Skalierung mit Main-Stat
|
||||
const DAMAGE_PER_MAIN_STAT = 0.5
|
||||
1
character_class.gd.uid
Normal file
1
character_class.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ci45xxb5vn857
|
||||
104
character_panel.gd
Normal file
104
character_panel.gd
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# CharacterPanel.gd
|
||||
# Zeigt Charakterinfos: Klasse, Level, Stats und Equipment
|
||||
extends CanvasLayer
|
||||
|
||||
var panel_visible = false
|
||||
|
||||
@onready var panel = $Panel
|
||||
@onready var class_label = $Panel/HBoxContainer/StatsColumn/ClassLabel
|
||||
@onready var level_label = $Panel/HBoxContainer/StatsColumn/LevelLabel
|
||||
@onready var stats_container = $Panel/HBoxContainer/StatsColumn/StatsContainer
|
||||
@onready var str_label = $Panel/HBoxContainer/StatsColumn/StatsContainer/StrLabel
|
||||
@onready var agi_label = $Panel/HBoxContainer/StatsColumn/StatsContainer/AgiLabel
|
||||
@onready var int_label = $Panel/HBoxContainer/StatsColumn/StatsContainer/IntLabel
|
||||
@onready var sta_label = $Panel/HBoxContainer/StatsColumn/StatsContainer/StaLabel
|
||||
@onready var armor_label = $Panel/HBoxContainer/StatsColumn/StatsContainer/ArmorLabel
|
||||
@onready var hp_label = $Panel/HBoxContainer/StatsColumn/HPLabel
|
||||
@onready var damage_label = $Panel/HBoxContainer/EquipmentColumn/DamageLabel
|
||||
@onready var dps_label = $Panel/HBoxContainer/EquipmentColumn/DPSLabel
|
||||
|
||||
# Equipment Slots
|
||||
@onready var head_slot = $Panel/HBoxContainer/EquipmentColumn/EquipmentContainer/HeadSlot
|
||||
@onready var chest_slot = $Panel/HBoxContainer/EquipmentColumn/EquipmentContainer/ChestSlot
|
||||
@onready var hands_slot = $Panel/HBoxContainer/EquipmentColumn/EquipmentContainer/HandsSlot
|
||||
@onready var legs_slot = $Panel/HBoxContainer/EquipmentColumn/EquipmentContainer/LegsSlot
|
||||
@onready var feet_slot = $Panel/HBoxContainer/EquipmentColumn/EquipmentContainer/FeetSlot
|
||||
@onready var weapon_slot = $Panel/HBoxContainer/EquipmentColumn/WeaponSlot
|
||||
@onready var offhand_slot = $Panel/HBoxContainer/EquipmentColumn/OffhandSlot
|
||||
|
||||
func _ready():
|
||||
panel.visible = false
|
||||
|
||||
func toggle():
|
||||
panel_visible = !panel_visible
|
||||
panel.visible = panel_visible
|
||||
|
||||
func update_stats(player):
|
||||
if player.character_class:
|
||||
var main_stat_name = ""
|
||||
match player.character_class.main_stat:
|
||||
CharacterClass.MainStat.STRENGTH:
|
||||
main_stat_name = "STR"
|
||||
CharacterClass.MainStat.AGILITY:
|
||||
main_stat_name = "AGI"
|
||||
CharacterClass.MainStat.INTELLIGENCE:
|
||||
main_stat_name = "INT"
|
||||
class_label.text = player.character_class.class_name_de + " (Haupt: " + main_stat_name + ")"
|
||||
else:
|
||||
class_label.text = "Keine Klasse"
|
||||
|
||||
level_label.text = "Level " + str(player.level) + " (" + str(player.current_xp) + "/" + str(player.xp_to_next_level) + " XP)"
|
||||
|
||||
str_label.text = "Stärke: " + str(player.strength)
|
||||
agi_label.text = "Beweglichkeit: " + str(player.agility)
|
||||
int_label.text = "Intelligenz: " + str(player.intelligence)
|
||||
sta_label.text = "Ausdauer: " + str(player.stamina)
|
||||
armor_label.text = "Rüstung: " + str(player.armor)
|
||||
|
||||
hp_label.text = "HP: " + str(player.current_hp) + " / " + str(player.max_hp)
|
||||
|
||||
# Waffen-Stats (jetzt in Equipment-Spalte)
|
||||
var weapon = player.get_equipped_weapon()
|
||||
if weapon:
|
||||
damage_label.text = "Schaden: " + str(weapon.min_damage) + "-" + str(weapon.max_damage) + " (%.1fs)" % weapon.attack_speed
|
||||
else:
|
||||
# Unbewaffnet: klassenabhängiger Schaden
|
||||
if player.character_class:
|
||||
var min_dmg = player.character_class.unarmed_min_damage
|
||||
var max_dmg = player.character_class.unarmed_max_damage
|
||||
var atk_spd = player.character_class.unarmed_attack_speed
|
||||
damage_label.text = "Unbewaffnet: " + str(min_dmg) + "-" + str(max_dmg) + " (%.1fs)" % atk_spd
|
||||
else:
|
||||
damage_label.text = "Unbewaffnet: 1-2 (2.0s)"
|
||||
dps_label.text = "DPS: %.1f" % player.get_dps()
|
||||
|
||||
# Main-Stat hervorheben
|
||||
str_label.modulate = Color(1, 1, 1)
|
||||
agi_label.modulate = Color(1, 1, 1)
|
||||
int_label.modulate = Color(1, 1, 1)
|
||||
|
||||
if player.character_class:
|
||||
match player.character_class.main_stat:
|
||||
CharacterClass.MainStat.STRENGTH:
|
||||
str_label.modulate = Color(1, 0.8, 0.2)
|
||||
CharacterClass.MainStat.AGILITY:
|
||||
agi_label.modulate = Color(1, 0.8, 0.2)
|
||||
CharacterClass.MainStat.INTELLIGENCE:
|
||||
int_label.modulate = Color(1, 0.8, 0.2)
|
||||
|
||||
# Equipment aktualisieren
|
||||
_update_equipment_slot(head_slot, "Kopf", player.equipment[Equipment.Slot.HEAD])
|
||||
_update_equipment_slot(chest_slot, "Brust", player.equipment[Equipment.Slot.CHEST])
|
||||
_update_equipment_slot(hands_slot, "Hände", player.equipment[Equipment.Slot.HANDS])
|
||||
_update_equipment_slot(legs_slot, "Beine", player.equipment[Equipment.Slot.LEGS])
|
||||
_update_equipment_slot(feet_slot, "Füße", player.equipment[Equipment.Slot.FEET])
|
||||
_update_equipment_slot(weapon_slot, "Waffe", player.equipment[Equipment.Slot.WEAPON])
|
||||
_update_equipment_slot(offhand_slot, "Nebenhand", player.equipment[Equipment.Slot.OFFHAND])
|
||||
|
||||
func _update_equipment_slot(label: Label, slot_name: String, item: Equipment):
|
||||
if item == null:
|
||||
label.text = slot_name + ": -"
|
||||
label.modulate = Color(0.6, 0.6, 0.6)
|
||||
else:
|
||||
label.text = slot_name + ": " + item.item_name
|
||||
label.modulate = Equipment.get_rarity_color(item.rarity)
|
||||
1
character_panel.gd.uid
Normal file
1
character_panel.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://7pdlor66gi51
|
||||
155
character_panel.tscn
Normal file
155
character_panel.tscn
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
[gd_scene format=3 uid="uid://character_panel"]
|
||||
|
||||
[ext_resource type="Script" path="res://character_panel.gd" id="1_panel"]
|
||||
|
||||
[node name="CharacterPanel" type="CanvasLayer"]
|
||||
script = ExtResource("1_panel")
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
anchors_preset = 4
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 20.0
|
||||
offset_top = -200.0
|
||||
offset_right = 520.0
|
||||
offset_bottom = 200.0
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Panel"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 15.0
|
||||
offset_top = 15.0
|
||||
offset_right = -15.0
|
||||
offset_bottom = -15.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 20
|
||||
|
||||
[node name="StatsColumn" type="VBoxContainer" parent="Panel/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 6
|
||||
|
||||
[node name="Title" type="Label" parent="Panel/HBoxContainer/StatsColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "Charakter"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="Panel/HBoxContainer/StatsColumn"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ClassLabel" type="Label" parent="Panel/HBoxContainer/StatsColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "Krieger (Haupt: STR)"
|
||||
|
||||
[node name="LevelLabel" type="Label" parent="Panel/HBoxContainer/StatsColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = "Level 1 (0/100 XP)"
|
||||
|
||||
[node name="HSeparator2" type="HSeparator" parent="Panel/HBoxContainer/StatsColumn"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="StatsContainer" type="VBoxContainer" parent="Panel/HBoxContainer/StatsColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="StrLabel" type="Label" parent="Panel/HBoxContainer/StatsColumn/StatsContainer"]
|
||||
layout_mode = 2
|
||||
text = "Stärke: 15"
|
||||
|
||||
[node name="AgiLabel" type="Label" parent="Panel/HBoxContainer/StatsColumn/StatsContainer"]
|
||||
layout_mode = 2
|
||||
text = "Beweglichkeit: 8"
|
||||
|
||||
[node name="IntLabel" type="Label" parent="Panel/HBoxContainer/StatsColumn/StatsContainer"]
|
||||
layout_mode = 2
|
||||
text = "Intelligenz: 5"
|
||||
|
||||
[node name="StaLabel" type="Label" parent="Panel/HBoxContainer/StatsColumn/StatsContainer"]
|
||||
layout_mode = 2
|
||||
text = "Ausdauer: 12"
|
||||
|
||||
[node name="ArmorLabel" type="Label" parent="Panel/HBoxContainer/StatsColumn/StatsContainer"]
|
||||
layout_mode = 2
|
||||
text = "Rüstung: 0"
|
||||
|
||||
[node name="HSeparator3" type="HSeparator" parent="Panel/HBoxContainer/StatsColumn"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HPLabel" type="Label" parent="Panel/HBoxContainer/StatsColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = "HP: 120 / 120"
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="Panel/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="EquipmentColumn" type="VBoxContainer" parent="Panel/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 6
|
||||
|
||||
[node name="EquipTitle" type="Label" parent="Panel/HBoxContainer/EquipmentColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "Ausrüstung"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="Panel/HBoxContainer/EquipmentColumn"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="EquipmentContainer" type="VBoxContainer" parent="Panel/HBoxContainer/EquipmentColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="HeadSlot" type="Label" parent="Panel/HBoxContainer/EquipmentColumn/EquipmentContainer"]
|
||||
layout_mode = 2
|
||||
text = "Kopf: -"
|
||||
|
||||
[node name="ChestSlot" type="Label" parent="Panel/HBoxContainer/EquipmentColumn/EquipmentContainer"]
|
||||
layout_mode = 2
|
||||
text = "Brust: -"
|
||||
|
||||
[node name="HandsSlot" type="Label" parent="Panel/HBoxContainer/EquipmentColumn/EquipmentContainer"]
|
||||
layout_mode = 2
|
||||
text = "Hände: -"
|
||||
|
||||
[node name="LegsSlot" type="Label" parent="Panel/HBoxContainer/EquipmentColumn/EquipmentContainer"]
|
||||
layout_mode = 2
|
||||
text = "Beine: -"
|
||||
|
||||
[node name="FeetSlot" type="Label" parent="Panel/HBoxContainer/EquipmentColumn/EquipmentContainer"]
|
||||
layout_mode = 2
|
||||
text = "Füße: -"
|
||||
|
||||
[node name="HSeparator2" type="HSeparator" parent="Panel/HBoxContainer/EquipmentColumn"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="WeaponSlot" type="Label" parent="Panel/HBoxContainer/EquipmentColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = "Waffe: -"
|
||||
|
||||
[node name="OffhandSlot" type="Label" parent="Panel/HBoxContainer/EquipmentColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = "Nebenhand: -"
|
||||
|
||||
[node name="HSeparator3" type="HSeparator" parent="Panel/HBoxContainer/EquipmentColumn"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DamageLabel" type="Label" parent="Panel/HBoxContainer/EquipmentColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = "Schaden: 3-6 (1.5s)"
|
||||
|
||||
[node name="DPSLabel" type="Label" parent="Panel/HBoxContainer/EquipmentColumn"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = "DPS: 5.0"
|
||||
81
class_selection_menu.gd
Normal file
81
class_selection_menu.gd
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# ClassSelectionMenu.gd
|
||||
# Menü zur Auswahl der Charakterklasse beim Spielstart
|
||||
extends CanvasLayer
|
||||
|
||||
signal class_selected(character_class: CharacterClass)
|
||||
|
||||
const WARRIOR_CLASS = preload("res://classes/warrior.tres")
|
||||
const ROGUE_CLASS = preload("res://classes/rogue.tres")
|
||||
const MAGE_CLASS = preload("res://classes/mage.tres")
|
||||
|
||||
var selected_class: CharacterClass = null
|
||||
|
||||
@onready var panel = $Panel
|
||||
@onready var warrior_btn = $Panel/VBoxContainer/ClassButtons/WarriorBtn
|
||||
@onready var rogue_btn = $Panel/VBoxContainer/ClassButtons/RogueBtn
|
||||
@onready var mage_btn = $Panel/VBoxContainer/ClassButtons/MageBtn
|
||||
@onready var start_btn = $Panel/VBoxContainer/StartBtn
|
||||
@onready var class_info = $Panel/VBoxContainer/ClassInfo
|
||||
@onready var stats_label = $Panel/VBoxContainer/StatsLabel
|
||||
|
||||
func _ready():
|
||||
# Spiel pausieren während Menü offen
|
||||
get_tree().paused = true
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
|
||||
# Buttons verbinden
|
||||
warrior_btn.pressed.connect(_on_warrior_selected)
|
||||
rogue_btn.pressed.connect(_on_rogue_selected)
|
||||
mage_btn.pressed.connect(_on_mage_selected)
|
||||
start_btn.pressed.connect(_on_start_pressed)
|
||||
|
||||
# Start-Button deaktiviert bis Klasse gewählt
|
||||
start_btn.disabled = true
|
||||
class_info.text = "Wähle eine Klasse!"
|
||||
stats_label.text = ""
|
||||
|
||||
func _on_warrior_selected():
|
||||
selected_class = WARRIOR_CLASS
|
||||
_update_selection("Krieger", WARRIOR_CLASS)
|
||||
_highlight_button(warrior_btn)
|
||||
|
||||
func _on_rogue_selected():
|
||||
selected_class = ROGUE_CLASS
|
||||
_update_selection("Schurke", ROGUE_CLASS)
|
||||
_highlight_button(rogue_btn)
|
||||
|
||||
func _on_mage_selected():
|
||||
selected_class = MAGE_CLASS
|
||||
_update_selection("Magier", MAGE_CLASS)
|
||||
_highlight_button(mage_btn)
|
||||
|
||||
func _update_selection(cls_name: String, char_class: CharacterClass):
|
||||
var main_stat_name = ""
|
||||
match char_class.main_stat:
|
||||
CharacterClass.MainStat.STRENGTH:
|
||||
main_stat_name = "Stärke"
|
||||
CharacterClass.MainStat.AGILITY:
|
||||
main_stat_name = "Beweglichkeit"
|
||||
CharacterClass.MainStat.INTELLIGENCE:
|
||||
main_stat_name = "Intelligenz"
|
||||
|
||||
class_info.text = cls_name + " - Haupt-Stat: " + main_stat_name
|
||||
stats_label.text = "STR: " + str(char_class.base_strength) + " AGI: " + str(char_class.base_agility) + " INT: " + str(char_class.base_intelligence) + " STA: " + str(char_class.base_stamina)
|
||||
start_btn.disabled = false
|
||||
|
||||
func _highlight_button(active_btn: Button):
|
||||
# Alle Buttons zurücksetzen
|
||||
warrior_btn.modulate = Color(1, 1, 1)
|
||||
rogue_btn.modulate = Color(1, 1, 1)
|
||||
mage_btn.modulate = Color(1, 1, 1)
|
||||
# Aktiven Button hervorheben
|
||||
active_btn.modulate = Color(1, 0.8, 0.2)
|
||||
|
||||
func _on_start_pressed():
|
||||
if selected_class == null:
|
||||
return
|
||||
|
||||
# Signal senden und Menü schließen
|
||||
class_selected.emit(selected_class)
|
||||
get_tree().paused = false
|
||||
queue_free()
|
||||
1
class_selection_menu.gd.uid
Normal file
1
class_selection_menu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://db8m2uw42hqfc
|
||||
80
class_selection_menu.tscn
Normal file
80
class_selection_menu.tscn
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
[gd_scene format=3 uid="uid://class_selection_menu"]
|
||||
|
||||
[ext_resource type="Script" path="res://class_selection_menu.gd" id="1_menu"]
|
||||
|
||||
[node name="ClassSelectionMenu" type="CanvasLayer"]
|
||||
script = ExtResource("1_menu")
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -200.0
|
||||
offset_top = -180.0
|
||||
offset_right = 200.0
|
||||
offset_bottom = 180.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 20.0
|
||||
offset_top = 20.0
|
||||
offset_right = -20.0
|
||||
offset_bottom = -20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 15
|
||||
|
||||
[node name="Title" type="Label" parent="Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 28
|
||||
text = "Wähle deine Klasse"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ClassButtons" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 20
|
||||
alignment = 1
|
||||
|
||||
[node name="WarriorBtn" type="Button" parent="Panel/VBoxContainer/ClassButtons"]
|
||||
custom_minimum_size = Vector2(100, 80)
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "Krieger"
|
||||
|
||||
[node name="RogueBtn" type="Button" parent="Panel/VBoxContainer/ClassButtons"]
|
||||
custom_minimum_size = Vector2(100, 80)
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "Schurke"
|
||||
|
||||
[node name="MageBtn" type="Button" parent="Panel/VBoxContainer/ClassButtons"]
|
||||
custom_minimum_size = Vector2(100, 80)
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "Magier"
|
||||
|
||||
[node name="ClassInfo" type="Label" parent="Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 18
|
||||
text = "Wähle eine Klasse!"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="StatsLabel" type="Label" parent="Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 14
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="StartBtn" type="Button" parent="Panel/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 50)
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 20
|
||||
disabled = true
|
||||
text = "Spiel starten"
|
||||
19
classes/mage.tres
Normal file
19
classes/mage.tres
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[gd_resource type="Resource" script_class="CharacterClass" format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://character_class.gd" id="1"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
class_name_de = "Magier"
|
||||
main_stat = 2
|
||||
base_strength = 5
|
||||
base_agility = 8
|
||||
base_intelligence = 15
|
||||
base_stamina = 8
|
||||
strength_per_level = 1.0
|
||||
agility_per_level = 1.5
|
||||
intelligence_per_level = 3.0
|
||||
stamina_per_level = 1.5
|
||||
unarmed_min_damage = 1
|
||||
unarmed_max_damage = 2
|
||||
unarmed_attack_speed = 2.0
|
||||
19
classes/rogue.tres
Normal file
19
classes/rogue.tres
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[gd_resource type="Resource" script_class="CharacterClass" format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://character_class.gd" id="1"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
class_name_de = "Schurke"
|
||||
main_stat = 1
|
||||
base_strength = 8
|
||||
base_agility = 15
|
||||
base_intelligence = 7
|
||||
base_stamina = 10
|
||||
strength_per_level = 1.5
|
||||
agility_per_level = 3.0
|
||||
intelligence_per_level = 1.5
|
||||
stamina_per_level = 2.0
|
||||
unarmed_min_damage = 1
|
||||
unarmed_max_damage = 3
|
||||
unarmed_attack_speed = 1.5
|
||||
19
classes/warrior.tres
Normal file
19
classes/warrior.tres
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[gd_resource type="Resource" script_class="CharacterClass" format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://character_class.gd" id="1"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
class_name_de = "Krieger"
|
||||
main_stat = 0
|
||||
base_strength = 15
|
||||
base_agility = 8
|
||||
base_intelligence = 5
|
||||
base_stamina = 12
|
||||
strength_per_level = 3.0
|
||||
agility_per_level = 1.5
|
||||
intelligence_per_level = 1.0
|
||||
stamina_per_level = 2.5
|
||||
unarmed_min_damage = 2
|
||||
unarmed_max_damage = 4
|
||||
unarmed_attack_speed = 1.8
|
||||
63
equipment.gd
Normal file
63
equipment.gd
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Equipment.gd
|
||||
# Resource für Ausrüstungsgegenstände
|
||||
extends Resource
|
||||
class_name Equipment
|
||||
|
||||
enum Slot {
|
||||
HEAD, # Helm
|
||||
CHEST, # Brustpanzer
|
||||
HANDS, # Handschuhe
|
||||
LEGS, # Beinschienen
|
||||
FEET, # Stiefel
|
||||
WEAPON, # Waffe
|
||||
OFFHAND # Nebenhand (Schild, etc.)
|
||||
}
|
||||
|
||||
enum Rarity {
|
||||
COMMON, # Weiß
|
||||
UNCOMMON, # Grün
|
||||
RARE, # Blau
|
||||
EPIC # Lila
|
||||
}
|
||||
|
||||
@export var item_name: String = "Unbekannt"
|
||||
@export var slot: Slot = Slot.WEAPON
|
||||
@export var rarity: Rarity = Rarity.COMMON
|
||||
|
||||
# Stats die das Item gibt
|
||||
@export var armor: int = 0
|
||||
@export var strength: int = 0
|
||||
@export var agility: int = 0
|
||||
@export var intelligence: int = 0
|
||||
@export var stamina: int = 0
|
||||
@export var haste: float = 0.0 # Angriffsgeschwindigkeit (0.1 = 10% schneller)
|
||||
|
||||
# Nur für Waffen
|
||||
@export var min_damage: int = 0
|
||||
@export var max_damage: int = 0
|
||||
@export var attack_speed: float = 1.5 # Sekunden zwischen Angriffen
|
||||
@export var weapon_range: float = 3.0
|
||||
|
||||
# Icon für UI
|
||||
@export var icon: Texture2D
|
||||
|
||||
# Slot-Namen für Anzeige
|
||||
static func get_slot_name(s: Slot) -> String:
|
||||
match s:
|
||||
Slot.HEAD: return "Kopf"
|
||||
Slot.CHEST: return "Brust"
|
||||
Slot.HANDS: return "Hände"
|
||||
Slot.LEGS: return "Beine"
|
||||
Slot.FEET: return "Füße"
|
||||
Slot.WEAPON: return "Waffe"
|
||||
Slot.OFFHAND: return "Nebenhand"
|
||||
return "Unbekannt"
|
||||
|
||||
# Seltenheitsfarbe
|
||||
static func get_rarity_color(r: Rarity) -> Color:
|
||||
match r:
|
||||
Rarity.COMMON: return Color(1, 1, 1) # Weiß
|
||||
Rarity.UNCOMMON: return Color(0.2, 0.8, 0.2) # Grün
|
||||
Rarity.RARE: return Color(0.3, 0.5, 1.0) # Blau
|
||||
Rarity.EPIC: return Color(0.7, 0.3, 0.9) # Lila
|
||||
return Color(1, 1, 1)
|
||||
1
equipment.gd.uid
Normal file
1
equipment.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://re0xiie1udfq
|
||||
18
equipment/iron_helm.tres
Normal file
18
equipment/iron_helm.tres
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[gd_resource type="Resource" script_class="Equipment" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://equipment.gd" id="1_equipment"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_equipment")
|
||||
item_name = "Eisenhelm"
|
||||
slot = 0
|
||||
rarity = 0
|
||||
armor = 5
|
||||
strength = 1
|
||||
agility = 0
|
||||
intelligence = 0
|
||||
stamina = 1
|
||||
min_damage = 0
|
||||
max_damage = 0
|
||||
attack_speed = 1.5
|
||||
weapon_range = 3.0
|
||||
18
equipment/iron_sword.tres
Normal file
18
equipment/iron_sword.tres
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[gd_resource type="Resource" script_class="Equipment" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://equipment.gd" id="1_equipment"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_equipment")
|
||||
item_name = "Eisenschwert"
|
||||
slot = 5
|
||||
rarity = 0
|
||||
armor = 0
|
||||
strength = 2
|
||||
agility = 0
|
||||
intelligence = 0
|
||||
stamina = 0
|
||||
min_damage = 3
|
||||
max_damage = 6
|
||||
attack_speed = 1.5
|
||||
weapon_range = 3.0
|
||||
18
equipment/leather_chest.tres
Normal file
18
equipment/leather_chest.tres
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[gd_resource type="Resource" script_class="Equipment" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://equipment.gd" id="1_equipment"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_equipment")
|
||||
item_name = "Lederrüstung"
|
||||
slot = 1
|
||||
rarity = 0
|
||||
armor = 8
|
||||
strength = 0
|
||||
agility = 1
|
||||
intelligence = 0
|
||||
stamina = 2
|
||||
min_damage = 0
|
||||
max_damage = 0
|
||||
attack_speed = 1.5
|
||||
weapon_range = 3.0
|
||||
18
equipment/steel_sword.tres
Normal file
18
equipment/steel_sword.tres
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[gd_resource type="Resource" script_class="Equipment" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://equipment.gd" id="1_equipment"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_equipment")
|
||||
item_name = "Stahlschwert"
|
||||
slot = 5
|
||||
rarity = 1
|
||||
armor = 0
|
||||
strength = 4
|
||||
agility = 0
|
||||
intelligence = 0
|
||||
stamina = 0
|
||||
min_damage = 5
|
||||
max_damage = 9
|
||||
attack_speed = 1.4
|
||||
weapon_range = 3.0
|
||||
18
equipment/wooden_shield.tres
Normal file
18
equipment/wooden_shield.tres
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[gd_resource type="Resource" script_class="Equipment" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://equipment.gd" id="1_equipment"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_equipment")
|
||||
item_name = "Holzschild"
|
||||
slot = 6
|
||||
rarity = 0
|
||||
armor = 6
|
||||
strength = 0
|
||||
agility = 0
|
||||
intelligence = 0
|
||||
stamina = 2
|
||||
min_damage = 0
|
||||
max_damage = 0
|
||||
attack_speed = 1.5
|
||||
weapon_range = 3.0
|
||||
9
heavy_strike.tres
Normal file
9
heavy_strike.tres
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[gd_resource type="Resource" script_class="Attack" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://resources/attack.gd" id="1"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
name = "Heavy Strike"
|
||||
damage_type = 0
|
||||
icon = null
|
||||
25
icons/autoattack_icon.svg
Normal file
25
icons/autoattack_icon.svg
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<svg width="64" height="64" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Autoattack Icon - Faust -->
|
||||
<defs>
|
||||
<linearGradient id="fist" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#ffd4a3;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#d4a574;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Circular arrow (autoattack symbol) -->
|
||||
<path d="M 45 15 A 12 12 0 1 1 33 3" stroke="#4CAF50" stroke-width="3" fill="none" stroke-linecap="round"/>
|
||||
<polygon points="45,15 50,10 50,20" fill="#4CAF50"/>
|
||||
|
||||
<!-- Fist palm -->
|
||||
<rect x="18" y="35" width="16" height="20" rx="3" fill="url(#fist)" stroke="#b8945f" stroke-width="2"/>
|
||||
|
||||
<!-- Thumb -->
|
||||
<ellipse cx="35" cy="45" rx="4" ry="8" fill="url(#fist)" stroke="#b8945f" stroke-width="2"/>
|
||||
|
||||
<!-- Fingers -->
|
||||
<rect x="18" y="28" width="3" height="10" rx="1.5" fill="url(#fist)" stroke="#b8945f" stroke-width="1"/>
|
||||
<rect x="22" y="25" width="3" height="12" rx="1.5" fill="url(#fist)" stroke="#b8945f" stroke-width="1"/>
|
||||
<rect x="26" y="26" width="3" height="11" rx="1.5" fill="url(#fist)" stroke="#b8945f" stroke-width="1"/>
|
||||
<rect x="30" y="28" width="3" height="9" rx="1.5" fill="url(#fist)" stroke="#b8945f" stroke-width="1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
43
icons/autoattack_icon.svg.import
Normal file
43
icons/autoattack_icon.svg.import
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bkujmu8r6370p"
|
||||
path="res://.godot/imported/autoattack_icon.svg-8c48165bd13a879d5f6cdbc811e19882.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icons/autoattack_icon.svg"
|
||||
dest_files=["res://.godot/imported/autoattack_icon.svg-8c48165bd13a879d5f6cdbc811e19882.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
26
icons/heavy_strike_icon.svg
Normal file
26
icons/heavy_strike_icon.svg
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<svg width="64" height="64" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Heavy Strike Icon - Schwert mit Schlageffekt -->
|
||||
<defs>
|
||||
<linearGradient id="blade" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#e0e0e0;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#808080;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Impact lines (red) -->
|
||||
<path d="M 10 15 L 20 10" stroke="#ff4444" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 8 25 L 18 20" stroke="#ff4444" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M 12 35 L 22 30" stroke="#ff4444" stroke-width="3" stroke-linecap="round"/>
|
||||
|
||||
<!-- Sword blade -->
|
||||
<polygon points="25,10 35,10 40,50 20,50" fill="url(#blade)" stroke="#404040" stroke-width="2"/>
|
||||
|
||||
<!-- Sword guard -->
|
||||
<rect x="15" y="48" width="30" height="4" fill="#8B4513" stroke="#654321" stroke-width="1"/>
|
||||
|
||||
<!-- Sword handle -->
|
||||
<rect x="25" y="50" width="10" height="10" fill="#654321" stroke="#3d2817" stroke-width="1"/>
|
||||
|
||||
<!-- Pommel -->
|
||||
<circle cx="30" cy="62" r="4" fill="#DAA520" stroke="#B8860B" stroke-width="1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
43
icons/heavy_strike_icon.svg.import
Normal file
43
icons/heavy_strike_icon.svg.import
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dqkaowq4cvtbl"
|
||||
path="res://.godot/imported/heavy_strike_icon.svg-ae86ca74d5a61e67598cea5812ee34ac.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icons/heavy_strike_icon.svg"
|
||||
dest_files=["res://.godot/imported/heavy_strike_icon.svg-ae86ca74d5a61e67598cea5812ee34ac.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
77
inventory.gd
Normal file
77
inventory.gd
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# Inventory.gd
|
||||
# Verwaltet das Spieler-Inventar mit Items und Gold
|
||||
extends Resource
|
||||
class_name Inventory
|
||||
|
||||
signal inventory_changed
|
||||
signal gold_changed(new_amount: int)
|
||||
|
||||
const MAX_SLOTS = 20 # Maximale Inventarplätze
|
||||
|
||||
var items: Array[Equipment] = []
|
||||
var gold: int = 0
|
||||
|
||||
func _init():
|
||||
items = []
|
||||
gold = 0
|
||||
|
||||
# Item hinzufügen - gibt true zurück wenn erfolgreich
|
||||
func add_item(item: Equipment) -> bool:
|
||||
if items.size() >= MAX_SLOTS:
|
||||
print("Inventar voll!")
|
||||
return false
|
||||
items.append(item)
|
||||
inventory_changed.emit()
|
||||
print("Item erhalten: ", item.item_name)
|
||||
return true
|
||||
|
||||
# Item an Index entfernen
|
||||
func remove_item_at(index: int) -> Equipment:
|
||||
if index < 0 or index >= items.size():
|
||||
return null
|
||||
var item = items[index]
|
||||
items.remove_at(index)
|
||||
inventory_changed.emit()
|
||||
return item
|
||||
|
||||
# Item direkt entfernen
|
||||
func remove_item(item: Equipment) -> bool:
|
||||
var index = items.find(item)
|
||||
if index == -1:
|
||||
return false
|
||||
items.remove_at(index)
|
||||
inventory_changed.emit()
|
||||
return true
|
||||
|
||||
# Gold hinzufügen
|
||||
func add_gold(amount: int):
|
||||
gold += amount
|
||||
gold_changed.emit(gold)
|
||||
print("+", amount, " Gold (Gesamt: ", gold, ")")
|
||||
|
||||
# Gold ausgeben - gibt true zurück wenn genug vorhanden
|
||||
func spend_gold(amount: int) -> bool:
|
||||
if gold < amount:
|
||||
print("Nicht genug Gold!")
|
||||
return false
|
||||
gold -= amount
|
||||
gold_changed.emit(gold)
|
||||
return true
|
||||
|
||||
# Prüfen ob Inventar voll ist
|
||||
func is_full() -> bool:
|
||||
return items.size() >= MAX_SLOTS
|
||||
|
||||
# Anzahl freier Slots
|
||||
func free_slots() -> int:
|
||||
return MAX_SLOTS - items.size()
|
||||
|
||||
# Item an Index holen
|
||||
func get_item(index: int) -> Equipment:
|
||||
if index < 0 or index >= items.size():
|
||||
return null
|
||||
return items[index]
|
||||
|
||||
# Anzahl Items
|
||||
func item_count() -> int:
|
||||
return items.size()
|
||||
1
inventory.gd.uid
Normal file
1
inventory.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b7x1jr36w0bfg
|
||||
128
inventory_panel.gd
Normal file
128
inventory_panel.gd
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# InventoryPanel.gd
|
||||
# UI für das Spieler-Inventar
|
||||
extends CanvasLayer
|
||||
|
||||
signal item_selected(item: Equipment, index: int)
|
||||
|
||||
var panel_visible = false
|
||||
var player = null
|
||||
|
||||
@onready var panel = $Panel
|
||||
@onready var gold_label = $Panel/VBoxContainer/Header/GoldLabel
|
||||
@onready var item_grid = $Panel/VBoxContainer/ScrollContainer/ItemGrid
|
||||
|
||||
const SLOT_SIZE = 50
|
||||
|
||||
func _ready():
|
||||
panel.visible = false
|
||||
|
||||
func setup(p):
|
||||
player = p
|
||||
if player and player.inventory:
|
||||
player.inventory.inventory_changed.connect(_on_inventory_changed)
|
||||
player.inventory.gold_changed.connect(_on_gold_changed)
|
||||
_refresh_inventory()
|
||||
|
||||
func toggle():
|
||||
panel_visible = !panel_visible
|
||||
panel.visible = panel_visible
|
||||
if panel_visible:
|
||||
_refresh_inventory()
|
||||
|
||||
func _on_inventory_changed():
|
||||
_refresh_inventory()
|
||||
|
||||
func _on_gold_changed(new_amount: int):
|
||||
gold_label.text = str(new_amount) + " Gold"
|
||||
|
||||
func _refresh_inventory():
|
||||
if player == null or player.inventory == null:
|
||||
return
|
||||
|
||||
# Gold aktualisieren
|
||||
gold_label.text = str(player.inventory.gold) + " Gold"
|
||||
|
||||
# Alte Slots entfernen
|
||||
for child in item_grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# Slots erstellen (immer MAX_SLOTS anzeigen)
|
||||
for i in range(Inventory.MAX_SLOTS):
|
||||
var slot = _create_slot(i)
|
||||
item_grid.add_child(slot)
|
||||
|
||||
func _create_slot(index: int) -> Panel:
|
||||
var slot = Panel.new()
|
||||
slot.custom_minimum_size = Vector2(SLOT_SIZE, SLOT_SIZE)
|
||||
|
||||
# Slot-Hintergrund stylen
|
||||
var style = StyleBoxFlat.new()
|
||||
style.bg_color = Color(0.15, 0.15, 0.15)
|
||||
style.border_color = Color(0.3, 0.3, 0.3)
|
||||
style.set_border_width_all(1)
|
||||
slot.add_theme_stylebox_override("panel", style)
|
||||
|
||||
# Item vorhanden?
|
||||
if player.inventory and index < player.inventory.item_count():
|
||||
var item = player.inventory.get_item(index)
|
||||
if item:
|
||||
# Item-Name Label
|
||||
var label = Label.new()
|
||||
label.text = item.item_name.substr(0, 3) # Erste 3 Buchstaben
|
||||
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
label.add_theme_font_size_override("font_size", 10)
|
||||
label.modulate = Equipment.get_rarity_color(item.rarity)
|
||||
label.anchors_preset = Control.PRESET_FULL_RECT
|
||||
slot.add_child(label)
|
||||
|
||||
# Rahmen in Seltenheitsfarbe
|
||||
style.border_color = Equipment.get_rarity_color(item.rarity)
|
||||
style.set_border_width_all(2)
|
||||
|
||||
# Klick-Handler
|
||||
slot.gui_input.connect(_on_slot_clicked.bind(index, item))
|
||||
|
||||
# Tooltip
|
||||
slot.tooltip_text = _get_item_tooltip(item)
|
||||
|
||||
return slot
|
||||
|
||||
func _on_slot_clicked(event: InputEvent, index: int, item: Equipment):
|
||||
if event is InputEventMouseButton and event.pressed:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
# Linksklick: Item auswählen/anlegen
|
||||
item_selected.emit(item, index)
|
||||
elif event.button_index == MOUSE_BUTTON_RIGHT:
|
||||
# Rechtsklick: Item direkt anlegen
|
||||
if player:
|
||||
var old_item = player.equip_item(item)
|
||||
player.inventory.remove_item(item)
|
||||
if old_item:
|
||||
player.inventory.add_item(old_item)
|
||||
_refresh_inventory()
|
||||
|
||||
func _get_item_tooltip(item: Equipment) -> String:
|
||||
var tooltip = item.item_name + "\n"
|
||||
tooltip += Equipment.get_slot_name(item.slot) + "\n"
|
||||
tooltip += "---\n"
|
||||
|
||||
if item.slot == Equipment.Slot.WEAPON:
|
||||
tooltip += "Schaden: " + str(item.min_damage) + "-" + str(item.max_damage) + "\n"
|
||||
tooltip += "Tempo: " + str(item.attack_speed) + "s\n"
|
||||
|
||||
if item.armor > 0:
|
||||
tooltip += "Rüstung: +" + str(item.armor) + "\n"
|
||||
if item.strength > 0:
|
||||
tooltip += "Stärke: +" + str(item.strength) + "\n"
|
||||
if item.agility > 0:
|
||||
tooltip += "Beweglichkeit: +" + str(item.agility) + "\n"
|
||||
if item.intelligence > 0:
|
||||
tooltip += "Intelligenz: +" + str(item.intelligence) + "\n"
|
||||
if item.stamina > 0:
|
||||
tooltip += "Ausdauer: +" + str(item.stamina) + "\n"
|
||||
if item.haste > 0:
|
||||
tooltip += "Tempo: +" + str(int(item.haste * 100)) + "%\n"
|
||||
|
||||
tooltip += "\n[Rechtsklick zum Anlegen]"
|
||||
return tooltip
|
||||
1
inventory_panel.gd.uid
Normal file
1
inventory_panel.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bjmcu0tyxqxmd
|
||||
63
inventory_panel.tscn
Normal file
63
inventory_panel.tscn
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
[gd_scene format=3 uid="uid://inventory_panel"]
|
||||
|
||||
[ext_resource type="Script" path="res://inventory_panel.gd" id="1_panel"]
|
||||
|
||||
[node name="InventoryPanel" type="CanvasLayer"]
|
||||
script = ExtResource("1_panel")
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
anchors_preset = 6
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -320.0
|
||||
offset_top = -250.0
|
||||
offset_right = -20.0
|
||||
offset_bottom = 250.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 10.0
|
||||
offset_top = 10.0
|
||||
offset_right = -10.0
|
||||
offset_bottom = -10.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 8
|
||||
|
||||
[node name="Header" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Title" type="Label" parent="Panel/VBoxContainer/Header"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "Inventar"
|
||||
|
||||
[node name="GoldLabel" type="Label" parent="Panel/VBoxContainer/Header"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 16
|
||||
theme_override_colors/font_color = Color(1, 0.85, 0, 1)
|
||||
text = "0 Gold"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="Panel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ItemGrid" type="GridContainer" parent="Panel/VBoxContainer/ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/h_separation = 5
|
||||
theme_override_constants/v_separation = 5
|
||||
columns = 5
|
||||
7
loot_entry.gd
Normal file
7
loot_entry.gd
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# LootEntry.gd
|
||||
# Ein einzelner Eintrag in einer LootTable
|
||||
extends Resource
|
||||
class_name LootEntry
|
||||
|
||||
@export var item: Equipment
|
||||
@export_range(0.0, 1.0) var drop_chance: float = 0.1 # 10% Standard
|
||||
1
loot_entry.gd.uid
Normal file
1
loot_entry.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cx2w8nkuoylv5
|
||||
24
loot_table.gd
Normal file
24
loot_table.gd
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# LootTable.gd
|
||||
# Definiert mögliche Drops eines Gegners
|
||||
extends Resource
|
||||
class_name LootTable
|
||||
|
||||
# Gold-Drop
|
||||
@export var min_gold: int = 1
|
||||
@export var max_gold: int = 5
|
||||
|
||||
# Item-Drops mit Wahrscheinlichkeiten
|
||||
@export var possible_drops: Array[LootEntry] = []
|
||||
|
||||
# Generiert Loot basierend auf Tabelle
|
||||
func generate_loot() -> Dictionary:
|
||||
var result = {
|
||||
"gold": randi_range(min_gold, max_gold),
|
||||
"items": []
|
||||
}
|
||||
|
||||
for entry in possible_drops:
|
||||
if randf() <= entry.drop_chance:
|
||||
result["items"].append(entry.item)
|
||||
|
||||
return result
|
||||
1
loot_table.gd.uid
Normal file
1
loot_table.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dej1tpamsi71r
|
||||
Loading…
Add table
Reference in a new issue