mirror of
https://github.com/Relintai/broken_seals.git
synced 2024-11-13 20:47:19 +01:00
The scripts folder.
This commit is contained in:
parent
907988a7d0
commit
1715506d4a
9
game/scripts/ai/TestContainer.gd
Normal file
9
game/scripts/ai/TestContainer.gd
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
extends AIActionContainer
|
||||||
|
class_name AITestActionContainer
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func get_title() -> String:
|
||||||
|
return "AITestActionContainer"
|
96
game/scripts/auras/aura_script.gd
Normal file
96
game/scripts/auras/aura_script.gd
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
extends Aura
|
||||||
|
class_name AuraGD
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _handle_aura_damage(aura_data : AuraData, damage_info : SpellDamageInfo) -> void:
|
||||||
|
randomize()
|
||||||
|
|
||||||
|
damage_info.damage = damage_min + (randi() % (damage_max - damage_min))
|
||||||
|
damage_info.damage_source_type = aura_data.aura.damage_type
|
||||||
|
|
||||||
|
if (is_instance_valid(damage_info.dealer)):
|
||||||
|
damage_info.dealer.sdeal_damage_to(damage_info)
|
||||||
|
|
||||||
|
func _handle_aura_heal(aura_data : AuraData, shi : SpellHealInfo) -> void:
|
||||||
|
randomize()
|
||||||
|
|
||||||
|
shi.heal = heal_min + (randi() % (heal_max - heal_min))
|
||||||
|
shi.heal_source_type = aura_data.aura.aura_type
|
||||||
|
|
||||||
|
shi.dealer.sdeal_heal_to(shi)
|
||||||
|
|
||||||
|
func _sapply(info : AuraApplyInfo) -> void:
|
||||||
|
# var add : bool = false
|
||||||
|
var ad : AuraData = info.target.sget_aura_by(info.caster, info.aura.id)
|
||||||
|
|
||||||
|
if ad == null:
|
||||||
|
# add = true
|
||||||
|
ad = AuraData.new()
|
||||||
|
|
||||||
|
setup_aura_data(ad, info);
|
||||||
|
|
||||||
|
for i in range(get_aura_stat_attribute_count()):
|
||||||
|
var stat_attribute : AuraStatAttribute = get_aura_stat_attribute(i)
|
||||||
|
var stat : Stat = info.target.get_stat_enum(stat_attribute.stat)
|
||||||
|
stat.add_modifier(id, stat_attribute.base_mod, stat_attribute.bonus_mod, stat_attribute.percent_mod)
|
||||||
|
|
||||||
|
if states_add != 0:
|
||||||
|
for i in range(EntityEnums.ENTITY_STATE_TYPE_INDEX_MAX):
|
||||||
|
var t : int = 1 << i
|
||||||
|
|
||||||
|
if states_add & t != 0:
|
||||||
|
info.target.sadd_state_ref(i)
|
||||||
|
|
||||||
|
|
||||||
|
info.target.sadd_aura(ad);
|
||||||
|
else:
|
||||||
|
ad.remaining_time = time
|
||||||
|
|
||||||
|
|
||||||
|
func _sdeapply(data : AuraData) -> void:
|
||||||
|
for i in range(get_aura_stat_attribute_count()):
|
||||||
|
var stat_attribute : AuraStatAttribute = get_aura_stat_attribute(i)
|
||||||
|
|
||||||
|
var stat : Stat = data.owner.get_stat_enum(stat_attribute.stat)
|
||||||
|
|
||||||
|
stat.remove_modifier(id)
|
||||||
|
|
||||||
|
if states_add != 0:
|
||||||
|
for i in range(EntityEnums.ENTITY_STATE_TYPE_INDEX_MAX):
|
||||||
|
var t : int = 1 << i
|
||||||
|
|
||||||
|
if states_add & t != 0:
|
||||||
|
data.owner.sremove_state_ref(i)
|
||||||
|
|
||||||
|
func _con_aura_added(data : AuraData) -> void:
|
||||||
|
if data.owner.get_character_skeleton() == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var bse : SpellEffectVisualBasic = visual_spell_effects as SpellEffectVisualBasic
|
||||||
|
|
||||||
|
if bse != null:
|
||||||
|
if bse.root_aura_effect != null:
|
||||||
|
if bse.root_aura_effect_time < 0.00001:
|
||||||
|
data.owner.get_character_skeleton().root_attach_point.add_effect(bse.root_aura_effect)
|
||||||
|
else:
|
||||||
|
data.owner.get_character_skeleton().root_attach_point.add_effect_timed(bse.root_aura_effect, bse.root_aura_effect_time)
|
||||||
|
|
||||||
|
if bse.torso_aura_effect != null:
|
||||||
|
if bse.torso_aura_effect_time < 0.00001:
|
||||||
|
data.owner.get_character_skeleton().torso_attach_point.add_effect(bse.torso_aura_effect)
|
||||||
|
else:
|
||||||
|
data.owner.get_character_skeleton().torso_attach_point.add_effect_timed(bse.torso_aura_effect, bse.torso_aura_effect_time)
|
||||||
|
|
||||||
|
func _con_aura_removed(data : AuraData) -> void:
|
||||||
|
var bse : SpellEffectVisualBasic = visual_spell_effects as SpellEffectVisualBasic
|
||||||
|
|
||||||
|
if bse != null:
|
||||||
|
if bse.root_aura_effect != null and bse.root_aura_effect_time < 0.00001:
|
||||||
|
data.owner.get_character_skeleton().root_attach_point.remove_effect(bse.root_aura_effect)
|
||||||
|
|
||||||
|
if bse.torso_aura_effect != null and bse.torso_aura_effect_time < 0.00001:
|
||||||
|
data.owner.get_character_skeleton().torso_attach_point.remove_effect(bse.torso_aura_effect)
|
||||||
|
|
74
game/scripts/biomes/simple_biome.gd
Normal file
74
game/scripts/biomes/simple_biome.gd
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
extends Biome
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _generate_chunk(chunk: VoxelChunk, spawn_mobs: bool) -> void:
|
||||||
|
# var chunk : VoxelChunk = chunk.get_chunk()
|
||||||
|
|
||||||
|
generate_terrarin(chunk, spawn_mobs)
|
||||||
|
|
||||||
|
func generate_terrarin(chunk : VoxelChunk, spawn_mobs: bool) -> void:
|
||||||
|
# chunk.create(int(chunk.size_x) + 1, int(chunk.size_y) + 1, int(chunk.size_z) + 1)
|
||||||
|
chunk.set_size(int(chunk.size_x), int(chunk.size_y), int(chunk.size_z), 0, 1)
|
||||||
|
|
||||||
|
var noise : OpenSimplexNoise = OpenSimplexNoise.new()
|
||||||
|
noise.seed = 10 * current_seed
|
||||||
|
noise.octaves = 4
|
||||||
|
noise.period = 180.0
|
||||||
|
noise.persistence = 0.8
|
||||||
|
|
||||||
|
var terr_noise : OpenSimplexNoise = OpenSimplexNoise.new()
|
||||||
|
terr_noise.seed = 10 * 321 + 112 * current_seed
|
||||||
|
terr_noise.octaves = 4
|
||||||
|
terr_noise.period = 20.0
|
||||||
|
terr_noise.persistence = 0.9
|
||||||
|
|
||||||
|
var det_noise : OpenSimplexNoise = OpenSimplexNoise.new()
|
||||||
|
det_noise.seed = 10 * 3231 + 112 * current_seed
|
||||||
|
det_noise.octaves = 6
|
||||||
|
det_noise.period = 10.0
|
||||||
|
det_noise.persistence = 0.3
|
||||||
|
|
||||||
|
for x in range(0, chunk.size_x + 1):
|
||||||
|
for z in range(0, chunk.size_z + 1):
|
||||||
|
var val : float = noise.get_noise_2d(x + (chunk.position_x * chunk.size_x), z + (chunk.position_z * chunk.size_z))
|
||||||
|
val *= val
|
||||||
|
val *= 100
|
||||||
|
val += 2
|
||||||
|
|
||||||
|
var tv : float = terr_noise.get_noise_2d(x + (chunk.position_x * chunk.size_x), z + (chunk.position_z * chunk.size_z))
|
||||||
|
tv *= tv * tv
|
||||||
|
val += tv * 2
|
||||||
|
|
||||||
|
var dval : float = noise.get_noise_2d(x + (chunk.position_x * chunk.size_x), z + (chunk.position_z * chunk.size_z))
|
||||||
|
|
||||||
|
val += dval * 6
|
||||||
|
|
||||||
|
var v : int = (int(val))
|
||||||
|
|
||||||
|
v -= chunk.position_y * (chunk.size_y)
|
||||||
|
|
||||||
|
if v > chunk.size_y + 1:
|
||||||
|
v = chunk.size_y + 1
|
||||||
|
|
||||||
|
for y in range(0, v):
|
||||||
|
seed(x + (chunk.position_x * chunk.size_x) + z + (chunk.position_z * chunk.size_z) + y + (chunk.position_y * chunk.size_y))
|
||||||
|
|
||||||
|
if v < 2:
|
||||||
|
chunk.set_voxel(1, x, y, z, VoxelChunk.DEFAULT_CHANNEL_TYPE)
|
||||||
|
elif v == 2:
|
||||||
|
chunk.set_voxel(3, x, y, z, VoxelChunk.DEFAULT_CHANNEL_TYPE)
|
||||||
|
else:
|
||||||
|
chunk.set_voxel(2, x, y, z, VoxelChunk.DEFAULT_CHANNEL_TYPE)
|
||||||
|
|
||||||
|
chunk.set_voxel(int(255.0 * (val - int(val)) / 180.0) * 180, x, y, z, VoxelChunk.DEFAULT_CHANNEL_ISOLEVEL)
|
||||||
|
|
||||||
|
# chunk.build()
|
||||||
|
|
||||||
|
if not Engine.editor_hint and chunk.position_y == 0 and spawn_mobs:
|
||||||
|
Entities.spawn_mob(1, randi() % 3, Vector3(chunk.position_x * chunk.size_x * chunk.voxel_scale - chunk.size_x / 2,\
|
||||||
|
(chunk.position_y + 1) * chunk.size_y * chunk.voxel_scale, \
|
||||||
|
chunk.position_z * chunk.size_z * chunk.voxel_scale - chunk.size_z / 2))
|
||||||
|
|
31
game/scripts/dungeon_start_rooms/start_room.gd
Normal file
31
game/scripts/dungeon_start_rooms/start_room.gd
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
tool
|
||||||
|
extends DungeonRoom
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _setup():
|
||||||
|
sizex = 5
|
||||||
|
sizey = 5
|
||||||
|
sizez = 5
|
||||||
|
|
||||||
|
func _generate_chunk(chunk : VoxelChunk, spawn_mobs: bool) -> void:
|
||||||
|
if chunk.position_x != 0 or chunk.position_z != 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
if chunk.position_y == 0:
|
||||||
|
for y in range(chunk.get_size_y()):
|
||||||
|
chunk.set_voxel(0, 10, y, 10, VoxelChunk.DEFAULT_CHANNEL_TYPE)
|
||||||
|
|
||||||
|
if chunk.position_y == -1:
|
||||||
|
var hs : int = chunk.get_size_y() / 2 - sizex / 2
|
||||||
|
|
||||||
|
for y in range(chunk.get_size_y() / 2, chunk.get_size_y()):
|
||||||
|
chunk.set_voxel(0, 10, y, 10, VoxelChunk.DEFAULT_CHANNEL_TYPE)
|
||||||
|
|
||||||
|
for y in range(hs, hs * 2):
|
||||||
|
for x in range(hs, hs * 2):
|
||||||
|
for z in range(hs, hs * 2):
|
||||||
|
chunk.set_voxel(0, x, y, z, VoxelChunk.DEFAULT_CHANNEL_TYPE)
|
||||||
|
|
47
game/scripts/dungeons/dungeon.gd
Normal file
47
game/scripts/dungeons/dungeon.gd
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
tool
|
||||||
|
extends Dungeon
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _setup():
|
||||||
|
if data.get_dungeon_start_room_data_count() == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
var drd : DungeonRoomData = data.get_dungeon_start_room_data(0)
|
||||||
|
|
||||||
|
var dung : DungeonRoom
|
||||||
|
if drd.target_script != null:
|
||||||
|
dung = drd.target_script.new()
|
||||||
|
|
||||||
|
if dung == null:
|
||||||
|
print("drd is null. wrong type? " + drd.resource_path)
|
||||||
|
return
|
||||||
|
elif drd.target_class_name != "":
|
||||||
|
if not ClassDB.class_exists(drd.target_class_name):
|
||||||
|
print("class doesnt exists" + drd.resource_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
dung = ClassDB.instance(drd.target_class_name)
|
||||||
|
else:
|
||||||
|
dung = DungeonRoom.new()
|
||||||
|
|
||||||
|
dung.posx = posx
|
||||||
|
dung.posy = posy
|
||||||
|
dung.posz = posz
|
||||||
|
dung.current_seed = current_seed
|
||||||
|
dung.data = drd
|
||||||
|
dung.setup()
|
||||||
|
|
||||||
|
add_dungeon_start_room(dung)
|
||||||
|
|
||||||
|
func _setup_library(library):
|
||||||
|
._setup_library(library)
|
||||||
|
|
||||||
|
for i in range(get_dungeon_start_room_count()):
|
||||||
|
get_dungeon_start_room(i).setup_library(library)
|
||||||
|
|
||||||
|
func _generate_chunk(chunk, spawn_mobs):
|
||||||
|
for i in range(get_dungeon_start_room_count()):
|
||||||
|
get_dungeon_start_room(i).generate_chunk(chunk, spawn_mobs)
|
42
game/scripts/entities/EntityDataGD.gd
Normal file
42
game/scripts/entities/EntityDataGD.gd
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
extends EntityData
|
||||||
|
class_name EntityDataGD
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _sinteract(entity: Entity) -> void:
|
||||||
|
var target : Entity = entity.gets_target()
|
||||||
|
|
||||||
|
if target == null or not is_instance_valid(target):
|
||||||
|
return
|
||||||
|
|
||||||
|
if target.sentity_interaction_type == EntityEnums.ENITIY_INTERACTION_TYPE_LOOT:
|
||||||
|
if target.gets_entity_data().loot_db != null and target.sbag == null:
|
||||||
|
var ldb : LootDataBase = target.gets_entity_data().loot_db
|
||||||
|
|
||||||
|
var loot : Array = Array()
|
||||||
|
|
||||||
|
ldb.get_loot(loot)
|
||||||
|
|
||||||
|
var bag : Bag = Bag.new()
|
||||||
|
bag.set_size(loot.size())
|
||||||
|
|
||||||
|
for item in loot:
|
||||||
|
var it : ItemTemplate = item as ItemTemplate
|
||||||
|
|
||||||
|
bag.add_item(it.create_item_instance())
|
||||||
|
|
||||||
|
target.sbag = bag
|
||||||
|
|
||||||
|
entity.starget_bag = target.sbag
|
||||||
|
|
||||||
|
entity.ssend_open_window(EntityEnums.ENTITY_WINDOW_LOOT)
|
||||||
|
|
||||||
|
func _cans_interact(entity):
|
||||||
|
var target : Entity = entity.gets_target()
|
||||||
|
|
||||||
|
if target == null or not is_instance_valid(target):
|
||||||
|
return false
|
||||||
|
|
||||||
|
return true
|
98
game/scripts/entities/NaturalistGD.gd
Normal file
98
game/scripts/entities/NaturalistGD.gd
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
extends EntityClassData
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
var _data : Dictionary = {
|
||||||
|
"target_aura_spells": {},
|
||||||
|
"spells": []
|
||||||
|
}
|
||||||
|
|
||||||
|
func _init():
|
||||||
|
for i in range(get_num_spells()):
|
||||||
|
var spell : Spell = get_spell(i)
|
||||||
|
|
||||||
|
if spell.get_num_target_aura_applys() > 0:
|
||||||
|
var aura : Aura = spell.get_target_aura_apply(0)
|
||||||
|
|
||||||
|
if not _data["target_aura_spells"].has(aura.aura_group):
|
||||||
|
_data["target_aura_spells"][aura.aura_group] = []
|
||||||
|
|
||||||
|
_data["target_aura_spells"][aura.aura_group].append({ "aura_id": aura.id, "spell_id": spell.id, "rank": spell.rank })
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
_data["spells"].append(spell.id)
|
||||||
|
|
||||||
|
for key in _data["target_aura_spells"]:
|
||||||
|
var arr : Array = _data["target_aura_spells"][key]
|
||||||
|
|
||||||
|
arr.sort_custom(self, "sort_spells_by_rank")
|
||||||
|
|
||||||
|
|
||||||
|
func _sai_attack(entity):
|
||||||
|
var mob : Entity = entity as Entity
|
||||||
|
|
||||||
|
var target : Entity = entity.starget
|
||||||
|
|
||||||
|
if mob != null and target == null:
|
||||||
|
mob.ai_state = EntityEnums.AI_STATE_REGENERATE
|
||||||
|
mob.target_movement_direction = Vector2()
|
||||||
|
return
|
||||||
|
|
||||||
|
var cast : bool = false
|
||||||
|
if not entity.gets_has_global_cooldown():
|
||||||
|
var taspellsdict : Dictionary = _data["target_aura_spells"]
|
||||||
|
|
||||||
|
for taskey in taspellsdict.keys():
|
||||||
|
for tas in taspellsdict[taskey]:
|
||||||
|
var spell_id : int = tas["spell_id"]
|
||||||
|
|
||||||
|
if not entity.hass_spell_id(spell_id):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if taskey == null:
|
||||||
|
if target.sget_aura_by(entity, tas["aura_id"]) == null and not entity.hass_cooldown(spell_id):
|
||||||
|
entity.crequest_spell_cast(spell_id)
|
||||||
|
cast = true
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if target.sget_aura_with_group_by(entity, taskey) == null and not entity.hass_cooldown(spell_id):
|
||||||
|
entity.crequest_spell_cast(spell_id)
|
||||||
|
cast = true
|
||||||
|
break
|
||||||
|
if cast:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not cast:
|
||||||
|
var sps : Array = _data["spells"]
|
||||||
|
|
||||||
|
for spell_id in sps:
|
||||||
|
if not entity.hass_spell_id(spell_id):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not entity.hass_cooldown(spell_id):
|
||||||
|
entity.crequest_spell_cast(spell_id)
|
||||||
|
cast = true
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
if entity.sis_casting():
|
||||||
|
mob.target_movement_direction = Vector2()
|
||||||
|
return
|
||||||
|
|
||||||
|
var dir : Vector3 = target.translation - entity.translation
|
||||||
|
|
||||||
|
mob.target_movement_direction = Vector2(dir.x, dir.z)
|
||||||
|
|
||||||
|
func _setup_resources(entity):
|
||||||
|
var p : EntityResource = ManaResource.new()
|
||||||
|
|
||||||
|
entity.adds_resource(p)
|
||||||
|
|
||||||
|
func sort_spells_by_rank(a, b):
|
||||||
|
if a == null or b == null:
|
||||||
|
return true
|
||||||
|
|
||||||
|
return a["rank"] > b["rank"]
|
13
game/scripts/items/ItemTemplateGD.gd
Normal file
13
game/scripts/items/ItemTemplateGD.gd
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
extends ItemTemplate
|
||||||
|
class_name ItemTemplateGD
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _create_item_instance():
|
||||||
|
var ii : ItemInstance = ItemInstance.new()
|
||||||
|
|
||||||
|
ii.item_template = self
|
||||||
|
|
||||||
|
return ii
|
94
game/scripts/planets/dung_simple_planet.gd
Normal file
94
game/scripts/planets/dung_simple_planet.gd
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
tool
|
||||||
|
extends Planet
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _setup():
|
||||||
|
if data == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
if data.get_biome_data_count() == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
var bdata : BiomeData = data.get_biome_data(0)
|
||||||
|
|
||||||
|
var b : Biome
|
||||||
|
|
||||||
|
if bdata.target_script != null:
|
||||||
|
b = bdata.target_script.new()
|
||||||
|
|
||||||
|
if b == null:
|
||||||
|
print("biome is null. wrong type? " + bdata.resource_path)
|
||||||
|
return
|
||||||
|
elif bdata.target_class_name != "":
|
||||||
|
if not ClassDB.class_exists(bdata.target_class_name):
|
||||||
|
print("class doesnt exists" + bdata.resource_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
b = ClassDB.instance(bdata.target_class_name)
|
||||||
|
else:
|
||||||
|
b = Biome.new()
|
||||||
|
|
||||||
|
b.current_seed = current_seed
|
||||||
|
b.data = bdata
|
||||||
|
b.setup()
|
||||||
|
add_biome(b)
|
||||||
|
|
||||||
|
if bdata.get_dungeon_data_count() == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
var dd : DungeonData = bdata.get_dungeon_data(0)
|
||||||
|
|
||||||
|
var dung : Dungeon
|
||||||
|
if dd.target_script != null:
|
||||||
|
dung = dd.target_script.new()
|
||||||
|
|
||||||
|
if dung == null:
|
||||||
|
print("dd is null. wrong type? " + dd.resource_path)
|
||||||
|
return
|
||||||
|
elif dd.target_class_name != "":
|
||||||
|
if not ClassDB.class_exists(dd.target_class_name):
|
||||||
|
print("class doesnt exists" + dd.resource_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
dung = ClassDB.instance(dd.target_class_name)
|
||||||
|
else:
|
||||||
|
dung = Dungeon.new()
|
||||||
|
|
||||||
|
dung.posx = 0
|
||||||
|
dung.posy = -4
|
||||||
|
dung.posz = 0
|
||||||
|
dung.current_seed = current_seed
|
||||||
|
dung.data = dd
|
||||||
|
dung.setup()
|
||||||
|
|
||||||
|
add_dungeon(dung)
|
||||||
|
|
||||||
|
func _setup_library(library):
|
||||||
|
._setup_library(library)
|
||||||
|
|
||||||
|
for i in range(get_biome_count()):
|
||||||
|
var b : Biome = get_biome(i)
|
||||||
|
|
||||||
|
if b != null:
|
||||||
|
b.setup_library(library)
|
||||||
|
|
||||||
|
for i in range(get_dungeon_count()):
|
||||||
|
var d : Dungeon = get_dungeon(i)
|
||||||
|
|
||||||
|
if d != null:
|
||||||
|
d.setup_library(library)
|
||||||
|
|
||||||
|
func _generate_chunk(chunk, spawn_mobs):
|
||||||
|
if (get_biome_count() == 0):
|
||||||
|
return
|
||||||
|
|
||||||
|
var b : Biome = get_biome(0)
|
||||||
|
|
||||||
|
b.generate_chunk(chunk, spawn_mobs)
|
||||||
|
|
||||||
|
for i in range(get_dungeon_count()):
|
||||||
|
get_dungeon(i).generate_chunk(chunk, spawn_mobs)
|
||||||
|
|
54
game/scripts/planets/simple_planet.gd
Normal file
54
game/scripts/planets/simple_planet.gd
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
tool
|
||||||
|
extends Planet
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _setup():
|
||||||
|
if data == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
if data.get_biome_data_count() == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
var bdata : BiomeData = data.get_biome_data(0)
|
||||||
|
|
||||||
|
var b : Biome
|
||||||
|
|
||||||
|
if bdata.target_script != null:
|
||||||
|
b = bdata.target_script.new()
|
||||||
|
|
||||||
|
if b == null:
|
||||||
|
print("biome is null. wrong type? " + bdata.resource_path)
|
||||||
|
return
|
||||||
|
elif bdata.target_class_name != "":
|
||||||
|
if not ClassDB.class_exists(bdata.target_class_name):
|
||||||
|
print("class doesnt exists" + bdata.resource_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
b = ClassDB.instance(bdata.target_class_name)
|
||||||
|
else:
|
||||||
|
b = Biome.new()
|
||||||
|
|
||||||
|
b.current_seed = current_seed
|
||||||
|
b.data = bdata
|
||||||
|
b.setup()
|
||||||
|
add_biome(b)
|
||||||
|
|
||||||
|
func _setup_library(library):
|
||||||
|
._setup_library(library)
|
||||||
|
|
||||||
|
for i in range(get_biome_count()):
|
||||||
|
var b : Biome = get_biome(i)
|
||||||
|
|
||||||
|
if b != null:
|
||||||
|
b.setup_library(library)
|
||||||
|
|
||||||
|
func _generate_chunk(chunk, spawn_mobs):
|
||||||
|
if (get_biome_count() == 0):
|
||||||
|
return
|
||||||
|
|
||||||
|
var b : Biome = get_biome(0)
|
||||||
|
|
||||||
|
b.generate_chunk(chunk, spawn_mobs)
|
51
game/scripts/projectiles/SpellProjectileGD.gd
Normal file
51
game/scripts/projectiles/SpellProjectileGD.gd
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
extends SpellProjectile
|
||||||
|
class_name SpellProjectileGD
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
var _target : Spatial
|
||||||
|
var _info : SpellCastInfo
|
||||||
|
var _speed : float
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if _info == null:
|
||||||
|
set_process(false)
|
||||||
|
|
||||||
|
func launch(info : SpellCastInfo, effect : PackedScene, speed : float) -> void:
|
||||||
|
if not is_instance_valid(info.target):
|
||||||
|
return
|
||||||
|
|
||||||
|
_info = info
|
||||||
|
_target = info.target.get_character_skeleton().torso_attach_point
|
||||||
|
_speed = speed
|
||||||
|
|
||||||
|
# translation = info.caster.translation
|
||||||
|
translation = info.caster.get_character_skeleton().right_hand_attach_point.global_transform.origin
|
||||||
|
|
||||||
|
var eff : Node = effect.instance()
|
||||||
|
|
||||||
|
eff.owner = self
|
||||||
|
add_child(eff)
|
||||||
|
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
func _process(delta : float) -> void:
|
||||||
|
if not is_instance_valid(_target):
|
||||||
|
# set_process(false)
|
||||||
|
queue_free()
|
||||||
|
return
|
||||||
|
|
||||||
|
var l : Vector3 = _target.global_transform.origin - translation
|
||||||
|
|
||||||
|
if l.length() < 1:
|
||||||
|
_info.spell.son_spell_hit(_info)
|
||||||
|
queue_free()
|
||||||
|
return
|
||||||
|
|
||||||
|
var dir : Vector3 = l.normalized()
|
||||||
|
|
||||||
|
global_transform.origin += dir * _speed * delta
|
||||||
|
global_transform = transform.looking_at(_target.global_transform.origin, Vector3(0, 1, 0))
|
||||||
|
|
14
game/scripts/resources/mana_resource.gd
Normal file
14
game/scripts/resources/mana_resource.gd
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
extends EntityResource
|
||||||
|
class_name ManaResource
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _init():
|
||||||
|
resource_type = EntityEnums.PLAYER_RESOURCE_TYPES_MANA
|
||||||
|
|
||||||
|
# should_process = true
|
||||||
|
|
||||||
|
#func _ons_stat_changed(stat : Stat):
|
||||||
|
# print(stat.get_id())
|
21
game/scripts/resources/spell_effect_visual_basic.gd
Normal file
21
game/scripts/resources/spell_effect_visual_basic.gd
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
extends SpellEffectVisual
|
||||||
|
class_name SpellEffectVisualBasic
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
export (PackedScene) var spell_cast_effect_left_hand : PackedScene
|
||||||
|
export (PackedScene) var spell_cast_effect_right_hand : PackedScene
|
||||||
|
|
||||||
|
export (PackedScene) var torso_aura_effect : PackedScene
|
||||||
|
export (float) var torso_aura_effect_time : float
|
||||||
|
|
||||||
|
export (PackedScene) var root_aura_effect : PackedScene
|
||||||
|
export (float) var root_aura_effect_time : float
|
||||||
|
|
||||||
|
export (PackedScene) var torso_spell_cast_finish_effect : PackedScene
|
||||||
|
export (float) var torso_spell_cast_finish_effect_time : float = 1
|
||||||
|
|
||||||
|
export (PackedScene) var root_spell_cast_finish_effect : PackedScene
|
||||||
|
export (float) var root_spell_cast_finish_effect_time : float = 1
|
17
game/scripts/settings/DirectionalLightSettings.gd
Normal file
17
game/scripts/settings/DirectionalLightSettings.gd
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
extends DirectionalLight
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
# 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
|
21
game/scripts/spells/amplify_pain.gd
Normal file
21
game/scripts/spells/amplify_pain.gd
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
extends SpellGD
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _sfinish_cast(info : SpellCastInfo) -> void:
|
||||||
|
var target : Entity = info.target
|
||||||
|
|
||||||
|
if not is_instance_valid(target):
|
||||||
|
return
|
||||||
|
|
||||||
|
for i in range(target.sget_aura_count()):
|
||||||
|
|
||||||
|
var ad : AuraData = target.sget_aura(i)
|
||||||
|
|
||||||
|
if ad.caster == info.caster:
|
||||||
|
var aura : Aura = ad.aura
|
||||||
|
|
||||||
|
if aura.aura_type & SpellEnums.AURA_TYPE_MAGIC != 0:
|
||||||
|
ad.time_since_last_tick += ad.tick
|
181
game/scripts/spells/gd_spell_script.gd
Normal file
181
game/scripts/spells/gd_spell_script.gd
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
extends Spell
|
||||||
|
class_name SpellGD
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
func _sstart_casting(info : SpellCastInfo) -> void:
|
||||||
|
if info.caster.sis_casting():
|
||||||
|
return
|
||||||
|
|
||||||
|
if info.spell.cooldown_global_cooldown and info.caster.gets_has_global_cooldown() or info.caster.hass_category_cooldown(spell_type) or info.caster.hass_cooldown(id):
|
||||||
|
return
|
||||||
|
|
||||||
|
if !info.caster.hass_spell(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
if cast:
|
||||||
|
info.caster.sstart_casting(info)
|
||||||
|
return
|
||||||
|
|
||||||
|
info.caster.sspell_cast_success(info)
|
||||||
|
|
||||||
|
if info.target:
|
||||||
|
info.target.son_cast_finished_target(info)
|
||||||
|
|
||||||
|
handle_cooldown(info)
|
||||||
|
|
||||||
|
if has_projectile():
|
||||||
|
fire_projectile(info)
|
||||||
|
else:
|
||||||
|
handle_effect(info)
|
||||||
|
|
||||||
|
handle_gcd(info)
|
||||||
|
|
||||||
|
func _sfinish_cast(info : SpellCastInfo) -> void:
|
||||||
|
info.caster.son_cast_finished(info)
|
||||||
|
info.caster.sspell_cast_success(info)
|
||||||
|
|
||||||
|
if is_instance_valid(info.target):
|
||||||
|
info.target.son_cast_finished_target(info)
|
||||||
|
|
||||||
|
if has_projectile():
|
||||||
|
fire_projectile(info)
|
||||||
|
else:
|
||||||
|
handle_effect(info)
|
||||||
|
|
||||||
|
handle_cooldown(info)
|
||||||
|
|
||||||
|
func _son_cast_player_moved(info):
|
||||||
|
if !cast_can_move_while_casting:
|
||||||
|
info.caster.sfail_cast()
|
||||||
|
|
||||||
|
func fire_projectile(info : SpellCastInfo):
|
||||||
|
if projectile_type == SPELL_PROJECTILE_TYPE_FOLLOW:
|
||||||
|
var sp : SpellProjectileGD = SpellProjectileGD.new()
|
||||||
|
|
||||||
|
info.get_caster().get_parent().add_child(sp)
|
||||||
|
sp.owner = info.get_caster().get_parent()
|
||||||
|
|
||||||
|
sp.launch(info, projectile, projectile_speed)
|
||||||
|
|
||||||
|
func _son_spell_hit(info):
|
||||||
|
handle_effect(info)
|
||||||
|
|
||||||
|
func handle_effect(info : SpellCastInfo) -> void:
|
||||||
|
if target_type == SPELL_TARGET_TYPE_TARGET:
|
||||||
|
if info.target == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var ok : bool = false
|
||||||
|
|
||||||
|
# if (target_relation_type & TARGET_SELF):
|
||||||
|
# ok = true
|
||||||
|
|
||||||
|
# if not ok and (target_relation_type & TARGET_ENEMY and info.target is Entity):
|
||||||
|
# ok = true
|
||||||
|
#
|
||||||
|
# if not ok and (target_relation_type & TARGET_FRIENDLY and info.target is Player):
|
||||||
|
# ok = true
|
||||||
|
|
||||||
|
# if not ok:
|
||||||
|
# return
|
||||||
|
|
||||||
|
elif target_type == SPELL_TARGET_TYPE_SELF:
|
||||||
|
info.target = info.caster
|
||||||
|
|
||||||
|
if damage and info.target:
|
||||||
|
var sdi : SpellDamageInfo = SpellDamageInfo.new()
|
||||||
|
|
||||||
|
sdi.damage_source = self
|
||||||
|
sdi.dealer = info.caster
|
||||||
|
sdi.receiver = info.target
|
||||||
|
|
||||||
|
handle_spell_damage(sdi)
|
||||||
|
|
||||||
|
for aura in caster_aura_applys:
|
||||||
|
var ainfo : AuraApplyInfo = AuraApplyInfo.new()
|
||||||
|
|
||||||
|
ainfo.caster = info.caster
|
||||||
|
ainfo.target = info.caster
|
||||||
|
ainfo.spell_scale = 1
|
||||||
|
ainfo.aura = aura
|
||||||
|
|
||||||
|
aura.sapply(ainfo)
|
||||||
|
|
||||||
|
if info.target != null:
|
||||||
|
for aura in target_aura_applys:
|
||||||
|
var ad : AuraData = null
|
||||||
|
|
||||||
|
if aura.aura_group != null:
|
||||||
|
ad = info.target.sget_aura_with_group_by(info.caster, aura.aura_group)
|
||||||
|
else:
|
||||||
|
ad = info.target.sget_aura_by(info.caster, aura.get_id())
|
||||||
|
|
||||||
|
if ad != null:
|
||||||
|
info.target.sremove_aura_exact(ad)
|
||||||
|
|
||||||
|
var ainfo : AuraApplyInfo = AuraApplyInfo.new()
|
||||||
|
|
||||||
|
ainfo.caster = info.caster
|
||||||
|
ainfo.target = info.target
|
||||||
|
ainfo.spell_scale = 1
|
||||||
|
ainfo.aura = aura
|
||||||
|
|
||||||
|
aura.sapply(ainfo)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func handle_cooldown(info : SpellCastInfo) -> void:
|
||||||
|
if cooldown_cooldown > 0:
|
||||||
|
info.caster.adds_cooldown(id, cooldown_cooldown)
|
||||||
|
|
||||||
|
func handle_gcd(info : SpellCastInfo) -> void:
|
||||||
|
if cooldown_global_cooldown and cast_cast_time < 0.01:
|
||||||
|
info.caster.sstart_global_cooldown(info.caster.get_gcd().scurrent)
|
||||||
|
|
||||||
|
func add_spell_cast_effect(info : SpellCastInfo) -> void:
|
||||||
|
var basic_spell_effect : SpellEffectVisualBasic = visual_spell_effects as SpellEffectVisualBasic
|
||||||
|
|
||||||
|
if basic_spell_effect != null:
|
||||||
|
if basic_spell_effect.spell_cast_effect_left_hand != null:
|
||||||
|
info.caster.get_character_skeleton().left_hand_attach_point.add_effect(basic_spell_effect.spell_cast_effect_left_hand)
|
||||||
|
|
||||||
|
if basic_spell_effect.spell_cast_effect_right_hand != null:
|
||||||
|
info.caster.get_character_skeleton().right_hand_attach_point.add_effect(basic_spell_effect.spell_cast_effect_right_hand)
|
||||||
|
|
||||||
|
func remove_spell_cast_effect(info : SpellCastInfo) -> void:
|
||||||
|
var basic_spell_effect : SpellEffectVisualBasic = visual_spell_effects as SpellEffectVisualBasic
|
||||||
|
|
||||||
|
if basic_spell_effect != null:
|
||||||
|
if basic_spell_effect.spell_cast_effect_left_hand != null:
|
||||||
|
info.caster.get_character_skeleton().left_hand_attach_point.remove_effect(basic_spell_effect.spell_cast_effect_left_hand)
|
||||||
|
|
||||||
|
if basic_spell_effect.spell_cast_effect_right_hand != null:
|
||||||
|
info.caster.get_character_skeleton().right_hand_attach_point.remove_effect(basic_spell_effect.spell_cast_effect_right_hand)
|
||||||
|
|
||||||
|
func _con_spell_cast_started(info):
|
||||||
|
add_spell_cast_effect(info)
|
||||||
|
|
||||||
|
func _con_spell_cast_failed(info):
|
||||||
|
remove_spell_cast_effect(info)
|
||||||
|
|
||||||
|
func _con_spell_cast_interrupted(info):
|
||||||
|
remove_spell_cast_effect(info)
|
||||||
|
|
||||||
|
func _con_spell_cast_success(info):
|
||||||
|
remove_spell_cast_effect(info)
|
||||||
|
|
||||||
|
if not is_instance_valid(info.target):
|
||||||
|
return
|
||||||
|
|
||||||
|
var bse : SpellEffectVisualBasic = visual_spell_effects as SpellEffectVisualBasic
|
||||||
|
|
||||||
|
if bse != null:
|
||||||
|
if bse.torso_spell_cast_finish_effect != null:
|
||||||
|
info.target.get_character_skeleton().torso_attach_point.add_effect_timed(bse.torso_spell_cast_finish_effect, bse.torso_spell_cast_finish_effect_time)
|
||||||
|
|
||||||
|
if bse.root_spell_cast_finish_effect != null:
|
||||||
|
info.target.get_character_skeleton().root_attach_point.add_effect_timed(bse.root_spell_cast_finish_effect, bse.root_spell_cast_finish_effect_time)
|
||||||
|
|
82
game/scripts/world_generators/MainPlanetGenerator.gd
Normal file
82
game/scripts/world_generators/MainPlanetGenerator.gd
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
tool
|
||||||
|
extends VoxelmanLevelGenerator
|
||||||
|
class_name MainPlanetGenerator
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
const planet_folder : String = "res://data/planets/"
|
||||||
|
|
||||||
|
export(int) var _force_planet : int = -1
|
||||||
|
export(int) var _level_seed : int
|
||||||
|
export(bool) var _spawn_mobs : bool
|
||||||
|
|
||||||
|
var _world : VoxelWorld
|
||||||
|
var _planet : Planet
|
||||||
|
var _library : VoxelmanLibrary
|
||||||
|
|
||||||
|
func setup(world : VoxelWorld, level_seed : int, spawn_mobs : bool, library: VoxelmanLibrary) -> void:
|
||||||
|
_level_seed = level_seed
|
||||||
|
_world = world
|
||||||
|
_spawn_mobs = spawn_mobs
|
||||||
|
_library = library
|
||||||
|
|
||||||
|
create_planet()
|
||||||
|
|
||||||
|
func _generate_chunk(chunk : VoxelChunk) -> void:
|
||||||
|
if _planet == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
_planet.generate_chunk(chunk, _spawn_mobs)
|
||||||
|
|
||||||
|
func create_planet():
|
||||||
|
var planet_files : Array
|
||||||
|
|
||||||
|
var dir = Directory.new()
|
||||||
|
if dir.open(planet_folder) == OK:
|
||||||
|
dir.list_dir_begin()
|
||||||
|
var file_name = dir.get_next()
|
||||||
|
while (file_name != ""):
|
||||||
|
if not dir.current_is_dir():
|
||||||
|
planet_files.append(file_name)
|
||||||
|
|
||||||
|
file_name = dir.get_next()
|
||||||
|
|
||||||
|
if planet_files.size() == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
var ind : int
|
||||||
|
if _force_planet == -1:
|
||||||
|
seed(_level_seed)
|
||||||
|
ind = randi() % planet_files.size()
|
||||||
|
else:
|
||||||
|
ind = _force_planet
|
||||||
|
|
||||||
|
var planet_data : PlanetData = ResourceLoader.load(planet_folder + planet_files[ind], "PlanetData")
|
||||||
|
|
||||||
|
if planet_data == null:
|
||||||
|
print("planet_data is null!")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("planet loaded: " + planet_data.resource_path)
|
||||||
|
|
||||||
|
if planet_data.target_script != null:
|
||||||
|
_planet = planet_data.target_script.new()
|
||||||
|
|
||||||
|
if _planet == null:
|
||||||
|
print("_planet is null. wrong type? " + planet_data.resource_path)
|
||||||
|
return
|
||||||
|
elif planet_data.target_class_name != "":
|
||||||
|
if not ClassDB.class_exists(planet_data.target_class_name):
|
||||||
|
print("class doesnt exists" + planet_data.resource_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
_planet = ClassDB.instance(planet_data.target_class_name)
|
||||||
|
else:
|
||||||
|
_planet = Planet.new()
|
||||||
|
|
||||||
|
_planet.current_seed = _level_seed
|
||||||
|
_planet.data = planet_data
|
||||||
|
_planet.setup()
|
||||||
|
_planet.setup_library(_library)
|
Loading…
Reference in New Issue
Block a user