Showing preview only (6,198K chars total). Download the full file or copy to clipboard to get everything.
Repository: Praytic/youtd2
Branch: main
Commit: 5471b4b472e7
Files: 3046
Total size: 5.3 MB
Directory structure:
gitextract_l9w5256r/
├── .github/
│ ├── CODEOWNERS
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── RCLONE.md
│ ├── TRANSLATING.md
│ └── workflows/
│ └── github-actions-youtd.yml
├── .gitignore
├── LICENSE
├── README.md
├── addons/
│ ├── com.heroiclabs.nakama/
│ │ ├── Nakama.gd
│ │ ├── Satori/
│ │ │ ├── NakamaEvent.gd
│ │ │ ├── SatoriAPI.gd
│ │ │ ├── SatoriClient.gd
│ │ │ ├── SatoriHttpAdapter.gd
│ │ │ ├── SatoriSession.gd
│ │ │ └── utils/
│ │ │ ├── SatoriAsyncResult.gd
│ │ │ ├── SatoriException.gd
│ │ │ ├── SatoriLogger.gd
│ │ │ └── SatoriSerializer.gd
│ │ ├── Satori.gd
│ │ ├── api/
│ │ │ ├── NakamaAPI.gd
│ │ │ ├── NakamaRTAPI.gd
│ │ │ ├── NakamaRTMessage.gd
│ │ │ ├── NakamaSession.gd
│ │ │ ├── NakamaStorageObjectId.gd
│ │ │ └── NakamaWriteStorageObject.gd
│ │ ├── client/
│ │ │ ├── NakamaClient.gd
│ │ │ └── NakamaHTTPAdapter.gd
│ │ ├── dotnet-utils/
│ │ │ ├── GodotHttpAdapter.cs
│ │ │ ├── GodotLogger.cs
│ │ │ └── GodotWebSocketAdapter.cs
│ │ ├── socket/
│ │ │ ├── NakamaSocket.gd
│ │ │ └── NakamaSocketAdapter.gd
│ │ └── utils/
│ │ ├── NakamaAsyncResult.gd
│ │ ├── NakamaException.gd
│ │ ├── NakamaLogger.gd
│ │ ├── NakamaMultiplayerBridge.gd
│ │ ├── NakamaMultiplayerPeer.gd
│ │ └── NakamaSerializer.gd
│ └── nakama-webrtc/
│ ├── LICENSE.txt
│ └── OnlineMatch.gd
├── assets/
│ ├── LICENSE.md
│ ├── README.md
│ ├── creeps/
│ │ ├── README.md
│ │ └── orc/
│ │ ├── air/
│ │ │ ├── fly_E.png.import
│ │ │ ├── fly_N.png.import
│ │ │ ├── fly_NE.png.import
│ │ │ ├── fly_NW.png.import
│ │ │ ├── fly_S.png.import
│ │ │ ├── fly_SE.png.import
│ │ │ ├── fly_SW.png.import
│ │ │ ├── fly_W.png.import
│ │ │ ├── metadata.csv
│ │ │ └── metadata.csv.import
│ │ ├── boss/
│ │ │ ├── death_E.png.import
│ │ │ ├── death_N.png.import
│ │ │ ├── death_S.png.import
│ │ │ ├── death_W.png.import
│ │ │ ├── metadata.csv
│ │ │ ├── metadata.csv.import
│ │ │ ├── slow_run_E.png.import
│ │ │ ├── slow_run_N.png.import
│ │ │ ├── slow_run_S.png.import
│ │ │ └── slow_run_W.png.import
│ │ ├── champion/
│ │ │ ├── death_E.png.import
│ │ │ ├── death_N.png.import
│ │ │ ├── death_S.png.import
│ │ │ ├── death_W.png.import
│ │ │ ├── metadata.csv
│ │ │ ├── metadata.csv.import
│ │ │ ├── slow_run_E.png.import
│ │ │ ├── slow_run_N.png.import
│ │ │ ├── slow_run_S.png.import
│ │ │ └── slow_run_W.png.import
│ │ ├── mass/
│ │ │ ├── death_E.png.import
│ │ │ ├── death_N.png.import
│ │ │ ├── death_S.png.import
│ │ │ ├── death_W.png.import
│ │ │ ├── metadata.csv
│ │ │ ├── metadata.csv.import
│ │ │ ├── slow_run_E.png.import
│ │ │ ├── slow_run_N.png.import
│ │ │ ├── slow_run_S.png.import
│ │ │ └── slow_run_W.png.import
│ │ └── normal/
│ │ ├── death_E.png.import
│ │ ├── death_N.png.import
│ │ ├── death_S.png.import
│ │ ├── death_W.png.import
│ │ ├── metadata.csv
│ │ ├── metadata.csv.import
│ │ ├── slow_run_E.png.import
│ │ ├── slow_run_N.png.import
│ │ ├── slow_run_S.png.import
│ │ └── slow_run_W.png.import
│ ├── effects/
│ │ ├── arrow.png.import
│ │ ├── bdragon/
│ │ │ ├── README.md
│ │ │ ├── ancient_protector_missile_293.png.import
│ │ │ ├── animated_dead_target_102.png.import
│ │ │ ├── apply_potion_537.png.import
│ │ │ ├── arcane_tower_attack_024.png.import
│ │ │ ├── avatar_caster_10.png.import
│ │ │ ├── banshee_missile_487.png.import
│ │ │ ├── blink_target_720.png.import
│ │ │ ├── blood_splatter_376.png.import
│ │ │ ├── build_tower_648.png.import
│ │ │ ├── charm_target_703.png.import
│ │ │ ├── cloud_of_fog_382.png.import
│ │ │ ├── cloud_of_fog_small_428.png.import
│ │ │ ├── cripple_target_198.png.import
│ │ │ ├── crushing_wave_damage_584.png.import
│ │ │ ├── crypt_fiend_eggsack_528.png.import
│ │ │ ├── cyclone_target_269.png.import
│ │ │ ├── death_and_decay_71.png.import
│ │ │ ├── death_coil_special_728.png.import
│ │ │ ├── devour_509.png.import
│ │ │ ├── dispel_magic_target_456.png.import
│ │ │ ├── doom_death_451.png.import
│ │ │ ├── faerie_dragon_missile_482.png.import
│ │ │ ├── firelord_death_explode_77.png.import
│ │ │ ├── flame_strike_embers_702.png.import
│ │ │ ├── flower_aura_655.png.import
│ │ │ ├── frag_boom_spawn_426.png.import
│ │ │ ├── freezing_breath_519.png.import
│ │ │ ├── frost_armor_damage_474.png.import
│ │ │ ├── frost_bolt_missile_063.png.import
│ │ │ ├── glaive_746.png.import
│ │ │ ├── gold_credit_673.png.import
│ │ │ ├── gold_credit_88.png.import
│ │ │ ├── healing_wave_target_453.png.import
│ │ │ ├── holy_bolt_241.png.import
│ │ │ ├── immolation_damage_541.png.import
│ │ │ ├── impale_hit_target_529.png.import
│ │ │ ├── impale_target_dust_025.png.import
│ │ │ ├── incinerate_76.png.import
│ │ │ ├── keeper_grove_missile_297.png.import
│ │ │ ├── level_up_455.png.import
│ │ │ ├── mana_burn_target_388.png.import
│ │ │ ├── mana_shield_026.png.import
│ │ │ ├── mass_teleport_caster_335.png.import
│ │ │ ├── mass_teleport_target_315.png.import
│ │ │ ├── mirror_image_caster_711.png.import
│ │ │ ├── moonwell_target_584.png.import
│ │ │ ├── ne_cancel_death_672.png.import
│ │ │ ├── ne_death_612.png.import
│ │ │ ├── placeholder_481.png.import
│ │ │ ├── polymorph_target_735.png.import
│ │ │ ├── projectile_explosion_299.png.import
│ │ │ ├── purge_buff_target_195.png.import
│ │ │ ├── quillspray_747.png.import
│ │ │ ├── raise_skeleton_624.png.import
│ │ │ ├── replenish_mana_334.png.import
│ │ │ ├── revive_human_623.png.import
│ │ │ ├── roar_506.png.import
│ │ │ ├── roots_235.png.import
│ │ │ ├── shackle_439.png.import
│ │ │ ├── shockwave_missile_440.png.import
│ │ │ ├── silence_area_611.png.import
│ │ │ ├── small_flame_spawn_240.png.import
│ │ │ ├── spell_aiil_452.png.import
│ │ │ ├── spell_ailb_723.png.import
│ │ │ ├── spell_aima_194.png.import
│ │ │ ├── spell_aire_174.png.import
│ │ │ ├── spell_aiso_295.png.import
│ │ │ ├── spell_alim_136.png.import
│ │ │ ├── spell_breaker_target_613.png.import
│ │ │ ├── spirit_link_target_175.png.import
│ │ │ ├── stampede_missile_death_63.png.import
│ │ │ ├── starfall_target_257.png.import
│ │ │ ├── thunder_clap_466.png.import
│ │ │ ├── undead_dissipate_633.png.import
│ │ │ ├── upgrade_tower_016.png.import
│ │ │ ├── vampiric_aura_199.png.import
│ │ │ ├── voodoo_aura_182.png.import
│ │ │ ├── warstomp_caster_536.png.import
│ │ │ ├── wind_shear_559.png.import
│ │ │ ├── wisp_explode_003.png.import
│ │ │ ├── ziggurat_frost_missile_325.png.import
│ │ │ └── zombify_target_274.png.import
│ │ ├── death_explode.png.import
│ │ ├── lightning_long.png.import
│ │ └── stun.png.import
│ ├── fonts/
│ │ ├── Friz Quadrata Std Medium.otf.import
│ │ └── NotoSansSC-Medium.ttf.import
│ ├── hud/
│ │ ├── bitmaps/
│ │ │ ├── circle_bitmap_100x100.png.import
│ │ │ └── circle_bitmap_256x256.png.import
│ │ ├── checkbox.png.import
│ │ ├── circle_bitmap_256x256.png.import
│ │ ├── darkness_face.png.import
│ │ ├── element_progress_circle.png.import
│ │ ├── horadric_cube.png.import
│ │ ├── hud_atlas.png.import
│ │ ├── misc2.png.import
│ │ ├── misc3.png.import
│ │ ├── misc3_s.png.import
│ │ ├── misc4.png.import
│ │ └── tranquility_face.png.import
│ ├── icons/
│ │ ├── amulets.png.import
│ │ ├── animals.png.import
│ │ ├── armor.png.import
│ │ ├── blunt_weapons.png.import
│ │ ├── books.png.import
│ │ ├── bows.png.import
│ │ ├── cannons.png.import
│ │ ├── clubs.png.import
│ │ ├── creep_icons_atlas.png.import
│ │ ├── daggers.png.import
│ │ ├── dioramas.png.import
│ │ ├── electricity.png.import
│ │ ├── elements.png.import
│ │ ├── faces.png.import
│ │ ├── fire.png.import
│ │ ├── food.png.import
│ │ ├── furniture.png.import
│ │ ├── gems.png.import
│ │ ├── generic_icons.png.import
│ │ ├── gloves.png.import
│ │ ├── helmets.png.import
│ │ ├── holy.png.import
│ │ ├── hud.png.import
│ │ ├── magic.png.import
│ │ ├── masks.png.import
│ │ ├── mechanical.png.import
│ │ ├── misc.png.import
│ │ ├── orbs.png.import
│ │ ├── plants.png.import
│ │ ├── potion_icons_m.png.import
│ │ ├── rings.png.import
│ │ ├── rockets.png.import
│ │ ├── scrolls.png.import
│ │ ├── shields.png.import
│ │ ├── spears.png.import
│ │ ├── statues.png.import
│ │ ├── staves.png.import
│ │ ├── swords.png.import
│ │ ├── tier_icons_m.png.import
│ │ ├── tower_icons_m.png.import
│ │ ├── tower_variations.png.import
│ │ ├── trinkets.png.import
│ │ ├── undead.png.import
│ │ └── weapons_misc.png.import
│ ├── misc/
│ │ ├── autocast_automode_particle.png.import
│ │ ├── cast_cursor.png.import
│ │ ├── circle_01.png.import
│ │ ├── circle_02.png.import
│ │ ├── circle_03.png.import
│ │ ├── circle_04.png.import
│ │ ├── circle_05.png.import
│ │ ├── creep_blood_pool.png.import
│ │ ├── icob_min.png.import
│ │ ├── icob_ultra_wide.png.import
│ │ ├── icon.png.import
│ │ ├── potion_drop_animation.png.import
│ │ └── projectile.png.import
│ ├── secrets/
│ │ ├── badwords.csv.import
│ │ └── secrets.csv.import
│ ├── sfx/
│ │ ├── 161654__qubodup__war-game-battle-level-up-remix.ogg.import
│ │ ├── 202147__qubodup__enchant.ogg.import
│ │ ├── 411177__silverillusionist__pick-up-item-1-short.ogg.import
│ │ ├── 420676__sypherzent__spell-cast-buff-high-tone.ogg.import
│ │ ├── 442827__qubodup__fireball.ogg.import
│ │ ├── 442903__qubodup__slash-remix.ogg.import
│ │ ├── 541478__eminyildirim__magic-fire-spell-impact-punch.ogg.import
│ │ ├── 562292__colorscrimsontears__heal-rpg.ogg.import
│ │ ├── 649359__sonofxaudio__sword_water01.ogg.import
│ │ ├── 665082__sunflora__thud.ogg.import
│ │ ├── 682635__bastianhallo__magic-spell.ogg.import
│ │ ├── 683044__brettrader__stomp-soft.ogg.import
│ │ ├── 714258__qubodup__cloud-poof.ogg.import
│ │ ├── 734247__noisyredfox__coins3.ogg.import
│ │ ├── 738438__qubodup__orc-grunt-2.ogg.import
│ │ ├── 745156__tigreplayz__blast-explosion.ogg.import
│ │ ├── DoKashiteru_healspell1.ogg.import
│ │ ├── DoKashiteru_healspell2.ogg.import
│ │ ├── DoKashiteru_healspell3.ogg.import
│ │ ├── README.md
│ │ ├── UI_Electric_01.ogg.import
│ │ ├── artisticdude_freeze.ogg.import
│ │ ├── attribution.csv
│ │ ├── attribution.csv.import
│ │ ├── bart_foom_0.ogg.import
│ │ ├── copyc4t_Archers-shooting.ogg.import
│ │ ├── kevl_level_up.ogg.import
│ │ ├── little_robot_Spell_00.ogg.import
│ │ ├── little_robot_Spell_01.ogg.import
│ │ ├── little_robot_UI_Electric_00.ogg.import
│ │ ├── little_robot_UI_Electric_01.ogg.import
│ │ ├── little_robot_Whoosh_Electric_00.ogg.import
│ │ ├── little_robot_Whoosh_Electric_01.ogg.import
│ │ ├── little_robot_Whoosh_Electric_02.ogg.import
│ │ ├── little_robot_Whoosh_Electric_03.ogg.import
│ │ ├── machel_baradari_jump.wav.import
│ │ ├── michel_baradari_jump.ogg.import
│ │ ├── michel_baradari_jump.wav.import
│ │ ├── michel_baradari_lava.ogg.import
│ │ ├── michel_baradari_teleport.ogg.import
│ │ ├── p0ss_confusion.ogg.import
│ │ ├── p0ss_curse5.ogg.import
│ │ ├── p0ss_enchant.ogg.import
│ │ ├── p0ss_enchant2.ogg.import
│ │ ├── p0ss_explode2.ogg.import
│ │ ├── p0ss_explode4.ogg.import
│ │ ├── p0ss_freeze2.ogg.import
│ │ ├── p0ss_heal.ogg.import
│ │ ├── p0ss_pestilence.ogg.import
│ │ ├── p0ss_sand.ogg.import
│ │ ├── p0ss_shot.ogg.import
│ │ ├── p0ss_spell.ogg.import
│ │ ├── p0ss_steam.ogg.import
│ │ ├── p0ss_teleport.ogg.import
│ │ ├── p0ss_warp.ogg.import
│ │ ├── p0ss_warp2.ogg.import
│ │ ├── p0ss_warp3.ogg.import
│ │ ├── p0ss_water.ogg.import
│ │ ├── p0ss_zap.ogg.import
│ │ ├── p0ss_zap10.ogg.import
│ │ ├── p0ss_zap5a.ogg.import
│ │ ├── spit_01.ogg.import
│ │ ├── unknown_attack_sound1.ogg.import
│ │ ├── unknown_fire_attack1.ogg.import
│ │ ├── unknown_iceball.ogg.import
│ │ ├── unknown_iron_attack1.ogg.import
│ │ ├── unknown_swosh-08.ogg.import
│ │ └── unknown_swosh-11.ogg.import
│ ├── texts/
│ │ ├── README.md
│ │ ├── texts.csv.import
│ │ ├── texts_history.csv
│ │ └── texts_history.csv.import
│ ├── tiles/
│ │ ├── License.txt
│ │ ├── README.md
│ │ ├── barrels.png.import
│ │ ├── bridges.png.import
│ │ ├── chairs.png.import
│ │ ├── chests.png.import
│ │ ├── empty_tiles.png.import
│ │ ├── floor.png.import
│ │ ├── floor1_walls.png.import
│ │ ├── planks.png.import
│ │ ├── spiral_stairs.png.import
│ │ ├── stairs.png.import
│ │ ├── stone_columns.png.import
│ │ ├── stone_walls.png.import
│ │ ├── tables.png.import
│ │ ├── wooden_pile.png.import
│ │ └── wooden_supports.png.import
│ ├── tiles_decoration/
│ │ ├── bushes1.png.import
│ │ ├── column_overgrown.png.import
│ │ ├── leaves1.png.import
│ │ ├── stones1.png.import
│ │ ├── stones2.png.import
│ │ ├── stones3.png.import
│ │ ├── trees1.png.import
│ │ ├── trees2.png.import
│ │ ├── vines1.png.import
│ │ ├── vines2.png.import
│ │ ├── vines3.png.import
│ │ ├── vines4.png.import
│ │ ├── vines5.png.import
│ │ ├── vines6.png.import
│ │ ├── vines7.png.import
│ │ └── wall_vines1.png.import
│ ├── tower_sprites/
│ │ ├── astral_common.png.import
│ │ ├── astral_rare.png.import
│ │ ├── astral_uncommon.png.import
│ │ ├── astral_unique.png.import
│ │ ├── darkness_common.png.import
│ │ ├── darkness_rare.png.import
│ │ ├── darkness_uncommon.png.import
│ │ ├── darkness_unique.png.import
│ │ ├── fire_common.png.import
│ │ ├── fire_rare.png.import
│ │ ├── fire_uncommon.png.import
│ │ ├── fire_unique.png.import
│ │ ├── ice_common.png.import
│ │ ├── ice_rare.png.import
│ │ ├── ice_uncommon.png.import
│ │ ├── ice_unique.png.import
│ │ ├── iron_common.png.import
│ │ ├── iron_rare.png.import
│ │ ├── iron_uncommon.png.import
│ │ ├── iron_unique.png.import
│ │ ├── nature_common.png.import
│ │ ├── nature_rare.png.import
│ │ ├── nature_uncommon.png.import
│ │ ├── nature_unique.png.import
│ │ ├── storm_common.png.import
│ │ ├── storm_rare.png.import
│ │ ├── storm_uncommon.png.import
│ │ └── storm_unique.png.import
│ └── tutorial_pictures/
│ ├── README.md
│ ├── build_tower.png.import
│ ├── item_drop.png.import
│ ├── research.png.import
│ ├── research_element.png.import
│ ├── resource_panel.png.import
│ ├── roll_towers.png.import
│ ├── tower_info.png.import
│ ├── tower_level.png.import
│ ├── tower_mouse_over.png.import
│ ├── tower_stash.png.import
│ ├── transform.png.import
│ ├── upgrade.png.import
│ └── wave_finish.png.import
├── build/
│ ├── README.md
│ ├── linux/
│ │ └── README.md
│ ├── macos/
│ │ └── README.md
│ ├── web/
│ │ └── full-size.html
│ └── windows/
│ └── README.md
├── data/
│ ├── README.md
│ ├── ability_properties.csv
│ ├── ability_properties.csv.import
│ ├── aura_properties.csv
│ ├── aura_properties.csv.import
│ ├── autocast_properties.csv
│ ├── autocast_properties.csv.import
│ ├── builder_properties.csv
│ ├── builder_properties.csv.import
│ ├── exp_for_level.csv
│ ├── exp_for_level.csv.import
│ ├── hints/
│ │ ├── advanced.csv
│ │ ├── advanced.csv.import
│ │ ├── basic.csv.import
│ │ ├── basics.csv
│ │ ├── basics.csv.import
│ │ ├── chat_commands.csv
│ │ ├── chat_commands.csv.import
│ │ ├── creep_specials.csv
│ │ ├── creep_specials.csv.import
│ │ ├── creeps.csv
│ │ ├── creeps.csv.import
│ │ ├── items.csv
│ │ ├── items.csv.import
│ │ ├── towers.csv
│ │ ├── towers.csv.import
│ │ ├── tutorial.csv
│ │ └── tutorial.csv.import
│ ├── item_properties.csv
│ ├── item_properties.csv.import
│ ├── mission_properties.csv
│ ├── mission_properties.csv.import
│ ├── player_exp_for_level.csv
│ ├── player_exp_for_level.csv.import
│ ├── recipe_properties.csv
│ ├── recipe_properties.csv.import
│ ├── tower_properties.csv
│ ├── tower_properties.csv.import
│ ├── wave_special_properties.csv
│ ├── wave_special_properties.csv.import
│ ├── wisdom_upgrades.csv
│ └── wisdom_upgrades.csv.import
├── export_presets.cfg
├── project.godot
├── rclone-filter
├── resources/
│ ├── README.md
│ ├── button_groups/
│ │ ├── element_filter_button_group.tres
│ │ ├── interface_size_setting_button_group.tres
│ │ ├── item_type_filter_button_group.tres
│ │ ├── menu_cards_button_group.tres
│ │ ├── right_panel_button_group.tres
│ │ └── speed_button_group.tres
│ ├── icons/
│ │ ├── amulets/
│ │ │ ├── amulet_01.tres
│ │ │ ├── amulet_02.tres
│ │ │ ├── amulet_03.tres
│ │ │ └── amulet_04.tres
│ │ ├── animals/
│ │ │ ├── bat_01.tres
│ │ │ ├── bat_02.tres
│ │ │ ├── bat_03.tres
│ │ │ ├── cow.tres
│ │ │ ├── dragon_01.tres
│ │ │ ├── dragon_02.tres
│ │ │ ├── dragon_03.tres
│ │ │ ├── dragon_04.tres
│ │ │ ├── dragon_05.tres
│ │ │ ├── fish_01.tres
│ │ │ ├── fish_02.tres
│ │ │ ├── fish_03.tres
│ │ │ ├── fish_04.tres
│ │ │ ├── mech_toad.tres
│ │ │ ├── piglet_warrior.tres
│ │ │ ├── rabbit.tres
│ │ │ ├── rooster_warrior.tres
│ │ │ ├── spider_01.tres
│ │ │ ├── spider_02.tres
│ │ │ ├── spider_03.tres
│ │ │ └── wing.tres
│ │ ├── armor/
│ │ │ ├── chest_plate.tres
│ │ │ ├── chest_plate_with_spike.tres
│ │ │ ├── coat.tres
│ │ │ ├── lightning_boot.tres
│ │ │ ├── vest_01.tres
│ │ │ ├── vest_02.tres
│ │ │ ├── vest_03.tres
│ │ │ └── vest_04.tres
│ │ ├── blunt_weapons/
│ │ │ ├── hammer_01.tres
│ │ │ ├── hammer_02.tres
│ │ │ ├── hammer_03.tres
│ │ │ ├── hammer_04.tres
│ │ │ ├── wood_01.tres
│ │ │ ├── wood_02.tres
│ │ │ ├── wood_03.tres
│ │ │ └── wood_04.tres
│ │ ├── books/
│ │ │ ├── book_01.tres
│ │ │ ├── book_02.tres
│ │ │ ├── book_03.tres
│ │ │ ├── book_04.tres
│ │ │ ├── book_05.tres
│ │ │ ├── book_06.tres
│ │ │ ├── book_07.tres
│ │ │ ├── book_08.tres
│ │ │ ├── book_09.tres
│ │ │ ├── book_10.tres
│ │ │ ├── book_11.tres
│ │ │ ├── note_01.tres
│ │ │ ├── note_02.tres
│ │ │ ├── note_03.tres
│ │ │ └── note_04.tres
│ │ ├── bows/
│ │ │ ├── arrow_01.tres
│ │ │ ├── arrow_02.tres
│ │ │ ├── bow_01.tres
│ │ │ ├── bow_02.tres
│ │ │ ├── bow_03.tres
│ │ │ ├── bow_04.tres
│ │ │ ├── bow_05.tres
│ │ │ └── bow_06.tres
│ │ ├── cannons/
│ │ │ ├── cannon_01.tres
│ │ │ ├── cannon_02.tres
│ │ │ ├── cannon_03.tres
│ │ │ ├── cannon_04.tres
│ │ │ ├── cannon_05.tres
│ │ │ ├── cannon_06.tres
│ │ │ ├── cannon_07.tres
│ │ │ ├── cannon_08.tres
│ │ │ ├── gun_01.tres
│ │ │ └── gun_02.tres
│ │ ├── clubs/
│ │ │ ├── club_01.tres
│ │ │ ├── club_02.tres
│ │ │ ├── club_03.tres
│ │ │ ├── club_04.tres
│ │ │ ├── club_04_without_handle.tres
│ │ │ └── club_glowing.tres
│ │ ├── creep_icons/
│ │ │ ├── challenge_challenge_boss.tres
│ │ │ ├── challenge_challenge_mass.tres
│ │ │ ├── humanoid_air.tres
│ │ │ ├── humanoid_boss.tres
│ │ │ ├── humanoid_champion.tres
│ │ │ ├── humanoid_mass.tres
│ │ │ ├── humanoid_normal.tres
│ │ │ ├── magic_air.tres
│ │ │ ├── magic_boss.tres
│ │ │ ├── magic_champion.tres
│ │ │ ├── magic_mass.tres
│ │ │ ├── magic_normal.tres
│ │ │ ├── nature_air.tres
│ │ │ ├── nature_boss.tres
│ │ │ ├── nature_champion.tres
│ │ │ ├── nature_mass.tres
│ │ │ ├── nature_normal.tres
│ │ │ ├── orc_air.tres
│ │ │ ├── orc_boss.tres
│ │ │ ├── orc_champion.tres
│ │ │ ├── orc_mass.tres
│ │ │ ├── orc_normal.tres
│ │ │ ├── undead_air.tres
│ │ │ ├── undead_boss.tres
│ │ │ ├── undead_champion.tres
│ │ │ ├── undead_mass.tres
│ │ │ └── undead_normal.tres
│ │ ├── daggers/
│ │ │ ├── dagger_01.tres
│ │ │ ├── dagger_02.tres
│ │ │ ├── dagger_03.tres
│ │ │ ├── dagger_04.tres
│ │ │ ├── dagger_05.tres
│ │ │ ├── dagger_06.tres
│ │ │ ├── dagger_07.tres
│ │ │ ├── dagger_08.tres
│ │ │ └── dagger_09.tres
│ │ ├── dioramas/
│ │ │ ├── book_display.tres
│ │ │ ├── church.tres
│ │ │ ├── fountain.tres
│ │ │ ├── mountain.tres
│ │ │ └── pyramid.tres
│ │ ├── electricity/
│ │ │ ├── electricity_blue.tres
│ │ │ ├── electricity_yellow.tres
│ │ │ ├── lightning_circle_cyan.tres
│ │ │ ├── lightning_circle_white.tres
│ │ │ ├── lightning_glowing.tres
│ │ │ └── thunderstorm.tres
│ │ ├── elements/
│ │ │ ├── astral.tres
│ │ │ ├── darkness.tres
│ │ │ ├── fire.tres
│ │ │ ├── ice.tres
│ │ │ ├── iron.tres
│ │ │ ├── nature.tres
│ │ │ └── storm.tres
│ │ ├── faces/
│ │ │ ├── green_demon.tres
│ │ │ ├── man_01.tres
│ │ │ ├── man_02.tres
│ │ │ ├── man_03.tres
│ │ │ ├── man_04.tres
│ │ │ ├── man_05.tres
│ │ │ ├── mech_zombie.tres
│ │ │ ├── orc_01.tres
│ │ │ ├── orc_02.tres
│ │ │ ├── sleeping_leaf_spirit.tres
│ │ │ ├── woman_01.tres
│ │ │ ├── woman_02.tres
│ │ │ └── woman_03.tres
│ │ ├── fire/
│ │ │ ├── burning_cloth.tres
│ │ │ ├── fire_bowl_01.tres
│ │ │ ├── fire_bowl_02.tres
│ │ │ ├── fire_bowl_03.tres
│ │ │ ├── fire_in_cup.tres
│ │ │ ├── flame_blue.tres
│ │ │ ├── flame_blue_glowing.tres
│ │ │ ├── flame_purple.tres
│ │ │ └── torch.tres
│ │ ├── food/
│ │ │ ├── barrel.tres
│ │ │ ├── beer_01.tres
│ │ │ ├── beer_02.tres
│ │ │ ├── lard.tres
│ │ │ ├── pork.tres
│ │ │ ├── pork_without_plate.tres
│ │ │ └── poultry.tres
│ │ ├── furniture/
│ │ │ ├── artifact_of_skadi.tres
│ │ │ ├── artifact_on_pedestal.tres
│ │ │ ├── bed.tres
│ │ │ ├── chest.tres
│ │ │ ├── exploding_mirror.tres
│ │ │ ├── furniture.tres
│ │ │ ├── stool.tres
│ │ │ ├── throne.tres
│ │ │ └── wooden_stand_with_nail.tres
│ │ ├── gems/
│ │ │ ├── crystal.tres
│ │ │ ├── earring_01.tres
│ │ │ ├── earring_02.tres
│ │ │ ├── earring_03.tres
│ │ │ ├── earring_04.tres
│ │ │ ├── earring_05.tres
│ │ │ ├── gem_01.tres
│ │ │ ├── gem_02.tres
│ │ │ ├── gem_03.tres
│ │ │ ├── gem_04.tres
│ │ │ ├── gem_05.tres
│ │ │ ├── gem_06.tres
│ │ │ ├── gem_07.tres
│ │ │ ├── stone_01.tres
│ │ │ ├── stone_02.tres
│ │ │ ├── stone_03.tres
│ │ │ └── stone_04.tres
│ │ ├── generic_icons/
│ │ │ ├── README.md
│ │ │ ├── abdominal_armor.tres
│ │ │ ├── alien_skull.tres
│ │ │ ├── alligator_clip.tres
│ │ │ ├── amber_mosquito.tres
│ │ │ ├── angel_outfit.tres
│ │ │ ├── angel_wings.tres
│ │ │ ├── animal_skull.tres
│ │ │ ├── ankh.tres
│ │ │ ├── aquarius.tres
│ │ │ ├── aries.tres
│ │ │ ├── armor_vest.tres
│ │ │ ├── atomic_slashes.tres
│ │ │ ├── azul_flake.tres
│ │ │ ├── barbute.tres
│ │ │ ├── barefoot.tres
│ │ │ ├── bat_mask.tres
│ │ │ ├── beard.tres
│ │ │ ├── biceps.tres
│ │ │ ├── burning_dot.tres
│ │ │ ├── burning_meteor.tres
│ │ │ ├── charm.tres
│ │ │ ├── chest_armor.tres
│ │ │ ├── cog.tres
│ │ │ ├── egg.tres
│ │ │ ├── electric.tres
│ │ │ ├── energy_breath.tres
│ │ │ ├── fire_dash.tres
│ │ │ ├── flame.tres
│ │ │ ├── foot_trip.tres
│ │ │ ├── ghost.tres
│ │ │ ├── gold_bar.tres
│ │ │ ├── hammer_drop.tres
│ │ │ ├── holy_grail.tres
│ │ │ ├── horned_helm.tres
│ │ │ ├── hourglass.tres
│ │ │ ├── knocked_out_stars.tres
│ │ │ ├── liberty_wing.tres
│ │ │ ├── meat.tres
│ │ │ ├── mighty_force.tres
│ │ │ ├── mine_explosion.tres
│ │ │ ├── moebius_trefoil.tres
│ │ │ ├── omega.tres
│ │ │ ├── open_wound.tres
│ │ │ ├── ophiucus.tres
│ │ │ ├── orc_head.tres
│ │ │ ├── over_infinity.tres
│ │ │ ├── perpendicular_rings.tres
│ │ │ ├── pisces.tres
│ │ │ ├── poison_gas.tres
│ │ │ ├── pokecog.tres
│ │ │ ├── polar_star.tres
│ │ │ ├── rolling_energy.tres
│ │ │ ├── root_tip.tres
│ │ │ ├── round_potion.tres
│ │ │ ├── rss.tres
│ │ │ ├── semi_closed_eye.tres
│ │ │ ├── shiny_omega.tres
│ │ │ ├── spell_book.tres
│ │ │ ├── spider_web.tres
│ │ │ ├── sprint.tres
│ │ │ ├── star_swirl.tres
│ │ │ ├── triple_scratches.tres
│ │ │ ├── turtle_shell.tres
│ │ │ └── wolf_howl.tres
│ │ ├── gloves/
│ │ │ ├── curse.tres
│ │ │ ├── gloves_01.tres
│ │ │ ├── gloves_02.tres
│ │ │ ├── gloves_03.tres
│ │ │ ├── gloves_04.tres
│ │ │ ├── gloves_05.tres
│ │ │ ├── gloves_06.tres
│ │ │ ├── gloves_07.tres
│ │ │ ├── gloves_08.tres
│ │ │ ├── heal.tres
│ │ │ └── steal.tres
│ │ ├── helmets/
│ │ │ ├── crown_01.tres
│ │ │ ├── crown_02.tres
│ │ │ ├── crown_03.tres
│ │ │ ├── helmet_01.tres
│ │ │ ├── helmet_02.tres
│ │ │ ├── helmet_03.tres
│ │ │ ├── helmet_04.tres
│ │ │ ├── helmet_05.tres
│ │ │ ├── helmet_06.tres
│ │ │ ├── helmet_07.tres
│ │ │ ├── helmet_08.tres
│ │ │ ├── wizard_hat_01.tres
│ │ │ └── wizard_hat_02.tres
│ │ ├── holy/
│ │ │ ├── altar.tres
│ │ │ ├── axe.tres
│ │ │ ├── cross_01.tres
│ │ │ ├── cross_02.tres
│ │ │ ├── cross_03.tres
│ │ │ ├── orb.tres
│ │ │ ├── tombstone.tres
│ │ │ └── white_trinket.tres
│ │ ├── hud/
│ │ │ ├── dice.tres
│ │ │ ├── gem_all_rarities.tres
│ │ │ ├── gem_common.tres
│ │ │ ├── gem_rare.tres
│ │ │ ├── gem_uncommon.tres
│ │ │ ├── gem_unique.tres
│ │ │ ├── gold.tres
│ │ │ ├── item_stash.tres
│ │ │ ├── knowledge_tome.tres
│ │ │ ├── oils.tres
│ │ │ ├── recipe_distill.tres
│ │ │ ├── recipe_perfect.tres
│ │ │ ├── recipe_reassemble.tres
│ │ │ ├── recipe_rebrew.tres
│ │ │ ├── research_elements.tres
│ │ │ ├── tower_food.tres
│ │ │ └── tower_stash.tres
│ │ ├── magic/
│ │ │ ├── bowl_01.tres
│ │ │ ├── bowl_02.tres
│ │ │ ├── claw_01.tres
│ │ │ ├── claw_02.tres
│ │ │ ├── claw_03.tres
│ │ │ ├── claw_04.tres
│ │ │ ├── eye.tres
│ │ │ ├── eye_blue.tres
│ │ │ ├── eyes_many.tres
│ │ │ ├── fire.tres
│ │ │ ├── lantern.tres
│ │ │ ├── lock_01.tres
│ │ │ ├── lock_02.tres
│ │ │ ├── lock_03.tres
│ │ │ ├── lock_04.tres
│ │ │ ├── magic_stone.tres
│ │ │ └── magic_stone_green.tres
│ │ ├── masks/
│ │ │ ├── mask_01.tres
│ │ │ ├── mask_02.tres
│ │ │ ├── mask_03.tres
│ │ │ ├── mask_04.tres
│ │ │ ├── mask_05.tres
│ │ │ ├── mask_06.tres
│ │ │ └── mask_07.tres
│ │ ├── mechanical/
│ │ │ ├── alchemy_kit_01.tres
│ │ │ ├── alchemy_kit_02.tres
│ │ │ ├── alchemy_kit_03.tres
│ │ │ ├── battery.tres
│ │ │ ├── black_gold_calculator.tres
│ │ │ ├── circuit_board.tres
│ │ │ ├── compass.tres
│ │ │ ├── factory_fumes.tres
│ │ │ ├── factory_gears.tres
│ │ │ ├── gold_machine.tres
│ │ │ ├── lamp.tres
│ │ │ ├── mech_badge.tres
│ │ │ └── mech_umbrella.tres
│ │ ├── misc/
│ │ │ ├── balls_01.tres
│ │ │ ├── balls_02.tres
│ │ │ ├── balls_03.tres
│ │ │ ├── cauldron.tres
│ │ │ ├── flag_01.tres
│ │ │ ├── flag_02.tres
│ │ │ ├── flag_03.tres
│ │ │ ├── gold_cart.tres
│ │ │ ├── grenade.tres
│ │ │ ├── poison_01.tres
│ │ │ ├── poison_02.tres
│ │ │ ├── quiver.tres
│ │ │ ├── red_knight.tres
│ │ │ ├── spiky_totem_01.tres
│ │ │ ├── spiky_totem_02.tres
│ │ │ ├── teapot_01.tres
│ │ │ ├── teapot_02.tres
│ │ │ ├── teapot_03.tres
│ │ │ ├── teapot_04.tres
│ │ │ ├── toolbox_01.tres
│ │ │ └── toolbox_02.tres
│ │ ├── orbs/
│ │ │ ├── moon.tres
│ │ │ ├── orb_fire.tres
│ │ │ ├── orb_green.tres
│ │ │ ├── orb_ice.tres
│ │ │ ├── orb_ice_melting.tres
│ │ │ ├── orb_molten.tres
│ │ │ ├── orb_molten_dull.tres
│ │ │ ├── orb_shadow.tres
│ │ │ └── orb_small.tres
│ │ ├── plants/
│ │ │ ├── branch_01.tres
│ │ │ ├── branch_02.tres
│ │ │ ├── flower_01.tres
│ │ │ ├── flower_02.tres
│ │ │ ├── flower_03.tres
│ │ │ ├── flower_04.tres
│ │ │ ├── flower_05.tres
│ │ │ ├── flower_06.tres
│ │ │ ├── leaf_01.tres
│ │ │ ├── leaf_02.tres
│ │ │ ├── leaf_03.tres
│ │ │ ├── plant_in_pot.tres
│ │ │ ├── stump.tres
│ │ │ └── tree.tres
│ │ ├── potions/
│ │ │ ├── beaker_01.tres
│ │ │ ├── beaker_02.tres
│ │ │ ├── beaker_03.tres
│ │ │ ├── potion_01.tres
│ │ │ ├── potion_02.tres
│ │ │ ├── potion_03.tres
│ │ │ ├── potion_04.tres
│ │ │ ├── potion_05.tres
│ │ │ ├── potion_06.tres
│ │ │ ├── potion_07.tres
│ │ │ ├── potion_08.tres
│ │ │ ├── potion_09.tres
│ │ │ ├── potion_10.tres
│ │ │ ├── potion_blue_01.tres
│ │ │ ├── potion_blue_02.tres
│ │ │ ├── potion_blue_03.tres
│ │ │ ├── potion_blue_04.tres
│ │ │ ├── potion_blue_05.tres
│ │ │ ├── potion_cyan_01.tres
│ │ │ ├── potion_cyan_02.tres
│ │ │ ├── potion_cyan_03.tres
│ │ │ ├── potion_green_01.tres
│ │ │ ├── potion_green_02.tres
│ │ │ ├── potion_green_03.tres
│ │ │ ├── potion_heart_01.tres
│ │ │ ├── potion_heart_02.tres
│ │ │ ├── potion_orange_01.tres
│ │ │ ├── potion_orange_02.tres
│ │ │ ├── potion_orange_03.tres
│ │ │ ├── potion_purple_01.tres
│ │ │ ├── potion_purple_02.tres
│ │ │ ├── potion_purple_03.tres
│ │ │ ├── potion_red_01.tres
│ │ │ ├── potion_red_02.tres
│ │ │ ├── potion_red_03.tres
│ │ │ ├── potion_yellow_01.tres
│ │ │ └── potion_yellow_02.tres
│ │ ├── rings/
│ │ │ ├── ring_01.tres
│ │ │ ├── ring_02.tres
│ │ │ ├── ring_03.tres
│ │ │ ├── ring_04.tres
│ │ │ ├── ring_05.tres
│ │ │ ├── ring_06.tres
│ │ │ ├── ring_07.tres
│ │ │ └── ring_08.tres
│ │ ├── rockets/
│ │ │ ├── rocket_01.tres
│ │ │ ├── rocket_02.tres
│ │ │ ├── rocket_03.tres
│ │ │ ├── rocket_04.tres
│ │ │ ├── rocket_05.tres
│ │ │ ├── rocket_06.tres
│ │ │ └── rocket_07.tres
│ │ ├── scrolls/
│ │ │ ├── scroll_01.tres
│ │ │ ├── scroll_02.tres
│ │ │ ├── scroll_03.tres
│ │ │ ├── scroll_04.tres
│ │ │ ├── scroll_05.tres
│ │ │ ├── scroll_06.tres
│ │ │ ├── scroll_07.tres
│ │ │ └── scroll_08.tres
│ │ ├── shields/
│ │ │ ├── shield_bronze.tres
│ │ │ ├── shield_castle.tres
│ │ │ ├── shield_gray_with_gold_emblem.tres
│ │ │ ├── shield_green.tres
│ │ │ ├── shield_skull.tres
│ │ │ ├── shield_white.tres
│ │ │ ├── shield_with_emblem.tres
│ │ │ ├── shield_with_gold_helmet.tres
│ │ │ ├── shield_wood.tres
│ │ │ ├── shield_wood_small.tres
│ │ │ └── shield_wood_small_glowing.tres
│ │ ├── spears/
│ │ │ ├── many_spears_01.tres
│ │ │ ├── many_spears_02.tres
│ │ │ ├── spear_01.tres
│ │ │ ├── spear_02.tres
│ │ │ └── spear_03.tres
│ │ ├── statues/
│ │ │ ├── statue_01.tres
│ │ │ ├── statue_02.tres
│ │ │ ├── statue_03.tres
│ │ │ ├── statue_dwarf_01.tres
│ │ │ ├── statue_dwarf_02.tres
│ │ │ └── statue_warrior.tres
│ │ ├── staves/
│ │ │ ├── staff_01.tres
│ │ │ ├── staff_02.tres
│ │ │ ├── staff_03.tres
│ │ │ ├── staff_04.tres
│ │ │ ├── staff_05.tres
│ │ │ ├── staff_06.tres
│ │ │ ├── staff_07.tres
│ │ │ ├── wand_01.tres
│ │ │ ├── wand_02.tres
│ │ │ ├── wand_03.tres
│ │ │ ├── wand_04.tres
│ │ │ ├── wand_05.tres
│ │ │ └── wand_glowing.tres
│ │ ├── swords/
│ │ │ ├── greatsword_01.tres
│ │ │ ├── greatsword_02.tres
│ │ │ ├── greatsword_03.tres
│ │ │ ├── greatsword_04.tres
│ │ │ ├── greatsword_05.tres
│ │ │ ├── sword_01.tres
│ │ │ ├── sword_02.tres
│ │ │ ├── sword_03.tres
│ │ │ ├── sword_swing_01.tres
│ │ │ └── sword_swing_02.tres
│ │ ├── tier_icons/
│ │ │ ├── common_1.tres
│ │ │ ├── common_2.tres
│ │ │ ├── common_3.tres
│ │ │ ├── common_4.tres
│ │ │ ├── common_5.tres
│ │ │ ├── common_6.tres
│ │ │ ├── common_7.tres
│ │ │ ├── rare_1.tres
│ │ │ ├── rare_2.tres
│ │ │ ├── rare_3.tres
│ │ │ ├── rare_4.tres
│ │ │ ├── rare_5.tres
│ │ │ ├── rare_6.tres
│ │ │ ├── rare_7.tres
│ │ │ ├── uncommon_1.tres
│ │ │ ├── uncommon_2.tres
│ │ │ ├── uncommon_3.tres
│ │ │ ├── uncommon_4.tres
│ │ │ ├── uncommon_5.tres
│ │ │ ├── uncommon_6.tres
│ │ │ ├── uncommon_7.tres
│ │ │ ├── unique_1.tres
│ │ │ ├── unique_2.tres
│ │ │ ├── unique_3.tres
│ │ │ ├── unique_4.tres
│ │ │ ├── unique_5.tres
│ │ │ ├── unique_6.tres
│ │ │ └── unique_7.tres
│ │ ├── tower_icons/
│ │ │ ├── abandoned_pit.tres
│ │ │ ├── abominable_snowman.tres
│ │ │ ├── afflicted_obelisk.tres
│ │ │ ├── ancient_energy_converter.tres
│ │ │ ├── annoyed_tree.tres
│ │ │ ├── arcane_storm.tres
│ │ │ ├── area_roaster.tres
│ │ │ ├── ash_geyser.tres
│ │ │ ├── astral_lantern.tres
│ │ │ ├── astral_rift.tres
│ │ │ ├── baby_plant.tres
│ │ │ ├── baby_tuskin.tres
│ │ │ ├── ball_lightning_accelerator.tres
│ │ │ ├── basic_knowledge.tres
│ │ │ ├── black_dragon_roost.tres
│ │ │ ├── black_rock_totem.tres
│ │ │ ├── bomb_turret.tres
│ │ │ ├── bone_shrine.tres
│ │ │ ├── bonk_the_living_mountain.tres
│ │ │ ├── broken_cage.tres
│ │ │ ├── broken_circle_of_wind.tres
│ │ │ ├── broken_fire_pit.tres
│ │ │ ├── broken_lightning_rod.tres
│ │ │ ├── bronze_dragon_roost.tres
│ │ │ ├── buried_soul.tres
│ │ │ ├── burning_watchtower.tres
│ │ │ ├── burrow.tres
│ │ │ ├── caged_fire.tres
│ │ │ ├── cenarion.tres
│ │ │ ├── chaining_storm.tres
│ │ │ ├── chaos_warlock.tres
│ │ │ ├── charged_obelisk.tres
│ │ │ ├── chilled_spire.tres
│ │ │ ├── cloud_warrior.tres
│ │ │ ├── cloudy_temple_of_absorption.tres
│ │ │ ├── coconut_sapling.tres
│ │ │ ├── coin_machine.tres
│ │ │ ├── cold_obelisk.tres
│ │ │ ├── cold_troll.tres
│ │ │ ├── contraption.tres
│ │ │ ├── crimson_wyrm.tres
│ │ │ ├── cruel_fire.tres
│ │ │ ├── cursed_grounds.tres
│ │ │ ├── cute_small_spider.tres
│ │ │ ├── dark_battery.tres
│ │ │ ├── dark_fire_pit.tres
│ │ │ ├── death_knight.tres
│ │ │ ├── dimensional_flux_collector.tres
│ │ │ ├── dragon_sorcerer.tres
│ │ │ ├── drake_whisperer.tres
│ │ │ ├── dreadlord.tres
│ │ │ ├── dutchmans_grave.tres
│ │ │ ├── dwarven_forgery.tres
│ │ │ ├── ebonfrost_crystal.tres
│ │ │ ├── embershell_turtle_hatchling.tres
│ │ │ ├── energy_junction.tres
│ │ │ ├── essence_of_fury.tres
│ │ │ ├── felweed.tres
│ │ │ ├── fenced_flames.tres
│ │ │ ├── fiery_dog.tres
│ │ │ ├── fiery_pebble.tres
│ │ │ ├── fire_battery.tres
│ │ │ ├── fire_star.tres
│ │ │ ├── firestorm_cell.tres
│ │ │ ├── fisherman.tres
│ │ │ ├── forest_archer.tres
│ │ │ ├── forest_protectress.tres
│ │ │ ├── forest_troll.tres
│ │ │ ├── frost_root.tres
│ │ │ ├── frosty_rock.tres
│ │ │ ├── frozen_well.tres
│ │ │ ├── garden_of_eden.tres
│ │ │ ├── gatling_gun.tres
│ │ │ ├── genis_sage.tres
│ │ │ ├── geothermal_extractor.tres
│ │ │ ├── glaive_master.tres
│ │ │ ├── glowing_solar_orb.tres
│ │ │ ├── gnoll_thunder_mage.tres
│ │ │ ├── goblin_stronghold.tres
│ │ │ ├── grab-o-bot.tres
│ │ │ ├── green_dragon_roost.tres
│ │ │ ├── green_lightning.tres
│ │ │ ├── greyfang.tres
│ │ │ ├── gryphon_rider.tres
│ │ │ ├── hall_of_souls.tres
│ │ │ ├── harby.tres
│ │ │ ├── harpy_witch.tres
│ │ │ ├── haunted_rubble.tres
│ │ │ ├── healing_obelisk.tres
│ │ │ ├── helicopter_zone.tres
│ │ │ ├── hell_bat.tres
│ │ │ ├── holy_energy.tres
│ │ │ ├── ice_battery.tres
│ │ │ ├── icy_core.tres
│ │ │ ├── icy_skulls.tres
│ │ │ ├── icy_spirit.tres
│ │ │ ├── igloo.tres
│ │ │ ├── inexperienced_huntress.tres
│ │ │ ├── inflamed_stone.tres
│ │ │ ├── initiate_elementalist.tres
│ │ │ ├── it.tres
│ │ │ ├── jungle_stalker.tres
│ │ │ ├── kraken.tres
│ │ │ ├── lesser_astral_defender.tres
│ │ │ ├── lesser_dark_defender.tres
│ │ │ ├── lesser_elemental_ghost.tres
│ │ │ ├── lesser_flamy_defender.tres
│ │ │ ├── lesser_ice_defender.tres
│ │ │ ├── lesser_iron_defender.tres
│ │ │ ├── lesser_natural_defender.tres
│ │ │ ├── lesser_priest.tres
│ │ │ ├── lesser_skeletal_mage.tres
│ │ │ ├── lesser_storm_defender.tres
│ │ │ ├── lesser_wolves_den.tres
│ │ │ ├── library_of_alexandria.tres
│ │ │ ├── lich_king.tres
│ │ │ ├── lightning_eye.tres
│ │ │ ├── lightning_generator.tres
│ │ │ ├── lightning_totem.tres
│ │ │ ├── little_phoenix.tres
│ │ │ ├── living_volcano.tres
│ │ │ ├── lunar_emitter.tres
│ │ │ ├── lunar_sentinel.tres
│ │ │ ├── magic_battery.tres
│ │ │ ├── magic_mushroom.tres
│ │ │ ├── magna_warrior.tres
│ │ │ ├── mana-touched_drake.tres
│ │ │ ├── marine.tres
│ │ │ ├── meteor_totem.tres
│ │ │ ├── militia_watchtower.tres
│ │ │ ├── miner.tres
│ │ │ ├── minor_magic_ruin.tres
│ │ │ ├── mister_fireflies.tres
│ │ │ ├── monolith_of_chaos.tres
│ │ │ ├── morphling.tres
│ │ │ ├── mossy_acid_sprayer.tres
│ │ │ ├── mud_golem.tres
│ │ │ ├── nature_sprites.tres
│ │ │ ├── necromantic_altar.tres
│ │ │ ├── nortrom_the_silencer.tres
│ │ │ ├── nuclear_missile_launcher.tres
│ │ │ ├── obelisk_of_fortuity.tres
│ │ │ ├── owl_of_wisdom.tres
│ │ │ ├── particle_accelerator.tres
│ │ │ ├── phantom.tres
│ │ │ ├── plagued_crypt.tres
│ │ │ ├── planar_gate.tres
│ │ │ ├── poison_battery.tres
│ │ │ ├── polar_bear_cub.tres
│ │ │ ├── portal_to_swine_purgatory.tres
│ │ │ ├── prince_of_lightning.tres
│ │ │ ├── princess_of_light.tres
│ │ │ ├── razorboar_thornweaver.tres
│ │ │ ├── red_ball_lightning.tres
│ │ │ ├── regenerating_well.tres
│ │ │ ├── rooted_chasm.tres
│ │ │ ├── rotted_flashing_grave.tres
│ │ │ ├── rowing_boat.tres
│ │ │ ├── ruined_monolith.tres
│ │ │ ├── ruined_storm_cap.tres
│ │ │ ├── ruined_sun_pedestal.tres
│ │ │ ├── ruined_wind_tower.tres
│ │ │ ├── rundown_iron_sentry.tres
│ │ │ ├── sacred_altar.tres
│ │ │ ├── sacrificial_lamb.tres
│ │ │ ├── safirons_cold_grave.tres
│ │ │ ├── scales.tres
│ │ │ ├── sea_turtle.tres
│ │ │ ├── servant_of_the_twin_flames.tres
│ │ │ ├── sewer_connection.tres
│ │ │ ├── shadow.tres
│ │ │ ├── shaman.tres
│ │ │ ├── shard_of_souls.tres
│ │ │ ├── silver_knight.tres
│ │ │ ├── skink.tres
│ │ │ ├── small_brazier.tres
│ │ │ ├── small_bug_nest.tres
│ │ │ ├── small_cactus.tres
│ │ │ ├── small_fire_sprayer.tres
│ │ │ ├── small_frost_fire.tres
│ │ │ ├── small_frozen_mushroom.tres
│ │ │ ├── small_ice_mine.tres
│ │ │ ├── small_light.tres
│ │ │ ├── small_pocket_rocket.tres
│ │ │ ├── small_ray_blaster.tres
│ │ │ ├── small_serpent_ward.tres
│ │ │ ├── small_torch.tres
│ │ │ ├── sniper.tres
│ │ │ ├── snowy_pebble.tres
│ │ │ ├── solar_collector.tres
│ │ │ ├── solar_emitter.tres
│ │ │ ├── sorceress.tres
│ │ │ ├── soul_vault.tres
│ │ │ ├── soulflame_device.tres
│ │ │ ├── spell_collector.tres
│ │ │ ├── spider_queen.tres
│ │ │ ├── star_gazer.tres
│ │ │ ├── storm_battery.tres
│ │ │ ├── storm_coil.tres
│ │ │ ├── storm_focus.tres
│ │ │ ├── stormy_dog.tres
│ │ │ ├── sun_crusader.tres
│ │ │ ├── taita_the_hermit.tres
│ │ │ ├── teacher.tres
│ │ │ ├── tentacle_spawn.tres
│ │ │ ├── the_conduit.tres
│ │ │ ├── the_council_of_demons.tres
│ │ │ ├── the_fire_lord.tres
│ │ │ ├── the_frozen_wyrm.tres
│ │ │ ├── the_furnace.tres
│ │ │ ├── the_omnislasher.tres
│ │ │ ├── the_steam_engine.tres
│ │ │ ├── thief_apprentice.tres
│ │ │ ├── tidewater_stream.tres
│ │ │ ├── time_manipulator.tres
│ │ │ ├── timevault.tres
│ │ │ ├── tiny_shrub.tres
│ │ │ ├── tiny_storm_lantern.tres
│ │ │ ├── tombstone.tres
│ │ │ ├── trash_heap.tres
│ │ │ ├── tree_stump.tres
│ │ │ ├── tundra_stalker.tres
│ │ │ ├── undisturbed_crypt.tres
│ │ │ ├── valor.tres
│ │ │ ├── village_witch.tres
│ │ │ ├── void_drake.tres
│ │ │ ├── vulshok_the_berserker.tres
│ │ │ ├── warrior_of_light.tres
│ │ │ ├── wild_warbeast.tres
│ │ │ ├── witch_doctor.tres
│ │ │ ├── wooden_trap.tres
│ │ │ ├── xeno_research_facility.tres
│ │ │ ├── ymir.tres
│ │ │ ├── young_northern_troll.tres
│ │ │ ├── zealot.tres
│ │ │ └── zeus.tres
│ │ ├── tower_variations/
│ │ │ ├── ash_geyser_blue.tres
│ │ │ ├── ash_geyser_green.tres
│ │ │ ├── ash_geyser_purple.tres
│ │ │ ├── bonk_the_living_mountain_small.tres
│ │ │ ├── forest_troll_small.tres
│ │ │ ├── meteor_totem_blue.tres
│ │ │ ├── meteor_totem_purple.tres
│ │ │ ├── mossy_acid_sprayer_gray.tres
│ │ │ ├── mossy_acid_sprayer_red.tres
│ │ │ ├── undisturbed_crypt_gold.tres
│ │ │ └── vulshok_the_berserker_blue.tres
│ │ ├── trinkets/
│ │ │ ├── claw_01.tres
│ │ │ ├── claw_02.tres
│ │ │ ├── claw_03.tres
│ │ │ ├── key_01.tres
│ │ │ ├── key_02.tres
│ │ │ ├── key_03.tres
│ │ │ ├── trinket_01.tres
│ │ │ ├── trinket_02.tres
│ │ │ ├── trinket_03.tres
│ │ │ ├── trinket_04.tres
│ │ │ ├── trinket_05.tres
│ │ │ ├── trinket_06.tres
│ │ │ ├── trinket_07.tres
│ │ │ ├── trinket_08.tres
│ │ │ ├── trinket_09.tres
│ │ │ └── trinket_10.tres
│ │ ├── undead/
│ │ │ ├── demon_emblem.tres
│ │ │ ├── monster_hand.tres
│ │ │ ├── skull_01.tres
│ │ │ ├── skull_02.tres
│ │ │ ├── skull_03.tres
│ │ │ ├── skull_04.tres
│ │ │ ├── skull_05.tres
│ │ │ ├── skull_06.tres
│ │ │ ├── skull_doll.tres
│ │ │ ├── skull_phazing.tres
│ │ │ ├── skull_wand_01.tres
│ │ │ ├── skull_wand_02.tres
│ │ │ ├── skull_wand_03.tres
│ │ │ └── skull_wand_04.tres
│ │ └── weapons_misc/
│ │ ├── axe_01.tres
│ │ ├── axe_02.tres
│ │ ├── barbed_spike.tres
│ │ ├── glaive_01.tres
│ │ ├── glaive_02.tres
│ │ ├── glaive_03.tres
│ │ ├── mining_pick_01.tres
│ │ ├── mining_pick_02.tres
│ │ ├── trident_01.tres
│ │ └── trident_02.tres
│ ├── misc/
│ │ ├── barrel.tres
│ │ └── pulsing_dot.tres
│ ├── shaders/
│ │ ├── foggy_camera.gdshader
│ │ ├── glowing_outline.gdshader
│ │ ├── glowing_outline.material
│ │ ├── glowing_outline_2.gdshader
│ │ └── saturation_burn.gdshader
│ ├── theme/
│ │ ├── common/
│ │ │ ├── rect_container_center_l.tres
│ │ │ ├── rect_container_l.tres
│ │ │ ├── rect_container_m.tres
│ │ │ ├── rect_container_s.tres
│ │ │ └── tab_container_m.tres
│ │ ├── element_towers_info/
│ │ │ └── empty_button_style_box.tres
│ │ ├── health_bar_background.tres
│ │ ├── health_bar_fill.tres
│ │ ├── item_button_hover.tres
│ │ ├── item_button_normal.tres
│ │ ├── item_button_pressed.tres
│ │ ├── mission_complete_indicator.tres
│ │ ├── player_resource_display/
│ │ │ ├── circle_container_l.tres
│ │ │ ├── rect_container_center_l.tres
│ │ │ ├── rect_container_left_l.tres
│ │ │ ├── rect_container_right_l.tres
│ │ │ ├── rect_container_top_menu.tres
│ │ │ ├── resource_status_panel.tres
│ │ │ └── stash_panel_background.tres
│ │ ├── selected_unit_info/
│ │ │ ├── mana_bar_fill.tres
│ │ │ ├── panel_container.tres
│ │ │ └── progress_bar_background.tres
│ │ ├── tower_actions/
│ │ │ ├── button_disabled.tres
│ │ │ ├── button_normal.tres
│ │ │ └── button_pressed.tres
│ │ ├── unit_button/
│ │ │ ├── button_disabled.tres
│ │ │ ├── button_hover.tres
│ │ │ ├── button_normal.tres
│ │ │ ├── common_rarity_panel_container.tres
│ │ │ ├── passive_ability_button.tres
│ │ │ ├── rare_rarity_panel_container.tres
│ │ │ ├── small_button_disabled.tres
│ │ │ ├── small_button_hover.tres
│ │ │ ├── small_button_normal.tres
│ │ │ ├── uncommon_rarity_panel_container.tres
│ │ │ └── unique_rarity_panel_container.tres
│ │ ├── unit_button_container/
│ │ │ └── counter_label_normal.tres
│ │ ├── unit_menu/
│ │ │ ├── button_disalbed.tres
│ │ │ ├── button_hover.tres
│ │ │ ├── button_normal.tres
│ │ │ ├── exp_bar_background.tres
│ │ │ ├── exp_bar_fill.tres
│ │ │ ├── health_bar_background.tres
│ │ │ ├── health_bar_fill.tres
│ │ │ ├── mana_bar_background.tres
│ │ │ ├── mana_bar_fill.tres
│ │ │ ├── title_button_normal.tres
│ │ │ ├── unit_level_label_normal.tres
│ │ │ ├── unit_menu_panel.tres
│ │ │ └── unit_name_label_normal.tres
│ │ └── wc3_theme.tres
│ ├── tilesets/
│ │ ├── buildable_area_tiles.tres
│ │ └── decorations.tres
│ └── ui_textures/
│ ├── buff_group_both.tres
│ ├── buff_group_incoming.tres
│ ├── buff_group_none.tres
│ ├── buff_group_outgoing.tres
│ ├── button_container_hover.tres
│ ├── common_background.tres
│ ├── common_unit_button.tres
│ ├── common_unit_button_hover.tres
│ ├── info_icon.tres
│ ├── menu_option_round_button.tres
│ ├── menu_option_round_button_hover.tres
│ ├── portal_lives_round_bg.tres
│ ├── rare_background.tres
│ ├── rare_unit_button.tres
│ ├── rare_unit_button_hover.tres
│ ├── rect_container_center_l.tres
│ ├── rect_container_l.tres
│ ├── rect_container_left_l.tres
│ ├── rect_container_m.tres
│ ├── rect_container_right_l.tres
│ ├── rect_container_s.tres
│ ├── rect_container_s_hover.tres
│ ├── speed_fast.tres
│ ├── speed_fastest.tres
│ ├── speed_normal.tres
│ ├── stash_panel_background.tres
│ ├── uncommon_background.tres
│ ├── uncommon_unit_button.tres
│ ├── uncommon_unit_button_hover.tres
│ ├── unique_background.tres
│ ├── unique_unit_button.tres
│ ├── unique_unit_button_hover.tres
│ ├── unit_button_disabled.tres
│ └── upgrade_icon.tres
├── src/
│ ├── README.md
│ ├── actions/
│ │ ├── action.gd
│ │ ├── action_autocast.gd
│ │ ├── action_autofill.gd
│ │ ├── action_build_tower.gd
│ │ ├── action_change_buffgroup.gd
│ │ ├── action_chat.gd
│ │ ├── action_consume_item.gd
│ │ ├── action_drop_item.gd
│ │ ├── action_focus_target.gd
│ │ ├── action_idle.gd
│ │ ├── action_move_item.gd
│ │ ├── action_research_element.gd
│ │ ├── action_roll_towers.gd
│ │ ├── action_select_builder.gd
│ │ ├── action_select_unit.gd
│ │ ├── action_select_wisdom_upgrades.gd
│ │ ├── action_sell_tower.gd
│ │ ├── action_sort_item_stash.gd
│ │ ├── action_start_next_wave.gd
│ │ ├── action_swap_items.gd
│ │ ├── action_toggle_autocast.gd
│ │ ├── action_transform_tower.gd
│ │ ├── action_transmute.gd
│ │ └── action_upgrade_tower.gd
│ ├── buffs/
│ │ ├── aura.gd
│ │ ├── aura.tscn
│ │ ├── buff.gd
│ │ ├── buff_range_area.gd
│ │ ├── buff_range_area.tscn
│ │ ├── buff_type.gd
│ │ ├── instances/
│ │ │ ├── cb_silence.gd
│ │ │ └── cb_stun.gd
│ │ ├── modification.gd
│ │ ├── modifier.gd
│ │ └── target_type.gd
│ ├── builders/
│ │ ├── builder.gd
│ │ └── instances/
│ │ ├── builder_adventurer.gd
│ │ ├── builder_antagonizer.gd
│ │ ├── builder_arch_sorceress.gd
│ │ ├── builder_backpacker.gd
│ │ ├── builder_barbarian_warlord.gd
│ │ ├── builder_benevolent_witch.gd
│ │ ├── builder_blademaster.gd
│ │ ├── builder_elementalist.gd
│ │ ├── builder_farseer.gd
│ │ ├── builder_feeble_fender.gd
│ │ ├── builder_goblin_alchemist.gd
│ │ ├── builder_iron_maiden.gd
│ │ ├── builder_master_of_encyclopedic_wisdom.gd
│ │ ├── builder_maverick.gd
│ │ ├── builder_naga_time_twister.gd
│ │ ├── builder_none.gd
│ │ ├── builder_panda_monk.gd
│ │ ├── builder_queen.gd
│ │ ├── builder_realist.gd
│ │ ├── builder_royal_assassin.gd
│ │ ├── builder_spirit_warden.gd
│ │ └── builder_veteran_pilot.gd
│ ├── creeps/
│ │ ├── creep.gd
│ │ ├── creep_blood_pool.gd
│ │ ├── creep_blood_pool.tscn
│ │ ├── creep_corpse.gd
│ │ ├── creep_corpse.tscn
│ │ ├── creep_spawner.gd
│ │ ├── creep_spawner.tscn
│ │ ├── creep_sprite.gd
│ │ ├── health_bar.gd
│ │ ├── instances/
│ │ │ ├── challenge/
│ │ │ │ ├── challenge_boss_creep.tscn
│ │ │ │ └── challenge_mass_creep.tscn
│ │ │ ├── creep.tscn
│ │ │ └── orc/
│ │ │ ├── orc_air_creep.tscn
│ │ │ ├── orc_boss_creep.tscn
│ │ │ ├── orc_champion_creep.tscn
│ │ │ ├── orc_mass_creep.tscn
│ │ │ └── orc_normal_creep.tscn
│ │ ├── packed_metadata.gd
│ │ ├── special_buffs/
│ │ │ ├── creep_armored.gd
│ │ │ ├── creep_broody.gd
│ │ │ ├── creep_dart.gd
│ │ │ ├── creep_ethereal.gd
│ │ │ ├── creep_evasion.gd
│ │ │ ├── creep_evolving.gd
│ │ │ ├── creep_fireball.gd
│ │ │ ├── creep_flock.gd
│ │ │ ├── creep_ghost.gd
│ │ │ ├── creep_gravid.gd
│ │ │ ├── creep_greater_speed.gd
│ │ │ ├── creep_greater_spell_resistance.gd
│ │ │ ├── creep_heavy_armored.gd
│ │ │ ├── creep_invisible.gd
│ │ │ ├── creep_magic_immunity.gd
│ │ │ ├── creep_mana_drain_aura.gd
│ │ │ ├── creep_manashield+.gd
│ │ │ ├── creep_manashield.gd
│ │ │ ├── creep_meaty.gd
│ │ │ ├── creep_mechanical.gd
│ │ │ ├── creep_necromancer.gd
│ │ │ ├── creep_protector.gd
│ │ │ ├── creep_purge_revenge.gd
│ │ │ ├── creep_regeneration.gd
│ │ │ ├── creep_relic_raider.gd
│ │ │ ├── creep_rich.gd
│ │ │ ├── creep_second_chance.gd
│ │ │ ├── creep_semi-mechanical.gd
│ │ │ ├── creep_slow.gd
│ │ │ ├── creep_slow_aura.gd
│ │ │ ├── creep_speed.gd
│ │ │ ├── creep_spell_resistance.gd
│ │ │ ├── creep_spellbinder.gd
│ │ │ ├── creep_strong.gd
│ │ │ ├── creep_stun_revenge.gd
│ │ │ ├── creep_ultra_wisdom.gd
│ │ │ ├── creep_unlucky.gd
│ │ │ ├── creep_xtreme_armor.gd
│ │ │ ├── creep_xtreme_evasion.gd
│ │ │ ├── creep_xtreme_regeneration.gd
│ │ │ └── creep_xtreme_speed.gd
│ │ ├── special_icons/
│ │ │ ├── CreepArmoredSpecial.tscn
│ │ │ ├── CreepBroodySpecial.tscn
│ │ │ ├── CreepDartSpecial.tscn
│ │ │ ├── CreepEtherealSpecial.tscn
│ │ │ ├── CreepEvasionSpecial.tscn
│ │ │ ├── CreepEvolvingSpecial.tscn
│ │ │ ├── CreepFireballSpecial.tscn
│ │ │ ├── CreepFlockSpecial.tscn
│ │ │ ├── CreepGhostSpecial.tscn
│ │ │ ├── CreepGravidSpecial.tscn
│ │ │ ├── CreepGreaterSpeedSpecial.tscn
│ │ │ ├── CreepGreaterSpellResistanceSpecial.tscn
│ │ │ ├── CreepHeavyArmoredSpecial.tscn
│ │ │ ├── CreepInvisibleSpecial.tscn
│ │ │ ├── CreepMagicImmunitySpecial.tscn
│ │ │ ├── CreepManaDrainAuraSpecial.tscn
│ │ │ ├── CreepManaShieldPlusSpecial.tscn
│ │ │ ├── CreepManaShieldSpecial.tscn
│ │ │ ├── CreepMeatySpecial.tscn
│ │ │ ├── CreepMechanicalSpecial.tscn
│ │ │ ├── CreepNecromancerSpecial.tscn
│ │ │ ├── CreepProtectorSpecial.tscn
│ │ │ ├── CreepPurgeRevengeSpecial.tscn
│ │ │ ├── CreepRegenerationSpecial.tscn
│ │ │ ├── CreepRelicRaiderSpecial.tscn
│ │ │ ├── CreepRichSpecial.tscn
│ │ │ ├── CreepSecondChanceSpecial.tscn
│ │ │ ├── CreepSemiMechanicalSpecial.tscn
│ │ │ ├── CreepSlowAuraSpecial.tscn
│ │ │ ├── CreepSlowSpecial.tscn
│ │ │ ├── CreepSpeedSpecial.tscn
│ │ │ ├── CreepSpellResistanceSpecial.tscn
│ │ │ ├── CreepSpellbinderSpecial.tscn
│ │ │ ├── CreepStrongSpecial.tscn
│ │ │ ├── CreepStunRevengeSpecial.tscn
│ │ │ ├── CreepUltraWisdomSpecial.tscn
│ │ │ ├── CreepUnluckySpecial.tscn
│ │ │ ├── CreepXtremeArmorSpecial.tscn
│ │ │ ├── CreepXtremeEvasionSpecial.tscn
│ │ │ ├── CreepXtremeRegenerationSpecial.tscn
│ │ │ └── CreepXtremeSpeedSpecial.tscn
│ │ ├── wave.gd
│ │ ├── wave_path.gd
│ │ ├── wave_spawner.gd
│ │ └── wave_spawner.tscn
│ ├── effects/
│ │ ├── ancient_protector_missile.tscn
│ │ ├── animated_dead_target.tscn
│ │ ├── apply_potion.tscn
│ │ ├── arcane_tower_attack.tscn
│ │ ├── arcane_tower_attack_flat.tscn
│ │ ├── avatar_caster.tscn
│ │ ├── banshee_missile.tscn
│ │ ├── barrel.tscn
│ │ ├── blink_target.tscn
│ │ ├── blood_splatter.tscn
│ │ ├── build_tower.tscn
│ │ ├── charm_target.tscn
│ │ ├── chimaera_acid.tscn
│ │ ├── cloud_of_fog_cycle.tscn
│ │ ├── cloud_of_fog_small.tscn
│ │ ├── cripple_target.tscn
│ │ ├── crushing_wave.tscn
│ │ ├── crypt_fiend_eggsack.tscn
│ │ ├── cyclone_target.tscn
│ │ ├── death_and_decay.tscn
│ │ ├── death_coil.tscn
│ │ ├── death_explode.tscn
│ │ ├── devour.tscn
│ │ ├── dispel_magic_target.tscn
│ │ ├── doom_death.tscn
│ │ ├── effects_container.gd
│ │ ├── faerie_dragon_missile.tscn
│ │ ├── firelord_death_explode.tscn
│ │ ├── flame_strike_embers.tscn
│ │ ├── flower_aura.tscn
│ │ ├── frag_boom_spawn.tscn
│ │ ├── freezing_breath.tscn
│ │ ├── freezing_breath_purple.tscn
│ │ ├── frost_armor_damage.tscn
│ │ ├── frost_armor_damage_purple.tscn
│ │ ├── frost_bolt_missile.tscn
│ │ ├── glaive.tscn
│ │ ├── gold_credit.tscn
│ │ ├── healing_wave_target.tscn
│ │ ├── holy_bolt.tscn
│ │ ├── holy_bolt_green.tscn
│ │ ├── howl_caster.tscn
│ │ ├── immolation_damage.tscn
│ │ ├── impale_hit_target.tscn
│ │ ├── impale_target_dust.tscn
│ │ ├── incinerate.tscn
│ │ ├── interpolated_sprite.gd
│ │ ├── keeper_grove_missile.tscn
│ │ ├── level_up.tscn
│ │ ├── mana_burn_target.tscn
│ │ ├── mana_shield_cycle.tscn
│ │ ├── mass_teleport_caster.tscn
│ │ ├── mass_teleport_target.tscn
│ │ ├── monsoon_bolt.tscn
│ │ ├── moonwell_target.tscn
│ │ ├── mortar_missile.tscn
│ │ ├── naga_death.tscn
│ │ ├── ne_cancel_death.tscn
│ │ ├── ne_death.tscn
│ │ ├── placeholder.tscn
│ │ ├── polymorph_target.tscn
│ │ ├── projectile_explosion_astral.tscn
│ │ ├── projectile_explosion_darkness.tscn
│ │ ├── projectile_explosion_fire.tscn
│ │ ├── projectile_explosion_ice.tscn
│ │ ├── projectile_explosion_iron.tscn
│ │ ├── projectile_explosion_nature.tscn
│ │ ├── projectile_explosion_storm.tscn
│ │ ├── purge_buff_target.tscn
│ │ ├── quillspray.tscn
│ │ ├── raise_skeleton.tscn
│ │ ├── replenish_mana.tscn
│ │ ├── revive_human.tscn
│ │ ├── roar.tscn
│ │ ├── roots.tscn
│ │ ├── shackle.tscn
│ │ ├── shockwave_missile.tscn
│ │ ├── silence_area.tscn
│ │ ├── small_flame_spawn.tscn
│ │ ├── spell_aiil.tscn
│ │ ├── spell_ailb.tscn
│ │ ├── spell_aima.tscn
│ │ ├── spell_aire.tscn
│ │ ├── spell_aire_flat.tscn
│ │ ├── spell_aiso.tscn
│ │ ├── spell_alim.tscn
│ │ ├── spell_breaker_target.tscn
│ │ ├── spirit_link_target.tscn
│ │ ├── stampede_missile_death.tscn
│ │ ├── starfall_target.tscn
│ │ ├── stun_visual.tscn
│ │ ├── target_arrow.gd
│ │ ├── target_arrow.tscn
│ │ ├── thunder_clap.tscn
│ │ ├── undead_dissipate.tscn
│ │ ├── upgrade_tower.tscn
│ │ ├── vampiric_aura.tscn
│ │ ├── voodoo_aura.tscn
│ │ ├── warstomp_caster.tscn
│ │ ├── wind_shear.tscn
│ │ ├── wisp_explode.tscn
│ │ ├── witch_doctor_ward.tscn
│ │ ├── ziggurat_frost_missile.tscn
│ │ └── zombify_target.tscn
│ ├── enums/
│ │ ├── README.md
│ │ ├── armor_type.gd
│ │ ├── attack_type.gd
│ │ ├── buff_group_mode.gd
│ │ ├── builder_tier.gd
│ │ ├── creep_category.gd
│ │ ├── creep_size.gd
│ │ ├── difficulty.gd
│ │ ├── display_mode.gd
│ │ ├── element.gd
│ │ ├── game_mode.gd
│ │ ├── item_type.gd
│ │ ├── language.gd
│ │ ├── modification_type.gd
│ │ ├── player_mode.gd
│ │ ├── rarity.gd
│ │ └── team_mode.gd
│ ├── game_scene/
│ │ ├── build_space.gd
│ │ ├── build_tower.gd
│ │ ├── camera_controller.gd
│ │ ├── chat_commands.gd
│ │ ├── combat_log_storage.gd
│ │ ├── game_client.gd
│ │ ├── game_client.tscn
│ │ ├── game_host.gd
│ │ ├── game_host.tscn
│ │ ├── game_scene.gd
│ │ ├── game_scene.tscn
│ │ ├── game_time.gd
│ │ ├── horadric_cube.gd
│ │ ├── manual_timer.gd
│ │ ├── mouse_state.gd
│ │ ├── move_item.gd
│ │ ├── select_point_for_cast.gd
│ │ ├── select_target_for_cast.gd
│ │ ├── select_unit.gd
│ │ ├── team_container.gd
│ │ └── tutorial_controller.gd
│ ├── items/
│ │ ├── README.md
│ │ ├── item.gd
│ │ ├── item_behavior.gd
│ │ ├── item_behaviors/
│ │ │ ├── aqueous_vapor.gd
│ │ │ ├── arcane_book_of_power.gd
│ │ │ ├── arcane_oil_of_lore.gd
│ │ │ ├── arcane_script.gd
│ │ │ ├── arms_dealer.gd
│ │ │ ├── artifact_of_skadi.gd
│ │ │ ├── backpack.gd
│ │ │ ├── ball_lightning.gd
│ │ │ ├── bartucs_spirit.gd
│ │ │ ├── basics_of_calculus.gd
│ │ │ ├── bhaals_essence.gd
│ │ │ ├── blaster_staff.gd
│ │ │ ├── bloodthirsty_wheel_of_fortune.gd
│ │ │ ├── bloody_key.gd
│ │ │ ├── bones_of_essence.gd
│ │ │ ├── bonks_face.gd
│ │ │ ├── book_of_force.gd
│ │ │ ├── book_of_knowledge.gd
│ │ │ ├── brimstone_helmet.gd
│ │ │ ├── chameleon_glaive.gd
│ │ │ ├── chameleons_soul.gd
│ │ │ ├── charged_disk.gd
│ │ │ ├── chrono_jumper.gd
│ │ │ ├── circle_of_power.gd
│ │ │ ├── commander.gd
│ │ │ ├── consumable_chicken.gd
│ │ │ ├── consumable_hobbit.gd
│ │ │ ├── consumable_piggy.gd
│ │ │ ├── consumable_plant.gd
│ │ │ ├── crescent_stone.gd
│ │ │ ├── crit_blade.gd
│ │ │ ├── cruel_torch.gd
│ │ │ ├── currency_converter.gd
│ │ │ ├── cursed_claw.gd
│ │ │ ├── dagger_of_bane.gd
│ │ │ ├── dark_matter_trident.gd
│ │ │ ├── deep_shadows.gd
│ │ │ ├── distorted_idol.gd
│ │ │ ├── divine_book_of_omnipotence.gd
│ │ │ ├── dooms_ensign.gd
│ │ │ ├── elunes_bow.gd
│ │ │ ├── empty_item_behavior.gd
│ │ │ ├── enchanted_knives.gd
│ │ │ ├── essence_of_rot.gd
│ │ │ ├── even_more_magical_hammer.gd
│ │ │ ├── excalibur.gd
│ │ │ ├── eye_of_true_sight.gd
│ │ │ ├── faithful_staff.gd
│ │ │ ├── fist_of_doom.gd
│ │ │ ├── flag_of_the_allegiance.gd
│ │ │ ├── forcefield_generator.gd
│ │ │ ├── fragmentation_round.gd
│ │ │ ├── frog_pipe.gd
│ │ │ ├── glaive_of_supreme_follow_up.gd
│ │ │ ├── golden_decoration.gd
│ │ │ ├── golden_trident.gd
│ │ │ ├── granite_hammer.gd
│ │ │ ├── grounding_gloves.gd
│ │ │ ├── haunted_hand.gd
│ │ │ ├── helm_of_insanity.gd
│ │ │ ├── hippogryph_egg.gd
│ │ │ ├── holy_hand_grenade.gd
│ │ │ ├── item_template_advanced.gd
│ │ │ ├── jah_rakals_fury.gd
│ │ │ ├── jewels_of_the_moon.gd
│ │ │ ├── jungle_stalkers_doll.gd
│ │ │ ├── libram_of_grace.gd
│ │ │ ├── lich_mask.gd
│ │ │ ├── liquid_gold.gd
│ │ │ ├── lucky_gem.gd
│ │ │ ├── lunar_essence.gd
│ │ │ ├── magic_conductor.gd
│ │ │ ├── magic_gloves.gd
│ │ │ ├── magic_hammer.gd
│ │ │ ├── magic_link.gd
│ │ │ ├── magnetic_field.gd
│ │ │ ├── mana_stone.gd
│ │ │ ├── medallion_of_opulence.gd
│ │ │ ├── mefis_rocket.gd
│ │ │ ├── mighty_trees_acorns.gd
│ │ │ ├── mindleecher.gd
│ │ │ ├── mine_cart.gd
│ │ │ ├── mini_forest_troll.gd
│ │ │ ├── mining_tools.gd
│ │ │ ├── mystical_shell.gd
│ │ │ ├── nerminds_eye.gd
│ │ │ ├── never-ending_keg.gd
│ │ │ ├── oil_of_lore.gd
│ │ │ ├── old_hunter.gd
│ │ │ ├── optimists_preserved_face.gd
│ │ │ ├── orb_of_souls.gd
│ │ │ ├── overcharge_shot.gd
│ │ │ ├── pendant_of_mana_supremacy.gd
│ │ │ ├── pendant_of_promptness.gd
│ │ │ ├── phase_gloves.gd
│ │ │ ├── plain_staff.gd
│ │ │ ├── pocket_emporium.gd
│ │ │ ├── polarisator.gd
│ │ │ ├── portable_tombstone.gd
│ │ │ ├── priest_figurine.gd
│ │ │ ├── purifying_gloves.gd
│ │ │ ├── ritual_talisman.gd
│ │ │ ├── scroll_of_piercing_magic.gd
│ │ │ ├── scroll_of_speed.gd
│ │ │ ├── scroll_of_strength.gd
│ │ │ ├── seekers_arcane_oil.gd
│ │ │ ├── seekers_oil.gd
│ │ │ ├── share_knowledge.gd
│ │ │ ├── shining_rock.gd
│ │ │ ├── shrapnel_ammunition.gd
│ │ │ ├── sign_of_energy_infusion.gd
│ │ │ ├── silver_armor.gd
│ │ │ ├── sleeve_of_rage.gd
│ │ │ ├── soul_collectors_cloak.gd
│ │ │ ├── soul_collectors_scythe.gd
│ │ │ ├── soul_extractor.gd
│ │ │ ├── spear_of_loki.gd
│ │ │ ├── speed_demons_reward.gd
│ │ │ ├── spellbook_of_item_mastery.gd
│ │ │ ├── spider_broach.gd
│ │ │ ├── spiderling.gd
│ │ │ ├── staff_of_essence.gd
│ │ │ ├── staff_of_the_wild_equus.gd
│ │ │ ├── stasis_trap.gd
│ │ │ ├── strange_item.gd
│ │ │ ├── stunner.gd
│ │ │ ├── sword_of_decay.gd
│ │ │ ├── sword_of_reckoning.gd
│ │ │ ├── the_divine_wings_of_tragedy.gd
│ │ │ ├── toy_boy.gd
│ │ │ ├── unstable_current.gd
│ │ │ ├── unyielding_maul.gd
│ │ │ ├── vampiric_skull.gd
│ │ │ ├── wand_of_mana_zap.gd
│ │ │ ├── wanted_list.gd
│ │ │ ├── war_drum.gd
│ │ │ ├── wise_mans_cooking_recipe.gd
│ │ │ ├── wizards_soul.gd
│ │ │ ├── wooden_leg.gd
│ │ │ ├── workbench.gd
│ │ │ └── writers_knowledge.gd
│ │ ├── item_container.gd
│ │ ├── item_drop.gd
│ │ ├── item_drop.tscn
│ │ └── tower_item_container.gd
│ ├── map/
│ │ ├── buildable_area.gd
│ │ ├── buildable_area.tscn
│ │ ├── map.gd
│ │ ├── map_big.tscn
│ │ └── map_small.tscn
│ ├── missions/
│ │ ├── instances/
│ │ │ ├── mission_120_in_60min.gd
│ │ │ ├── mission_240_in_120min.gd
│ │ │ ├── mission_35_food_or_less.gd
│ │ │ ├── mission_empty.gd
│ │ │ ├── mission_no_items.gd
│ │ │ ├── mission_no_oils.gd
│ │ │ ├── mission_only_astral_towers.gd
│ │ │ ├── mission_only_common_uncommon.gd
│ │ │ ├── mission_only_darkness_towers.gd
│ │ │ ├── mission_only_fire_towers.gd
│ │ │ ├── mission_only_ice_towers.gd
│ │ │ ├── mission_only_iron_towers.gd
│ │ │ ├── mission_only_nature_towers.gd
│ │ │ └── mission_only_storm_towers.gd
│ │ ├── mission.gd
│ │ ├── mission_manager.gd
│ │ └── mission_manager.tscn
│ ├── player/
│ │ ├── auto_oil.gd
│ │ ├── camera_origin.gd
│ │ ├── camera_origin.tscn
│ │ ├── player.gd
│ │ ├── player.tscn
│ │ ├── team.gd
│ │ ├── team.tscn
│ │ └── tower_stash.gd
│ ├── projectiles/
│ │ ├── projectile.gd
│ │ ├── projectile.tscn
│ │ ├── projectile_type.gd
│ │ └── projectile_visuals/
│ │ ├── ball_lightning_projectile.tscn
│ │ ├── default_projectile.gd
│ │ ├── default_projectile.tscn
│ │ ├── energy_ball.tscn
│ │ ├── flying_pork.tscn
│ │ ├── omnislasher_mirror_image.tscn
│ │ └── quillspray_projectile.tscn
│ ├── singletons/
│ │ ├── README.md
│ │ ├── button_sounds.gd
│ │ ├── combat_log.gd
│ │ ├── config.gd
│ │ ├── constants.gd
│ │ ├── effect.gd
│ │ ├── elapsed_timer.gd
│ │ ├── event_bus.gd
│ │ ├── experience.gd
│ │ ├── experience_password.gd
│ │ ├── globals.gd
│ │ ├── group_manager.gd
│ │ ├── item_drop_calc.gd
│ │ ├── messages.gd
│ │ ├── mission_status.gd
│ │ ├── mission_tracking.gd
│ │ ├── nakama_connection.gd
│ │ ├── player_experience.gd
│ │ ├── player_manager.gd
│ │ ├── preloads.gd
│ │ ├── properties/
│ │ │ ├── README.md
│ │ │ ├── ability_properties.gd
│ │ │ ├── aura_properties.gd
│ │ │ ├── autocast_properties.gd
│ │ │ ├── builder_properties.gd
│ │ │ ├── item_properties.gd
│ │ │ ├── mission_properties.gd
│ │ │ ├── recipe_properties.gd
│ │ │ ├── tower_properties.gd
│ │ │ ├── tutorial_properties.gd
│ │ │ ├── wave_special_properties.gd
│ │ │ └── wisdom_upgrade_properties.gd
│ │ ├── rich_texts.gd
│ │ ├── sanitize_text.gd
│ │ ├── secrets.gd
│ │ ├── settings.gd
│ │ ├── sfx.gd
│ │ ├── sfx_paths.gd
│ │ ├── tower_distribution.gd
│ │ ├── tower_sprites.gd
│ │ ├── unit_icons.gd
│ │ ├── utils.gd
│ │ ├── vector_utils.gd
│ │ └── wave_special.gd
│ ├── spells/
│ │ ├── spell_blizzard.gd
│ │ ├── spell_blizzard.tscn
│ │ ├── spell_chain_lightning.gd
│ │ ├── spell_chain_lightning.tscn
│ │ ├── spell_dummy.gd
│ │ ├── spell_dummy.tscn
│ │ ├── spell_forked_lightning.gd
│ │ ├── spell_forked_lightning.tscn
│ │ ├── spell_swarm.gd
│ │ ├── spell_swarm.tscn
│ │ └── spell_type.gd
│ ├── sprites/
│ │ ├── lightning_animation.tscn
│ │ └── pulsing_dot.tscn
│ ├── tests/
│ │ ├── README.md
│ │ ├── playtest_bot.gd
│ │ ├── test_horadric_tool.gd
│ │ ├── test_item_drop_chances.gd
│ │ ├── test_items_tool.gd
│ │ ├── test_tool.gd
│ │ ├── test_tower_sprite_size.gd
│ │ └── test_towers_tool.gd
│ ├── towers/
│ │ ├── README.md
│ │ ├── autocast.gd
│ │ ├── autocast.tscn
│ │ ├── event.gd
│ │ ├── multiboard_values.gd
│ │ ├── range_data.gd
│ │ ├── range_indicator.gd
│ │ ├── range_indicator.tscn
│ │ ├── tower.gd
│ │ ├── tower.tscn
│ │ ├── tower_behavior.gd
│ │ ├── tower_behavior_template.gd
│ │ ├── tower_behaviors/
│ │ │ ├── afflicted_obelisk.gd
│ │ │ ├── ancient_energy_converter.gd
│ │ │ ├── annoyed_tree.gd
│ │ │ ├── arcane_storm.gd
│ │ │ ├── area_roaster.gd
│ │ │ ├── ash_geyser.gd
│ │ │ ├── astral_lantern.gd
│ │ │ ├── astral_rift.gd
│ │ │ ├── baby_tuskin.gd
│ │ │ ├── ball_lightning_accelerator.gd
│ │ │ ├── basic_knowledge.gd
│ │ │ ├── black_dragon_roost.gd
│ │ │ ├── black_rock_totem.gd
│ │ │ ├── bomb_turret.gd
│ │ │ ├── bone_shrine.gd
│ │ │ ├── bonk_the_living_mountain.gd
│ │ │ ├── broken_cage.gd
│ │ │ ├── broken_circle_of_wind.gd
│ │ │ ├── broken_fire_pit.gd
│ │ │ ├── broken_lightning_rod.gd
│ │ │ ├── bronze_dragon_roost.gd
│ │ │ ├── buried_soul.gd
│ │ │ ├── burning_watchtower.gd
│ │ │ ├── burrow.gd
│ │ │ ├── caged_fire.gd
│ │ │ ├── cenarion.gd
│ │ │ ├── chaining_storm.gd
│ │ │ ├── chaos_warlock.gd
│ │ │ ├── charged_obelisk.gd
│ │ │ ├── chilled_spire.gd
│ │ │ ├── cloud_warrior.gd
│ │ │ ├── cloudy_temple_of_absorption.gd
│ │ │ ├── coconut_sapling.gd
│ │ │ ├── coin_machine.gd
│ │ │ ├── cold_obelisk.gd
│ │ │ ├── cold_troll.gd
│ │ │ ├── contraption.gd
│ │ │ ├── crimson_wyrm.gd
│ │ │ ├── cruel_fire.gd
│ │ │ ├── cursed_grounds.gd
│ │ │ ├── cute_small_spider.gd
│ │ │ ├── dark_battery.gd
│ │ │ ├── death_knight.gd
│ │ │ ├── dimensional_flux_collector.gd
│ │ │ ├── dragon_sorcerer.gd
│ │ │ ├── drake_whisperer.gd
│ │ │ ├── dreadlord.gd
│ │ │ ├── dutchmans_grave.gd
│ │ │ ├── dwarven_forgery.gd
│ │ │ ├── ebonfrost_crystal.gd
│ │ │ ├── embershell_turtle_hatchling.gd
│ │ │ ├── empty_tower_behavior.gd
│ │ │ ├── energy_junction.gd
│ │ │ ├── essence_of_fury.gd
│ │ │ ├── felweed.gd
│ │ │ ├── fenced_flames.gd
│ │ │ ├── fiery_dog.gd
│ │ │ ├── fire_battery.gd
│ │ │ ├── fire_star.gd
│ │ │ ├── firestorm_cell.gd
│ │ │ ├── fisherman.gd
│ │ │ ├── forest_archer.gd
│ │ │ ├── forest_protectress.gd
│ │ │ ├── forest_troll.gd
│ │ │ ├── frost_root.gd
│ │ │ ├── frosty_rock.gd
│ │ │ ├── frozen_well.gd
│ │ │ ├── garden_of_eden.gd
│ │ │ ├── gatling_gun.gd
│ │ │ ├── genis_sage.gd
│ │ │ ├── geothermal_extractor.gd
│ │ │ ├── glaive_master.gd
│ │ │ ├── glowing_solar_orb.gd
│ │ │ ├── gnoll_thunder_mage.gd
│ │ │ ├── goblin_stronghold.gd
│ │ │ ├── grab-o-bot.gd
│ │ │ ├── green_dragon_roost.gd
│ │ │ ├── green_lightning.gd
│ │ │ ├── greyfang.gd
│ │ │ ├── gryphon_rider.gd
│ │ │ ├── hall_of_souls.gd
│ │ │ ├── harby.gd
│ │ │ ├── harpy_witch.gd
│ │ │ ├── haunted_rubble.gd
│ │ │ ├── healing_obelisk.gd
│ │ │ ├── helicopter_zone.gd
│ │ │ ├── hell_bat.gd
│ │ │ ├── holy_energy.gd
│ │ │ ├── ice_battery.gd
│ │ │ ├── icy_core.gd
│ │ │ ├── icy_skulls.gd
│ │ │ ├── icy_spirit.gd
│ │ │ ├── igloo.gd
│ │ │ ├── inexperienced_huntress.gd
│ │ │ ├── inflamed_stone.gd
│ │ │ ├── initiate_elementalist.gd
│ │ │ ├── it.gd
│ │ │ ├── jungle_stalker.gd
│ │ │ ├── kraken.gd
│ │ │ ├── lesser_elemental_ghost.gd
│ │ │ ├── lesser_priest.gd
│ │ │ ├── lesser_skeletal_mage.gd
│ │ │ ├── lesser_wolves_den.gd
│ │ │ ├── library_of_alexandria.gd
│ │ │ ├── lich_king.gd
│ │ │ ├── lightning_eye.gd
│ │ │ ├── lightning_generator.gd
│ │ │ ├── lightning_totem.gd
│ │ │ ├── little_phoenix.gd
│ │ │ ├── living_volcano.gd
│ │ │ ├── lunar_emitter.gd
│ │ │ ├── lunar_sentinel.gd
│ │ │ ├── magic_battery.gd
│ │ │ ├── magic_mushroom.gd
│ │ │ ├── magna_warrior.gd
│ │ │ ├── mana-touched_drake.gd
│ │ │ ├── marine.gd
│ │ │ ├── meteor_totem.gd
│ │ │ ├── militia_watchtower.gd
│ │ │ ├── miner.gd
│ │ │ ├── minor_magic_ruin.gd
│ │ │ ├── mister_fireflies.gd
│ │ │ ├── monolith_of_chaos.gd
│ │ │ ├── morphling.gd
│ │ │ ├── mossy_acid_sprayer.gd
│ │ │ ├── mud_golem.gd
│ │ │ ├── nature_sprites.gd
│ │ │ ├── necromantic_altar.gd
│ │ │ ├── nortrom_the_silencer.gd
│ │ │ ├── nuclear_missile_launcher.gd
│ │ │ ├── obelisk_of_fortuity.gd
│ │ │ ├── owl_of_wisdom.gd
│ │ │ ├── particle_accelerator.gd
│ │ │ ├── phantom.gd
│ │ │ ├── plagued_crypt.gd
│ │ │ ├── planar_gate.gd
│ │ │ ├── poison_battery.gd
│ │ │ ├── polar_bear_cub.gd
│ │ │ ├── portal_to_swine_purgatory.gd
│ │ │ ├── prince_of_lightning.gd
│ │ │ ├── princess_of_light.gd
│ │ │ ├── razorboar_thornweaver.gd
│ │ │ ├── red_ball_lightning.gd
│ │ │ ├── regenerating_well.gd
│ │ │ ├── rooted_chasm.gd
│ │ │ ├── rotted_flashing_grave.gd
│ │ │ ├── rowing_boat.gd
│ │ │ ├── ruined_wind_tower.gd
│ │ │ ├── rundown_iron_sentry.gd
│ │ │ ├── sacred_altar.gd
│ │ │ ├── sacrificial_lamb.gd
│ │ │ ├── safirons_cold_grave.gd
│ │ │ ├── scales.gd
│ │ │ ├── sea_turtle.gd
│ │ │ ├── servant_of_the_twin_flames.gd
│ │ │ ├── sewer_connection.gd
│ │ │ ├── shadow.gd
│ │ │ ├── shaman.gd
│ │ │ ├── shard_of_souls.gd
│ │ │ ├── silver_knight.gd
│ │ │ ├── skink.gd
│ │ │ ├── small_bug_nest.gd
│ │ │ ├── small_fire_sprayer.gd
│ │ │ ├── small_frost_fire.gd
│ │ │ ├── small_ice_mine.gd
│ │ │ ├── small_light.gd
│ │ │ ├── small_ray_blaster.gd
│ │ │ ├── small_serpent_ward.gd
│ │ │ ├── small_torch.gd
│ │ │ ├── sniper.gd
│ │ │ ├── solar_collector.gd
│ │ │ ├── solar_emitter.gd
│ │ │ ├── sorceress.gd
│ │ │ ├── soul_vault.gd
│ │ │ ├── soulflame_device.gd
│ │ │ ├── spell_collector.gd
│ │ │ ├── spider_queen.gd
│ │ │ ├── star_gazer.gd
│ │ │ ├── storm_battery.gd
│ │ │ ├── storm_coil.gd
│ │ │ ├── storm_focus.gd
│ │ │ ├── stormy_dog.gd
│ │ │ ├── sun_crusader.gd
│ │ │ ├── taita_the_hermit.gd
│ │ │ ├── teacher.gd
│ │ │ ├── tentacle_spawn.gd
│ │ │ ├── the_conduit.gd
│ │ │ ├── the_council_of_demons.gd
│ │ │ ├── the_fire_lord.gd
│ │ │ ├── the_frozen_wyrm.gd
│ │ │ ├── the_furnace.gd
│ │ │ ├── the_omnislasher.gd
│ │ │ ├── the_steam_engine.gd
│ │ │ ├── thief_apprentice.gd
│ │ │ ├── tidewater_stream.gd
│ │ │ ├── time_manipulator.gd
│ │ │ ├── timevault.gd
│ │ │ ├── tiny_storm_lantern.gd
│ │ │ ├── tombstone.gd
│ │ │ ├── tundra_stalker.gd
│ │ │ ├── undisturbed_crypt.gd
│ │ │ ├── valor.gd
│ │ │ ├── village_witch.gd
│ │ │ ├── void_drake.gd
│ │ │ ├── vulshok_the_berserker.gd
│ │ │ ├── warrior_of_light.gd
│ │ │ ├── wild_warbeast.gd
│ │ │ ├── witch_doctor.gd
│ │ │ ├── wooden_trap.gd
│ │ │ ├── xeno_research_facility.gd
│ │ │ ├── ymir.gd
│ │ │ ├── young_northern_troll.gd
│ │ │ ├── zealot.gd
│ │ │ └── zeus.gd
│ │ ├── tower_preview.gd
│ │ ├── tower_preview.tscn
│ │ └── tower_sprites/
│ │ ├── abandoned_pit_1.tscn
│ │ ├── abandoned_pit_2.tscn
│ │ ├── abandoned_pit_3.tscn
│ │ ├── abandoned_pit_4.tscn
│ │ ├── abandoned_pit_5.tscn
│ │ ├── abominable_snowman_1.tscn
│ │ ├── abominable_snowman_2.tscn
│ │ ├── abominable_snowman_3.tscn
│ │ ├── abominable_snowman_4.tscn
│ │ ├── abominable_snowman_5.tscn
│ │ ├── afflicted_obelisk_1.tscn
│ │ ├── afflicted_obelisk_2.tscn
│ │ ├── afflicted_obelisk_3.tscn
│ │ ├── afflicted_obelisk_4.tscn
│ │ ├── ancient_energy_converter_1.tscn
│ │ ├── annoyed_tree_1.tscn
│ │ ├── annoyed_tree_2.tscn
│ │ ├── annoyed_tree_3.tscn
│ │ ├── annoyed_tree_4.tscn
│ │ ├── arcane_storm_1.tscn
│ │ ├── area_roaster_1.tscn
│ │ ├── area_roaster_2.tscn
│ │ ├── area_roaster_3.tscn
│ │ ├── ash_geyser_1.tscn
│ │ ├── ash_geyser_2.tscn
│ │ ├── ash_geyser_3.tscn
│ │ ├── ash_geyser_4.tscn
│ │ ├── ash_geyser_5.tscn
│ │ ├── astral_lantern_1.tscn
│ │ ├── astral_lantern_2.tscn
│ │ ├── astral_lantern_3.tscn
│ │ ├── astral_lantern_4.tscn
│ │ ├── astral_rift_1.tscn
│ │ ├── baby_plant_1.tscn
│ │ ├── baby_plant_2.tscn
│ │ ├── baby_plant_3.tscn
│ │ ├── baby_plant_4.tscn
│ │ ├── baby_plant_5.tscn
│ │ ├── baby_plant_6.tscn
│ │ ├── baby_tuskin_1.tscn
│ │ ├── baby_tuskin_2.tscn
│ │ ├── baby_tuskin_3.tscn
│ │ ├── ball_lightning_accelerator_1.tscn
│ │ ├── ball_lightning_accelerator_2.tscn
│ │ ├── basic_knowledge_1.tscn
│ │ ├── basic_knowledge_2.tscn
│ │ ├── basic_knowledge_3.tscn
│ │ ├── basic_knowledge_4.tscn
│ │ ├── basic_knowledge_5.tscn
│ │ ├── black_dragon_roost_1.tscn
│ │ ├── black_rock_totem_1.tscn
│ │ ├── bomb_turret_1.tscn
│ │ ├── bomb_turret_2.tscn
│ │ ├── bone_shrine_1.tscn
│ │ ├── bone_shrine_2.tscn
│ │ ├── bone_shrine_3.tscn
│ │ ├── bonk_the_living_mountain_1.tscn
│ │ ├── broken_cage_1.tscn
│ │ ├── broken_cage_2.tscn
│ │ ├── broken_cage_3.tscn
│ │ ├── broken_cage_4.tscn
│ │ ├── broken_cage_5.tscn
│ │ ├── broken_circle_of_wind_1.tscn
│ │ ├── broken_circle_of_wind_2.tscn
│ │ ├── broken_circle_of_wind_3.tscn
│ │ ├── broken_circle_of_wind_4.tscn
│ │ ├── broken_circle_of_wind_5.tscn
│ │ ├── broken_fire_pit_1.tscn
│ │ ├── broken_fire_pit_2.tscn
│ │ ├── broken_fire_pit_3.tscn
│ │ ├── broken_fire_pit_4.tscn
│ │ ├── broken_fire_pit_5.tscn
│ │ ├── broken_lightning_rod_1.tscn
│ │ ├── broken_lightning_rod_2.tscn
│ │ ├── broken_lightning_rod_3.tscn
│ │ ├── broken_lightning_rod_4.tscn
│ │ ├── broken_lightning_rod_5.tscn
│ │ ├── bronze_dragon_roost_1.tscn
│ │ ├── buried_soul_1.tscn
│ │ ├── buried_soul_2.tscn
│ │ ├── buried_soul_3.tscn
│ │ ├── buried_soul_4.tscn
│ │ ├── burning_watchtower_1.tscn
│ │ ├── burning_watchtower_2.tscn
│ │ ├── burning_watchtower_3.tscn
│ │ ├── burning_watchtower_4.tscn
│ │ ├── burrow_1.tscn
│ │ ├── burrow_2.tscn
│ │ ├── burrow_3.tscn
│ │ ├── burrow_4.tscn
│ │ ├── caged_fire_1.tscn
│ │ ├── caged_fire_2.tscn
│ │ ├── cenarion_1.tscn
│ │ ├── chaining_storm_1.tscn
│ │ ├── chaos_warlock_1.tscn
│ │ ├── chaos_warlock_2.tscn
│ │ ├── charged_obelisk_1.tscn
│ │ ├── chilled_spire_1.tscn
│ │ ├── chilled_spire_2.tscn
│ │ ├── cloud_warrior_1.tscn
│ │ ├── cloud_warrior_2.tscn
│ │ ├── cloud_warrior_3.tscn
│ │ ├── cloud_warrior_4.tscn
│ │ ├── cloud_warrior_5.tscn
│ │ ├── cloudy_temple_of_absorption_1.tscn
│ │ ├── coconut_sapling_1.tscn
│ │ ├── coconut_sapling_2.tscn
│ │ ├── coin_machine_1.tscn
│ │ ├── coin_machine_2.tscn
│ │ ├── cold_obelisk_1.tscn
│ │ ├── cold_obelisk_2.tscn
│ │ ├── cold_obelisk_3.tscn
│ │ ├── cold_troll_1.tscn
│ │ ├── cold_troll_2.tscn
│ │ ├── cold_troll_3.tscn
│ │ ├── cold_troll_4.tscn
│ │ ├── contraption_1.tscn
│ │ ├── contraption_2.tscn
│ │ ├── contraption_3.tscn
│ │ ├── contraption_4.tscn
│ │ ├── crimson_wyrm_1.tscn
│ │ ├── cruel_fire_1.tscn
│ │ ├── cruel_fire_2.tscn
│ │ ├── cruel_fire_3.tscn
│ │ ├── cursed_grounds_1.tscn
│ │ ├── cursed_grounds_2.tscn
│ │ ├── cursed_grounds_3.tscn
│ │ ├── cute_small_spider_1.tscn
│ │ ├── cute_small_spider_2.tscn
│ │ ├── cute_small_spider_3.tscn
│ │ ├── cute_small_spider_4.tscn
│ │ ├── dark_battery_1.tscn
│ │ ├── dark_battery_2.tscn
│ │ ├── dark_battery_3.tscn
│ │ ├── dark_fire_pit_1.tscn
│ │ ├── dark_fire_pit_2.tscn
│ │ ├── dark_fire_pit_3.tscn
│ │ ├── dark_fire_pit_4.tscn
│ │ ├── dark_fire_pit_5.tscn
│ │ ├── death_knight_1.tscn
│ │ ├── dimensional_flux_collector_1.tscn
│ │ ├── dragon_sorcerer_1.tscn
│ │ ├── drake_whisperer_1.tscn
│ │ ├── dreadlord_1.tscn
│ │ ├── dutchmans_grave_1.tscn
│ │ ├── dwarven_forgery_1.tscn
│ │ ├── ebonfrost_crystal_1.tscn
│ │ ├── embershell_turtle_hatchling_1.tscn
│ │ ├── embershell_turtle_hatchling_2.tscn
│ │ ├── embershell_turtle_hatchling_3.tscn
│ │ ├── embershell_turtle_hatchling_4.tscn
│ │ ├── embershell_turtle_hatchling_5.tscn
│ │ ├── energy_junction_1.tscn
│ │ ├── energy_junction_2.tscn
│ │ ├── energy_junction_3.tscn
│ │ ├── essence_of_fury_1.tscn
│ │ ├── essence_of_fury_2.tscn
│ │ ├── essence_of_fury_3.tscn
│ │ ├── essence_of_fury_4.tscn
│ │ ├── essence_of_fury_5.tscn
│ │ ├── felweed_1.tscn
│ │ ├── felweed_2.tscn
│ │ ├── felweed_3.tscn
│ │ ├── felweed_4.tscn
│ │ ├── felweed_5.tscn
│ │ ├── felweed_6.tscn
│ │ ├── fenced_flames_1.tscn
│ │ ├── fenced_flames_2.tscn
│ │ ├── fenced_flames_3.tscn
│ │ ├── fenced_flames_4.tscn
│ │ ├── fiery_dog_1.tscn
│ │ ├── fiery_dog_2.tscn
│ │ ├── fiery_dog_3.tscn
│ │ ├── fiery_dog_4.tscn
│ │ ├── fiery_dog_5.tscn
│ │ ├── fiery_pebble_1.tscn
│ │ ├── fiery_pebble_2.tscn
│ │ ├── fiery_pebble_3.tscn
│ │ ├── fiery_pebble_4.tscn
│ │ ├── fiery_pebble_5.tscn
│ │ ├── fiery_pebble_6.tscn
│ │ ├── fire_battery_1.tscn
│ │ ├── fire_battery_2.tscn
│ │ ├── fire_battery_3.tscn
│ │ ├── fire_star_1.tscn
│ │ ├── firestorm_cell_1.tscn
│ │ ├── firestorm_cell_2.tscn
│ │ ├── firestorm_cell_3.tscn
│ │ ├── firestorm_cell_4.tscn
│ │ ├── fisherman_1.tscn
│ │ ├── forest_archer_1.tscn
│ │ ├── forest_archer_2.tscn
│ │ ├── forest_archer_3.tscn
│ │ ├── forest_protectress_1.tscn
│ │ ├── forest_troll_1.tscn
│ │ ├── forest_troll_2.tscn
│ │ ├── forest_troll_3.tscn
│ │ ├── frost_root_1.tscn
│ │ ├── frost_root_2.tscn
│ │ ├── frost_root_3.tscn
│ │ ├── frost_root_4.tscn
│ │ ├── frost_root_5.tscn
│ │ ├── frost_root_6.tscn
│ │ ├── frosty_rock_1.tscn
│ │ ├── frosty_rock_2.tscn
│ │ ├── frosty_rock_3.tscn
│ │ ├── frosty_rock_4.tscn
│ │ ├── frozen_well_1.tscn
│ │ ├── garden_of_eden_1.tscn
│ │ ├── gatling_gun_1.tscn
│ │ ├── genis_sage_1.tscn
│ │ ├── geothermal_extractor_1.tscn
│ │ ├── geothermal_extractor_2.tscn
│ │ ├── glaive_master_1.tscn
│ │ ├── glowing_solar_orb_1.tscn
│ │ ├── glowing_solar_orb_2.tscn
│ │ ├── glowing_solar_orb_3.tscn
│ │ ├── glowing_solar_orb_4.tscn
│ │ ├── glowing_solar_orb_5.tscn
│ │ ├── gnoll_thunder_mage_1.tscn
│ │ ├── gnoll_thunder_mage_2.tscn
│ │ ├── gnoll_thunder_mage_3.tscn
│ │ ├── goblin_stronghold_1.tscn
│ │ ├── grab-o-bot_1.tscn
│ │ ├── green_dragon_roost_1.tscn
│ │ ├── green_lightning_1.tscn
│ │ ├── green_lightning_2.tscn
│ │ ├── green_lightning_3.tscn
│ │ ├── green_lightning_4.tscn
│ │ ├── greyfang_1.tscn
│ │ ├── gryphon_rider_1.tscn
│ │ ├── hall_of_souls_1.tscn
│ │ ├── hall_of_souls_2.tscn
│ │ ├── hall_of_souls_3.tscn
│ │ ├── harby_1.tscn
│ │ ├── harpy_witch_1.tscn
│ │ ├── harpy_witch_2.tscn
│ │ ├── haunted_rubble_1.tscn
│ │ ├── haunted_rubble_2.tscn
│ │ ├── haunted_rubble_3.tscn
│ │ ├── haunted_rubble_4.tscn
│ │ ├── haunted_rubble_5.tscn
│ │ ├── healing_obelisk_1.tscn
│ │ ├── healing_obelisk_2.tscn
│ │ ├── healing_obelisk_3.tscn
│ │ ├── healing_obelisk_4.tscn
│ │ ├── helicopter_zone_1.tscn
│ │ ├── hell_bat_1.tscn
│ │ ├── hell_bat_2.tscn
│ │ ├── hell_bat_3.tscn
│ │ ├── holy_energy_1.tscn
│ │ ├── ice_battery_1.tscn
│ │ ├── ice_battery_2.tscn
│ │ ├── ice_battery_3.tscn
│ │ ├── icy_core_1.tscn
│ │ ├── icy_core_2.tscn
│ │ ├── icy_skulls_1.tscn
│ │ ├── icy_skulls_2.tscn
│ │ ├── icy_skulls_3.tscn
│ │ ├── icy_skulls_4.tscn
│ │ ├── icy_spirit_1.tscn
│ │ ├── icy_spirit_2.tscn
│ │ ├── icy_spirit_3.tscn
│ │ ├── igloo_1.tscn
│ │ ├── igloo_2.tscn
│ │ ├── igloo_3.tscn
│ │ ├── inexperienced_huntress_1.tscn
│ │ ├── inexperienced_huntress_2.tscn
│ │ ├── inexperienced_huntress_3.tscn
│ │ ├── inflamed_stone_1.tscn
│ │ ├── inflamed_stone_2.tscn
│ │ ├── inflamed_stone_3.tscn
│ │ ├── initiate_elementalist_1.tscn
│ │ ├── initiate_elementalist_2.tscn
│ │ ├── initiate_elementalist_3.tscn
│ │ ├── initiate_elementalist_4.tscn
│ │ ├── it_1.tscn
│ │ ├── jungle_stalker_1.tscn
│ │ ├── jungle_stalker_2.tscn
│ │ ├── jungle_stalker_3.tscn
│ │ ├── kraken_1.tscn
│ │ ├── lesser_astral_defender_1.tscn
│ │ ├── lesser_astral_defender_2.tscn
│ │ ├── lesser_astral_defender_3.tscn
│ │ ├── lesser_astral_defender_4.tscn
│ │ ├── lesser_astral_defender_5.tscn
│ │ ├── lesser_dark_defender_1.tscn
│ │ ├── lesser_dark_defender_2.tscn
│ │ ├── lesser_dark_defender_3.tscn
│ │ ├── lesser_dark_defender_4.tscn
│ │ ├── lesser_dark_defender_5.tscn
│ │ ├── lesser_elemental_ghost_1.tscn
│ │ ├── lesser_elemental_ghost_2.tscn
│ │ ├── lesser_elemental_ghost_3.tscn
│ │ ├── lesser_elemental_ghost_4.tscn
│ │ ├── lesser_elemental_ghost_5.tscn
│ │ ├── lesser_flamy_defender_1.tscn
│ │ ├── lesser_flamy_defender_2.tscn
│ │ ├── lesser_flamy_defender_3.tscn
│ │ ├── lesser_flamy_defender_4.tscn
│ │ ├── lesser_flamy_defender_5.tscn
│ │ ├── lesser_ice_defender_1.tscn
│ │ ├── lesser_ice_defender_2.tscn
│ │ ├── lesser_ice_defender_3.tscn
│ │ ├── lesser_ice_defender_4.tscn
│ │ ├── lesser_ice_defender_5.tscn
│ │ ├── lesser_iron_defender_1.tscn
│ │ ├── lesser_iron_defender_2.tscn
│ │ ├── lesser_iron_defender_3.tscn
│ │ ├── lesser_iron_defender_4.tscn
│ │ ├── lesser_iron_defender_5.tscn
│ │ ├── lesser_natural_defender_1.tscn
│ │ ├── lesser_natural_defender_2.tscn
│ │ ├── lesser_natural_defender_3.tscn
│ │ ├── lesser_natural_defender_4.tscn
│ │ ├── lesser_natural_defender_5.tscn
│ │ ├── lesser_priest_1.tscn
│ │ ├── lesser_priest_2.tscn
│ │ ├── lesser_priest_3.tscn
│ │ ├── lesser_priest_4.tscn
│ │ ├── lesser_priest_5.tscn
│ │ ├── lesser_skeletal_mage_1.tscn
│ │ ├── lesser_skeletal_mage_2.tscn
│ │ ├── lesser_skeletal_mage_3.tscn
│ │ ├── lesser_skeletal_mage_4.tscn
│ │ ├── lesser_storm_defender_1.tscn
│ │ ├── lesser_storm_defender_2.tscn
│ │ ├── lesser_storm_defender_3.tscn
│ │ ├── lesser_storm_defender_4.tscn
│ │ ├── lesser_storm_defender_5.tscn
│ │ ├── lesser_wolves_den_1.tscn
│ │ ├── lesser_wolves_den_2.tscn
│ │ ├── lesser_wolves_den_3.tscn
│ │ ├── library_of_alexandria_1.tscn
│ │ ├── lich_king_1.tscn
│ │ ├── lightning_eye_1.tscn
│ │ ├── lightning_generator_1.tscn
│ │ ├── lightning_generator_2.tscn
│ │ ├── lightning_generator_3.tscn
│ │ ├── lightning_generator_4.tscn
│ │ ├── lightning_totem_1.tscn
│ │ ├── lightning_totem_2.tscn
│ │ ├── lightning_totem_3.tscn
│ │ ├── little_phoenix_1.tscn
│ │ ├── little_phoenix_2.tscn
│ │ ├── little_phoenix_3.tscn
│ │ ├── living_volcano_1.tscn
│ │ ├── lunar_emitter_1.tscn
│ │ ├── lunar_emitter_2.tscn
│ │ ├── lunar_sentinel_1.tscn
│ │ ├── lunar_sentinel_2.tscn
│ │ ├── lunar_sentinel_3.tscn
│ │ ├── lunar_sentinel_4.tscn
│ │ ├── magic_battery_1.tscn
│ │ ├── magic_battery_2.tscn
│ │ ├── magic_battery_3.tscn
│ │ ├── magic_mushroom_1.tscn
│ │ ├── magna_warrior_1.tscn
│ │ ├── magna_warrior_2.tscn
│ │ ├── magna_warrior_3.tscn
│ │ ├── magna_warrior_4.tscn
│ │ ├── magna_warrior_5.tscn
│ │ ├── mana-touched_drake_1.tscn
│ │ ├── mana-touched_drake_2.tscn
│ │ ├── mana-touched_drake_3.tscn
│ │ ├── mana-touched_drake_4.tscn
│ │ ├── marine_1.tscn
│ │ ├── marine_2.tscn
│ │ ├── meteor_totem_1.tscn
│ │ ├── militia_watchtower_1.tscn
│ │ ├── militia_watchtower_2.tscn
│ │ ├── militia_watchtower_3.tscn
│ │ ├── militia_watchtower_4.tscn
│ │ ├── miner_1.tscn
│ │ ├── miner_2.tscn
│ │ ├── miner_3.tscn
│ │ ├── minor_magic_ruin_1.tscn
│ │ ├── minor_magic_ruin_2.tscn
│ │ ├── minor_magic_ruin_3.tscn
│ │ ├── minor_magic_ruin_4.tscn
│ │ ├── minor_magic_ruin_5.tscn
│ │ ├── minor_magic_ruin_6.tscn
│ │ ├── mister_fireflies_1.tscn
│ │ ├── mister_fireflies_2.tscn
│ │ ├── mister_fireflies_3.tscn
│ │ ├── monolith_of_chaos_1.tscn
│ │ ├── morphling_1.tscn
│ │ ├── mossy_acid_sprayer_1.tscn
│ │ ├── mossy_acid_sprayer_2.tscn
│ │ ├── mossy_acid_sprayer_3.tscn
│ │ ├── mossy_acid_sprayer_4.tscn
│ │ ├── mossy_acid_sprayer_5.tscn
│ │ ├── mud_golem_1.tscn
│ │ ├── nature_sprites_1.tscn
│ │ ├── nature_sprites_2.tscn
│ │ ├── nature_sprites_3.tscn
│ │ ├── necromantic_altar_1.tscn
│ │ ├── necromantic_altar_2.tscn
│ │ ├── necromantic_altar_3.tscn
│ │ ├── necromantic_altar_4.tscn
│ │ ├── nortrom_the_silencer_1.tscn
│ │ ├── nuclear_missile_launcher_1.tscn
│ │ ├── obelisk_of_fortuity_1.tscn
│ │ ├── obelisk_of_fortuity_2.tscn
│ │ ├── obelisk_of_fortuity_3.tscn
│ │ ├── obelisk_of_fortuity_4.tscn
│ │ ├── obelisk_of_fortuity_5.tscn
│ │ ├── owl_of_wisdom_1.tscn
│ │ ├── owl_of_wisdom_2.tscn
│ │ ├── particle_accelerator_1.tscn
│ │ ├── particle_accelerator_2.tscn
│ │ ├── particle_accelerator_3.tscn
│ │ ├── phantom_1.tscn
│ │ ├── phantom_2.tscn
│ │ ├── phantom_3.tscn
│ │ ├── phantom_4.tscn
│ │ ├── phantom_5.tscn
│ │ ├── plagued_crypt_1.tscn
│ │ ├── planar_gate_1.tscn
│ │ ├── poison_battery_1.tscn
│ │ ├── poison_battery_2.tscn
│ │ ├── poison_battery_3.tscn
│ │ ├── polar_bear_cub_1.tscn
│ │ ├── polar_bear_cub_2.tscn
│ │ ├── polar_bear_cub_3.tscn
│ │ ├── portal_to_swine_purgatory_1.tscn
│ │ ├── portal_to_swine_purgatory_2.tscn
│ │ ├── portal_to_swine_purgatory_3.tscn
│ │ ├── prince_of_lightning_1.tscn
│ │ ├── prince_of_lightning_2.tscn
│ │ ├── princess_of_light_1.tscn
│ │ ├── princess_of_light_2.tscn
│ │ ├── razorboar_thornweaver_1.tscn
│ │ ├── razorboar_thornweaver_2.tscn
│ │ ├── razorboar_thornweaver_3.tscn
│ │ ├── red_ball_lightning_1.tscn
│ │ ├── red_ball_lightning_2.tscn
│ │ ├── regenerating_well_1.tscn
│ │ ├── regenerating_well_2.tscn
│ │ ├── regenerating_well_3.tscn
│ │ ├── rooted_chasm_1.tscn
│ │ ├── rooted_chasm_2.tscn
│ │ ├── rooted_chasm_3.tscn
│ │ ├── rooted_chasm_4.tscn
│ │ ├── rotted_flashing_grave_1.tscn
│ │ ├── rotted_flashing_grave_2.tscn
│ │ ├── rotted_flashing_grave_3.tscn
│ │ ├── rotted_flashing_grave_4.tscn
│ │ ├── rotted_flashing_grave_5.tscn
│ │ ├── rotted_flashing_grave_6.tscn
│ │ ├── rowing_boat_1.tscn
│ │ ├── rowing_boat_2.tscn
│ │ ├── rowing_boat_3.tscn
│ │ ├── rowing_boat_4.tscn
│ │ ├── ruined_monolith_1.tscn
│ │ ├── ruined_monolith_2.tscn
│ │ ├── ruined_monolith_3.tscn
│ │ ├── ruined_monolith_4.tscn
│ │ ├── ruined_monolith_5.tscn
│ │ ├── ruined_monolith_6.tscn
│ │ ├── ruined_storm_cap_1.tscn
│ │ ├── ruined_storm_cap_2.tscn
│ │ ├── ruined_storm_cap_3.tscn
│ │ ├── ruined_storm_cap_4.tscn
│ │ ├── ruined_storm_cap_5.tscn
│ │ ├── ruined_storm_cap_6.tscn
│ │ ├── ruined_sun_pedestal_1.tscn
│ │ ├── ruined_sun_pedestal_2.tscn
│ │ ├── ruined_sun_pedestal_3.tscn
│ │ ├── ruined_sun_pedestal_4.tscn
│ │ ├── ruined_sun_pedestal_5.tscn
│ │ ├── ruined_sun_pedestal_6.tscn
│ │ ├── ruined_sun_pedestal_7.tscn
│ │ ├── ruined_wind_tower_1.tscn
│ │ ├── ruined_wind_tower_2.tscn
│ │ ├── ruined_wind_tower_3.tscn
│ │ ├── ruined_wind_tower_4.tscn
│ │ ├── rundown_iron_sentry_1.tscn
│ │ ├── rundown_iron_sentry_2.tscn
│ │ ├── rundown_iron_sentry_3.tscn
│ │ ├── sacred_altar_1.tscn
│ │ ├── sacrificial_lamb_1.tscn
│ │ ├── sacrificial_lamb_2.tscn
│ │ ├── safirons_cold_grave_1.tscn
│ │ ├── scales_1.tscn
│ │ ├── sea_turtle_1.tscn
│ │ ├── sea_turtle_2.tscn
│ │ ├── sea_turtle_3.tscn
│ │ ├── servant_of_the_twin_flames_1.tscn
│ │ ├── servant_of_the_twin_flames_2.tscn
│ │ ├── sewer_connection_1.tscn
│ │ ├── sewer_connection_2.tscn
│ │ ├── sewer_connection_3.tscn
│ │ ├── sewer_connection_4.tscn
│ │ ├── shadow_1.tscn
│ │ ├── shaman_1.tscn
│ │ ├── shaman_2.tscn
│ │ ├── shaman_3.tscn
│ │ ├── shard_of_souls_1.tscn
│ │ ├── shard_of_souls_2.tscn
│ │ ├── silver_knight_1.tscn
│ │ ├── silver_knight_2.tscn
│ │ ├── skink_1.tscn
│ │ ├── skink_2.tscn
│ │ ├── skink_3.tscn
│ │ ├── skink_4.tscn
│ │ ├── skink_5.tscn
│ │ ├── small_brazier_1.tscn
│ │ ├── small_brazier_2.tscn
│ │ ├── small_brazier_3.tscn
│ │ ├── small_brazier_4.tscn
│ │ ├── small_bug_nest_1.tscn
│ │ ├── small_bug_nest_2.tscn
│ │ ├── small_bug_nest_3.tscn
│ │ ├── small_bug_nest_4.tscn
│ │ ├── small_cactus_1.tscn
│ │ ├── small_cactus_2.tscn
│ │ ├── small_cactus_3.tscn
│ │ ├── small_cactus_4.tscn
│ │ ├── small_cactus_5.tscn
│ │ ├── small_cactus_6.tscn
│ │ ├── small_fire_sprayer_1.tscn
│ │ ├── small_fire_sprayer_2.tscn
│ │ ├── small_fire_sprayer_3.tscn
│ │ ├── small_fire_sprayer_4.tscn
│ │ ├── small_fire_sprayer_5.tscn
│ │ ├── small_fire_sprayer_6.tscn
│ │ ├── small_frost_fire_1.tscn
│ │ ├── small_frost_fire_2.tscn
│ │ ├── small_frost_fire_3.tscn
│ │ ├── small_frost_fire_4.tscn
│ │ ├── small_frost_fire_5.tscn
│ │ ├── small_frozen_mushroom_1.tscn
│ │ ├── small_frozen_mushroom_2.tscn
│ │ ├── small_frozen_mushroom_3.tscn
│ │ ├── small_frozen_mushroom_4.tscn
│ │ ├── small_frozen_mushroom_5.tscn
│ │ ├── small_ice_mine_1.tscn
│ │ ├── small_ice_mine_2.tscn
│ │ ├── small_ice_mine_3.tscn
│ │ ├── small_ice_mine_4.tscn
│ │ ├── small_light_1.tscn
│ │ ├── small_light_2.tscn
│ │ ├── small_light_3.tscn
│ │ ├── small_light_4.tscn
│ │ ├── small_light_5.tscn
│ │ ├── small_pocket_rocket_1.tscn
│ │ ├── small_pocket_rocket_2.tscn
│ │ ├── small_pocket_rocket_3.tscn
│ │ ├── small_pocket_rocket_4.tscn
│ │ ├── small_pocket_rocket_5.tscn
│ │ ├── small_ray_blaster_1.tscn
│ │ ├── small_ray_blaster_2.tscn
│ │ ├── small_ray_blaster_3.tscn
│ │ ├── small_ray_blaster_4.tscn
│ │ ├── small_ray_blaster_5.tscn
│ │ ├── small_serpent_ward_1.tscn
│ │ ├── small_serpent_ward_2.tscn
│ │ ├── small_serpent_ward_3.tscn
│ │ ├── small_serpent_ward_4.tscn
│ │ ├── small_torch_1.tscn
│ │ ├── small_torch_2.tscn
│ │ ├── small_torch_3.tscn
│ │ ├── small_torch_4.tscn
│ │ ├── small_torch_5.tscn
│ │ ├── sniper_1.tscn
│ │ ├── sniper_2.tscn
│ │ ├── sniper_3.tscn
│ │ ├── sniper_4.tscn
│ │ ├── snowy_pebble_1.tscn
│ │ ├── snowy_pebble_2.tscn
│ │ ├── snowy_pebble_3.tscn
│ │ ├── snowy_pebble_4.tscn
│ │ ├── snowy_pebble_5.tscn
│ │ ├── snowy_pebble_6.tscn
│ │ ├── solar_collector_1.tscn
│ │ ├── solar_collector_2.tscn
│ │ ├── solar_emitter_1.tscn
│ │ ├── solar_emitter_2.tscn
│ │ ├── sorceress_1.tscn
│ │ ├── soul_vault_1.tscn
│ │ ├── soulflame_device_1.tscn
│ │ ├── spell_collector_1.tscn
│ │ ├── spell_collector_2.tscn
│ │ ├── spider_queen_1.tscn
│ │ ├── star_gazer_1.tscn
│ │ ├── star_gazer_2.tscn
│ │ ├── star_gazer_3.tscn
│ │ ├── star_gazer_4.tscn
│ │ ├── storm_battery_1.tscn
│ │ ├── storm_battery_2.tscn
│ │ ├── storm_battery_3.tscn
│ │ ├── storm_coil_1.tscn
│ │ ├── storm_focus_1.tscn
│ │ ├── stormy_dog_1.tscn
│ │ ├── stormy_dog_2.tscn
│ │ ├── stormy_dog_3.tscn
│ │ ├── stormy_dog_4.tscn
│ │ ├── stormy_dog_5.tscn
│ │ ├── sun_crusader_1.tscn
│ │ ├── sun_crusader_2.tscn
│ │ ├── taita_the_hermit_1.tscn
│ │ ├── teacher_1.tscn
│ │ ├── teacher_2.tscn
│ │ ├── teacher_3.tscn
│ │ ├── teacher_4.tscn
│ │ ├── teacher_5.tscn
│ │ ├── teacher_6.tscn
│ │ ├── tentacle_spawn_1.tscn
│ │ ├── tentacle_spawn_2.tscn
│ │ ├── tentacle_spawn_3.tscn
│ │ ├── tentacle_spawn_4.tscn
│ │ ├── tentacle_spawn_5.tscn
│ │ ├── tentacle_spawn_6.tscn
│ │ ├── the_conduit_1.tscn
│ │ ├── the_council_of_demons_1.tscn
│ │ ├── the_fire_lord_1.tscn
│ │ ├── the_frozen_wyrm_1.tscn
│ │ ├── the_furnace_1.tscn
│ │ ├── the_omnislasher_1.tscn
│ │ ├── the_steam_engine_1.tscn
│ │ ├── thief_apprentice_1.tscn
│ │ ├── thief_apprentice_2.tscn
│ │ ├── thief_apprentice_3.tscn
│ │ ├── thief_apprentice_4.tscn
│ │ ├── thief_apprentice_5.tscn
│ │ ├── tidewater_stream_1.tscn
│ │ ├── time_manipulator_1.tscn
│ │ ├── timevault_1.tscn
│ │ ├── tiny_shrub_1.tscn
│ │ ├── tiny_shrub_2.tscn
│ │ ├── tiny_shrub_3.tscn
│ │ ├── tiny_shrub_4.tscn
│ │ ├── tiny_shrub_5.tscn
│ │ ├── tiny_shrub_6.tscn
│ │ ├── tiny_storm_lantern_1.tscn
│ │ ├── tiny_storm_lantern_2.tscn
│ │ ├── tiny_storm_lantern_3.tscn
│ │ ├── tiny_storm_lantern_4.tscn
│ │ ├── tombstone_1.tscn
│ │ ├── tombstone_2.tscn
│ │ ├── tombstone_3.tscn
│ │ ├── tombstone_4.tscn
│ │ ├── tombstone_5.tscn
│ │ ├── tombstone_6.tscn
│ │ ├── trash_heap_1.tscn
│ │ ├── trash_heap_2.tscn
│ │ ├── trash_heap_3.tscn
│ │ ├── trash_heap_4.tscn
│ │ ├── trash_heap_5.tscn
│ │ ├── trash_heap_6.tscn
│ │ ├── tree_stump_1.tscn
│ │ ├── tree_stump_2.tscn
│ │ ├── tree_stump_3.tscn
│ │ ├── tree_stump_4.tscn
│ │ ├── tree_stump_5.tscn
│ │ ├── tundra_stalker_1.tscn
│ │ ├── tundra_stalker_2.tscn
│ │ ├── tundra_stalker_3.tscn
│ │ ├── tundra_stalker_4.tscn
│ │ ├── tundra_stalker_5.tscn
│ │ ├── undisturbed_crypt_1.tscn
│ │ ├── undisturbed_crypt_2.tscn
│ │ ├── undisturbed_crypt_3.tscn
│ │ ├── undisturbed_crypt_4.tscn
│ │ ├── valor_1.tscn
│ │ ├── village_witch_1.tscn
│ │ ├── village_witch_2.tscn
│ │ ├── village_witch_3.tscn
│ │ ├── village_witch_4.tscn
│ │ ├── void_drake_1.tscn
│ │ ├── void_drake_2.tscn
│ │ ├── vulshok_the_berserker_1.tscn
│ │ ├── warrior_of_light_1.tscn
│ │ ├── warrior_of_light_2.tscn
│ │ ├── warrior_of_light_3.tscn
│ │ ├── wild_warbeast_1.tscn
│ │ ├── witch_doctor_1.tscn
│ │ ├── wooden_trap_1.tscn
│ │ ├── wooden_trap_2.tscn
│ │ ├── wooden_trap_3.tscn
│ │ ├── wooden_trap_4.tscn
│ │ ├── wooden_trap_5.tscn
│ │ ├── xeno_research_facility_1.tscn
│ │ ├── ymir_1.tscn
│ │ ├── young_northern_troll_1.tscn
│ │ ├── young_northern_troll_2.tscn
│ │ ├── young_northern_troll_3.tscn
│ │ ├── zealot_1.tscn
│ │ ├── zealot_2.tscn
│ │ ├── zealot_3.tscn
│ │ ├── zealot_4.tscn
│ │ └── zeus_1.tscn
│ ├── ui/
│ │ ├── buttons/
│ │ │ ├── ability_button.gd
│ │ │ ├── ability_button.tscn
│ │ │ ├── auto_mode_indicator.gd
│ │ │ ├── auto_mode_indicator.tscn
│ │ │ ├── autocast_button.gd
│ │ │ ├── autocast_button.tscn
│ │ │ ├── buff_group_button.gd
│ │ │ ├── buff_group_button.tscn
│ │ │ ├── builder_button.tscn
│ │ │ ├── button_tooltip.gd
│ │ │ ├── button_tooltip.tscn
│ │ │ ├── button_with_rich_tooltip.gd
│ │ │ ├── element_button.gd
│ │ │ ├── element_button.tscn
│ │ │ ├── empty_unit_button.gd
│ │ │ ├── empty_unit_button.tscn
│ │ │ ├── freshness_indicator.gd
│ │ │ ├── freshness_indicator.tscn
│ │ │ ├── inventory_slot_button.tscn
│ │ │ ├── item_button.gd
│ │ │ ├── item_button.tscn
│ │ │ ├── item_button_inner.gd
│ │ │ ├── menu_expanding_button.gd
│ │ │ ├── menu_expanding_button.tscn
│ │ │ ├── rarity_background.gd
│ │ │ ├── rarity_background.tscn
│ │ │ ├── recipe_button.gd
│ │ │ ├── recipe_button.tscn
│ │ │ ├── speed_button.tscn
│ │ │ ├── time_indicator.gd
│ │ │ ├── time_indicator.tscn
│ │ │ ├── tower_button.gd
│ │ │ ├── tower_button.tscn
│ │ │ ├── wisdom_upgrade_button.gd
│ │ │ └── wisdom_upgrade_button.tscn
│ │ ├── dev_controls/
│ │ │ ├── dev_controls.gd
│ │ │ ├── dev_controls.tscn
│ │ │ ├── signals_control.gd
│ │ │ ├── signals_control.tscn
│ │ │ ├── wave_control.gd
│ │ │ └── wave_control.tscn
│ │ ├── filter_buttons/
│ │ │ ├── element_filter.gd
│ │ │ ├── element_filter.tscn
│ │ │ ├── filter_button.tscn
│ │ │ ├── filter_button_element.gd
│ │ │ ├── filter_button_element.tscn
│ │ │ ├── filter_button_item_type.gd
│ │ │ ├── filter_button_item_type.tscn
│ │ │ ├── filter_button_rarity.gd
│ │ │ ├── filter_button_rarity.tscn
│ │ │ ├── item_type_filter.gd
│ │ │ ├── item_type_filter.tscn
│ │ │ ├── rarity_filter.gd
│ │ │ └── rarity_filter.tscn
│ │ ├── game_menu/
│ │ │ ├── credits_menu.gd
│ │ │ ├── credits_menu.tscn
│ │ │ ├── game_menu.gd
│ │ │ ├── game_menu.tscn
│ │ │ ├── help_menu.gd
│ │ │ ├── help_menu.tscn
│ │ │ ├── help_menu_tab.gd
│ │ │ ├── help_menu_tab.tscn
│ │ │ ├── settings_menu.gd
│ │ │ └── settings_menu.tscn
│ │ ├── hud/
│ │ │ ├── OneTimeHelpPopup.tscn
│ │ │ ├── build_version_label.gd
│ │ │ ├── build_version_label.tscn
│ │ │ ├── builder_menu.gd
│ │ │ ├── builder_menu.tscn
│ │ │ ├── combat_log_window.gd
│ │ │ ├── combat_log_window.tscn
│ │ │ ├── desync_indicator.tscn
│ │ │ ├── elements_menu.gd
│ │ │ ├── elements_menu.tscn
│ │ │ ├── floating_text.gd
│ │ │ ├── floating_text.tscn
│ │ │ ├── flying_item.gd
│ │ │ ├── flying_item.tscn
│ │ │ ├── game_speed_controller.gd
│ │ │ ├── game_speed_controller.tscn
│ │ │ ├── hud.gd
│ │ │ ├── hud.tscn
│ │ │ ├── label_with_rich_tooltip.gd
│ │ │ ├── mission_track_indicator.gd
│ │ │ ├── mission_track_indicator.tscn
│ │ │ ├── mission_tracker_container.gd
│ │ │ ├── mission_tracker_container.tscn
│ │ │ ├── movable_window.gd
│ │ │ ├── movable_window.tscn
│ │ │ ├── multiplayer_pause_indicator.tscn
│ │ │ ├── one_time_help_popup.gd
│ │ │ ├── rich_text_label_with_rich_tooltip.gd
│ │ │ ├── texture_rect_with_rich_tooltip.gd
│ │ │ ├── tutorial_menu.gd
│ │ │ └── tutorial_menu.tscn
│ │ ├── item_stash_menu/
│ │ │ ├── item_stash_menu.gd
│ │ │ └── item_stash_menu.tscn
│ │ ├── player_resource_display/
│ │ │ ├── player_resource_display.gd
│ │ │ ├── player_resource_display.tscn
│ │ │ ├── resource_status_panel.gd
│ │ │ └── resource_status_panel.tscn
│ │ ├── title_screen/
│ │ │ ├── configure_singleplayer_menu.gd
│ │ │ ├── configure_singleplayer_menu.tscn
│ │ │ ├── connecting_to_server_indicator.tscn
│ │ │ ├── encyclopedia_generic_tab.gd
│ │ │ ├── encyclopedia_generic_tab.tscn
│ │ │ ├── encyclopedia_items.gd
│ │ │ ├── encyclopedia_items.tscn
│ │ │ ├── encyclopedia_menu.gd
│ │ │ ├── encyclopedia_menu.tscn
│ │ │ ├── encyclopedia_towers.gd
│ │ │ ├── encyclopedia_towers.tscn
│ │ │ ├── export_exp_menu.gd
│ │ │ ├── export_exp_menu.tscn
│ │ │ ├── import_exp_menu.gd
│ │ │ ├── import_exp_menu.tscn
│ │ │ ├── lan_match/
│ │ │ │ ├── create_lan_match_menu.gd
│ │ │ │ ├── create_lan_match_menu.tscn
│ │ │ │ ├── lan_connect_menu.gd
│ │ │ │ ├── lan_connect_menu.tscn
│ │ │ │ ├── lan_lobby_menu.gd
│ │ │ │ ├── lan_lobby_menu.tscn
│ │ │ │ ├── setup_lan_game.gd
│ │ │ │ └── setup_lan_game.tscn
│ │ │ ├── match_config.gd
│ │ │ ├── match_config_panel.gd
│ │ │ ├── match_config_panel.tscn
│ │ │ ├── message_popup.gd
│ │ │ ├── message_popup.tscn
│ │ │ ├── missions_menu/
│ │ │ │ ├── mission_card.gd
│ │ │ │ ├── mission_card.tscn
│ │ │ │ ├── missions_menu.gd
│ │ │ │ ├── missions_menu.tscn
│ │ │ │ ├── missions_menu_tab.gd
│ │ │ │ └── missions_menu_tab.tscn
│ │ │ ├── notification_panel.gd
│ │ │ ├── notification_panel.tscn
│ │ │ ├── online/
│ │ │ │ ├── create_online_match_menu.gd
│ │ │ │ ├── create_online_match_menu.tscn
│ │ │ │ ├── match_card.gd
│ │ │ │ ├── match_card.tscn
│ │ │ │ ├── online_lobby_menu.gd
│ │ │ │ ├── online_lobby_menu.tscn
│ │ │ │ ├── online_match_list_menu.gd
│ │ │ │ ├── online_match_list_menu.tscn
│ │ │ │ ├── setup_online_game.gd
│ │ │ │ └── setup_online_game.tscn
│ │ │ ├── profile_menu.gd
│ │ │ ├── profile_menu.tscn
│ │ │ ├── title_screen.gd
│ │ │ ├── title_screen.tscn
│ │ │ ├── wisdom_upgrade_menu.gd
│ │ │ └── wisdom_upgrade_menu.tscn
│ │ ├── top_left_menu/
│ │ │ ├── game_stats.gd
│ │ │ ├── game_stats.tscn
│ │ │ ├── plus_mode_label.gd
│ │ │ ├── plus_mode_label.tscn
│ │ │ ├── top_left_menu.gd
│ │ │ ├── top_left_menu.tscn
│ │ │ ├── wave_status.gd
│ │ │ └── wave_status.tscn
│ │ ├── tower_stash_menu/
│ │ │ ├── tower_stash_menu.gd
│ │ │ └── tower_stash_menu.tscn
│ │ └── unit_menu/
│ │ ├── buff_container.gd
│ │ ├── buff_container.tscn
│ │ ├── buff_display.gd
│ │ ├── buff_display.tscn
│ │ ├── buff_group_editor.gd
│ │ ├── buff_group_editor.tscn
│ │ ├── creep_details.gd
│ │ ├── creep_details.tscn
│ │ ├── creep_mini_details.gd
│ │ ├── creep_mini_details.tscn
│ │ ├── item_container_panel.gd
│ │ ├── item_container_panel.tscn
│ │ ├── mini_details_label.tscn
│ │ ├── progress_bar_with_label.gd
│ │ ├── progress_bar_with_label.tscn
│ │ ├── tower_details.gd
│ │ ├── tower_details.tscn
│ │ ├── tower_mini_details.gd
│ │ ├── tower_mini_details.tscn
│ │ ├── unit_menu.gd
│ │ └── unit_menu.tscn
│ └── unit/
│ ├── dummy_unit.gd
│ ├── dummy_unit.tscn
│ ├── iterate.gd
│ ├── selection_indicator.gd
│ └── unit.gd
├── tools/
│ ├── README.md
│ ├── check_buff_icons.gd
│ ├── check_rng_sync.gd
│ ├── check_translations.gd
│ ├── check_tscn_paths_in_scripts.gd
│ ├── convert_blender_export.gd
│ ├── convert_tower_scene_to_sprite.gd
│ ├── create_tilesheet.gd
│ ├── cut_single_tile.gd
│ ├── cut_tiles_into_connectors.gd
│ ├── cut_tiles_into_decorations.gd
│ ├── generate_censored_assets.gd
│ ├── pack_sprite_sheet.gd
│ ├── remove_empty_space_tilesheet.gd
│ ├── remove_sheet_margins.gd
│ ├── rename_files.gd
│ ├── render_8_direction_sprites.py
│ ├── separate_tilesheet.gd
│ ├── show_missing_imports.py
│ └── slice_sheet_into_rows.gd
└── webrtc/
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/CODEOWNERS
================================================
* @Kvel2D @Praytic
================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[INSERT CONTACT METHOD].
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contribution guidance
## How to contribute
You can contribute in different ways:
- Report a bug in Issues
- Write a suggestion in Discussions
- Submit a modification to source code!
For the last one, you will need to download the Godot editor and obtain assets.
Read below to find out how to obtain assets.
## Editing the game in the Godot editor
First, obtain necessary files:
1. Download Godot editor *version 4.3* from the [Godot website](https://godotengine.org).
2. Clone the game repository using Git.
3. Download assets folder from this [Google Drive folder](https://drive.google.com/drive/folders/1U4wTjBu2qo1cInH3IAowsFC5yq56V5uQ?usp=sharing).
4. Copy and paste downloaded assets into 'assets' folder in the game repository.
5. You will see a popup asking whether you want to replace some files - press "Yes".
Then, follow these steps to correctly import assets into Godot editor:
1. Open the game project in the Godot editor.
2. Wait for Godot editor to import assets. Open the "Output" window to confirm that the process is finished. There will be some errors - that's expected.
3. Press Ctrl-S to save changes.
4. Close Godot editor
5. Open a terminal with Git and run this command: $ git status. You should see that some files were modified (by Godot editor).
6. Run this command: $ git restore
7. Open the game project in the Godot editor again.
8. Wait for Godot editor to import assets. This time, there should be no errors.
9. Run this command again: $ git status. There should be no local changes if steps were followed correctly.
Note: Public version of assets contains censored versions of item icons, tower icons and tower sprites. Such assets will look like they are a solid "blue" color.
## Copyright / Contributor License Agreement
Any code you submit will become part of the repository and be distributed under the YouTD2 license. By submitting code to the project you agree that the code is your work and you can give it to the project.
You also agree by submitting your code that you grant all transferrable rights to the code to the project maintainer, including for example re-licensing the code, modifying the code, and distributing it in source or binary forms. Specifically, this includes a requirement that you assign copyright to the project maintainer. For this reason, do not modify any copyright statements in files in any PRs.
================================================
FILE: .github/RCLONE.md
================================================
# Setup rclone
Rclone is an advanced way to sync assets between your computer and google drive.
Note that if you're using the public version of assets (assets_public), you can ignore this page and manually download files from drive.
## Setup steps
1. Install rclone from [here](https://rclone.org/downloads/).
2. Go to this [page](https://console.cloud.google.com/apis/credentials/oauthclient/909699965518-qt5c21qf6r7mr3rg26vkh6nml4s397e7.apps.googleusercontent.com?project=youtd2-385722). Copy and save `client_id` and `client_secret` to a text file. You will need them in the next step.
3. Follow the instructions [here](https://rclone.org/drive/) to configure `rcloud`. When prompted for `client_id` and `client_secret`, use the strings you have copied in the previous step.
4. Check that the remote is installed correctly. This command will print the installed `<remote>`.
```
rclone listremotes
```
5. This command should print the list of folders insides assets in Google Drive.
```
rclone lsd <remote>:assets
```
6. Transfer files to your local.
```
rclone sync -P --filter-from rclone-filter "<remote>:assets" "assets"
```
Now you should be able to run the project inside the Godot editor. If you make changes to a file inside assets folder, make sure to update Google Drive as well. There are two options.
**First option - Google Drive upload.**
1. Upload a file to [Google Drive](https://drive.google.com/drive/u/1/folders/1V9GN1uoX9-mu2J5IoWPaNJU2aC_ejGIA)
2. Run `rclone sync`
3. Generate `.import` by opening the file in the editor
4. Commit `.import` file to remote
**Second option - rclone copy.**
1. Move a file to `assets` folder
2. Generate `.import` by opening the file in the editor
3. Commit `.import` file to remote
4. Upload the file to <remote>.
```
rclone copy -v --filter-from rclone-filter assets <remote>:assets
```
================================================
FILE: .github/TRANSLATING.md
================================================
# Translation guidance
## How to contribute to translation
Translated text strings are stored in texts.csv. This file is not included on Github because it is too big.
Download link: [texts.csv](https://drive.google.com/file/d/1dfaUKx5CoU9oVQQ4DgFVJH_twJ7M5k4Q/view?usp=drive_link).
You can contribute translations like this:
1. Download the texts.csv file
2. Edit the texts.csv file
3. Create new column for your language, for example "es"
4. Add translated strings to that column
Then you can submit the changes like this:
1. Create a new Issue on Github
2. Attach changed texts.csv file to the Issue
3. Follow the format from here: https://github.com/Praytic/youtd2/issues/483
## How to add a new language
This section is intended for developers. If you only want to contribute new translation texts, you can skip this section and let someone else handle adding the new language.
1. Find the locale code here: https://docs.godotengine.org/en/stable/tutorials/i18n/locales.html
2. Create new column in texts.csv with locale code in first row.
3. Close texts.csv and open Godot editor, confirm in editor log that texts.csv was reloaded.
4. Go to Menubar -> Project -> Project Settings -> Localization -> Add. Then add the translation file.
5. Edit src/enums/language.gd. Add new language to the following: "enm", "language_map", "language_option_map", "language_option_locale_map"
6. Open settings_menu.tscn in editor and modify the language OptionButton. Add new language and use the same index as the one in language.gd.
7. Start the game and confirm that new language works.
================================================
FILE: .github/workflows/github-actions-youtd.yml
================================================
name: build-and-publish
# NOTE: disabled this export job because it doesn't work
# with webrtc lib. Webrtc lib files need to be included
# together with the game but this job for some reason fails
# to do it. It only adds executable and .pck file to the
# zip.
# on:
# push:
# # Sequence of patterns matched against refs/heads
# # branches:
# # - workflow*
# # Sequence of patterns matched against refs/tags
# tags:
# - v*
jobs:
setup:
runs-on: ubuntu-latest
name: cache repo with assets
steps:
- uses: actions/checkout@v3
- name: list assets in gdrive
uses: wei/rclone@v1
with:
args: lsf -R --filter-from rclone-filter "assets" | sort > .assets-list
env:
RCLONE_CONF: ${{ secrets.RCLONE_GDRIVE_CONF }}
- name: restore cache
uses: actions/cache@v3
with:
path: assets
key: assets-${{ hashFiles('.assets-list') }}
- name: sync assets from gdrive via rclone
uses: wei/rclone@v1
with:
args: sync -P --filter-from rclone-filter "gdrive:assets" "assets"
env:
RCLONE_CONF: ${{ secrets.RCLONE_GDRIVE_CONF }}
- name: upload repo with assets
id: upload_repo_with_assets
uses: actions/upload-artifact@v3
with:
path: |
./*
!.git/
name: repo-with-assets
- name: generate version for the build
id: version_generation
run: |
latest_tag=$(git ls-remote --tags --sort=-v:refname origin | grep -v 'vrefs/heads/main' | grep -o 'refs/tags/[^^{]*' | sed 's/refs\/tags\///' | head -n 1)
short_hash=$(git rev-parse --short HEAD)
version=${latest_tag:1}
echo "tag_version=${latest_tag}-${short_hash}" | tee -a $GITHUB_OUTPUT
echo "version=${version}" | tee -a $GITHUB_OUTPUT
echo "commit_ref=$GITHUB_REF_NAME" | tee -a $GITHUB_OUTPUT
outputs:
tag_version: ${{ steps.version_generation.outputs.tag_version }}
version: ${{ steps.version_generation.outputs.version }}
commit_ref: ${{ steps.version_generation.outputs.commit_ref }}
export_game:
runs-on: ubuntu-latest
needs: setup
name: export game
steps:
- name: download repo with assets
uses: actions/download-artifact@v3
with:
path: ./
name: repo-with-assets
- name: release requested check
run: |
if [[ ${{ needs.setup.outputs.commit_ref }} =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then
echo "NEED=true" >> "$GITHUB_ENV"
echo 'true'
else
echo "NEED=false" >> "$GITHUB_ENV"
echo 'false'
fi
- name: update project.godot with new version
run: |
project_godot_file="${{ github.workspace }}/project.godot"
sed -i 's/\(config\/version="\).*\("\)/\1'"${{ needs.setup.outputs.tag_version }}"'\2/' "${project_godot_file}"
echo "New project.godot contents:"
cat "${project_godot_file}"
- name: update release version for Sentry lib
run: |
sed -i "s/youtd2@[0-9]\+\.[0-9]\+\.[0-9]\+/youtd2@${{ needs.setup.outputs.version }}/g" "${{ github.workspace }}/build/web/full-size.html"
- name: create .godot dirs
run: |
mkdir -p .godot/{editor,imported}
- name: export game
id: export
uses: firebelley/godot-export@v5.2.0
with:
godot_executable_download_url: https://github.com/godotengine/godot-builds/releases/download/4.1.3-stable/Godot_v4.1.3-stable_linux.x86_64.zip
godot_export_templates_download_url: https://github.com/godotengine/godot-builds/releases/download/4.1.3-stable/Godot_v4.1.3-stable_export_templates.tpz
relative_project_path: ./
export_debug: false
archive_output: true
cache: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: repack web artifact
run: |
zip -uj ${{ steps.export.outputs.archive_directory }}/web.zip ${{ github.workspace }}/build/web/*
cp ${{ github.workspace }}/build/web/* ${{ steps.export.outputs.build_directory }}/web/
- uses: actions/upload-artifact@v3
with:
name: youtd-${{ needs.setup.outputs.tag_version }}
path: ${{ steps.export.outputs.archive_directory }}/*.zip
if-no-files-found: error
outputs:
tag_version: ${{ needs.setup.outputs.tag_version }}
commit_ref: ${{ needs.setup.outputs.commit_ref }}
release_flag: ${{ env.NEED }}
upload_artifacts:
needs: export_game
strategy:
matrix:
platform: [windows, macos, web, linux]
runs-on: ubuntu-latest
steps:
- name: download exported files
uses: actions/download-artifact@v3
with:
name: youtd-${{ needs.export_game.outputs.tag_version }}
path: exported_files
- name: rename artifacts
id: rename_artifacts
run: |
VERSION_TAG="${{ needs.export_game.outputs.tag_version }}"
mv "exported_files/${{ matrix.platform }}.zip" "exported_files/${{ matrix.platform }}-$VERSION_TAG.zip"
echo "${{ matrix.platform }}=exported_files/$platform-$VERSION_TAG.zip" >> $GITHUB_OUTPUT
- name: upload artifacts
id: upload_artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.platform }}-${{ needs.export_game.outputs.tag_version }}
path: exported_files/${{ matrix.platform }}-${{ needs.export_game.outputs.tag_version }}.zip
outputs:
macos_artifact: ${{ steps.rename_artifacts.outputs.macos_artifact }}
linux_artifact: ${{ steps.rename_artifacts.outputs.linux_artifact }}
web_artifact: ${{ steps.rename_artifacts.outputs.web_artifact }}
windows_artifact: ${{ steps.rename_artifacts.outputs.windows_artifact }}
create_release:
name: create release
needs: [upload_artifacts, export_game]
if: needs.export_game.outputs.release_flag == 'true'
runs-on: ubuntu-latest
steps:
- name: show props
run: |
echo "Commit ref: $GITHUB_REF_NAME"
echo "Release tag: ${{ needs.export_game.outputs.commit_ref }}"
- name: download artifacts
uses: actions/download-artifact@v3
with:
path: .
- name: display structure of downloaded files
run: ls -R
working-directory: .
- name: release client
uses: ncipollo/release-action@v1.11.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ needs.export_game.outputs.commit_ref }}
generateReleaseNotes: true
artifacts: ./**/*.zip
clean_up_artifacts:
needs: [create_release, export_game]
runs-on: ubuntu-latest
steps:
- uses: geekyeggo/delete-artifact@v2
with:
name: |
youtd-${{ needs.export_game.outputs.tag_version }}
repo-with-assets
================================================
FILE: .gitignore
================================================
# Godot .gitignore config
#
# Aims to encompass the most commonly found files that we don't want committed
# to Git, such as compilation output, IDE specific files, etc.
#
# It doesn't cover *all* thirdparty IDE extensions under the sun so if you have
# specific needs covered here, you can add them to:
# .git/info/exclude
#
# Or contribute them to this file if they're common enough that a good number of
# users would benefit from the shared rules.
#
# This file is organized by sections, with subsections ordered alphabetically.
# - Build configuration
# - Godot generated files
# - General build output
# - IDE and tool specific
# - Visual Studio specific
# - OS specific
###########################
### Build configuration ###
###########################
/custom.py
misc/hooks/pre-commit-custom-*
#############################
### Godot generated files ###
#############################
# Buildsystem
bin/
*.gen.*
compile_commands.json
platform/windows/godot_res.res
# Generated by Godot binary
.import/
.godot/
/gdnative_interface.h
extension_api.json
logs/
*.translation
# Generated by unit tests
tests/data/*.translation
############################
### General build output ###
############################
# C/C++ generated
*.a
*.ax
*.d
*.dll
*.lib
*.lo
*.o
*.os
*.ox
*.Plo
*.so
# Binutils tmp linker output of the form "stXXXXXX" where "X" is alphanumeric
st[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]
# Python generated
__pycache__/
*.pyc
# Documentation
doc/_build/
# Android
.gradle/
local.properties
*.iml
.gradletasknamecache
project.properties
platform/android/java/*/.cxx/
platform/android/java/*/build/
platform/android/java/*/libs/
# iOS
*.dSYM
# Web platform
*.bc
platform/web/node_modules/
# Misc
*.debug
#############################
### IDE and tool specific ###
#############################
# Automake
.deps/*
.dirstamp
# ccls
.ccls-cache/
# clangd
.clangd/
.cache/
# CLion
cmake-build-debug
# Code::Blocks
*.cbp
*.layout
*.depend
# CodeLite
*.project
*.workspace
.codelite/
# Cppcheck
*.cppcheck
cppcheck-cppcheck-build-dir/
# Eclipse CDT
.cproject
.settings/
*.pydevproject
*.launch
# Gcov and Lcov code coverage
*.gcno
*.gcda
*.gcov.html
*.func.html
*.func-sort-c.html
*index-sort-f.html
*index-sort-l.html
*index.html
godot.info
amber.png
emerald.png
glass.png
ruby.png
snow.png
updown.png
gcov.css
# Geany
*.geany
.geanyprj
# Gprof
gmon.out
# Jetbrains IDEs
.idea/
.fleet/
# Kate
*.kate-swp
# Kdevelop
*.kdev4
# Qt Creator
*.config
*.creator
*.creator.*
*.files
*.includes
*.cflags
*.cxxflags
# SCons
.sconf_temp
.sconsign*.dblite
.scons_env.json
.scons_node_count
# Sourcetrail
*.srctrl*
# Tags
# https://github.com/github/gitignore/blob/master/Global/Tags.gitignore
# Ignore tags created by etags, ctags, gtags (GNU global) and cscope
TAGS
!TAGS/
tags
*.tags
!tags/
gtags.files
GTAGS
GRTAGS
GPATH
cscope.files
cscope.out
cscope.in.out
cscope.po.out
# Vim
*.swo
*.swp
# Visual Studio Code
.vscode/
*.code-workspace
.history/
# Xcode
xcuserdata/
*.xcscmblueprint
*.xccheckout
*.xcodeproj/*
##############################
### Visual Studio specific ###
##############################
# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# Ignore Visual Studio temporary files, build results, and
# files generated by popular Visual Studio add-ons.
# Actual VS project files we don't use
*.sln
*.vcxproj*
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Visual Studio 2017 auto generated files
Generated\ Files/
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# Others
ClientBin/
enc_temp_folder/
~$*
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# Hint file for IntelliSense
cpp.hint
###################
### OS specific ###
###################
# Linux
*~
.directory
# macOS
.DS_Store
__MACOSX
# Windows
# https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
[Tt]humbs.db
[Tt]humbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
*.stackdump
[Dd]esktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msix
*.msm
*.msp
*.lnk
########################
### Project specific ###
########################
/build/windows/YouTD2.zip
/build/linux/YouTD2.zip
/build/macos/YouTD2.zip
/build/web/*
!/build/README.md
!/build/web/full-size.html
!/build/web/loading_screen.mp4
!/build/web/loading_screen.png
override.cfg
/webrtc/*
!/webrtc/README.md
#######################
### Assets specific ###
#######################
# Archives
*.7z
*.br
*.gz
*.tar
*.zip
# Documents
*.pdf
# Images
*.gif
*.ico
*.jpg
*.png
*.psd
*.webp
# Fonts
*.woff2
*.otf
*.ttf
# Audio
*.mp3
*.wav
*.ogg
# Other
*.exe
/assets/secrets/secrets.csv
/assets/secrets/badwords.csv
/assets/texts/texts.csv
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 Icob2Games
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# YouTD 2

YouTD 2 is a remake of the tower defense mod "YouTD" from WC3.
_[itch.io](https://praytic.itch.io/youtd2)_
_[Discord](https://discord.gg/EksA2CfCS9)_
## Contributing
See [CONTRIBUTING.md](.github/CONTRIBUTING.md).
## Matchmaking server
Repository for matchmaking server is [here](https://github.com/Kvel2D/youtd2-server).
## Credits
Developed by [Dmitry Degtyarev](https://github.com/Kvel2D), [Praytic](https://github.com/Praytic) and every direct and indirect [contributors](https://github.com/Praytic/youtd2/graphs/contributors) to the GitHub.
Based on "YouTD" - a WC3 mod created by geX and the YouTD community.
Also thank you to everyone posting feedback and questions on YouTD2 Discord.
## License
YouTD 2 source code is licensed under the [MIT licence](https://github.com/Praytic/youtd2/tree/main?tab=MIT-1-ov-file#readme).
Assets files are licensed under [CC-BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/legalcode).
================================================
FILE: addons/com.heroiclabs.nakama/Nakama.gd
================================================
@tool
extends Node
# The default host address of the server.
const DEFAULT_HOST : String = "127.0.0.1"
# The default port number of the server.
const DEFAULT_PORT : int = 7350
# The default timeout for the connections.
const DEFAULT_TIMEOUT = 3
# The default protocol scheme for the client connection.
const DEFAULT_CLIENT_SCHEME : String = "http"
# The default protocol scheme for the socket connection.
const DEFAULT_SOCKET_SCHEME : String = "ws"
# The default log level for the Nakama logger.
const DEFAULT_LOG_LEVEL = NakamaLogger.LOG_LEVEL.DEBUG
var _http_adapter = null
var logger = NakamaLogger.new()
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS
func get_client_adapter() -> NakamaHTTPAdapter:
if _http_adapter == null:
_http_adapter = NakamaHTTPAdapter.new()
_http_adapter.logger = logger
_http_adapter.name = "NakamaHTTPAdapter"
add_child(_http_adapter)
return _http_adapter
func create_socket_adapter() -> NakamaSocketAdapter:
var adapter = NakamaSocketAdapter.new()
adapter.name = "NakamaWebSocketAdapter"
adapter.logger = logger
add_child(adapter)
return adapter
func create_client(p_server_key : String,
p_host : String = DEFAULT_HOST,
p_port : int = DEFAULT_PORT,
p_scheme : String = DEFAULT_CLIENT_SCHEME,
p_timeout : int = DEFAULT_TIMEOUT,
p_log_level : int = DEFAULT_LOG_LEVEL) -> NakamaClient:
logger._level = p_log_level
return NakamaClient.new(get_client_adapter(), p_server_key, p_scheme, p_host, p_port, p_timeout)
func create_socket(p_host : String = DEFAULT_HOST,
p_port : int = DEFAULT_PORT,
p_scheme : String = DEFAULT_SOCKET_SCHEME) -> NakamaSocket:
return NakamaSocket.new(create_socket_adapter(), p_host, p_port, p_scheme, true)
func create_socket_from(p_client : NakamaClient) -> NakamaSocket:
var scheme = "ws"
if p_client.scheme == "https":
scheme = "wss"
return NakamaSocket.new(create_socket_adapter(), p_client.host, p_client.port, scheme, true)
================================================
FILE: addons/com.heroiclabs.nakama/Satori/NakamaEvent.gd
================================================
extends SatoriAsyncResult
# NOTE: renamed from original "Event" to avoid name conflicts
class_name NakamaEvent
# The name of the event.
var name: String
# The time when the event was triggered.
var timestamp: String
# Optional value.
var value: String
# NakamaEvent metadata, if any.
var metadata: Dictionary
# Optional event ID assigned by the client, used to de-duplicate in retransmission scenarios.
# If not supplied the server will assign a randomly generated unique event identifier.
var id: String
# The event constructor.
# Initializes a new NakamaEvent object.
#
# @param name The name of the event.
# @param timestamp The timestamp of the event.
# @param value The value associated with the event (optional).
# @param metadata The metadata associated with the event (optional).
# @param id The ID of the event (optional).
func _init(name: String, timestamp: float, value: String = "", metadata: Dictionary = {}, id: String = "", p_exception = null):
super(p_exception)
self.name = name
self.timestamp = unix_to_protobuf_timestamp_format(timestamp)
self.value = value
self.metadata = metadata
self.id = id
func to_api_event_dict() -> Dictionary:
return {
"name": self.name,
"timestamp": self.timestamp,
"value": self.value,
"metadata": self.metadata,
"id": self.id
}
func unix_to_protobuf_timestamp_format(unix_time: float) -> String:
# Extract microseconds precision from unix time
var microseconds = int(fmod(unix_time, 1.0) * 1_000_000)
# Convert seconds to datetime structure
var datetime = Time.get_datetime_dict_from_unix_time(int(unix_time))
var year = datetime.year
var month = str(datetime.month).pad_zeros(2)
var day = str(datetime.day).pad_zeros(2)
var hour = str(datetime.hour).pad_zeros(2)
var minute = str(datetime.minute).pad_zeros(2)
var second = str(datetime.second).pad_zeros(2)
var microsecond = str(microseconds).pad_zeros(6)
# Construct the protobuf timestamp format string
var timestamp_str = "%s-%s-%sT%s:%s:%s.%sZ" % [year, month, day, hour, minute, second, microsecond]
return timestamp_str
================================================
FILE: addons/com.heroiclabs.nakama/Satori/SatoriAPI.gd
================================================
### Code generated by codegen/main.go. DO NOT EDIT. ###
extends RefCounted
class_name SatoriAPI
# Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.
class ApiAuthenticateLogoutRequest extends SatoriAsyncResult:
const _SCHEMA = {
"refresh_token": {"name": "_refresh_token", "type": TYPE_STRING, "required": false},
"token": {"name": "_token", "type": TYPE_STRING, "required": false},
}
# Refresh token to invalidate.
var _refresh_token
var refresh_token : String:
get:
return "" if not _refresh_token is String else String(_refresh_token)
# Session token to log out.
var _token
var token : String:
get:
return "" if not _token is String else String(_token)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAuthenticateLogoutRequest:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiAuthenticateLogoutRequest", p_dict), ApiAuthenticateLogoutRequest) as ApiAuthenticateLogoutRequest
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "refresh_token: %s, " % _refresh_token
output += "token: %s, " % _token
output += map_string
return output
# Authenticate against the server with a refresh token.
class ApiAuthenticateRefreshRequest extends SatoriAsyncResult:
const _SCHEMA = {
"refresh_token": {"name": "_refresh_token", "type": TYPE_STRING, "required": false},
}
# Refresh token.
var _refresh_token
var refresh_token : String:
get:
return "" if not _refresh_token is String else String(_refresh_token)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAuthenticateRefreshRequest:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiAuthenticateRefreshRequest", p_dict), ApiAuthenticateRefreshRequest) as ApiAuthenticateRefreshRequest
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "refresh_token: %s, " % _refresh_token
output += map_string
return output
#
class ApiAuthenticateRequest extends SatoriAsyncResult:
const _SCHEMA = {
"custom": {"name": "_custom", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"default": {"name": "_default", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
}
# Optional custom properties to update with this call.
# If not set, properties are left as they are on the server.
var _custom
var custom : Dictionary:
get:
return Dictionary() if not _custom is Dictionary else _custom.duplicate()
# Optional default properties to update with this call.
# If not set, properties are left as they are on the server.
var _default
var default : Dictionary:
get:
return Dictionary() if not _default is Dictionary else _default.duplicate()
# Identity ID. Must be between eight and 128 characters (inclusive).
# Must be an alphanumeric string with only underscores and hyphens allowed.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAuthenticateRequest:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiAuthenticateRequest", p_dict), ApiAuthenticateRequest) as ApiAuthenticateRequest
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
if typeof(_custom) == TYPE_DICTIONARY:
for k in _custom:
map_string += "{%s=%s}, " % [k, _custom[k]]
output += "custom: [%s], " % map_string
map_string = ""
if typeof(_default) == TYPE_DICTIONARY:
for k in _default:
map_string += "{%s=%s}, " % [k, _default[k]]
output += "default: [%s], " % map_string
map_string = ""
output += "id: %s, " % _id
output += map_string
return output
# A single event. Usually, but not necessarily, part of a batch.
class ApiEvent extends SatoriAsyncResult:
const _SCHEMA = {
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
"metadata": {"name": "_metadata", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"name": {"name": "_name", "type": TYPE_STRING, "required": false},
"timestamp": {"name": "_timestamp", "type": TYPE_STRING, "required": false},
"value": {"name": "_value", "type": TYPE_STRING, "required": false},
}
# Optional event ID assigned by the client, used to de-duplicate in retransmission scenarios.
# If not supplied the server will assign a randomly generated unique event identifier.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
# Event metadata, if any.
var _metadata
var metadata : Dictionary:
get:
return Dictionary() if not _metadata is Dictionary else _metadata.duplicate()
# Event name.
var _name
var name : String:
get:
return "" if not _name is String else String(_name)
# The time when the event was triggered on the producer side.
var _timestamp
var timestamp : String:
get:
return "" if not _timestamp is String else String(_timestamp)
# Optional value.
var _value
var value : String:
get:
return "" if not _value is String else String(_value)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiEvent:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiEvent", p_dict), ApiEvent) as ApiEvent
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "id: %s, " % _id
if typeof(_metadata) == TYPE_DICTIONARY:
for k in _metadata:
map_string += "{%s=%s}, " % [k, _metadata[k]]
output += "metadata: [%s], " % map_string
map_string = ""
output += "name: %s, " % _name
output += "timestamp: %s, " % _timestamp
output += "value: %s, " % _value
output += map_string
return output
#
class ApiEventRequest extends SatoriAsyncResult:
const _SCHEMA = {
"events": {"name": "_events", "type": TYPE_ARRAY, "required": false, "content": TYPE_DICTIONARY},
}
# Some number of events produced by a client.
var _events
var events : Array:
get:
return Array() if not _events is Array else Array(_events)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiEventRequest:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiEventRequest", p_dict), ApiEventRequest) as ApiEventRequest
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "events: %s, " % [_events]
output += map_string
return output
# An experiment that this user is partaking.
class ApiExperiment extends SatoriAsyncResult:
const _SCHEMA = {
"name": {"name": "_name", "type": TYPE_STRING, "required": false},
"value": {"name": "_value", "type": TYPE_STRING, "required": false},
}
#
var _name
var name : String:
get:
return "" if not _name is String else String(_name)
# Value associated with this Experiment.
var _value
var value : String:
get:
return "" if not _value is String else String(_value)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiExperiment:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiExperiment", p_dict), ApiExperiment) as ApiExperiment
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "name: %s, " % _name
output += "value: %s, " % _value
output += map_string
return output
# All experiments that this identity is involved with.
class ApiExperimentList extends SatoriAsyncResult:
const _SCHEMA = {
"experiments": {"name": "_experiments", "type": TYPE_ARRAY, "required": false, "content": TYPE_DICTIONARY},
}
# All experiments for this identity.
var _experiments
var experiments : Array:
get:
return Array() if not _experiments is Array else Array(_experiments)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiExperimentList:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiExperimentList", p_dict), ApiExperimentList) as ApiExperimentList
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "experiments: %s, " % [_experiments]
output += map_string
return output
# Feature flag available to the identity.
class ApiFlag extends SatoriAsyncResult:
const _SCHEMA = {
"condition_changed": {"name": "_condition_changed", "type": TYPE_BOOL, "required": false},
"name": {"name": "_name", "type": TYPE_STRING, "required": false},
"value": {"name": "_value", "type": TYPE_STRING, "required": false},
}
# Whether the value for this flag has conditionally changed from the default state.
var _condition_changed
var condition_changed : bool:
get:
return false if not _condition_changed is bool else bool(_condition_changed)
#
var _name
var name : String:
get:
return "" if not _name is String else String(_name)
# Value associated with this flag.
var _value
var value : String:
get:
return "" if not _value is String else String(_value)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiFlag:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiFlag", p_dict), ApiFlag) as ApiFlag
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "condition_changed: %s, " % _condition_changed
output += "name: %s, " % _name
output += "value: %s, " % _value
output += map_string
return output
#
class ApiFlagList extends SatoriAsyncResult:
const _SCHEMA = {
"flags": {"name": "_flags", "type": TYPE_ARRAY, "required": false, "content": TYPE_DICTIONARY},
}
#
var _flags
var flags : Array:
get:
return Array() if not _flags is Array else Array(_flags)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiFlagList:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiFlagList", p_dict), ApiFlagList) as ApiFlagList
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "flags: %s, " % [_flags]
output += map_string
return output
# A response containing all the messages for an identity.
class ApiGetMessageListResponse extends SatoriAsyncResult:
const _SCHEMA = {
"cacheable_cursor": {"name": "_cacheable_cursor", "type": TYPE_STRING, "required": false},
"messages": {"name": "_messages", "type": TYPE_ARRAY, "required": false, "content": TYPE_DICTIONARY},
"next_cursor": {"name": "_next_cursor", "type": TYPE_STRING, "required": false},
"prev_cursor": {"name": "_prev_cursor", "type": TYPE_STRING, "required": false},
}
# Cacheable cursor to list newer messages. Durable and designed to be stored, unlike next/prev cursors.
var _cacheable_cursor
var cacheable_cursor : String:
get:
return "" if not _cacheable_cursor is String else String(_cacheable_cursor)
# The list of messages.
var _messages
var messages : Array:
get:
return Array() if not _messages is Array else Array(_messages)
# The cursor to send when retrieving the next page, if any.
var _next_cursor
var next_cursor : String:
get:
return "" if not _next_cursor is String else String(_next_cursor)
# The cursor to send when retrieving the previous page, if any.
var _prev_cursor
var prev_cursor : String:
get:
return "" if not _prev_cursor is String else String(_prev_cursor)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiGetMessageListResponse:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiGetMessageListResponse", p_dict), ApiGetMessageListResponse) as ApiGetMessageListResponse
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "cacheable_cursor: %s, " % _cacheable_cursor
output += "messages: %s, " % [_messages]
output += "next_cursor: %s, " % _next_cursor
output += "prev_cursor: %s, " % _prev_cursor
output += map_string
return output
# Enrich/replace the current session with a new ID.
class ApiIdentifyRequest extends SatoriAsyncResult:
const _SCHEMA = {
"custom": {"name": "_custom", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"default": {"name": "_default", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
}
# Optional custom properties to update with this call.
# If not set, properties are left as they are on the server.
var _custom
var custom : Dictionary:
get:
return Dictionary() if not _custom is Dictionary else _custom.duplicate()
# Optional default properties to update with this call.
# If not set, properties are left as they are on the server.
var _default
var default : Dictionary:
get:
return Dictionary() if not _default is Dictionary else _default.duplicate()
# Identity ID to enrich the current session and return a new session. Old session will no longer be usable.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiIdentifyRequest:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiIdentifyRequest", p_dict), ApiIdentifyRequest) as ApiIdentifyRequest
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
if typeof(_custom) == TYPE_DICTIONARY:
for k in _custom:
map_string += "{%s=%s}, " % [k, _custom[k]]
output += "custom: [%s], " % map_string
map_string = ""
if typeof(_default) == TYPE_DICTIONARY:
for k in _default:
map_string += "{%s=%s}, " % [k, _default[k]]
output += "default: [%s], " % map_string
map_string = ""
output += "id: %s, " % _id
output += map_string
return output
# A single live event.
class ApiLiveEvent extends SatoriAsyncResult:
const _SCHEMA = {
"active_end_time_sec": {"name": "_active_end_time_sec", "type": TYPE_STRING, "required": false},
"active_start_time_sec": {"name": "_active_start_time_sec", "type": TYPE_STRING, "required": false},
"description": {"name": "_description", "type": TYPE_STRING, "required": false},
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
"name": {"name": "_name", "type": TYPE_STRING, "required": false},
"value": {"name": "_value", "type": TYPE_STRING, "required": false},
}
# End time of current event run.
var _active_end_time_sec
var active_end_time_sec : String:
get:
return "" if not _active_end_time_sec is String else String(_active_end_time_sec)
# Start time of current event run.
var _active_start_time_sec
var active_start_time_sec : String:
get:
return "" if not _active_start_time_sec is String else String(_active_start_time_sec)
# Description.
var _description
var description : String:
get:
return "" if not _description is String else String(_description)
# The live event identifier.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
# Name.
var _name
var name : String:
get:
return "" if not _name is String else String(_name)
# Event value.
var _value
var value : String:
get:
return "" if not _value is String else String(_value)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLiveEvent:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiLiveEvent", p_dict), ApiLiveEvent) as ApiLiveEvent
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "active_end_time_sec: %s, " % _active_end_time_sec
output += "active_start_time_sec: %s, " % _active_start_time_sec
output += "description: %s, " % _description
output += "id: %s, " % _id
output += "name: %s, " % _name
output += "value: %s, " % _value
output += map_string
return output
# List of Live events.
class ApiLiveEventList extends SatoriAsyncResult:
const _SCHEMA = {
"live_events": {"name": "_live_events", "type": TYPE_ARRAY, "required": false, "content": TYPE_DICTIONARY},
}
# Live events.
var _live_events
var live_events : Array:
get:
return Array() if not _live_events is Array else Array(_live_events)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLiveEventList:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiLiveEventList", p_dict), ApiLiveEventList) as ApiLiveEventList
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "live_events: %s, " % [_live_events]
output += map_string
return output
# A scheduled message.
class ApiMessage extends SatoriAsyncResult:
const _SCHEMA = {
"consume_time": {"name": "_consume_time", "type": TYPE_STRING, "required": false},
"create_time": {"name": "_create_time", "type": TYPE_STRING, "required": false},
"metadata": {"name": "_metadata", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"read_time": {"name": "_read_time", "type": TYPE_STRING, "required": false},
"schedule_id": {"name": "_schedule_id", "type": TYPE_STRING, "required": false},
"send_time": {"name": "_send_time", "type": TYPE_STRING, "required": false},
"text": {"name": "_text", "type": TYPE_STRING, "required": false},
"update_time": {"name": "_update_time", "type": TYPE_STRING, "required": false},
}
# The time the message was consumed by the identity.
var _consume_time
var consume_time : String:
get:
return "" if not _consume_time is String else String(_consume_time)
# The time the message was created.
var _create_time
var create_time : String:
get:
return "" if not _create_time is String else String(_create_time)
# A key-value pairs of metadata.
var _metadata
var metadata : Dictionary:
get:
return Dictionary() if not _metadata is Dictionary else _metadata.duplicate()
# The time the message was read by the client.
var _read_time
var read_time : String:
get:
return "" if not _read_time is String else String(_read_time)
# The identifier of the schedule.
var _schedule_id
var schedule_id : String:
get:
return "" if not _schedule_id is String else String(_schedule_id)
# The send time for the message.
var _send_time
var send_time : String:
get:
return "" if not _send_time is String else String(_send_time)
# The message's text.
var _text
var text : String:
get:
return "" if not _text is String else String(_text)
# The time the message was updated.
var _update_time
var update_time : String:
get:
return "" if not _update_time is String else String(_update_time)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiMessage:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiMessage", p_dict), ApiMessage) as ApiMessage
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "consume_time: %s, " % _consume_time
output += "create_time: %s, " % _create_time
if typeof(_metadata) == TYPE_DICTIONARY:
for k in _metadata:
map_string += "{%s=%s}, " % [k, _metadata[k]]
output += "metadata: [%s], " % map_string
map_string = ""
output += "read_time: %s, " % _read_time
output += "schedule_id: %s, " % _schedule_id
output += "send_time: %s, " % _send_time
output += "text: %s, " % _text
output += "update_time: %s, " % _update_time
output += map_string
return output
# Properties associated with an identity.
class ApiProperties extends SatoriAsyncResult:
const _SCHEMA = {
"computed": {"name": "_computed", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"custom": {"name": "_custom", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"default": {"name": "_default", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# Event computed properties.
var _computed
var computed : Dictionary:
get:
return Dictionary() if not _computed is Dictionary else _computed.duplicate()
# Event custom properties.
var _custom
var custom : Dictionary:
get:
return Dictionary() if not _custom is Dictionary else _custom.duplicate()
# Event default properties.
var _default
var default : Dictionary:
get:
return Dictionary() if not _default is Dictionary else _default.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiProperties:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiProperties", p_dict), ApiProperties) as ApiProperties
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
if typeof(_computed) == TYPE_DICTIONARY:
for k in _computed:
map_string += "{%s=%s}, " % [k, _computed[k]]
output += "computed: [%s], " % map_string
map_string = ""
if typeof(_custom) == TYPE_DICTIONARY:
for k in _custom:
map_string += "{%s=%s}, " % [k, _custom[k]]
output += "custom: [%s], " % map_string
map_string = ""
if typeof(_default) == TYPE_DICTIONARY:
for k in _default:
map_string += "{%s=%s}, " % [k, _default[k]]
output += "default: [%s], " % map_string
map_string = ""
output += map_string
return output
# A session.
class ApiSession extends SatoriAsyncResult:
const _SCHEMA = {
"properties": {"name": "_properties", "type": "ApiProperties", "required": false},
"refresh_token": {"name": "_refresh_token", "type": TYPE_STRING, "required": false},
"token": {"name": "_token", "type": TYPE_STRING, "required": false},
}
# Properties associated with this identity.
var _properties
var properties : ApiProperties:
get:
return _properties as ApiProperties
# Refresh token.
var _refresh_token
var refresh_token : String:
get:
return "" if not _refresh_token is String else String(_refresh_token)
# Token credential.
var _token
var token : String:
get:
return "" if not _token is String else String(_token)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSession:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiSession", p_dict), ApiSession) as ApiSession
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "properties: %s, " % _properties
output += "refresh_token: %s, " % _refresh_token
output += "token: %s, " % _token
output += map_string
return output
# Update Properties associated with this identity.
class ApiUpdatePropertiesRequest extends SatoriAsyncResult:
const _SCHEMA = {
"custom": {"name": "_custom", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"default": {"name": "_default", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"recompute": {"name": "_recompute", "type": TYPE_BOOL, "required": false},
}
# Event custom properties.
var _custom
var custom : Dictionary:
get:
return Dictionary() if not _custom is Dictionary else _custom.duplicate()
# Event default properties.
var _default
var default : Dictionary:
get:
return Dictionary() if not _default is Dictionary else _default.duplicate()
# Informs the server to recompute the audience membership of the identity.
var _recompute
var recompute : bool:
get:
return false if not _recompute is bool else bool(_recompute)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUpdatePropertiesRequest:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ApiUpdatePropertiesRequest", p_dict), ApiUpdatePropertiesRequest) as ApiUpdatePropertiesRequest
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
if typeof(_custom) == TYPE_DICTIONARY:
for k in _custom:
map_string += "{%s=%s}, " % [k, _custom[k]]
output += "custom: [%s], " % map_string
map_string = ""
if typeof(_default) == TYPE_DICTIONARY:
for k in _default:
map_string += "{%s=%s}, " % [k, _default[k]]
output += "default: [%s], " % map_string
map_string = ""
output += "recompute: %s, " % _recompute
output += map_string
return output
#
class ProtobufAny extends SatoriAsyncResult:
const _SCHEMA = {
"type": {"name": "_type", "type": TYPE_STRING, "required": false},
}
#
var _type
var type : String:
get:
return "" if not _type is String else String(_type)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ProtobufAny:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "ProtobufAny", p_dict), ProtobufAny) as ProtobufAny
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "type: %s, " % _type
output += map_string
return output
#
class RpcStatus extends SatoriAsyncResult:
const _SCHEMA = {
"code": {"name": "_code", "type": TYPE_INT, "required": false},
"details": {"name": "_details", "type": TYPE_ARRAY, "required": false, "content": TYPE_DICTIONARY},
"message": {"name": "_message", "type": TYPE_STRING, "required": false},
}
#
var _code
var code : int:
get:
return 0 if not _code is int else int(_code)
#
var _details
var details : Array:
get:
return Array() if not _details is Array else Array(_details)
#
var _message
var message : String:
get:
return "" if not _message is String else String(_message)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> RpcStatus:
return _safe_ret(SatoriSerializer.deserialize(p_ns, "RpcStatus", p_dict), RpcStatus) as RpcStatus
func serialize() -> Dictionary:
return SatoriSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
var map_string : String = ""
output += "code: %s, " % _code
output += "details: %s, " % [_details]
output += "message: %s, " % _message
output += map_string
return output
# The low level client for the Satori API.
class ApiClient extends RefCounted:
var _base_uri : String
var _http_adapter
var _namespace : GDScript
var _server_key : String
var auto_refresh := true
var auto_refresh_time := 300
var auto_retry : bool:
set(p_value):
_http_adapter.auto_retry = p_value
get:
return _http_adapter.auto_retry
var auto_retry_count : int:
set(p_value):
_http_adapter.auto_retry_count = p_value
get:
return _http_adapter.auto_retry_count
var auto_retry_backoff_base : int:
set(p_value):
_http_adapter.auto_retry_backoff_base = p_value
get:
return _http_adapter.auto_retry_backoff_base
var last_cancel_token:
get:
return _http_adapter.get_last_token()
func _init(p_base_uri : String, p_http_adapter, p_namespace : GDScript, p_server_key : String, p_timeout : int = 10):
_base_uri = p_base_uri
_http_adapter = p_http_adapter
_http_adapter.timeout = p_timeout
_namespace = p_namespace
_server_key = p_server_key
func _refresh_session(p_session : SatoriSession):
if auto_refresh and p_session.is_valid() and p_session.refresh_token and not p_session.is_refresh_expired() and p_session.would_expire_in(auto_refresh_time):
var request = ApiAuthenticateRefreshRequest.new()
request._token = p_session.refresh_token
return await authenticate_refresh_async(_server_key, "", request)
return null
func cancel_request(p_token):
if p_token:
_http_adapter.cancel_request(p_token)
# A healthcheck which load balancers can use to check the service.
func healthcheck_async(
p_session : SatoriSession
) -> SatoriAsyncResult:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return SatoriAsyncResult.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/healthcheck"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "GET"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return SatoriAsyncResult.new(result)
return SatoriAsyncResult.new()
# A readycheck which load balancers can use to check the service.
func readycheck_async(
p_session : SatoriSession
) -> SatoriAsyncResult:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return SatoriAsyncResult.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/readycheck"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "GET"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return SatoriAsyncResult.new(result)
return SatoriAsyncResult.new()
# Authenticate against the server.
func authenticate_async(
p_basic_auth_username : String
, p_basic_auth_password : String
, p_body : ApiAuthenticateRequest
) -> ApiSession:
var urlpath : String = "/v1/authenticate"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "POST"
var headers = {}
var credentials = Marshalls.utf8_to_base64(p_basic_auth_username + ":" + p_basic_auth_password)
var header = "Basic %s" % credentials
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
content = JSON.stringify(p_body.serialize()).to_utf8_buffer()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return ApiSession.new(result)
var out : ApiSession = SatoriSerializer.deserialize(_namespace, "ApiSession", result)
return out
# Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.
func authenticate_logout_async(
p_session : SatoriSession
, p_body : ApiAuthenticateLogoutRequest
) -> SatoriAsyncResult:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return SatoriAsyncResult.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/authenticate/logout"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "POST"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
content = JSON.stringify(p_body.serialize()).to_utf8_buffer()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return SatoriAsyncResult.new(result)
return SatoriAsyncResult.new()
# Refresh a user's session using a refresh token retrieved from a previous authentication request.
func authenticate_refresh_async(
p_basic_auth_username : String
, p_basic_auth_password : String
, p_body : ApiAuthenticateRefreshRequest
) -> ApiSession:
var urlpath : String = "/v1/authenticate/refresh"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "POST"
var headers = {}
var credentials = Marshalls.utf8_to_base64(p_basic_auth_username + ":" + p_basic_auth_password)
var header = "Basic %s" % credentials
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
content = JSON.stringify(p_body.serialize()).to_utf8_buffer()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return ApiSession.new(result)
var out : ApiSession = SatoriSerializer.deserialize(_namespace, "ApiSession", result)
return out
# Publish an event for this session.
func event_async(
p_session : SatoriSession
, p_body : ApiEventRequest
) -> SatoriAsyncResult:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return SatoriAsyncResult.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/event"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "POST"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
content = JSON.stringify(p_body.serialize()).to_utf8_buffer()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return SatoriAsyncResult.new(result)
return SatoriAsyncResult.new()
# Get or list all available experiments for this identity.
func get_experiments_async(
p_session : SatoriSession
, p_names = null # : array
) -> ApiExperimentList:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return ApiExperimentList.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/experiment"
var query_params = ""
if p_names != null:
for elem in p_names:
query_params += "names=%s&" % elem
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "GET"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return ApiExperimentList.new(result)
var out : ApiExperimentList = SatoriSerializer.deserialize(_namespace, "ApiExperimentList", result)
return out
# List all available flags for this identity.
func get_flags_async(
p_bearer_token : String
, p_names = null # : array
) -> ApiFlagList:
var urlpath : String = "/v1/flag"
var query_params = ""
if p_names != null:
for elem in p_names:
query_params += "names=%s&" % elem
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "GET"
var headers = {}
if (p_bearer_token):
var header = "Bearer %s" % p_bearer_token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return ApiFlagList.new(result)
var out : ApiFlagList = SatoriSerializer.deserialize(_namespace, "ApiFlagList", result)
return out
# Enrich/replace the current session with new identifier.
func identify_async(
p_session : SatoriSession
, p_body : ApiIdentifyRequest
) -> ApiSession:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return ApiSession.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/identify"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "PUT"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
content = JSON.stringify(p_body.serialize()).to_utf8_buffer()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return ApiSession.new(result)
var out : ApiSession = SatoriSerializer.deserialize(_namespace, "ApiSession", result)
return out
# Delete the caller's identity and associated data.
func delete_identity_async(
p_session : SatoriSession
) -> SatoriAsyncResult:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return SatoriAsyncResult.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/identity"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "DELETE"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return SatoriAsyncResult.new(result)
return SatoriAsyncResult.new()
# List available live events.
func get_live_events_async(
p_session : SatoriSession
, p_names = null # : array
) -> ApiLiveEventList:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return ApiLiveEventList.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/live-event"
var query_params = ""
if p_names != null:
for elem in p_names:
query_params += "names=%s&" % elem
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "GET"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return ApiLiveEventList.new(result)
var out : ApiLiveEventList = SatoriSerializer.deserialize(_namespace, "ApiLiveEventList", result)
return out
# Get the list of messages for the identity.
func get_message_list_async(
p_session : SatoriSession
, p_limit = null # : integer
, p_forward = null # : boolean
, p_cursor = null # : string
) -> ApiGetMessageListResponse:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return ApiGetMessageListResponse.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/message"
var query_params = ""
if p_limit != null:
query_params += "limit=%d&" % p_limit
if p_forward != null:
query_params += "forward=%s&" % str(bool(p_forward)).to_lower()
if p_cursor != null:
query_params += "cursor=%s&" % SatoriSerializer.escape_http(p_cursor)
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "GET"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return ApiGetMessageListResponse.new(result)
var out : ApiGetMessageListResponse = SatoriSerializer.deserialize(_namespace, "ApiGetMessageListResponse", result)
return out
# Deletes a message for an identity.
func delete_message_async(
p_session : SatoriSession
, p_id : String
) -> SatoriAsyncResult:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return SatoriAsyncResult.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/message/{id}"
urlpath = urlpath.replace("{id}", SatoriSerializer.escape_http(p_id))
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "DELETE"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return SatoriAsyncResult.new(result)
return SatoriAsyncResult.new()
# Updates a message for an identity.
func update_message_async(
p_session : SatoriSession
, p_id : String
, p_body :
) -> SatoriAsyncResult:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return SatoriAsyncResult.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/message/{id}"
urlpath = urlpath.replace("{id}", SatoriSerializer.escape_http(p_id))
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "PUT"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
content = JSON.stringify(p_body.serialize()).to_utf8_buffer()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return SatoriAsyncResult.new(result)
return SatoriAsyncResult.new()
# List properties associated with this identity.
func list_properties_async(
p_session : SatoriSession
) -> ApiProperties:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return ApiProperties.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/properties"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "GET"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return ApiProperties.new(result)
var out : ApiProperties = SatoriSerializer.deserialize(_namespace, "ApiProperties", result)
return out
# Update identity properties.
func update_properties_async(
p_session : SatoriSession
, p_body : ApiUpdatePropertiesRequest
) -> SatoriAsyncResult:
var try_refresh = await _refresh_session(p_session)
if try_refresh != null:
if try_refresh.is_exception():
return SatoriAsyncResult.new(try_refresh.get_exception())
await p_session.refresh(try_refresh)
var urlpath : String = "/v1/properties"
var query_params = ""
var uri = "%s%s%s" % [_base_uri, urlpath, "?" + query_params if query_params else ""]
var method = "PUT"
var headers = {}
var header = "Bearer %s" % p_session.token
headers["Authorization"] = header
var content : PackedByteArray = PackedByteArray()
content = JSON.stringify(p_body.serialize()).to_utf8_buffer()
var result = await _http_adapter.send_async(method, uri, headers, content)
if result is SatoriException:
return SatoriAsyncResult.new(result)
return SatoriAsyncResult.new()
================================================
FILE: addons/com.heroiclabs.nakama/Satori/SatoriClient.gd
================================================
extends RefCounted
## A client for the API in Satori Server.
class_name SatoriClient
#region Properties
var _host
## The host address of the server.
var host : String:
get:
return _host
var _port
## The port number of the server.
var port : int:
get:
return _port
var _scheme
## The protocol scheme used to connect with the server. Must be either "http" or "https".
var scheme : String:
get:
return _scheme
## The key used to authenticate with the server without a session.
var api_key : String
## Set the timeout in seconds on requests sent to the server.
var timeout : int
var _api_client : SatoriAPI.ApiClient
var auto_refresh : bool = false:
set(v):
set_auto_refresh(v)
get:
return get_auto_refresh()
func get_auto_refresh():
return _api_client.auto_refresh
func set_auto_refresh(p_value):
_api_client.auto_refresh = p_value
#endregion
#region Initialization
func _init(p_adapter : SatoriHTTPAdapter,
p_api_key : String,
p_scheme : String,
p_host : String,
p_port : int,
p_timeout : int):
api_key = p_api_key
_scheme = p_scheme
_host = p_host
_port = p_port
timeout = p_timeout
_api_client = SatoriAPI.ApiClient.new(_scheme + "://" + _host + ":" + str(_port), p_adapter, SatoriAPI, api_key, p_timeout)
#endregion
#region Client APIs
## Authenticate against the server.
## [p_id]: An optional user id.
## [p_default_properties]: Optional default properties to update with this call.
## If not set, properties are left as they are on the server.
## [p_custom_properties]: Optional custom properties to update with this call.
## If not set, properties are left as they are on the server.
func authenticate_async(p_id: String, p_default_properties: Dictionary = {}, p_custom_properties: Dictionary = {}) -> SatoriSession:
return _parse_session(await _api_client.authenticate_async(api_key, "",
SatoriAPI.ApiAuthenticateRequest.create(SatoriAPI, {
"id": p_id,
"default": p_default_properties,
"custom": p_custom_properties
})))
## Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.
## [p_session]: The session of the user.
func authenticate_logout_async(p_session: SatoriSession) -> SatoriAsyncResult:
return await _api_client.authenticate_logout_async(p_session,
SatoriAPI.ApiAuthenticateLogoutRequest.create(SatoriAPI, {
"refresh_token": p_session.refresh_token,
"token": p_session.token
}))
# Parses the Satori API session and returns a SatoriSession object.
func _parse_session(p_session: SatoriAPI.ApiSession) -> SatoriSession:
if p_session.is_exception():
return SatoriSession.new(null, null, p_session.get_exception())
return SatoriSession.new(p_session.token, p_session.refresh_token)
## Refresh a user's session using a refresh token retrieved from a previous authentication request.
## [p_sesison]: The session of the user.
func session_refresh_async(p_session : SatoriSession) -> SatoriSession:
return _parse_session(await _api_client.authenticate_refresh_async(api_key, "",
SatoriAPI.ApiAuthenticateRefreshRequest.create(SatoriAPI, {
"refresh_token": p_session.refresh_token,
})
))
## Send an event for this session.
## [p_session]: The session of the user.
## [p_event]: The event which will be sent.
func event_async(p_session: SatoriSession, p_event: NakamaEvent) -> SatoriAsyncResult:
return await events_async(p_session, [
p_event
])
## Send a batch of events for this session.
## [p_session]: The session of the user.
## [p_events]: The batch of events which will be sent.
func events_async(p_session: SatoriSession, p_events: Array) -> SatoriAsyncResult:
var p_dict = {
"events": p_events.map(func(e):
return e.to_api_event_dict())
}
var req = SatoriAPI.ApiEventRequest.create(SatoriAPI, p_dict)
return await _api_client.event_async(p_session,
req)
## Get all experiments data.
## [p_session]: The session of the user.
func get_all_experiments_async(p_session: SatoriSession) -> SatoriAsyncResult:
return await _api_client.get_experiments_async(p_session)
## Get specific experiments data.
## [p_session]: The session of the user.
## [p_names]: Experiment names.
func get_experiments_async(p_session: SatoriSession, p_names: Array) -> SatoriAPI.ApiExperimentList:
return await _api_client.get_experiments_async(p_session, p_names)
## Get a single flag for this identity.
## This method will return the default value
## specified and will not raise an exception if the network is unavailable
## [p_session]: The session of the user.
## [p_name]: The name of the flag.
## [p_default]: The default value if the server is unreachable.
func get_flag_async(p_session: SatoriSession, p_name: String, p_default: String = "") -> SatoriAPI.ApiFlag:
var p_names = [p_name]
var flags = await get_flags_async(p_session, p_names)
if flags.is_exception():
return SatoriAPI.ApiFlag.create(SatoriAPI, {
"name": p_name,
"value": p_default
})
for flag in flags.flags:
if flag.name == p_name:
return flag
return null
## List all available flags for this identity.
## [p_session]: The session of the user.
## [p_names]: Flag names, if empty all flags will be returned.
func get_flags_async(p_session: SatoriSession, p_names: Array) -> SatoriAPI.ApiFlagList:
return await _api_client.get_flags_async(p_session.token, p_names)
## List available live events.
## [p_session]: The session of the user.
## [p_names]: Live event names, if null or empty all live events are returned.
func get_live_events_async(p_session: SatoriSession, p_names: Array = []) -> SatoriAPI.ApiLiveEventList:
return await _api_client.get_live_events_async(p_session, p_names)
## Identify a session with a new ID.
## [p_session]: The session of the user.
## [p_id]: Identity ID to enrich the current session and return a new session.
## The old session will no longer be usable.
## Must be between eight and 128 characters (inclusive).
## Must be an alphanumeric string with only underscores and hyphens allowed.
## [p_default_properties]: The default properties.
## [p_custom_properties]: The custom event properties.
func identify_async(p_session: SatoriSession, p_id: String, p_default_properties: Dictionary = {}, p_custom_properties: Dictionary = {}) -> SatoriSession:
var req = SatoriAPI.ApiIdentifyRequest.create(SatoriAPI, {
"id": p_id,
"default": p_default_properties,
"custom": p_custom_properties
})
return _parse_session(await _api_client.identify_async(p_session, req))
## List properties associated with this identity.
## [p_session]: The session of the user.
func list_properties_async(p_session: SatoriSession) -> SatoriAsyncResult:
return await _api_client.list_properties_async(p_session)
## Update properties associated with this identity.
## [p_session]: The session of the user.
## [p_default_properties]: The default properties to update.
## [p_custom_properties]: The custom properties to update.
## [p_recompute]: Whether or not to recompute the user's audience membership immediately after property update.
func update_properties_async(p_session: SatoriSession, p_default_properties: Dictionary, p_custom_properties: Dictionary, p_recompute: bool = false) -> SatoriAsyncResult:
var req = SatoriAPI.ApiUpdatePropertiesRequest.create(SatoriAPI, {
"default": p_default_properties,
"custom": p_custom_properties,
"recompute": p_recompute
})
return await _api_client.update_properties_async(p_session, req)
## Delete the caller's identity and associated data.
## [p_session]: The session of the user.
func delete_identity_async(p_session: SatoriSession) -> SatoriAsyncResult:
return await _api_client.delete_identity_async(p_session)
#endregion
================================================
FILE: addons/com.heroiclabs.nakama/Satori/SatoriHttpAdapter.gd
================================================
@tool
extends Node
# An adapter which implements the HTTP protocol.
class_name SatoriHTTPAdapter
# The logger to use with the adapter.
var logger : RefCounted = SatoriLogger.new()
# The timeout for requests
var timeout : int = 3
# If request should be automatically retried when a network error occurs.
var auto_retry : bool = true
# The maximum number of time a request will be retried when auto_retry is true
var auto_retry_count : int = 3
var auto_retry_backoff_base : int = 10
# Whether or not to use threads when making HTTP requests.
var use_threads : bool = true
var _pending = {}
var id : int = 0
class AsyncRequest:
var id : int
var request : HTTPRequest
var uri : String
var method : int
var headers : PackedStringArray
var body : PackedByteArray
var retry_count := 3
var backoff_time := 10
var logger : SatoriLogger
var cancelled = false
var result : int = HTTPRequest.RESULT_NO_RESPONSE
var response_code : int = -1
var response_body : PackedByteArray
var timer : SceneTreeTimer = null
var cur_try : int = 1
var rng = RandomNumberGenerator.new()
func _init(p_id : int, p_request : HTTPRequest, p_uri : String,
p_method : int, p_headers : PackedStringArray, p_body : PackedByteArray,
p_retry_count : int, p_backoff_time : int, p_logger : SatoriLogger):
rng.seed = Time.get_ticks_usec()
id = p_id
request = p_request
uri = p_uri
method = p_method
headers = p_headers
body = p_body
retry_count = p_retry_count
backoff_time = p_backoff_time
logger = p_logger
func should_retry():
return cur_try < retry_count and not cancelled
func retry():
var time = pow(backoff_time, cur_try) * rng.randf_range(0.5, 1)
logger.debug("Retrying request %d. Tries left: %d. Backoff: %d ms" % [
id, retry_count - cur_try, time
])
cur_try += 1
await backoff(time)
if cancelled:
return
return await make_request()
func make_request():
var err = request.request(uri, headers, method, body.get_string_from_utf8())
if err != OK:
await request.get_tree().process_frame
result = HTTPRequest.RESULT_CANT_CONNECT
logger.debug("Request %d failed to start, error: %d" % [id, err])
return
var args = await request.request_completed
result = args[0]
response_code = args[1]
response_body = args[3]
func backoff(p_time : int):
timer = request.get_tree().create_timer(p_time / 1000.0)
await timer.timeout
timer = null
func cancel():
cancelled = true
request.cancel_request()
if timer:
timer.time_left = 0
else:
request.call_deferred("emit_signal", "request_completed", HTTPRequest.RESULT_REQUEST_FAILED, 0, [], [])
func parse_result():
if cancelled:
return SatoriException.new("Request cancelled", -1, -1, true)
elif result != HTTPRequest.RESULT_SUCCESS:
if result == null:
result = 0
return SatoriException.new("HTTPRequest failed!", result)
var json = JSON.new()
var json_error = json.parse(response_body.get_string_from_utf8())
if json_error != OK:
logger.debug("Unable to parse request %d response. JSON error: %d, JSON error message: %s, response code: %d" % [
id, json_error, json.get_error_message(), response_code
])
return SatoriException.new("Failed to decode JSON response", response_code)
var parsed = json.get_data()
if response_code != HTTPClient.RESPONSE_OK:
var error = ""
var code = -1
if typeof(parsed) == TYPE_DICTIONARY:
if "message" in parsed:
error = parsed["message"]
elif "error" in parsed:
error = parsed["error"]
else:
error = str(parsed)
code = parsed["code"] if "code" in parsed else -1
else:
error = str(parsed)
if typeof(error) == TYPE_DICTIONARY:
error = JSON.stringify(error)
logger.debug("Request %d returned response code: %d, RPC code: %d, error: %s" % [
id, response_code, code, error
])
return SatoriException.new(error, response_code, code)
return parsed
# Send a HTTP request.
# @param method - HTTP method to use for this request.
# @param uri - The fully qualified URI to use.
# @param headers - Request headers to set.
# @param body - Request content body to set.
# @param timeoutSec - Request timeout.
# Returns a task which resolves to the contents of the response.
func send_async(p_method : String, p_uri : String, p_headers : Dictionary, p_body : PackedByteArray):
var req = HTTPRequest.new()
req.timeout = timeout
if use_threads and OS.get_name() != 'Web':
req.use_threads = true # Threads not available nor needed on the web.
# Parse method
var method = HTTPClient.METHOD_GET
if p_method == "POST":
method = HTTPClient.METHOD_POST
elif p_method == "PUT":
method = HTTPClient.METHOD_PUT
elif p_method == "DELETE":
method = HTTPClient.METHOD_DELETE
elif p_method == "HEAD":
method = HTTPClient.METHOD_HEAD
var headers = PackedStringArray()
# Parse headers
headers.append("Accept: application/json")
for k in p_headers:
headers.append("%s: %s" % [k, p_headers[k]])
id += 1
var retry = auto_retry_count if auto_retry else 0
var backoff = auto_retry_backoff_base
_pending[id] = AsyncRequest.new(id, req, p_uri, method, headers, p_body, retry, backoff, logger)
logger.debug("Sending request [ID: %d, Method: %s, Uri: %s, Headers: %s, Body: %s, Timeout: %d, Retries: %d, Backoff base: %d ms]" % [
id, p_method, p_uri, p_headers, p_body.get_string_from_utf8(), timeout, retry, backoff
])
add_child(req)
return await _send_async(id, _pending)
func get_last_token():
return id
func cancel_request(p_token):
if _pending.has(p_token):
_pending[p_token].cancel()
static func _clear_request(p_request : AsyncRequest, p_pending : Dictionary, p_id : int):
if not p_request.request.is_queued_for_deletion():
p_request.logger.debug("Freeing request %d" % p_id)
p_request.request.queue_free()
p_pending.erase(p_id)
static func _send_async(p_id : int, p_pending : Dictionary):
var req : AsyncRequest = p_pending[p_id]
await req.make_request()
while req.result != HTTPRequest.RESULT_SUCCESS:
req.logger.debug("Request %d failed with result: %d, response code: %d" % [
p_id, req.result, req.response_code
])
if not req.should_retry():
break
await req.retry()
_clear_request(req, p_pending, p_id)
return req.parse_result()
================================================
FILE: addons/com.heroiclabs.nakama/Satori/SatoriSession.gd
================================================
extends SatoriAsyncResult
class_name SatoriSession
var _token: String = ""
var token: String:
get:
return _token
var _refresh_token: String = ""
var refresh_token: String:
get:
return _refresh_token
var _expire_time: int = 0
var expire_time: int:
get:
return _expire_time
var expired: bool:
get:
return is_expired()
var _refresh_expire_time: int = 0
var refresh_expire_time: int:
get:
return _refresh_expire_time
var _identity_id: String = ""
var identity_id: String:
get:
return _identity_id
var _valid : bool = false
var valid : bool:
get:
return _valid
func is_expired() -> bool:
return _expire_time < Time.get_unix_time_from_system()
func would_expire_in(p_secs : int) -> bool:
return _expire_time < Time.get_unix_time_from_system() + p_secs
func has_refresh_expired(offset: float) -> bool:
return _expire_time < offset
func is_refresh_expired() -> bool:
return _refresh_expire_time < Time.get_unix_time_from_system()
func is_valid():
return _valid
# Initializes a new instance of the SatoriSession class.
#
# @param p_token - The authentication token.
# @param p_refresh_token - The refresh token.
# @param p_exception - The exception to be thrown, if any.
func _init(p_token = null, p_refresh_token = null, p_exception = null):
super(p_exception)
_refresh_expire_time = 0
if p_token:
_update(p_token, p_refresh_token)
func _update(p_token, p_refresh_token):
_token = p_token
_refresh_token = p_refresh_token
var decoded = _jwt_unpack(p_token)
if decoded.is_empty():
_valid = false
return
_valid = true
_expire_time = int(decoded.get("exp", 0))
_identity_id = str(decoded.get("iid", ""))
_refresh_expire_time = int(_jwt_unpack(refresh_token).get("exp", 0)) if !refresh_token.is_empty() else 0
func _to_string():
if is_exception():
return get_exception()._to_string()
return "Session<AuthToken=%s, ExpireTime=%d, RefreshToken=%s, RefreshExpireTime=%d, IdentityId=%s>" % [
_token, _expire_time, _refresh_token, _refresh_expire_time, identity_id]
func _jwt_unpack(p_token : String) -> Dictionary:
# Hack decode JSON payload from JWT.
if p_token.find(".") == -1:
_ex = SatoriException.new("Missing payload: %s" % p_token)
return {}
var payload = p_token.split('.')[1];
var pad_length = ceil(payload.length() / 4.0) * 4;
# Pad base64
for i in range(0, pad_length - payload.length()):
payload += "="
payload = payload.replace("-", "+").replace("_", "/")
var unpacked = Marshalls.base64_to_utf8(payload)
var json = JSON.new()
var error = json.parse(unpacked)
if error == OK:
var decoded = json.get_data()
if typeof(decoded) == TYPE_DICTIONARY:
return decoded
_ex = SatoriException.new("Unable to unpack token: %s" % p_token)
return {}
================================================
FILE: addons/com.heroiclabs.nakama/Satori/utils/SatoriAsyncResult.gd
================================================
extends RefCounted
class_name SatoriAsyncResult
var exception : SatoriException:
set(v):
pass
get:
return get_exception()
var _ex = null
func _init(p_ex = null):
_ex = p_ex
func is_exception():
return get_exception() != null
func was_cancelled():
return is_exception() and get_exception().cancelled
func get_exception() -> SatoriException:
return _ex as SatoriException
func _to_string():
if is_exception():
return get_exception()._to_string()
return "SatoriAsyncResult<>"
static func _safe_ret(p_obj, p_type : GDScript):
if is_instance_of(p_obj, p_type):
return p_obj
elif p_obj is SatoriException:
return p_type.new(p_obj)
return p_type.new(SatoriException.new())
================================================
FILE: addons/com.heroiclabs.nakama/Satori/utils/SatoriException.gd
================================================
extends RefCounted
# An exception generated during a request.
# Usually contains at least an error message.
class_name SatoriException
var _status_code : int = -1
var status_code : int:
set(v):
pass
get:
return _status_code
var _grpc_status_code : int = -1
var grpc_status_code : int:
set(v):
pass
get:
return _grpc_status_code
var _message : String = ""
var message : String:
set(v):
pass
get:
return _message
var _cancelled : bool = false
var cancelled : bool:
set(v):
pass
get:
return _cancelled
func _init(p_message : String = "", p_status_code : int = -1, p_grpc_status_code : int = -1, p_cancelled : bool = false):
_status_code = p_status_code
_grpc_status_code = p_grpc_status_code
_message = p_message
_cancelled = p_cancelled
func _to_string() -> String:
return "SatoriException(StatusCode={%s}, Message='{%s}', GrpcStatusCode={%s})" % [_status_code, _message, _grpc_status_code]
================================================
FILE: addons/com.heroiclabs.nakama/Satori/utils/SatoriLogger.gd
================================================
extends RefCounted
class_name SatoriLogger
enum LOG_LEVEL {NONE, ERROR, WARNING, INFO, VERBOSE, DEBUG}
var _level = LOG_LEVEL.ERROR
var _module = "Satori"
func _init(p_module : String = "Satori", p_level : int = LOG_LEVEL.ERROR):
_level = p_level
_module = p_module
func _log(level : int, msg):
if level <= _level:
if level == LOG_LEVEL.ERROR:
printerr("=== %s : ERROR === %s" % [_module, str(msg)])
else:
var what = "=== UNKNOWN === "
for k in LOG_LEVEL:
if level == LOG_LEVEL[k]:
what = "=== %s : %s === " % [_module, k]
break
print(what + str(msg))
func error(msg):
_log(LOG_LEVEL.ERROR, msg)
func warning(msg):
_log(LOG_LEVEL.WARNING, msg)
func info(msg):
_log(LOG_LEVEL.INFO, msg)
func verbose(msg):
_log(LOG_LEVEL.VERBOSE, msg)
func debug(msg):
_log(LOG_LEVEL.DEBUG, msg)
================================================
FILE: addons/com.heroiclabs.nakama/Satori/utils/SatoriSerializer.gd
================================================
extends RefCounted
class_name SatoriSerializer
static func serialize(p_obj : Object) -> Dictionary:
var out = {}
var schema = p_obj.get("_SCHEMA")
if schema == null:
return {} # No schema defined
for k in schema:
var prop = schema[k]
var val = p_obj.get(prop["name"])
if val == null:
continue
var type = prop["type"]
var content = prop.get("content", TYPE_NIL)
if typeof(content) == TYPE_STRING:
content = TYPE_OBJECT
var val_type = typeof(val)
match val_type:
TYPE_OBJECT: # Simple objects
out[k] = serialize(val)
TYPE_ARRAY: # Array of objects
var arr = []
if val.size() > 0 and typeof(val[0]) == TYPE_OBJECT: # Array of objects
for e in val:
arr.append(serialize(e))
else:
arr = val
out[k] = arr
TYPE_PACKED_INT32_ARRAY, TYPE_PACKED_STRING_ARRAY: # Array of ints, bools, or strings
var arr = []
for e in val:
if content == TYPE_BOOL:
e = bool(e)
if typeof(e) != content:
continue
arr.append(e)
out[k] = arr
TYPE_DICTIONARY: # Maps
var dict = {}
if content == TYPE_OBJECT: # Map of objects
for l in val:
if typeof(val[l]) != TYPE_OBJECT:
continue
dict[l] = serialize(val[l])
else: # Map of simple types
for l in val:
var e = val[l]
if content == TYPE_FLOAT:
e = float(e)
elif content == TYPE_INT:
e = int(e)
elif content == TYPE_BOOL:
e = bool(e)
if typeof(e) != content:
continue
dict[l] = e
out[k] = dict
_:
out[k] = val
return out
static func deserialize(p_ns : GDScript, p_cls_name : String, p_dict : Dictionary) -> Object:
var cls : GDScript = p_ns.get(p_cls_name)
var schema = cls.get("_SCHEMA")
if schema == null:
return SatoriException.new() # No schema defined
var obj = cls.new()
for k in schema:
var prop = schema[k]
var pname = prop["name"]
var type = prop["type"]
var required = prop["required"]
var content = prop.get("content", TYPE_NIL)
var type_cmp = type
if typeof(type) == TYPE_STRING: # A class
type_cmp = TYPE_DICTIONARY
if type_cmp == TYPE_PACKED_STRING_ARRAY or type_cmp == TYPE_PACKED_INT32_ARRAY: # A specialized array
type_cmp = TYPE_ARRAY
var content_cmp = content
if typeof(content) == TYPE_STRING: # A dictionary or array of classes
content_cmp = TYPE_DICTIONARY
var val = p_dict.get(k, null)
# Ints might and up being recognized as floats. Change that if needed
if type_cmp == TYPE_INT:
if typeof(val) == TYPE_FLOAT:
val = int(val)
elif typeof(val) == TYPE_STRING and val.is_valid_int():
val = val.to_int()
if typeof(val) == type_cmp:
if typeof(type) == TYPE_STRING:
obj.set(pname, deserialize(p_ns, type, val))
elif type_cmp == TYPE_DICTIONARY:
var v = {}
for l in val:
if typeof(content) == TYPE_STRING:
v[l] = deserialize(p_ns, content, val[l])
elif content == TYPE_FLOAT:
v[l] = float(val[l])
elif content == TYPE_INT:
v[l] = int(val[l])
elif content == TYPE_BOOL:
v[l] = bool(val[l])
else:
v[l] = str(val[l])
obj.set(pname, v)
elif type_cmp == TYPE_ARRAY:
var v
match content:
TYPE_INT, TYPE_BOOL: v = PackedInt32Array()
TYPE_STRING: v = PackedStringArray()
_: v = Array()
for e in val:
if typeof(e) == TYPE_DICTIONARY:
v.append(e) # Avoid deserialization if e is already a dictionary
elif typeof(content) == TYPE_STRING:
v.append(deserialize(p_ns, content, e))
elif content == TYPE_FLOAT:
v.append(float(e))
elif content == TYPE_INT:
v.append(int(e))
elif content == TYPE_BOOL:
v.append(bool(e))
else:
v.append(str(e))
obj.set(pname, v)
else:
obj.set(pname, val)
elif required:
obj._ex = SatoriException.new("ERROR [%s]: Missing or invalid required prop %s = %s:\n\t%s" % [p_cls_name, prop, p_dict.get(k), p_dict])
return obj
return obj
###
# Compatibility with Godot 3.1 which does not expose String.http_escape
###
const HEX = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"]
static func escape_http(p_str : String) -> String:
var out : String = ""
for o in p_str:
if (o == '.' or o == '-' or o == '_' or o == '~' or
(o >= 'a' and o <= 'z') or
(o >= 'A' and o <= 'Z') or
(o >= '0' and o <= '9')):
out += o
else:
for b in o.to_utf8_buffer():
out += "%%%s" % to_hex(b)
return out
static func to_hex(p_val : int) -> String:
var v := p_val
var o := ""
while v != 0:
o = HEX[v % 16] + o
v /= 16
return o
================================================
FILE: addons/com.heroiclabs.nakama/Satori.gd
================================================
@tool
extends Node
# The default host address of the server.
const DEFAULT_HOST : String = "127.0.0.1"
# The default port number of the server.
const DEFAULT_PORT : int = 7450
# The default timeout for the connections.
const DEFAULT_TIMEOUT = 15
# The default protocol scheme for the client connection.
const DEFAULT_CLIENT_SCHEME : String = "http"
# The default log level for the Satori logger.
const DEFAULT_LOG_LEVEL = SatoriLogger.LOG_LEVEL.DEBUG
var _http_adapter = null
var logger = SatoriLogger.new()
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS
func get_client_adapter() -> SatoriHTTPAdapter:
if _http_adapter == null:
_http_adapter = SatoriHTTPAdapter.new()
_http_adapter.logger = logger
_http_adapter.name = "SatoriHTTPAdapter"
add_child(_http_adapter)
return _http_adapter
func create_client(p_api_key : String,
p_host : String = DEFAULT_HOST,
p_port : int = DEFAULT_PORT,
p_scheme : String = DEFAULT_CLIENT_SCHEME,
p_timeout : int = DEFAULT_TIMEOUT,
p_log_level : int = DEFAULT_LOG_LEVEL,
) -> SatoriClient:
logger._level = p_log_level
return SatoriClient.new(get_client_adapter(), p_api_key, p_scheme, p_host, p_port, p_timeout)
================================================
FILE: addons/com.heroiclabs.nakama/api/NakamaAPI.gd
================================================
### Code generated by codegen/main.go. DO NOT EDIT. ###
extends RefCounted
class_name NakamaAPI
# A single user-role pair.
class GroupUserListGroupUser extends NakamaAsyncResult:
const _SCHEMA = {
"state": {"name": "_state", "type": TYPE_INT, "required": false},
"user": {"name": "_user", "type": "ApiUser", "required": false},
}
# Their relationship to the group.
var _state
var state : int:
get:
return 0 if not _state is int else int(_state)
# User.
var _user
var user : ApiUser:
get:
return _user as ApiUser
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> GroupUserListGroupUser:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "GroupUserListGroupUser", p_dict), GroupUserListGroupUser) as GroupUserListGroupUser
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "state: %s, " % _state
output += "user: %s, " % _user
return output
# A single group-role pair.
class UserGroupListUserGroup extends NakamaAsyncResult:
const _SCHEMA = {
"group": {"name": "_group", "type": "ApiGroup", "required": false},
"state": {"name": "_state", "type": TYPE_INT, "required": false},
}
# Group.
var _group
var group : ApiGroup:
get:
return _group as ApiGroup
# The user's relationship to the group.
var _state
var state : int:
get:
return 0 if not _state is int else int(_state)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> UserGroupListUserGroup:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "UserGroupListUserGroup", p_dict), UserGroupListUserGroup) as UserGroupListUserGroup
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "group: %s, " % _group
output += "state: %s, " % _state
return output
# Record values to write.
class WriteLeaderboardRecordRequestLeaderboardRecordWrite extends NakamaAsyncResult:
const _SCHEMA = {
"metadata": {"name": "_metadata", "type": TYPE_STRING, "required": false},
"operator": {"name": "_operator", "type": TYPE_INT, "required": false},
"score": {"name": "_score", "type": TYPE_STRING, "required": false},
"subscore": {"name": "_subscore", "type": TYPE_STRING, "required": false},
}
# Optional record metadata.
var _metadata
var metadata : String:
get:
return "" if not _metadata is String else String(_metadata)
# Operator override.
var _operator
var operator : int:
get:
return ApiOperator.values()[0] if not ApiOperator.values().has(_operator) else _operator
# The score value to submit.
var _score
var score : String:
get:
return "" if not _score is String else String(_score)
# An optional secondary value.
var _subscore
var subscore : String:
get:
return "" if not _subscore is String else String(_subscore)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> WriteLeaderboardRecordRequestLeaderboardRecordWrite:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "WriteLeaderboardRecordRequestLeaderboardRecordWrite", p_dict), WriteLeaderboardRecordRequestLeaderboardRecordWrite) as WriteLeaderboardRecordRequestLeaderboardRecordWrite
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "metadata: %s, " % _metadata
output += "operator: %s, " % _operator
output += "score: %s, " % _score
output += "subscore: %s, " % _subscore
return output
# Record values to write.
class WriteTournamentRecordRequestTournamentRecordWrite extends NakamaAsyncResult:
const _SCHEMA = {
"metadata": {"name": "_metadata", "type": TYPE_STRING, "required": false},
"operator": {"name": "_operator", "type": TYPE_INT, "required": false},
"score": {"name": "_score", "type": TYPE_STRING, "required": false},
"subscore": {"name": "_subscore", "type": TYPE_STRING, "required": false},
}
# A JSON object of additional properties (optional).
var _metadata
var metadata : String:
get:
return "" if not _metadata is String else String(_metadata)
# Operator override.
var _operator
var operator : int:
get:
return ApiOperator.values()[0] if not ApiOperator.values().has(_operator) else _operator
# The score value to submit.
var _score
var score : String:
get:
return "" if not _score is String else String(_score)
# An optional secondary value.
var _subscore
var subscore : String:
get:
return "" if not _subscore is String else String(_subscore)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> WriteTournamentRecordRequestTournamentRecordWrite:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "WriteTournamentRecordRequestTournamentRecordWrite", p_dict), WriteTournamentRecordRequestTournamentRecordWrite) as WriteTournamentRecordRequestTournamentRecordWrite
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "metadata: %s, " % _metadata
output += "operator: %s, " % _operator
output += "score: %s, " % _score
output += "subscore: %s, " % _subscore
return output
# A user with additional account details. Always the current user.
class ApiAccount extends NakamaAsyncResult:
const _SCHEMA = {
"custom_id": {"name": "_custom_id", "type": TYPE_STRING, "required": false},
"devices": {"name": "_devices", "type": TYPE_ARRAY, "required": false, "content": "ApiAccountDevice"},
"disable_time": {"name": "_disable_time", "type": TYPE_STRING, "required": false},
"email": {"name": "_email", "type": TYPE_STRING, "required": false},
"user": {"name": "_user", "type": "ApiUser", "required": false},
"verify_time": {"name": "_verify_time", "type": TYPE_STRING, "required": false},
"wallet": {"name": "_wallet", "type": TYPE_STRING, "required": false},
}
# The custom id in the user's account.
var _custom_id
var custom_id : String:
get:
return "" if not _custom_id is String else String(_custom_id)
# The devices which belong to the user's account.
var _devices
var devices : Array:
get:
return Array() if not _devices is Array else Array(_devices)
# The UNIX time when the user's account was disabled/banned.
var _disable_time
var disable_time : String:
get:
return "" if not _disable_time is String else String(_disable_time)
# The email address of the user.
var _email
var email : String:
get:
return "" if not _email is String else String(_email)
# The user object.
var _user
var user : ApiUser:
get:
return _user as ApiUser
# The UNIX time when the user's email was verified.
var _verify_time
var verify_time : String:
get:
return "" if not _verify_time is String else String(_verify_time)
# The user's wallet data.
var _wallet
var wallet : String:
get:
return "" if not _wallet is String else String(_wallet)
var _wallet_dict = null
var wallet_dict : Dictionary:
get:
if _wallet_dict == null:
if _wallet == null:
return {}
var json = JSON.new()
if json.parse(_wallet) != OK:
return {}
_wallet_dict = json.get_data()
return _wallet_dict as Dictionary
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccount:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccount", p_dict), ApiAccount) as ApiAccount
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "custom_id: %s, " % _custom_id
output += "devices: %s, " % [_devices]
output += "disable_time: %s, " % _disable_time
output += "email: %s, " % _email
output += "user: %s, " % _user
output += "verify_time: %s, " % _verify_time
output += "wallet: %s, " % _wallet
return output
# Send a Apple Sign In token to the server. Used with authenticate/link/unlink.
class ApiAccountApple extends NakamaAsyncResult:
const _SCHEMA = {
"token": {"name": "_token", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# The ID token received from Apple to validate.
var _token
var token : String:
get:
return "" if not _token is String else String(_token)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountApple:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccountApple", p_dict), ApiAccountApple) as ApiAccountApple
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "token: %s, " % _token
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# Send a custom ID to the server. Used with authenticate/link/unlink.
class ApiAccountCustom extends NakamaAsyncResult:
const _SCHEMA = {
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# A custom identifier.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountCustom:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccountCustom", p_dict), ApiAccountCustom) as ApiAccountCustom
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "id: %s, " % _id
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# Send a device to the server. Used with authenticate/link/unlink and user.
class ApiAccountDevice extends NakamaAsyncResult:
const _SCHEMA = {
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# A device identifier. Should be obtained by a platform-specific device API.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountDevice:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccountDevice", p_dict), ApiAccountDevice) as ApiAccountDevice
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "id: %s, " % _id
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# Send an email with password to the server. Used with authenticate/link/unlink.
class ApiAccountEmail extends NakamaAsyncResult:
const _SCHEMA = {
"email": {"name": "_email", "type": TYPE_STRING, "required": false},
"password": {"name": "_password", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# A valid RFC-5322 email address.
var _email
var email : String:
get:
return "" if not _email is String else String(_email)
# A password for the user account.
var _password
var password : String:
get:
return "" if not _password is String else String(_password)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountEmail:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccountEmail", p_dict), ApiAccountEmail) as ApiAccountEmail
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "email: %s, " % _email
output += "password: %s, " % _password
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# Send a Facebook token to the server. Used with authenticate/link/unlink.
class ApiAccountFacebook extends NakamaAsyncResult:
const _SCHEMA = {
"token": {"name": "_token", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# The OAuth token received from Facebook to access their profile API.
var _token
var token : String:
get:
return "" if not _token is String else String(_token)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountFacebook:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccountFacebook", p_dict), ApiAccountFacebook) as ApiAccountFacebook
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "token: %s, " % _token
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# Send a Facebook Instant Game token to the server. Used with authenticate/link/unlink.
class ApiAccountFacebookInstantGame extends NakamaAsyncResult:
const _SCHEMA = {
"signed_player_info": {"name": "_signed_player_info", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
#
var _signed_player_info
var signed_player_info : String:
get:
return "" if not _signed_player_info is String else String(_signed_player_info)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountFacebookInstantGame:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccountFacebookInstantGame", p_dict), ApiAccountFacebookInstantGame) as ApiAccountFacebookInstantGame
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "signed_player_info: %s, " % _signed_player_info
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# Send Apple's Game Center account credentials to the server. Used with authenticate/link/unlink.
class ApiAccountGameCenter extends NakamaAsyncResult:
const _SCHEMA = {
"bundle_id": {"name": "_bundle_id", "type": TYPE_STRING, "required": false},
"player_id": {"name": "_player_id", "type": TYPE_STRING, "required": false},
"public_key_url": {"name": "_public_key_url", "type": TYPE_STRING, "required": false},
"salt": {"name": "_salt", "type": TYPE_STRING, "required": false},
"signature": {"name": "_signature", "type": TYPE_STRING, "required": false},
"timestamp_seconds": {"name": "_timestamp_seconds", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# Bundle ID (generated by GameCenter).
var _bundle_id
var bundle_id : String:
get:
return "" if not _bundle_id is String else String(_bundle_id)
# Player ID (generated by GameCenter).
var _player_id
var player_id : String:
get:
return "" if not _player_id is String else String(_player_id)
# The URL for the public encryption key.
var _public_key_url
var public_key_url : String:
get:
return "" if not _public_key_url is String else String(_public_key_url)
# A random "NSString" used to compute the hash and keep it randomized.
var _salt
var salt : String:
get:
return "" if not _salt is String else String(_salt)
# The verification signature data generated.
var _signature
var signature : String:
get:
return "" if not _signature is String else String(_signature)
# Time since UNIX epoch when the signature was created.
var _timestamp_seconds
var timestamp_seconds : String:
get:
return "" if not _timestamp_seconds is String else String(_timestamp_seconds)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountGameCenter:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccountGameCenter", p_dict), ApiAccountGameCenter) as ApiAccountGameCenter
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "bundle_id: %s, " % _bundle_id
output += "player_id: %s, " % _player_id
output += "public_key_url: %s, " % _public_key_url
output += "salt: %s, " % _salt
output += "signature: %s, " % _signature
output += "timestamp_seconds: %s, " % _timestamp_seconds
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# Send a Google token to the server. Used with authenticate/link/unlink.
class ApiAccountGoogle extends NakamaAsyncResult:
const _SCHEMA = {
"token": {"name": "_token", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# The OAuth token received from Google to access their profile API.
var _token
var token : String:
get:
return "" if not _token is String else String(_token)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountGoogle:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccountGoogle", p_dict), ApiAccountGoogle) as ApiAccountGoogle
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "token: %s, " % _token
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# Send a Steam token to the server. Used with authenticate/link/unlink.
class ApiAccountSteam extends NakamaAsyncResult:
const _SCHEMA = {
"token": {"name": "_token", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# The account token received from Steam to access their profile API.
var _token
var token : String:
get:
return "" if not _token is String else String(_token)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiAccountSteam:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiAccountSteam", p_dict), ApiAccountSteam) as ApiAccountSteam
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "token: %s, " % _token
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# A message sent on a channel.
class ApiChannelMessage extends NakamaAsyncResult:
const _SCHEMA = {
"channel_id": {"name": "_channel_id", "type": TYPE_STRING, "required": false},
"code": {"name": "_code", "type": TYPE_INT, "required": false},
"content": {"name": "_content", "type": TYPE_STRING, "required": false},
"create_time": {"name": "_create_time", "type": TYPE_STRING, "required": false},
"group_id": {"name": "_group_id", "type": TYPE_STRING, "required": false},
"message_id": {"name": "_message_id", "type": TYPE_STRING, "required": false},
"persistent": {"name": "_persistent", "type": TYPE_BOOL, "required": false},
"room_name": {"name": "_room_name", "type": TYPE_STRING, "required": false},
"sender_id": {"name": "_sender_id", "type": TYPE_STRING, "required": false},
"update_time": {"name": "_update_time", "type": TYPE_STRING, "required": false},
"user_id_one": {"name": "_user_id_one", "type": TYPE_STRING, "required": false},
"user_id_two": {"name": "_user_id_two", "type": TYPE_STRING, "required": false},
"username": {"name": "_username", "type": TYPE_STRING, "required": false},
}
# The channel this message belongs to.
var _channel_id
var channel_id : String:
get:
return "" if not _channel_id is String else String(_channel_id)
# The code representing a message type or category.
var _code
var code : int:
get:
return 0 if not _code is int else int(_code)
# The content payload.
var _content
var content : String:
get:
return "" if not _content is String else String(_content)
# The UNIX time when the message was created.
var _create_time
var create_time : String:
get:
return "" if not _create_time is String else String(_create_time)
# The ID of the group, or an empty string if this message was not sent through a group channel.
var _group_id
var group_id : String:
get:
return "" if not _group_id is String else String(_group_id)
# The unique ID of this message.
var _message_id
var message_id : String:
get:
return "" if not _message_id is String else String(_message_id)
# True if the message was persisted to the channel's history, false otherwise.
var _persistent
var persistent : bool:
get:
return false if not _persistent is bool else bool(_persistent)
# The name of the chat room, or an empty string if this message was not sent through a chat room.
var _room_name
var room_name : String:
get:
return "" if not _room_name is String else String(_room_name)
# Message sender, usually a user ID.
var _sender_id
var sender_id : String:
get:
return "" if not _sender_id is String else String(_sender_id)
# The UNIX time when the message was last updated.
var _update_time
var update_time : String:
get:
return "" if not _update_time is String else String(_update_time)
# The ID of the first DM user, or an empty string if this message was not sent through a DM chat.
var _user_id_one
var user_id_one : String:
get:
return "" if not _user_id_one is String else String(_user_id_one)
# The ID of the second DM user, or an empty string if this message was not sent through a DM chat.
var _user_id_two
var user_id_two : String:
get:
return "" if not _user_id_two is String else String(_user_id_two)
# The username of the message sender, if any.
var _username
var username : String:
get:
return "" if not _username is String else String(_username)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiChannelMessage:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiChannelMessage", p_dict), ApiChannelMessage) as ApiChannelMessage
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "channel_id: %s, " % _channel_id
output += "code: %s, " % _code
output += "content: %s, " % _content
output += "create_time: %s, " % _create_time
output += "group_id: %s, " % _group_id
output += "message_id: %s, " % _message_id
output += "persistent: %s, " % _persistent
output += "room_name: %s, " % _room_name
output += "sender_id: %s, " % _sender_id
output += "update_time: %s, " % _update_time
output += "user_id_one: %s, " % _user_id_one
output += "user_id_two: %s, " % _user_id_two
output += "username: %s, " % _username
return output
# A list of channel messages, usually a result of a list operation.
class ApiChannelMessageList extends NakamaAsyncResult:
const _SCHEMA = {
"cacheable_cursor": {"name": "_cacheable_cursor", "type": TYPE_STRING, "required": false},
"messages": {"name": "_messages", "type": TYPE_ARRAY, "required": false, "content": "ApiChannelMessage"},
"next_cursor": {"name": "_next_cursor", "type": TYPE_STRING, "required": false},
"prev_cursor": {"name": "_prev_cursor", "type": TYPE_STRING, "required": false},
}
# Cacheable cursor to list newer messages. Durable and designed to be stored, unlike next/prev cursors.
var _cacheable_cursor
var cacheable_cursor : String:
get:
return "" if not _cacheable_cursor is String else String(_cacheable_cursor)
# A list of messages.
var _messages
var messages : Array:
get:
return Array() if not _messages is Array else Array(_messages)
# The cursor to send when retrieving the next page, if any.
var _next_cursor
var next_cursor : String:
get:
return "" if not _next_cursor is String else String(_next_cursor)
# The cursor to send when retrieving the previous page, if any.
var _prev_cursor
var prev_cursor : String:
get:
return "" if not _prev_cursor is String else String(_prev_cursor)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiChannelMessageList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiChannelMessageList", p_dict), ApiChannelMessageList) as ApiChannelMessageList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "cacheable_cursor: %s, " % _cacheable_cursor
output += "messages: %s, " % [_messages]
output += "next_cursor: %s, " % _next_cursor
output += "prev_cursor: %s, " % _prev_cursor
return output
# Create a group with the current user as owner.
class ApiCreateGroupRequest extends NakamaAsyncResult:
const _SCHEMA = {
"avatar_url": {"name": "_avatar_url", "type": TYPE_STRING, "required": false},
"description": {"name": "_description", "type": TYPE_STRING, "required": false},
"lang_tag": {"name": "_lang_tag", "type": TYPE_STRING, "required": false},
"max_count": {"name": "_max_count", "type": TYPE_INT, "required": false},
"name": {"name": "_name", "type": TYPE_STRING, "required": false},
"open": {"name": "_open", "type": TYPE_BOOL, "required": false},
}
# A URL for an avatar image.
var _avatar_url
var avatar_url : String:
get:
return "" if not _avatar_url is String else String(_avatar_url)
# A description for the group.
var _description
var description : String:
get:
return "" if not _description is String else String(_description)
# The language expected to be a tag which follows the BCP-47 spec.
var _lang_tag
var lang_tag : String:
get:
return "" if not _lang_tag is String else String(_lang_tag)
# Maximum number of group members.
var _max_count
var max_count : int:
get:
return 0 if not _max_count is int else int(_max_count)
# A unique name for the group.
var _name
var name : String:
get:
return "" if not _name is String else String(_name)
# Mark a group as open or not where only admins can accept members.
var _open
var open : bool:
get:
return false if not _open is bool else bool(_open)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiCreateGroupRequest:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiCreateGroupRequest", p_dict), ApiCreateGroupRequest) as ApiCreateGroupRequest
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "avatar_url: %s, " % _avatar_url
output += "description: %s, " % _description
output += "lang_tag: %s, " % _lang_tag
output += "max_count: %s, " % _max_count
output += "name: %s, " % _name
output += "open: %s, " % _open
return output
# Storage objects to delete.
class ApiDeleteStorageObjectId extends NakamaAsyncResult:
const _SCHEMA = {
"collection": {"name": "_collection", "type": TYPE_STRING, "required": false},
"key": {"name": "_key", "type": TYPE_STRING, "required": false},
"version": {"name": "_version", "type": TYPE_STRING, "required": false},
}
# The collection which stores the object.
var _collection
var collection : String:
get:
return "" if not _collection is String else String(_collection)
# The key of the object within the collection.
var _key
var key : String:
get:
return "" if not _key is String else String(_key)
# The version hash of the object.
var _version
var version : String:
get:
return "" if not _version is String else String(_version)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiDeleteStorageObjectId:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiDeleteStorageObjectId", p_dict), ApiDeleteStorageObjectId) as ApiDeleteStorageObjectId
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "collection: %s, " % _collection
output += "key: %s, " % _key
output += "version: %s, " % _version
return output
# Batch delete storage objects.
class ApiDeleteStorageObjectsRequest extends NakamaAsyncResult:
const _SCHEMA = {
"object_ids": {"name": "_object_ids", "type": TYPE_ARRAY, "required": false, "content": "ApiDeleteStorageObjectId"},
}
# Batch of storage objects.
var _object_ids
var object_ids : Array:
get:
return Array() if not _object_ids is Array else Array(_object_ids)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiDeleteStorageObjectsRequest:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiDeleteStorageObjectsRequest", p_dict), ApiDeleteStorageObjectsRequest) as ApiDeleteStorageObjectsRequest
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "object_ids: %s, " % [_object_ids]
return output
# Represents an event to be passed through the server to registered event handlers.
class ApiEvent extends NakamaAsyncResult:
const _SCHEMA = {
"external": {"name": "_external", "type": TYPE_BOOL, "required": false},
"name": {"name": "_name", "type": TYPE_STRING, "required": false},
"properties": {"name": "_properties", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
"timestamp": {"name": "_timestamp", "type": TYPE_STRING, "required": false},
}
# True if the event came directly from a client call, false otherwise.
var _external
var external : bool:
get:
return false if not _external is bool else bool(_external)
# An event name, type, category, or identifier.
var _name
var name : String:
get:
return "" if not _name is String else String(_name)
# Arbitrary event property values.
var _properties
var properties : Dictionary:
get:
return Dictionary() if not _properties is Dictionary else _properties.duplicate()
# The time when the event was triggered.
var _timestamp
var timestamp : String:
get:
return "" if not _timestamp is String else String(_timestamp)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiEvent:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiEvent", p_dict), ApiEvent) as ApiEvent
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "external: %s, " % _external
output += "name: %s, " % _name
var map_string : String = ""
if typeof(_properties) == TYPE_DICTIONARY:
for k in _properties:
map_string += "{%s=%s}, " % [k, _properties[k]]
output += "properties: [%s], " % map_string
output += "timestamp: %s, " % _timestamp
return output
# A friend of a user.
class ApiFriend extends NakamaAsyncResult:
const _SCHEMA = {
"state": {"name": "_state", "type": TYPE_INT, "required": false},
"update_time": {"name": "_update_time", "type": TYPE_STRING, "required": false},
"user": {"name": "_user", "type": "ApiUser", "required": false},
}
# The friend status.
var _state
var state : int:
get:
return 0 if not _state is int else int(_state)
# Time of the latest relationship update.
var _update_time
var update_time : String:
get:
return "" if not _update_time is String else String(_update_time)
# The user object.
var _user
var user : ApiUser:
get:
return _user as ApiUser
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiFriend:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiFriend", p_dict), ApiFriend) as ApiFriend
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "state: %s, " % _state
output += "update_time: %s, " % _update_time
output += "user: %s, " % _user
return output
# A collection of zero or more friends of the user.
class ApiFriendList extends NakamaAsyncResult:
const _SCHEMA = {
"cursor": {"name": "_cursor", "type": TYPE_STRING, "required": false},
"friends": {"name": "_friends", "type": TYPE_ARRAY, "required": false, "content": "ApiFriend"},
}
# Cursor for the next page of results, if any.
var _cursor
var cursor : String:
get:
return "" if not _cursor is String else String(_cursor)
# The Friend objects.
var _friends
var friends : Array:
get:
return Array() if not _friends is Array else Array(_friends)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiFriendList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiFriendList", p_dict), ApiFriendList) as ApiFriendList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "cursor: %s, " % _cursor
output += "friends: %s, " % [_friends]
return output
# A group in the server.
class ApiGroup extends NakamaAsyncResult:
const _SCHEMA = {
"avatar_url": {"name": "_avatar_url", "type": TYPE_STRING, "required": false},
"create_time": {"name": "_create_time", "type": TYPE_STRING, "required": false},
"creator_id": {"name": "_creator_id", "type": TYPE_STRING, "required": false},
"description": {"name": "_description", "type": TYPE_STRING, "required": false},
"edge_count": {"name": "_edge_count", "type": TYPE_INT, "required": false},
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
"lang_tag": {"name": "_lang_tag", "type": TYPE_STRING, "required": false},
"max_count": {"name": "_max_count", "type": TYPE_INT, "required": false},
"metadata": {"name": "_metadata", "type": TYPE_STRING, "required": false},
"name": {"name": "_name", "type": TYPE_STRING, "required": false},
"open": {"name": "_open", "type": TYPE_BOOL, "required": false},
"update_time": {"name": "_update_time", "type": TYPE_STRING, "required": false},
}
# A URL for an avatar image.
var _avatar_url
var avatar_url : String:
get:
return "" if not _avatar_url is String else String(_avatar_url)
# The UNIX time when the group was created.
var _create_time
var create_time : String:
get:
return "" if not _create_time is String else String(_create_time)
# The id of the user who created the group.
var _creator_id
var creator_id : String:
get:
return "" if not _creator_id is String else String(_creator_id)
# A description for the group.
var _description
var description : String:
get:
return "" if not _description is String else String(_description)
# The current count of all members in the group.
var _edge_count
var edge_count : int:
get:
return 0 if not _edge_count is int else int(_edge_count)
# The id of a group.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
# The language expected to be a tag which follows the BCP-47 spec.
var _lang_tag
var lang_tag : String:
get:
return "" if not _lang_tag is String else String(_lang_tag)
# The maximum number of members allowed.
var _max_count
var max_count : int:
get:
return 0 if not _max_count is int else int(_max_count)
# Additional information stored as a JSON object.
var _metadata
var metadata : String:
get:
return "" if not _metadata is String else String(_metadata)
# The unique name of the group.
var _name
var name : String:
get:
return "" if not _name is String else String(_name)
# Anyone can join open groups, otherwise only admins can accept members.
var _open
var open : bool:
get:
return false if not _open is bool else bool(_open)
# The UNIX time when the group was last updated.
var _update_time
var update_time : String:
get:
return "" if not _update_time is String else String(_update_time)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiGroup:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiGroup", p_dict), ApiGroup) as ApiGroup
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "avatar_url: %s, " % _avatar_url
output += "create_time: %s, " % _create_time
output += "creator_id: %s, " % _creator_id
output += "description: %s, " % _description
output += "edge_count: %s, " % _edge_count
output += "id: %s, " % _id
output += "lang_tag: %s, " % _lang_tag
output += "max_count: %s, " % _max_count
output += "metadata: %s, " % _metadata
output += "name: %s, " % _name
output += "open: %s, " % _open
output += "update_time: %s, " % _update_time
return output
# One or more groups returned from a listing operation.
class ApiGroupList extends NakamaAsyncResult:
const _SCHEMA = {
"cursor": {"name": "_cursor", "type": TYPE_STRING, "required": false},
"groups": {"name": "_groups", "type": TYPE_ARRAY, "required": false, "content": "ApiGroup"},
}
# A cursor used to get the next page.
var _cursor
var cursor : String:
get:
return "" if not _cursor is String else String(_cursor)
# One or more groups.
var _groups
var groups : Array:
get:
return Array() if not _groups is Array else Array(_groups)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiGroupList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiGroupList", p_dict), ApiGroupList) as ApiGroupList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "cursor: %s, " % _cursor
output += "groups: %s, " % [_groups]
return output
# A list of users belonging to a group, along with their role.
class ApiGroupUserList extends NakamaAsyncResult:
const _SCHEMA = {
"cursor": {"name": "_cursor", "type": TYPE_STRING, "required": false},
"group_users": {"name": "_group_users", "type": TYPE_ARRAY, "required": false, "content": "GroupUserListGroupUser"},
}
# Cursor for the next page of results, if any.
var _cursor
var cursor : String:
get:
return "" if not _cursor is String else String(_cursor)
# User-role pairs for a group.
var _group_users
var group_users : Array:
get:
return Array() if not _group_users is Array else Array(_group_users)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiGroupUserList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiGroupUserList", p_dict), ApiGroupUserList) as ApiGroupUserList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "cursor: %s, " % _cursor
output += "group_users: %s, " % [_group_users]
return output
# Represents a complete leaderboard record with all scores and associated metadata.
class ApiLeaderboardRecord extends NakamaAsyncResult:
const _SCHEMA = {
"create_time": {"name": "_create_time", "type": TYPE_STRING, "required": false},
"expiry_time": {"name": "_expiry_time", "type": TYPE_STRING, "required": false},
"leaderboard_id": {"name": "_leaderboard_id", "type": TYPE_STRING, "required": false},
"max_num_score": {"name": "_max_num_score", "type": TYPE_INT, "required": false},
"metadata": {"name": "_metadata", "type": TYPE_STRING, "required": false},
"num_score": {"name": "_num_score", "type": TYPE_INT, "required": false},
"owner_id": {"name": "_owner_id", "type": TYPE_STRING, "required": false},
"rank": {"name": "_rank", "type": TYPE_STRING, "required": false},
"score": {"name": "_score", "type": TYPE_STRING, "required": false},
"subscore": {"name": "_subscore", "type": TYPE_STRING, "required": false},
"update_time": {"name": "_update_time", "type": TYPE_STRING, "required": false},
"username": {"name": "_username", "type": TYPE_STRING, "required": false},
}
# The UNIX time when the leaderboard record was created.
var _create_time
var create_time : String:
get:
return "" if not _create_time is String else String(_create_time)
# The UNIX time when the leaderboard record expires.
var _expiry_time
var expiry_time : String:
get:
return "" if not _expiry_time is String else String(_expiry_time)
# The ID of the leaderboard this score belongs to.
var _leaderboard_id
var leaderboard_id : String:
get:
return "" if not _leaderboard_id is String else String(_leaderboard_id)
# The maximum number of score updates allowed by the owner.
var _max_num_score
var max_num_score : int:
get:
return 0 if not _max_num_score is int else int(_max_num_score)
# Metadata.
var _metadata
var metadata : String:
get:
return "" if not _metadata is String else String(_metadata)
# The number of submissions to this score record.
var _num_score
var num_score : int:
get:
return 0 if not _num_score is int else int(_num_score)
# The ID of the score owner, usually a user or group.
var _owner_id
var owner_id : String:
get:
return "" if not _owner_id is String else String(_owner_id)
# The rank of this record.
var _rank
var rank : String:
get:
return "" if not _rank is String else String(_rank)
# The score value.
var _score
var score : String:
get:
return "" if not _score is String else String(_score)
# An optional subscore value.
var _subscore
var subscore : String:
get:
return "" if not _subscore is String else String(_subscore)
# The UNIX time when the leaderboard record was updated.
var _update_time
var update_time : String:
get:
return "" if not _update_time is String else String(_update_time)
# The username of the score owner, if the owner is a user.
var _username
var username : String:
get:
return "" if not _username is String else String(_username)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLeaderboardRecord:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiLeaderboardRecord", p_dict), ApiLeaderboardRecord) as ApiLeaderboardRecord
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "create_time: %s, " % _create_time
output += "expiry_time: %s, " % _expiry_time
output += "leaderboard_id: %s, " % _leaderboard_id
output += "max_num_score: %s, " % _max_num_score
output += "metadata: %s, " % _metadata
output += "num_score: %s, " % _num_score
output += "owner_id: %s, " % _owner_id
output += "rank: %s, " % _rank
output += "score: %s, " % _score
output += "subscore: %s, " % _subscore
output += "update_time: %s, " % _update_time
output += "username: %s, " % _username
return output
# A set of leaderboard records, may be part of a leaderboard records page or a batch of individual records.
class ApiLeaderboardRecordList extends NakamaAsyncResult:
const _SCHEMA = {
"next_cursor": {"name": "_next_cursor", "type": TYPE_STRING, "required": false},
"owner_records": {"name": "_owner_records", "type": TYPE_ARRAY, "required": false, "content": "ApiLeaderboardRecord"},
"prev_cursor": {"name": "_prev_cursor", "type": TYPE_STRING, "required": false},
"records": {"name": "_records", "type": TYPE_ARRAY, "required": false, "content": "ApiLeaderboardRecord"},
}
# The cursor to send when retrieving the next page, if any.
var _next_cursor
var next_cursor : String:
get:
return "" if not _next_cursor is String else String(_next_cursor)
# A batched set of leaderboard records belonging to specified owners.
var _owner_records
var owner_records : Array:
get:
return Array() if not _owner_records is Array else Array(_owner_records)
# The cursor to send when retrieving the previous page, if any.
var _prev_cursor
var prev_cursor : String:
get:
return "" if not _prev_cursor is String else String(_prev_cursor)
# A list of leaderboard records.
var _records
var records : Array:
get:
return Array() if not _records is Array else Array(_records)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLeaderboardRecordList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiLeaderboardRecordList", p_dict), ApiLeaderboardRecordList) as ApiLeaderboardRecordList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "next_cursor: %s, " % _next_cursor
output += "owner_records: %s, " % [_owner_records]
output += "prev_cursor: %s, " % _prev_cursor
output += "records: %s, " % [_records]
return output
# Link Steam to the current user's account.
class ApiLinkSteamRequest extends NakamaAsyncResult:
const _SCHEMA = {
"account": {"name": "_account", "type": "ApiAccountSteam", "required": false},
"sync": {"name": "_sync", "type": TYPE_BOOL, "required": false},
}
# The Facebook account details.
var _account
var account : ApiAccountSteam:
get:
return _account as ApiAccountSteam
# Import Steam friends for the user.
var _sync
var sync : bool:
get:
return false if not _sync is bool else bool(_sync)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiLinkSteamRequest:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiLinkSteamRequest", p_dict), ApiLinkSteamRequest) as ApiLinkSteamRequest
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "account: %s, " % _account
output += "sync: %s, " % _sync
return output
# List user subscriptions.
class ApiListSubscriptionsRequest extends NakamaAsyncResult:
const _SCHEMA = {
"cursor": {"name": "_cursor", "type": TYPE_STRING, "required": false},
"limit": {"name": "_limit", "type": TYPE_INT, "required": false},
}
#
var _cursor
var cursor : String:
get:
return "" if not _cursor is String else String(_cursor)
#
var _limit
var limit : int:
get:
return 0 if not _limit is int else int(_limit)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiListSubscriptionsRequest:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiListSubscriptionsRequest", p_dict), ApiListSubscriptionsRequest) as ApiListSubscriptionsRequest
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "cursor: %s, " % _cursor
output += "limit: %s, " % _limit
return output
# Represents a realtime match.
class ApiMatch extends NakamaAsyncResult:
const _SCHEMA = {
"authoritative": {"name": "_authoritative", "type": TYPE_BOOL, "required": false},
"handler_name": {"name": "_handler_name", "type": TYPE_STRING, "required": false},
"label": {"name": "_label", "type": TYPE_STRING, "required": false},
"match_id": {"name": "_match_id", "type": TYPE_STRING, "required": false},
"size": {"name": "_size", "type": TYPE_INT, "required": false},
"tick_rate": {"name": "_tick_rate", "type": TYPE_INT, "required": false},
}
# True if it's an server-managed authoritative match, false otherwise.
var _authoritative
var authoritative : bool:
get:
return false if not _authoritative is bool else bool(_authoritative)
#
var _handler_name
var handler_name : String:
get:
return "" if not _handler_name is String else String(_handler_name)
# Match label, if any.
var _label
var label : String:
get:
return "" if not _label is String else String(_label)
# The ID of the match, can be used to join.
var _match_id
var match_id : String:
get:
return "" if not _match_id is String else String(_match_id)
# Current number of users in the match.
var _size
var size : int:
get:
return 0 if not _size is int else int(_size)
#
var _tick_rate
var tick_rate : int:
get:
return 0 if not _tick_rate is int else int(_tick_rate)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiMatch:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiMatch", p_dict), ApiMatch) as ApiMatch
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "authoritative: %s, " % _authoritative
output += "handler_name: %s, " % _handler_name
output += "label: %s, " % _label
output += "match_id: %s, " % _match_id
output += "size: %s, " % _size
output += "tick_rate: %s, " % _tick_rate
return output
# A list of realtime matches.
class ApiMatchList extends NakamaAsyncResult:
const _SCHEMA = {
"matches": {"name": "_matches", "type": TYPE_ARRAY, "required": false, "content": "ApiMatch"},
}
# A number of matches corresponding to a list operation.
var _matches
var matches : Array:
get:
return Array() if not _matches is Array else Array(_matches)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiMatchList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiMatchList", p_dict), ApiMatchList) as ApiMatchList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "matches: %s, " % [_matches]
return output
# A notification in the server.
class ApiNotification extends NakamaAsyncResult:
const _SCHEMA = {
"code": {"name": "_code", "type": TYPE_INT, "required": false},
"content": {"name": "_content", "type": TYPE_STRING, "required": false},
"create_time": {"name": "_create_time", "type": TYPE_STRING, "required": false},
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
"persistent": {"name": "_persistent", "type": TYPE_BOOL, "required": false},
"sender_id": {"name": "_sender_id", "type": TYPE_STRING, "required": false},
"subject": {"name": "_subject", "type": TYPE_STRING, "required": false},
}
# Category code for this notification.
var _code
var code : int:
get:
return 0 if not _code is int else int(_code)
# Content of the notification in JSON.
var _content
var content : String:
get:
return "" if not _content is String else String(_content)
# The UNIX time when the notification was created.
var _create_time
var create_time : String:
get:
return "" if not _create_time is String else String(_create_time)
# ID of the Notification.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
# True if this notification was persisted to the database.
var _persistent
var persistent : bool:
get:
return false if not _persistent is bool else bool(_persistent)
# ID of the sender, if a user. Otherwise 'null'.
var _sender_id
var sender_id : String:
get:
return "" if not _sender_id is String else String(_sender_id)
# Subject of the notification.
var _subject
var subject : String:
get:
return "" if not _subject is String else String(_subject)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiNotification:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiNotification", p_dict), ApiNotification) as ApiNotification
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "code: %s, " % _code
output += "content: %s, " % _content
output += "create_time: %s, " % _create_time
output += "id: %s, " % _id
output += "persistent: %s, " % _persistent
output += "sender_id: %s, " % _sender_id
output += "subject: %s, " % _subject
return output
# A collection of zero or more notifications.
class ApiNotificationList extends NakamaAsyncResult:
const _SCHEMA = {
"cacheable_cursor": {"name": "_cacheable_cursor", "type": TYPE_STRING, "required": false},
"notifications": {"name": "_notifications", "type": TYPE_ARRAY, "required": false, "content": "ApiNotification"},
}
# Use this cursor to paginate notifications. Cache this to catch up to new notifications.
var _cacheable_cursor
var cacheable_cursor : String:
get:
return "" if not _cacheable_cursor is String else String(_cacheable_cursor)
# Collection of notifications.
var _notifications
var notifications : Array:
get:
return Array() if not _notifications is Array else Array(_notifications)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiNotificationList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiNotificationList", p_dict), ApiNotificationList) as ApiNotificationList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "cacheable_cursor: %s, " % _cacheable_cursor
output += "notifications: %s, " % [_notifications]
return output
# Operator that can be used to override the one set in the leaderboard.
# - NO_OVERRIDE: Do not override the leaderboard operator.
# - BEST: Override the leaderboard operator with BEST.
# - SET: Override the leaderboard operator with SET.
# - INCREMENT: Override the leaderboard operator with INCREMENT.
# - DECREMENT: Override the leaderboard operator with DECREMENT.# [ - NO_OVERRIDE: Do not override the leaderboard operator. - BEST: Override the leaderboard operator with BEST. - SET: Override the leaderboard operator with SET. - INCREMENT: Override the leaderboard operator with INCREMENT. - DECREMENT: Override the leaderboard operator with DECREMENT.]
enum ApiOperator {NO_OVERRIDE = 0,BEST = 1,SET = 2,INCREMENT = 3,DECREMENT = 4,}
# Storage objects to get.
class ApiReadStorageObjectId extends NakamaAsyncResult:
const _SCHEMA = {
"collection": {"name": "_collection", "type": TYPE_STRING, "required": false},
"key": {"name": "_key", "type": TYPE_STRING, "required": false},
"user_id": {"name": "_user_id", "type": TYPE_STRING, "required": false},
}
# The collection which stores the object.
var _collection
var collection : String:
get:
return "" if not _collection is String else String(_collection)
# The key of the object within the collection.
var _key
var key : String:
get:
return "" if not _key is String else String(_key)
# The user owner of the object.
var _user_id
var user_id : String:
get:
return "" if not _user_id is String else String(_user_id)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiReadStorageObjectId:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiReadStorageObjectId", p_dict), ApiReadStorageObjectId) as ApiReadStorageObjectId
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "collection: %s, " % _collection
output += "key: %s, " % _key
output += "user_id: %s, " % _user_id
return output
# Batch get storage objects.
class ApiReadStorageObjectsRequest extends NakamaAsyncResult:
const _SCHEMA = {
"object_ids": {"name": "_object_ids", "type": TYPE_ARRAY, "required": false, "content": "ApiReadStorageObjectId"},
}
# Batch of storage objects.
var _object_ids
var object_ids : Array:
get:
return Array() if not _object_ids is Array else Array(_object_ids)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiReadStorageObjectsRequest:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiReadStorageObjectsRequest", p_dict), ApiReadStorageObjectsRequest) as ApiReadStorageObjectsRequest
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "object_ids: %s, " % [_object_ids]
return output
# Execute an Lua function on the server.
class ApiRpc extends NakamaAsyncResult:
const _SCHEMA = {
"http_key": {"name": "_http_key", "type": TYPE_STRING, "required": false},
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
"payload": {"name": "_payload", "type": TYPE_STRING, "required": false},
}
# The authentication key used when executed as a non-client HTTP request.
var _http_key
var http_key : String:
get:
return "" if not _http_key is String else String(_http_key)
# The identifier of the function.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
# The payload of the function which must be a JSON object.
var _payload
var payload : String:
get:
return "" if not _payload is String else String(_payload)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiRpc:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiRpc", p_dict), ApiRpc) as ApiRpc
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "http_key: %s, " % _http_key
output += "id: %s, " % _id
output += "payload: %s, " % _payload
return output
# A user's session used to authenticate messages.
class ApiSession extends NakamaAsyncResult:
const _SCHEMA = {
"created": {"name": "_created", "type": TYPE_BOOL, "required": false},
"refresh_token": {"name": "_refresh_token", "type": TYPE_STRING, "required": false},
"token": {"name": "_token", "type": TYPE_STRING, "required": false},
}
# True if the corresponding account was just created, false otherwise.
var _created
var created : bool:
get:
return false if not _created is bool else bool(_created)
# Refresh token that can be used for session token renewal.
var _refresh_token
var refresh_token : String:
get:
return "" if not _refresh_token is String else String(_refresh_token)
# Authentication credentials.
var _token
var token : String:
get:
return "" if not _token is String else String(_token)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSession:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiSession", p_dict), ApiSession) as ApiSession
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "created: %s, " % _created
output += "refresh_token: %s, " % _refresh_token
output += "token: %s, " % _token
return output
# Log out a session, invalidate a refresh token, or log out all sessions/refresh tokens for a user.
class ApiSessionLogoutRequest extends NakamaAsyncResult:
const _SCHEMA = {
"refresh_token": {"name": "_refresh_token", "type": TYPE_STRING, "required": false},
"token": {"name": "_token", "type": TYPE_STRING, "required": false},
}
# Refresh token to invalidate.
var _refresh_token
var refresh_token : String:
get:
return "" if not _refresh_token is String else String(_refresh_token)
# Session token to log out.
var _token
var token : String:
get:
return "" if not _token is String else String(_token)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSessionLogoutRequest:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiSessionLogoutRequest", p_dict), ApiSessionLogoutRequest) as ApiSessionLogoutRequest
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "refresh_token: %s, " % _refresh_token
output += "token: %s, " % _token
return output
# Authenticate against the server with a refresh token.
class ApiSessionRefreshRequest extends NakamaAsyncResult:
const _SCHEMA = {
"token": {"name": "_token", "type": TYPE_STRING, "required": false},
"vars": {"name": "_vars", "type": TYPE_DICTIONARY, "required": false, "content": TYPE_STRING},
}
# Refresh token.
var _token
var token : String:
get:
return "" if not _token is String else String(_token)
# Extra information that will be bundled in the session token.
var _vars
var vars : Dictionary:
get:
return Dictionary() if not _vars is Dictionary else _vars.duplicate()
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSessionRefreshRequest:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiSessionRefreshRequest", p_dict), ApiSessionRefreshRequest) as ApiSessionRefreshRequest
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "token: %s, " % _token
var map_string : String = ""
if typeof(_vars) == TYPE_DICTIONARY:
for k in _vars:
map_string += "{%s=%s}, " % [k, _vars[k]]
output += "vars: [%s], " % map_string
return output
# An object within the storage engine.
class ApiStorageObject extends NakamaAsyncResult:
const _SCHEMA = {
"collection": {"name": "_collection", "type": TYPE_STRING, "required": false},
"create_time": {"name": "_create_time", "type": TYPE_STRING, "required": false},
"key": {"name": "_key", "type": TYPE_STRING, "required": false},
"permission_read": {"name": "_permission_read", "type": TYPE_INT, "required": false},
"permission_write": {"name": "_permission_write", "type": TYPE_INT, "required": false},
"update_time": {"name": "_update_time", "type": TYPE_STRING, "required": false},
"user_id": {"name": "_user_id", "type": TYPE_STRING, "required": false},
"value": {"name": "_value", "type": TYPE_STRING, "required": false},
"version": {"name": "_version", "type": TYPE_STRING, "required": false},
}
# The collection which stores the object.
var _collection
var collection : String:
get:
return "" if not _collection is String else String(_collection)
# The UNIX time when the object was created.
var _create_time
var create_time : String:
get:
return "" if not _create_time is String else String(_create_time)
# The key of the object within the collection.
var _key
var key : String:
get:
return "" if not _key is String else String(_key)
# The read access permissions for the object.
var _permission_read
var permission_read : int:
get:
return 0 if not _permission_read is int else int(_permission_read)
# The write access permissions for the object.
var _permission_write
var permission_write : int:
get:
return 0 if not _permission_write is int else int(_permission_write)
# The UNIX time when the object was last updated.
var _update_time
var update_time : String:
get:
return "" if not _update_time is String else String(_update_time)
# The user owner of the object.
var _user_id
var user_id : String:
get:
return "" if not _user_id is String else String(_user_id)
# The value of the object.
var _value
var value : String:
get:
return "" if not _value is String else String(_value)
# The version hash of the object.
var _version
var version : String:
get:
return "" if not _version is String else String(_version)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObject:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiStorageObject", p_dict), ApiStorageObject) as ApiStorageObject
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "collection: %s, " % _collection
output += "create_time: %s, " % _create_time
output += "key: %s, " % _key
output += "permission_read: %s, " % _permission_read
output += "permission_write: %s, " % _permission_write
output += "update_time: %s, " % _update_time
output += "user_id: %s, " % _user_id
output += "value: %s, " % _value
output += "version: %s, " % _version
return output
# A storage acknowledgement.
class ApiStorageObjectAck extends NakamaAsyncResult:
const _SCHEMA = {
"collection": {"name": "_collection", "type": TYPE_STRING, "required": false},
"key": {"name": "_key", "type": TYPE_STRING, "required": false},
"user_id": {"name": "_user_id", "type": TYPE_STRING, "required": false},
"version": {"name": "_version", "type": TYPE_STRING, "required": false},
}
# The collection which stores the object.
var _collection
var collection : String:
get:
return "" if not _collection is String else String(_collection)
# The key of the object within the collection.
var _key
var key : String:
get:
return "" if not _key is String else String(_key)
# The owner of the object.
var _user_id
var user_id : String:
get:
return "" if not _user_id is String else String(_user_id)
# The version hash of the object.
var _version
var version : String:
get:
return "" if not _version is String else String(_version)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObjectAck:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiStorageObjectAck", p_dict), ApiStorageObjectAck) as ApiStorageObjectAck
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "collection: %s, " % _collection
output += "key: %s, " % _key
output += "user_id: %s, " % _user_id
output += "version: %s, " % _version
return output
# Batch of acknowledgements for the storage object write.
class ApiStorageObjectAcks extends NakamaAsyncResult:
const _SCHEMA = {
"acks": {"name": "_acks", "type": TYPE_ARRAY, "required": false, "content": "ApiStorageObjectAck"},
}
# Batch of storage write acknowledgements.
var _acks
var acks : Array:
get:
return Array() if not _acks is Array else Array(_acks)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObjectAcks:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiStorageObjectAcks", p_dict), ApiStorageObjectAcks) as ApiStorageObjectAcks
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "acks: %s, " % [_acks]
return output
# List of storage objects.
class ApiStorageObjectList extends NakamaAsyncResult:
const _SCHEMA = {
"cursor": {"name": "_cursor", "type": TYPE_STRING, "required": false},
"objects": {"name": "_objects", "type": TYPE_ARRAY, "required": false, "content": "ApiStorageObject"},
}
# The cursor for the next page of results, if any.
var _cursor
var cursor : String:
get:
return "" if not _cursor is String else String(_cursor)
# The list of storage objects.
var _objects
var objects : Array:
get:
return Array() if not _objects is Array else Array(_objects)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObjectList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiStorageObjectList", p_dict), ApiStorageObjectList) as ApiStorageObjectList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "cursor: %s, " % _cursor
output += "objects: %s, " % [_objects]
return output
# Batch of storage objects.
class ApiStorageObjects extends NakamaAsyncResult:
const _SCHEMA = {
"objects": {"name": "_objects", "type": TYPE_ARRAY, "required": false, "content": "ApiStorageObject"},
}
# The batch of storage objects.
var _objects
var objects : Array:
get:
return Array() if not _objects is Array else Array(_objects)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiStorageObjects:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiStorageObjects", p_dict), ApiStorageObjects) as ApiStorageObjects
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "objects: %s, " % [_objects]
return output
# Environment where a purchase/subscription took place,
# - UNKNOWN: Unknown environment.
# - SANDBOX: Sandbox/test environment.
# - PRODUCTION: Production environment.# [- UNKNOWN: Unknown environment. - SANDBOX: Sandbox/test environment. - PRODUCTION: Production environment.]
enum ApiStoreEnvironment {UNKNOWN = 0,SANDBOX = 1,PRODUCTION = 2,}
# Validation Provider,
# - APPLE_APP_STORE: Apple App Store
# - GOOGLE_PLAY_STORE: Google Play Store
# - HUAWEI_APP_GALLERY: Huawei App Gallery# [- APPLE_APP_STORE: Apple App Store - GOOGLE_PLAY_STORE: Google Play Store - HUAWEI_APP_GALLERY: Huawei App Gallery]
enum ApiStoreProvider {APPLE_APP_STORE = 0,GOOGLE_PLAY_STORE = 1,HUAWEI_APP_GALLERY = 2,}
# A list of validated subscriptions stored by Nakama.
class ApiSubscriptionList extends NakamaAsyncResult:
const _SCHEMA = {
"cursor": {"name": "_cursor", "type": TYPE_STRING, "required": false},
"prev_cursor": {"name": "_prev_cursor", "type": TYPE_STRING, "required": false},
"validated_subscriptions": {"name": "_validated_subscriptions", "type": TYPE_ARRAY, "required": false, "content": "ApiValidatedSubscription"},
}
# The cursor to send when retrieving the next page, if any.
var _cursor
var cursor : String:
get:
return "" if not _cursor is String else String(_cursor)
# The cursor to send when retrieving the previous page, if any.
var _prev_cursor
var prev_cursor : String:
get:
return "" if not _prev_cursor is String else String(_prev_cursor)
# Stored validated subscriptions.
var _validated_subscriptions
var validated_subscriptions : Array:
get:
return Array() if not _validated_subscriptions is Array else Array(_validated_subscriptions)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiSubscriptionList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiSubscriptionList", p_dict), ApiSubscriptionList) as ApiSubscriptionList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "cursor: %s, " % _cursor
output += "prev_cursor: %s, " % _prev_cursor
output += "validated_subscriptions: %s, " % [_validated_subscriptions]
return output
# A tournament on the server.
class ApiTournament extends NakamaAsyncResult:
const _SCHEMA = {
"authoritative": {"name": "_authoritative", "type": TYPE_BOOL, "required": false},
"can_enter": {"name": "_can_enter", "type": TYPE_BOOL, "required": false},
"category": {"name": "_category", "type": TYPE_INT, "required": false},
"create_time": {"name": "_create_time", "type": TYPE_STRING, "required": false},
"description": {"name": "_description", "type": TYPE_STRING, "required": false},
"duration": {"name": "_duration", "type": TYPE_INT, "required": false},
"end_active": {"name": "_end_active", "type": TYPE_INT, "required": false},
"end_time": {"name": "_end_time", "type": TYPE_STRING, "required": false},
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
"max_num_score": {"name": "_max_num_score", "type": TYPE_INT, "required": false},
"max_size": {"name": "_max_size", "type": TYPE_INT, "required": false},
"metadata": {"name": "_metadata", "type": TYPE_STRING, "required": false},
"next_reset": {"name": "_next_reset", "type": TYPE_INT, "required": false},
"operator": {"name": "_operator", "type": TYPE_INT, "required": false},
"prev_reset": {"name": "_prev_reset", "type": TYPE_INT, "required": false},
"size": {"name": "_size", "type": TYPE_INT, "required": false},
"sort_order": {"name": "_sort_order", "type": TYPE_INT, "required": false},
"start_active": {"name": "_start_active", "type": TYPE_INT, "required": false},
"start_time": {"name": "_start_time", "type": TYPE_STRING, "required": false},
"title": {"name": "_title", "type": TYPE_STRING, "required": false},
}
# Whether the leaderboard was created authoritatively or not.
var _authoritative
var authoritative : bool:
get:
return false if not _authoritative is bool else bool(_authoritative)
# True if the tournament is active and can enter. A computed value.
var _can_enter
var can_enter : bool:
get:
return false if not _can_enter is bool else bool(_can_enter)
# The category of the tournament. e.g. "vip" could be category 1.
var _category
var category : int:
get:
return 0 if not _category is int else int(_category)
# The UNIX time when the tournament was created.
var _create_time
var create_time : String:
get:
return "" if not _create_time is String else String(_create_time)
# The description of the tournament. May be blank.
var _description
var description : String:
get:
return "" if not _description is String else String(_description)
# Duration of the tournament in seconds.
var _duration
var duration : int:
get:
return 0 if not _duration is int else int(_duration)
# The UNIX time when the tournament stops being active until next reset. A computed value.
var _end_active
var end_active : int:
get:
return 0 if not _end_active is int else int(_end_active)
# The UNIX time when the tournament will be stopped.
var _end_time
var end_time : String:
get:
return "" if not _end_time is String else String(_end_time)
# The ID of the tournament.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
# The maximum score updates allowed per player for the current tournament.
var _max_num_score
var max_num_score : int:
get:
return 0 if not _max_num_score is int else int(_max_num_score)
# The maximum number of players for the tournament.
var _max_size
var max_size : int:
get:
return 0 if not _max_size is int else int(_max_size)
# Additional information stored as a JSON object.
var _metadata
var metadata : String:
get:
return "" if not _metadata is String else String(_metadata)
# The UNIX time when the tournament is next playable. A computed value.
var _next_reset
var next_reset : int:
get:
return 0 if not _next_reset is int else int(_next_reset)
# Operator.
var _operator
var operator : int:
get:
return ApiOperator.values()[0] if not ApiOperator.values().has(_operator) else _operator
# The UNIX time when the tournament was last reset. A computed value.
var _prev_reset
var prev_reset : int:
get:
return 0 if not _prev_reset is int else int(_prev_reset)
# The current number of players in the tournament.
var _size
var size : int:
get:
return 0 if not _size is int else int(_size)
# ASC (0) or DESC (1) sort mode of scores in the tournament.
var _sort_order
var sort_order : int:
get:
return 0 if not _sort_order is int else int(_sort_order)
# The UNIX time when the tournament start being active. A computed value.
var _start_active
var start_active : int:
get:
return 0 if not _start_active is int else int(_start_active)
# The UNIX time when the tournament will start.
var _start_time
var start_time : String:
get:
return "" if not _start_time is String else String(_start_time)
# The title for the tournament.
var _title
var title : String:
get:
return "" if not _title is String else String(_title)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiTournament:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiTournament", p_dict), ApiTournament) as ApiTournament
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "authoritative: %s, " % _authoritative
output += "can_enter: %s, " % _can_enter
output += "category: %s, " % _category
output += "create_time: %s, " % _create_time
output += "description: %s, " % _description
output += "duration: %s, " % _duration
output += "end_active: %s, " % _end_active
output += "end_time: %s, " % _end_time
output += "id: %s, " % _id
output += "max_num_score: %s, " % _max_num_score
output += "max_size: %s, " % _max_size
output += "metadata: %s, " % _metadata
output += "next_reset: %s, " % _next_reset
output += "operator: %s, " % _operator
output += "prev_reset: %s, " % _prev_reset
output += "size: %s, " % _size
output += "sort_order: %s, " % _sort_order
output += "start_active: %s, " % _start_active
output += "start_time: %s, " % _start_time
output += "title: %s, " % _title
return output
# A list of tournaments.
class ApiTournamentList extends NakamaAsyncResult:
const _SCHEMA = {
"cursor": {"name": "_cursor", "type": TYPE_STRING, "required": false},
"tournaments": {"name": "_tournaments", "type": TYPE_ARRAY, "required": false, "content": "ApiTournament"},
}
# A pagination cursor (optional).
var _cursor
var cursor : String:
get:
return "" if not _cursor is String else String(_cursor)
# The list of tournaments returned.
var _tournaments
var tournaments : Array:
get:
return Array() if not _tournaments is Array else Array(_tournaments)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiTournamentList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiTournamentList", p_dict), ApiTournamentList) as ApiTournamentList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "cursor: %s, " % _cursor
output += "tournaments: %s, " % [_tournaments]
return output
# A set of tournament records which may be part of a tournament records page or a batch of individual records.
class ApiTournamentRecordList extends NakamaAsyncResult:
const _SCHEMA = {
"next_cursor": {"name": "_next_cursor", "type": TYPE_STRING, "required": false},
"owner_records": {"name": "_owner_records", "type": TYPE_ARRAY, "required": false, "content": "ApiLeaderboardRecord"},
"prev_cursor": {"name": "_prev_cursor", "type": TYPE_STRING, "required": false},
"records": {"name": "_records", "type": TYPE_ARRAY, "required": false, "content": "ApiLeaderboardRecord"},
}
# The cursor to send when retireving the next page (optional).
var _next_cursor
var next_cursor : String:
get:
return "" if not _next_cursor is String else String(_next_cursor)
# A batched set of tournament records belonging to specified owners.
var _owner_records
var owner_records : Array:
get:
return Array() if not _owner_records is Array else Array(_owner_records)
# The cursor to send when retrieving the previous page (optional).
var _prev_cursor
var prev_cursor : String:
get:
return "" if not _prev_cursor is String else String(_prev_cursor)
# A list of tournament records.
var _records
var records : Array:
get:
return Array() if not _records is Array else Array(_records)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiTournamentRecordList:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiTournamentRecordList", p_dict), ApiTournamentRecordList) as ApiTournamentRecordList
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "next_cursor: %s, " % _next_cursor
output += "owner_records: %s, " % [_owner_records]
output += "prev_cursor: %s, " % _prev_cursor
output += "records: %s, " % [_records]
return output
# Update a user's account details.
class ApiUpdateAccountRequest extends NakamaAsyncResult:
const _SCHEMA = {
"avatar_url": {"name": "_avatar_url", "type": TYPE_STRING, "required": false},
"display_name": {"name": "_display_name", "type": TYPE_STRING, "required": false},
"lang_tag": {"name": "_lang_tag", "type": TYPE_STRING, "required": false},
"location": {"name": "_location", "type": TYPE_STRING, "required": false},
"timezone": {"name": "_timezone", "type": TYPE_STRING, "required": false},
"username": {"name": "_username", "type": TYPE_STRING, "required": false},
}
# A URL for an avatar image.
var _avatar_url
var avatar_url : String:
get:
return "" if not _avatar_url is String else String(_avatar_url)
# The display name of the user.
var _display_name
var display_name : String:
get:
return "" if not _display_name is String else String(_display_name)
# The language expected to be a tag which follows the BCP-47 spec.
var _lang_tag
var lang_tag : String:
get:
return "" if not _lang_tag is String else String(_lang_tag)
# The location set by the user.
var _location
var location : String:
get:
return "" if not _location is String else String(_location)
# The timezone set by the user.
var _timezone
var timezone : String:
get:
return "" if not _timezone is String else String(_timezone)
# The username of the user's account.
var _username
var username : String:
get:
return "" if not _username is String else String(_username)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUpdateAccountRequest:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiUpdateAccountRequest", p_dict), ApiUpdateAccountRequest) as ApiUpdateAccountRequest
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "avatar_url: %s, " % _avatar_url
output += "display_name: %s, " % _display_name
output += "lang_tag: %s, " % _lang_tag
output += "location: %s, " % _location
output += "timezone: %s, " % _timezone
output += "username: %s, " % _username
return output
# Update fields in a given group.
class ApiUpdateGroupRequest extends NakamaAsyncResult:
const _SCHEMA = {
"avatar_url": {"name": "_avatar_url", "type": TYPE_STRING, "required": false},
"description": {"name": "_description", "type": TYPE_STRING, "required": false},
"group_id": {"name": "_group_id", "type": TYPE_STRING, "required": false},
"lang_tag": {"name": "_lang_tag", "type": TYPE_STRING, "required": false},
"name": {"name": "_name", "type": TYPE_STRING, "required": false},
"open": {"name": "_open", "type": TYPE_BOOL, "required": false},
}
# Avatar URL.
var _avatar_url
var avatar_url : String:
get:
return "" if not _avatar_url is String else String(_avatar_url)
# Description string.
var _description
var description : String:
get:
return "" if not _description is String else String(_description)
# The ID of the group to update.
var _group_id
var group_id : String:
get:
return "" if not _group_id is String else String(_group_id)
# Lang tag.
var _lang_tag
var lang_tag : String:
get:
return "" if not _lang_tag is String else String(_lang_tag)
# Name.
var _name
var name : String:
get:
return "" if not _name is String else String(_name)
# Open is true if anyone should be allowed to join, or false if joins must be approved by a group admin.
var _open
var open : bool:
get:
return false if not _open is bool else bool(_open)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUpdateGroupRequest:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiUpdateGroupRequest", p_dict), ApiUpdateGroupRequest) as ApiUpdateGroupRequest
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "avatar_url: %s, " % _avatar_url
output += "description: %s, " % _description
output += "group_id: %s, " % _group_id
output += "lang_tag: %s, " % _lang_tag
output += "name: %s, " % _name
output += "open: %s, " % _open
return output
# A user in the server.
class ApiUser extends NakamaAsyncResult:
const _SCHEMA = {
"apple_id": {"name": "_apple_id", "type": TYPE_STRING, "required": false},
"avatar_url": {"name": "_avatar_url", "type": TYPE_STRING, "required": false},
"create_time": {"name": "_create_time", "type": TYPE_STRING, "required": false},
"display_name": {"name": "_display_name", "type": TYPE_STRING, "required": false},
"edge_count": {"name": "_edge_count", "type": TYPE_INT, "required": false},
"facebook_id": {"name": "_facebook_id", "type": TYPE_STRING, "required": false},
"facebook_instant_game_id": {"name": "_facebook_instant_game_id", "type": TYPE_STRING, "required": false},
"gamecenter_id": {"name": "_gamecenter_id", "type": TYPE_STRING, "required": false},
"google_id": {"name": "_google_id", "type": TYPE_STRING, "required": false},
"id": {"name": "_id", "type": TYPE_STRING, "required": false},
"lang_tag": {"name": "_lang_tag", "type": TYPE_STRING, "required": false},
"location": {"name": "_location", "type": TYPE_STRING, "required": false},
"metadata": {"name": "_metadata", "type": TYPE_STRING, "required": false},
"online": {"name": "_online", "type": TYPE_BOOL, "required": false},
"steam_id": {"name": "_steam_id", "type": TYPE_STRING, "required": false},
"timezone": {"name": "_timezone", "type": TYPE_STRING, "required": false},
"update_time": {"name": "_update_time", "type": TYPE_STRING, "required": false},
"username": {"name": "_username", "type": TYPE_STRING, "required": false},
}
# The Apple Sign In ID in the user's account.
var _apple_id
var apple_id : String:
get:
return "" if not _apple_id is String else String(_apple_id)
# A URL for an avatar image.
var _avatar_url
var avatar_url : String:
get:
return "" if not _avatar_url is String else String(_avatar_url)
# The UNIX time when the user was created.
var _create_time
var create_time : String:
get:
return "" if not _create_time is String else String(_create_time)
# The display name of the user.
var _display_name
var display_name : String:
get:
return "" if not _display_name is String else String(_display_name)
# Number of related edges to this user.
var _edge_count
var edge_count : int:
get:
return 0 if not _edge_count is int else int(_edge_count)
# The Facebook id in the user's account.
var _facebook_id
var facebook_id : String:
get:
return "" if not _facebook_id is String else String(_facebook_id)
# The Facebook Instant Game ID in the user's account.
var _facebook_instant_game_id
var facebook_instant_game_id : String:
get:
return "" if not _facebook_instant_game_id is String else String(_facebook_instant_game_id)
# The Apple Game Center in of the user's account.
var _gamecenter_id
var gamecenter_id : String:
get:
return "" if not _gamecenter_id is String else String(_gamecenter_id)
# The Google id in the user's account.
var _google_id
var google_id : String:
get:
return "" if not _google_id is String else String(_google_id)
# The id of the user's account.
var _id
var id : String:
get:
return "" if not _id is String else String(_id)
# The language expected to be a tag which follows the BCP-47 spec.
var _lang_tag
var lang_tag : String:
get:
return "" if not _lang_tag is String else String(_lang_tag)
# The location set by the user.
var _location
var location : String:
get:
return "" if not _location is String else String(_location)
# Additional information stored as a JSON object.
var _metadata
var metadata : String:
get:
return "" if not _metadata is String else String(_metadata)
# Indicates whether the user is currently online.
var _online
var online : bool:
get:
return false if not _online is bool else bool(_online)
# The Steam id in the user's account.
var _steam_id
var steam_id : String:
get:
return "" if not _steam_id is String else String(_steam_id)
# The timezone set by the user.
var _timezone
var timezone : String:
get:
return "" if not _timezone is String else String(_timezone)
# The UNIX time when the user was last updated.
var _update_time
var update_time : String:
get:
return "" if not _update_time is String else String(_update_time)
# The username of the user's account.
var _username
var username : String:
get:
return "" if not _username is String else String(_username)
func _init(p_exception = null):
super(p_exception)
static func create(p_ns : GDScript, p_dict : Dictionary) -> ApiUser:
return _safe_ret(NakamaSerializer.deserialize(p_ns, "ApiUser", p_dict), ApiUser) as ApiUser
func serialize() -> Dictionary:
return NakamaSerializer.serialize(self)
func _to_string() -> String:
if is_exception():
return get_exception()._to_string()
var output : String = ""
output += "apple_id: %s, " % _apple_id
output += "avatar_url: %s, " % _avatar_url
output += "create_time: %s, " % _create_time
output += "display_name: %s, " % _display_name
output += "edge_count: %s, " % _edge_count
output += "facebook_id: %s, " % _facebook_id
output += "facebook_instant_game_id: %s, " % _facebook_instant_game_id
output += "gamecenter_id: %s, " % _gamecenter_id
output += "google_id: %s, " % _google_id
output += "id: %s, " % _id
output += "lang_tag: %s, " % _lang_tag
output += "location: %s, " % _location
output += "metadata: %s, " % _metadata
output += "onli
gitextract_l9w5256r/
├── .github/
│ ├── CODEOWNERS
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── RCLONE.md
│ ├── TRANSLATING.md
│ └── workflows/
│ └── github-actions-youtd.yml
├── .gitignore
├── LICENSE
├── README.md
├── addons/
│ ├── com.heroiclabs.nakama/
│ │ ├── Nakama.gd
│ │ ├── Satori/
│ │ │ ├── NakamaEvent.gd
│ │ │ ├── SatoriAPI.gd
│ │ │ ├── SatoriClient.gd
│ │ │ ├── SatoriHttpAdapter.gd
│ │ │ ├── SatoriSession.gd
│ │ │ └── utils/
│ │ │ ├── SatoriAsyncResult.gd
│ │ │ ├── SatoriException.gd
│ │ │ ├── SatoriLogger.gd
│ │ │ └── SatoriSerializer.gd
│ │ ├── Satori.gd
│ │ ├── api/
│ │ │ ├── NakamaAPI.gd
│ │ │ ├── NakamaRTAPI.gd
│ │ │ ├── NakamaRTMessage.gd
│ │ │ ├── NakamaSession.gd
│ │ │ ├── NakamaStorageObjectId.gd
│ │ │ └── NakamaWriteStorageObject.gd
│ │ ├── client/
│ │ │ ├── NakamaClient.gd
│ │ │ └── NakamaHTTPAdapter.gd
│ │ ├── dotnet-utils/
│ │ │ ├── GodotHttpAdapter.cs
│ │ │ ├── GodotLogger.cs
│ │ │ └── GodotWebSocketAdapter.cs
│ │ ├── socket/
│ │ │ ├── NakamaSocket.gd
│ │ │ └── NakamaSocketAdapter.gd
│ │ └── utils/
│ │ ├── NakamaAsyncResult.gd
│ │ ├── NakamaException.gd
│ │ ├── NakamaLogger.gd
│ │ ├── NakamaMultiplayerBridge.gd
│ │ ├── NakamaMultiplayerPeer.gd
│ │ └── NakamaSerializer.gd
│ └── nakama-webrtc/
│ ├── LICENSE.txt
│ └── OnlineMatch.gd
├── assets/
│ ├── LICENSE.md
│ ├── README.md
│ ├── creeps/
│ │ ├── README.md
│ │ └── orc/
│ │ ├── air/
│ │ │ ├── fly_E.png.import
│ │ │ ├── fly_N.png.import
│ │ │ ├── fly_NE.png.import
│ │ │ ├── fly_NW.png.import
│ │ │ ├── fly_S.png.import
│ │ │ ├── fly_SE.png.import
│ │ │ ├── fly_SW.png.import
│ │ │ ├── fly_W.png.import
│ │ │ ├── metadata.csv
│ │ │ └── metadata.csv.import
│ │ ├── boss/
│ │ │ ├── death_E.png.import
│ │ │ ├── death_N.png.import
│ │ │ ├── death_S.png.import
│ │ │ ├── death_W.png.import
│ │ │ ├── metadata.csv
│ │ │ ├── metadata.csv.import
│ │ │ ├── slow_run_E.png.import
│ │ │ ├── slow_run_N.png.import
│ │ │ ├── slow_run_S.png.import
│ │ │ └── slow_run_W.png.import
│ │ ├── champion/
│ │ │ ├── death_E.png.import
│ │ │ ├── death_N.png.import
│ │ │ ├── death_S.png.import
│ │ │ ├── death_W.png.import
│ │ │ ├── metadata.csv
│ │ │ ├── metadata.csv.import
│ │ │ ├── slow_run_E.png.import
│ │ │ ├── slow_run_N.png.import
│ │ │ ├── slow_run_S.png.import
│ │ │ └── slow_run_W.png.import
│ │ ├── mass/
│ │ │ ├── death_E.png.import
│ │ │ ├── death_N.png.import
│ │ │ ├── death_S.png.import
│ │ │ ├── death_W.png.import
│ │ │ ├── metadata.csv
│ │ │ ├── metadata.csv.import
│ │ │ ├── slow_run_E.png.import
│ │ │ ├── slow_run_N.png.import
│ │ │ ├── slow_run_S.png.import
│ │ │ └── slow_run_W.png.import
│ │ └── normal/
│ │ ├── death_E.png.import
│ │ ├── death_N.png.import
│ │ ├── death_S.png.import
│ │ ├── death_W.png.import
│ │ ├── metadata.csv
│ │ ├── metadata.csv.import
│ │ ├── slow_run_E.png.import
│ │ ├── slow_run_N.png.import
│ │ ├── slow_run_S.png.import
│ │ └── slow_run_W.png.import
│ ├── effects/
│ │ ├── arrow.png.import
│ │ ├── bdragon/
│ │ │ ├── README.md
│ │ │ ├── ancient_protector_missile_293.png.import
│ │ │ ├── animated_dead_target_102.png.import
│ │ │ ├── apply_potion_537.png.import
│ │ │ ├── arcane_tower_attack_024.png.import
│ │ │ ├── avatar_caster_10.png.import
│ │ │ ├── banshee_missile_487.png.import
│ │ │ ├── blink_target_720.png.import
│ │ │ ├── blood_splatter_376.png.import
│ │ │ ├── build_tower_648.png.import
│ │ │ ├── charm_target_703.png.import
│ │ │ ├── cloud_of_fog_382.png.import
│ │ │ ├── cloud_of_fog_small_428.png.import
│ │ │ ├── cripple_target_198.png.import
│ │ │ ├── crushing_wave_damage_584.png.import
│ │ │ ├── crypt_fiend_eggsack_528.png.import
│ │ │ ├── cyclone_target_269.png.import
│ │ │ ├── death_and_decay_71.png.import
│ │ │ ├── death_coil_special_728.png.import
│ │ │ ├── devour_509.png.import
│ │ │ ├── dispel_magic_target_456.png.import
│ │ │ ├── doom_death_451.png.import
│ │ │ ├── faerie_dragon_missile_482.png.import
│ │ │ ├── firelord_death_explode_77.png.import
│ │ │ ├── flame_strike_embers_702.png.import
│ │ │ ├── flower_aura_655.png.import
│ │ │ ├── frag_boom_spawn_426.png.import
│ │ │ ├── freezing_breath_519.png.import
│ │ │ ├── frost_armor_damage_474.png.import
│ │ │ ├── frost_bolt_missile_063.png.import
│ │ │ ├── glaive_746.png.import
│ │ │ ├── gold_credit_673.png.import
│ │ │ ├── gold_credit_88.png.import
│ │ │ ├── healing_wave_target_453.png.import
│ │ │ ├── holy_bolt_241.png.import
│ │ │ ├── immolation_damage_541.png.import
│ │ │ ├── impale_hit_target_529.png.import
│ │ │ ├── impale_target_dust_025.png.import
│ │ │ ├── incinerate_76.png.import
│ │ │ ├── keeper_grove_missile_297.png.import
│ │ │ ├── level_up_455.png.import
│ │ │ ├── mana_burn_target_388.png.import
│ │ │ ├── mana_shield_026.png.import
│ │ │ ├── mass_teleport_caster_335.png.import
│ │ │ ├── mass_teleport_target_315.png.import
│ │ │ ├── mirror_image_caster_711.png.import
│ │ │ ├── moonwell_target_584.png.import
│ │ │ ├── ne_cancel_death_672.png.import
│ │ │ ├── ne_death_612.png.import
│ │ │ ├── placeholder_481.png.import
│ │ │ ├── polymorph_target_735.png.import
│ │ │ ├── projectile_explosion_299.png.import
│ │ │ ├── purge_buff_target_195.png.import
│ │ │ ├── quillspray_747.png.import
│ │ │ ├── raise_skeleton_624.png.import
│ │ │ ├── replenish_mana_334.png.import
│ │ │ ├── revive_human_623.png.import
│ │ │ ├── roar_506.png.import
│ │ │ ├── roots_235.png.import
│ │ │ ├── shackle_439.png.import
│ │ │ ├── shockwave_missile_440.png.import
│ │ │ ├── silence_area_611.png.import
│ │ │ ├── small_flame_spawn_240.png.import
│ │ │ ├── spell_aiil_452.png.import
│ │ │ ├── spell_ailb_723.png.import
│ │ │ ├── spell_aima_194.png.import
│ │ │ ├── spell_aire_174.png.import
│ │ │ ├── spell_aiso_295.png.import
│ │ │ ├── spell_alim_136.png.import
│ │ │ ├── spell_breaker_target_613.png.import
│ │ │ ├── spirit_link_target_175.png.import
│ │ │ ├── stampede_missile_death_63.png.import
│ │ │ ├── starfall_target_257.png.import
│ │ │ ├── thunder_clap_466.png.import
│ │ │ ├── undead_dissipate_633.png.import
│ │ │ ├── upgrade_tower_016.png.import
│ │ │ ├── vampiric_aura_199.png.import
│ │ │ ├── voodoo_aura_182.png.import
│ │ │ ├── warstomp_caster_536.png.import
│ │ │ ├── wind_shear_559.png.import
│ │ │ ├── wisp_explode_003.png.import
│ │ │ ├── ziggurat_frost_missile_325.png.import
│ │ │ └── zombify_target_274.png.import
│ │ ├── death_explode.png.import
│ │ ├── lightning_long.png.import
│ │ └── stun.png.import
│ ├── fonts/
│ │ ├── Friz Quadrata Std Medium.otf.import
│ │ └── NotoSansSC-Medium.ttf.import
│ ├── hud/
│ │ ├── bitmaps/
│ │ │ ├── circle_bitmap_100x100.png.import
│ │ │ └── circle_bitmap_256x256.png.import
│ │ ├── checkbox.png.import
│ │ ├── circle_bitmap_256x256.png.import
│ │ ├── darkness_face.png.import
│ │ ├── element_progress_circle.png.import
│ │ ├── horadric_cube.png.import
│ │ ├── hud_atlas.png.import
│ │ ├── misc2.png.import
│ │ ├── misc3.png.import
│ │ ├── misc3_s.png.import
│ │ ├── misc4.png.import
│ │ └── tranquility_face.png.import
│ ├── icons/
│ │ ├── amulets.png.import
│ │ ├── animals.png.import
│ │ ├── armor.png.import
│ │ ├── blunt_weapons.png.import
│ │ ├── books.png.import
│ │ ├── bows.png.import
│ │ ├── cannons.png.import
│ │ ├── clubs.png.import
│ │ ├── creep_icons_atlas.png.import
│ │ ├── daggers.png.import
│ │ ├── dioramas.png.import
│ │ ├── electricity.png.import
│ │ ├── elements.png.import
│ │ ├── faces.png.import
│ │ ├── fire.png.import
│ │ ├── food.png.import
│ │ ├── furniture.png.import
│ │ ├── gems.png.import
│ │ ├── generic_icons.png.import
│ │ ├── gloves.png.import
│ │ ├── helmets.png.import
│ │ ├── holy.png.import
│ │ ├── hud.png.import
│ │ ├── magic.png.import
│ │ ├── masks.png.import
│ │ ├── mechanical.png.import
│ │ ├── misc.png.import
│ │ ├── orbs.png.import
│ │ ├── plants.png.import
│ │ ├── potion_icons_m.png.import
│ │ ├── rings.png.import
│ │ ├── rockets.png.import
│ │ ├── scrolls.png.import
│ │ ├── shields.png.import
│ │ ├── spears.png.import
│ │ ├── statues.png.import
│ │ ├── staves.png.import
│ │ ├── swords.png.import
│ │ ├── tier_icons_m.png.import
│ │ ├── tower_icons_m.png.import
│ │ ├── tower_variations.png.import
│ │ ├── trinkets.png.import
│ │ ├── undead.png.import
│ │ └── weapons_misc.png.import
│ ├── misc/
│ │ ├── autocast_automode_particle.png.import
│ │ ├── cast_cursor.png.import
│ │ ├── circle_01.png.import
│ │ ├── circle_02.png.import
│ │ ├── circle_03.png.import
│ │ ├── circle_04.png.import
│ │ ├── circle_05.png.import
│ │ ├── creep_blood_pool.png.import
│ │ ├── icob_min.png.import
│ │ ├── icob_ultra_wide.png.import
│ │ ├── icon.png.import
│ │ ├── potion_drop_animation.png.import
│ │ └── projectile.png.import
│ ├── secrets/
│ │ ├── badwords.csv.import
│ │ └── secrets.csv.import
│ ├── sfx/
│ │ ├── 161654__qubodup__war-game-battle-level-up-remix.ogg.import
│ │ ├── 202147__qubodup__enchant.ogg.import
│ │ ├── 411177__silverillusionist__pick-up-item-1-short.ogg.import
│ │ ├── 420676__sypherzent__spell-cast-buff-high-tone.ogg.import
│ │ ├── 442827__qubodup__fireball.ogg.import
│ │ ├── 442903__qubodup__slash-remix.ogg.import
│ │ ├── 541478__eminyildirim__magic-fire-spell-impact-punch.ogg.import
│ │ ├── 562292__colorscrimsontears__heal-rpg.ogg.import
│ │ ├── 649359__sonofxaudio__sword_water01.ogg.import
│ │ ├── 665082__sunflora__thud.ogg.import
│ │ ├── 682635__bastianhallo__magic-spell.ogg.import
│ │ ├── 683044__brettrader__stomp-soft.ogg.import
│ │ ├── 714258__qubodup__cloud-poof.ogg.import
│ │ ├── 734247__noisyredfox__coins3.ogg.import
│ │ ├── 738438__qubodup__orc-grunt-2.ogg.import
│ │ ├── 745156__tigreplayz__blast-explosion.ogg.import
│ │ ├── DoKashiteru_healspell1.ogg.import
│ │ ├── DoKashiteru_healspell2.ogg.import
│ │ ├── DoKashiteru_healspell3.ogg.import
│ │ ├── README.md
│ │ ├── UI_Electric_01.ogg.import
│ │ ├── artisticdude_freeze.ogg.import
│ │ ├── attribution.csv
│ │ ├── attribution.csv.import
│ │ ├── bart_foom_0.ogg.import
│ │ ├── copyc4t_Archers-shooting.ogg.import
│ │ ├── kevl_level_up.ogg.import
│ │ ├── little_robot_Spell_00.ogg.import
│ │ ├── little_robot_Spell_01.ogg.import
│ │ ├── little_robot_UI_Electric_00.ogg.import
│ │ ├── little_robot_UI_Electric_01.ogg.import
│ │ ├── little_robot_Whoosh_Electric_00.ogg.import
│ │ ├── little_robot_Whoosh_Electric_01.ogg.import
│ │ ├── little_robot_Whoosh_Electric_02.ogg.import
│ │ ├── little_robot_Whoosh_Electric_03.ogg.import
│ │ ├── machel_baradari_jump.wav.import
│ │ ├── michel_baradari_jump.ogg.import
│ │ ├── michel_baradari_jump.wav.import
│ │ ├── michel_baradari_lava.ogg.import
│ │ ├── michel_baradari_teleport.ogg.import
│ │ ├── p0ss_confusion.ogg.import
│ │ ├── p0ss_curse5.ogg.import
│ │ ├── p0ss_enchant.ogg.import
│ │ ├── p0ss_enchant2.ogg.import
│ │ ├── p0ss_explode2.ogg.import
│ │ ├── p0ss_explode4.ogg.import
│ │ ├── p0ss_freeze2.ogg.import
│ │ ├── p0ss_heal.ogg.import
│ │ ├── p0ss_pestilence.ogg.import
│ │ ├── p0ss_sand.ogg.import
│ │ ├── p0ss_shot.ogg.import
│ │ ├── p0ss_spell.ogg.import
│ │ ├── p0ss_steam.ogg.import
│ │ ├── p0ss_teleport.ogg.import
│ │ ├── p0ss_warp.ogg.import
│ │ ├── p0ss_warp2.ogg.import
│ │ ├── p0ss_warp3.ogg.import
│ │ ├── p0ss_water.ogg.import
│ │ ├── p0ss_zap.ogg.import
│ │ ├── p0ss_zap10.ogg.import
│ │ ├── p0ss_zap5a.ogg.import
│ │ ├── spit_01.ogg.import
│ │ ├── unknown_attack_sound1.ogg.import
│ │ ├── unknown_fire_attack1.ogg.import
│ │ ├── unknown_iceball.ogg.import
│ │ ├── unknown_iron_attack1.ogg.import
│ │ ├── unknown_swosh-08.ogg.import
│ │ └── unknown_swosh-11.ogg.import
│ ├── texts/
│ │ ├── README.md
│ │ ├── texts.csv.import
│ │ ├── texts_history.csv
│ │ └── texts_history.csv.import
│ ├── tiles/
│ │ ├── License.txt
│ │ ├── README.md
│ │ ├── barrels.png.import
│ │ ├── bridges.png.import
│ │ ├── chairs.png.import
│ │ ├── chests.png.import
│ │ ├── empty_tiles.png.import
│ │ ├── floor.png.import
│ │ ├── floor1_walls.png.import
│ │ ├── planks.png.import
│ │ ├── spiral_stairs.png.import
│ │ ├── stairs.png.import
│ │ ├── stone_columns.png.import
│ │ ├── stone_walls.png.import
│ │ ├── tables.png.import
│ │ ├── wooden_pile.png.import
│ │ └── wooden_supports.png.import
│ ├── tiles_decoration/
│ │ ├── bushes1.png.import
│ │ ├── column_overgrown.png.import
│ │ ├── leaves1.png.import
│ │ ├── stones1.png.import
│ │ ├── stones2.png.import
│ │ ├── stones3.png.import
│ │ ├── trees1.png.import
│ │ ├── trees2.png.import
│ │ ├── vines1.png.import
│ │ ├── vines2.png.import
│ │ ├── vines3.png.import
│ │ ├── vines4.png.import
│ │ ├── vines5.png.import
│ │ ├── vines6.png.import
│ │ ├── vines7.png.import
│ │ └── wall_vines1.png.import
│ ├── tower_sprites/
│ │ ├── astral_common.png.import
│ │ ├── astral_rare.png.import
│ │ ├── astral_uncommon.png.import
│ │ ├── astral_unique.png.import
│ │ ├── darkness_common.png.import
│ │ ├── darkness_rare.png.import
│ │ ├── darkness_uncommon.png.import
│ │ ├── darkness_unique.png.import
│ │ ├── fire_common.png.import
│ │ ├── fire_rare.png.import
│ │ ├── fire_uncommon.png.import
│ │ ├── fire_unique.png.import
│ │ ├── ice_common.png.import
│ │ ├── ice_rare.png.import
│ │ ├── ice_uncommon.png.import
│ │ ├── ice_unique.png.import
│ │ ├── iron_common.png.import
│ │ ├── iron_rare.png.import
│ │ ├── iron_uncommon.png.import
│ │ ├── iron_unique.png.import
│ │ ├── nature_common.png.import
│ │ ├── nature_rare.png.import
│ │ ├── nature_uncommon.png.import
│ │ ├── nature_unique.png.import
│ │ ├── storm_common.png.import
│ │ ├── storm_rare.png.import
│ │ ├── storm_uncommon.png.import
│ │ └── storm_unique.png.import
│ └── tutorial_pictures/
│ ├── README.md
│ ├── build_tower.png.import
│ ├── item_drop.png.import
│ ├── research.png.import
│ ├── research_element.png.import
│ ├── resource_panel.png.import
│ ├── roll_towers.png.import
│ ├── tower_info.png.import
│ ├── tower_level.png.import
│ ├── tower_mouse_over.png.import
│ ├── tower_stash.png.import
│ ├── transform.png.import
│ ├── upgrade.png.import
│ └── wave_finish.png.import
├── build/
│ ├── README.md
│ ├── linux/
│ │ └── README.md
│ ├── macos/
│ │ └── README.md
│ ├── web/
│ │ └── full-size.html
│ └── windows/
│ └── README.md
├── data/
│ ├── README.md
│ ├── ability_properties.csv
│ ├── ability_properties.csv.import
│ ├── aura_properties.csv
│ ├── aura_properties.csv.import
│ ├── autocast_properties.csv
│ ├── autocast_properties.csv.import
│ ├── builder_properties.csv
│ ├── builder_properties.csv.import
│ ├── exp_for_level.csv
│ ├── exp_for_level.csv.import
│ ├── hints/
│ │ ├── advanced.csv
│ │ ├── advanced.csv.import
│ │ ├── basic.csv.import
│ │ ├── basics.csv
│ │ ├── basics.csv.import
│ │ ├── chat_commands.csv
│ │ ├── chat_commands.csv.import
│ │ ├── creep_specials.csv
│ │ ├── creep_specials.csv.import
│ │ ├── creeps.csv
│ │ ├── creeps.csv.import
│ │ ├── items.csv
│ │ ├── items.csv.import
│ │ ├── towers.csv
│ │ ├── towers.csv.import
│ │ ├── tutorial.csv
│ │ └── tutorial.csv.import
│ ├── item_properties.csv
│ ├── item_properties.csv.import
│ ├── mission_properties.csv
│ ├── mission_properties.csv.import
│ ├── player_exp_for_level.csv
│ ├── player_exp_for_level.csv.import
│ ├── recipe_properties.csv
│ ├── recipe_properties.csv.import
│ ├── tower_properties.csv
│ ├── tower_properties.csv.import
│ ├── wave_special_properties.csv
│ ├── wave_special_properties.csv.import
│ ├── wisdom_upgrades.csv
│ └── wisdom_upgrades.csv.import
├── export_presets.cfg
├── project.godot
├── rclone-filter
├── resources/
│ ├── README.md
│ ├── button_groups/
│ │ ├── element_filter_button_group.tres
│ │ ├── interface_size_setting_button_group.tres
│ │ ├── item_type_filter_button_group.tres
│ │ ├── menu_cards_button_group.tres
│ │ ├── right_panel_button_group.tres
│ │ └── speed_button_group.tres
│ ├── icons/
│ │ ├── amulets/
│ │ │ ├── amulet_01.tres
│ │ │ ├── amulet_02.tres
│ │ │ ├── amulet_03.tres
│ │ │ └── amulet_04.tres
│ │ ├── animals/
│ │ │ ├── bat_01.tres
│ │ │ ├── bat_02.tres
│ │ │ ├── bat_03.tres
│ │ │ ├── cow.tres
│ │ │ ├── dragon_01.tres
│ │ │ ├── dragon_02.tres
│ │ │ ├── dragon_03.tres
│ │ │ ├── dragon_04.tres
│ │ │ ├── dragon_05.tres
│ │ │ ├── fish_01.tres
│ │ │ ├── fish_02.tres
│ │ │ ├── fish_03.tres
│ │ │ ├── fish_04.tres
│ │ │ ├── mech_toad.tres
│ │ │ ├── piglet_warrior.tres
│ │ │ ├── rabbit.tres
│ │ │ ├── rooster_warrior.tres
│ │ │ ├── spider_01.tres
│ │ │ ├── spider_02.tres
│ │ │ ├── spider_03.tres
│ │ │ └── wing.tres
│ │ ├── armor/
│ │ │ ├── chest_plate.tres
│ │ │ ├── chest_plate_with_spike.tres
│ │ │ ├── coat.tres
│ │ │ ├── lightning_boot.tres
│ │ │ ├── vest_01.tres
│ │ │ ├── vest_02.tres
│ │ │ ├── vest_03.tres
│ │ │ └── vest_04.tres
│ │ ├── blunt_weapons/
│ │ │ ├── hammer_01.tres
│ │ │ ├── hammer_02.tres
│ │ │ ├── hammer_03.tres
│ │ │ ├── hammer_04.tres
│ │ │ ├── wood_01.tres
│ │ │ ├── wood_02.tres
│ │ │ ├── wood_03.tres
│ │ │ └── wood_04.tres
│ │ ├── books/
│ │ │ ├── book_01.tres
│ │ │ ├── book_02.tres
│ │ │ ├── book_03.tres
│ │ │ ├── book_04.tres
│ │ │ ├── book_05.tres
│ │ │ ├── book_06.tres
│ │ │ ├── book_07.tres
│ │ │ ├── book_08.tres
│ │ │ ├── book_09.tres
│ │ │ ├── book_10.tres
│ │ │ ├── book_11.tres
│ │ │ ├── note_01.tres
│ │ │ ├── note_02.tres
│ │ │ ├── note_03.tres
│ │ │ └── note_04.tres
│ │ ├── bows/
│ │ │ ├── arrow_01.tres
│ │ │ ├── arrow_02.tres
│ │ │ ├── bow_01.tres
│ │ │ ├── bow_02.tres
│ │ │ ├── bow_03.tres
│ │ │ ├── bow_04.tres
│ │ │ ├── bow_05.tres
│ │ │ └── bow_06.tres
│ │ ├── cannons/
│ │ │ ├── cannon_01.tres
│ │ │ ├── cannon_02.tres
│ │ │ ├── cannon_03.tres
│ │ │ ├── cannon_04.tres
│ │ │ ├── cannon_05.tres
│ │ │ ├── cannon_06.tres
│ │ │ ├── cannon_07.tres
│ │ │ ├── cannon_08.tres
│ │ │ ├── gun_01.tres
│ │ │ └── gun_02.tres
│ │ ├── clubs/
│ │ │ ├── club_01.tres
│ │ │ ├── club_02.tres
│ │ │ ├── club_03.tres
│ │ │ ├── club_04.tres
│ │ │ ├── club_04_without_handle.tres
│ │ │ └── club_glowing.tres
│ │ ├── creep_icons/
│ │ │ ├── challenge_challenge_boss.tres
│ │ │ ├── challenge_challenge_mass.tres
│ │ │ ├── humanoid_air.tres
│ │ │ ├── humanoid_boss.tres
│ │ │ ├── humanoid_champion.tres
│ │ │ ├── humanoid_mass.tres
│ │ │ ├── humanoid_normal.tres
│ │ │ ├── magic_air.tres
│ │ │ ├── magic_boss.tres
│ │ │ ├── magic_champion.tres
│ │ │ ├── magic_mass.tres
│ │ │ ├── magic_normal.tres
│ │ │ ├── nature_air.tres
│ │ │ ├── nature_boss.tres
│ │ │ ├── nature_champion.tres
│ │ │ ├── nature_mass.tres
│ │ │ ├── nature_normal.tres
│ │ │ ├── orc_air.tres
│ │ │ ├── orc_boss.tres
│ │ │ ├── orc_champion.tres
│ │ │ ├── orc_mass.tres
│ │ │ ├── orc_normal.tres
│ │ │ ├── undead_air.tres
│ │ │ ├── undead_boss.tres
│ │ │ ├── undead_champion.tres
│ │ │ ├── undead_mass.tres
│ │ │ └── undead_normal.tres
│ │ ├── daggers/
│ │ │ ├── dagger_01.tres
│ │ │ ├── dagger_02.tres
│ │ │ ├── dagger_03.tres
│ │ │ ├── dagger_04.tres
│ │ │ ├── dagger_05.tres
│ │ │ ├── dagger_06.tres
│ │ │ ├── dagger_07.tres
│ │ │ ├── dagger_08.tres
│ │ │ └── dagger_09.tres
│ │ ├── dioramas/
│ │ │ ├── book_display.tres
│ │ │ ├── church.tres
│ │ │ ├── fountain.tres
│ │ │ ├── mountain.tres
│ │ │ └── pyramid.tres
│ │ ├── electricity/
│ │ │ ├── electricity_blue.tres
│ │ │ ├── electricity_yellow.tres
│ │ │ ├── lightning_circle_cyan.tres
│ │ │ ├── lightning_circle_white.tres
│ │ │ ├── lightning_glowing.tres
│ │ │ └── thunderstorm.tres
│ │ ├── elements/
│ │ │ ├── astral.tres
│ │ │ ├── darkness.tres
│ │ │ ├── fire.tres
│ │ │ ├── ice.tres
│ │ │ ├── iron.tres
│ │ │ ├── nature.tres
│ │ │ └── storm.tres
│ │ ├── faces/
│ │ │ ├── green_demon.tres
│ │ │ ├── man_01.tres
│ │ │ ├── man_02.tres
│ │ │ ├── man_03.tres
│ │ │ ├── man_04.tres
│ │ │ ├── man_05.tres
│ │ │ ├── mech_zombie.tres
│ │ │ ├── orc_01.tres
│ │ │ ├── orc_02.tres
│ │ │ ├── sleeping_leaf_spirit.tres
│ │ │ ├── woman_01.tres
│ │ │ ├── woman_02.tres
│ │ │ └── woman_03.tres
│ │ ├── fire/
│ │ │ ├── burning_cloth.tres
│ │ │ ├── fire_bowl_01.tres
│ │ │ ├── fire_bowl_02.tres
│ │ │ ├── fire_bowl_03.tres
│ │ │ ├── fire_in_cup.tres
│ │ │ ├── flame_blue.tres
│ │ │ ├── flame_blue_glowing.tres
│ │ │ ├── flame_purple.tres
│ │ │ └── torch.tres
│ │ ├── food/
│ │ │ ├── barrel.tres
│ │ │ ├── beer_01.tres
│ │ │ ├── beer_02.tres
│ │ │ ├── lard.tres
│ │ │ ├── pork.tres
│ │ │ ├── pork_without_plate.tres
│ │ │ └── poultry.tres
│ │ ├── furniture/
│ │ │ ├── artifact_of_skadi.tres
│ │ │ ├── artifact_on_pedestal.tres
│ │ │ ├── bed.tres
│ │ │ ├── chest.tres
│ │ │ ├── exploding_mirror.tres
│ │ │ ├── furniture.tres
│ │ │ ├── stool.tres
│ │ │ ├── throne.tres
│ │ │ └── wooden_stand_with_nail.tres
│ │ ├── gems/
│ │ │ ├── crystal.tres
│ │ │ ├── earring_01.tres
│ │ │ ├── earring_02.tres
│ │ │ ├── earring_03.tres
│ │ │ ├── earring_04.tres
│ │ │ ├── earring_05.tres
│ │ │ ├── gem_01.tres
│ │ │ ├── gem_02.tres
│ │ │ ├── gem_03.tres
│ │ │ ├── gem_04.tres
│ │ │ ├── gem_05.tres
│ │ │ ├── gem_06.tres
│ │ │ ├── gem_07.tres
│ │ │ ├── stone_01.tres
│ │ │ ├── stone_02.tres
│ │ │ ├── stone_03.tres
│ │ │ └── stone_04.tres
│ │ ├── generic_icons/
│ │ │ ├── README.md
│ │ │ ├── abdominal_armor.tres
│ │ │ ├── alien_skull.tres
│ │ │ ├── alligator_clip.tres
│ │ │ ├── amber_mosquito.tres
│ │ │ ├── angel_outfit.tres
│ │ │ ├── angel_wings.tres
│ │ │ ├── animal_skull.tres
│ │ │ ├── ankh.tres
│ │ │ ├── aquarius.tres
│ │ │ ├── aries.tres
│ │ │ ├── armor_vest.tres
│ │ │ ├── atomic_slashes.tres
│ │ │ ├── azul_flake.tres
│ │ │ ├── barbute.tres
│ │ │ ├── barefoot.tres
│ │ │ ├── bat_mask.tres
│ │ │ ├── beard.tres
│ │ │ ├── biceps.tres
│ │ │ ├── burning_dot.tres
│ │ │ ├── burning_meteor.tres
│ │ │ ├── charm.tres
│ │ │ ├── chest_armor.tres
│ │ │ ├── cog.tres
│ │ │ ├── egg.tres
│ │ │ ├── electric.tres
│ │ │ ├── energy_breath.tres
│ │ │ ├── fire_dash.tres
│ │ │ ├── flame.tres
│ │ │ ├── foot_trip.tres
│ │ │ ├── ghost.tres
│ │ │ ├── gold_bar.tres
│ │ │ ├── hammer_drop.tres
│ │ │ ├── holy_grail.tres
│ │ │ ├── horned_helm.tres
│ │ │ ├── hourglass.tres
│ │ │ ├── knocked_out_stars.tres
│ │ │ ├── liberty_wing.tres
│ │ │ ├── meat.tres
│ │ │ ├── mighty_force.tres
│ │ │ ├── mine_explosion.tres
│ │ │ ├── moebius_trefoil.tres
│ │ │ ├── omega.tres
│ │ │ ├── open_wound.tres
│ │ │ ├── ophiucus.tres
│ │ │ ├── orc_head.tres
│ │ │ ├── over_infinity.tres
│ │ │ ├── perpendicular_rings.tres
│ │ │ ├── pisces.tres
│ │ │ ├── poison_gas.tres
│ │ │ ├── pokecog.tres
│ │ │ ├── polar_star.tres
│ │ │ ├── rolling_energy.tres
│ │ │ ├── root_tip.tres
│ │ │ ├── round_potion.tres
│ │ │ ├── rss.tres
│ │ │ ├── semi_closed_eye.tres
│ │ │ ├── shiny_omega.tres
│ │ │ ├── spell_book.tres
│ │ │ ├── spider_web.tres
│ │ │ ├── sprint.tres
│ │ │ ├── star_swirl.tres
│ │ │ ├── triple_scratches.tres
│ │ │ ├── turtle_shell.tres
│ │ │ └── wolf_howl.tres
│ │ ├── gloves/
│ │ │ ├── curse.tres
│ │ │ ├── gloves_01.tres
│ │ │ ├── gloves_02.tres
│ │ │ ├── gloves_03.tres
│ │ │ ├── gloves_04.tres
│ │ │ ├── gloves_05.tres
│ │ │ ├── gloves_06.tres
│ │ │ ├── gloves_07.tres
│ │ │ ├── gloves_08.tres
│ │ │ ├── heal.tres
│ │ │ └── steal.tres
│ │ ├── helmets/
│ │ │ ├── crown_01.tres
│ │ │ ├── crown_02.tres
│ │ │ ├── crown_03.tres
│ │ │ ├── helmet_01.tres
│ │ │ ├── helmet_02.tres
│ │ │ ├── helmet_03.tres
│ │ │ ├── helmet_04.tres
│ │ │ ├── helmet_05.tres
│ │ │ ├── helmet_06.tres
│ │ │ ├── helmet_07.tres
│ │ │ ├── helmet_08.tres
│ │ │ ├── wizard_hat_01.tres
│ │ │ └── wizard_hat_02.tres
│ │ ├── holy/
│ │ │ ├── altar.tres
│ │ │ ├── axe.tres
│ │ │ ├── cross_01.tres
│ │ │ ├── cross_02.tres
│ │ │ ├── cross_03.tres
│ │ │ ├── orb.tres
│ │ │ ├── tombstone.tres
│ │ │ └── white_trinket.tres
│ │ ├── hud/
│ │ │ ├── dice.tres
│ │ │ ├── gem_all_rarities.tres
│ │ │ ├── gem_common.tres
│ │ │ ├── gem_rare.tres
│ │ │ ├── gem_uncommon.tres
│ │ │ ├── gem_unique.tres
│ │ │ ├── gold.tres
│ │ │ ├── item_stash.tres
│ │ │ ├── knowledge_tome.tres
│ │ │ ├── oils.tres
│ │ │ ├── recipe_distill.tres
│ │ │ ├── recipe_perfect.tres
│ │ │ ├── recipe_reassemble.tres
│ │ │ ├── recipe_rebrew.tres
│ │ │ ├── research_elements.tres
│ │ │ ├── tower_food.tres
│ │ │ └── tower_stash.tres
│ │ ├── magic/
│ │ │ ├── bowl_01.tres
│ │ │ ├── bowl_02.tres
│ │ │ ├── claw_01.tres
│ │ │ ├── claw_02.tres
│ │ │ ├── claw_03.tres
│ │ │ ├── claw_04.tres
│ │ │ ├── eye.tres
│ │ │ ├── eye_blue.tres
│ │ │ ├── eyes_many.tres
│ │ │ ├── fire.tres
│ │ │ ├── lantern.tres
│ │ │ ├── lock_01.tres
│ │ │ ├── lock_02.tres
│ │ │ ├── lock_03.tres
│ │ │ ├── lock_04.tres
│ │ │ ├── magic_stone.tres
│ │ │ └── magic_stone_green.tres
│ │ ├── masks/
│ │ │ ├── mask_01.tres
│ │ │ ├── mask_02.tres
│ │ │ ├── mask_03.tres
│ │ │ ├── mask_04.tres
│ │ │ ├── mask_05.tres
│ │ │ ├── mask_06.tres
│ │ │ └── mask_07.tres
│ │ ├── mechanical/
│ │ │ ├── alchemy_kit_01.tres
│ │ │ ├── alchemy_kit_02.tres
│ │ │ ├── alchemy_kit_03.tres
│ │ │ ├── battery.tres
│ │ │ ├── black_gold_calculator.tres
│ │ │ ├── circuit_board.tres
│ │ │ ├── compass.tres
│ │ │ ├── factory_fumes.tres
│ │ │ ├── factory_gears.tres
│ │ │ ├── gold_machine.tres
│ │ │ ├── lamp.tres
│ │ │ ├── mech_badge.tres
│ │ │ └── mech_umbrella.tres
│ │ ├── misc/
│ │ │ ├── balls_01.tres
│ │ │ ├── balls_02.tres
│ │ │ ├── balls_03.tres
│ │ │ ├── cauldron.tres
│ │ │ ├── flag_01.tres
│ │ │ ├── flag_02.tres
│ │ │ ├── flag_03.tres
│ │ │ ├── gold_cart.tres
│ │ │ ├── grenade.tres
│ │ │ ├── poison_01.tres
│ │ │ ├── poison_02.tres
│ │ │ ├── quiver.tres
│ │ │ ├── red_knight.tres
│ │ │ ├── spiky_totem_01.tres
│ │ │ ├── spiky_totem_02.tres
│ │ │ ├── teapot_01.tres
│ │ │ ├── teapot_02.tres
│ │ │ ├── teapot_03.tres
│ │ │ ├── teapot_04.tres
│ │ │ ├── toolbox_01.tres
│ │ │ └── toolbox_02.tres
│ │ ├── orbs/
│ │ │ ├── moon.tres
│ │ │ ├── orb_fire.tres
│ │ │ ├── orb_green.tres
│ │ │ ├── orb_ice.tres
│ │ │ ├── orb_ice_melting.tres
│ │ │ ├── orb_molten.tres
│ │ │ ├── orb_molten_dull.tres
│ │ │ ├── orb_shadow.tres
│ │ │ └── orb_small.tres
│ │ ├── plants/
│ │ │ ├── branch_01.tres
│ │ │ ├── branch_02.tres
│ │ │ ├── flower_01.tres
│ │ │ ├── flower_02.tres
│ │ │ ├── flower_03.tres
│ │ │ ├── flower_04.tres
│ │ │ ├── flower_05.tres
│ │ │ ├── flower_06.tres
│ │ │ ├── leaf_01.tres
│ │ │ ├── leaf_02.tres
│ │ │ ├── leaf_03.tres
│ │ │ ├── plant_in_pot.tres
│ │ │ ├── stump.tres
│ │ │ └── tree.tres
│ │ ├── potions/
│ │ │ ├── beaker_01.tres
│ │ │ ├── beaker_02.tres
│ │ │ ├── beaker_03.tres
│ │ │ ├── potion_01.tres
│ │ │ ├── potion_02.tres
│ │ │ ├── potion_03.tres
│ │ │ ├── potion_04.tres
│ │ │ ├── potion_05.tres
│ │ │ ├── potion_06.tres
│ │ │ ├── potion_07.tres
│ │ │ ├── potion_08.tres
│ │ │ ├── potion_09.tres
│ │ │ ├── potion_10.tres
│ │ │ ├── potion_blue_01.tres
│ │ │ ├── potion_blue_02.tres
│ │ │ ├── potion_blue_03.tres
│ │ │ ├── potion_blue_04.tres
│ │ │ ├── potion_blue_05.tres
│ │ │ ├── potion_cyan_01.tres
│ │ │ ├── potion_cyan_02.tres
│ │ │ ├── potion_cyan_03.tres
│ │ │ ├── potion_green_01.tres
│ │ │ ├── potion_green_02.tres
│ │ │ ├── potion_green_03.tres
│ │ │ ├── potion_heart_01.tres
│ │ │ ├── potion_heart_02.tres
│ │ │ ├── potion_orange_01.tres
│ │ │ ├── potion_orange_02.tres
│ │ │ ├── potion_orange_03.tres
│ │ │ ├── potion_purple_01.tres
│ │ │ ├── potion_purple_02.tres
│ │ │ ├── potion_purple_03.tres
│ │ │ ├── potion_red_01.tres
│ │ │ ├── potion_red_02.tres
│ │ │ ├── potion_red_03.tres
│ │ │ ├── potion_yellow_01.tres
│ │ │ └── potion_yellow_02.tres
│ │ ├── rings/
│ │ │ ├── ring_01.tres
│ │ │ ├── ring_02.tres
│ │ │ ├── ring_03.tres
│ │ │ ├── ring_04.tres
│ │ │ ├── ring_05.tres
│ │ │ ├── ring_06.tres
│ │ │ ├── ring_07.tres
│ │ │ └── ring_08.tres
│ │ ├── rockets/
│ │ │ ├── rocket_01.tres
│ │ │ ├── rocket_02.tres
│ │ │ ├── rocket_03.tres
│ │ │ ├── rocket_04.tres
│ │ │ ├── rocket_05.tres
│ │ │ ├── rocket_06.tres
│ │ │ └── rocket_07.tres
│ │ ├── scrolls/
│ │ │ ├── scroll_01.tres
│ │ │ ├── scroll_02.tres
│ │ │ ├── scroll_03.tres
│ │ │ ├── scroll_04.tres
│ │ │ ├── scroll_05.tres
│ │ │ ├── scroll_06.tres
│ │ │ ├── scroll_07.tres
│ │ │ └── scroll_08.tres
│ │ ├── shields/
│ │ │ ├── shield_bronze.tres
│ │ │ ├── shield_castle.tres
│ │ │ ├── shield_gray_with_gold_emblem.tres
│ │ │ ├── shield_green.tres
│ │ │ ├── shield_skull.tres
│ │ │ ├── shield_white.tres
│ │ │ ├── shield_with_emblem.tres
│ │ │ ├── shield_with_gold_helmet.tres
│ │ │ ├── shield_wood.tres
│ │ │ ├── shield_wood_small.tres
│ │ │ └── shield_wood_small_glowing.tres
│ │ ├── spears/
│ │ │ ├── many_spears_01.tres
│ │ │ ├── many_spears_02.tres
│ │ │ ├── spear_01.tres
│ │ │ ├── spear_02.tres
│ │ │ └── spear_03.tres
│ │ ├── statues/
│ │ │ ├── statue_01.tres
│ │ │ ├── statue_02.tres
│ │ │ ├── statue_03.tres
│ │ │ ├── statue_dwarf_01.tres
│ │ │ ├── statue_dwarf_02.tres
│ │ │ └── statue_warrior.tres
│ │ ├── staves/
│ │ │ ├── staff_01.tres
│ │ │ ├── staff_02.tres
│ │ │ ├── staff_03.tres
│ │ │ ├── staff_04.tres
│ │ │ ├── staff_05.tres
│ │ │ ├── staff_06.tres
│ │ │ ├── staff_07.tres
│ │ │ ├── wand_01.tres
│ │ │ ├── wand_02.tres
│ │ │ ├── wand_03.tres
│ │ │ ├── wand_04.tres
│ │ │ ├── wand_05.tres
│ │ │ └── wand_glowing.tres
│ │ ├── swords/
│ │ │ ├── greatsword_01.tres
│ │ │ ├── greatsword_02.tres
│ │ │ ├── greatsword_03.tres
│ │ │ ├── greatsword_04.tres
│ │ │ ├── greatsword_05.tres
│ │ │ ├── sword_01.tres
│ │ │ ├── sword_02.tres
│ │ │ ├── sword_03.tres
│ │ │ ├── sword_swing_01.tres
│ │ │ └── sword_swing_02.tres
│ │ ├── tier_icons/
│ │ │ ├── common_1.tres
│ │ │ ├── common_2.tres
│ │ │ ├── common_3.tres
│ │ │ ├── common_4.tres
│ │ │ ├── common_5.tres
│ │ │ ├── common_6.tres
│ │ │ ├── common_7.tres
│ │ │ ├── rare_1.tres
│ │ │ ├── rare_2.tres
│ │ │ ├── rare_3.tres
│ │ │ ├── rare_4.tres
│ │ │ ├── rare_5.tres
│ │ │ ├── rare_6.tres
│ │ │ ├── rare_7.tres
│ │ │ ├── uncommon_1.tres
│ │ │ ├── uncommon_2.tres
│ │ │ ├── uncommon_3.tres
│ │ │ ├── uncommon_4.tres
│ │ │ ├── uncommon_5.tres
│ │ │ ├── uncommon_6.tres
│ │ │ ├── uncommon_7.tres
│ │ │ ├── unique_1.tres
│ │ │ ├── unique_2.tres
│ │ │ ├── unique_3.tres
│ │ │ ├── unique_4.tres
│ │ │ ├── unique_5.tres
│ │ │ ├── unique_6.tres
│ │ │ └── unique_7.tres
│ │ ├── tower_icons/
│ │ │ ├── abandoned_pit.tres
│ │ │ ├── abominable_snowman.tres
│ │ │ ├── afflicted_obelisk.tres
│ │ │ ├── ancient_energy_converter.tres
│ │ │ ├── annoyed_tree.tres
│ │ │ ├── arcane_storm.tres
│ │ │ ├── area_roaster.tres
│ │ │ ├── ash_geyser.tres
│ │ │ ├── astral_lantern.tres
│ │ │ ├── astral_rift.tres
│ │ │ ├── baby_plant.tres
│ │ │ ├── baby_tuskin.tres
│ │ │ ├── ball_lightning_accelerator.tres
│ │ │ ├── basic_knowledge.tres
│ │ │ ├── black_dragon_roost.tres
│ │ │ ├── black_rock_totem.tres
│ │ │ ├── bomb_turret.tres
│ │ │ ├── bone_shrine.tres
│ │ │ ├── bonk_the_living_mountain.tres
│ │ │ ├── broken_cage.tres
│ │ │ ├── broken_circle_of_wind.tres
│ │ │ ├── broken_fire_pit.tres
│ │ │ ├── broken_lightning_rod.tres
│ │ │ ├── bronze_dragon_roost.tres
│ │ │ ├── buried_soul.tres
│ │ │ ├── burning_watchtower.tres
│ │ │ ├── burrow.tres
│ │ │ ├── caged_fire.tres
│ │ │ ├── cenarion.tres
│ │ │ ├── chaining_storm.tres
│ │ │ ├── chaos_warlock.tres
│ │ │ ├── charged_obelisk.tres
│ │ │ ├── chilled_spire.tres
│ │ │ ├── cloud_warrior.tres
│ │ │ ├── cloudy_temple_of_absorption.tres
│ │ │ ├── coconut_sapling.tres
│ │ │ ├── coin_machine.tres
│ │ │ ├── cold_obelisk.tres
│ │ │ ├── cold_troll.tres
│ │ │ ├── contraption.tres
│ │ │ ├── crimson_wyrm.tres
│ │ │ ├── cruel_fire.tres
│ │ │ ├── cursed_grounds.tres
│ │ │ ├── cute_small_spider.tres
│ │ │ ├── dark_battery.tres
│ │ │ ├── dark_fire_pit.tres
│ │ │ ├── death_knight.tres
│ │ │ ├── dimensional_flux_collector.tres
│ │ │ ├── dragon_sorcerer.tres
│ │ │ ├── drake_whisperer.tres
│ │ │ ├── dreadlord.tres
│ │ │ ├── dutchmans_grave.tres
│ │ │ ├── dwarven_forgery.tres
│ │ │ ├── ebonfrost_crystal.tres
│ │ │ ├── embershell_turtle_hatchling.tres
│ │ │ ├── energy_junction.tres
│ │ │ ├── essence_of_fury.tres
│ │ │ ├── felweed.tres
│ │ │ ├── fenced_flames.tres
│ │ │ ├── fiery_dog.tres
│ │ │ ├── fiery_pebble.tres
│ │ │ ├── fire_battery.tres
│ │ │ ├── fire_star.tres
│ │ │ ├── firestorm_cell.tres
│ │ │ ├── fisherman.tres
│ │ │ ├── forest_archer.tres
│ │ │ ├── forest_protectress.tres
│ │ │ ├── forest_troll.tres
│ │ │ ├── frost_root.tres
│ │ │ ├── frosty_rock.tres
│ │ │ ├── frozen_well.tres
│ │ │ ├── garden_of_eden.tres
│ │ │ ├── gatling_gun.tres
│ │ │ ├── genis_sage.tres
│ │ │ ├── geothermal_extractor.tres
│ │ │ ├── glaive_master.tres
│ │ │ ├── glowing_solar_orb.tres
│ │ │ ├── gnoll_thunder_mage.tres
│ │ │ ├── goblin_stronghold.tres
│ │ │ ├── grab-o-bot.tres
│ │ │ ├── green_dragon_roost.tres
│ │ │ ├── green_lightning.tres
│ │ │ ├── greyfang.tres
│ │ │ ├── gryphon_rider.tres
│ │ │ ├── hall_of_souls.tres
│ │ │ ├── harby.tres
│ │ │ ├── harpy_witch.tres
│ │ │ ├── haunted_rubble.tres
│ │ │ ├── healing_obelisk.tres
│ │ │ ├── helicopter_zone.tres
│ │ │ ├── hell_bat.tres
│ │ │ ├── holy_energy.tres
│ │ │ ├── ice_battery.tres
│ │ │ ├── icy_core.tres
│ │ │ ├── icy_skulls.tres
│ │ │ ├── icy_spirit.tres
│ │ │ ├── igloo.tres
│ │ │ ├── inexperienced_huntress.tres
│ │ │ ├── inflamed_stone.tres
│ │ │ ├── initiate_elementalist.tres
│ │ │ ├── it.tres
│ │ │ ├── jungle_stalker.tres
│ │ │ ├── kraken.tres
│ │ │ ├── lesser_astral_defender.tres
│ │ │ ├── lesser_dark_defender.tres
│ │ │ ├── lesser_elemental_ghost.tres
│ │ │ ├── lesser_flamy_defender.tres
│ │ │ ├── lesser_ice_defender.tres
│ │ │ ├── lesser_iron_defender.tres
│ │ │ ├── lesser_natural_defender.tres
│ │ │ ├── lesser_priest.tres
│ │ │ ├── lesser_skeletal_mage.tres
│ │ │ ├── lesser_storm_defender.tres
│ │ │ ├── lesser_wolves_den.tres
│ │ │ ├── library_of_alexandria.tres
│ │ │ ├── lich_king.tres
│ │ │ ├── lightning_eye.tres
│ │ │ ├── lightning_generator.tres
│ │ │ ├── lightning_totem.tres
│ │ │ ├── little_phoenix.tres
│ │ │ ├── living_volcano.tres
│ │ │ ├── lunar_emitter.tres
│ │ │ ├── lunar_sentinel.tres
│ │ │ ├── magic_battery.tres
│ │ │ ├── magic_mushroom.tres
│ │ │ ├── magna_warrior.tres
│ │ │ ├── mana-touched_drake.tres
│ │ │ ├── marine.tres
│ │ │ ├── meteor_totem.tres
│ │ │ ├── militia_watchtower.tres
│ │ │ ├── miner.tres
│ │ │ ├── minor_magic_ruin.tres
│ │ │ ├── mister_fireflies.tres
│ │ │ ├── monolith_of_chaos.tres
│ │ │ ├── morphling.tres
│ │ │ ├── mossy_acid_sprayer.tres
│ │ │ ├── mud_golem.tres
│ │ │ ├── nature_sprites.tres
│ │ │ ├── necromantic_altar.tres
│ │ │ ├── nortrom_the_silencer.tres
│ │ │ ├── nuclear_missile_launcher.tres
│ │ │ ├── obelisk_of_fortuity.tres
│ │ │ ├── owl_of_wisdom.tres
│ │ │ ├── particle_accelerator.tres
│ │ │ ├── phantom.tres
│ │ │ ├── plagued_crypt.tres
│ │ │ ├── planar_gate.tres
│ │ │ ├── poison_battery.tres
│ │ │ ├── polar_bear_cub.tres
│ │ │ ├── portal_to_swine_purgatory.tres
│ │ │ ├── prince_of_lightning.tres
│ │ │ ├── princess_of_light.tres
│ │ │ ├── razorboar_thornweaver.tres
│ │ │ ├── red_ball_lightning.tres
│ │ │ ├── regenerating_well.tres
│ │ │ ├── rooted_chasm.tres
│ │ │ ├── rotted_flashing_grave.tres
│ │ │ ├── rowing_boat.tres
│ │ │ ├── ruined_monolith.tres
│ │ │ ├── ruined_storm_cap.tres
│ │ │ ├── ruined_sun_pedestal.tres
│ │ │ ├── ruined_wind_tower.tres
│ │ │ ├── rundown_iron_sentry.tres
│ │ │ ├── sacred_altar.tres
│ │ │ ├── sacrificial_lamb.tres
│ │ │ ├── safirons_cold_grave.tres
│ │ │ ├── scales.tres
│ │ │ ├── sea_turtle.tres
│ │ │ ├── servant_of_the_twin_flames.tres
│ │ │ ├── sewer_connection.tres
│ │ │ ├── shadow.tres
│ │ │ ├── shaman.tres
│ │ │ ├── shard_of_souls.tres
│ │ │ ├── silver_knight.tres
│ │ │ ├── skink.tres
│ │ │ ├── small_brazier.tres
│ │ │ ├── small_bug_nest.tres
│ │ │ ├── small_cactus.tres
│ │ │ ├── small_fire_sprayer.tres
│ │ │ ├── small_frost_fire.tres
│ │ │ ├── small_frozen_mushroom.tres
│ │ │ ├── small_ice_mine.tres
│ │ │ ├── small_light.tres
│ │ │ ├── small_pocket_rocket.tres
│ │ │ ├── small_ray_blaster.tres
│ │ │ ├── small_serpent_ward.tres
│ │ │ ├── small_torch.tres
│ │ │ ├── sniper.tres
│ │ │ ├── snowy_pebble.tres
│ │ │ ├── solar_collector.tres
│ │ │ ├── solar_emitter.tres
│ │ │ ├── sorceress.tres
│ │ │ ├── soul_vault.tres
│ │ │ ├── soulflame_device.tres
│ │ │ ├── spell_collector.tres
│ │ │ ├── spider_queen.tres
│ │ │ ├── star_gazer.tres
│ │ │ ├── storm_battery.tres
│ │ │ ├── storm_coil.tres
│ │ │ ├── storm_focus.tres
│ │ │ ├── stormy_dog.tres
│ │ │ ├── sun_crusader.tres
│ │ │ ├── taita_the_hermit.tres
│ │ │ ├── teacher.tres
│ │ │ ├── tentacle_spawn.tres
│ │ │ ├── the_conduit.tres
│ │ │ ├── the_council_of_demons.tres
│ │ │ ├── the_fire_lord.tres
│ │ │ ├── the_frozen_wyrm.tres
│ │ │ ├── the_furnace.tres
│ │ │ ├── the_omnislasher.tres
│ │ │ ├── the_steam_engine.tres
│ │ │ ├── thief_apprentice.tres
│ │ │ ├── tidewater_stream.tres
│ │ │ ├── time_manipulator.tres
│ │ │ ├── timevault.tres
│ │ │ ├── tiny_shrub.tres
│ │ │ ├── tiny_storm_lantern.tres
│ │ │ ├── tombstone.tres
│ │ │ ├── trash_heap.tres
│ │ │ ├── tree_stump.tres
│ │ │ ├── tundra_stalker.tres
│ │ │ ├── undisturbed_crypt.tres
│ │ │ ├── valor.tres
│ │ │ ├── village_witch.tres
│ │ │ ├── void_drake.tres
│ │ │ ├── vulshok_the_berserker.tres
│ │ │ ├── warrior_of_light.tres
│ │ │ ├── wild_warbeast.tres
│ │ │ ├── witch_doctor.tres
│ │ │ ├── wooden_trap.tres
│ │ │ ├── xeno_research_facility.tres
│ │ │ ├── ymir.tres
│ │ │ ├── young_northern_troll.tres
│ │ │ ├── zealot.tres
│ │ │ └── zeus.tres
│ │ ├── tower_variations/
│ │ │ ├── ash_geyser_blue.tres
│ │ │ ├── ash_geyser_green.tres
│ │ │ ├── ash_geyser_purple.tres
│ │ │ ├── bonk_the_living_mountain_small.tres
│ │ │ ├── forest_troll_small.tres
│ │ │ ├── meteor_totem_blue.tres
│ │ │ ├── meteor_totem_purple.tres
│ │ │ ├── mossy_acid_sprayer_gray.tres
│ │ │ ├── mossy_acid_sprayer_red.tres
│ │ │ ├── undisturbed_crypt_gold.tres
│ │ │ └── vulshok_the_berserker_blue.tres
│ │ ├── trinkets/
│ │ │ ├── claw_01.tres
│ │ │ ├── claw_02.tres
│ │ │ ├── claw_03.tres
│ │ │ ├── key_01.tres
│ │ │ ├── key_02.tres
│ │ │ ├── key_03.tres
│ │ │ ├── trinket_01.tres
│ │ │ ├── trinket_02.tres
│ │ │ ├── trinket_03.tres
│ │ │ ├── trinket_04.tres
│ │ │ ├── trinket_05.tres
│ │ │ ├── trinket_06.tres
│ │ │ ├── trinket_07.tres
│ │ │ ├── trinket_08.tres
│ │ │ ├── trinket_09.tres
│ │ │ └── trinket_10.tres
│ │ ├── undead/
│ │ │ ├── demon_emblem.tres
│ │ │ ├── monster_hand.tres
│ │ │ ├── skull_01.tres
│ │ │ ├── skull_02.tres
│ │ │ ├── skull_03.tres
│ │ │ ├── skull_04.tres
│ │ │ ├── skull_05.tres
│ │ │ ├── skull_06.tres
│ │ │ ├── skull_doll.tres
│ │ │ ├── skull_phazing.tres
│ │ │ ├── skull_wand_01.tres
│ │ │ ├── skull_wand_02.tres
│ │ │ ├── skull_wand_03.tres
│ │ │ └── skull_wand_04.tres
│ │ └── weapons_misc/
│ │ ├── axe_01.tres
│ │ ├── axe_02.tres
│ │ ├── barbed_spike.tres
│ │ ├── glaive_01.tres
│ │ ├── glaive_02.tres
│ │ ├── glaive_03.tres
│ │ ├── mining_pick_01.tres
│ │ ├── mining_pick_02.tres
│ │ ├── trident_01.tres
│ │ └── trident_02.tres
│ ├── misc/
│ │ ├── barrel.tres
│ │ └── pulsing_dot.tres
│ ├── shaders/
│ │ ├── foggy_camera.gdshader
│ │ ├── glowing_outline.gdshader
│ │ ├── glowing_outline.material
│ │ ├── glowing_outline_2.gdshader
│ │ └── saturation_burn.gdshader
│ ├── theme/
│ │ ├── common/
│ │ │ ├── rect_container_center_l.tres
│ │ │ ├── rect_container_l.tres
│ │ │ ├── rect_container_m.tres
│ │ │ ├── rect_container_s.tres
│ │ │ └── tab_container_m.tres
│ │ ├── element_towers_info/
│ │ │ └── empty_button_style_box.tres
│ │ ├── health_bar_background.tres
│ │ ├── health_bar_fill.tres
│ │ ├── item_button_hover.tres
│ │ ├── item_button_normal.tres
│ │ ├── item_button_pressed.tres
│ │ ├── mission_complete_indicator.tres
│ │ ├── player_resource_display/
│ │ │ ├── circle_container_l.tres
│ │ │ ├── rect_container_center_l.tres
│ │ │ ├── rect_container_left_l.tres
│ │ │ ├── rect_container_right_l.tres
│ │ │ ├── rect_container_top_menu.tres
│ │ │ ├── resource_status_panel.tres
│ │ │ └── stash_panel_background.tres
│ │ ├── selected_unit_info/
│ │ │ ├── mana_bar_fill.tres
│ │ │ ├── panel_container.tres
│ │ │ └── progress_bar_background.tres
│ │ ├── tower_actions/
│ │ │ ├── button_disabled.tres
│ │ │ ├── button_normal.tres
│ │ │ └── button_pressed.tres
│ │ ├── unit_button/
│ │ │ ├── button_disabled.tres
│ │ │ ├── button_hover.tres
│ │ │ ├── button_normal.tres
│ │ │ ├── common_rarity_panel_container.tres
│ │ │ ├── passive_ability_button.tres
│ │ │ ├── rare_rarity_panel_container.tres
│ │ │ ├── small_button_disabled.tres
│ │ │ ├── small_button_hover.tres
│ │ │ ├── small_button_normal.tres
│ │ │ ├── uncommon_rarity_panel_container.tres
│ │ │ └── unique_rarity_panel_container.tres
│ │ ├── unit_button_container/
│ │ │ └── counter_label_normal.tres
│ │ ├── unit_menu/
│ │ │ ├── button_disalbed.tres
│ │ │ ├── button_hover.tres
│ │ │ ├── button_normal.tres
│ │ │ ├── exp_bar_background.tres
│ │ │ ├── exp_bar_fill.tres
│ │ │ ├── health_bar_background.tres
│ │ │ ├── health_bar_fill.tres
│ │ │ ├── mana_bar_background.tres
│ │ │ ├── mana_bar_fill.tres
│ │ │ ├── title_button_normal.tres
│ │ │ ├── unit_level_label_normal.tres
│ │ │ ├── unit_menu_panel.tres
│ │ │ └── unit_name_label_normal.tres
│ │ └── wc3_theme.tres
│ ├── tilesets/
│ │ ├── buildable_area_tiles.tres
│ │ └── decorations.tres
│ └── ui_textures/
│ ├── buff_group_both.tres
│ ├── buff_group_incoming.tres
│ ├── buff_group_none.tres
│ ├── buff_group_outgoing.tres
│ ├── button_container_hover.tres
│ ├── common_background.tres
│ ├── common_unit_button.tres
│ ├── common_unit_button_hover.tres
│ ├── info_icon.tres
│ ├── menu_option_round_button.tres
│ ├── menu_option_round_button_hover.tres
│ ├── portal_lives_round_bg.tres
│ ├── rare_background.tres
│ ├── rare_unit_button.tres
│ ├── rare_unit_button_hover.tres
│ ├── rect_container_center_l.tres
│ ├── rect_container_l.tres
│ ├── rect_container_left_l.tres
│ ├── rect_container_m.tres
│ ├── rect_container_right_l.tres
│ ├── rect_container_s.tres
│ ├── rect_container_s_hover.tres
│ ├── speed_fast.tres
│ ├── speed_fastest.tres
│ ├── speed_normal.tres
│ ├── stash_panel_background.tres
│ ├── uncommon_background.tres
│ ├── uncommon_unit_button.tres
│ ├── uncommon_unit_button_hover.tres
│ ├── unique_background.tres
│ ├── unique_unit_button.tres
│ ├── unique_unit_button_hover.tres
│ ├── unit_button_disabled.tres
│ └── upgrade_icon.tres
├── src/
│ ├── README.md
│ ├── actions/
│ │ ├── action.gd
│ │ ├── action_autocast.gd
│ │ ├── action_autofill.gd
│ │ ├── action_build_tower.gd
│ │ ├── action_change_buffgroup.gd
│ │ ├── action_chat.gd
│ │ ├── action_consume_item.gd
│ │ ├── action_drop_item.gd
│ │ ├── action_focus_target.gd
│ │ ├── action_idle.gd
│ │ ├── action_move_item.gd
│ │ ├── action_research_element.gd
│ │ ├── action_roll_towers.gd
│ │ ├── action_select_builder.gd
│ │ ├── action_select_unit.gd
│ │ ├── action_select_wisdom_upgrades.gd
│ │ ├── action_sell_tower.gd
│ │ ├── action_sort_item_stash.gd
│ │ ├── action_start_next_wave.gd
│ │ ├── action_swap_items.gd
│ │ ├── action_toggle_autocast.gd
│ │ ├── action_transform_tower.gd
│ │ ├── action_transmute.gd
│ │ └── action_upgrade_tower.gd
│ ├── buffs/
│ │ ├── aura.gd
│ │ ├── aura.tscn
│ │ ├── buff.gd
│ │ ├── buff_range_area.gd
│ │ ├── buff_range_area.tscn
│ │ ├── buff_type.gd
│ │ ├── instances/
│ │ │ ├── cb_silence.gd
│ │ │ └── cb_stun.gd
│ │ ├── modification.gd
│ │ ├── modifier.gd
│ │ └── target_type.gd
│ ├── builders/
│ │ ├── builder.gd
│ │ └── instances/
│ │ ├── builder_adventurer.gd
│ │ ├── builder_antagonizer.gd
│ │ ├── builder_arch_sorceress.gd
│ │ ├── builder_backpacker.gd
│ │ ├── builder_barbarian_warlord.gd
│ │ ├── builder_benevolent_witch.gd
│ │ ├── builder_blademaster.gd
│ │ ├── builder_elementalist.gd
│ │ ├── builder_farseer.gd
│ │ ├── builder_feeble_fender.gd
│ │ ├── builder_goblin_alchemist.gd
│ │ ├── builder_iron_maiden.gd
│ │ ├── builder_master_of_encyclopedic_wisdom.gd
│ │ ├── builder_maverick.gd
│ │ ├── builder_naga_time_twister.gd
│ │ ├── builder_none.gd
│ │ ├── builder_panda_monk.gd
│ │ ├── builder_queen.gd
│ │ ├── builder_realist.gd
│ │ ├── builder_royal_assassin.gd
│ │ ├── builder_spirit_warden.gd
│ │ └── builder_veteran_pilot.gd
│ ├── creeps/
│ │ ├── creep.gd
│ │ ├── creep_blood_pool.gd
│ │ ├── creep_blood_pool.tscn
│ │ ├── creep_corpse.gd
│ │ ├── creep_corpse.tscn
│ │ ├── creep_spawner.gd
│ │ ├── creep_spawner.tscn
│ │ ├── creep_sprite.gd
│ │ ├── health_bar.gd
│ │ ├── instances/
│ │ │ ├── challenge/
│ │ │ │ ├── challenge_boss_creep.tscn
│ │ │ │ └── challenge_mass_creep.tscn
│ │ │ ├── creep.tscn
│ │ │ └── orc/
│ │ │ ├── orc_air_creep.tscn
│ │ │ ├── orc_boss_creep.tscn
│ │ │ ├── orc_champion_creep.tscn
│ │ │ ├── orc_mass_creep.tscn
│ │ │ └── orc_normal_creep.tscn
│ │ ├── packed_metadata.gd
│ │ ├── special_buffs/
│ │ │ ├── creep_armored.gd
│ │ │ ├── creep_broody.gd
│ │ │ ├── creep_dart.gd
│ │ │ ├── creep_ethereal.gd
│ │ │ ├── creep_evasion.gd
│ │ │ ├── creep_evolving.gd
│ │ │ ├── creep_fireball.gd
│ │ │ ├── creep_flock.gd
│ │ │ ├── creep_ghost.gd
│ │ │ ├── creep_gravid.gd
│ │ │ ├── creep_greater_speed.gd
│ │ │ ├── creep_greater_spell_resistance.gd
│ │ │ ├── creep_heavy_armored.gd
│ │ │ ├── creep_invisible.gd
│ │ │ ├── creep_magic_immunity.gd
│ │ │ ├── creep_mana_drain_aura.gd
│ │ │ ├── creep_manashield+.gd
│ │ │ ├── creep_manashield.gd
│ │ │ ├── creep_meaty.gd
│ │ │ ├── creep_mechanical.gd
│ │ │ ├── creep_necromancer.gd
│ │ │ ├── creep_protector.gd
│ │ │ ├── creep_purge_revenge.gd
│ │ │ ├── creep_regeneration.gd
│ │ │ ├── creep_relic_raider.gd
│ │ │ ├── creep_rich.gd
│ │ │ ├── creep_second_chance.gd
│ │ │ ├── creep_semi-mechanical.gd
│ │ │ ├── creep_slow.gd
│ │ │ ├── creep_slow_aura.gd
│ │ │ ├── creep_speed.gd
│ │ │ ├── creep_spell_resistance.gd
│ │ │ ├── creep_spellbinder.gd
│ │ │ ├── creep_strong.gd
│ │ │ ├── creep_stun_revenge.gd
│ │ │ ├── creep_ultra_wisdom.gd
│ │ │ ├── creep_unlucky.gd
│ │ │ ├── creep_xtreme_armor.gd
│ │ │ ├── creep_xtreme_evasion.gd
│ │ │ ├── creep_xtreme_regeneration.gd
│ │ │ └── creep_xtreme_speed.gd
│ │ ├── special_icons/
│ │ │ ├── CreepArmoredSpecial.tscn
│ │ │ ├── CreepBroodySpecial.tscn
│ │ │ ├── CreepDartSpecial.tscn
│ │ │ ├── CreepEtherealSpecial.tscn
│ │ │ ├── CreepEvasionSpecial.tscn
│ │ │ ├── CreepEvolvingSpecial.tscn
│ │ │ ├── CreepFireballSpecial.tscn
│ │ │ ├── CreepFlockSpecial.tscn
│ │ │ ├── CreepGhostSpecial.tscn
│ │ │ ├── CreepGravidSpecial.tscn
│ │ │ ├── CreepGreaterSpeedSpecial.tscn
│ │ │ ├── CreepGreaterSpellResistanceSpecial.tscn
│ │ │ ├── CreepHeavyArmoredSpecial.tscn
│ │ │ ├── CreepInvisibleSpecial.tscn
│ │ │ ├── CreepMagicImmunitySpecial.tscn
│ │ │ ├── CreepManaDrainAuraSpecial.tscn
│ │ │ ├── CreepManaShieldPlusSpecial.tscn
│ │ │ ├── CreepManaShieldSpecial.tscn
│ │ │ ├── CreepMeatySpecial.tscn
│ │ │ ├── CreepMechanicalSpecial.tscn
│ │ │ ├── CreepNecromancerSpecial.tscn
│ │ │ ├── CreepProtectorSpecial.tscn
│ │ │ ├── CreepPurgeRevengeSpecial.tscn
│ │ │ ├── CreepRegenerationSpecial.tscn
│ │ │ ├── CreepRelicRaiderSpecial.tscn
│ │ │ ├── CreepRichSpecial.tscn
│ │ │ ├── CreepSecondChanceSpecial.tscn
│ │ │ ├── CreepSemiMechanicalSpecial.tscn
│ │ │ ├── CreepSlowAuraSpecial.tscn
│ │ │ ├── CreepSlowSpecial.tscn
│ │ │ ├── CreepSpeedSpecial.tscn
│ │ │ ├── CreepSpellResistanceSpecial.tscn
│ │ │ ├── CreepSpellbinderSpecial.tscn
│ │ │ ├── CreepStrongSpecial.tscn
│ │ │ ├── CreepStunRevengeSpecial.tscn
│ │ │ ├── CreepUltraWisdomSpecial.tscn
│ │ │ ├── CreepUnluckySpecial.tscn
│ │ │ ├── CreepXtremeArmorSpecial.tscn
│ │ │ ├── CreepXtremeEvasionSpecial.tscn
│ │ │ ├── CreepXtremeRegenerationSpecial.tscn
│ │ │ └── CreepXtremeSpeedSpecial.tscn
│ │ ├── wave.gd
│ │ ├── wave_path.gd
│ │ ├── wave_spawner.gd
│ │ └── wave_spawner.tscn
│ ├── effects/
│ │ ├── ancient_protector_missile.tscn
│ │ ├── animated_dead_target.tscn
│ │ ├── apply_potion.tscn
│ │ ├── arcane_tower_attack.tscn
│ │ ├── arcane_tower_attack_flat.tscn
│ │ ├── avatar_caster.tscn
│ │ ├── banshee_missile.tscn
│ │ ├── barrel.tscn
│ │ ├── blink_target.tscn
│ │ ├── blood_splatter.tscn
│ │ ├── build_tower.tscn
│ │ ├── charm_target.tscn
│ │ ├── chimaera_acid.tscn
│ │ ├── cloud_of_fog_cycle.tscn
│ │ ├── cloud_of_fog_small.tscn
│ │ ├── cripple_target.tscn
│ │ ├── crushing_wave.tscn
│ │ ├── crypt_fiend_eggsack.tscn
│ │ ├── cyclone_target.tscn
│ │ ├── death_and_decay.tscn
│ │ ├── death_coil.tscn
│ │ ├── death_explode.tscn
│ │ ├── devour.tscn
│ │ ├── dispel_magic_target.tscn
│ │ ├── doom_death.tscn
│ │ ├── effects_container.gd
│ │ ├── faerie_dragon_missile.tscn
│ │ ├── firelord_death_explode.tscn
│ │ ├── flame_strike_embers.tscn
│ │ ├── flower_aura.tscn
│ │ ├── frag_boom_spawn.tscn
│ │ ├── freezing_breath.tscn
│ │ ├── freezing_breath_purple.tscn
│ │ ├── frost_armor_damage.tscn
│ │ ├── frost_armor_damage_purple.tscn
│ │ ├── frost_bolt_missile.tscn
│ │ ├── glaive.tscn
│ │ ├── gold_credit.tscn
│ │ ├── healing_wave_target.tscn
│ │ ├── holy_bolt.tscn
│ │ ├── holy_bolt_green.tscn
│ │ ├── howl_caster.tscn
│ │ ├── immolation_damage.tscn
│ │ ├── impale_hit_target.tscn
│ │ ├── impale_target_dust.tscn
│ │ ├── incinerate.tscn
│ │ ├── interpolated_sprite.gd
│ │ ├── keeper_grove_missile.tscn
│ │ ├── level_up.tscn
│ │ ├── mana_burn_target.tscn
│ │ ├── mana_shield_cycle.tscn
│ │ ├── mass_teleport_caster.tscn
│ │ ├── mass_teleport_target.tscn
│ │ ├── monsoon_bolt.tscn
│ │ ├── moonwell_target.tscn
│ │ ├── mortar_missile.tscn
│ │ ├── naga_death.tscn
│ │ ├── ne_cancel_death.tscn
│ │ ├── ne_death.tscn
│ │ ├── placeholder.tscn
│ │ ├── polymorph_target.tscn
│ │ ├── projectile_explosion_astral.tscn
│ │ ├── projectile_explosion_darkness.tscn
│ │ ├── projectile_explosion_fire.tscn
│ │ ├── projectile_explosion_ice.tscn
│ │ ├── projectile_explosion_iron.tscn
│ │ ├── projectile_explosion_nature.tscn
│ │ ├── projectile_explosion_storm.tscn
│ │ ├── purge_buff_target.tscn
│ │ ├── quillspray.tscn
│ │ ├── raise_skeleton.tscn
│ │ ├── replenish_mana.tscn
│ │ ├── revive_human.tscn
│ │ ├── roar.tscn
│ │ ├── roots.tscn
│ │ ├── shackle.tscn
│ │ ├── shockwave_missile.tscn
│ │ ├── silence_area.tscn
│ │ ├── small_flame_spawn.tscn
│ │ ├── spell_aiil.tscn
│ │ ├── spell_ailb.tscn
│ │ ├── spell_aima.tscn
│ │ ├── spell_aire.tscn
│ │ ├── spell_aire_flat.tscn
│ │ ├── spell_aiso.tscn
│ │ ├── spell_alim.tscn
│ │ ├── spell_breaker_target.tscn
│ │ ├── spirit_link_target.tscn
│ │ ├── stampede_missile_death.tscn
│ │ ├── starfall_target.tscn
│ │ ├── stun_visual.tscn
│ │ ├── target_arrow.gd
│ │ ├── target_arrow.tscn
│ │ ├── thunder_clap.tscn
│ │ ├── undead_dissipate.tscn
│ │ ├── upgrade_tower.tscn
│ │ ├── vampiric_aura.tscn
│ │ ├── voodoo_aura.tscn
│ │ ├── warstomp_caster.tscn
│ │ ├── wind_shear.tscn
│ │ ├── wisp_explode.tscn
│ │ ├── witch_doctor_ward.tscn
│ │ ├── ziggurat_frost_missile.tscn
│ │ └── zombify_target.tscn
│ ├── enums/
│ │ ├── README.md
│ │ ├── armor_type.gd
│ │ ├── attack_type.gd
│ │ ├── buff_group_mode.gd
│ │ ├── builder_tier.gd
│ │ ├── creep_category.gd
│ │ ├── creep_size.gd
│ │ ├── difficulty.gd
│ │ ├── display_mode.gd
│ │ ├── element.gd
│ │ ├── game_mode.gd
│ │ ├── item_type.gd
│ │ ├── language.gd
│ │ ├── modification_type.gd
│ │ ├── player_mode.gd
│ │ ├── rarity.gd
│ │ └── team_mode.gd
│ ├── game_scene/
│ │ ├── build_space.gd
│ │ ├── build_tower.gd
│ │ ├── camera_controller.gd
│ │ ├── chat_commands.gd
│ │ ├── combat_log_storage.gd
│ │ ├── game_client.gd
│ │ ├── game_client.tscn
│ │ ├── game_host.gd
│ │ ├── game_host.tscn
│ │ ├── game_scene.gd
│ │ ├── game_scene.tscn
│ │ ├── game_time.gd
│ │ ├── horadric_cube.gd
│ │ ├── manual_timer.gd
│ │ ├── mouse_state.gd
│ │ ├── move_item.gd
│ │ ├── select_point_for_cast.gd
│ │ ├── select_target_for_cast.gd
│ │ ├── select_unit.gd
│ │ ├── team_container.gd
│ │ └── tutorial_controller.gd
│ ├── items/
│ │ ├── README.md
│ │ ├── item.gd
│ │ ├── item_behavior.gd
│ │ ├── item_behaviors/
│ │ │ ├── aqueous_vapor.gd
│ │ │ ├── arcane_book_of_power.gd
│ │ │ ├── arcane_oil_of_lore.gd
│ │ │ ├── arcane_script.gd
│ │ │ ├── arms_dealer.gd
│ │ │ ├── artifact_of_skadi.gd
│ │ │ ├── backpack.gd
│ │ │ ├── ball_lightning.gd
│ │ │ ├── bartucs_spirit.gd
│ │ │ ├── basics_of_calculus.gd
│ │ │ ├── bhaals_essence.gd
│ │ │ ├── blaster_staff.gd
│ │ │ ├── bloodthirsty_wheel_of_fortune.gd
│ │ │ ├── bloody_key.gd
│ │ │ ├── bones_of_essence.gd
│ │ │ ├── bonks_face.gd
│ │ │ ├── book_of_force.gd
│ │ │ ├── book_of_knowledge.gd
│ │ │ ├── brimstone_helmet.gd
│ │ │ ├── chameleon_glaive.gd
│ │ │ ├── chameleons_soul.gd
│ │ │ ├── charged_disk.gd
│ │ │ ├── chrono_jumper.gd
│ │ │ ├── circle_of_power.gd
│ │ │ ├── commander.gd
│ │ │ ├── consumable_chicken.gd
│ │ │ ├── consumable_hobbit.gd
│ │ │ ├── consumable_piggy.gd
│ │ │ ├── consumable_plant.gd
│ │ │ ├── crescent_stone.gd
│ │ │ ├── crit_blade.gd
│ │ │ ├── cruel_torch.gd
│ │ │ ├── currency_converter.gd
│ │ │ ├── cursed_claw.gd
│ │ │ ├── dagger_of_bane.gd
│ │ │ ├── dark_matter_trident.gd
│ │ │ ├── deep_shadows.gd
│ │ │ ├── distorted_idol.gd
│ │ │ ├── divine_book_of_omnipotence.gd
│ │ │ ├── dooms_ensign.gd
│ │ │ ├── elunes_bow.gd
│ │ │ ├── empty_item_behavior.gd
│ │ │ ├── enchanted_knives.gd
│ │ │ ├── essence_of_rot.gd
│ │ │ ├── even_more_magical_hammer.gd
│ │ │ ├── excalibur.gd
│ │ │ ├── eye_of_true_sight.gd
│ │ │ ├── faithful_staff.gd
│ │ │ ├── fist_of_doom.gd
│ │ │ ├── flag_of_the_allegiance.gd
│ │ │ ├── forcefield_generator.gd
│ │ │ ├── fragmentation_round.gd
│ │ │ ├── frog_pipe.gd
│ │ │ ├── glaive_of_supreme_follow_up.gd
│ │ │ ├── golden_decoration.gd
│ │ │ ├── golden_trident.gd
│ │ │ ├── granite_hammer.gd
│ │ │ ├── grounding_gloves.gd
│ │ │ ├── haunted_hand.gd
│ │ │ ├── helm_of_insanity.gd
│ │ │ ├── hippogryph_egg.gd
│ │ │ ├── holy_hand_grenade.gd
│ │ │ ├── item_template_advanced.gd
│ │ │ ├── jah_rakals_fury.gd
│ │ │ ├── jewels_of_the_moon.gd
│ │ │ ├── jungle_stalkers_doll.gd
│ │ │ ├── libram_of_grace.gd
│ │ │ ├── lich_mask.gd
│ │ │ ├── liquid_gold.gd
│ │ │ ├── lucky_gem.gd
│ │ │ ├── lunar_essence.gd
│ │ │ ├── magic_conductor.gd
│ │ │ ├── magic_gloves.gd
│ │ │ ├── magic_hammer.gd
│ │ │ ├── magic_link.gd
│ │ │ ├── magnetic_field.gd
│ │ │ ├── mana_stone.gd
│ │ │ ├── medallion_of_opulence.gd
│ │ │ ├── mefis_rocket.gd
│ │ │ ├── mighty_trees_acorns.gd
│ │ │ ├── mindleecher.gd
│ │ │ ├── mine_cart.gd
│ │ │ ├── mini_forest_troll.gd
│ │ │ ├── mining_tools.gd
│ │ │ ├── mystical_shell.gd
│ │ │ ├── nerminds_eye.gd
│ │ │ ├── never-ending_keg.gd
│ │ │ ├── oil_of_lore.gd
│ │ │ ├── old_hunter.gd
│ │ │ ├── optimists_preserved_face.gd
│ │ │ ├── orb_of_souls.gd
│ │ │ ├── overcharge_shot.gd
│ │ │ ├── pendant_of_mana_supremacy.gd
│ │ │ ├── pendant_of_promptness.gd
│ │ │ ├── phase_gloves.gd
│ │ │ ├── plain_staff.gd
│ │ │ ├── pocket_emporium.gd
│ │ │ ├── polarisator.gd
│ │ │ ├── portable_tombstone.gd
│ │ │ ├── priest_figurine.gd
│ │ │ ├── purifying_gloves.gd
│ │ │ ├── ritual_talisman.gd
│ │ │ ├── scroll_of_piercing_magic.gd
│ │ │ ├── scroll_of_speed.gd
│ │ │ ├── scroll_of_strength.gd
│ │ │ ├── seekers_arcane_oil.gd
│ │ │ ├── seekers_oil.gd
│ │ │ ├── share_knowledge.gd
│ │ │ ├── shining_rock.gd
│ │ │ ├── shrapnel_ammunition.gd
│ │ │ ├── sign_of_energy_infusion.gd
│ │ │ ├── silver_armor.gd
│ │ │ ├── sleeve_of_rage.gd
│ │ │ ├── soul_collectors_cloak.gd
│ │ │ ├── soul_collectors_scythe.gd
│ │ │ ├── soul_extractor.gd
│ │ │ ├── spear_of_loki.gd
│ │ │ ├── speed_demons_reward.gd
│ │ │ ├── spellbook_of_item_mastery.gd
│ │ │ ├── spider_broach.gd
│ │ │ ├── spiderling.gd
│ │ │ ├── staff_of_essence.gd
│ │ │ ├── staff_of_the_wild_equus.gd
│ │ │ ├── stasis_trap.gd
│ │ │ ├── strange_item.gd
│ │ │ ├── stunner.gd
│ │ │ ├── sword_of_decay.gd
│ │ │ ├── sword_of_reckoning.gd
│ │ │ ├── the_divine_wings_of_tragedy.gd
│ │ │ ├── toy_boy.gd
│ │ │ ├── unstable_current.gd
│ │ │ ├── unyielding_maul.gd
│ │ │ ├── vampiric_skull.gd
│ │ │ ├── wand_of_mana_zap.gd
│ │ │ ├── wanted_list.gd
│ │ │ ├── war_drum.gd
│ │ │ ├── wise_mans_cooking_recipe.gd
│ │ │ ├── wizards_soul.gd
│ │ │ ├── wooden_leg.gd
│ │ │ ├── workbench.gd
│ │ │ └── writers_knowledge.gd
│ │ ├── item_container.gd
│ │ ├── item_drop.gd
│ │ ├── item_drop.tscn
│ │ └── tower_item_container.gd
│ ├── map/
│ │ ├── buildable_area.gd
│ │ ├── buildable_area.tscn
│ │ ├── map.gd
│ │ ├── map_big.tscn
│ │ └── map_small.tscn
│ ├── missions/
│ │ ├── instances/
│ │ │ ├── mission_120_in_60min.gd
│ │ │ ├── mission_240_in_120min.gd
│ │ │ ├── mission_35_food_or_less.gd
│ │ │ ├── mission_empty.gd
│ │ │ ├── mission_no_items.gd
│ │ │ ├── mission_no_oils.gd
│ │ │ ├── mission_only_astral_towers.gd
│ │ │ ├── mission_only_common_uncommon.gd
│ │ │ ├── mission_only_darkness_towers.gd
│ │ │ ├── mission_only_fire_towers.gd
│ │ │ ├── mission_only_ice_towers.gd
│ │ │ ├── mission_only_iron_towers.gd
│ │ │ ├── mission_only_nature_towers.gd
│ │ │ └── mission_only_storm_towers.gd
│ │ ├── mission.gd
│ │ ├── mission_manager.gd
│ │ └── mission_manager.tscn
│ ├── player/
│ │ ├── auto_oil.gd
│ │ ├── camera_origin.gd
│ │ ├── camera_origin.tscn
│ │ ├── player.gd
│ │ ├── player.tscn
│ │ ├── team.gd
│ │ ├── team.tscn
│ │ └── tower_stash.gd
│ ├── projectiles/
│ │ ├── projectile.gd
│ │ ├── projectile.tscn
│ │ ├── projectile_type.gd
│ │ └── projectile_visuals/
│ │ ├── ball_lightning_projectile.tscn
│ │ ├── default_projectile.gd
│ │ ├── default_projectile.tscn
│ │ ├── energy_ball.tscn
│ │ ├── flying_pork.tscn
│ │ ├── omnislasher_mirror_image.tscn
│ │ └── quillspray_projectile.tscn
│ ├── singletons/
│ │ ├── README.md
│ │ ├── button_sounds.gd
│ │ ├── combat_log.gd
│ │ ├── config.gd
│ │ ├── constants.gd
│ │ ├── effect.gd
│ │ ├── elapsed_timer.gd
│ │ ├── event_bus.gd
│ │ ├── experience.gd
│ │ ├── experience_password.gd
│ │ ├── globals.gd
│ │ ├── group_manager.gd
│ │ ├── item_drop_calc.gd
│ │ ├── messages.gd
│ │ ├── mission_status.gd
│ │ ├── mission_tracking.gd
│ │ ├── nakama_connection.gd
│ │ ├── player_experience.gd
│ │ ├── player_manager.gd
│ │ ├── preloads.gd
│ │ ├── properties/
│ │ │ ├── README.md
│ │ │ ├── ability_properties.gd
│ │ │ ├── aura_properties.gd
│ │ │ ├── autocast_properties.gd
│ │ │ ├── builder_properties.gd
│ │ │ ├── item_properties.gd
│ │ │ ├── mission_properties.gd
│ │ │ ├── recipe_properties.gd
│ │ │ ├── tower_properties.gd
│ │ │ ├── tutorial_properties.gd
│ │ │ ├── wave_special_properties.gd
│ │ │ └── wisdom_upgrade_properties.gd
│ │ ├── rich_texts.gd
│ │ ├── sanitize_text.gd
│ │ ├── secrets.gd
│ │ ├── settings.gd
│ │ ├── sfx.gd
│ │ ├── sfx_paths.gd
│ │ ├── tower_distribution.gd
│ │ ├── tower_sprites.gd
│ │ ├── unit_icons.gd
│ │ ├── utils.gd
│ │ ├── vector_utils.gd
│ │ └── wave_special.gd
│ ├── spells/
│ │ ├── spell_blizzard.gd
│ │ ├── spell_blizzard.tscn
│ │ ├── spell_chain_lightning.gd
│ │ ├── spell_chain_lightning.tscn
│ │ ├── spell_dummy.gd
│ │ ├── spell_dummy.tscn
│ │ ├── spell_forked_lightning.gd
│ │ ├── spell_forked_lightning.tscn
│ │ ├── spell_swarm.gd
│ │ ├── spell_swarm.tscn
│ │ └── spell_type.gd
│ ├── sprites/
│ │ ├── lightning_animation.tscn
│ │ └── pulsing_dot.tscn
│ ├── tests/
│ │ ├── README.md
│ │ ├── playtest_bot.gd
│ │ ├── test_horadric_tool.gd
│ │ ├── test_item_drop_chances.gd
│ │ ├── test_items_tool.gd
│ │ ├── test_tool.gd
│ │ ├── test_tower_sprite_size.gd
│ │ └── test_towers_tool.gd
│ ├── towers/
│ │ ├── README.md
│ │ ├── autocast.gd
│ │ ├── autocast.tscn
│ │ ├── event.gd
│ │ ├── multiboard_values.gd
│ │ ├── range_data.gd
│ │ ├── range_indicator.gd
│ │ ├── range_indicator.tscn
│ │ ├── tower.gd
│ │ ├── tower.tscn
│ │ ├── tower_behavior.gd
│ │ ├── tower_behavior_template.gd
│ │ ├── tower_behaviors/
│ │ │ ├── afflicted_obelisk.gd
│ │ │ ├── ancient_energy_converter.gd
│ │ │ ├── annoyed_tree.gd
│ │ │ ├── arcane_storm.gd
│ │ │ ├── area_roaster.gd
│ │ │ ├── ash_geyser.gd
│ │ │ ├── astral_lantern.gd
│ │ │ ├── astral_rift.gd
│ │ │ ├── baby_tuskin.gd
│ │ │ ├── ball_lightning_accelerator.gd
│ │ │ ├── basic_knowledge.gd
│ │ │ ├── black_dragon_roost.gd
│ │ │ ├── black_rock_totem.gd
│ │ │ ├── bomb_turret.gd
│ │ │ ├── bone_shrine.gd
│ │ │ ├── bonk_the_living_mountain.gd
│ │ │ ├── broken_cage.gd
│ │ │ ├── broken_circle_of_wind.gd
│ │ │ ├── broken_fire_pit.gd
│ │ │ ├── broken_lightning_rod.gd
│ │ │ ├── bronze_dragon_roost.gd
│ │ │ ├── buried_soul.gd
│ │ │ ├── burning_watchtower.gd
│ │ │ ├── burrow.gd
│ │ │ ├── caged_fire.gd
│ │ │ ├── cenarion.gd
│ │ │ ├── chaining_storm.gd
│ │ │ ├── chaos_warlock.gd
│ │ │ ├── charged_obelisk.gd
│ │ │ ├── chilled_spire.gd
│ │ │ ├── cloud_warrior.gd
│ │ │ ├── cloudy_temple_of_absorption.gd
│ │ │ ├── coconut_sapling.gd
│ │ │ ├── coin_machine.gd
│ │ │ ├── cold_obelisk.gd
│ │ │ ├── cold_troll.gd
│ │ │ ├── contraption.gd
│ │ │ ├── crimson_wyrm.gd
│ │ │ ├── cruel_fire.gd
│ │ │ ├── cursed_grounds.gd
│ │ │ ├── cute_small_spider.gd
│ │ │ ├── dark_battery.gd
│ │ │ ├── death_knight.gd
│ │ │ ├── dimensional_flux_collector.gd
│ │ │ ├── dragon_sorcerer.gd
│ │ │ ├── drake_whisperer.gd
│ │ │ ├── dreadlord.gd
│ │ │ ├── dutchmans_grave.gd
│ │ │ ├── dwarven_forgery.gd
│ │ │ ├── ebonfrost_crystal.gd
│ │ │ ├── embershell_turtle_hatchling.gd
│ │ │ ├── empty_tower_behavior.gd
│ │ │ ├── energy_junction.gd
│ │ │ ├── essence_of_fury.gd
│ │ │ ├── felweed.gd
│ │ │ ├── fenced_flames.gd
│ │ │ ├── fiery_dog.gd
│ │ │ ├── fire_battery.gd
│ │ │ ├── fire_star.gd
│ │ │ ├── firestorm_cell.gd
│ │ │ ├── fisherman.gd
│ │ │ ├── forest_archer.gd
│ │ │ ├── forest_protectress.gd
│ │ │ ├── forest_troll.gd
│ │ │ ├── frost_root.gd
│ │ │ ├── frosty_rock.gd
│ │ │ ├── frozen_well.gd
│ │ │ ├── garden_of_eden.gd
│ │ │ ├── gatling_gun.gd
│ │ │ ├── genis_sage.gd
│ │ │ ├── geothermal_extractor.gd
│ │ │ ├── glaive_master.gd
│ │ │ ├── glowing_solar_orb.gd
│ │ │ ├── gnoll_thunder_mage.gd
│ │ │ ├── goblin_stronghold.gd
│ │ │ ├── grab-o-bot.gd
│ │ │ ├── green_dragon_roost.gd
│ │ │ ├── green_lightning.gd
│ │ │ ├── greyfang.gd
│ │ │ ├── gryphon_rider.gd
│ │ │ ├── hall_of_souls.gd
│ │ │ ├── harby.gd
│ │ │ ├── harpy_witch.gd
│ │ │ ├── haunted_rubble.gd
│ │ │ ├── healing_obelisk.gd
│ │ │ ├── helicopter_zone.gd
│ │ │ ├── hell_bat.gd
│ │ │ ├── holy_energy.gd
│ │ │ ├── ice_battery.gd
│ │ │ ├── icy_core.gd
│ │ │ ├── icy_skulls.gd
│ │ │ ├── icy_spirit.gd
│ │ │ ├── igloo.gd
│ │ │ ├── inexperienced_huntress.gd
│ │ │ ├── inflamed_stone.gd
│ │ │ ├── initiate_elementalist.gd
│ │ │ ├── it.gd
│ │ │ ├── jungle_stalker.gd
│ │ │ ├── kraken.gd
│ │ │ ├── lesser_elemental_ghost.gd
│ │ │ ├── lesser_priest.gd
│ │ │ ├── lesser_skeletal_mage.gd
│ │ │ ├── lesser_wolves_den.gd
│ │ │ ├── library_of_alexandria.gd
│ │ │ ├── lich_king.gd
│ │ │ ├── lightning_eye.gd
│ │ │ ├── lightning_generator.gd
│ │ │ ├── lightning_totem.gd
│ │ │ ├── little_phoenix.gd
│ │ │ ├── living_volcano.gd
│ │ │ ├── lunar_emitter.gd
│ │ │ ├── lunar_sentinel.gd
│ │ │ ├── magic_battery.gd
│ │ │ ├── magic_mushroom.gd
│ │ │ ├── magna_warrior.gd
│ │ │ ├── mana-touched_drake.gd
│ │ │ ├── marine.gd
│ │ │ ├── meteor_totem.gd
│ │ │ ├── militia_watchtower.gd
│ │ │ ├── miner.gd
│ │ │ ├── minor_magic_ruin.gd
│ │ │ ├── mister_fireflies.gd
│ │ │ ├── monolith_of_chaos.gd
│ │ │ ├── morphling.gd
│ │ │ ├── mossy_acid_sprayer.gd
│ │ │ ├── mud_golem.gd
│ │ │ ├── nature_sprites.gd
│ │ │ ├── necromantic_altar.gd
│ │ │ ├── nortrom_the_silencer.gd
│ │ │ ├── nuclear_missile_launcher.gd
│ │ │ ├── obelisk_of_fortuity.gd
│ │ │ ├── owl_of_wisdom.gd
│ │ │ ├── particle_accelerator.gd
│ │ │ ├── phantom.gd
│ │ │ ├── plagued_crypt.gd
│ │ │ ├── planar_gate.gd
│ │ │ ├── poison_battery.gd
│ │ │ ├── polar_bear_cub.gd
│ │ │ ├── portal_to_swine_purgatory.gd
│ │ │ ├── prince_of_lightning.gd
│ │ │ ├── princess_of_light.gd
│ │ │ ├── razorboar_thornweaver.gd
│ │ │ ├── red_ball_lightning.gd
│ │ │ ├── regenerating_well.gd
│ │ │ ├── rooted_chasm.gd
│ │ │ ├── rotted_flashing_grave.gd
│ │ │ ├── rowing_boat.gd
│ │ │ ├── ruined_wind_tower.gd
│ │ │ ├── rundown_iron_sentry.gd
│ │ │ ├── sacred_altar.gd
│ │ │ ├── sacrificial_lamb.gd
│ │ │ ├── safirons_cold_grave.gd
│ │ │ ├── scales.gd
│ │ │ ├── sea_turtle.gd
│ │ │ ├── servant_of_the_twin_flames.gd
│ │ │ ├── sewer_connection.gd
│ │ │ ├── shadow.gd
│ │ │ ├── shaman.gd
│ │ │ ├── shard_of_souls.gd
│ │ │ ├── silver_knight.gd
│ │ │ ├── skink.gd
│ │ │ ├── small_bug_nest.gd
│ │ │ ├── small_fire_sprayer.gd
│ │ │ ├── small_frost_fire.gd
│ │ │ ├── small_ice_mine.gd
│ │ │ ├── small_light.gd
│ │ │ ├── small_ray_blaster.gd
│ │ │ ├── small_serpent_ward.gd
│ │ │ ├── small_torch.gd
│ │ │ ├── sniper.gd
│ │ │ ├── solar_collector.gd
│ │ │ ├── solar_emitter.gd
│ │ │ ├── sorceress.gd
│ │ │ ├── soul_vault.gd
│ │ │ ├── soulflame_device.gd
│ │ │ ├── spell_collector.gd
│ │ │ ├── spider_queen.gd
│ │ │ ├── star_gazer.gd
│ │ │ ├── storm_battery.gd
│ │ │ ├── storm_coil.gd
│ │ │ ├── storm_focus.gd
│ │ │ ├── stormy_dog.gd
│ │ │ ├── sun_crusader.gd
│ │ │ ├── taita_the_hermit.gd
│ │ │ ├── teacher.gd
│ │ │ ├── tentacle_spawn.gd
│ │ │ ├── the_conduit.gd
│ │ │ ├── the_council_of_demons.gd
│ │ │ ├── the_fire_lord.gd
│ │ │ ├── the_frozen_wyrm.gd
│ │ │ ├── the_furnace.gd
│ │ │ ├── the_omnislasher.gd
│ │ │ ├── the_steam_engine.gd
│ │ │ ├── thief_apprentice.gd
│ │ │ ├── tidewater_stream.gd
│ │ │ ├── time_manipulator.gd
│ │ │ ├── timevault.gd
│ │ │ ├── tiny_storm_lantern.gd
│ │ │ ├── tombstone.gd
│ │ │ ├── tundra_stalker.gd
│ │ │ ├── undisturbed_crypt.gd
│ │ │ ├── valor.gd
│ │ │ ├── village_witch.gd
│ │ │ ├── void_drake.gd
│ │ │ ├── vulshok_the_berserker.gd
│ │ │ ├── warrior_of_light.gd
│ │ │ ├── wild_warbeast.gd
│ │ │ ├── witch_doctor.gd
│ │ │ ├── wooden_trap.gd
│ │ │ ├── xeno_research_facility.gd
│ │ │ ├── ymir.gd
│ │ │ ├── young_northern_troll.gd
│ │ │ ├── zealot.gd
│ │ │ └── zeus.gd
│ │ ├── tower_preview.gd
│ │ ├── tower_preview.tscn
│ │ └── tower_sprites/
│ │ ├── abandoned_pit_1.tscn
│ │ ├── abandoned_pit_2.tscn
│ │ ├── abandoned_pit_3.tscn
│ │ ├── abandoned_pit_4.tscn
│ │ ├── abandoned_pit_5.tscn
│ │ ├── abominable_snowman_1.tscn
│ │ ├── abominable_snowman_2.tscn
│ │ ├── abominable_snowman_3.tscn
│ │ ├── abominable_snowman_4.tscn
│ │ ├── abominable_snowman_5.tscn
│ │ ├── afflicted_obelisk_1.tscn
│ │ ├── afflicted_obelisk_2.tscn
│ │ ├── afflicted_obelisk_3.tscn
│ │ ├── afflicted_obelisk_4.tscn
│ │ ├── ancient_energy_converter_1.tscn
│ │ ├── annoyed_tree_1.tscn
│ │ ├── annoyed_tree_2.tscn
│ │ ├── annoyed_tree_3.tscn
│ │ ├── annoyed_tree_4.tscn
│ │ ├── arcane_storm_1.tscn
│ │ ├── area_roaster_1.tscn
│ │ ├── area_roaster_2.tscn
│ │ ├── area_roaster_3.tscn
│ │ ├── ash_geyser_1.tscn
│ │ ├── ash_geyser_2.tscn
│ │ ├── ash_geyser_3.tscn
│ │ ├── ash_geyser_4.tscn
│ │ ├── ash_geyser_5.tscn
│ │ ├── astral_lantern_1.tscn
│ │ ├── astral_lantern_2.tscn
│ │ ├── astral_lantern_3.tscn
│ │ ├── astral_lantern_4.tscn
│ │ ├── astral_rift_1.tscn
│ │ ├── baby_plant_1.tscn
│ │ ├── baby_plant_2.tscn
│ │ ├── baby_plant_3.tscn
│ │ ├── baby_plant_4.tscn
│ │ ├── baby_plant_5.tscn
│ │ ├── baby_plant_6.tscn
│ │ ├── baby_tuskin_1.tscn
│ │ ├── baby_tuskin_2.tscn
│ │ ├── baby_tuskin_3.tscn
│ │ ├── ball_lightning_accelerator_1.tscn
│ │ ├── ball_lightning_accelerator_2.tscn
│ │ ├── basic_knowledge_1.tscn
│ │ ├── basic_knowledge_2.tscn
│ │ ├── basic_knowledge_3.tscn
│ │ ├── basic_knowledge_4.tscn
│ │ ├── basic_knowledge_5.tscn
│ │ ├── black_dragon_roost_1.tscn
│ │ ├── black_rock_totem_1.tscn
│ │ ├── bomb_turret_1.tscn
│ │ ├── bomb_turret_2.tscn
│ │ ├── bone_shrine_1.tscn
│ │ ├── bone_shrine_2.tscn
│ │ ├── bone_shrine_3.tscn
│ │ ├── bonk_the_living_mountain_1.tscn
│ │ ├── broken_cage_1.tscn
│ │ ├── broken_cage_2.tscn
│ │ ├── broken_cage_3.tscn
│ │ ├── broken_cage_4.tscn
│ │ ├── broken_cage_5.tscn
│ │ ├── broken_circle_of_wind_1.tscn
│ │ ├── broken_circle_of_wind_2.tscn
│ │ ├── broken_circle_of_wind_3.tscn
│ │ ├── broken_circle_of_wind_4.tscn
│ │ ├── broken_circle_of_wind_5.tscn
│ │ ├── broken_fire_pit_1.tscn
│ │ ├── broken_fire_pit_2.tscn
│ │ ├── broken_fire_pit_3.tscn
│ │ ├── broken_fire_pit_4.tscn
│ │ ├── broken_fire_pit_5.tscn
│ │ ├── broken_lightning_rod_1.tscn
│ │ ├── broken_lightning_rod_2.tscn
│ │ ├── broken_lightning_rod_3.tscn
│ │ ├── broken_lightning_rod_4.tscn
│ │ ├── broken_lightning_rod_5.tscn
│ │ ├── bronze_dragon_roost_1.tscn
│ │ ├── buried_soul_1.tscn
│ │ ├── buried_soul_2.tscn
│ │ ├── buried_soul_3.tscn
│ │ ├── buried_soul_4.tscn
│ │ ├── burning_watchtower_1.tscn
│ │ ├── burning_watchtower_2.tscn
│ │ ├── burning_watchtower_3.tscn
│ │ ├── burning_watchtower_4.tscn
│ │ ├── burrow_1.tscn
│ │ ├── burrow_2.tscn
│ │ ├── burrow_3.tscn
│ │ ├── burrow_4.tscn
│ │ ├── caged_fire_1.tscn
│ │ ├── caged_fire_2.tscn
│ │ ├── cenarion_1.tscn
│ │ ├── chaining_storm_1.tscn
│ │ ├── chaos_warlock_1.tscn
│ │ ├── chaos_warlock_2.tscn
│ │ ├── charged_obelisk_1.tscn
│ │ ├── chilled_spire_1.tscn
│ │ ├── chilled_spire_2.tscn
│ │ ├── cloud_warrior_1.tscn
│ │ ├── cloud_warrior_2.tscn
│ │ ├── cloud_warrior_3.tscn
│ │ ├── cloud_warrior_4.tscn
│ │ ├── cloud_warrior_5.tscn
│ │ ├── cloudy_temple_of_absorption_1.tscn
│ │ ├── coconut_sapling_1.tscn
│ │ ├── coconut_sapling_2.tscn
│ │ ├── coin_machine_1.tscn
│ │ ├── coin_machine_2.tscn
│ │ ├── cold_obelisk_1.tscn
│ │ ├── cold_obelisk_2.tscn
│ │ ├── cold_obelisk_3.tscn
│ │ ├── cold_troll_1.tscn
│ │ ├── cold_troll_2.tscn
│ │ ├── cold_troll_3.tscn
│ │ ├── cold_troll_4.tscn
│ │ ├── contraption_1.tscn
│ │ ├── contraption_2.tscn
│ │ ├── contraption_3.tscn
│ │ ├── contraption_4.tscn
│ │ ├── crimson_wyrm_1.tscn
│ │ ├── cruel_fire_1.tscn
│ │ ├── cruel_fire_2.tscn
│ │ ├── cruel_fire_3.tscn
│ │ ├── cursed_grounds_1.tscn
│ │ ├── cursed_grounds_2.tscn
│ │ ├── cursed_grounds_3.tscn
│ │ ├── cute_small_spider_1.tscn
│ │ ├── cute_small_spider_2.tscn
│ │ ├── cute_small_spider_3.tscn
│ │ ├── cute_small_spider_4.tscn
│ │ ├── dark_battery_1.tscn
│ │ ├── dark_battery_2.tscn
│ │ ├── dark_battery_3.tscn
│ │ ├── dark_fire_pit_1.tscn
│ │ ├── dark_fire_pit_2.tscn
│ │ ├── dark_fire_pit_3.tscn
│ │ ├── dark_fire_pit_4.tscn
│ │ ├── dark_fire_pit_5.tscn
│ │ ├── death_knight_1.tscn
│ │ ├── dimensional_flux_collector_1.tscn
│ │ ├── dragon_sorcerer_1.tscn
│ │ ├── drake_whisperer_1.tscn
│ │ ├── dreadlord_1.tscn
│ │ ├── dutchmans_grave_1.tscn
│ │ ├── dwarven_forgery_1.tscn
│ │ ├── ebonfrost_crystal_1.tscn
│ │ ├── embershell_turtle_hatchling_1.tscn
│ │ ├── embershell_turtle_hatchling_2.tscn
│ │ ├── embershell_turtle_hatchling_3.tscn
│ │ ├── embershell_turtle_hatchling_4.tscn
│ │ ├── embershell_turtle_hatchling_5.tscn
│ │ ├── energy_junction_1.tscn
│ │ ├── energy_junction_2.tscn
│ │ ├── energy_junction_3.tscn
│ │ ├── essence_of_fury_1.tscn
│ │ ├── essence_of_fury_2.tscn
│ │ ├── essence_of_fury_3.tscn
│ │ ├── essence_of_fury_4.tscn
│ │ ├── essence_of_fury_5.tscn
│ │ ├── felweed_1.tscn
│ │ ├── felweed_2.tscn
│ │ ├── felweed_3.tscn
│ │ ├── felweed_4.tscn
│ │ ├── felweed_5.tscn
│ │ ├── felweed_6.tscn
│ │ ├── fenced_flames_1.tscn
│ │ ├── fenced_flames_2.tscn
│ │ ├── fenced_flames_3.tscn
│ │ ├── fenced_flames_4.tscn
│ │ ├── fiery_dog_1.tscn
│ │ ├── fiery_dog_2.tscn
│ │ ├── fiery_dog_3.tscn
│ │ ├── fiery_dog_4.tscn
│ │ ├── fiery_dog_5.tscn
│ │ ├── fiery_pebble_1.tscn
│ │ ├── fiery_pebble_2.tscn
│ │ ├── fiery_pebble_3.tscn
│ │ ├── fiery_pebble_4.tscn
│ │ ├── fiery_pebble_5.tscn
│ │ ├── fiery_pebble_6.tscn
│ │ ├── fire_battery_1.tscn
│ │ ├── fire_battery_2.tscn
│ │ ├── fire_battery_3.tscn
│ │ ├── fire_star_1.tscn
│ │ ├── firestorm_cell_1.tscn
│ │ ├── firestorm_cell_2.tscn
│ │ ├── firestorm_cell_3.tscn
│ │ ├── firestorm_cell_4.tscn
│ │ ├── fisherman_1.tscn
│ │ ├── forest_archer_1.tscn
│ │ ├── forest_archer_2.tscn
│ │ ├── forest_archer_3.tscn
│ │ ├── forest_protectress_1.tscn
│ │ ├── forest_troll_1.tscn
│ │ ├── forest_troll_2.tscn
│ │ ├── forest_troll_3.tscn
│ │ ├── frost_root_1.tscn
│ │ ├── frost_root_2.tscn
│ │ ├── frost_root_3.tscn
│ │ ├── frost_root_4.tscn
│ │ ├── frost_root_5.tscn
│ │ ├── frost_root_6.tscn
│ │ ├── frosty_rock_1.tscn
│ │ ├── frosty_rock_2.tscn
│ │ ├── frosty_rock_3.tscn
│ │ ├── frosty_rock_4.tscn
│ │ ├── frozen_well_1.tscn
│ │ ├── garden_of_eden_1.tscn
│ │ ├── gatling_gun_1.tscn
│ │ ├── genis_sage_1.tscn
│ │ ├── geothermal_extractor_1.tscn
│ │ ├── geothermal_extractor_2.tscn
│ │ ├── glaive_master_1.tscn
│ │ ├── glowing_solar_orb_1.tscn
│ │ ├── glowing_solar_orb_2.tscn
│ │ ├── glowing_solar_orb_3.tscn
│ │ ├── glowing_solar_orb_4.tscn
│ │ ├── glowing_solar_orb_5.tscn
│ │ ├── gnoll_thunder_mage_1.tscn
│ │ ├── gnoll_thunder_mage_2.tscn
│ │ ├── gnoll_thunder_mage_3.tscn
│ │ ├── goblin_stronghold_1.tscn
│ │ ├── grab-o-bot_1.tscn
│ │ ├── green_dragon_roost_1.tscn
│ │ ├── green_lightning_1.tscn
│ │ ├── green_lightning_2.tscn
│ │ ├── green_lightning_3.tscn
│ │ ├── green_lightning_4.tscn
│ │ ├── greyfang_1.tscn
│ │ ├── gryphon_rider_1.tscn
│ │ ├── hall_of_souls_1.tscn
│ │ ├── hall_of_souls_2.tscn
│ │ ├── hall_of_souls_3.tscn
│ │ ├── harby_1.tscn
│ │ ├── harpy_witch_1.tscn
│ │ ├── harpy_witch_2.tscn
│ │ ├── haunted_rubble_1.tscn
│ │ ├── haunted_rubble_2.tscn
│ │ ├── haunted_rubble_3.tscn
│ │ ├── haunted_rubble_4.tscn
│ │ ├── haunted_rubble_5.tscn
│ │ ├── healing_obelisk_1.tscn
│ │ ├── healing_obelisk_2.tscn
│ │ ├── healing_obelisk_3.tscn
│ │ ├── healing_obelisk_4.tscn
│ │ ├── helicopter_zone_1.tscn
│ │ ├── hell_bat_1.tscn
│ │ ├── hell_bat_2.tscn
│ │ ├── hell_bat_3.tscn
│ │ ├── holy_energy_1.tscn
│ │ ├── ice_battery_1.tscn
│ │ ├── ice_battery_2.tscn
│ │ ├── ice_battery_3.tscn
│ │ ├── icy_core_1.tscn
│ │ ├── icy_core_2.tscn
│ │ ├── icy_skulls_1.tscn
│ │ ├── icy_skulls_2.tscn
│ │ ├── icy_skulls_3.tscn
│ │ ├── icy_skulls_4.tscn
│ │ ├── icy_spirit_1.tscn
│ │ ├── icy_spirit_2.tscn
│ │ ├── icy_spirit_3.tscn
│ │ ├── igloo_1.tscn
│ │ ├── igloo_2.tscn
│ │ ├── igloo_3.tscn
│ │ ├── inexperienced_huntress_1.tscn
│ │ ├── inexperienced_huntress_2.tscn
│ │ ├── inexperienced_huntress_3.tscn
│ │ ├── inflamed_stone_1.tscn
│ │ ├── inflamed_stone_2.tscn
│ │ ├── inflamed_stone_3.tscn
│ │ ├── initiate_elementalist_1.tscn
│ │ ├── initiate_elementalist_2.tscn
│ │ ├── initiate_elementalist_3.tscn
│ │ ├── initiate_elementalist_4.tscn
│ │ ├── it_1.tscn
│ │ ├── jungle_stalker_1.tscn
│ │ ├── jungle_stalker_2.tscn
│ │ ├── jungle_stalker_3.tscn
│ │ ├── kraken_1.tscn
│ │ ├── lesser_astral_defender_1.tscn
│ │ ├── lesser_astral_defender_2.tscn
│ │ ├── lesser_astral_defender_3.tscn
│ │ ├── lesser_astral_defender_4.tscn
│ │ ├── lesser_astral_defender_5.tscn
│ │ ├── lesser_dark_defender_1.tscn
│ │ ├── lesser_dark_defender_2.tscn
│ │ ├── lesser_dark_defender_3.tscn
│ │ ├── lesser_dark_defender_4.tscn
│ │ ├── lesser_dark_defender_5.tscn
│ │ ├── lesser_elemental_ghost_1.tscn
│ │ ├── lesser_elemental_ghost_2.tscn
│ │ ├── lesser_elemental_ghost_3.tscn
│ │ ├── lesser_elemental_ghost_4.tscn
│ │ ├── lesser_elemental_ghost_5.tscn
│ │ ├── lesser_flamy_defender_1.tscn
│ │ ├── lesser_flamy_defender_2.tscn
│ │ ├── lesser_flamy_defender_3.tscn
│ │ ├── lesser_flamy_defender_4.tscn
│ │ ├── lesser_flamy_defender_5.tscn
│ │ ├── lesser_ice_defender_1.tscn
│ │ ├── lesser_ice_defender_2.tscn
│ │ ├── lesser_ice_defender_3.tscn
│ │ ├── lesser_ice_defender_4.tscn
│ │ ├── lesser_ice_defender_5.tscn
│ │ ├── lesser_iron_defender_1.tscn
│ │ ├── lesser_iron_defender_2.tscn
│ │ ├── lesser_iron_defender_3.tscn
│ │ ├── lesser_iron_defender_4.tscn
│ │ ├── lesser_iron_defender_5.tscn
│ │ ├── lesser_natural_defender_1.tscn
│ │ ├── lesser_natural_defender_2.tscn
│ │ ├── lesser_natural_defender_3.tscn
│ │ ├── lesser_natural_defender_4.tscn
│ │ ├── lesser_natural_defender_5.tscn
│ │ ├── lesser_priest_1.tscn
│ │ ├── lesser_priest_2.tscn
│ │ ├── lesser_priest_3.tscn
│ │ ├── lesser_priest_4.tscn
│ │ ├── lesser_priest_5.tscn
│ │ ├── lesser_skeletal_mage_1.tscn
│ │ ├── lesser_skeletal_mage_2.tscn
│ │ ├── lesser_skeletal_mage_3.tscn
│ │ ├── lesser_skeletal_mage_4.tscn
│ │ ├── lesser_storm_defender_1.tscn
│ │ ├── lesser_storm_defender_2.tscn
│ │ ├── lesser_storm_defender_3.tscn
│ │ ├── lesser_storm_defender_4.tscn
│ │ ├── lesser_storm_defender_5.tscn
│ │ ├── lesser_wolves_den_1.tscn
│ │ ├── lesser_wolves_den_2.tscn
│ │ ├── lesser_wolves_den_3.tscn
│ │ ├── library_of_alexandria_1.tscn
│ │ ├── lich_king_1.tscn
│ │ ├── lightning_eye_1.tscn
│ │ ├── lightning_generator_1.tscn
│ │ ├── lightning_generator_2.tscn
│ │ ├── lightning_generator_3.tscn
│ │ ├── lightning_generator_4.tscn
│ │ ├── lightning_totem_1.tscn
│ │ ├── lightning_totem_2.tscn
│ │ ├── lightning_totem_3.tscn
│ │ ├── little_phoenix_1.tscn
│ │ ├── little_phoenix_2.tscn
│ │ ├── little_phoenix_3.tscn
│ │ ├── living_volcano_1.tscn
│ │ ├── lunar_emitter_1.tscn
│ │ ├── lunar_emitter_2.tscn
│ │ ├── lunar_sentinel_1.tscn
│ │ ├── lunar_sentinel_2.tscn
│ │ ├── lunar_sentinel_3.tscn
│ │ ├── lunar_sentinel_4.tscn
│ │ ├── magic_battery_1.tscn
│ │ ├── magic_battery_2.tscn
│ │ ├── magic_battery_3.tscn
│ │ ├── magic_mushroom_1.tscn
│ │ ├── magna_warrior_1.tscn
│ │ ├── magna_warrior_2.tscn
│ │ ├── magna_warrior_3.tscn
│ │ ├── magna_warrior_4.tscn
│ │ ├── magna_warrior_5.tscn
│ │ ├── mana-touched_drake_1.tscn
│ │ ├── mana-touched_drake_2.tscn
│ │ ├── mana-touched_drake_3.tscn
│ │ ├── mana-touched_drake_4.tscn
│ │ ├── marine_1.tscn
│ │ ├── marine_2.tscn
│ │ ├── meteor_totem_1.tscn
│ │ ├── militia_watchtower_1.tscn
│ │ ├── militia_watchtower_2.tscn
│ │ ├── militia_watchtower_3.tscn
│ │ ├── militia_watchtower_4.tscn
│ │ ├── miner_1.tscn
│ │ ├── miner_2.tscn
│ │ ├── miner_3.tscn
│ │ ├── minor_magic_ruin_1.tscn
│ │ ├── minor_magic_ruin_2.tscn
│ │ ├── minor_magic_ruin_3.tscn
│ │ ├── minor_magic_ruin_4.tscn
│ │ ├── minor_magic_ruin_5.tscn
│ │ ├── minor_magic_ruin_6.tscn
│ │ ├── mister_fireflies_1.tscn
│ │ ├── mister_fireflies_2.tscn
│ │ ├── mister_fireflies_3.tscn
│ │ ├── monolith_of_chaos_1.tscn
│ │ ├── morphling_1.tscn
│ │ ├── mossy_acid_sprayer_1.tscn
│ │ ├── mossy_acid_sprayer_2.tscn
│ │ ├── mossy_acid_sprayer_3.tscn
│ │ ├── mossy_acid_sprayer_4.tscn
│ │ ├── mossy_acid_sprayer_5.tscn
│ │ ├── mud_golem_1.tscn
│ │ ├── nature_sprites_1.tscn
│ │ ├── nature_sprites_2.tscn
│ │ ├── nature_sprites_3.tscn
│ │ ├── necromantic_altar_1.tscn
│ │ ├── necromantic_altar_2.tscn
│ │ ├── necromantic_altar_3.tscn
│ │ ├── necromantic_altar_4.tscn
│ │ ├── nortrom_the_silencer_1.tscn
│ │ ├── nuclear_missile_launcher_1.tscn
│ │ ├── obelisk_of_fortuity_1.tscn
│ │ ├── obelisk_of_fortuity_2.tscn
│ │ ├── obelisk_of_fortuity_3.tscn
│ │ ├── obelisk_of_fortuity_4.tscn
│ │ ├── obelisk_of_fortuity_5.tscn
│ │ ├── owl_of_wisdom_1.tscn
│ │ ├── owl_of_wisdom_2.tscn
│ │ ├── particle_accelerator_1.tscn
│ │ ├── particle_accelerator_2.tscn
│ │ ├── particle_accelerator_3.tscn
│ │ ├── phantom_1.tscn
│ │ ├── phantom_2.tscn
│ │ ├── phantom_3.tscn
│ │ ├── phantom_4.tscn
│ │ ├── phantom_5.tscn
│ │ ├── plagued_crypt_1.tscn
│ │ ├── planar_gate_1.tscn
│ │ ├── poison_battery_1.tscn
│ │ ├── poison_battery_2.tscn
│ │ ├── poison_battery_3.tscn
│ │ ├── polar_bear_cub_1.tscn
│ │ ├── polar_bear_cub_2.tscn
│ │ ├── polar_bear_cub_3.tscn
│ │ ├── portal_to_swine_purgatory_1.tscn
│ │ ├── portal_to_swine_purgatory_2.tscn
│ │ ├── portal_to_swine_purgatory_3.tscn
│ │ ├── prince_of_lightning_1.tscn
│ │ ├── prince_of_lightning_2.tscn
│ │ ├── princess_of_light_1.tscn
│ │ ├── princess_of_light_2.tscn
│ │ ├── razorboar_thornweaver_1.tscn
│ │ ├── razorboar_thornweaver_2.tscn
│ │ ├── razorboar_thornweaver_3.tscn
│ │ ├── red_ball_lightning_1.tscn
│ │ ├── red_ball_lightning_2.tscn
│ │ ├── regenerating_well_1.tscn
│ │ ├── regenerating_well_2.tscn
│ │ ├── regenerating_well_3.tscn
│ │ ├── rooted_chasm_1.tscn
│ │ ├── rooted_chasm_2.tscn
│ │ ├── rooted_chasm_3.tscn
│ │ ├── rooted_chasm_4.tscn
│ │ ├── rotted_flashing_grave_1.tscn
│ │ ├── rotted_flashing_grave_2.tscn
│ │ ├── rotted_flashing_grave_3.tscn
│ │ ├── rotted_flashing_grave_4.tscn
│ │ ├── rotted_flashing_grave_5.tscn
│ │ ├── rotted_flashing_grave_6.tscn
│ │ ├── rowing_boat_1.tscn
│ │ ├── rowing_boat_2.tscn
│ │ ├── rowing_boat_3.tscn
│ │ ├── rowing_boat_4.tscn
│ │ ├── ruined_monolith_1.tscn
│ │ ├── ruined_monolith_2.tscn
│ │ ├── ruined_monolith_3.tscn
│ │ ├── ruined_monolith_4.tscn
│ │ ├── ruined_monolith_5.tscn
│ │ ├── ruined_monolith_6.tscn
│ │ ├── ruined_storm_cap_1.tscn
│ │ ├── ruined_storm_cap_2.tscn
│ │ ├── ruined_storm_cap_3.tscn
│ │ ├── ruined_storm_cap_4.tscn
│ │ ├── ruined_storm_cap_5.tscn
│ │ ├── ruined_storm_cap_6.tscn
│ │ ├── ruined_sun_pedestal_1.tscn
│ │ ├── ruined_sun_pedestal_2.tscn
│ │ ├── ruined_sun_pedestal_3.tscn
│ │ ├── ruined_sun_pedestal_4.tscn
│ │ ├── ruined_sun_pedestal_5.tscn
│ │ ├── ruined_sun_pedestal_6.tscn
│ │ ├── ruined_sun_pedestal_7.tscn
│ │ ├── ruined_wind_tower_1.tscn
│ │ ├── ruined_wind_tower_2.tscn
│ │ ├── ruined_wind_tower_3.tscn
│ │ ├── ruined_wind_tower_4.tscn
│ │ ├── rundown_iron_sentry_1.tscn
│ │ ├── rundown_iron_sentry_2.tscn
│ │ ├── rundown_iron_sentry_3.tscn
│ │ ├── sacred_altar_1.tscn
│ │ ├── sacrificial_lamb_1.tscn
│ │ ├── sacrificial_lamb_2.tscn
│ │ ├── safirons_cold_grave_1.tscn
│ │ ├── scales_1.tscn
│ │ ├── sea_turtle_1.tscn
│ │ ├── sea_turtle_2.tscn
│ │ ├── sea_turtle_3.tscn
│ │ ├── servant_of_the_twin_flames_1.tscn
│ │ ├── servant_of_the_twin_flames_2.tscn
│ │ ├── sewer_connection_1.tscn
│ │ ├── sewer_connection_2.tscn
│ │ ├── sewer_connection_3.tscn
│ │ ├── sewer_connection_4.tscn
│ │ ├── shadow_1.tscn
│ │ ├── shaman_1.tscn
│ │ ├── shaman_2.tscn
│ │ ├── shaman_3.tscn
│ │ ├── shard_of_souls_1.tscn
│ │ ├── shard_of_souls_2.tscn
│ │ ├── silver_knight_1.tscn
│ │ ├── silver_knight_2.tscn
│ │ ├── skink_1.tscn
│ │ ├── skink_2.tscn
│ │ ├── skink_3.tscn
│ │ ├── skink_4.tscn
│ │ ├── skink_5.tscn
│ │ ├── small_brazier_1.tscn
│ │ ├── small_brazier_2.tscn
│ │ ├── small_brazier_3.tscn
│ │ ├── small_brazier_4.tscn
│ │ ├── small_bug_nest_1.tscn
│ │ ├── small_bug_nest_2.tscn
│ │ ├── small_bug_nest_3.tscn
│ │ ├── small_bug_nest_4.tscn
│ │ ├── small_cactus_1.tscn
│ │ ├── small_cactus_2.tscn
│ │ ├── small_cactus_3.tscn
│ │ ├── small_cactus_4.tscn
│ │ ├── small_cactus_5.tscn
│ │ ├── small_cactus_6.tscn
│ │ ├── small_fire_sprayer_1.tscn
│ │ ├── small_fire_sprayer_2.tscn
│ │ ├── small_fire_sprayer_3.tscn
│ │ ├── small_fire_sprayer_4.tscn
│ │ ├── small_fire_sprayer_5.tscn
│ │ ├── small_fire_sprayer_6.tscn
│ │ ├── small_frost_fire_1.tscn
│ │ ├── small_frost_fire_2.tscn
│ │ ├── small_frost_fire_3.tscn
│ │ ├── small_frost_fire_4.tscn
│ │ ├── small_frost_fire_5.tscn
│ │ ├── small_frozen_mushroom_1.tscn
│ │ ├── small_frozen_mushroom_2.tscn
│ │ ├── small_frozen_mushroom_3.tscn
│ │ ├── small_frozen_mushroom_4.tscn
│ │ ├── small_frozen_mushroom_5.tscn
│ │ ├── small_ice_mine_1.tscn
│ │ ├── small_ice_mine_2.tscn
│ │ ├── small_ice_mine_3.tscn
│ │ ├── small_ice_mine_4.tscn
│ │ ├── small_light_1.tscn
│ │ ├── small_light_2.tscn
│ │ ├── small_light_3.tscn
│ │ ├── small_light_4.tscn
│ │ ├── small_light_5.tscn
│ │ ├── small_pocket_rocket_1.tscn
│ │ ├── small_pocket_rocket_2.tscn
│ │ ├── small_pocket_rocket_3.tscn
│ │ ├── small_pocket_rocket_4.tscn
│ │ ├── small_pocket_rocket_5.tscn
│ │ ├── small_ray_blaster_1.tscn
│ │ ├── small_ray_blaster_2.tscn
│ │ ├── small_ray_blaster_3.tscn
│ │ ├── small_ray_blaster_4.tscn
│ │ ├── small_ray_blaster_5.tscn
│ │ ├── small_serpent_ward_1.tscn
│ │ ├── small_serpent_ward_2.tscn
│ │ ├── small_serpent_ward_3.tscn
│ │ ├── small_serpent_ward_4.tscn
│ │ ├── small_torch_1.tscn
│ │ ├── small_torch_2.tscn
│ │ ├── small_torch_3.tscn
│ │ ├── small_torch_4.tscn
│ │ ├── small_torch_5.tscn
│ │ ├── sniper_1.tscn
│ │ ├── sniper_2.tscn
│ │ ├── sniper_3.tscn
│ │ ├── sniper_4.tscn
│ │ ├── snowy_pebble_1.tscn
│ │ ├── snowy_pebble_2.tscn
│ │ ├── snowy_pebble_3.tscn
│ │ ├── snowy_pebble_4.tscn
│ │ ├── snowy_pebble_5.tscn
│ │ ├── snowy_pebble_6.tscn
│ │ ├── solar_collector_1.tscn
│ │ ├── solar_collector_2.tscn
│ │ ├── solar_emitter_1.tscn
│ │ ├── solar_emitter_2.tscn
│ │ ├── sorceress_1.tscn
│ │ ├── soul_vault_1.tscn
│ │ ├── soulflame_device_1.tscn
│ │ ├── spell_collector_1.tscn
│ │ ├── spell_collector_2.tscn
│ │ ├── spider_queen_1.tscn
│ │ ├── star_gazer_1.tscn
│ │ ├── star_gazer_2.tscn
│ │ ├── star_gazer_3.tscn
│ │ ├── star_gazer_4.tscn
│ │ ├── storm_battery_1.tscn
│ │ ├── storm_battery_2.tscn
│ │ ├── storm_battery_3.tscn
│ │ ├── storm_coil_1.tscn
│ │ ├── storm_focus_1.tscn
│ │ ├── stormy_dog_1.tscn
│ │ ├── stormy_dog_2.tscn
│ │ ├── stormy_dog_3.tscn
│ │ ├── stormy_dog_4.tscn
│ │ ├── stormy_dog_5.tscn
│ │ ├── sun_crusader_1.tscn
│ │ ├── sun_crusader_2.tscn
│ │ ├── taita_the_hermit_1.tscn
│ │ ├── teacher_1.tscn
│ │ ├── teacher_2.tscn
│ │ ├── teacher_3.tscn
│ │ ├── teacher_4.tscn
│ │ ├── teacher_5.tscn
│ │ ├── teacher_6.tscn
│ │ ├── tentacle_spawn_1.tscn
│ │ ├── tentacle_spawn_2.tscn
│ │ ├── tentacle_spawn_3.tscn
│ │ ├── tentacle_spawn_4.tscn
│ │ ├── tentacle_spawn_5.tscn
│ │ ├── tentacle_spawn_6.tscn
│ │ ├── the_conduit_1.tscn
│ │ ├── the_council_of_demons_1.tscn
│ │ ├── the_fire_lord_1.tscn
│ │ ├── the_frozen_wyrm_1.tscn
│ │ ├── the_furnace_1.tscn
│ │ ├── the_omnislasher_1.tscn
│ │ ├── the_steam_engine_1.tscn
│ │ ├── thief_apprentice_1.tscn
│ │ ├── thief_apprentice_2.tscn
│ │ ├── thief_apprentice_3.tscn
│ │ ├── thief_apprentice_4.tscn
│ │ ├── thief_apprentice_5.tscn
│ │ ├── tidewater_stream_1.tscn
│ │ ├── time_manipulator_1.tscn
│ │ ├── timevault_1.tscn
│ │ ├── tiny_shrub_1.tscn
│ │ ├── tiny_shrub_2.tscn
│ │ ├── tiny_shrub_3.tscn
│ │ ├── tiny_shrub_4.tscn
│ │ ├── tiny_shrub_5.tscn
│ │ ├── tiny_shrub_6.tscn
│ │ ├── tiny_storm_lantern_1.tscn
│ │ ├── tiny_storm_lantern_2.tscn
│ │ ├── tiny_storm_lantern_3.tscn
│ │ ├── tiny_storm_lantern_4.tscn
│ │ ├── tombstone_1.tscn
│ │ ├── tombstone_2.tscn
│ │ ├── tombstone_3.tscn
│ │ ├── tombstone_4.tscn
│ │ ├── tombstone_5.tscn
│ │ ├── tombstone_6.tscn
│ │ ├── trash_heap_1.tscn
│ │ ├── trash_heap_2.tscn
│ │ ├── trash_heap_3.tscn
│ │ ├── trash_heap_4.tscn
│ │ ├── trash_heap_5.tscn
│ │ ├── trash_heap_6.tscn
│ │ ├── tree_stump_1.tscn
│ │ ├── tree_stump_2.tscn
│ │ ├── tree_stump_3.tscn
│ │ ├── tree_stump_4.tscn
│ │ ├── tree_stump_5.tscn
│ │ ├── tundra_stalker_1.tscn
│ │ ├── tundra_stalker_2.tscn
│ │ ├── tundra_stalker_3.tscn
│ │ ├── tundra_stalker_4.tscn
│ │ ├── tundra_stalker_5.tscn
│ │ ├── undisturbed_crypt_1.tscn
│ │ ├── undisturbed_crypt_2.tscn
│ │ ├── undisturbed_crypt_3.tscn
│ │ ├── undisturbed_crypt_4.tscn
│ │ ├── valor_1.tscn
│ │ ├── village_witch_1.tscn
│ │ ├── village_witch_2.tscn
│ │ ├── village_witch_3.tscn
│ │ ├── village_witch_4.tscn
│ │ ├── void_drake_1.tscn
│ │ ├── void_drake_2.tscn
│ │ ├── vulshok_the_berserker_1.tscn
│ │ ├── warrior_of_light_1.tscn
│ │ ├── warrior_of_light_2.tscn
│ │ ├── warrior_of_light_3.tscn
│ │ ├── wild_warbeast_1.tscn
│ │ ├── witch_doctor_1.tscn
│ │ ├── wooden_trap_1.tscn
│ │ ├── wooden_trap_2.tscn
│ │ ├── wooden_trap_3.tscn
│ │ ├── wooden_trap_4.tscn
│ │ ├── wooden_trap_5.tscn
│ │ ├── xeno_research_facility_1.tscn
│ │ ├── ymir_1.tscn
│ │ ├── young_northern_troll_1.tscn
│ │ ├── young_northern_troll_2.tscn
│ │ ├── young_northern_troll_3.tscn
│ │ ├── zealot_1.tscn
│ │ ├── zealot_2.tscn
│ │ ├── zealot_3.tscn
│ │ ├── zealot_4.tscn
│ │ └── zeus_1.tscn
│ ├── ui/
│ │ ├── buttons/
│ │ │ ├── ability_button.gd
│ │ │ ├── ability_button.tscn
│ │ │ ├── auto_mode_indicator.gd
│ │ │ ├── auto_mode_indicator.tscn
│ │ │ ├── autocast_button.gd
│ │ │ ├── autocast_button.tscn
│ │ │ ├── buff_group_button.gd
│ │ │ ├── buff_group_button.tscn
│ │ │ ├── builder_button.tscn
│ │ │ ├── button_tooltip.gd
│ │ │ ├── button_tooltip.tscn
│ │ │ ├── button_with_rich_tooltip.gd
│ │ │ ├── element_button.gd
│ │ │ ├── element_button.tscn
│ │ │ ├── empty_unit_button.gd
│ │ │ ├── empty_unit_button.tscn
│ │ │ ├── freshness_indicator.gd
│ │ │ ├── freshness_indicator.tscn
│ │ │ ├── inventory_slot_button.tscn
│ │ │ ├── item_button.gd
│ │ │ ├── item_button.tscn
│ │ │ ├── item_button_inner.gd
│ │ │ ├── menu_expanding_button.gd
│ │ │ ├── menu_expanding_button.tscn
│ │ │ ├── rarity_background.gd
│ │ │ ├── rarity_background.tscn
│ │ │ ├── recipe_button.gd
│ │ │ ├── recipe_button.tscn
│ │ │ ├── speed_button.tscn
│ │ │ ├── time_indicator.gd
│ │ │ ├── time_indicator.tscn
│ │ │ ├── tower_button.gd
│ │ │ ├── tower_button.tscn
│ │ │ ├── wisdom_upgrade_button.gd
│ │ │ └── wisdom_upgrade_button.tscn
│ │ ├── dev_controls/
│ │ │ ├── dev_controls.gd
│ │ │ ├── dev_controls.tscn
│ │ │ ├── signals_control.gd
│ │ │ ├── signals_control.tscn
│ │ │ ├── wave_control.gd
│ │ │ └── wave_control.tscn
│ │ ├── filter_buttons/
│ │ │ ├── element_filter.gd
│ │ │ ├── element_filter.tscn
│ │ │ ├── filter_button.tscn
│ │ │ ├── filter_button_element.gd
│ │ │ ├── filter_button_element.tscn
│ │ │ ├── filter_button_item_type.gd
│ │ │ ├── filter_button_item_type.tscn
│ │ │ ├── filter_button_rarity.gd
│ │ │ ├── filter_button_rarity.tscn
│ │ │ ├── item_type_filter.gd
│ │ │ ├── item_type_filter.tscn
│ │ │ ├── rarity_filter.gd
│ │ │ └── rarity_filter.tscn
│ │ ├── game_menu/
│ │ │ ├── credits_menu.gd
│ │ │ ├── credits_menu.tscn
│ │ │ ├── game_menu.gd
│ │ │ ├── game_menu.tscn
│ │ │ ├── help_menu.gd
│ │ │ ├── help_menu.tscn
│ │ │ ├── help_menu_tab.gd
│ │ │ ├── help_menu_tab.tscn
│ │ │ ├── settings_menu.gd
│ │ │ └── settings_menu.tscn
│ │ ├── hud/
│ │ │ ├── OneTimeHelpPopup.tscn
│ │ │ ├── build_version_label.gd
│ │ │ ├── build_version_label.tscn
│ │ │ ├── builder_menu.gd
│ │ │ ├── builder_menu.tscn
│ │ │ ├── combat_log_window.gd
│ │ │ ├── combat_log_window.tscn
│ │ │ ├── desync_indicator.tscn
│ │ │ ├── elements_menu.gd
│ │ │ ├── elements_menu.tscn
│ │ │ ├── floating_text.gd
│ │ │ ├── floating_text.tscn
│ │ │ ├── flying_item.gd
│ │ │ ├── flying_item.tscn
│ │ │ ├── game_speed_controller.gd
│ │ │ ├── game_speed_controller.tscn
│ │ │ ├── hud.gd
│ │ │ ├── hud.tscn
│ │ │ ├── label_with_rich_tooltip.gd
│ │ │ ├── mission_track_indicator.gd
│ │ │ ├── mission_track_indicator.tscn
│ │ │ ├── mission_tracker_container.gd
│ │ │ ├── mission_tracker_container.tscn
│ │ │ ├── movable_window.gd
│ │ │ ├── movable_window.tscn
│ │ │ ├── multiplayer_pause_indicator.tscn
│ │ │ ├── one_time_help_popup.gd
│ │ │ ├── rich_text_label_with_rich_tooltip.gd
│ │ │ ├── texture_rect_with_rich_tooltip.gd
│ │ │ ├── tutorial_menu.gd
│ │ │ └── tutorial_menu.tscn
│ │ ├── item_stash_menu/
│ │ │ ├── item_stash_menu.gd
│ │ │ └── item_stash_menu.tscn
│ │ ├── player_resource_display/
│ │ │ ├── player_resource_display.gd
│ │ │ ├── player_resource_display.tscn
│ │ │ ├── resource_status_panel.gd
│ │ │ └── resource_status_panel.tscn
│ │ ├── title_screen/
│ │ │ ├── configure_singleplayer_menu.gd
│ │ │ ├── configure_singleplayer_menu.tscn
│ │ │ ├── connecting_to_server_indicator.tscn
│ │ │ ├── encyclopedia_generic_tab.gd
│ │ │ ├── encyclopedia_generic_tab.tscn
│ │ │ ├── encyclopedia_items.gd
│ │ │ ├── encyclopedia_items.tscn
│ │ │ ├── encyclopedia_menu.gd
│ │ │ ├── encyclopedia_menu.tscn
│ │ │ ├── encyclopedia_towers.gd
│ │ │ ├── encyclopedia_towers.tscn
│ │ │ ├── export_exp_menu.gd
│ │ │ ├── export_exp_menu.tscn
│ │ │ ├── import_exp_menu.gd
│ │ │ ├── import_exp_menu.tscn
│ │ │ ├── lan_match/
│ │ │ │ ├── create_lan_match_menu.gd
│ │ │ │ ├── create_lan_match_menu.tscn
│ │ │ │ ├── lan_connect_menu.gd
│ │ │ │ ├── lan_connect_menu.tscn
│ │ │ │ ├── lan_lobby_menu.gd
│ │ │ │ ├── lan_lobby_menu.tscn
│ │ │ │ ├── setup_lan_game.gd
│ │ │ │ └── setup_lan_game.tscn
│ │ │ ├── match_config.gd
│ │ │ ├── match_config_panel.gd
│ │ │ ├── match_config_panel.tscn
│ │ │ ├── message_popup.gd
│ │ │ ├── message_popup.tscn
│ │ │ ├── missions_menu/
│ │ │ │ ├── mission_card.gd
│ │ │ │ ├── mission_card.tscn
│ │ │ │ ├── missions_menu.gd
│ │ │ │ ├── missions_menu.tscn
│ │ │ │ ├── missions_menu_tab.gd
│ │ │ │ └── missions_menu_tab.tscn
│ │ │ ├── notification_panel.gd
│ │ │ ├── notification_panel.tscn
│ │ │ ├── online/
│ │ │ │ ├── create_online_match_menu.gd
│ │ │ │ ├── create_online_match_menu.tscn
│ │ │ │ ├── match_card.gd
│ │ │ │ ├── match_card.tscn
│ │ │ │ ├── online_lobby_menu.gd
│ │ │ │ ├── online_lobby_menu.tscn
│ │ │ │ ├── online_match_list_menu.gd
│ │ │ │ ├── online_match_list_menu.tscn
│ │ │ │ ├── setup_online_game.gd
│ │ │ │ └── setup_online_game.tscn
│ │ │ ├── profile_menu.gd
│ │ │ ├── profile_menu.tscn
│ │ │ ├── title_screen.gd
│ │ │ ├── title_screen.tscn
│ │ │ ├── wisdom_upgrade_menu.gd
│ │ │ └── wisdom_upgrade_menu.tscn
│ │ ├── top_left_menu/
│ │ │ ├── game_stats.gd
│ │ │ ├── game_stats.tscn
│ │ │ ├── plus_mode_label.gd
│ │ │ ├── plus_mode_label.tscn
│ │ │ ├── top_left_menu.gd
│ │ │ ├── top_left_menu.tscn
│ │ │ ├── wave_status.gd
│ │ │ └── wave_status.tscn
│ │ ├── tower_stash_menu/
│ │ │ ├── tower_stash_menu.gd
│ │ │ └── tower_stash_menu.tscn
│ │ └── unit_menu/
│ │ ├── buff_container.gd
│ │ ├── buff_container.tscn
│ │ ├── buff_display.gd
│ │ ├── buff_display.tscn
│ │ ├── buff_group_editor.gd
│ │ ├── buff_group_editor.tscn
│ │ ├── creep_details.gd
│ │ ├── creep_details.tscn
│ │ ├── creep_mini_details.gd
│ │ ├── creep_mini_details.tscn
│ │ ├── item_container_panel.gd
│ │ ├── item_container_panel.tscn
│ │ ├── mini_details_label.tscn
│ │ ├── progress_bar_with_label.gd
│ │ ├── progress_bar_with_label.tscn
│ │ ├── tower_details.gd
│ │ ├── tower_details.tscn
│ │ ├── tower_mini_details.gd
│ │ ├── tower_mini_details.tscn
│ │ ├── unit_menu.gd
│ │ └── unit_menu.tscn
│ └── unit/
│ ├── dummy_unit.gd
│ ├── dummy_unit.tscn
│ ├── iterate.gd
│ ├── selection_indicator.gd
│ └── unit.gd
├── tools/
│ ├── README.md
│ ├── check_buff_icons.gd
│ ├── check_rng_sync.gd
│ ├── check_translations.gd
│ ├── check_tscn_paths_in_scripts.gd
│ ├── convert_blender_export.gd
│ ├── convert_tower_scene_to_sprite.gd
│ ├── create_tilesheet.gd
│ ├── cut_single_tile.gd
│ ├── cut_tiles_into_connectors.gd
│ ├── cut_tiles_into_decorations.gd
│ ├── generate_censored_assets.gd
│ ├── pack_sprite_sheet.gd
│ ├── remove_empty_space_tilesheet.gd
│ ├── remove_sheet_margins.gd
│ ├── rename_files.gd
│ ├── render_8_direction_sprites.py
│ ├── separate_tilesheet.gd
│ ├── show_missing_imports.py
│ └── slice_sheet_into_rows.gd
└── webrtc/
└── README.md
SYMBOL INDEX (23 symbols across 5 files)
FILE: addons/com.heroiclabs.nakama/dotnet-utils/GodotHttpAdapter.cs
class GodotHttpAdapter (line 30) | public partial class GodotHttpAdapter : Node, IHttpAdapter {
method SendAsync (line 39) | public async Task<string> SendAsync(string method, Uri uri, IDictionar...
method IsTransientException (line 106) | private static bool IsTransientException(Exception e) {
FILE: addons/com.heroiclabs.nakama/dotnet-utils/GodotLogger.cs
class GodotLogger (line 23) | public class GodotLogger : ILogger {
type LogLevel (line 28) | public enum LogLevel {
method GodotLogger (line 44) | public GodotLogger(string p_module = "Nakama", LogLevel p_level = LogL...
method ErrorFormat (line 50) | public void ErrorFormat(string format, params object[] args) {
method WarnFormat (line 57) | public void WarnFormat(string format, params object[] args) {
method InfoFormat (line 64) | public void InfoFormat(string format, params object[] args) {
method DebugFormat (line 71) | public void DebugFormat(string format, params object[] args) {
FILE: addons/com.heroiclabs.nakama/dotnet-utils/GodotWebSocketAdapter.cs
class GodotWebSocketConnectionException (line 25) | public class GodotWebSocketConnectionException : Exception {
method GodotWebSocketConnectionException (line 26) | public GodotWebSocketConnectionException(string message = "WebSocket u...
class GodotWebSocketSendException (line 33) | public class GodotWebSocketSendException : Exception {
method GodotWebSocketSendException (line 34) | public GodotWebSocketSendException() : base("Unable to send over WebSo...
class GodotWebSocketAdapter (line 40) | public partial class GodotWebSocketAdapter : Node, ISocketAdapter
method GodotWebSocketAdapter (line 83) | public GodotWebSocketAdapter()
method CloseAsync (line 89) | public Task CloseAsync()
method ConnectAsync (line 100) | public Task ConnectAsync(Uri uri, int timeout)
method SendAsync (line 130) | public Task SendAsync(ArraySegment<byte> buffer, bool reliable = true,...
method _Process (line 153) | public override void _Process(double delta)
FILE: tools/render_8_direction_sprites.py
function render8directions_selected_objects (line 34) | def render8directions_selected_objects(path):
function get_export_path (line 141) | def get_export_path() -> str:
FILE: tools/show_missing_imports.py
function print_usage (line 4) | def print_usage():
Condensed preview — 3046 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,178K chars).
[
{
"path": ".github/CODEOWNERS",
"chars": 21,
"preview": "* @Kvel2D @Praytic\n"
},
{
"path": ".github/CODE_OF_CONDUCT.md",
"chars": 5488,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": ".github/CONTRIBUTING.md",
"chars": 2379,
"preview": "# Contribution guidance\n\n## How to contribute\n\nYou can contribute in different ways:\n\n- Report a bug in Issues\n- Write a"
},
{
"path": ".github/RCLONE.md",
"chars": 1852,
"preview": "# Setup rclone\n\nRclone is an advanced way to sync assets between your computer and google drive.\n\nNote that if you're us"
},
{
"path": ".github/TRANSLATING.md",
"chars": 1585,
"preview": "# Translation guidance\n\n## How to contribute to translation\n\nTranslated text strings are stored in texts.csv. This file "
},
{
"path": ".github/workflows/github-actions-youtd.yml",
"chars": 6859,
"preview": "name: build-and-publish\n\n# NOTE: disabled this export job because it doesn't work\n# with webrtc lib. Webrtc lib files ne"
},
{
"path": ".gitignore",
"chars": 5822,
"preview": "# Godot .gitignore config\n#\n# Aims to encompass the most commonly found files that we don't want committed\n# to Git, suc"
},
{
"path": "LICENSE",
"chars": 1067,
"preview": "MIT License\n\nCopyright (c) 2023 Icob2Games\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
},
{
"path": "README.md",
"chars": 1059,
"preview": "# YouTD 2\n\n\n\nYouTD 2 is a"
},
{
"path": "addons/com.heroiclabs.nakama/Nakama.gd",
"chars": 1950,
"preview": "@tool\nextends Node\n\n# The default host address of the server.\nconst DEFAULT_HOST : String = \"127.0.0.1\"\n\n# The default p"
},
{
"path": "addons/com.heroiclabs.nakama/Satori/NakamaEvent.gd",
"chars": 2082,
"preview": "extends SatoriAsyncResult\n\n# NOTE: renamed from original \"Event\" to avoid name conflicts\nclass_name NakamaEvent\n\n# The n"
},
{
"path": "addons/com.heroiclabs.nakama/Satori/SatoriAPI.gd",
"chars": 46024,
"preview": "### Code generated by codegen/main.go. DO NOT EDIT. ###\n\nextends RefCounted\nclass_name SatoriAPI\n\n# Log out a session, i"
},
{
"path": "addons/com.heroiclabs.nakama/Satori/SatoriClient.gd",
"chars": 7647,
"preview": "extends RefCounted\n\n## A client for the API in Satori Server.\nclass_name SatoriClient\n\n#region Properties\n\nvar _host\n## "
},
{
"path": "addons/com.heroiclabs.nakama/Satori/SatoriHttpAdapter.gd",
"chars": 6246,
"preview": "@tool\nextends Node\n\n# An adapter which implements the HTTP protocol.\nclass_name SatoriHTTPAdapter\n\n# The logger to use w"
},
{
"path": "addons/com.heroiclabs.nakama/Satori/SatoriSession.gd",
"chars": 2976,
"preview": "extends SatoriAsyncResult\nclass_name SatoriSession\n\nvar _token: String = \"\"\nvar token: String:\n get:\n return "
},
{
"path": "addons/com.heroiclabs.nakama/Satori/utils/SatoriAsyncResult.gd",
"chars": 695,
"preview": "extends RefCounted\nclass_name SatoriAsyncResult\n\nvar exception : SatoriException:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn get_exc"
},
{
"path": "addons/com.heroiclabs.nakama/Satori/utils/SatoriException.gd",
"chars": 925,
"preview": "extends RefCounted\n\n# An exception generated during a request.\n# Usually contains at least an error message.\nclass_name "
},
{
"path": "addons/com.heroiclabs.nakama/Satori/utils/SatoriLogger.gd",
"chars": 825,
"preview": "extends RefCounted\nclass_name SatoriLogger\n\nenum LOG_LEVEL {NONE, ERROR, WARNING, INFO, VERBOSE, DEBUG}\n\nvar _level = LO"
},
{
"path": "addons/com.heroiclabs.nakama/Satori/utils/SatoriSerializer.gd",
"chars": 4584,
"preview": "extends RefCounted\nclass_name SatoriSerializer\n\nstatic func serialize(p_obj : Object) -> Dictionary:\n\tvar out = {}\n\tvar "
},
{
"path": "addons/com.heroiclabs.nakama/Satori.gd",
"chars": 1194,
"preview": "@tool\nextends Node\n\n# The default host address of the server.\nconst DEFAULT_HOST : String = \"127.0.0.1\"\n\n# The default p"
},
{
"path": "addons/com.heroiclabs.nakama/api/NakamaAPI.gd",
"chars": 212718,
"preview": "### Code generated by codegen/main.go. DO NOT EDIT. ###\n\nextends RefCounted\nclass_name NakamaAPI\n\n# A single user-role p"
},
{
"path": "addons/com.heroiclabs.nakama/api/NakamaRTAPI.gd",
"chars": 31697,
"preview": "extends NakamaAsyncResult\n\nclass_name NakamaRTAPI\n\n# A chat channel on the server.\nclass Channel extends NakamaAsyncResu"
},
{
"path": "addons/com.heroiclabs.nakama/api/NakamaRTMessage.gd",
"chars": 17932,
"preview": "extends RefCounted\nclass_name NakamaRTMessage\n\n# Send a channel join message to the server.\nclass ChannelJoin:\n\n\tconst _"
},
{
"path": "addons/com.heroiclabs.nakama/api/NakamaSession.gd",
"chars": 3517,
"preview": "extends NakamaAsyncResult\nclass_name NakamaSession\n\nvar _created : bool = false\nvar created : bool:\n\tset(v):\n\t\tpass\n\tget"
},
{
"path": "addons/com.heroiclabs.nakama/api/NakamaStorageObjectId.gd",
"chars": 736,
"preview": "extends RefCounted\nclass_name NakamaStorageObjectId\n\n# The collection which stores the object.\nvar collection : String\n\n"
},
{
"path": "addons/com.heroiclabs.nakama/api/NakamaWriteStorageObject.gd",
"chars": 736,
"preview": "extends RefCounted\nclass_name NakamaWriteStorageObject\n\nvar collection : String\nvar key : String\nvar permission_read : i"
},
{
"path": "addons/com.heroiclabs.nakama/client/NakamaClient.gd",
"chars": 53873,
"preview": "extends RefCounted\n\n# A client for the API in Nakama server.\nclass_name NakamaClient\n\nconst ChannelType = NakamaRTMessag"
},
{
"path": "addons/com.heroiclabs.nakama/client/NakamaHTTPAdapter.gd",
"chars": 6244,
"preview": "@tool\nextends Node\n\n# An adapter which implements the HTTP protocol.\nclass_name NakamaHTTPAdapter\n\n# The logger to use w"
},
{
"path": "addons/com.heroiclabs.nakama/dotnet-utils/GodotHttpAdapter.cs",
"chars": 4193,
"preview": "// Copyright 2022 The Nakama Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
},
{
"path": "addons/com.heroiclabs.nakama/dotnet-utils/GodotLogger.cs",
"chars": 2551,
"preview": "// Copyright 2022 The Nakama Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
},
{
"path": "addons/com.heroiclabs.nakama/dotnet-utils/GodotWebSocketAdapter.cs",
"chars": 7108,
"preview": "// Copyright 2022 The Nakama Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
},
{
"path": "addons/com.heroiclabs.nakama/socket/NakamaSocket.gd",
"chars": 25319,
"preview": "extends RefCounted\n\n# A socket to interact with Nakama server.\nclass_name NakamaSocket\n\nconst ChannelType = NakamaRTMess"
},
{
"path": "addons/com.heroiclabs.nakama/socket/NakamaSocketAdapter.gd",
"chars": 2436,
"preview": "@tool\nextends Node\n\n# An adapter which implements a socket with a protocol supported by Nakama.\nclass_name NakamaSocketA"
},
{
"path": "addons/com.heroiclabs.nakama/utils/NakamaAsyncResult.gd",
"chars": 791,
"preview": "extends RefCounted\nclass_name NakamaAsyncResult\n\nvar exception : NakamaException:\n\tset(v):\n\t\tpass\n\tget:\n\t\treturn get_exc"
},
{
"path": "addons/com.heroiclabs.nakama/utils/NakamaException.gd",
"chars": 925,
"preview": "extends RefCounted\n\n# An exception generated during a request.\n# Usually contains at least an error message.\nclass_name "
},
{
"path": "addons/com.heroiclabs.nakama/utils/NakamaLogger.gd",
"chars": 825,
"preview": "extends RefCounted\nclass_name NakamaLogger\n\nenum LOG_LEVEL {NONE, ERROR, WARNING, INFO, VERBOSE, DEBUG}\n\nvar _level = LO"
},
{
"path": "addons/com.heroiclabs.nakama/utils/NakamaMultiplayerBridge.gd",
"chars": 10999,
"preview": "extends RefCounted\nclass_name NakamaMultiplayerBridge\n\nenum MatchState {\n\tDISCONNECTED,\n\tJOINING,\n\tCONNECTED,\n\tSOCKET_CL"
},
{
"path": "addons/com.heroiclabs.nakama/utils/NakamaMultiplayerPeer.gd",
"chars": 2332,
"preview": "extends MultiplayerPeerExtension\nclass_name NakamaMultiplayerPeer\n\nconst MAX_PACKET_SIZE := 1 << 24\n\nvar _self_id := 0\nv"
},
{
"path": "addons/com.heroiclabs.nakama/utils/NakamaSerializer.gd",
"chars": 4418,
"preview": "extends RefCounted\nclass_name NakamaSerializer\n\nstatic func serialize(p_obj : Object) -> Dictionary:\n\tvar out = {}\n\tvar "
},
{
"path": "addons/nakama-webrtc/LICENSE.txt",
"chars": 1062,
"preview": "Copyright (c) 2019-2021 David Snopek\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof th"
},
{
"path": "addons/nakama-webrtc/OnlineMatch.gd",
"chars": 20371,
"preview": "extends Node\n\n# For developers to set from the outside, for example:\n# OnlineMatch.max_players = 8\n# OnlineMatch.cli"
},
{
"path": "assets/LICENSE.md",
"chars": 17691,
"preview": "## creative commons\n\n# Attribution-NonCommercial 4.0 International\n\nCreative Commons Corporation (“Creative Commons”) is"
},
{
"path": "assets/README.md",
"chars": 218,
"preview": "This folder contains assets.\n\nNote that only the .import files are checked into git. The actual .png, .mp3 files are sto"
},
{
"path": "assets/creeps/README.md",
"chars": 261,
"preview": "Assets in this folder CANNOT be shared.\nShare placeholders instead. Generate placeholders with generate_censored_assets."
},
{
"path": "assets/creeps/orc/air/fly_E.png.import",
"chars": 771,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b5se2dom7rt6d\"\npath=\"res://.godot/imported/fly_E.png-d"
},
{
"path": "assets/creeps/orc/air/fly_N.png.import",
"chars": 771,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dg22ncv2bbgpl\"\npath=\"res://.godot/imported/fly_N.png-d"
},
{
"path": "assets/creeps/orc/air/fly_NE.png.import",
"chars": 773,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://lhbh8ncpikea\"\npath=\"res://.godot/imported/fly_NE.png-8"
},
{
"path": "assets/creeps/orc/air/fly_NW.png.import",
"chars": 773,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://m74fw3s6vh5h\"\npath=\"res://.godot/imported/fly_NW.png-7"
},
{
"path": "assets/creeps/orc/air/fly_S.png.import",
"chars": 771,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ctrob5r1weymb\"\npath=\"res://.godot/imported/fly_S.png-4"
},
{
"path": "assets/creeps/orc/air/fly_SE.png.import",
"chars": 774,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dejolx201xt4l\"\npath=\"res://.godot/imported/fly_SE.png-"
},
{
"path": "assets/creeps/orc/air/fly_SW.png.import",
"chars": 774,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://beysr35mknwqu\"\npath=\"res://.godot/imported/fly_SW.png-"
},
{
"path": "assets/creeps/orc/air/fly_W.png.import",
"chars": 771,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ddhb3w0ho041v\"\npath=\"res://.godot/imported/fly_W.png-2"
},
{
"path": "assets/creeps/orc/air/metadata.csv",
"chars": 437,
"preview": "name,row_count,col_count,sprite_count,offset_x,offset_y\nfly_E,7,4,25,0.01201923098415,0.05306122452021\nfly_N,7,4,25,0.01"
},
{
"path": "assets/creeps/orc/air/metadata.csv.import",
"chars": 25,
"preview": "[remap]\n\nimporter=\"keep\"\n"
},
{
"path": "assets/creeps/orc/boss/death_E.png.import",
"chars": 778,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b1s341ilp1g0f\"\npath=\"res://.godot/imported/death_E.png"
},
{
"path": "assets/creeps/orc/boss/death_N.png.import",
"chars": 777,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://kyq50l132wm1\"\npath=\"res://.godot/imported/death_N.png-"
},
{
"path": "assets/creeps/orc/boss/death_S.png.import",
"chars": 778,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cmytlwkuq6i8q\"\npath=\"res://.godot/imported/death_S.png"
},
{
"path": "assets/creeps/orc/boss/death_W.png.import",
"chars": 777,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://pulp58p3vflw\"\npath=\"res://.godot/imported/death_W.png-"
},
{
"path": "assets/creeps/orc/boss/metadata.csv",
"chars": 460,
"preview": "name,row_count,col_count,sprite_count,offset_x,offset_y\ndeath_E,7,4,28,0.0024509804789,0.0247104242444\ndeath_N,7,4,28,0."
},
{
"path": "assets/creeps/orc/boss/metadata.csv.import",
"chars": 25,
"preview": "[remap]\n\nimporter=\"keep\"\n"
},
{
"path": "assets/creeps/orc/boss/slow_run_E.png.import",
"chars": 787,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c4mbacosga5se\"\npath=\"res://.godot/imported/slow_run_E."
},
{
"path": "assets/creeps/orc/boss/slow_run_N.png.import",
"chars": 787,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dcrmib66n1i1k\"\npath=\"res://.godot/imported/slow_run_N."
},
{
"path": "assets/creeps/orc/boss/slow_run_S.png.import",
"chars": 787,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://be8at5qd2xtfm\"\npath=\"res://.godot/imported/slow_run_S."
},
{
"path": "assets/creeps/orc/boss/slow_run_W.png.import",
"chars": 787,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bf8mfmg7jkmv7\"\npath=\"res://.godot/imported/slow_run_W."
},
{
"path": "assets/creeps/orc/champion/death_E.png.import",
"chars": 781,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://hdtvoqf7jppc\"\npath=\"res://.godot/imported/death_E.png-"
},
{
"path": "assets/creeps/orc/champion/death_N.png.import",
"chars": 782,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bt0fnps8to5c5\"\npath=\"res://.godot/imported/death_N.png"
},
{
"path": "assets/creeps/orc/champion/death_S.png.import",
"chars": 782,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bn3cfvfeop2ni\"\npath=\"res://.godot/imported/death_S.png"
},
{
"path": "assets/creeps/orc/champion/death_W.png.import",
"chars": 782,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dvwut2d2wdqo3\"\npath=\"res://.godot/imported/death_W.png"
},
{
"path": "assets/creeps/orc/champion/metadata.csv",
"chars": 462,
"preview": "name,row_count,col_count,sprite_count,offset_x,offset_y\ndeath_E,7,4,28,0.01123595517129,0.02873563207686\ndeath_N,7,4,28,"
},
{
"path": "assets/creeps/orc/champion/metadata.csv.import",
"chars": 25,
"preview": "[remap]\n\nimporter=\"keep\"\n"
},
{
"path": "assets/creeps/orc/champion/slow_run_E.png.import",
"chars": 791,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ch7gt4062eyrj\"\npath=\"res://.godot/imported/slow_run_E."
},
{
"path": "assets/creeps/orc/champion/slow_run_N.png.import",
"chars": 791,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dxvx01jjvjcye\"\npath=\"res://.godot/imported/slow_run_N."
},
{
"path": "assets/creeps/orc/champion/slow_run_S.png.import",
"chars": 791,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d4cer5fkla46y\"\npath=\"res://.godot/imported/slow_run_S."
},
{
"path": "assets/creeps/orc/champion/slow_run_W.png.import",
"chars": 791,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bvaegexu3foek\"\npath=\"res://.godot/imported/slow_run_W."
},
{
"path": "assets/creeps/orc/mass/death_E.png.import",
"chars": 778,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c031gwyl83vsh\"\npath=\"res://.godot/imported/death_E.png"
},
{
"path": "assets/creeps/orc/mass/death_N.png.import",
"chars": 778,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://byqwfls7534ta\"\npath=\"res://.godot/imported/death_N.png"
},
{
"path": "assets/creeps/orc/mass/death_S.png.import",
"chars": 778,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dc3ghqhhglmqi\"\npath=\"res://.godot/imported/death_S.png"
},
{
"path": "assets/creeps/orc/mass/death_W.png.import",
"chars": 777,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://e7syh2jbikvl\"\npath=\"res://.godot/imported/death_W.png-"
},
{
"path": "assets/creeps/orc/mass/metadata.csv",
"chars": 463,
"preview": "name,row_count,col_count,sprite_count,offset_x,offset_y\ndeath_E,7,4,28,0.00811688322574,0.03686635941267\ndeath_N,7,4,28,"
},
{
"path": "assets/creeps/orc/mass/metadata.csv.import",
"chars": 25,
"preview": "[remap]\n\nimporter=\"keep\"\n"
},
{
"path": "assets/creeps/orc/mass/slow_run_E.png.import",
"chars": 787,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bd5vg4oke4m70\"\npath=\"res://.godot/imported/slow_run_E."
},
{
"path": "assets/creeps/orc/mass/slow_run_N.png.import",
"chars": 786,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://jmweiopkc2gm\"\npath=\"res://.godot/imported/slow_run_N.p"
},
{
"path": "assets/creeps/orc/mass/slow_run_S.png.import",
"chars": 787,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://beanme0cwvawx\"\npath=\"res://.godot/imported/slow_run_S."
},
{
"path": "assets/creeps/orc/mass/slow_run_W.png.import",
"chars": 787,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c2kjqefq762mo\"\npath=\"res://.godot/imported/slow_run_W."
},
{
"path": "assets/creeps/orc/normal/death_E.png.import",
"chars": 779,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://3fls0dd5msho\"\npath=\"res://.godot/imported/death_E.png-"
},
{
"path": "assets/creeps/orc/normal/death_N.png.import",
"chars": 780,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ceyrhdt7hrlvb\"\npath=\"res://.godot/imported/death_N.png"
},
{
"path": "assets/creeps/orc/normal/death_S.png.import",
"chars": 780,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ca3nyf1hqvlca\"\npath=\"res://.godot/imported/death_S.png"
},
{
"path": "assets/creeps/orc/normal/death_W.png.import",
"chars": 779,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://nh8ulueomejj\"\npath=\"res://.godot/imported/death_W.png-"
},
{
"path": "assets/creeps/orc/normal/metadata.csv",
"chars": 442,
"preview": "name,row_count,col_count,sprite_count,offset_x,offset_y\ndeath_E,7,4,28,0.0441176481545,0.03763900697231\ndeath_N,7,4,28,0"
},
{
"path": "assets/creeps/orc/normal/metadata.csv.import",
"chars": 25,
"preview": "[remap]\n\nimporter=\"keep\"\n"
},
{
"path": "assets/creeps/orc/normal/slow_run_E.png.import",
"chars": 789,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dby3igs0d3hvn\"\npath=\"res://.godot/imported/slow_run_E."
},
{
"path": "assets/creeps/orc/normal/slow_run_N.png.import",
"chars": 789,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bns6kclfij3yy\"\npath=\"res://.godot/imported/slow_run_N."
},
{
"path": "assets/creeps/orc/normal/slow_run_S.png.import",
"chars": 789,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bshgy2yv32i6a\"\npath=\"res://.godot/imported/slow_run_S."
},
{
"path": "assets/creeps/orc/normal/slow_run_W.png.import",
"chars": 788,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://5hpj51wwf21h\"\npath=\"res://.godot/imported/slow_run_W.p"
},
{
"path": "assets/effects/arrow.png.import",
"chars": 764,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://djotx5jk18gc0\"\npath=\"res://.godot/imported/arrow.png-9"
},
{
"path": "assets/effects/bdragon/README.md",
"chars": 232,
"preview": "Assets in this folder CANNOT be shared.\nShare placeholders instead. Generate placeholders with generate_censored_assets."
},
{
"path": "assets/effects/bdragon/ancient_protector_missile_293.png.import",
"chars": 844,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dwdvvm6bwoxfw\"\npath=\"res://.godot/imported/ancient_pro"
},
{
"path": "assets/effects/bdragon/animated_dead_target_102.png.import",
"chars": 829,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c4t5ody7wg6wa\"\npath=\"res://.godot/imported/animated_de"
},
{
"path": "assets/effects/bdragon/apply_potion_537.png.import",
"chars": 805,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bvcsmcf7c2lf8\"\npath=\"res://.godot/imported/apply_potio"
},
{
"path": "assets/effects/bdragon/arcane_tower_attack_024.png.import",
"chars": 826,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c4xwqnjdc1ipo\"\npath=\"res://.godot/imported/arcane_towe"
},
{
"path": "assets/effects/bdragon/avatar_caster_10.png.import",
"chars": 805,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bpanfd3kpr8y7\"\npath=\"res://.godot/imported/avatar_cast"
},
{
"path": "assets/effects/bdragon/banshee_missile_487.png.import",
"chars": 814,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c1q82fl7tji4e\"\npath=\"res://.godot/imported/banshee_mis"
},
{
"path": "assets/effects/bdragon/blink_target_720.png.import",
"chars": 804,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://l77fhcp00n6l\"\npath=\"res://.godot/imported/blink_target"
},
{
"path": "assets/effects/bdragon/blood_splatter_376.png.import",
"chars": 810,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cueu6nx32scn\"\npath=\"res://.godot/imported/blood_splatt"
},
{
"path": "assets/effects/bdragon/build_tower_648.png.import",
"chars": 802,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dng7ptld4y130\"\npath=\"res://.godot/imported/build_tower"
},
{
"path": "assets/effects/bdragon/charm_target_703.png.import",
"chars": 805,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c75jmqs4u7hnv\"\npath=\"res://.godot/imported/charm_targe"
},
{
"path": "assets/effects/bdragon/cloud_of_fog_382.png.import",
"chars": 805,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dhm5njivfgxpo\"\npath=\"res://.godot/imported/cloud_of_fo"
},
{
"path": "assets/effects/bdragon/cloud_of_fog_small_428.png.import",
"chars": 822,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://m4w03jglmnu1\"\npath=\"res://.godot/imported/cloud_of_fog"
},
{
"path": "assets/effects/bdragon/cripple_target_198.png.import",
"chars": 811,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://crdvk0hy3x3px\"\npath=\"res://.godot/imported/cripple_tar"
},
{
"path": "assets/effects/bdragon/crushing_wave_damage_584.png.import",
"chars": 829,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bxvpwc34g1fgw\"\npath=\"res://.godot/imported/crushing_wa"
},
{
"path": "assets/effects/bdragon/crypt_fiend_eggsack_528.png.import",
"chars": 826,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cvu38ecsot0h2\"\npath=\"res://.godot/imported/crypt_fiend"
},
{
"path": "assets/effects/bdragon/cyclone_target_269.png.import",
"chars": 811,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://d4e4pstgsefwc\"\npath=\"res://.godot/imported/cyclone_tar"
},
{
"path": "assets/effects/bdragon/death_and_decay_71.png.import",
"chars": 810,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c8w3beqtm72u\"\npath=\"res://.godot/imported/death_and_de"
},
{
"path": "assets/effects/bdragon/death_coil_special_728.png.import",
"chars": 823,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cbmu8xdosr3xw\"\npath=\"res://.godot/imported/death_coil_"
},
{
"path": "assets/effects/bdragon/devour_509.png.import",
"chars": 787,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dqligfo47vxn1\"\npath=\"res://.godot/imported/devour_509."
},
{
"path": "assets/effects/bdragon/dispel_magic_target_456.png.import",
"chars": 825,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://e2i8sa520qes\"\npath=\"res://.godot/imported/dispel_magic"
},
{
"path": "assets/effects/bdragon/doom_death_451.png.import",
"chars": 799,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b7j12e3p73bqd\"\npath=\"res://.godot/imported/doom_death_"
},
{
"path": "assets/effects/bdragon/faerie_dragon_missile_482.png.import",
"chars": 832,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cuavhpswhvx4s\"\npath=\"res://.godot/imported/faerie_drag"
},
{
"path": "assets/effects/bdragon/firelord_death_explode_77.png.import",
"chars": 832,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bcgbhwc4vii7u\"\npath=\"res://.godot/imported/firelord_de"
},
{
"path": "assets/effects/bdragon/flame_strike_embers_702.png.import",
"chars": 826,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ddtif7hi5hsjr\"\npath=\"res://.godot/imported/flame_strik"
},
{
"path": "assets/effects/bdragon/flower_aura_655.png.import",
"chars": 802,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c78vkmjgqto8v\"\npath=\"res://.godot/imported/flower_aura"
},
{
"path": "assets/effects/bdragon/frag_boom_spawn_426.png.import",
"chars": 813,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://yvx6sbavyr4p\"\npath=\"res://.godot/imported/frag_boom_sp"
},
{
"path": "assets/effects/bdragon/freezing_breath_519.png.import",
"chars": 814,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c22lkk5uieshi\"\npath=\"res://.godot/imported/freezing_br"
},
{
"path": "assets/effects/bdragon/frost_armor_damage_474.png.import",
"chars": 822,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ijncv7mjaq1q\"\npath=\"res://.godot/imported/frost_armor_"
},
{
"path": "assets/effects/bdragon/frost_bolt_missile_063.png.import",
"chars": 823,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cvxaisa1jliqu\"\npath=\"res://.godot/imported/frost_bolt_"
},
{
"path": "assets/effects/bdragon/glaive_746.png.import",
"chars": 786,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://204ebjk0432r\"\npath=\"res://.godot/imported/glaive_746.p"
},
{
"path": "assets/effects/bdragon/gold_credit_673.png.import",
"chars": 802,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://du2y31j6qbb5m\"\npath=\"res://.godot/imported/gold_credit"
},
{
"path": "assets/effects/bdragon/gold_credit_88.png.import",
"chars": 799,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bg6jx8tkf0t6l\"\npath=\"res://.godot/imported/gold_credit"
},
{
"path": "assets/effects/bdragon/healing_wave_target_453.png.import",
"chars": 826,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c56ujjaxdg1my\"\npath=\"res://.godot/imported/healing_wav"
},
{
"path": "assets/effects/bdragon/holy_bolt_241.png.import",
"chars": 796,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bfnbtlckgbnfs\"\npath=\"res://.godot/imported/holy_bolt_2"
},
{
"path": "assets/effects/bdragon/immolation_damage_541.png.import",
"chars": 819,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://hyqt8yi512yh\"\npath=\"res://.godot/imported/immolation_d"
},
{
"path": "assets/effects/bdragon/impale_hit_target_529.png.import",
"chars": 819,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://tnlbuwsjjav0\"\npath=\"res://.godot/imported/impale_hit_t"
},
{
"path": "assets/effects/bdragon/impale_target_dust_025.png.import",
"chars": 823,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://brfqvsks7awtk\"\npath=\"res://.godot/imported/impale_targ"
},
{
"path": "assets/effects/bdragon/incinerate_76.png.import",
"chars": 796,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cujsekapgggit\"\npath=\"res://.godot/imported/incinerate_"
},
{
"path": "assets/effects/bdragon/keeper_grove_missile_297.png.import",
"chars": 829,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ch2peil7lqosf\"\npath=\"res://.godot/imported/keeper_grov"
},
{
"path": "assets/effects/bdragon/level_up_455.png.import",
"chars": 792,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://wspy8ha1qyck\"\npath=\"res://.godot/imported/level_up_455"
},
{
"path": "assets/effects/bdragon/mana_burn_target_388.png.import",
"chars": 817,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cgakg4s2ct3ru\"\npath=\"res://.godot/imported/mana_burn_t"
},
{
"path": "assets/effects/bdragon/mana_shield_026.png.import",
"chars": 802,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b01ug8hkohe4a\"\npath=\"res://.godot/imported/mana_shield"
},
{
"path": "assets/effects/bdragon/mass_teleport_caster_335.png.import",
"chars": 828,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ewm7nac57wox\"\npath=\"res://.godot/imported/mass_telepor"
},
{
"path": "assets/effects/bdragon/mass_teleport_target_315.png.import",
"chars": 829,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://biy8bqpp0e7kj\"\npath=\"res://.godot/imported/mass_telepo"
},
{
"path": "assets/effects/bdragon/mirror_image_caster_711.png.import",
"chars": 826,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cdt55t8kxtqiq\"\npath=\"res://.godot/imported/mirror_imag"
},
{
"path": "assets/effects/bdragon/moonwell_target_584.png.import",
"chars": 814,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cxngu4anhtvk6\"\npath=\"res://.godot/imported/moonwell_ta"
},
{
"path": "assets/effects/bdragon/ne_cancel_death_672.png.import",
"chars": 814,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bryrhw6t0k26o\"\npath=\"res://.godot/imported/ne_cancel_d"
},
{
"path": "assets/effects/bdragon/ne_death_612.png.import",
"chars": 793,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dbjenjgmw6cgt\"\npath=\"res://.godot/imported/ne_death_61"
},
{
"path": "assets/effects/bdragon/placeholder_481.png.import",
"chars": 801,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://8aycp6wxnpve\"\npath=\"res://.godot/imported/placeholder_"
},
{
"path": "assets/effects/bdragon/polymorph_target_735.png.import",
"chars": 817,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dcfs2k3q3dixg\"\npath=\"res://.godot/imported/polymorph_t"
},
{
"path": "assets/effects/bdragon/projectile_explosion_299.png.import",
"chars": 829,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cyyax4tkjt7au\"\npath=\"res://.godot/imported/projectile_"
},
{
"path": "assets/effects/bdragon/purge_buff_target_195.png.import",
"chars": 820,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dsvu05xjwic5g\"\npath=\"res://.godot/imported/purge_buff_"
},
{
"path": "assets/effects/bdragon/quillspray_747.png.import",
"chars": 799,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cknypfqkfkgiq\"\npath=\"res://.godot/imported/quillspray_"
},
{
"path": "assets/effects/bdragon/raise_skeleton_624.png.import",
"chars": 811,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dfwypnwsg3p3u\"\npath=\"res://.godot/imported/raise_skele"
},
{
"path": "assets/effects/bdragon/replenish_mana_334.png.import",
"chars": 811,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cwembk4judxy3\"\npath=\"res://.godot/imported/replenish_m"
},
{
"path": "assets/effects/bdragon/revive_human_623.png.import",
"chars": 805,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c7ufux57uh5ua\"\npath=\"res://.godot/imported/revive_huma"
},
{
"path": "assets/effects/bdragon/roar_506.png.import",
"chars": 780,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://un4kd4n5xqem\"\npath=\"res://.godot/imported/roar_506.png"
},
{
"path": "assets/effects/bdragon/roots_235.png.import",
"chars": 784,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ddh33dc161220\"\npath=\"res://.godot/imported/roots_235.p"
},
{
"path": "assets/effects/bdragon/shackle_439.png.import",
"chars": 790,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cv8vncnltc5ta\"\npath=\"res://.godot/imported/shackle_439"
},
{
"path": "assets/effects/bdragon/shockwave_missile_440.png.import",
"chars": 820,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://btlx0a8g4015b\"\npath=\"res://.godot/imported/shockwave_m"
},
{
"path": "assets/effects/bdragon/silence_area_611.png.import",
"chars": 805,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cetfk6yto1khh\"\npath=\"res://.godot/imported/silence_are"
},
{
"path": "assets/effects/bdragon/small_flame_spawn_240.png.import",
"chars": 820,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://caisjfsu3fyap\"\npath=\"res://.godot/imported/small_flame"
},
{
"path": "assets/effects/bdragon/spell_aiil_452.png.import",
"chars": 799,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dr841ukdn8762\"\npath=\"res://.godot/imported/spell_aiil_"
},
{
"path": "assets/effects/bdragon/spell_ailb_723.png.import",
"chars": 798,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://0152qy55d5hs\"\npath=\"res://.godot/imported/spell_ailb_7"
},
{
"path": "assets/effects/bdragon/spell_aima_194.png.import",
"chars": 799,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://csiqjph81rdq8\"\npath=\"res://.godot/imported/spell_aima_"
},
{
"path": "assets/effects/bdragon/spell_aire_174.png.import",
"chars": 797,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ne67yotbsow\"\npath=\"res://.godot/imported/spell_aire_17"
},
{
"path": "assets/effects/bdragon/spell_aiso_295.png.import",
"chars": 799,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://carq8d0wtr1pl\"\npath=\"res://.godot/imported/spell_aiso_"
},
{
"path": "assets/effects/bdragon/spell_alim_136.png.import",
"chars": 799,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cxr4c28mmw4nn\"\npath=\"res://.godot/imported/spell_alim_"
},
{
"path": "assets/effects/bdragon/spell_breaker_target_613.png.import",
"chars": 828,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://gtoj6o1w8tv0\"\npath=\"res://.godot/imported/spell_breake"
},
{
"path": "assets/effects/bdragon/spirit_link_target_175.png.import",
"chars": 822,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://terakoeeqruj\"\npath=\"res://.godot/imported/spirit_link_"
},
{
"path": "assets/effects/bdragon/stampede_missile_death_63.png.import",
"chars": 832,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bbmm2xf32v0tx\"\npath=\"res://.godot/imported/stampede_mi"
},
{
"path": "assets/effects/bdragon/starfall_target_257.png.import",
"chars": 814,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b7swdbv14utxv\"\npath=\"res://.godot/imported/starfall_ta"
},
{
"path": "assets/effects/bdragon/thunder_clap_466.png.import",
"chars": 804,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://2dquk1ppfku0\"\npath=\"res://.godot/imported/thunder_clap"
},
{
"path": "assets/effects/bdragon/undead_dissipate_633.png.import",
"chars": 817,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://blekt36dlhmd2\"\npath=\"res://.godot/imported/undead_diss"
},
{
"path": "assets/effects/bdragon/upgrade_tower_016.png.import",
"chars": 808,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cpuu4w0gghqoe\"\npath=\"res://.godot/imported/upgrade_tow"
},
{
"path": "assets/effects/bdragon/vampiric_aura_199.png.import",
"chars": 807,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b2nm17eb4jt7\"\npath=\"res://.godot/imported/vampiric_aur"
},
{
"path": "assets/effects/bdragon/voodoo_aura_182.png.import",
"chars": 802,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cktvui85usgvp\"\npath=\"res://.godot/imported/voodoo_aura"
},
{
"path": "assets/effects/bdragon/warstomp_caster_536.png.import",
"chars": 814,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://di3fq4jkhoq4y\"\npath=\"res://.godot/imported/warstomp_ca"
},
{
"path": "assets/effects/bdragon/wind_shear_559.png.import",
"chars": 798,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://4vi0ba0hi12o\"\npath=\"res://.godot/imported/wind_shear_5"
},
{
"path": "assets/effects/bdragon/wisp_explode_003.png.import",
"chars": 804,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://pb01lu85dqby\"\npath=\"res://.godot/imported/wisp_explode"
},
{
"path": "assets/effects/bdragon/ziggurat_frost_missile_325.png.import",
"chars": 835,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bvvxqx0twqcdq\"\npath=\"res://.godot/imported/ziggurat_fr"
},
{
"path": "assets/effects/bdragon/zombify_target_274.png.import",
"chars": 811,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dtoev5csbiekv\"\npath=\"res://.godot/imported/zombify_tar"
},
{
"path": "assets/effects/death_explode.png.import",
"chars": 788,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://ctpc46l8ddp8n\"\npath=\"res://.godot/imported/death_explo"
},
{
"path": "assets/effects/lightning_long.png.import",
"chars": 791,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dyle0v7ow0gxp\"\npath=\"res://.godot/imported/lightning_l"
},
{
"path": "assets/effects/stun.png.import",
"chars": 761,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bmtjm6qhm3rop\"\npath=\"res://.godot/imported/stun.png-70"
},
{
"path": "assets/fonts/Friz Quadrata Std Medium.otf.import",
"chars": 835,
"preview": "[remap]\n\nimporter=\"font_data_dynamic\"\ntype=\"FontFile\"\nuid=\"uid://d1pnwehsosppo\"\npath=\"res://.godot/imported/Friz Quadrat"
},
{
"path": "assets/fonts/NotoSansSC-Medium.ttf.import",
"chars": 731,
"preview": "[remap]\n\nimporter=\"font_data_dynamic\"\ntype=\"FontFile\"\nuid=\"uid://b230565e8xtmg\"\npath=\"res://.godot/imported/NotoSansSC-M"
},
{
"path": "assets/hud/bitmaps/circle_bitmap_100x100.png.import",
"chars": 817,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://tuxggwvj4o35\"\npath=\"res://.godot/imported/circle_bitma"
},
{
"path": "assets/hud/bitmaps/circle_bitmap_256x256.png.import",
"chars": 816,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cbw3opxuts8mj\"\npath=\"res://.godot/imported/circle_bitm"
},
{
"path": "assets/hud/checkbox.png.import",
"chars": 769,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bxfq60uwqny4m\"\npath=\"res://.godot/imported/checkbox.pn"
},
{
"path": "assets/hud/circle_bitmap_256x256.png.import",
"chars": 808,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dsbsuq1mmtbwf\"\npath=\"res://.godot/imported/circle_bitm"
},
{
"path": "assets/hud/darkness_face.png.import",
"chars": 784,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b3s3mtb8efipi\"\npath=\"res://.godot/imported/darkness_fa"
},
{
"path": "assets/hud/element_progress_circle.png.import",
"chars": 815,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b36lpf5pdifac\"\npath=\"res://.godot/imported/element_pro"
},
{
"path": "assets/hud/horadric_cube.png.import",
"chars": 783,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://h5ppp14fvtrd\"\npath=\"res://.godot/imported/horadric_cub"
},
{
"path": "assets/hud/hud_atlas.png.import",
"chars": 773,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dl22jvey8l5fo\"\npath=\"res://.godot/imported/hud_atlas.p"
},
{
"path": "assets/hud/misc2.png.import",
"chars": 760,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bf7g834206kwo\"\npath=\"res://.godot/imported/misc2.png-8"
},
{
"path": "assets/hud/misc3.png.import",
"chars": 759,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://60qc7jcvckhh\"\npath=\"res://.godot/imported/misc3.png-6f"
},
{
"path": "assets/hud/misc3_s.png.import",
"chars": 768,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dyixmgwifdsin\"\npath=\"res://.godot/imported/misc3_s.png"
},
{
"path": "assets/hud/misc4.png.import",
"chars": 760,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dfuxtb0pn0imr\"\npath=\"res://.godot/imported/misc4.png-3"
},
{
"path": "assets/hud/tranquility_face.png.import",
"chars": 792,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://mglwvt681k5r\"\npath=\"res://.godot/imported/tranquility_"
},
{
"path": "assets/icons/amulets.png.import",
"chars": 768,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://c4f2vpcxem3iv\"\npath=\"res://.godot/imported/amulets.png"
},
{
"path": "assets/icons/animals.png.import",
"chars": 768,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dqw2twgahvt7e\"\npath=\"res://.godot/imported/animals.png"
},
{
"path": "assets/icons/armor.png.import",
"chars": 761,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://jy45uwdi1vwj\"\npath=\"res://.godot/imported/armor.png-cd"
},
{
"path": "assets/icons/blunt_weapons.png.import",
"chars": 786,
"preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dxmouedtoclok\"\npath=\"res://.godot/imported/blunt_weapo"
}
]
// ... and 2846 more files (download for full content)
About this extraction
This page contains the full source code of the Praytic/youtd2 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 3046 files (5.3 MB), approximately 1.6M tokens, and a symbol index with 23 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.