Ball implemented, started work on game AI
This commit is contained in:
92
proto2/ai/ball_game_ai3d.gd
Normal file
92
proto2/ai/ball_game_ai3d.gd
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
extends Node
|
||||||
|
class_name BallGameAI3D
|
||||||
|
|
||||||
|
var _cheers = {}
|
||||||
|
var _game_area: AABB
|
||||||
|
var _teams = {}
|
||||||
|
var _main
|
||||||
|
var _state = STATE_INIT
|
||||||
|
var _ball_instance
|
||||||
|
var _cheer_locations = {}
|
||||||
|
var _team_start = {}
|
||||||
|
var _ball_carrier = null
|
||||||
|
var _ball_team = -1
|
||||||
|
var ch2team: Dictionary = {}
|
||||||
|
var gate2team = {}
|
||||||
|
var _gates = {}
|
||||||
|
var _scores = {}
|
||||||
|
|
||||||
|
enum {STATE_INIT, STATE_START, STATE_RUNNING, STATE_FINISH}
|
||||||
|
func _ready():
|
||||||
|
_game_area = AABB()
|
||||||
|
|
||||||
|
func set_ball(ball: Node):
|
||||||
|
_ball_instance = ball
|
||||||
|
|
||||||
|
func add_player(team: int, pl: Dictionary):
|
||||||
|
if !_teams.has(team):
|
||||||
|
_teams[team] = [pl]
|
||||||
|
else:
|
||||||
|
_teams[team].push_back(pl)
|
||||||
|
assert pl != null
|
||||||
|
ch2team[pl.scene] = team
|
||||||
|
func add_cheer(team: int, ch: Dictionary):
|
||||||
|
if !_cheers.has(team):
|
||||||
|
_cheers[team] = [ch]
|
||||||
|
else:
|
||||||
|
_cheers[team].push_back(ch)
|
||||||
|
assert ch != null
|
||||||
|
ch2team[ch.scene] = team
|
||||||
|
func add_cheer_game_location(team: int, loc: Vector3):
|
||||||
|
if !_cheer_locations.has(team):
|
||||||
|
_cheer_locations[team] = [loc]
|
||||||
|
else:
|
||||||
|
_cheer_locations[team].push_back(loc)
|
||||||
|
_game_area = _game_area.expand(loc)
|
||||||
|
func set_team_start(team: int, v: Vector3):
|
||||||
|
_team_start[team] = v
|
||||||
|
_game_area = _game_area.expand(v)
|
||||||
|
func set_team_gate(team: int, gate: Area):
|
||||||
|
_gates[team] = gate
|
||||||
|
gate2team[gate] = team
|
||||||
|
gate.connect("body_entered", self, "check_goal", [gate])
|
||||||
|
var o : = gate.global_transform.origin
|
||||||
|
_game_area = _game_area.expand(o)
|
||||||
|
func set_main(n):
|
||||||
|
_main = n
|
||||||
|
func start_game():
|
||||||
|
var ball = _ball_instance
|
||||||
|
ball.add_to_group("ball")
|
||||||
|
_state = STATE_START
|
||||||
|
for t in _teams.keys():
|
||||||
|
for ch in _teams[t]:
|
||||||
|
assert ch != null
|
||||||
|
print(ch)
|
||||||
|
assert ch.scene != null
|
||||||
|
print("start: ", _team_start[t])
|
||||||
|
ch.scene.walkto(_team_start[t])
|
||||||
|
var loc = 0
|
||||||
|
for t in _cheers.keys():
|
||||||
|
for ch in _cheers[t]:
|
||||||
|
assert ch != null
|
||||||
|
print(ch)
|
||||||
|
assert ch.scene != null
|
||||||
|
ch.scene.walkto(_cheer_locations[t][loc % _cheer_locations[t].size()])
|
||||||
|
loc += 1
|
||||||
|
for t in _teams.keys():
|
||||||
|
_scores[t] = 0
|
||||||
|
func stop_game():
|
||||||
|
# for k in get_tree().get_nodes_in_group("ball"):
|
||||||
|
# k.queue_free()
|
||||||
|
_state = STATE_INIT
|
||||||
|
var max_score = -1
|
||||||
|
var winner_team = -1
|
||||||
|
for k in _scores.keys():
|
||||||
|
if _scores[k] > max_score:
|
||||||
|
max_score = _scores[k]
|
||||||
|
winner_team = k
|
||||||
|
if winner_team >= 0:
|
||||||
|
for e in _teams[winner_team]:
|
||||||
|
world.increase_xp(e, min(e.xp * 2, min(100 * e.level, 1000)))
|
||||||
|
for e in _cheers[winner_team]:
|
||||||
|
world.increase_xp(e, min(e.xp * 2, min(200 * e.level, 2000)))
|
||||||
Binary file not shown.
@@ -12,3 +12,6 @@ func _ready():
|
|||||||
# 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):
|
||||||
# pass
|
# pass
|
||||||
|
#func _physics_process(delta):
|
||||||
|
# for obj in get_tree().get_nodes_in_group("characters"):
|
||||||
|
# pass
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ func _process(delta):
|
|||||||
var tf_turn = Transform(Quat(Vector3(0, 1, 0), PI * 0.6 * delta))
|
var tf_turn = Transform(Quat(Vector3(0, 1, 0), PI * 0.6 * delta))
|
||||||
frame_tf *= tf_turn
|
frame_tf *= tf_turn
|
||||||
if Input.is_action_just_pressed("action1"):
|
if Input.is_action_just_pressed("action1"):
|
||||||
if monitored_objects.size() > 0:
|
if master_node.item_right_hand:
|
||||||
|
master_node.item_right_hand.activate()
|
||||||
|
elif monitored_objects.size() > 0:
|
||||||
var closest = monitored_objects[0]
|
var closest = monitored_objects[0]
|
||||||
var dst = master_node.global_transform.origin.distance_to(closest.global_transform.origin)
|
var dst = master_node.global_transform.origin.distance_to(closest.global_transform.origin)
|
||||||
for k in monitored_objects:
|
for k in monitored_objects:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ signal room_event
|
|||||||
signal next_day
|
signal next_day
|
||||||
signal next_period
|
signal next_period
|
||||||
signal level_up
|
signal level_up
|
||||||
|
signal start_training
|
||||||
|
|
||||||
var money: int = 2000
|
var money: int = 2000
|
||||||
var master_node
|
var master_node
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ var skel: Skeleton
|
|||||||
var anim_tree: AnimationTree
|
var anim_tree: AnimationTree
|
||||||
var aplay: AnimationPlayer
|
var aplay: AnimationPlayer
|
||||||
const GRAVITY = Vector3(0, -9.8, 0)
|
const GRAVITY = Vector3(0, -9.8, 0)
|
||||||
|
var ball_carry: Node
|
||||||
|
var item_right_hand: Node
|
||||||
# Declare member variables here. Examples:
|
# Declare member variables here. Examples:
|
||||||
# var a = 2
|
# var a = 2
|
||||||
# var b = "text"
|
# var b = "text"
|
||||||
@@ -33,6 +35,7 @@ func _ready():
|
|||||||
anim.loop = true
|
anim.loop = true
|
||||||
add_to_group("characters")
|
add_to_group("characters")
|
||||||
add_to_group("activatable")
|
add_to_group("activatable")
|
||||||
|
ball_carry = get_children()[0].get_children()[0].get_node("item_carry/ball_carry")
|
||||||
|
|
||||||
func get_act():
|
func get_act():
|
||||||
return "Talk"
|
return "Talk"
|
||||||
@@ -61,7 +64,12 @@ func walkto(target: Vector3, spd: float = 1.4):
|
|||||||
set_walk_speed(spd)
|
set_walk_speed(spd)
|
||||||
walk()
|
walk()
|
||||||
|
|
||||||
func _process(delta):
|
func take_object(obj):
|
||||||
|
if obj.is_in_group("items"):
|
||||||
|
obj.taken(self)
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
orientation = global_transform
|
orientation = global_transform
|
||||||
orientation.origin = Vector3()
|
orientation.origin = Vector3()
|
||||||
var sm: AnimationNodeStateMachinePlayback = anim_tree["parameters/base/playback"]
|
var sm: AnimationNodeStateMachinePlayback = anim_tree["parameters/base/playback"]
|
||||||
@@ -84,7 +92,7 @@ func _process(delta):
|
|||||||
var direction: Vector3 = (next - global_transform.origin).normalized()
|
var direction: Vector3 = (next - global_transform.origin).normalized()
|
||||||
var actual_direction: Vector3 = -global_transform.basis[2]
|
var actual_direction: Vector3 = -global_transform.basis[2]
|
||||||
var angle: float = Vector2(actual_direction.x, actual_direction.z).angle_to(Vector2(direction.x, direction.z))
|
var angle: float = Vector2(actual_direction.x, actual_direction.z).angle_to(Vector2(direction.x, direction.z))
|
||||||
var tf_turn = Transform(Quat(Vector3(0, 1, 0), -angle * delta))
|
var tf_turn = Transform(Quat(Vector3(0, 1, 0), -angle * min(delta * 2.0, 1.0)))
|
||||||
orientation *= tf_turn
|
orientation *= tf_turn
|
||||||
if !_path || _path.size() == 0:
|
if !_path || _path.size() == 0:
|
||||||
idle()
|
idle()
|
||||||
|
|||||||
@@ -78,6 +78,16 @@ script = ExtResource( 1 )
|
|||||||
|
|
||||||
[node name="female_2018" parent="." instance=ExtResource( 2 )]
|
[node name="female_2018" parent="." instance=ExtResource( 2 )]
|
||||||
|
|
||||||
|
[node name="female_2018" parent="female_2018" index="0"]
|
||||||
|
bones/132/bound_children = [ NodePath("item_carry") ]
|
||||||
|
|
||||||
|
[node name="item_carry" type="BoneAttachment" parent="female_2018/female_2018" index="13"]
|
||||||
|
transform = Transform( 0.816538, -0.555132, -0.158408, 0.505615, 0.555284, 0.660309, -0.278598, -0.619263, 0.734095, 0.174373, 0.783361, -0.0350451 )
|
||||||
|
bone_name = "wrist_R"
|
||||||
|
|
||||||
|
[node name="ball_carry" type="Spatial" parent="female_2018/female_2018/item_carry"]
|
||||||
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.12, 0, 0 )
|
||||||
|
|
||||||
[node name="AnimationTree" type="AnimationTree" parent="female_2018"]
|
[node name="AnimationTree" type="AnimationTree" parent="female_2018"]
|
||||||
tree_root = SubResource( 14 )
|
tree_root = SubResource( 14 )
|
||||||
anim_player = NodePath("../female_2018/AnimationPlayer")
|
anim_player = NodePath("../female_2018/AnimationPlayer")
|
||||||
|
|||||||
@@ -74,6 +74,15 @@ script = ExtResource( 2 )
|
|||||||
|
|
||||||
[node name="male_2018" parent="." instance=ExtResource( 1 )]
|
[node name="male_2018" parent="." instance=ExtResource( 1 )]
|
||||||
|
|
||||||
|
[node name="male_g_2018" parent="male_2018" index="0"]
|
||||||
|
bones/110/bound_children = [ NodePath("item_carry") ]
|
||||||
|
|
||||||
|
[node name="item_carry" type="BoneAttachment" parent="male_2018/male_g_2018" index="9"]
|
||||||
|
transform = Transform( 0.579234, -0.742538, -0.336341, 0.736249, 0.299448, 0.606851, -0.349893, -0.59914, 0.720144, 0.334017, 1.00794, -0.175007 )
|
||||||
|
bone_name = "wrist_R"
|
||||||
|
|
||||||
|
[node name="ball_carry" type="Spatial" parent="male_2018/male_g_2018/item_carry"]
|
||||||
|
|
||||||
[node name="AnimationTree" type="AnimationTree" parent="male_2018"]
|
[node name="AnimationTree" type="AnimationTree" parent="male_2018"]
|
||||||
tree_root = SubResource( 13 )
|
tree_root = SubResource( 13 )
|
||||||
anim_player = NodePath("../male_g_2018/AnimationPlayer")
|
anim_player = NodePath("../male_g_2018/AnimationPlayer")
|
||||||
|
|||||||
@@ -9,9 +9,14 @@ func _ready():
|
|||||||
add_to_group("activatable")
|
add_to_group("activatable")
|
||||||
|
|
||||||
func get_act():
|
func get_act():
|
||||||
return "Start training"
|
return "Get a ball"
|
||||||
func activate():
|
func activate():
|
||||||
print("Starting training...")
|
print("Getting a ball...")
|
||||||
|
var ball_st = load("res://items/ball/ball.tscn").instance()
|
||||||
|
get_node("/root/main").add_child(ball_st)
|
||||||
|
ball_st.global_transform = world.master_node.global_transform
|
||||||
|
ball_st.global_transform.origin += ball_st.global_transform.xform(Vector3(0, 0.5, -0.25))
|
||||||
|
ball_st.taken(world.master_node)
|
||||||
|
|
||||||
# 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):
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
importer="scene"
|
importer="scene"
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
path="res://.import/ball.escn-c244a295d2ddfac47ce2708f1bcb6791.scn"
|
path="res://.import/ball.escn-8722f09c6da73e6847feb641eaa35784.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://ball/ball.escn"
|
source_file="res://items/ball/ball.escn"
|
||||||
dest_files=[ "res://.import/ball.escn-c244a295d2ddfac47ce2708f1bcb6791.scn" ]
|
dest_files=[ "res://.import/ball.escn-8722f09c6da73e6847feb641eaa35784.scn" ]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
43
proto2/items/ball/ball.gd
Normal file
43
proto2/items/ball/ball.gd
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
extends Item
|
||||||
|
|
||||||
|
# Declare member variables here. Examples:
|
||||||
|
# var a = 2
|
||||||
|
# var b = "text"
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready():
|
||||||
|
pass # Replace with function body.
|
||||||
|
|
||||||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
#func _process(delta):
|
||||||
|
# pass
|
||||||
|
func _taken_act(pobj):
|
||||||
|
mode = RigidBody.MODE_KINEMATIC
|
||||||
|
collision_layer = 16
|
||||||
|
collision_mask = 16 | 2
|
||||||
|
get_parent().remove_child(self)
|
||||||
|
if pobj.is_in_group("characters"):
|
||||||
|
pobj.ball_carry.add_child(self)
|
||||||
|
transform = Transform()
|
||||||
|
pobj.item_right_hand = self
|
||||||
|
remove_from_group("activatable")
|
||||||
|
else:
|
||||||
|
pobj.add_child(self)
|
||||||
|
transform = Transform()
|
||||||
|
set_as_toplevel(false)
|
||||||
|
is_at_hands = true
|
||||||
|
func _dropped_act(pobj):
|
||||||
|
._dropped_act(get_parent())
|
||||||
|
pobj.item_right_hand = null
|
||||||
|
add_to_group("activatable")
|
||||||
|
|
||||||
|
func get_take_act():
|
||||||
|
return "Take ball"
|
||||||
|
|
||||||
|
func get_drop_act():
|
||||||
|
return "Drop ball"
|
||||||
|
|
||||||
|
func activate():
|
||||||
|
if is_at_hands:
|
||||||
|
dropped(world.master_node)
|
||||||
|
world.emit_signal("start_training", self)
|
||||||
15
proto2/items/ball/ball.tscn
Normal file
15
proto2/items/ball/ball.tscn
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://items/ball/ball.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://items/ball/ball.escn" type="PackedScene" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape" id=1]
|
||||||
|
radius = 0.25
|
||||||
|
|
||||||
|
[node name="ball" type="RigidBody"]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="ball" parent="." instance=ExtResource( 2 )]
|
||||||
|
|
||||||
|
[node name="CollisionShape" type="CollisionShape" parent="."]
|
||||||
|
shape = SubResource( 1 )
|
||||||
68
proto2/items/item.gd
Normal file
68
proto2/items/item.gd
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
extends RigidBody
|
||||||
|
class_name Item
|
||||||
|
|
||||||
|
var _taken: bool = false
|
||||||
|
var _taken_by: Object
|
||||||
|
var _dropped: bool = false
|
||||||
|
var _dropped_by: Object
|
||||||
|
var is_at_hands: bool = false
|
||||||
|
# Declare member variables here. Examples:
|
||||||
|
# var a = 2
|
||||||
|
# var b = "text"
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready():
|
||||||
|
add_to_group("activatable")
|
||||||
|
|
||||||
|
func get_take_act():
|
||||||
|
return "Take item"
|
||||||
|
|
||||||
|
func get_drop_act():
|
||||||
|
return "Drop item"
|
||||||
|
|
||||||
|
func get_act():
|
||||||
|
if is_at_hands:
|
||||||
|
return get_drop_act()
|
||||||
|
else:
|
||||||
|
return get_take_act()
|
||||||
|
func activate():
|
||||||
|
if is_at_hands:
|
||||||
|
dropped(world.master_node)
|
||||||
|
|
||||||
|
|
||||||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
#func _process(delta):
|
||||||
|
# pass
|
||||||
|
func _taken_act(pobj):
|
||||||
|
mode = RigidBody.MODE_KINEMATIC
|
||||||
|
collision_layer = 16
|
||||||
|
collision_mask = 16 | 2
|
||||||
|
get_parent().remove_child(self)
|
||||||
|
pobj.add_child(self)
|
||||||
|
transform = Transform()
|
||||||
|
set_as_toplevel(false)
|
||||||
|
is_at_hands = true
|
||||||
|
func _dropped_act(pobj):
|
||||||
|
mode = RigidBody.MODE_RIGID
|
||||||
|
collision_layer = 1
|
||||||
|
collision_mask = 1 | 2
|
||||||
|
get_parent().remove_child(self)
|
||||||
|
world.master_node.get_node("/root/main").add_child(self)
|
||||||
|
global_transform = pobj.global_transform
|
||||||
|
set_as_toplevel(true)
|
||||||
|
is_at_hands = false
|
||||||
|
func _physics_process(delta):
|
||||||
|
if _taken:
|
||||||
|
_taken_act(_taken_by)
|
||||||
|
_taken = false
|
||||||
|
_taken_by = null
|
||||||
|
if _dropped:
|
||||||
|
_dropped_act(_dropped_by)
|
||||||
|
_dropped = false
|
||||||
|
_dropped_by = null
|
||||||
|
func taken(pobj):
|
||||||
|
_taken = true
|
||||||
|
_taken_by = pobj
|
||||||
|
func dropped(pobj):
|
||||||
|
_dropped = true
|
||||||
|
_dropped_by = pobj
|
||||||
@@ -6,8 +6,11 @@ extends Spatial
|
|||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
var frame_tf: Transform = Transform()
|
var frame_tf: Transform = Transform()
|
||||||
|
var ball_game : BallGameAI3D
|
||||||
|
|
||||||
func master_control(pos):
|
func master_control(pos):
|
||||||
|
var n = lerp(world.master_node.get_walk_speed(), 3.8, 0.1)
|
||||||
|
world.master_node.set_walk_speed(n)
|
||||||
$master.walkto(pos)
|
$master.walkto(pos)
|
||||||
|
|
||||||
func update_quests():
|
func update_quests():
|
||||||
@@ -28,6 +31,35 @@ func start_interaction(obj):
|
|||||||
else:
|
else:
|
||||||
obj.activate()
|
obj.activate()
|
||||||
|
|
||||||
|
func start_training(ball):
|
||||||
|
print("start training")
|
||||||
|
ball_game = BallGameAI3D.new()
|
||||||
|
var t0 = $team0
|
||||||
|
var t1 = $team1
|
||||||
|
for k in t0.get_children():
|
||||||
|
if k.name.begins_with("cheer"):
|
||||||
|
ball_game.add_cheer_game_location(0, k.global_transform.origin)
|
||||||
|
elif k.name == "start":
|
||||||
|
ball_game.set_team_start(0, k.global_transform.origin)
|
||||||
|
elif k.name == "gate":
|
||||||
|
ball_game.set_team_gate(0, k)
|
||||||
|
for k in t1.get_children():
|
||||||
|
if k.name.begins_with("cheer"):
|
||||||
|
ball_game.add_cheer_game_location(1, k.global_transform.origin)
|
||||||
|
elif k.name == "start":
|
||||||
|
ball_game.set_team_start(1, k.global_transform.origin)
|
||||||
|
elif k.name == "gate":
|
||||||
|
ball_game.set_team_gate(1, k)
|
||||||
|
for ch in world.cheer_team.keys():
|
||||||
|
assert world.cheer_team[ch] != null
|
||||||
|
ball_game.add_cheer(randi() % 2, world.cheer_team[ch])
|
||||||
|
for ch in world.team.keys():
|
||||||
|
assert world.team[ch] != null
|
||||||
|
ball_game.add_player(randi() % 2, world.team[ch])
|
||||||
|
ball_game.set_ball(ball)
|
||||||
|
ball_game.set_main(self)
|
||||||
|
ball_game.start_game()
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
$master.add_to_group("master")
|
$master.add_to_group("master")
|
||||||
controls.master_node = $master
|
controls.master_node = $master
|
||||||
@@ -79,6 +111,7 @@ func _ready():
|
|||||||
quest_timer.connect("timeout", self, "update_quests")
|
quest_timer.connect("timeout", self, "update_quests")
|
||||||
quest_timer.start()
|
quest_timer.start()
|
||||||
controls.connect("action1", self, "start_interaction")
|
controls.connect("action1", self, "start_interaction")
|
||||||
|
world.connect("start_training", self, "start_training")
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
var pos = $master.global_transform.origin
|
var pos = $master.global_transform.origin
|
||||||
|
|||||||
104
proto2/main.tscn
104
proto2/main.tscn
File diff suppressed because one or more lines are too long
@@ -14,6 +14,16 @@ _global_script_classes=[ {
|
|||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://ai/ball_game_ai.gd"
|
"path": "res://ai/ball_game_ai.gd"
|
||||||
}, {
|
}, {
|
||||||
|
"base": "Node",
|
||||||
|
"class": "BallGameAI3D",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://ai/ball_game_ai3d.gd"
|
||||||
|
}, {
|
||||||
|
"base": "RigidBody",
|
||||||
|
"class": "Item",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://items/item.gd"
|
||||||
|
}, {
|
||||||
"base": "Reference",
|
"base": "Reference",
|
||||||
"class": "Quest",
|
"class": "Quest",
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
@@ -36,6 +46,8 @@ _global_script_classes=[ {
|
|||||||
} ]
|
} ]
|
||||||
_global_script_class_icons={
|
_global_script_class_icons={
|
||||||
"BallGameAI": "",
|
"BallGameAI": "",
|
||||||
|
"BallGameAI3D": "",
|
||||||
|
"Item": "",
|
||||||
"Quest": "",
|
"Quest": "",
|
||||||
"QuestObjective": "",
|
"QuestObjective": "",
|
||||||
"StatsQuest": "",
|
"StatsQuest": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user