Godot Version
v4.2.2.stable.official
Question
I am curently creating my own Pokemon like RPG and to do that, i have followed a tutorial series by the Youtuber Coding Quest. He explained everything clearly, but he left out one important aspect. He did not explain how to make the opponent choose an attack at random from his repertoire to attack. And now I just don’t know how to program this into my game. I’ve already written to the Youtuber, but the tutorial series and the video in which my problem begins are already a year old, so I don’t think he’ll reply to my message.
I’m just a beginner in coding (and I’m not very good at it) This is also my first message in the forum and I’m not sure if I should just put all the code from the tutorial in the message (because it’s really a lot of code) or if it’s enough if someone just shows me the flow of turn based combat
I apologize for the bad grammar and spelling mistakes if there are any but english is not my native language.
Greetings from Germany
Can you show how the different abilities are implemented?
I have one Database that holds every Creature with all of its stats and attacks that gets autoloaded at the start of the game.
extends Node
func _ready():
addEsentia("ESCARGEL")
var dataBaseEsentia = {
0 : {
"Name": "ESCARGEL",
"Frame": 0,
"Health" : 100,
"Level" : 1,
"Exp" : 0,
"MaxExp" : 10,
"Strength" : 5,
"Defence" : 10,
"Scene" : preload("res://Esentia Battle/Escargel.tscn"),
"Attacks":{
0 : {
"Name": ": Ramme",
"Target" : "Monster",
"Damage" : randi_range(5,7),
"cost" : 2
},
1 : {
"Name": ": Schleim",
"Target" : "Monster",
"Damage" : randi_range(8,10),
"cost" : 3
}
}
},
In the battle scene I have a node called Player and one called Enemy which have the respective monsters on each side as children. The players turn is determined in the UI node. The turn of the enemy monster in the battle scene itself.
Here is the code from the battle scene:
extends CanvasLayer
var escargel = preload("res://Esentia Battle/Escargel.tscn")
var selected = 0
# Called when the node enters the scene tree for the first time.
func _ready():
var montemp = escargel.instantiate()
$Enemy.add_child(montemp)
$Enemy.scale.x = -1
$UI/Menu/GridContainer/Angriff.grab_focus()
for i in Game.selectedEsentia:
var monTemp = Game.selectedEsentia[i]["Scene"].instantiate()
monTemp.name = Game.selectedEsentia[i]["Name"]
monTemp.hide()
$Player.add_child(monTemp)
$Player.get_child(0).show()
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
func _on_item_pressed():
pass # Replace with function body.
func MonsterTurn():
$UI/Menu.hide()
$UI/Switch.hide()
$UI/Fight.hide()
var damage = randi_range(5,8)
await get_tree().create_timer(2).timeout
if $Enemy.get_child(0).Health <= 0:
Game.addExp(10)
$"../UI/AnimationPlayer".play("TransIn")
await get_tree().create_timer(1.5).timeout
$"../Player/AnimatedSprite2D".visible = true
get_tree().paused = false
queue_free()
$"../UI/AnimationPlayer".play("TransOut")
$Player.get_child(selected).hit(": Schleim", damage)#HERE IS THE PROBLEM.
$Action.text = "(Gegner) " + $Enemy.get_child(0).name + " setzt eine Attacke ein! "
Game.selectedEsentia[0]["Health"] -= damage
await get_tree().create_timer(2).timeout
$UI/Menu/GridContainer/Angriff.grab_focus()
$UI/Menu.show()
Everything works perfectly, I just don’t know how to get the opponent to randomly select an attack from his repertoire at line 46 and use it.
I hope it is roughly understandable what I mean. I am not really good at explaining.
you can grab a random value from the attack dictionary like this:
var entity_attacks = Game.selectedEsentia[0]["Attacks"]
var attack = entity_attacks[randi_range(0, entity_attacks.size()-1)
this should select a random attack from the given data
First of all, thank you for your help
but I get an error message when I enter the code in the game.
Invalid get index 'attack'(on base: 'StaticBody2D (Escargel.gd)').
In this case, ‘Escargel’ is the type of monster that is called into battle. The monster is also a Scene with code:
extends StaticBody2D
var Health = 20
var Level = 1
func _ready():
Level = randi_range(1,5)
$"Aim/Attack".hide()
func hit(anim, damage):
Health -= damage
$"Aim/Attack".show()
$"Aim/Attack".play(anim)
func _on_attack_animation_finished():
$"Aim/Attack".hide()
func capture():
$AnimationPlayer.play("capture", -1,3)
await $AnimationPlayer.animation_finished
get_parent().get_parent()._on_flee_pressed()
Where do you store the dataBaseEsentia?
In the autoloaded game node that has all the Monsters.
Here is the whole thing:
extends Node
func _ready():
addEsentia("ESCARGEL")
var dataBaseEsentia = {
0 : {
"Name": "ESCARGEL",
"Frame": 0,
"Health" : 100,
"Level" : 1,
"Exp" : 0,
"MaxExp" : 10,
"Strength" : 5,
"Defence" : 10,
"Scene" : preload("res://Esentia Battle/Escargel.tscn"),
"Attacks":{
0 : {
"Name": ": Ramme",
"Target" : "Monster",
"Damage" : randi_range(5,7),
"cost" : 2
},
1 : {
"Name": ": Schleim",
"Target" : "Monster",
"Damage" : randi_range(8,10),
"cost" : 3
}
}
}
var selectedEsentia = {
}
func addEsentia(Name):
for i in dataBaseEsentia:
if dataBaseEsentia[i]["Name"] == Name:
var tempDic = dataBaseEsentia[i].duplicate(true)
selectedEsentia[selectedEsentia.size()] = tempDic
func addExp(amount):
for i in selectedEsentia:
selectedEsentia[i]["Exp"] += amount
if selectedEsentia[i]["Exp"] >= selectedEsentia[i]["MaxExp"]:
#LEVEL UP
selectedEsentia[i]["Level"] += 1
selectedEsentia[i]["Exp"] = 0
selectedEsentia[i]["MaxExp"] = selectedEsentia[i]["MaxExp"]*1.5
Hope this helps.
Then you can just reference the dictionary as follows:
var entity_attacks = Game.dataBaseEsentia[0]["Attacks"]
Make sure that you replace the “0” with the corresponding entity index.
And just a little tip. You are storing a lot of data in a dictionary. Godot has a nice way of dealing with this called “Resource”. You can look up some tutorials on custom resources, this makes creating all this data way easier and also easier to handle
Thank you for the tip. I will look it up.
I have implemented your code like this:
var entity_attacks = Game.dataBaseEsentia[0]["Attacks"]
var attack = entity_attacks[randi_range(0, entity_attacks.size()-1)]
$Player.get_child(selected).hit(attack, damage) #HERE IS THE PROBLEM.
$Action.text = "(Gegner) " + $Enemy.get_child(0).name + " setzt eine Attacke ein! "
Game.selectedEsentia[0]["Health"] -= damage
await get_tree().create_timer(2).timeout
$UI/Menu/GridContainer/Angriff.grab_focus()
$UI/Menu.show()
I now get this error message:
Invalid type in function 'play' in base 'AnimatedSprite2D'. Cannot convert argument 1 from Dictionary to StringName.
This is the part that causes the error:
func hit(anim, damage):
Health -= damage
$"Aim/Attack".show()
$"Aim/Attack".play(anim)#ERROR
I guess it has something to do with the attack Animation that is in the AnimatedSprite2D from the Monster scene.
What are the names of the attack animations? Do they correspond to the “name” property in the dictionary?
If yes then you need to call the hit method like this:
$Player.get_child(selected).hit(attack["Name"], damage)
IT WORK’S! Thank you and thank you for your’e patience.
1 Like