Full Code of OpenDiablo2/OpenDiablo2 for AI

master 7f92c571bf04 cached
649 files
3.6 MB
969.4k tokens
5639 symbols
1 requests
Download .txt
Showing preview only (3,865K chars total). Download the full file or copy to clipboard to get everything.
Repository: OpenDiablo2/OpenDiablo2
Branch: master
Commit: 7f92c571bf04
Files: 649
Total size: 3.6 MB

Directory structure:
gitextract_unj84ffm/

├── .circleci/
│   └── config.yml
├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── dependabot.yml
│   └── workflows/
│       └── auto-author-assign.yml
├── .gitignore
├── .golangci.yml
├── .vscode/
│   └── extensions.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTORS
├── LICENSE
├── README.md
├── build.sh
├── d2app/
│   ├── app.go
│   ├── capture_state.go
│   ├── console_commands.go
│   └── initialization.go
├── d2common/
│   ├── d2cache/
│   │   ├── cache.go
│   │   ├── cache_test.go
│   │   └── doc.go
│   ├── d2calculation/
│   │   ├── calcstring.go
│   │   ├── calculation.go
│   │   ├── d2lexer/
│   │   │   ├── lexer.go
│   │   │   └── lexer_test.go
│   │   └── d2parser/
│   │       ├── d2parser.go
│   │       ├── operations.go
│   │       ├── parser.go
│   │       └── parser_test.go
│   ├── d2data/
│   │   ├── d2compression/
│   │   │   ├── huffman.go
│   │   │   └── wav.go
│   │   ├── d2video/
│   │   │   ├── binkdecoder.go
│   │   │   └── doc.go
│   │   └── doc.go
│   ├── d2datautils/
│   │   ├── bitmuncher.go
│   │   ├── bitmuncher_test.go
│   │   ├── bitstream.go
│   │   ├── bitstream_test.go
│   │   ├── doc.go
│   │   ├── stream_reader.go
│   │   ├── stream_reader_test.go
│   │   ├── stream_writer.go
│   │   └── stream_writer_test.go
│   ├── d2enum/
│   │   ├── animation_frame.go
│   │   ├── animation_frame_direction.go
│   │   ├── animation_frame_event.go
│   │   ├── composite_type.go
│   │   ├── composite_type_string.go
│   │   ├── difficulty.go
│   │   ├── doc.go
│   │   ├── draw_effect.go
│   │   ├── encoding_type.go
│   │   ├── equipped_slot.go
│   │   ├── filter.go
│   │   ├── game_event.go
│   │   ├── hero.go
│   │   ├── hero_stance.go
│   │   ├── hero_string.go
│   │   ├── hero_string2enum.go
│   │   ├── input_button.go
│   │   ├── input_key.go
│   │   ├── input_priority.go
│   │   ├── inventory_item_type.go
│   │   ├── item_affix_type.go
│   │   ├── item_armor_class.go
│   │   ├── item_event_functions.go
│   │   ├── item_events.go
│   │   ├── item_quality.go
│   │   ├── level_generation_types.go
│   │   ├── level_teleport_flags.go
│   │   ├── monster_alignment_type.go
│   │   ├── monster_animation_mode.go
│   │   ├── monster_animation_mode_string.go
│   │   ├── monster_combat_type.go
│   │   ├── monumod_const_index.go
│   │   ├── npc_action_type.go
│   │   ├── numeric_labels.go
│   │   ├── object_animation_mode.go
│   │   ├── object_animation_mode_string.go
│   │   ├── object_animation_mode_string2enum.go
│   │   ├── object_type.go
│   │   ├── operator_type.go
│   │   ├── party_buttons.go
│   │   ├── pet_icon_type.go
│   │   ├── player_animation_mode.go
│   │   ├── player_animation_mode_string.go
│   │   ├── players_relationships.go
│   │   ├── quests.go
│   │   ├── readme.md
│   │   ├── region_id.go
│   │   ├── region_layer.go
│   │   ├── render_type.go
│   │   ├── skill_class.go
│   │   ├── terminal_category.go
│   │   ├── tile.go
│   │   ├── weapon_class.go
│   │   ├── weapon_class_string.go
│   │   └── weapon_class_string2enum.go
│   ├── d2fileformats/
│   │   ├── d2animdata/
│   │   │   ├── animdata.go
│   │   │   ├── animdata_test.go
│   │   │   ├── block.go
│   │   │   ├── doc.go
│   │   │   ├── events.go
│   │   │   ├── hash.go
│   │   │   ├── record.go
│   │   │   └── testdata/
│   │   │       ├── AnimData.d2
│   │   │       └── BadData.d2
│   │   ├── d2cof/
│   │   │   ├── cof.go
│   │   │   ├── cof_dir_lookup.go
│   │   │   ├── cof_layer.go
│   │   │   ├── cof_test.go
│   │   │   ├── doc.go
│   │   │   └── helpers.go
│   │   ├── d2dat/
│   │   │   ├── dat.go
│   │   │   ├── dat_color.go
│   │   │   ├── dat_palette.go
│   │   │   └── doc.go
│   │   ├── d2dc6/
│   │   │   ├── dc6.go
│   │   │   ├── dc6.ksy
│   │   │   ├── dc6_frame.go
│   │   │   ├── dc6_frame_header.go
│   │   │   ├── dc6_header.go
│   │   │   ├── dc6_test.go
│   │   │   └── doc.go
│   │   ├── d2dcc/
│   │   │   ├── dcc.go
│   │   │   ├── dcc_cell.go
│   │   │   ├── dcc_dir_lookup.go
│   │   │   ├── dcc_direction.go
│   │   │   ├── dcc_direction_frame.go
│   │   │   ├── dcc_pixel_buffer_entry.go
│   │   │   └── doc.go
│   │   ├── d2ds1/
│   │   │   ├── doc.go
│   │   │   ├── ds1.go
│   │   │   ├── ds1_layers.go
│   │   │   ├── ds1_layers_test.go
│   │   │   ├── ds1_test.go
│   │   │   ├── ds1_version.go
│   │   │   ├── layer.go
│   │   │   ├── layer_test.go
│   │   │   ├── object.go
│   │   │   ├── substitution_group.go
│   │   │   └── tile.go
│   │   ├── d2dt1/
│   │   │   ├── block.go
│   │   │   ├── doc.go
│   │   │   ├── dt1.go
│   │   │   ├── gfx_decode.go
│   │   │   ├── material.go
│   │   │   ├── subtile.go
│   │   │   ├── subtile_test.go
│   │   │   └── tile.go
│   │   ├── d2font/
│   │   │   ├── d2fontglyph/
│   │   │   │   └── font_glyph.go
│   │   │   ├── doc.go
│   │   │   └── font.go
│   │   ├── d2mpq/
│   │   │   ├── crypto.go
│   │   │   ├── doc.go
│   │   │   ├── mpq.go
│   │   │   ├── mpq_block.go
│   │   │   ├── mpq_data_stream.go
│   │   │   ├── mpq_file_record.go
│   │   │   ├── mpq_hash.go
│   │   │   ├── mpq_header.go
│   │   │   └── mpq_stream.go
│   │   ├── d2pl2/
│   │   │   ├── doc.go
│   │   │   ├── pl2.go
│   │   │   ├── pl2_color.go
│   │   │   ├── pl2_color_24bits.go
│   │   │   ├── pl2_palette.go
│   │   │   ├── pl2_palette_transform.go
│   │   │   └── pl2_test.go
│   │   ├── d2tbl/
│   │   │   ├── doc.go
│   │   │   ├── text_dictionary.go
│   │   │   └── text_dictionary_test.go
│   │   └── d2txt/
│   │       ├── data_dictionary.go
│   │       └── doc.go
│   ├── d2geom/
│   │   ├── doc.go
│   │   ├── point.go
│   │   ├── rectangle.go
│   │   └── size.go
│   ├── d2interface/
│   │   ├── animation.go
│   │   ├── archive.go
│   │   ├── audio_provider.go
│   │   ├── cache.go
│   │   ├── data_stream.go
│   │   ├── doc.go
│   │   ├── input_events.go
│   │   ├── input_handlers.go
│   │   ├── input_manager.go
│   │   ├── input_service.go
│   │   ├── map_entity.go
│   │   ├── navigate.go
│   │   ├── palette.go
│   │   ├── renderer.go
│   │   ├── sound_effect.go
│   │   ├── surface.go
│   │   └── terminal.go
│   ├── d2loader/
│   │   ├── asset/
│   │   │   ├── asset.go
│   │   │   ├── doc.go
│   │   │   ├── source.go
│   │   │   └── types/
│   │   │       ├── asset_types.go
│   │   │       ├── doc.go
│   │   │       └── source_types.go
│   │   ├── doc.go
│   │   ├── filesystem/
│   │   │   ├── asset.go
│   │   │   ├── doc.go
│   │   │   ├── loader_provider.go
│   │   │   └── source.go
│   │   ├── loader.go
│   │   ├── loader_test.go
│   │   ├── mpq/
│   │   │   ├── asset.go
│   │   │   ├── doc.go
│   │   │   └── source.go
│   │   └── testdata/
│   │       ├── A/
│   │       │   ├── common.txt
│   │       │   └── exclusive_a.txt
│   │       ├── B/
│   │       │   ├── common.txt
│   │       │   └── exclusive_b.txt
│   │       ├── C/
│   │       │   ├── common.txt
│   │       │   └── exclusive_c.txt
│   │       └── D.mpq
│   ├── d2math/
│   │   ├── d2vector/
│   │   │   ├── doc.go
│   │   │   ├── position.go
│   │   │   ├── position_test.go
│   │   │   ├── vector.go
│   │   │   └── vector_test.go
│   │   ├── doc.go
│   │   ├── math.go
│   │   ├── math_test.go
│   │   ├── ranged_number.go
│   │   └── ranged_number_test.go
│   ├── d2path/
│   │   ├── doc.go
│   │   └── path.go
│   ├── d2resource/
│   │   ├── doc.go
│   │   ├── languages_map.go
│   │   ├── music_defs.go
│   │   └── resource_paths.go
│   ├── d2util/
│   │   ├── assets/
│   │   │   ├── assets.go
│   │   │   └── zipbmp.go
│   │   ├── debug_print.go
│   │   ├── doc.go
│   │   ├── logger.go
│   │   ├── logger_test.go
│   │   ├── palette.go
│   │   ├── rgba_color.go
│   │   ├── stringutils.go
│   │   └── timeutils.go
│   └── doc.go
├── d2core/
│   ├── d2asset/
│   │   ├── animation.go
│   │   ├── asset_manager.go
│   │   ├── composite.go
│   │   ├── d2asset.go
│   │   ├── dc6_animation.go
│   │   ├── dcc_animation.go
│   │   └── doc.go
│   ├── d2audio/
│   │   ├── doc.go
│   │   ├── ebiten/
│   │   │   ├── ebiten_audio_provider.go
│   │   │   └── ebiten_sound_effect.go
│   │   ├── sound_engine.go
│   │   └── sound_environment.go
│   ├── d2config/
│   │   ├── d2config.go
│   │   ├── default_directories.go
│   │   ├── defaults.go
│   │   └── doc.go
│   ├── d2gui/
│   │   ├── box.go
│   │   ├── button.go
│   │   ├── common.go
│   │   ├── doc.go
│   │   ├── gui_manager.go
│   │   ├── label.go
│   │   ├── label_button.go
│   │   ├── layout.go
│   │   ├── layout_entry.go
│   │   ├── layout_scrollbar.go
│   │   ├── spacer.go
│   │   ├── sprite.go
│   │   ├── style.go
│   │   └── widget.go
│   ├── d2hero/
│   │   ├── doc.go
│   │   ├── hero_skill.go
│   │   ├── hero_skill_util.go
│   │   ├── hero_state.go
│   │   ├── hero_state_factory.go
│   │   └── hero_stats_state.go
│   ├── d2input/
│   │   ├── d2input.go
│   │   ├── doc.go
│   │   ├── ebiten/
│   │   │   └── ebiten_input.go
│   │   ├── handler_event.go
│   │   ├── input_manager.go
│   │   ├── key_event.go
│   │   ├── keychars_event.go
│   │   ├── mouse_event.go
│   │   └── mousemove_event.go
│   ├── d2inventory/
│   │   ├── character_equipment.go
│   │   ├── doc.go
│   │   ├── hero_objects.go
│   │   ├── inventory_item.go
│   │   ├── inventory_item_armor.go
│   │   ├── inventory_item_factory.go
│   │   ├── inventory_item_misc.go
│   │   └── inventory_item_weapon.go
│   ├── d2item/
│   │   ├── context.go
│   │   ├── diablo2item/
│   │   │   ├── doc.go
│   │   │   ├── item.go
│   │   │   ├── item_factory.go
│   │   │   ├── item_property.go
│   │   │   └── item_property_test.go
│   │   ├── doc.go
│   │   ├── equipper.go
│   │   └── item.go
│   ├── d2map/
│   │   ├── d2mapengine/
│   │   │   ├── doc.go
│   │   │   ├── engine.go
│   │   │   ├── map_tile.go
│   │   │   └── pathfind.go
│   │   ├── d2mapentity/
│   │   │   ├── animated_entity.go
│   │   │   ├── cast_overlay.go
│   │   │   ├── doc.go
│   │   │   ├── factory.go
│   │   │   ├── item.go
│   │   │   ├── map_entity.go
│   │   │   ├── map_entity_test.go
│   │   │   ├── missile.go
│   │   │   ├── npc.go
│   │   │   ├── object.go
│   │   │   ├── object_init.go
│   │   │   └── player.go
│   │   ├── d2mapgen/
│   │   │   ├── act1_overworld.go
│   │   │   ├── d2wilderness/
│   │   │   │   └── wilderness_tile_types.go
│   │   │   ├── doc.go
│   │   │   └── map_generator.go
│   │   ├── d2maprenderer/
│   │   │   ├── camera.go
│   │   │   ├── doc.go
│   │   │   ├── renderer.go
│   │   │   ├── tile_cache.go
│   │   │   └── viewport.go
│   │   └── d2mapstamp/
│   │       ├── doc.go
│   │       ├── factory.go
│   │       └── stamp.go
│   ├── d2records/
│   │   ├── armor_type_loader.go
│   │   ├── armor_type_record.go
│   │   ├── automagic_loader.go
│   │   ├── automagic_record.go
│   │   ├── automap_loader.go
│   │   ├── automap_record.go
│   │   ├── belts_loader.go
│   │   ├── belts_record.go
│   │   ├── body_locations_loader.go
│   │   ├── body_locations_record.go
│   │   ├── books_loader.go
│   │   ├── books_record.go
│   │   ├── calculations_loader.go
│   │   ├── calculations_record.go
│   │   ├── charstats_loader.go
│   │   ├── charstats_record.go
│   │   ├── color_loader.go
│   │   ├── color_record.go
│   │   ├── component_codes_loader.go
│   │   ├── component_codes_record.go
│   │   ├── composite_type_loader.go
│   │   ├── composite_type_record.go
│   │   ├── constants.go
│   │   ├── cube_modifier_loader.go
│   │   ├── cube_modifier_record.go
│   │   ├── cube_type_loader.go
│   │   ├── cube_type_record.go
│   │   ├── cubemain_loader.go
│   │   ├── cubemain_record.go
│   │   ├── difficultylevels_loader.go
│   │   ├── difficultylevels_record.go
│   │   ├── doc.go
│   │   ├── elemtype_loader.go
│   │   ├── elemtype_record.go
│   │   ├── events_loader.go
│   │   ├── events_record.go
│   │   ├── experience_loader.go
│   │   ├── experience_record.go
│   │   ├── gamble_loader.go
│   │   ├── gamble_record.go
│   │   ├── gems_loader.go
│   │   ├── gems_record.go
│   │   ├── hireling_description_loader.go
│   │   ├── hireling_description_record.go
│   │   ├── hireling_loader.go
│   │   ├── hireling_record.go
│   │   ├── hit_class_loader.go
│   │   ├── hit_class_record.go
│   │   ├── inventory_loader.go
│   │   ├── inventory_record.go
│   │   ├── item_affix_loader.go
│   │   ├── item_affix_record.go
│   │   ├── item_armor_loader.go
│   │   ├── item_common_loader.go
│   │   ├── item_common_record.go
│   │   ├── item_low_quality_loader.go
│   │   ├── item_low_quality_record.go
│   │   ├── item_misc_loader.go
│   │   ├── item_quality_loader.go
│   │   ├── item_quality_record.go
│   │   ├── item_ratio_loader.go
│   │   ├── item_ratio_record.go
│   │   ├── item_types_loader.go
│   │   ├── item_types_record.go
│   │   ├── item_weapons_loader.go
│   │   ├── itemstatcost_loader.go
│   │   ├── itemstatcost_record.go
│   │   ├── level_details_loader.go
│   │   ├── level_details_record.go
│   │   ├── level_maze_loader.go
│   │   ├── level_maze_record.go
│   │   ├── level_presets_loader.go
│   │   ├── level_presets_record.go
│   │   ├── level_substitutions_loader.go
│   │   ├── level_substitutions_record.go
│   │   ├── level_types_loader.go
│   │   ├── level_types_record.go
│   │   ├── level_warp_loader.go
│   │   ├── level_warp_record.go
│   │   ├── missiles_loader.go
│   │   ├── missiles_record.go
│   │   ├── monster_ai_loader.go
│   │   ├── monster_ai_record.go
│   │   ├── monster_equipment_loader.go
│   │   ├── monster_equipment_record.go
│   │   ├── monster_levels_loader.go
│   │   ├── monster_levels_record.go
│   │   ├── monster_mode_loader.go
│   │   ├── monster_mode_record.go
│   │   ├── monster_placement_loader.go
│   │   ├── monster_placement_record.go
│   │   ├── monster_preset_loader.go
│   │   ├── monster_preset_record.go
│   │   ├── monster_property_loader.go
│   │   ├── monster_property_record.go
│   │   ├── monster_sequence_loader.go
│   │   ├── monster_sequence_record.go
│   │   ├── monster_sound_loader.go
│   │   ├── monster_sound_record.go
│   │   ├── monster_stats2_loader.go
│   │   ├── monster_stats2_record.go
│   │   ├── monster_stats_loader.go
│   │   ├── monster_stats_record.go
│   │   ├── monster_super_unique_loader.go
│   │   ├── monster_super_unique_record.go
│   │   ├── monster_type_loader.go
│   │   ├── monster_type_record.go
│   │   ├── monster_unique_affix_loader.go
│   │   ├── monster_unique_affix_record.go
│   │   ├── monster_unique_modifiers_loader.go
│   │   ├── monster_unique_modifiers_record.go
│   │   ├── npc_loader.go
│   │   ├── npc_record.go
│   │   ├── object_details_loader.go
│   │   ├── object_details_record.go
│   │   ├── object_groups_loader.go
│   │   ├── object_groups_record.go
│   │   ├── object_lookup_record.go
│   │   ├── object_lookup_record_data.go
│   │   ├── object_lookup_record_test.go
│   │   ├── object_mode_loader.go
│   │   ├── object_mode_record.go
│   │   ├── object_types_loader.go
│   │   ├── object_types_record.go
│   │   ├── overlays_loader.go
│   │   ├── overlays_record.go
│   │   ├── pet_type_loader.go
│   │   ├── pet_type_record.go
│   │   ├── player_class_loader.go
│   │   ├── player_class_record.go
│   │   ├── player_mode_loader.go
│   │   ├── player_mode_record.go
│   │   ├── player_type_loader.go
│   │   ├── player_type_record.go
│   │   ├── property_descriptor.go
│   │   ├── property_loader.go
│   │   ├── property_record.go
│   │   ├── rare_affix.go
│   │   ├── rare_affix_loader.go
│   │   ├── rare_prefix_loader.go
│   │   ├── rare_prefix_record.go
│   │   ├── rare_suffix_loader.go
│   │   ├── rare_suffix_record.go
│   │   ├── record_loader.go
│   │   ├── record_manager.go
│   │   ├── runeword_loader.go
│   │   ├── runeword_record.go
│   │   ├── set_item_loader.go
│   │   ├── set_item_record.go
│   │   ├── set_loader.go
│   │   ├── set_record.go
│   │   ├── shrine_loader.go
│   │   ├── shrine_record.go
│   │   ├── skill_description_loader.go
│   │   ├── skill_description_record.go
│   │   ├── skill_details_loader.go
│   │   ├── skill_details_record.go
│   │   ├── sound_details_loader.go
│   │   ├── sound_details_record.go
│   │   ├── sound_environment_loader.go
│   │   ├── sound_environment_record.go
│   │   ├── states_loader.go
│   │   ├── states_record.go
│   │   ├── storepage_loader.go
│   │   ├── storepage_record.go
│   │   ├── treasure_class_loader.go
│   │   ├── treasure_class_record.go
│   │   ├── unique_appellation_loader.go
│   │   ├── unique_appellations_record.go
│   │   ├── unique_items_loader.go
│   │   ├── unique_items_record.go
│   │   ├── weapon_class_loader.go
│   │   └── weapon_class_record.go
│   ├── d2render/
│   │   └── ebiten/
│   │       ├── doc.go
│   │       ├── ebiten_panic_screen.go
│   │       ├── ebiten_renderer.go
│   │       ├── ebiten_surface.go
│   │       ├── filter_helper.go
│   │       └── surface_state.go
│   ├── d2screen/
│   │   ├── d2screen.go
│   │   ├── doc.go
│   │   ├── loading_state.go
│   │   ├── loading_update.go
│   │   └── screen_manager.go
│   ├── d2stats/
│   │   ├── diablo2stats/
│   │   │   ├── doc.go
│   │   │   ├── stat.go
│   │   │   ├── stat_factory.go
│   │   │   ├── stat_test.go
│   │   │   ├── stat_value.go
│   │   │   ├── stat_value_stringers.go
│   │   │   ├── statlist.go
│   │   │   └── statlist_test.go
│   │   ├── doc.go
│   │   ├── stat.go
│   │   ├── stat_list.go
│   │   └── stat_value.go
│   ├── d2term/
│   │   ├── commmand.go
│   │   ├── d2term.go
│   │   ├── doc.go
│   │   ├── terminal.go
│   │   ├── terminal_logger.go
│   │   └── terminal_test.go
│   └── d2ui/
│       ├── button.go
│       ├── checkbox.go
│       ├── color_tokens.go
│       ├── custom_widget.go
│       ├── d2ui.go
│       ├── doc.go
│       ├── drawable.go
│       ├── frame.go
│       ├── label.go
│       ├── label_button.go
│       ├── scrollbar.go
│       ├── sprite.go
│       ├── switchable_button.go
│       ├── textbox.go
│       ├── tooltip.go
│       ├── ui_manager.go
│       ├── widget.go
│       └── widget_group.go
├── d2game/
│   ├── d2gamescreen/
│   │   ├── blizzard_intro.go
│   │   ├── character_select.go
│   │   ├── cinematics.go
│   │   ├── credits.go
│   │   ├── doc.go
│   │   ├── game.go
│   │   ├── gui_testing.go
│   │   ├── main_menu.go
│   │   ├── map_engine_testing.go
│   │   └── select_hero_class.go
│   └── d2player/
│       ├── binding_layout.go
│       ├── doc.go
│       ├── equipment_slot.go
│       ├── escape_menu.go
│       ├── game_controls.go
│       ├── globeWidget.go
│       ├── help_overlay.go
│       ├── hero_stats_panel.go
│       ├── hud.go
│       ├── input_callback_listener.go
│       ├── inventory.go
│       ├── inventory_grid.go
│       ├── key_binding_menu.go
│       ├── key_map.go
│       ├── mini_panel.go
│       ├── move_gold_panel.go
│       ├── party_panel.go
│       ├── quest_log.go
│       ├── skill_row.go
│       ├── skill_select_menu.go
│       ├── skill_select_panel.go
│       ├── skillicon.go
│       └── skilltree.go
├── d2networking/
│   ├── client_listener.go
│   ├── d2client/
│   │   ├── d2clientconnectiontype/
│   │   │   ├── connectiontype.go
│   │   │   └── doc.go
│   │   ├── d2localclient/
│   │   │   ├── doc.go
│   │   │   └── local_client_connection.go
│   │   ├── d2remoteclient/
│   │   │   ├── doc.go
│   │   │   └── remote_client_connection.go
│   │   ├── doc.go
│   │   ├── game_client.go
│   │   └── server_connection.go
│   ├── d2netpacket/
│   │   ├── d2netpackettype/
│   │   │   ├── doc.go
│   │   │   └── message_type.go
│   │   ├── doc.go
│   │   ├── net_packet.go
│   │   ├── packet_add_player.go
│   │   ├── packet_generate_map.go
│   │   ├── packet_item_spawn.go
│   │   ├── packet_move_player.go
│   │   ├── packet_ping.go
│   │   ├── packet_player_cast.go
│   │   ├── packet_player_connection_request.go
│   │   ├── packet_player_disconnect_request.go
│   │   ├── packet_pong.go
│   │   ├── packet_save_player.go
│   │   ├── packet_server_closed.go
│   │   ├── packet_server_full.go
│   │   └── packet_update_server_info.go
│   ├── d2server/
│   │   ├── client_connection.go
│   │   ├── d2tcpclientconnection/
│   │   │   └── tcp_client_connection.go
│   │   ├── d2udpclientconnection/
│   │   │   └── udp_client_connection.go
│   │   ├── doc.go
│   │   └── game_server.go
│   ├── dedicated_server.go
│   └── doc.go
├── d2script/
│   ├── doc.go
│   └── engine.go
├── d2thread/
│   └── mainthread.go
├── docs/
│   ├── CNAME
│   ├── CONTRIBUTING.md
│   ├── building.md
│   ├── debug.md
│   ├── development.md
│   ├── faq.md
│   ├── index.html
│   ├── install.md
│   ├── mpq.md
│   ├── play.md
│   ├── profiling.md
│   ├── purchase.md
│   ├── roadmap.md
│   ├── status.md
│   └── style.css
├── go.mod
├── go.sum
├── main.go
├── scripts/
│   ├── server/
│   │   └── server.js
│   └── test.js
├── tagdev.bat
└── utils/
    └── extract-mpq/
        ├── doc.go
        └── extract-mpq.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .circleci/config.yml
================================================
# Golang CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-go/ for more details
version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.16
    working_directory: /go/src/github.com/{{ORG_NAME}}/{{REPO_NAME}}
    steps:
      - checkout
      - run: sudo apt-get --allow-releaseinfo-change update && sudo apt-get install -y libgtk-3-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libgl1-mesa-dev libsdl2-dev libasound2-dev > /dev/null 2>&1
      - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
      - run: go get -v -t -d ./...
      - run: go build .
      - run: xvfb-run --auto-servernum go test -v -race ./...
      - run: golangci-lint run ./...
workflows:
  version: 2
  build:
    jobs:
      - build


================================================
FILE: .editorconfig
================================================
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = tab
indent_size = 4


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

patreon: essial


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Version [e.g. 22]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"


================================================
FILE: .github/workflows/auto-author-assign.yml
================================================
name: 'Auto Author Assign'

on:
    pull_request_target:
        types: [opened, reopened]

jobs:
    assign-author:
        runs-on: ubuntu-latest
        steps:
            - uses: toshimaru/auto-author-assign@v1.3.0
              with:
                  repo-token: "${{ secrets.GITHUB_TOKEN }}"


================================================
FILE: .gitignore
================================================
**/*__debug_bin
.vscode/**/*
!.vscode/extensions.json
**/Client.exe
**/Client
.idea/**/*
.vs/**/*
/OpenDiablo2.exe
/OpenDiablo2
**/*.pprof
*.swp
.*.swp
tags
heap.out
heap.pdf
.DS_Store


================================================
FILE: .golangci.yml
================================================
---
linters-settings:
  dupl:
    threshold: 100
  funlen:
    lines: 100
    statements: 50
  goconst:
    min-len: 2
    min-occurrences: 2
  gocritic:
    enabled-tags:
      - diagnostic
      - experimental
      - opinionated
      - performance
      - style
    disabled-checks:
  gocyclo:
    min-complexity: 15
  gofmt:
    simplify: true
  goimports:
    local-prefixes: github.com/OpenDiablo2/OpenDiablo2
  golint:
    min-confidence: 0.8
  govet:
    enable-all: true
    check-shadowing: true
    disable:
      # While struct sizes could be smaller if fields aligned properly, that also leads
      # to possibly non-intuitive layout of struct fields (harder to read). Disable
      # `fieldalignment` check here until we evaluate if it is worthwhile.
      - fieldalignment
      # https://github.com/golangci/golangci-lint/issues/1973
      - sigchanyzer
  lll:
    line-length: 140
  misspell:
    locale: US

linters:
  disable-all: true
  enable:
    - bodyclose
    - deadcode
    - depguard
    - dogsled
    - dupl
    - errcheck
    - funlen
    - gochecknoglobals
    - gochecknoinits
    - gocognit
    - goconst
    - gocritic
    - gocyclo
    - godox
    - gofmt
    - goimports
    - golint
    - gomnd
    - goprintffuncname
    - gosec
    - gosimple
    - govet
    - ineffassign
    - lll
    - misspell
    - nakedret
    - prealloc
    - rowserrcheck
    - staticcheck
    - structcheck
    - stylecheck
    - typecheck
    - unconvert
    - unparam
    - unused
    - varcheck
    - whitespace
    - wsl

run:
  timeout: 5m
  tests: true
  skip-dirs:
    - .github
    - build
    - web

issues:
  exclude-rules:
    - linters:
        - funlen
      # Disable 'funlen' linter for test functions.
      # It's common for table-driven tests to be more than 60 characters long
      source: "^func Test"
  max-issues-per-linter: 0
  max-same-issues: 0
  exclude-use-default: false


================================================
FILE: .vscode/extensions.json
================================================
{
    "recommendations": [
        "golang.go",
        "soren.go-coverage-viewer"
    ]
}


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
 advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
 address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
 professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers 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, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at tim.sarbin@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq


================================================
FILE: CONTRIBUTORS
================================================
* OPEN DIABLO 2
Tim "essial" Sarbin
ndechiara
mewmew
grazz
Erexo
Ziemas
liberodark
cardoso
Mirey
Lectem
wtfblub
q3cpma
averrin
Dylan "Gravestench" Knuth
Intyre
Gürkan Kaymak
Maxime "malavv" Lavigne
Ripolak
dafe
presiyan
Natureknight
Ganitzsh

* PATREON SUPPORTERS
K C
Blixt
Dylan Knuth
Brendan Porter
Frazier Phillips

* DIABLO2 LOGO
Jose Pardilla (th3-prophetman)

* DT1 File Specifications
Paul SIRAMY

* Other Specifications and general info
Various users on Phrozen Keep


================================================
FILE: LICENSE
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.


================================================
FILE: README.md
================================================
# NOTE 
<image align="left" src="https://user-images.githubusercontent.com/242652/138285004-b27d55b3-163b-4fe3-a8ff-6c34518044bd.png">
This project is currently being split into an Engine+Toolset (called Abyss Engine) and the game as a project (still called OpenDiablo 2). The new project repo is located here:
<br /><br />
https://github.com/AbyssEngine/

<br clear="all" />

# OpenDiablo2

![CircleCI](https://img.shields.io/circleci/build/github/OpenDiablo2/OpenDiablo2/master)
[![Go Report Card](https://goreportcard.com/badge/github.com/OpenDiablo2/OpenDiablo2)](https://goreportcard.com/report/github.com/OpenDiablo2/OpenDiablo2)
[![GoDoc](https://pkg.go.dev/badge/github.com/OpenDiablo2/OpenDiablo2?utm_source=godoc)](https://pkg.go.dev/mod/github.com/OpenDiablo2/OpenDiablo2)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Discord](https://img.shields.io/discord/515518620034662421?label=Discord&style=social)](https://discord.gg/pRy8tdc)
[![Twitch Status](https://img.shields.io/twitch/status/essial?style=social)](https://www.twitch.tv/essial)
[![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/OpenDiablo2?label=reddit&style=social)](https://www.reddit.com/r/OpenDiablo2/)


![Logo](d2logo.png)

[![Patreon](https://img.shields.io/badge/dynamic/json?color=%23e85b46&label=Support%20us%20on%20Patreon&query=data.attributes.patron_count&suffix=%20patrons&url=https://www.patreon.com/api/campaigns/4762180)](https://www.patreon.com/bePatron?u=37261055)

----
[OpenDiablo2](https://opendiablo2.com/) is an ARPG game engine in the same vein of the 2000's games, and supports playing Diablo 2.

The engine is written in Go and is cross platform.

> The project does not ship with the assets or content required to play Diablo 2.
You must have a legally purchased copy of [Diablo 2](https://us.shop.battle.net/en-us/product/diablo-ii) and its expansion [Lord of Destruction](https://us.shop.battle.net/en-us/product/diablo-ii-lord-of-destruction) installed on your computer in order to run that game on this engine.

If you like to contribute to OpenDiablo2, please be so kind to read our [Contribution Policy](./docs/CONTRIBUTING.md) first.

----

## Documentation

_Stay awhile and listen_ ...

### ⚡ Project Info

* 👉 **[Current Status](./docs/status.md)** 👈 - what you should focus on
* [Roadmap](./docs/roadmap.md) - Planning ahead
* Design - High-level overview of the OpenDiablo2 org and its projects
* [FAQ](./docs/faq.md) - Common questions from new people to the project

### ⭐ For Users

* [Purchase](./docs/purchase.md) - Buy the official game from Blizzard
* [MPQ](./docs/mpq.md) - Locate the MPQ files
* [Install](./docs/install.md) - Install OpenDiablo2 to your system (Linux/Windows/MacOS)
* [Run it](./docs/play.md) - How to play the game

### 🔥 For Developers

* [Building](./docs/building.md) - Instructions for building the project
* [Development](./docs/development.md) - Instructions for developers who want to contribute
* [Profiling](./docs/profiling.md) - Debug performance issues
* [Debugging](./docs/debug.md) - Common errors and pitfalls

## Screenshots

![Main Menu](docs/MainMenuSS.png)

![Select Hero](docs/SelectHeroSS.png)

![Select Hero](docs/areas.gif)

![Gameplay](docs/Gameplay.png)

![Inventory Window](docs/Inventory.png)

![Game Panels](docs/game_panels.png)

## Additional Credits

*   Diablo2 Logo
    *   Jose Pardilla (th3-prophetman)
*   DT1 File Specifications
    *   Paul SIRAMY (http://paul.siramy.free.fr/\_divers/dt1\_doc/)
*   Other Specifications and general info
    *   Various users on [Phrozen Keep](https://d2mods.info/home.php)

## Legal Notice

Please note that **this game is neither developed by, nor endorsed by Blizzard or its parent company Activision**.

Diablo 2 and its content is ©2000 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries.

ALL OTHER TRADEMARKS ARE THE PROPERTY OF THEIR RESPECTIVE OWNERS.


================================================
FILE: build.sh
================================================
#!/bin/bash
#
# About: Build OpenDiablo 2 automatically
# Author: liberodark
# License: GNU GPLv3

version="0.0.8"
go_version="1.16"
echo "OpenDiablo 2 Build Script $version"

#=================================================
# RETRIEVE ARGUMENTS FROM THE MANIFEST AND VAR
#=================================================
export PATH=$PATH:/usr/local/go/bin

distribution=$(cat /etc/*release | grep "PRETTY_NAME" | sed 's/PRETTY_NAME=//g' | sed 's/["]//g' | awk '{print $1}')

go_install() {
	# Check OS & go

	if ! command -v go >/dev/null 2>&1; then

		echo "Install Go for OpenDiablo 2 ($distribution)? y/n"
		read -r choice
		[ "$choice" != y ] && [ "$choice" != Y ] && exit

		if [ "$distribution" = "CentOS" ] || [ "$distribution" = "Red\ Hat" ] || [ "$distribution" = "Oracle" ]; then
			echo "Downloading Go"
			wget https://dl.google.com/go/go"$go_version".linux-amd64.tar.gz >/dev/null 2>&1
			echo "Install Go"
			sudo tar -C /usr/local -xzf go*.linux-amd64.tar.gz >/dev/null 2>&1
			echo "Clean unneeded files"
			rm go*.linux-amd64.tar.gz

		elif [ "$distribution" = "Fedora" ]; then
			echo "Downloading Go"
			wget https://dl.google.com/go/go"$go_version".linux-amd64.tar.gz >/dev/null 2>&1
			echo "Install Go"
			sudo tar -C /usr/local -xzf go*.linux-amd64.tar.gz >/dev/null 2>&1
			echo "Clean unneeded files"
			rm go*.linux-amd64.tar.gz

		elif [ "$distribution" = "Debian" ] || [ "$distribution" = "Ubuntu" ] || [ "$distribution" = "Deepin" ]; then
			echo "Downloading Go"
			wget https://dl.google.com/go/go"$go_version".linux-amd64.tar.gz >/dev/null 2>&1
			echo "Install Go"
			sudo tar -C /usr/local -xzf go*.linux-amd64.tar.gz >/dev/null 2>&1
			echo "Clean unneeded files"
			rm go*.linux-amd64.tar.gz

		elif [ "$distribution" = "Gentoo" ]; then
			sudo emerge --ask n go

		elif [ "$distribution" = "Manjaro" ] || [ "$distribution" = "Arch\ Linux" ]; then
			sudo pacman -S go --noconfirm

		elif [ "$distribution" = "OpenSUSE" ] || [ "$distribution" = "SUSE" ]; then
			echo "Downloading Go"
			wget https://dl.google.com/go/go"$go_version".linux-amd64.tar.gz >/dev/null 2>&1
			echo "Install Go"
			sudo tar -C /usr/local -xzf go*.linux-amd64.tar.gz >/dev/null 2>&1
			echo "Clean unneeded files"
			rm go*.linux-amd64.tar.gz

		fi
	fi
}

dep_install() {
	if [ "$distribution" = "CentOS" ] || [ "$distribution" = "Red\ Hat" ] || [ "$distribution" = "Oracle" ]; then
		sudo yum install -y libX11-devel libXcursor-devel libXrandr-devel libXinerama-devel mesa-libGL-devel alsa-lib-devel libXi-devel >/dev/null 2>&1

	elif [ "$distribution" = "Fedora" ]; then
		sudo dnf install -y libX11-devel libXcursor-devel libXrandr-devel libXinerama-devel mesa-libGL-devel alsa-lib-devel libXi-devel >/dev/null 2>&1

	elif [ "$distribution" = "Debian" ] || [ "$distribution" = "Ubuntu" ] || [ "$distribution" = "Deepin" ]; then
		sudo apt-get install -y libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libgl1-mesa-dev libsdl2-dev libasound2-dev >/dev/null 2>&1

	elif [ "$distribution" = "Gentoo" ]; then
		sudo emerge --ask n libXcursor libXrandr libXinerama libXi libGLw libglvnd libsdl2 alsa-lib >/dev/null 2>&1

	elif [ "$distribution" = "Manjaro" ] || [ "$distribution" = "Arch\ Linux" ]; then
		mesa_detect_arch=$(pacman -Q | grep mesa)

		if [ -z "$mesa_detect_arch" ]; then
			sudo pacman -S libxcursor libxrandr libxinerama libxi mesa libglvnd sdl2 sdl2_mixer sdl2_net alsa-lib --noconfirm >/dev/null 2>&1
		else
			sudo pacman -S libxcursor libxrandr libxinerama libxi libglvnd sdl2 sdl2_mixer sdl2_net alsa-lib --noconfirm >/dev/null 2>&1
		fi

	elif [ "$distribution" = "OpenSUSE" ] || [ "$distribution" = "SUSE" ]; then
		sudo zypper install -y libX11-devel libXcursor-devel libXrandr-devel libXinerama-devel Mesa-libGL-devel alsa-lib-devel libXi-devel >/dev/null 2>&1

	elif [[ "$OSTYPE" == "darwin"* ]]; then
		# are there dependencies required? did I just have all of them already?
		echo "Mac OS detected, no dependency installation necessary..."

	fi
}

# Build
echo "Check Go"
go_install

echo "Install libraries"
if [ ! -e "$HOME/.config/OpenDiablo2" ]; then
	mkdir -p $HOME/.config/OpenDiablo2
fi

if [ -e "$HOME/.config/OpenDiablo2/.libs" ]; then
	echo "libraries is installed"
else
	echo "OK" >"$HOME/.config/OpenDiablo2/.libs"
	dep_install
fi

echo "Build OpenDiablo 2"
go get -d
go build

echo "Build finished. Running OpenDiablo2 will generate a config.json file."
echo "If there are subsequent errors, please inspect and edit the config.json file. See doc/index.html for more details"


================================================
FILE: d2app/app.go
================================================
// Package d2app contains the OpenDiablo2 application shell
package d2app

import (
	"bytes"
	"container/ring"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"image"
	"image/gif"
	"image/png"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"syscall"

	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2loader/asset/types"

	"github.com/pkg/profile"
	"golang.org/x/image/colornames"

	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
	ebiten2 "github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio/ebiten"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render/ebiten"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
	"github.com/OpenDiablo2/OpenDiablo2/d2game/d2gamescreen"
	"github.com/OpenDiablo2/OpenDiablo2/d2networking"
	"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
	"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
	"github.com/OpenDiablo2/OpenDiablo2/d2script"
)

// these are used for debug print info
const (
	fpsX, fpsY         = 5, 565
	memInfoX, memInfoY = 670, 5
	debugLineHeight    = 16
	errMsgPadding      = 20
)

// App represents the main application for the engine
type App struct {
	lastTime          float64
	lastScreenAdvance float64
	showFPS           bool
	timeScale         float64
	captureState      captureState
	capturePath       string
	captureFrames     []*image.RGBA
	gitBranch         string
	gitCommit         string
	language          string
	charset           string
	asset             *d2asset.AssetManager
	inputManager      d2interface.InputManager
	terminal          d2interface.Terminal
	scriptEngine      *d2script.ScriptEngine
	audio             d2interface.AudioProvider
	renderer          d2interface.Renderer
	screen            *d2screen.ScreenManager
	ui                *d2ui.UIManager
	tAllocSamples     *ring.Ring
	guiManager        *d2gui.GuiManager
	config            *d2config.Configuration
	*d2util.Logger
	errorMessage error
	*Options
}

// Options is used to store all of the app options that can be set with arguments
type Options struct {
	Debug    *bool
	profiler *string
	Server   *d2networking.ServerOptions
	LogLevel *d2util.LogLevel
}

const (
	bytesToMegabyte = 1024 * 1024
	nSamplesTAlloc  = 100
	debugPopN       = 6
)

const (
	appLoggerPrefix = "App"
)

// Create creates a new instance of the application
func Create(gitBranch, gitCommit string) *App {
	runtime.LockOSThread()

	logger := d2util.NewLogger()
	logger.SetPrefix(appLoggerPrefix)

	app := &App{
		Logger:    logger,
		gitBranch: gitBranch,
		gitCommit: gitCommit,
		Options: &Options{
			Server: &d2networking.ServerOptions{},
		},
	}
	app.Infof("OpenDiablo2 - Open source Diablo 2 engine")

	app.parseArguments()

	app.SetLevel(*app.Options.LogLevel)

	app.asset, app.errorMessage = d2asset.NewAssetManager(*app.Options.LogLevel)

	return app
}

func updateNOOP() error {
	return nil
}

func (a *App) startDedicatedServer() error {
	min, max := d2networking.ServerMinPlayers, d2networking.ServerMaxPlayersDefault
	maxPlayers := d2math.ClampInt(*a.Options.Server.MaxPlayers, min, max)

	srvChanIn := make(chan int)
	srvChanLog := make(chan string)

	srvErr := d2networking.StartDedicatedServer(a.asset, srvChanIn, srvChanLog, *a.Options.LogLevel, maxPlayers)
	if srvErr != nil {
		return srvErr
	}

	c := make(chan os.Signal)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM) // This traps Control-c to safely shut down the server

	go func() {
		<-c
		srvChanIn <- d2networking.ServerEventStop
	}()

	for {
		for data := range srvChanLog {
			a.Info(data)
		}
	}
}

func (a *App) loadEngine() error {
	// Create our renderer
	renderer, err := ebiten.CreateRenderer(a.config)
	if err != nil {
		return err
	}

	a.renderer = renderer

	if a.errorMessage != nil {
		return a.renderer.Run(a.updateInitError, updateNOOP, 800, 600, "OpenDiablo2")
	}

	audio := ebiten2.CreateAudio(*a.Options.LogLevel, a.asset)

	inputManager := d2input.NewInputManager()

	term, err := d2term.New(inputManager)
	if err != nil {
		return err
	}

	scriptEngine := d2script.CreateScriptEngine()

	uiManager := d2ui.NewUIManager(a.asset, renderer, inputManager, *a.Options.LogLevel, audio)

	a.inputManager = inputManager
	a.terminal = term
	a.scriptEngine = scriptEngine
	a.audio = audio
	a.ui = uiManager
	a.tAllocSamples = createZeroedRing(nSamplesTAlloc)

	return nil
}

func (a *App) parseArguments() {
	const (
		descProfile = "Profiles the program,\none of (cpu, mem, block, goroutine, trace, thread, mutex)"
		descPlayers = "Sets the number of max players for the dedicated server"
		descLogging = "Enables verbose logging. Log levels will include those below it.\n" +
			" 0 disables log messages\n" +
			" 1 shows fatal\n" +
			" 2 shows error\n" +
			" 3 shows warning\n" +
			" 4 shows info\n" +
			" 5 shows debug\n"
	)

	a.Options.profiler = flag.String("profile", "", descProfile)
	a.Options.Server.Dedicated = flag.Bool("dedicated", false, "Starts a dedicated server")
	a.Options.Server.MaxPlayers = flag.Int("players", 0, descPlayers)
	a.Options.LogLevel = flag.Int("l", d2util.LogLevelDefault, descLogging)
	showVersion := flag.Bool("v", false, "Show version")
	showHelp := flag.Bool("h", false, "Show help")

	flag.Usage = func() {
		fmt.Printf("usage: %s [<flags>]\n\nFlags:\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()

	if *a.Options.LogLevel >= d2util.LogLevelUnspecified {
		*a.Options.LogLevel = d2util.LogLevelDefault
	}

	if *showVersion {
		a.Infof("version: OpenDiablo2 (%s %s)", a.gitBranch, a.gitCommit)
		os.Exit(0)
	}

	if *showHelp {
		flag.Usage()
		os.Exit(0)
	}
}

// LoadConfig loads the OpenDiablo2 config file
func (a *App) LoadConfig() (*d2config.Configuration, error) {
	// by now the, the loader has initialized and added our config dirs as sources...
	configBaseName := filepath.Base(d2config.DefaultConfigPath())

	configAsset, _ := a.asset.LoadAsset(configBaseName)

	config := &d2config.Configuration{}
	config.SetPath(d2config.DefaultConfigPath())

	// create the default if not found
	if configAsset == nil {
		config = d2config.DefaultConfig()

		fullPath := filepath.Join(config.Dir(), config.Base())
		config.SetPath(fullPath)

		a.Infof("creating default configuration file at %s...", fullPath)

		saveErr := config.Save()

		return config, saveErr
	}

	if err := json.NewDecoder(configAsset).Decode(config); err != nil {
		return nil, err
	}

	a.Infof("loaded configuration file from %s", config.Path())

	return config, nil
}

// Run executes the application and kicks off the entire game process
func (a *App) Run() (err error) {
	// add our possible config directories
	_ = a.asset.AddSource(filepath.Dir(d2config.LocalConfigPath()), types.AssetSourceFileSystem)
	_ = a.asset.AddSource(filepath.Dir(d2config.DefaultConfigPath()), types.AssetSourceFileSystem)

	if a.config, err = a.LoadConfig(); err != nil {
		return err
	}

	// start profiler if argument was supplied
	if len(*a.Options.profiler) > 0 {
		profiler := enableProfiler(*a.Options.profiler, a)
		if profiler != nil {
			defer profiler.Stop()
		}
	}

	// start the server if `--listen` option was supplied
	if *a.Options.Server.Dedicated {
		if err := a.startDedicatedServer(); err != nil {
			return err
		}
	}

	if err := a.loadEngine(); err != nil {
		a.renderer.ShowPanicScreen(err.Error())
		return err
	}

	windowTitle := fmt.Sprintf("OpenDiablo2 (%s)", a.gitBranch)

	// If we fail to initialize, we will show the error screen
	if err := a.initialize(); err != nil {
		if a.errorMessage == nil {
			a.errorMessage = err // if there was an error during init, don't clobber it
		}

		gameErr := a.renderer.Run(a.updateInitError, updateNOOP, 800, 600, windowTitle)
		if gameErr != nil {
			return gameErr
		}

		return err
	}

	a.ToMainMenu()

	if err := a.renderer.Run(a.update, a.advance, 800, 600, windowTitle); err != nil {
		return err
	}

	return nil
}

func (a *App) renderDebug(target d2interface.Surface) {
	if !a.showFPS {
		return
	}

	vsyncEnabled := a.renderer.GetVSyncEnabled()
	fps := a.renderer.CurrentFPS()
	cx, cy := a.renderer.GetCursorPos()

	target.PushTranslation(fpsX, fpsY)
	target.DrawTextf("vsync:" + strconv.FormatBool(vsyncEnabled) + "\nFPS:" + strconv.Itoa(int(fps)))
	target.Pop()

	var m runtime.MemStats

	runtime.ReadMemStats(&m)
	target.PushTranslation(memInfoX, memInfoY)
	target.DrawTextf("Alloc    " + strconv.FormatInt(int64(m.Alloc)/bytesToMegabyte, 10))
	target.PushTranslation(0, debugLineHeight)
	target.DrawTextf("TAlloc/s " + strconv.FormatFloat(a.allocRate(m.TotalAlloc, fps), 'f', 2, 64))
	target.PushTranslation(0, debugLineHeight)
	target.DrawTextf("Pause    " + strconv.FormatInt(int64(m.PauseTotalNs/bytesToMegabyte), 10))
	target.PushTranslation(0, debugLineHeight)
	target.DrawTextf("HeapSys  " + strconv.FormatInt(int64(m.HeapSys/bytesToMegabyte), 10))
	target.PushTranslation(0, debugLineHeight)
	target.DrawTextf("NumGC    " + strconv.FormatInt(int64(m.NumGC), 10))
	target.PushTranslation(0, debugLineHeight)
	target.DrawTextf("Coords   " + strconv.FormatInt(int64(cx), 10) + "," + strconv.FormatInt(int64(cy), 10))
	target.PopN(debugPopN)
}

func (a *App) renderCapture(target d2interface.Surface) error {
	cleanupCapture := func() {
		a.captureState = captureStateNone
		a.capturePath = ""
		a.captureFrames = nil
	}

	switch a.captureState {
	case captureStateFrame:
		defer cleanupCapture()

		if err := a.doCaptureFrame(target); err != nil {
			return err
		}
	case captureStateGif:
		a.doCaptureGif(target)
	case captureStateNone:
		if len(a.captureFrames) > 0 {
			defer cleanupCapture()

			if err := a.convertFramesToGif(); err != nil {
				return err
			}
		}
	}

	return nil
}

func (a *App) render(target d2interface.Surface) {
	a.screen.Render(target)
	a.ui.Render(target)

	if err := a.guiManager.Render(target); err != nil {
		return
	}

	a.renderDebug(target)

	if err := a.renderCapture(target); err != nil {
		return
	}

	if err := a.terminal.Render(target); err != nil {
		return
	}
}

func (a *App) advance() error {
	current := d2util.Now()
	elapsedUnscaled := current - a.lastTime
	elapsed := elapsedUnscaled * a.timeScale

	a.lastTime = current

	elapsedLastScreenAdvance := (current - a.lastScreenAdvance) * a.timeScale
	a.lastScreenAdvance = current

	if err := a.screen.Advance(elapsedLastScreenAdvance); err != nil {
		return err
	}

	a.ui.Advance(elapsed)

	if err := a.inputManager.Advance(elapsed, current); err != nil {
		return err
	}

	if err := a.guiManager.Advance(elapsed); err != nil {
		return err
	}

	if err := a.terminal.Advance(elapsedUnscaled); err != nil {
		return err
	}

	return nil
}

func (a *App) update(target d2interface.Surface) error {
	a.render(target)

	if target.GetDepth() > 0 {
		return errors.New("detected surface stack leak")
	}

	return nil
}

func (a *App) allocRate(totalAlloc uint64, fps float64) float64 {
	a.tAllocSamples.Value = totalAlloc
	a.tAllocSamples = a.tAllocSamples.Next()
	deltaAllocPerFrame := float64(totalAlloc-a.tAllocSamples.Value.(uint64)) / nSamplesTAlloc

	return deltaAllocPerFrame * fps / bytesToMegabyte
}

func (a *App) doCaptureFrame(target d2interface.Surface) error {
	fp, err := os.Create(a.capturePath)
	if err != nil {
		a.terminal.Errorf("failed to create %q", a.capturePath)
		return err
	}

	screenshot := target.Screenshot()
	if err := png.Encode(fp, screenshot); err != nil {
		return err
	}

	if err := fp.Close(); err != nil {
		a.terminal.Errorf("failed to create %q", a.capturePath)
		return nil
	}

	a.terminal.Infof("saved frame to %s", a.capturePath)

	return nil
}

func (a *App) doCaptureGif(target d2interface.Surface) {
	screenshot := target.Screenshot()
	a.captureFrames = append(a.captureFrames, screenshot)
}

func (a *App) convertFramesToGif() error {
	fp, err := os.Create(a.capturePath)
	if err != nil {
		return err
	}

	defer func() {
		if err := fp.Close(); err != nil {
			a.Fatal(err.Error())
		}
	}()

	var (
		framesTotal  = len(a.captureFrames)
		framesPal    = make([]*image.Paletted, framesTotal)
		frameDelays  = make([]int, framesTotal)
		framesPerCPU = framesTotal / runtime.NumCPU()
	)

	var waitGroup sync.WaitGroup

	for i := 0; i < framesTotal; i += framesPerCPU {
		waitGroup.Add(1)

		go func(start, end int) {
			defer waitGroup.Done()

			for j := start; j < end; j++ {
				var buffer bytes.Buffer
				if err := gif.Encode(&buffer, a.captureFrames[j], nil); err != nil {
					panic(err)
				}

				framePal, err := gif.Decode(&buffer)
				if err != nil {
					panic(err)
				}

				framesPal[j] = framePal.(*image.Paletted)
				frameDelays[j] = 5
			}
		}(i, d2math.MinInt(i+framesPerCPU, framesTotal))
	}

	waitGroup.Wait()

	if err := gif.EncodeAll(fp, &gif.GIF{Image: framesPal, Delay: frameDelays}); err != nil {
		return err
	}

	a.Infof("saved animation to %s", a.capturePath)

	return nil
}

func createZeroedRing(n int) *ring.Ring {
	r := ring.New(n)
	for i := 0; i < n; i++ {
		r.Value = uint64(0)
		r = r.Next()
	}

	return r
}

func enableProfiler(profileOption string, a *App) interface{ Stop() } {
	var options []func(*profile.Profile)

	switch strings.ToLower(strings.Trim(profileOption, " ")) {
	case "cpu":
		a.Logger.Debug("CPU profiling is enabled.")

		options = append(options, profile.CPUProfile)
	case "mem":
		a.Logger.Debug("Memory profiling is enabled.")

		options = append(options, profile.MemProfile)
	case "block":
		a.Logger.Debug("Block profiling is enabled.")

		options = append(options, profile.BlockProfile)
	case "goroutine":
		a.Logger.Debug("Goroutine profiling is enabled.")

		options = append(options, profile.GoroutineProfile)
	case "trace":
		a.Logger.Debug("Trace profiling is enabled.")

		options = append(options, profile.TraceProfile)
	case "thread":
		a.Logger.Debug("Thread creation profiling is enabled.")

		options = append(options, profile.ThreadcreationProfile)
	case "mutex":
		a.Logger.Debug("Mutex profiling is enabled.")

		options = append(options, profile.MutexProfile)
	}

	options = append(options, profile.ProfilePath("./pprof/"))

	if len(options) > 1 {
		return profile.Start(options...)
	}

	return nil
}

func (a *App) updateInitError(target d2interface.Surface) error {
	target.Clear(colornames.Darkred)
	target.PushTranslation(errMsgPadding, errMsgPadding)
	target.DrawTextf(a.errorMessage.Error())

	return nil
}

// ToMainMenu forces the game to transition to the Main Menu
func (a *App) ToMainMenu(errorMessageOptional ...string) {
	buildInfo := d2gamescreen.BuildInfo{Branch: a.gitBranch, Commit: a.gitCommit}

	mainMenu, err := d2gamescreen.CreateMainMenu(a, a.asset, a.renderer, a.inputManager, a.audio, a.ui, buildInfo,
		*a.Options.LogLevel, errorMessageOptional...)
	if err != nil {
		a.Error(err.Error())
		return
	}

	a.screen.SetNextScreen(mainMenu)
}

// ToSelectHero forces the game to transition to the Select Hero (create character) screen
func (a *App) ToSelectHero(connType d2clientconnectiontype.ClientConnectionType, host string) {
	selectHero, err := d2gamescreen.CreateSelectHeroClass(a, a.asset, a.renderer, a.audio, a.ui, connType, *a.Options.LogLevel, host)
	if err != nil {
		a.Error(err.Error())
		return
	}

	a.screen.SetNextScreen(selectHero)
}

// ToCreateGame forces the game to transition to the Create Game screen
func (a *App) ToCreateGame(filePath string, connType d2clientconnectiontype.ClientConnectionType, host string) {
	gameClient, err := d2client.Create(connType, a.asset, *a.Options.LogLevel, a.scriptEngine)
	if err != nil {
		a.Error(err.Error())
	}

	if gameClient == nil {
		a.Error("could not create client")
		return
	}

	if err = gameClient.Open(host, filePath); err != nil {
		errorMessage := fmt.Sprintf("can not connect to the host: %s", host)
		a.Error(errorMessage)
		a.ToMainMenu(errorMessage)
	} else {
		game, err := d2gamescreen.CreateGame(
			a, a.asset, a.ui, a.renderer, a.inputManager, a.audio, gameClient, a.terminal, *a.Options.LogLevel, a.guiManager,
		)
		if err != nil {
			a.Error(err.Error())
		}

		a.screen.SetNextScreen(game)
	}
}

// ToCharacterSelect forces the game to transition to the Character Select (load character) screen
func (a *App) ToCharacterSelect(connType d2clientconnectiontype.ClientConnectionType, connHost string) {
	characterSelect, err := d2gamescreen.CreateCharacterSelect(a, a.asset, a.renderer, a.inputManager,
		a.audio, a.ui, connType, *a.Options.LogLevel, connHost)
	if err != nil {
		a.Errorf("unable to create character select screen: %s", err)
	}

	a.screen.SetNextScreen(characterSelect)
}

// ToMapEngineTest forces the game to transition to the map engine test screen
func (a *App) ToMapEngineTest(region, level int) {
	met, err := d2gamescreen.CreateMapEngineTest(region, level, a.asset, a.terminal, a.renderer, a.inputManager, a.audio,
		*a.Options.LogLevel, a.screen)
	if err != nil {
		a.Error(err.Error())
		return
	}

	a.screen.SetNextScreen(met)
}

// ToCredits forces the game to transition to the credits screen
func (a *App) ToCredits() {
	a.screen.SetNextScreen(d2gamescreen.CreateCredits(a, a.asset, a.renderer, *a.Options.LogLevel, a.ui))
}

// ToCinematics forces the game to transition to the cinematics menu
func (a *App) ToCinematics() {
	a.screen.SetNextScreen(d2gamescreen.CreateCinematics(a, a.asset, a.renderer, a.audio, *a.Options.LogLevel, a.ui))
}


================================================
FILE: d2app/capture_state.go
================================================
package d2app

type captureState int

const (
	captureStateNone captureState = iota
	captureStateFrame
	captureStateGif
)


================================================
FILE: d2app/console_commands.go
================================================
package d2app

import (
	"os"
	"runtime/pprof"
	"strconv"

	"github.com/OpenDiablo2/OpenDiablo2/d2game/d2gamescreen"
)

func (a *App) initTerminalCommands() {
	terminalCommands := []struct {
		name string
		desc string
		args []string
		fn   func(args []string) error
	}{
		{"dumpheap", "dumps the heap to pprof/heap.pprof", nil, a.dumpHeap},
		{"fullscreen", "toggles fullscreen", nil, a.toggleFullScreen},
		{"capframe", "captures a still frame", []string{"filename"}, a.setupCaptureFrame},
		{"capgifstart", "captures an animation (start)", []string{"filename"}, a.startAnimationCapture},
		{"capgifstop", "captures an animation (stop)", nil, a.stopAnimationCapture},
		{"vsync", "toggles vsync", nil, a.toggleVsync},
		{"fps", "toggle fps counter", nil, a.toggleFpsCounter},
		{"timescale", "set scalar for elapsed time", []string{"float"}, a.setTimeScale},
		{"quit", "exits the game", nil, a.quitGame},
		{"screen-gui", "enters the gui playground screen", nil, a.enterGuiPlayground},
		{"js", "eval JS scripts", []string{"code"}, a.evalJS},
	}

	for _, cmd := range terminalCommands {
		if err := a.terminal.Bind(cmd.name, cmd.desc, cmd.args, cmd.fn); err != nil {
			a.Fatalf("failed to bind action %q: %v", cmd.name, err.Error())
		}
	}
}

func (a *App) dumpHeap([]string) error {
	if _, err := os.Stat("./pprof/"); os.IsNotExist(err) {
		if err := os.Mkdir("./pprof/", 0750); err != nil {
			a.Fatal(err.Error())
		}
	}

	fileOut, err := os.Create("./pprof/heap.pprof")
	if err != nil {
		a.Error(err.Error())
	}

	if err := pprof.WriteHeapProfile(fileOut); err != nil {
		a.Fatal(err.Error())
	}

	if err := fileOut.Close(); err != nil {
		a.Fatal(err.Error())
	}

	return nil
}

func (a *App) evalJS(args []string) error {
	val, err := a.scriptEngine.Eval(args[0])
	if err != nil {
		a.terminal.Errorf(err.Error())
		return nil
	}

	a.Info("%s" + val)

	return nil
}

func (a *App) toggleFullScreen([]string) error {
	fullscreen := !a.renderer.IsFullScreen()
	a.renderer.SetFullScreen(fullscreen)
	a.terminal.Infof("fullscreen is now: %v", fullscreen)

	return nil
}

func (a *App) setupCaptureFrame(args []string) error {
	a.captureState = captureStateFrame
	a.capturePath = args[0]
	a.captureFrames = nil

	return nil
}

func (a *App) startAnimationCapture(args []string) error {
	a.captureState = captureStateGif
	a.capturePath = args[0]
	a.captureFrames = nil

	return nil
}

func (a *App) stopAnimationCapture([]string) error {
	a.captureState = captureStateNone

	return nil
}

func (a *App) toggleVsync([]string) error {
	vsync := !a.renderer.GetVSyncEnabled()
	a.renderer.SetVSyncEnabled(vsync)
	a.terminal.Infof("vsync is now: %v", vsync)

	return nil
}

func (a *App) toggleFpsCounter([]string) error {
	a.showFPS = !a.showFPS
	a.terminal.Infof("fps counter is now: %v", a.showFPS)

	return nil
}

func (a *App) setTimeScale(args []string) error {
	timeScale, err := strconv.ParseFloat(args[0], 64)
	if err != nil || timeScale <= 0 {
		a.terminal.Errorf("invalid time scale value")
		return nil
	}

	a.terminal.Infof("timescale changed from %f to %f", a.timeScale, timeScale)
	a.timeScale = timeScale

	return nil
}

func (a *App) quitGame([]string) error {
	os.Exit(0)
	return nil
}

func (a *App) enterGuiPlayground([]string) error {
	a.screen.SetNextScreen(d2gamescreen.CreateGuiTestMain(a.renderer, a.guiManager, *a.Options.LogLevel, a.asset))
	return nil
}


================================================
FILE: d2app/initialization.go
================================================
package d2app

import (
	"fmt"
	"path/filepath"

	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2loader/asset/types"

	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2animdata"
	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
	"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
)

func (a *App) initialize() error {
	if err := a.initConfig(a.config); err != nil {
		return err
	}

	a.initLanguage()

	if err := a.initDataDictionaries(); err != nil {
		return err
	}

	a.timeScale = 1.0
	a.lastTime = d2util.Now()
	a.lastScreenAdvance = a.lastTime

	a.renderer.SetWindowIcon("d2logo.png")
	a.terminal.BindLogger()
	a.initTerminalCommands()

	gui, err := d2gui.CreateGuiManager(a.asset, *a.Options.LogLevel, a.inputManager)
	if err != nil {
		return err
	}

	a.guiManager = gui

	a.screen = d2screen.NewScreenManager(a.ui, *a.Options.LogLevel, a.guiManager)

	a.audio.SetVolumes(a.config.BgmVolume, a.config.SfxVolume)

	if err := a.loadStrings(); err != nil {
		return err
	}

	a.ui.Initialize()

	return nil
}

const (
	fmtErrSourceNotFound = `file not found: %q

Please check your config file at %q

Also, verify that the MPQ files exist at %q

Capitalization in the file name matters.
`
)

func (a *App) initConfig(config *d2config.Configuration) error {
	a.config = config

	for _, mpqName := range a.config.MpqLoadOrder {
		cleanDir := filepath.Clean(a.config.MpqPath)
		srcPath := filepath.Join(cleanDir, mpqName)

		err := a.asset.AddSource(srcPath, types.AssetSourceMPQ)
		if err != nil {
			// nolint:stylecheck // we want a multiline error message here..
			return fmt.Errorf(fmtErrSourceNotFound, srcPath, a.config.Path(), a.config.MpqPath)
		}
	}

	return nil
}

func (a *App) initLanguage() {
	a.language = a.asset.LoadLanguage(d2resource.LocalLanguage)
	a.asset.Loader.SetLanguage(&a.language)

	a.charset = d2resource.GetFontCharset(a.language)
	a.asset.Loader.SetCharset(&a.charset)
}

func (a *App) initDataDictionaries() error {
	dictPaths := []string{
		d2resource.LevelType, d2resource.LevelPreset, d2resource.LevelWarp,
		d2resource.ObjectType, d2resource.ObjectDetails, d2resource.Weapons,
		d2resource.Armor, d2resource.Misc, d2resource.Books, d2resource.ItemTypes,
		d2resource.UniqueItems, d2resource.Missiles, d2resource.SoundSettings,
		d2resource.MonStats, d2resource.MonStats2, d2resource.MonPreset,
		d2resource.MonProp, d2resource.MonType, d2resource.MonMode,
		d2resource.MagicPrefix, d2resource.MagicSuffix, d2resource.ItemStatCost,
		d2resource.ItemRatio, d2resource.StorePage, d2resource.Overlays,
		d2resource.CharStats, d2resource.Hireling, d2resource.Experience,
		d2resource.Gems, d2resource.QualityItems, d2resource.Runes,
		d2resource.DifficultyLevels, d2resource.AutoMap, d2resource.LevelDetails,
		d2resource.LevelMaze, d2resource.LevelSubstitutions, d2resource.CubeRecipes,
		d2resource.SuperUniques, d2resource.Inventory, d2resource.Skills,
		d2resource.SkillCalc, d2resource.MissileCalc, d2resource.Properties,
		d2resource.SkillDesc, d2resource.BodyLocations, d2resource.Sets,
		d2resource.SetItems, d2resource.AutoMagic, d2resource.TreasureClass,
		d2resource.TreasureClassEx, d2resource.States, d2resource.SoundEnvirons,
		d2resource.Shrines, d2resource.ElemType, d2resource.PlrMode,
		d2resource.PetType, d2resource.NPC, d2resource.MonsterUniqueModifier,
		d2resource.MonsterEquipment, d2resource.UniqueAppellation, d2resource.MonsterLevel,
		d2resource.MonsterSound, d2resource.MonsterSequence, d2resource.PlayerClass,
		d2resource.MonsterPlacement, d2resource.ObjectGroup, d2resource.CompCode,
		d2resource.MonsterAI, d2resource.RarePrefix, d2resource.RareSuffix,
		d2resource.Events, d2resource.Colors, d2resource.ArmorType,
		d2resource.WeaponClass, d2resource.PlayerType, d2resource.Composite,
		d2resource.HitClass, d2resource.UniquePrefix, d2resource.UniqueSuffix,
		d2resource.CubeModifier, d2resource.CubeType, d2resource.HirelingDescription,
		d2resource.LowQualityItems,
	}

	a.Info("Initializing asset manager")

	for _, path := range dictPaths {
		err := a.asset.LoadRecords(path)
		if err != nil {
			return err
		}
	}

	err := a.initAnimationData(d2resource.AnimationData)
	if err != nil {
		return err
	}

	return nil
}

const (
	fmtLoadAnimData = "loading animation data from: %s"
)

func (a *App) initAnimationData(path string) error {
	animDataBytes, err := a.asset.LoadFile(path)
	if err != nil {
		return err
	}

	a.Debugf(fmtLoadAnimData, path)

	animData, err := d2animdata.Load(animDataBytes)
	if err != nil {
		a.Error(err.Error())
	}

	a.Infof("Loaded %d animation data records", animData.GetRecordsCount())

	a.asset.Records.Animation.Data = animData

	return nil
}

func (a *App) loadStrings() error {
	tablePaths := []string{
		d2resource.PatchStringTable,
		d2resource.ExpansionStringTable,
		d2resource.StringTable,
	}

	for _, tablePath := range tablePaths {
		_, err := a.asset.LoadStringTable(tablePath)
		if err != nil {
			return err
		}
	}

	return nil
}


================================================
FILE: d2common/d2cache/cache.go
================================================
package d2cache

import (
	"errors"
	"log"
	"sync"

	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
)

var _ d2interface.Cache = &Cache{} // Static check to confirm struct conforms to interface

type cacheNode struct {
	next   *cacheNode
	prev   *cacheNode
	key    string
	value  interface{}
	weight int
}

// Cache stores arbitrary data for fast retrieval
type Cache struct {
	head    *cacheNode
	tail    *cacheNode
	lookup  map[string]*cacheNode
	weight  int
	budget  int
	verbose bool
	mutex   sync.Mutex
}

// CreateCache creates an  instance of a Cache
func CreateCache(budget int) d2interface.Cache {
	return &Cache{lookup: make(map[string]*cacheNode), budget: budget}
}

// SetVerbose turns on verbose printing (warnings and stuff)
func (c *Cache) SetVerbose(verbose bool) {
	c.verbose = verbose
}

// GetWeight gets the "weight" of a cache
func (c *Cache) GetWeight() int {
	return c.weight
}

// GetBudget gets the memory budget of a cache
func (c *Cache) GetBudget() int {
	return c.budget
}

// Insert inserts an object into the cache
func (c *Cache) Insert(key string, value interface{}, weight int) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if _, found := c.lookup[key]; found {
		return errors.New("key already exists in Cache")
	}

	node := &cacheNode{
		key:    key,
		value:  value,
		weight: weight,
		next:   c.head,
	}

	if c.head != nil {
		c.head.prev = node
	}

	c.head = node
	if c.tail == nil {
		c.tail = node
	}

	c.lookup[key] = node
	c.weight += node.weight

	for ; c.tail != nil && c.tail != c.head && c.weight > c.budget; c.tail = c.tail.prev {
		c.weight -= c.tail.weight
		c.tail.prev.next = nil

		if c.verbose {
			log.Printf(
				"warning -- Cache is evicting %s (%d) for %s (%d); spare weight is now %d",
				c.tail.key,
				c.tail.weight,
				key,
				weight,
				c.budget-c.weight,
			)
		}

		delete(c.lookup, c.tail.key)
	}

	return nil
}

// Retrieve gets an object out of the cache
func (c *Cache) Retrieve(key string) (interface{}, bool) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	node, found := c.lookup[key]
	if !found {
		return nil, false
	}

	if node != c.head {
		if node.next != nil {
			node.next.prev = node.prev
		}

		if node.prev != nil {
			node.prev.next = node.next
		}

		if node == c.tail {
			c.tail = c.tail.prev
		}

		node.next = c.head
		node.prev = nil

		if c.head != nil {
			c.head.prev = node
		}

		c.head = node
	}

	return node.value, true
}

// Clear removes all cache entries
func (c *Cache) Clear() {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.head = nil
	c.tail = nil
	c.lookup = make(map[string]*cacheNode)
	c.weight = 0
}


================================================
FILE: d2common/d2cache/cache_test.go
================================================
package d2cache

import (
	"testing"
)

func TestCacheInsert(t *testing.T) {
	cache := CreateCache(1)
	insertError := cache.Insert("A", "", 1)

	if insertError != nil {
		t.Fatalf("Cache insert resulted in unexpected error: %s", insertError)
	}
}

func TestCacheInsertWithinBudget(t *testing.T) {
	cache := CreateCache(1)
	insertError := cache.Insert("A", "", 2)

	if insertError != nil {
		t.Fatalf("Cache insert resulted in unexpected error: %s", insertError)
	}
}

func TestCacheInsertUpdatesWeight(t *testing.T) {
	cache := CreateCache(2)
	_ = cache.Insert("A", "", 1)
	_ = cache.Insert("B", "", 1)
	_ = cache.Insert("budget_exceeded", "", 1)

	if cache.GetWeight() != 2 {
		t.Fatal("Cache with budget 2 did not correctly set weight after evicting one of three nodes")
	}
}

func TestCacheInsertDuplicateRejected(t *testing.T) {
	cache := CreateCache(2)
	_ = cache.Insert("dupe", "", 1)
	dupeError := cache.Insert("dupe", "", 1)

	if dupeError == nil {
		t.Fatal("Cache insert of duplicate key did not result in any err")
	}
}

func TestCacheInsertEvictsLeastRecentlyUsed(t *testing.T) {
	cache := CreateCache(2)
	// with a budget of 2, inserting 3 keys should evict the last
	_ = cache.Insert("evicted", "", 1)
	_ = cache.Insert("A", "", 1)
	_ = cache.Insert("B", "", 1)

	_, foundEvicted := cache.Retrieve("evicted")
	if foundEvicted {
		t.Fatal("Cache insert did not trigger eviction after weight exceedance")
	}

	// double check that only 1 one was evicted and not any extra
	_, foundA := cache.Retrieve("A")
	_, foundB := cache.Retrieve("B")

	if !foundA || !foundB {
		t.Fatal("Cache insert evicted more than necessary")
	}
}

func TestCacheInsertEvictsLeastRecentlyRetrieved(t *testing.T) {
	cache := CreateCache(2)
	_ = cache.Insert("A", "", 1)
	_ = cache.Insert("evicted", "", 1)

	// retrieve the oldest node, promoting it head so it is not evicted
	cache.Retrieve("A")

	// insert once more, exceeding weight capacity
	_ = cache.Insert("B", "", 1)
	// now the least recently used key should be evicted
	_, foundEvicted := cache.Retrieve("evicted")
	if foundEvicted {
		t.Fatal("Cache insert did not evict least recently used after weight exceedance")
	}
}

func TestClear(t *testing.T) {
	cache := CreateCache(1)
	_ = cache.Insert("cleared", "", 1)
	cache.Clear()
	_, found := cache.Retrieve("cleared")

	if found {
		t.Fatal("Still able to retrieve nodes after cache was cleared")
	}
}


================================================
FILE: d2common/d2cache/doc.go
================================================
// Package d2cache provides a generic caching implementation
package d2cache


================================================
FILE: d2common/d2calculation/calcstring.go
================================================
package d2calculation

// CalcString is a type of string often used in datafiles to specify
// a value that is calculated dynamically based on the stats of the relevant
// source, for instance a missile might have a movement speed of lvl*2
type CalcString string

// Issue #689
// info about calcstrings can be found here: https://d2mods.info/forum/kb/viewarticle?a=371


================================================
FILE: d2common/d2calculation/calculation.go
================================================
// Package d2calculation contains code for calculation nodes.
package d2calculation

import (
	"fmt"
	"strconv"
)

// Calculation is the interface of every evaluatable calculation.
type Calculation interface {
	fmt.Stringer
	Eval() int
}

// BinaryCalculation is a calculation with a binary function or operator.
type BinaryCalculation struct {
	// Left is the left operand.
	Left Calculation

	// Right is the right operand.
	Right Calculation

	// Op is the actual operation.
	Op func(v1, v2 int) int
}

// Eval evaluates the calculation.
func (node *BinaryCalculation) Eval() int {
	return node.Op(node.Left.Eval(), node.Right.Eval())
}

func (node *BinaryCalculation) String() string {
	return "Binary(" + node.Left.String() + "," + node.Right.String() + ")"
}

// UnaryCalculation is a calculation with a unary function or operator.
type UnaryCalculation struct {
	// Child is the operand.
	Child Calculation

	// Op is the operation.
	Op func(v int) int
}

// Eval evaluates the calculation.
func (node *UnaryCalculation) Eval() int {
	return node.Op(node.Child.Eval())
}

func (node *UnaryCalculation) String() string {
	return "Unary(" + node.Child.String() + ")"
}

// TernaryCalculation is a calculation with a ternary function or operator.
type TernaryCalculation struct {
	// Left is the left operand.
	Left Calculation

	// Middle is the middle operand.
	Middle Calculation

	// Right is the right operand.
	Right Calculation
	Op    func(v1, v2, v3 int) int
}

// Eval evaluates the calculation.
func (node *TernaryCalculation) Eval() int {
	return node.Op(node.Left.Eval(), node.Middle.Eval(), node.Right.Eval())
}

func (node *TernaryCalculation) String() string {
	return "Ternary(" + node.Left.String() + "," + node.Middle.String() + "," + node.Right.String() + ")"
}

// PropertyReferenceCalculation is the calculation representing a property.
type PropertyReferenceCalculation struct {
	Type      string
	Name      string
	Qualifier string
}

// Eval evaluates the calculation.
func (node *PropertyReferenceCalculation) Eval() int {
	return 1
}

func (node *PropertyReferenceCalculation) String() string {
	return "Property(" + node.Type + "," + node.Name + "," + node.Qualifier + ")"
}

// ConstantCalculation is a constant value.
type ConstantCalculation struct {
	// Value is the constant value.
	Value int
}

// Eval evaluates the calculation.
func (node *ConstantCalculation) Eval() int {
	return node.Value
}

func (node *ConstantCalculation) String() string {
	return strconv.Itoa(node.Value)
}


================================================
FILE: d2common/d2calculation/d2lexer/lexer.go
================================================
// Package d2lexer contains the code for tokenizing calculation strings.
package d2lexer

import (
	"errors"
	"strconv"
	"strings"
	"unicode"
)

type tokenType int

const (
	// Name represents a name token, such as skill, par1 etc.
	Name tokenType = iota

	// String represents a quoted string token, such as "Sacrifice".
	String

	// Symbol represents a symbol token, such as '+', '-', '?, '.' etc.
	Symbol

	// Number represents an integer token.
	Number

	// EOF is the end-of-file token, generated when the end of data is reached.
	EOF
)

func (t tokenType) String() string {
	return []string{
		"Name",
		"String",
		"Symbol",
		"Number",
		"EOF",
	}[t]
}

// Token is a lexical token of a calculation string.
type Token struct {
	Type  tokenType
	Value string
}

func (t *Token) String() string {
	return "(" + t.Type.String() + ", " + t.Value + ")\n"
}

// Lexer is the tokenizer for calculation strings.
type Lexer struct {
	data         []byte
	CurrentToken Token
	index        int
	peeked       bool
	nextToken    Token
}

// New creates a new Lexer for tokenizing the given data.
func New(input []byte) *Lexer {
	return &Lexer{
		data: input,
	}
}

func (l *Lexer) peekNext() (byte, error) {
	if l.index+1 >= len(l.data) {
		return 0, errors.New("cannot peek")
	}

	return l.data[l.index+1], nil
}

func (l *Lexer) extractOpToken() Token {
	c := l.data[l.index]
	if c == '=' || c == '!' {
		next, ok := l.peekNext()
		if ok != nil || next != '=' {
			panic("Invalid operator at index!" + strconv.Itoa(l.index))
		} else {
			l.index += 2
			return Token{Symbol, string(c) + "="}
		}
	}

	if c == '<' || c == '>' {
		next, ok := l.peekNext()
		if ok == nil && next == '=' {
			l.index += 2
			return Token{Symbol, string(c) + "="}
		}
		l.index++

		return Token{Symbol, string(c)}
	}
	l.index++

	return Token{Symbol, string(c)}
}

func (l *Lexer) extractNumber() Token {
	var sb strings.Builder

	for l.index < len(l.data) && unicode.IsDigit(rune(l.data[l.index])) {
		sb.WriteByte(l.data[l.index])
		l.index++
	}

	return Token{Number, sb.String()}
}

func (l *Lexer) extractString() Token {
	var sb strings.Builder
	l.index++

	for l.index < len(l.data) && l.data[l.index] != '\'' {
		sb.WriteByte(l.data[l.index])
		l.index++
	}
	l.index++

	return Token{String, sb.String()}
}

func (l *Lexer) extractName() Token {
	var sb strings.Builder

	for l.index < len(l.data) &&
		(unicode.IsLetter(rune(l.data[l.index])) ||
			unicode.IsDigit(rune(l.data[l.index]))) {
		sb.WriteByte(l.data[l.index])
		l.index++
	}

	return Token{Name, sb.String()}
}

// Peek returns the next token, but does not advance the tokenizer.
// The peeked token is cached until the tokenizer advances.
func (l *Lexer) Peek() Token {
	if l.peeked {
		return l.nextToken
	}

	if l.index == len(l.data) {
		l.nextToken = Token{EOF, ""}
		return l.nextToken
	}

	for l.index < len(l.data) && unicode.IsSpace(rune(l.data[l.index])) {
		l.index++
	}

	if l.index == len(l.data) {
		l.nextToken = Token{EOF, ""}
		return l.nextToken
	}

	switch {
	case strings.IndexByte("^=!><+-/*.,:?()", l.data[l.index]) != -1:
		l.nextToken = l.extractOpToken()
	case unicode.IsDigit(rune(l.data[l.index])):
		l.nextToken = l.extractNumber()
	case l.data[l.index] == '\'':
		l.nextToken = l.extractString()
	case unicode.IsLetter(rune(l.data[l.index])):
		l.nextToken = l.extractName()
	default:
		panic("Invalid token at index: " + strconv.Itoa(l.index))
	}

	l.peeked = true

	return l.nextToken
}

// NextToken returns the next token and advances the tokenizer.
func (l *Lexer) NextToken() Token {
	if l.peeked {
		l.CurrentToken = l.nextToken
	} else {
		l.CurrentToken = l.Peek()
	}

	l.peeked = false

	return l.CurrentToken
}


================================================
FILE: d2common/d2calculation/d2lexer/lexer_test.go
================================================
package d2lexer

import (
	"testing"
)

func TestName(t *testing.T) {
	lexer := New([]byte("correct horse battery staple andromeda13142 n1n2n4"))

	expected := []Token{
		{Name, "correct"},
		{Name, "horse"},
		{Name, "battery"},
		{Name, "staple"},
		{Name, "andromeda13142"},
		{Name, "n1n2n4"},
	}

	for _, want := range expected {
		got := lexer.NextToken()
		if got.Type != Name || got.Value != want.Value {
			t.Errorf("Got: %v, want %v", got, want)
		}
	}

	eof := lexer.NextToken()
	if eof.Type != EOF {
		t.Errorf("Did not reach EOF")
	}
}

func TestNumber(t *testing.T) {
	lexer := New([]byte("12 2325 53252 312 3411"))

	expected := []Token{
		{Number, "12"},
		{Number, "2325"},
		{Number, "53252"},
		{Number, "312"},
		{Number, "3411"},
	}

	for _, want := range expected {
		got := lexer.NextToken()
		if got.Type != Number || got.Value != want.Value {
			t.Errorf("Got: %v, want %v", got, want)
		}
	}

	eof := lexer.NextToken()
	if eof.Type != EOF {
		t.Errorf("Did not reach EOF")
	}
}

func TestSymbol(t *testing.T) {
	lexer := New([]byte("((+-==>>>=!=<=<=<*//*)?(::.,.:?"))

	expected := []Token{
		{Symbol, "("},
		{Symbol, "("},
		{Symbol, "+"},
		{Symbol, "-"},
		{Symbol, "=="},
		{Symbol, ">"},
		{Symbol, ">"},
		{Symbol, ">="},
		{Symbol, "!="},
		{Symbol, "<="},
		{Symbol, "<="},
		{Symbol, "<"},
		{Symbol, "*"},
		{Symbol, "/"},
		{Symbol, "/"},
		{Symbol, "*"},
		{Symbol, ")"},
		{Symbol, "?"},
		{Symbol, "("},
		{Symbol, ":"},
		{Symbol, ":"},
		{Symbol, "."},
		{Symbol, ","},
		{Symbol, "."},
		{Symbol, ":"},
		{Symbol, "?"},
	}

	for _, want := range expected {
		got := lexer.NextToken()
		if got.Type != Symbol || got.Value != want.Value {
			t.Errorf("Got: %v, want %v", got, want)
		}
	}

	eof := lexer.NextToken()
	if eof.Type != EOF {
		t.Errorf("Did not reach EOF")
	}
}

func TestString(t *testing.T) {
	lexer := New([]byte(`correct 'horse' 'battery staple' 'andromeda13142 ' n1n2n4`))

	expected := []Token{
		{Name, "correct"},
		{String, "horse"},
		{String, "battery staple"},
		{String, "andromeda13142 "},
		{Name, "n1n2n4"},
	}

	for _, want := range expected {
		got := lexer.NextToken()
		if got.Type != want.Type || got.Value != want.Value {
			t.Errorf("Got: %v, want %v", got, want)
		}
	}

	eof := lexer.NextToken()
	if eof.Type != EOF {
		t.Errorf("Did not reach EOF")
	}
}

func TestActualConstructions(t *testing.T) {
	lexer := New([]byte("skill('Sacrifice'.blvl) > 3 ? min(50, lvl) : skill('Sacrifice'.lvl) * ln12"))

	expected := []Token{
		{Name, "skill"},
		{Symbol, "("},
		{String, "Sacrifice"},
		{Symbol, "."},
		{Name, "blvl"},
		{Symbol, ")"},
		{Symbol, ">"},
		{Number, "3"},
		{Symbol, "?"},
		{Name, "min"},
		{Symbol, "("},
		{Number, "50"},
		{Symbol, ","},
		{Name, "lvl"},
		{Symbol, ")"},
		{Symbol, ":"},
		{Name, "skill"},
		{Symbol, "("},
		{String, "Sacrifice"},
		{Symbol, "."},
		{Name, "lvl"},
		{Symbol, ")"},
		{Symbol, "*"},
		{Name, "ln12"},
	}

	for _, want := range expected {
		got := lexer.NextToken()
		if got.Type != want.Type || got.Value != want.Value {
			t.Errorf("Got: %v, want %v", got, want)
		}
	}

	eof := lexer.NextToken()
	if eof.Type != EOF {
		t.Errorf("Did not reach EOF")
	}
}


================================================
FILE: d2common/d2calculation/d2parser/d2parser.go
================================================
// Package d2parser contains the code for parsing calculation strings.
package d2parser


================================================
FILE: d2common/d2calculation/d2parser/operations.go
================================================
package d2parser

import (
	"math"
	"math/rand"
)

type binaryOperation struct {
	Operator          string
	Precedence        int
	IsRightAssociated bool
	Function          func(v1, v2 int) int
}

type unaryOperation struct {
	Operator   string
	Precedence int
	Function   func(v int) int
}

type ternaryOperation struct {
	Operator          string
	Marker            string
	Precedence        int
	IsRightAssociated bool
	Function          func(v1, v2, v3 int) int
}

func getUnaryOperations() map[string]unaryOperation {
	return map[string]unaryOperation{
		"+": {
			"+",
			4,
			func(v int) int {
				return v
			},
		},
		"-": {
			"-",
			4,
			func(v int) int {
				return -v
			},
		},
	}
}

func getTernaryOperations() map[string]ternaryOperation {
	return map[string]ternaryOperation{
		"?": {
			"?",
			":",
			0,
			true,
			func(v1, v2, v3 int) int {
				if v1 != 0 {
					return v2
				}
				return v3
			},
		},
	}
}

func getBinaryOperations() map[string]binaryOperation { //nolint:funlen // No reason to split function, just creates the operations.
	return map[string]binaryOperation{
		"==": {
			"==",
			1,
			false,
			func(v1, v2 int) int {
				if v1 == v2 {
					return 1
				}
				return 0
			},
		},
		"!=": {
			"!=",
			1,
			false,
			func(v1, v2 int) int {
				if v1 != v2 {
					return 1
				}
				return 0
			},
		},
		"<": {
			"<",
			2,
			false,
			func(v1, v2 int) int {
				if v1 < v2 {
					return 1
				}
				return 0
			},
		},
		">": {
			">",
			2,
			false,
			func(v1, v2 int) int {
				if v1 > v2 {
					return 1
				}
				return 0
			},
		},
		"<=": {
			"<=",
			2,
			false,
			func(v1, v2 int) int {
				if v1 <= v2 {
					return 1
				}
				return 0
			},
		},
		">=": {
			">=",
			2,
			false,
			func(v1, v2 int) int {
				if v1 >= v2 {
					return 1
				}
				return 0
			},
		},
		"+": {
			"+",
			3,
			false,
			func(v1, v2 int) int {
				return v1 + v2
			},
		},
		"-": {
			"-",
			3,
			false,
			func(v1, v2 int) int {
				return v1 - v2
			},
		},
		"*": {
			"*",
			5,
			false,
			func(v1, v2 int) int {
				return v1 * v2
			},
		},
		"/": {
			"/",
			5,
			false,
			func(v1, v2 int) int {
				return v1 / v2
			},
		},
		"^": {
			"^",
			6,
			true,
			func(v1, v2 int) int {
				return int(math.Pow(float64(v1), float64(v2)))
			},
		},
	}
}

func getFunctions() map[string]func(v1, v2 int) int {
	return map[string]func(v1, v2 int) int{
		"min": func(v1, v2 int) int {
			if v1 < v2 {
				return v1
			}
			return v2
		},
		"max": func(v1, v2 int) int {
			if v1 > v2 {
				return v1
			}
			return v2
		},
		"rand": func(v1, v2 int) int {
			if rand.Int()%2 == 0 { //nolint:gosec // Secure random not necessary.
				return v1
			}
			return v2
		},
	}
}


================================================
FILE: d2common/d2calculation/d2parser/parser.go
================================================
package d2parser

import (
	"log"
	"strconv"
	"strings"

	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation"
	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation/d2lexer"
)

// Parser is a parser for calculations used for skill and missiles.
type Parser struct {
	lex *d2lexer.Lexer

	binaryOperations  map[string]binaryOperation
	unaryOperations   map[string]unaryOperation
	ternaryOperations map[string]ternaryOperation
	fixedFunctions    map[string]func(v1, v2 int) int

	currentType string
	currentName string
}

// New creates a new parser.
func New() *Parser {
	return &Parser{
		binaryOperations:  getBinaryOperations(),
		unaryOperations:   getUnaryOperations(),
		ternaryOperations: getTernaryOperations(),
		fixedFunctions:    getFunctions(),
	}
}

// SetCurrentReference sets the current reference type and name, such as "skill" and skill name.
func (parser *Parser) SetCurrentReference(propType, propName string) {
	parser.currentType = propType
	parser.currentName = propName
}

// Parse parses the calculation string and creates a Calculation tree.
func (parser *Parser) Parse(calc string) d2calculation.Calculation {
	calc = strings.TrimSpace(calc)
	if calc == "" {
		return &d2calculation.ConstantCalculation{Value: 0}
	}

	defer func() {
		if r := recover(); r != nil {
			log.Printf("Error parsing calculation: %v", calc)
		}
	}()

	parser.lex = d2lexer.New([]byte(calc))

	return parser.parseLevel(0)
}

func (parser *Parser) peek() d2lexer.Token {
	return parser.lex.Peek()
}

func (parser *Parser) consume() d2lexer.Token {
	return parser.lex.NextToken()
}

func (parser *Parser) parseLevel(level int) d2calculation.Calculation {
	node := parser.parseProduction()

	t := parser.peek()
	if t.Type == d2lexer.EOF {
		return node
	}

	for {
		if t.Type != d2lexer.Symbol {
			break
		}

		op, ok := parser.binaryOperations[t.Value]
		if !ok || op.Precedence < level {
			break
		}

		parser.consume()

		var nextLevel int

		if op.IsRightAssociated {
			nextLevel = op.Precedence
		} else {
			nextLevel = op.Precedence + 1
		}

		otherCalculation := parser.parseLevel(nextLevel)
		node = &d2calculation.BinaryCalculation{
			Left:  node,
			Right: otherCalculation,
			Op:    op.Function,
		}
		t = parser.peek()
	}

	for {
		if t.Type != d2lexer.Symbol {
			break
		}

		op, ok := parser.ternaryOperations[t.Value]
		if !ok || op.Precedence < level {
			break
		}

		parser.consume()

		var nextLevel int

		if op.IsRightAssociated {
			nextLevel = op.Precedence
		} else {
			nextLevel = op.Precedence + 1
		}

		middleCalculation := parser.parseLevel(nextLevel)

		t = parser.peek()
		if t.Type != d2lexer.Symbol || t.Value != op.Marker {
			panic("Invalid ternary! " + t.Value + ", expected: " + op.Marker)
		}

		parser.consume()
		rightCalculation := parser.parseLevel(nextLevel)

		node = &d2calculation.TernaryCalculation{
			Left:   node,
			Middle: middleCalculation,
			Right:  rightCalculation,
			Op:     op.Function,
		}
		t = parser.peek()
	}

	return node
}

func (parser *Parser) parseProduction() d2calculation.Calculation {
	t := parser.peek()

	switch {
	case t.Type == d2lexer.Symbol:
		if t.Value == "(" {
			parser.consume()
			node := parser.parseLevel(0)

			t = parser.peek()
			if t.Type != d2lexer.Symbol ||
				t.Value != ")" {
				if t.Type == d2lexer.EOF { // Ignore unclosed final parenthesis due to syntax error in original Fire Wall calculation.
					return node
				}

				panic("Parenthesis not closed!")
			}

			parser.consume()

			return node
		}

		op, ok := parser.unaryOperations[t.Value]
		if !ok {
			panic("Invalid unary symbol: " + t.Value)
		}

		parser.consume()
		node := parser.parseLevel(op.Precedence)

		return &d2calculation.UnaryCalculation{
			Child: node,
			Op:    op.Function,
		}

	case t.Type == d2lexer.Name || t.Type == d2lexer.Number:
		return parser.parseLeafCalculation()
	default:
		panic("Expected parenthesis, unary operator, function or value!")
	}
}

func (parser *Parser) parseLeafCalculation() d2calculation.Calculation {
	t := parser.peek()

	if t.Type == d2lexer.Number {
		val, err := strconv.Atoi(t.Value)
		if err != nil {
			panic("Invalid number: " + t.Value)
		}

		parser.consume()

		return &d2calculation.ConstantCalculation{Value: val}
	}

	if t.Value == "skill" ||
		t.Value == "miss" ||
		t.Value == "stat" {
		return parser.parseProperty()
	}

	if parser.fixedFunctions[t.Value] != nil {
		return parser.parseFunction(t.Value)
	}

	if t.Type == d2lexer.Name {
		parser.consume()

		return &d2calculation.PropertyReferenceCalculation{
			Type:      parser.currentType,
			Name:      parser.currentName,
			Qualifier: t.Value,
		}
	}

	panic(t.Value + " is not a function, property, or number!")
}

func (parser *Parser) parseFunction(name string) d2calculation.Calculation {
	function := parser.fixedFunctions[name]
	parser.consume()

	t := parser.peek()
	if t.Value != "(" {
		panic("Invalid function!")
	}

	parser.consume()

	firstParam := parser.parseLevel(0)

	t = parser.peek()
	if t.Type != d2lexer.Symbol || t.Value != "," {
		panic("Invalid function!")
	}

	parser.consume()

	secondParam := parser.parseLevel(0)

	t = parser.peek()
	if t.Value != ")" {
		panic("Invalid function!")
	}

	parser.consume()

	return &d2calculation.BinaryCalculation{
		Left:  firstParam,
		Right: secondParam,
		Op:    function,
	}
}

func (parser *Parser) parseProperty() d2calculation.Calculation {
	t := parser.peek()
	propType := t.Value
	t = parser.consume()

	t = parser.peek()
	if t.Value != "(" {
		panic("Invalid property: " + propType + ", open parenthesis missing.")
	}

	parser.consume()

	t = parser.peek()
	if t.Type != d2lexer.String {
		panic("Property name must be in quotes: " + propType)
	}

	propName := t.Value

	parser.consume()

	t = parser.peek()
	if t.Type != d2lexer.Symbol || t.Value != "." {
		panic("Property name must be followed by dot: " + propType)
	}

	parser.consume()

	t = parser.peek()
	if t.Type != d2lexer.Name {
		panic("Invalid propery qualifier: " + propType)
	}

	propQual := t.Value

	parser.consume()

	t = parser.peek()
	if t.Value != ")" {
		panic("Invalid property: " + propType + ", closed parenthesis missing.")
	}

	parser.consume()

	return &d2calculation.PropertyReferenceCalculation{
		Type:      propType,
		Name:      propName,
		Qualifier: propQual,
	}
}


================================================
FILE: d2common/d2calculation/d2parser/parser_test.go
================================================
package d2parser

import (
	"math"
	"math/rand"
	"testing"
)

func TestEmptyInput(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result int
	}{
		{"", 0},
		{" ", 0},
		{"\t\t \t\t \t", 0},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if res != row.result {
			t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
		}
	}
}

func TestConstantExpression(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result int
	}{
		{"0", 0},
		{"5", 5},
		{"455", 455},
		{"789", 789},
		{"3242", 3242},
		{"45454", 45454},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if res != row.result {
			t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
		}
	}
}

func TestUnaryOperations(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result int
	}{
		{"+0", 0},
		{"-0", 0},
		{"+455", 455},
		{"++455", 455},
		{"+++455", 455},
		{"-455", -455},
		{"--455", 455},
		{"---455", -455},
		{"+-+789", -789},
		{"-++3242", -3242},
		{"++--+-+45454", -45454},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if res != row.result {
			t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
		}
	}
}

func TestArithmeticBinaryOperations(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result int
	}{
		{"1 + 2", 3},
		{"54+56", 54 + 56},
		{"9212-2121", 9212 - 2121},
		{"1+2-5", -2},
		{"5-3-1", 1},
		{"4*5", 20},
		{"512/2", 256},
		{"10/9", 1},
		{"1/3*5", 0},
		{"2^3^2", int(math.Pow(2., 9.))},
		{"4^2*2+1", 33},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if res != row.result {
			t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
		}
	}
}

func TestParentheses(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result int
	}{
		{"(1+2)*5", 15},
		{"(99-98)/2", 0},
		{"((3+2)*6)/3", 10},
		{"(3+2)*(6/3)", 10},
		{"(20+10)/6/5", 1},
		{"(20+10)/(6/5)", 30},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if res != row.result {
			t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
		}
	}
}

func TestLackFinalParethesis(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result int
	}{
		{"(3+2)*(6/3", 10},
		{"(20+10)/(6/5", 30},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if res != row.result {
			t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
		}
	}
}

func TestLogicalBinaryOperations(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result bool
	}{
		{"1 < 2", true},
		{"1 < -5", false},
		{"1 <= 5", true},
		{"1 <= 10", true},
		{"5 <= 1", false},
		{"1 <= 1", true},
		{"5 > 10", false},
		{"54 >= 100", false},
		{"45 >= 45", true},
		{"10 == 10", true},
		{"10 == 1", false},
		{"10 != 1", true},
		{"10 != 10", false},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if (res == 0 && row.result) || (res != 0 && !row.result) {
			t.Errorf("Expression %v gave wrong result, got %d, want %v", row.expr, res, row.result)
		}
	}
}

func TestLogicalAndArithmetic(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result bool
	}{
		{"(1 < 2)*(5 < 10)", true},
		{"(1 < -5)+(1 == 5)", false},
		{"(5 > 10)*(10 == 10)", false},
		{"(45 >= 45)+(1 > 500000)", true},
		{"(10 == 10)*(30 > 50)+(5 >= 5)", true},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if (res == 0 && row.result) || (res != 0 && !row.result) {
			t.Errorf("Expression %v gave wrong result, got %d, want %v", row.expr, res, row.result)
		}
	}
}

func TestTernaryOperator(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result int
	}{
		{"5 > 1 ? 3 : 5", 3},
		{"5 <= 1 ? 3 : 5", 5},
		{"(1 < 10)*(5 < 3) ? 43 : 5 == 5 ? 1 : 2", 1},
		{"(1 < 10)*(5 < 3) ? 43 : 5 != 5 ? 1 : 2", 2},
		{"(1 < 10)*(5 > 3) ? 43 : 5 == 5 ? 1 : 2", 43},
		{"(1 < 10)*(5 > 3) ? 43 != 0 ? 65 : 32 : 5 == 5 ? 1 : 2", 65},
		{"(1 < 10)*(5 > 3) ? 43 == 0 ? 65 : 32 : 5 == 5 ? 1 : 2", 32},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if res != row.result {
			t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
		}
	}
}

func TestBuiltinFunctions(t *testing.T) {
	parser := New()

	table := []struct {
		expr   string
		result int
	}{
		{"min(5, 2)", 2},
		{"min(4^6, 5+10)", 15},
		{"max(10, 4*3)", 12},
		{"max(50-2, 50-3)", 48},
	}

	for _, row := range table {
		c := parser.Parse(row.expr)
		res := c.Eval()

		if res != row.result {
			t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
		}
	}
}

func TestRandFunction(t *testing.T) {
	parser := New()
	c := parser.Parse("rand(1,5)")

	rand.Seed(1)

	res1 := []int{c.Eval(), c.Eval(), c.Eval(), c.Eval(), c.Eval()}

	rand.Seed(1)

	res2 := []int{c.Eval(), c.Eval(), c.Eval(), c.Eval(), c.Eval()}

	for i := 0; i < len(res1); i++ {
		t.Logf("%d, %d", res1[i], res2[i])

		if res1[i] != res2[i] {
			t.Error("Results not equal.")
		}
	}
}

func BenchmarkSimpleExpression(b *testing.B) {
	parser := New()
	expr := "(1 < 10)*(5 > 3) ? 43 == 0 ? 65 : 32 : 5 == 5 ? 1 : 2"

	for n := 0; n < b.N; n++ {
		parser.Parse(expr)
	}
}


================================================
FILE: d2common/d2data/d2compression/huffman.go
================================================
// Package d2compression is used for decompressing WAV files.
package d2compression

// MpqHuffman.go based on the original CS file
//
// Authors:
//		Foole (fooleau@gmail.com)
//      Tim Sarbin (tim.sarbin@gmail.com) (go translation)
//
// (C) 2006 Foole (fooleau@gmail.com)
// Based on code from StormLib by Ladislav Zezula and ShadowFlare
//
// 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.
//

import (
	"log"

	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
)

// linkedNode is a node which is both hierachcical (parent/child) and doubly linked (next/prev)
type linkedNode struct {
	decompressedValue int
	weight            int
	parent            *linkedNode
	child0            *linkedNode
	prev              *linkedNode
	next              *linkedNode
}

// createLinkedNode creates a linked node
func createLinkedNode(decompVal, weight int) *linkedNode {
	result := &linkedNode{
		decompressedValue: decompVal,
		weight:            weight,
	}

	return result
}

func (v *linkedNode) getChild1() *linkedNode {
	return v.child0.prev
}

func (v *linkedNode) insert(other *linkedNode) *linkedNode {
	// 'next' should have a lower weight we should return the lower weight
	if other.weight <= v.weight {
		// insert before
		if v.next != nil {
			v.next.prev = other
			other.next = v.next
		}

		v.next = other

		other.prev = v

		return other
	}

	if v.prev == nil {
		// insert after
		other.prev = nil
		v.prev = other
		other.next = v
	} else {
		v.prev.insert(other)
	}

	return v
}

//nolint:funlen,dupl // it's ok to have duplicates and a long func here
func getPrimes() [][]byte {
	return [][]byte{
		{
			// Compression type 0
			0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
		},
		{ //nolint:dupl // it doesnt matter here
			// Compression type 1
			0x54, 0x16, 0x16, 0x0D, 0x0C, 0x08, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x04, 0x04, 0x03, 0x05,
			0x0E, 0x0B, 0x14, 0x13, 0x13, 0x09, 0x0B, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02,
			0x0D, 0x07, 0x09, 0x06, 0x06, 0x04, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
			0x09, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04,
			0x08, 0x03, 0x04, 0x07, 0x09, 0x05, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
			0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02,
			0x06, 0x0A, 0x08, 0x08, 0x06, 0x07, 0x04, 0x03, 0x04, 0x04, 0x02, 0x02, 0x04, 0x02, 0x03, 0x03,
			0x04, 0x03, 0x07, 0x07, 0x09, 0x06, 0x04, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02,
			0x0A, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x03, 0x05, 0x02, 0x03,
			0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01,
			0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x09, 0x08, 0x0C, 0x02,
			0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
			0x04, 0x01, 0x02, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
			0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
			0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
			0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x4B,
		}, {
			// Compression type 2 //nolint:dupl // it doesnt matter here
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00, 0x23, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x06, 0x0E, 0x10, 0x04,
			0x06, 0x08, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01,
			0x01, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x03, 0x02,
			0x03, 0x01, 0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01,
			0x01, 0x29, 0x07, 0x16, 0x12, 0x40, 0x0A, 0x0A, 0x11, 0x25, 0x01, 0x03, 0x17, 0x10, 0x26, 0x2A,
			0x10, 0x01, 0x23, 0x23, 0x2F, 0x10, 0x06, 0x07, 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01,
		}, { //nolint:dupl // it doesnt matter here
			// Compression type 3 //nolint:dupl // it doesnt matter here
			0xFF, 0x0B, 0x07, 0x05, 0x0B, 0x02, 0x02, 0x02, 0x06, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x03,
			0x09, 0x01, 0x01, 0x01, 0x03, 0x04, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
			0x05, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
			0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
			0x0A, 0x04, 0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01,
			0x05, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03,
			0x01, 0x03, 0x01, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x03, 0x05, 0x01, 0x03, 0x01, 0x03, 0x03,
			0x02, 0x01, 0x04, 0x03, 0x0A, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
			0x02, 0x02, 0x01, 0x0A, 0x02, 0x05, 0x01, 0x01, 0x02, 0x07, 0x02, 0x17, 0x01, 0x05, 0x01, 0x01,
			0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
			0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
			0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
			0x06, 0x02, 0x01, 0x04, 0x05, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
			0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
			0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
			0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11,
		}, { // Compression type 4 //nolint:dupl // it doesnt matter here
			0xFF, 0xFB, 0x98, 0x9A, 0x84, 0x85, 0x63, 0x64, 0x3E, 0x3E, 0x22, 0x22, 0x13, 0x13, 0x18, 0x17,
		}, { // Compression type 5 //nolint:dupl // it doesnt matter here
			0xFF, 0xF1, 0x9D, 0x9E, 0x9A, 0x9B, 0x9A, 0x97, 0x93, 0x93, 0x8C, 0x8E, 0x86, 0x88, 0x80, 0x82,
			0x7C, 0x7C, 0x72, 0x73, 0x69, 0x6B, 0x5F, 0x60, 0x55, 0x56, 0x4A, 0x4B, 0x40, 0x41, 0x37, 0x37,
			0x2F, 0x2F, 0x27, 0x27, 0x21, 0x21, 0x1B, 0x1C, 0x17, 0x17, 0x13, 0x13, 0x10, 0x10, 0x0D, 0x0D,
			0x0B, 0x0B, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x04, 0x19, 0x18,
		}, { //nolint:dupl // it doesnt matter here
			// Compression type 6
			0xC3, 0xCB, 0xF5, 0x41, 0xFF, 0x7B, 0xF7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0xBF, 0xCC, 0xF2, 0x40, 0xFD, 0x7C, 0xF7, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x7A, 0x46,
		}, { //nolint:dupl // it doesnt matter here
			// Compression type 7
			0xC3, 0xD9, 0xEF, 0x3D, 0xF9, 0x7C, 0xE9, 0x1E, 0xFD, 0xAB, 0xF1, 0x2C, 0xFC, 0x5B, 0xFE, 0x17,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0xBD, 0xD9, 0xEC, 0x3D, 0xF5, 0x7D, 0xE8, 0x1D, 0xFB, 0xAE, 0xF0, 0x2C, 0xFB, 0x5C, 0xFF, 0x18,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x70, 0x6C,
		}, { // Compression type 8
			0xBA, 0xC5, 0xDA, 0x33, 0xE3, 0x6D, 0xD8, 0x18, 0xE5, 0x94, 0xDA, 0x23, 0xDF, 0x4A, 0xD1, 0x10,
			0xEE, 0xAF, 0xE4, 0x2C, 0xEA, 0x5A, 0xDE, 0x15, 0xF4, 0x87, 0xE9, 0x21, 0xF6, 0x43, 0xFC, 0x12,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0xB0, 0xC7, 0xD8, 0x33, 0xE3, 0x6B, 0xD6, 0x18, 0xE7, 0x95, 0xD8, 0x23, 0xDB, 0x49, 0xD0, 0x11,
			0xE9, 0xB2, 0xE2, 0x2B, 0xE8, 0x5C, 0xDD, 0x15, 0xF1, 0x87, 0xE7, 0x20, 0xF7, 0x44, 0xFF, 0x13,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x5F, 0x9E,
		},
	}
}

func decode(input *d2datautils.BitStream, head *linkedNode) *linkedNode {
	node := head

	for node.child0 != nil {
		bit := input.ReadBits(1)
		if bit == -1 {
			log.Fatal("unexpected end of file")
		}

		if bit == 0 {
			node = node.child0
			continue
		}

		node = node.getChild1()
	}

	return node
}

const (
	decompVal1 = 256
	decompVal2 = 257
)

func buildList(primeData []byte) *linkedNode {
	root := createLinkedNode(decompVal1, 1)
	root = root.insert(createLinkedNode(decompVal2, 1))

	for i := 0; i < len(primeData); i++ {
		if primeData[i] != 0 {
			root = root.insert(createLinkedNode(i, int(primeData[i])))
		}
	}

	return root
}

func insertNode(tail *linkedNode, decomp int) *linkedNode {
	parent := tail
	result := tail.prev // This will be the new tail after the tree is updated

	temp := createLinkedNode(parent.decompressedValue, parent.weight)
	temp.parent = parent

	newnode := createLinkedNode(decomp, 0)
	newnode.parent = parent

	parent.child0 = newnode

	tail.next = temp
	temp.prev = tail
	newnode.prev = temp
	temp.next = newnode

	adjustTree(newnode)

	// ISSUE #680: For compression type 0, adjustTree should be
	// called once for every value written and only once here
	adjustTree(newnode)

	return result
}

// This increases the weight of the new node and its antecendants
// and adjusts the tree if needed
func adjustTree(newNode *linkedNode) {
	current := newNode

	for current != nil {
		current.weight++

		var insertpoint *linkedNode

		var prev *linkedNode

		// Go backwards thru the list looking for the insertion point
		insertpoint = current

		for {
			prev = insertpoint.prev
			if prev == nil {
				break
			}

			if prev.weight >= current.weight {
				break
			}

			insertpoint = prev
		}

		// No insertion point found
		if insertpoint == current {
			current = current.parent
			continue
		}

		// The following code basically swaps insertpoint with current

		// remove insert point
		if insertpoint.prev != nil {
			insertpoint.prev.next = insertpoint.next
		}

		insertpoint.next.prev = insertpoint.prev

		// insert insertpoint after current
		insertpoint.next = current.next
		insertpoint.prev = current

		if current.next != nil {
			current.next.prev = insertpoint
		}

		current.next = insertpoint

		// remove current
		current.prev.next = current.next
		current.next.prev = current.prev

		// insert current after prev
		if prev == nil {
			log.Fatal("previous frame not defined!")
		}

		temp := prev.next
		current.next = temp
		current.prev = prev
		temp.prev = current
		prev.next = current

		// Set up parent/child links
		currentparent := current.parent
		insertparent := insertpoint.parent

		if currentparent.child0 == current {
			currentparent.child0 = insertpoint
		}

		if currentparent != insertparent && insertparent.child0 == insertpoint {
			insertparent.child0 = current
		}

		current.parent = insertparent
		insertpoint.parent = currentparent

		current = current.parent
	}
}

func buildTree(tail *linkedNode) *linkedNode {
	current := tail

	for current != nil {
		child0 := current
		child1 := current.prev

		if child1 == nil {
			break
		}

		parent := createLinkedNode(0, child0.weight+child1.weight)
		parent.child0 = child0
		child0.parent = parent
		child1.parent = parent

		current.insert(parent)
		current = current.prev.prev
	}

	return current
}

// HuffmanDecompress decompresses huffman-compressed data
//nolint:gomnd // binary decode magic
func HuffmanDecompress(data []byte) []byte {
	comptype := data[0]
	primes := getPrimes()

	if comptype == 0 {
		log.Panic("compression type 0 is not currently supported")
	}

	tail := buildList(primes[comptype])
	head := buildTree(tail)

	outputstream := d2datautils.CreateStreamWriter()
	bitstream := d2datautils.CreateBitStream(data[1:])

	var decoded int

Loop:
	for {
		node := decode(bitstream, head)
		decoded = node.decompressedValue
		switch decoded {
		case 256:
			break Loop
		case 257:
			newvalue := bitstream.ReadBits(8)

			outputstream.PushBytes(byte(newvalue))
			tail = insertNode(tail, newvalue)
		default:
			outputstream.PushBytes(byte(decoded))
		}
	}

	return outputstream.GetBytes()
}


================================================
FILE: d2common/d2data/d2compression/wav.go
================================================
package d2compression

import (
	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
)

// WavDecompress decompresses wav files
//nolint:gomnd // binary decode magic
func WavDecompress(data []byte, channelCount int) ([]byte, error) { //nolint:funlen,gocognit,gocyclo // can't reduce
	Array1 := []int{0x2c, 0x2c}
	Array2 := make([]int, channelCount)

	var sLookup = []int{
		0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E,
		0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F,
		0x0022, 0x0025, 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042,
		0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F,
		0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117, 0x0133,
		0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292,
		0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583,
		0x0610, 0x06AB, 0x0756, 0x0812, 0x08E0, 0x09C3, 0x0ABD, 0x0BD0,
		0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954,
		0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B,
		0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462,
		0x7FFF,
	}

	var sLookup2 = []int{
		-1, 0, -1, 4, -1, 2, -1, 6,
		-1, 1, -1, 5, -1, 3, -1, 7,
		-1, 1, -1, 5, -1, 3, -1, 7,
		-1, 2, -1, 4, -1, 6, -1, 8,
	}

	input := d2datautils.CreateStreamReader(data)
	output := d2datautils.CreateStreamWriter()

	_, err := input.ReadByte()
	if err != nil {
		return nil, err
	}

	shift, err := input.ReadByte()
	if err != nil {
		return nil, err
	}

	for i := 0; i < channelCount; i++ {
		temp, err := input.ReadInt16()
		if err != nil {
			return nil, err
		}

		Array2[i] = int(temp)
		output.PushInt16(temp)
	}

	channel := channelCount - 1

	for input.Position() < input.Size() {
		value, err := input.ReadByte()
		if err != nil {
			return nil, err
		}

		if channelCount == 2 {
			channel = 1 - channel
		}

		if (value & 0x80) != 0 {
			switch value & 0x7f {
			case 0:
				if Array1[channel] != 0 {
					Array1[channel]--
				}

				output.PushInt16(int16(Array2[channel]))
			case 1:
				Array1[channel] += 8
				if Array1[channel] > 0x58 {
					Array1[channel] = 0x58
				}

				if channelCount == 2 {
					channel = 1 - channel
				}
			case 2:
			default:
				Array1[channel] -= 8
				if Array1[channel] < 0 {
					Array1[channel] = 0
				}

				if channelCount == 2 {
					channel = 1 - channel
				}
			}
		} else {
			temp1 := sLookup[Array1[channel]]
			temp2 := temp1 >> shift

			if (value & 1) != 0 {
				temp2 += temp1 >> 0
			}
			if (value & 2) != 0 {
				temp2 += temp1 >> 1
			}
			if (value & 4) != 0 {
				temp2 += temp1 >> 2
			}
			if (value & 8) != 0 {
				temp2 += temp1 >> 3
			}
			if (value & 0x10) != 0 {
				temp2 += temp1 >> 4
			}
			if (value & 0x20) != 0 {
				temp2 += temp1 >> 5
			}

			temp3 := Array2[channel]
			if (value & 0x40) != 0 {
				temp3 -= temp2
				if temp3 <= -32768 {
					temp3 = -32768
				}
			} else {
				temp3 += temp2
				if temp3 >= 32767 {
					temp3 = 32767
				}
			}
			Array2[channel] = temp3
			output.PushInt16(int16(temp3))
			Array1[channel] += sLookup2[value&0x1f]

			if Array1[channel] < 0 {
				Array1[channel] = 0
			} else if Array1[channel] > 0x58 {
				Array1[channel] = 0x58
			}
		}
	}

	return output.GetBytes(), nil
}


================================================
FILE: d2common/d2data/d2video/binkdecoder.go
================================================
package d2video

import (
	"errors"
	"log"

	"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils"
)

// BinkVideoMode is the video mode type
type BinkVideoMode uint32

const (
	// BinkVideoModeNormal is a normal video
	BinkVideoModeNormal BinkVideoMode = iota

	// BinkVideoModeHeightDoubled is a height-doubled video
	BinkVideoModeHeightDoubled

	// BinkVideoModeHeightInterlaced is a height-interlaced video
	BinkVideoModeHeightInterlaced

	// BinkVideoModeWidthDoubled is a width-doubled video
	BinkVideoModeWidthDoubled

	// BinkVideoModeWidthAndHeightDoubled is a width and height-doubled video
	BinkVideoModeWidthAndHeightDoubled

	// BinkVideoModeWidthAndHeightInterlaced is a width and height interlaced video
	BinkVideoModeWidthAndHeightInterlaced
)

const (
	numHeaderBytes            = 3
	bikHeaderStr              = "BIK"
	numAudioTrackUnknownBytes = 2
)

// BinkAudioAlgorithm represents the type of bink audio algorithm
type BinkAudioAlgorithm uint32

const (
	// BinkAudioAlgorithmFFT is the FTT audio algorithm
	BinkAudioAlgorithmFFT BinkAudioAlgorithm = iota

	// BinkAudioAlgorithmDCT is the DCT audio algorithm
	BinkAudioAlgorithmDCT
)

// BinkAudioTrack represents an audio track
type BinkAudioTrack struct {
	AudioChannels     uint16
	AudioSampleRateHz uint16
	Stereo            bool
	Algorithm         BinkAudioAlgorithm
	AudioTrackID      uint32
}

// BinkDecoder represents the bink decoder
type BinkDecoder struct {
	AudioTracks           []BinkAudioTrack
	FrameIndexTable       []uint32
	streamReader          *d2datautils.StreamReader
	fileSize              uint32
	numberOfFrames        uint32
	largestFrameSizeBytes uint32
	VideoWidth            uint32
	VideoHeight           uint32
	FPS                   uint32
	FrameTimeMS           uint32
	VideoMode             BinkVideoMode
	frameIndex            uint32
	videoCodecRevision    byte
	HasAlphaPlane         bool
	Grayscale             bool

	// Mask bit 0, as this is defined as a keyframe

}

// CreateBinkDecoder returns a new instance of the bink decoder
func CreateBinkDecoder(source []byte) (*BinkDecoder, error) {
	result := &BinkDecoder{
		streamReader: d2datautils.CreateStreamReader(source),
	}

	err := result.loadHeaderInformation()

	return result, err
}

// GetNextFrame gets the next frame
func (v *BinkDecoder) GetNextFrame() error {
	//nolint:gocritic // v.streamReader.SetPosition(uint64(v.FrameIndexTable[i] & 0xFFFFFFFE))
	lengthOfAudioPackets, err := v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	samplesInPacket, err := v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	v.streamReader.SkipBytes(int(lengthOfAudioPackets) - 4) //nolint:gomnd // decode magic

	log.Printf("Frame %d:\tSamp: %d", v.frameIndex, samplesInPacket)

	v.frameIndex++

	return nil
}

//nolint:gomnd,funlen,gocyclo // Decoder magic, can't help the long function length for now
func (v *BinkDecoder) loadHeaderInformation() error {
	v.streamReader.SetPosition(0)

	var err error

	headerBytes, err := v.streamReader.ReadBytes(numHeaderBytes)
	if err != nil {
		return err
	}

	if string(headerBytes) != bikHeaderStr {
		return errors.New("invalid header for bink video")
	}

	v.videoCodecRevision, err = v.streamReader.ReadByte()
	if err != nil {
		return err
	}

	v.fileSize, err = v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	v.numberOfFrames, err = v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	v.largestFrameSizeBytes, err = v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	const numBytesToSkip = 4 // Number of frames again?

	v.streamReader.SkipBytes(numBytesToSkip)

	v.VideoWidth, err = v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	v.VideoHeight, err = v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	fpsDividend, err := v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	fpsDivider, err := v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	v.FPS = uint32(float32(fpsDividend) / float32(fpsDivider))
	v.FrameTimeMS = 1000 / v.FPS

	videoFlags, err := v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	v.VideoMode = BinkVideoMode((videoFlags >> 28) & 0x0F)
	v.HasAlphaPlane = ((videoFlags >> 20) & 0x1) == 1
	v.Grayscale = ((videoFlags >> 17) & 0x1) == 1

	numberOfAudioTracks, err := v.streamReader.ReadUInt32()
	if err != nil {
		return err
	}

	v.AudioTracks = make([]BinkAudioTrack, numberOfAudioTracks)

	for i := 0; i < int(numberOfAudioTracks); i++ {
		v.streamReader.SkipBytes(numAudioTrackUnknownBytes)

		v.AudioTracks[i].AudioChannels, err = v.streamReader.ReadUInt16()
		if err != nil {
			return err
		}
	}

	for i := 0; i < int(numberOfAudioTracks); i++ {
		v.AudioTracks[i].AudioSampleRateHz, err = v.streamReader.ReadUInt16()
		if err != nil {
			return err
		}

		var flags uint16

		flags, err = v.streamReader.ReadUInt16()
		if err != nil {
			return err
		}

		v.AudioTracks[i].Stereo = ((flags >> 13) & 0x1) == 1
		v.AudioTracks[i].Algorithm = BinkAudioAlgorithm((flags >> 12) & 0x1)
	}

	for i := 0; i < int(numberOfAudioTracks); i++ {
		v.AudioTracks[i].AudioTrackID, err = v.streamReader.ReadUInt32()
		if err != nil {
			return err
		}
	}

	v.FrameIndexTable = make([]uint32, v.numberOfFrames+1)

	for i := 0; i < int(v.numberOfFrames+1); i++ {
		v.FrameIndexTable[i], err = v.streamReader.ReadUInt32()
		if err != nil {
			return err
		}
	}

	return nil
}


================================================
FILE: d2common/d2data/d2video/doc.go
================================================
// Package d2video provides a bink video decoder
package d2video


================================================
FILE: d2common/d2data/doc.go
================================================
// Package d2data provides file compression utilities, video decoders, and file loaders
// for the txt files inside of diablo's mpq files
package d2data


================================================
FILE: d2common/d2datautils/bitmuncher.go
================================================
package d2datautils

// BitMuncher is used for parsing files that are not byte-aligned such as the DCC files.
type BitMuncher struct {
	data     []byte
	offset   int
	bitsRead int
}

const (
	twosComplimentNegativeOne = 4294967295
	byteLen                   = 8
	oneBit                    = 0x01
	fourBytes                 = byteLen * 4
)

// CreateBitMuncher Creates a BitMuncher
func CreateBitMuncher(data []byte, offset int) *BitMuncher {
	return (&BitMuncher{}).Init(data, offset)
}

// CopyBitMuncher Creates a copy of the source BitMuncher
func CopyBitMuncher(source *BitMuncher) *BitMuncher {
	return source.Copy()
}

// Init initializes the BitMuncher with data and an offset
func (v *BitMuncher) Init(data []byte, offset int) *BitMuncher {
	v.data = data
	v.offset = offset
	v.bitsRead = 0

	return v
}

// Copy returns a copy of a BitMuncher
func (v BitMuncher) Copy() *BitMuncher {
	v.bitsRead = 0
	return &v
}

// Offset returns the offset of the BitMuncher
func (v *BitMuncher) Offset() int {
	return v.offset
}

// SetOffset sets the offset of the BitMuncher
func (v *BitMuncher) SetOffset(n int) {
	v.offset = n
}

// BitsRead returns the number of bits the BitMuncher has read
func (v *BitMuncher) BitsRead() int {
	return v.bitsRead
}

// SetBitsRead sets the number of bits the BitMuncher has read
func (v *BitMuncher) SetBitsRead(n int) {
	v.bitsRead = n
}

// GetBit reads a bit and returns it as uint32
func (v *BitMuncher) GetBit() uint32 {
	result := uint32(v.data[v.offset/byteLen]>>uint(v.offset%byteLen)) & oneBit
	v.offset++
	v.bitsRead++

	return result
}

// SkipBits skips bits, incrementing the offset and bits read
func (v *BitMuncher) SkipBits(bits int) {
	v.offset += bits
	v.bitsRead += bits
}

// GetByte reads a byte from data
func (v *BitMuncher) GetByte() byte {
	return byte(v.GetBits(byteLen))
}

// GetInt32 reads an int32 from data
func (v *BitMuncher) GetInt32() int32 {
	return v.MakeSigned(v.GetBits(fourBytes), fourBytes)
}

// GetUInt32 reads an unsigned uint32 from data
func (v *BitMuncher) GetUInt32() uint32 {
	return v.GetBits(fourBytes)
}

// GetBits given a number of bits to read, reads that number of
// bits and retruns as a uint32
func (v *BitMuncher) GetBits(bits int) uint32 {
	if bits == 0 {
		return 0
	}

	result := uint32(0)
	for i := 0; i < bits; i++ {
		result |= v.GetBit() << uint(i)
	}

	return result
}

// GetSignedBits Given a number of bits, reads that many bits and returns as int
func (v *BitMuncher) GetSignedBits(bits int) int {
	return int(v.MakeSigned(v.GetBits(bits), bits))
}

// MakeSigned converts a uint32 value into an int32
func (v *BitMuncher) MakeSigned(value uint32, bits int) int32 {
	if bits == 0 {
		return 0
	}
	// If its a single bit, a value of 1 is -1 automagically
	if bits == 1 {
		return -int32(value)
	}
	// If there is no sign bit, return the value as is
	if (value & (1 << uint(bits-1))) == 0 {
		return int32(value)
	}

	// We need to extend the signed bit out so that the negative value
	// representation still works with the 2s compliment rule.
	result := uint32(twosComplimentNegativeOne)

	for i := byte(0); i < byte(bits); i++ {
		if ((value >> uint(i)) & 1) == 0 {
			result -= uint32(1 << uint(i))
		}
	}

	// Force casting to a signed value
	return int32(result)
}


================================================
FILE: d2common/d2datautils/bitmuncher_test.go
================================================
package d2datautils

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

var testData = []byte{33, 23, 4, 33, 192, 243} //nolint:gochecknoglobals // just a test

func TestBitmuncherCopy(t *testing.T) {
	bm1 := CreateBitMuncher(testData, 0)
	bm2 := CopyBitMuncher(bm1)

	for i := range bm1.data {
		assert.Equal(t, bm1.data[i], bm2.data[i], "original bitmuncher isn't equal to copied")
	}
}

func TestBitmuncherSetOffset(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)
	bm.SetOffset(5)

	assert.Equal(t, bm.Offset(), 5, "Set Offset method didn't set offset to expected number")
}

func TestBitmuncherSteBitsRead(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)
	bm.SetBitsRead(8)

	assert.Equal(t, bm.BitsRead(), 8, "Set bits read method didn't set bits read to expected value")
}

func TestBitmuncherReadBit(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)

	var result byte

	for i := 0; i < bitsPerByte; i++ {
		v := bm.GetBit()
		result |= byte(v) << byte(i)
	}

	assert.Equal(t, result, testData[0], "result of rpeated 8 times get bit didn't return expected byte")
}

func TestBitmuncherGetBits(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)

	assert.Equal(t, byte(bm.GetBits(bitsPerByte)), testData[0], "get bits didn't return expected value")
}

func TestBitmuncherGetNoBits(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)

	assert.Equal(t, bm.GetBits(0), uint32(0), "get bits didn't return expected value: 0")
}

func TestBitmuncherGetSignedBits(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)

	assert.Equal(t, bm.GetSignedBits(6), -31, "get signed bits didn't return expected value")
}

func TestBitmuncherGetNoSignedBits(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)

	assert.Equal(t, bm.GetSignedBits(0), 0, "get signed bits didn't return expected value")
}

func TestBitmuncherGetOneSignedBit(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)

	assert.Equal(t, bm.GetSignedBits(1), -1, "get signed bits didn't return expected value")
}

func TestBitmuncherSkipBits(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)

	bm.SkipBits(bitsPerByte)

	assert.Equal(t, bm.GetByte(), testData[1], "skipping 8 bits didn't moved bit muncher's position into next byte")
}

func TestBitmuncherGetInt32(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)

	var testInt int32

	for i := 0; i < bytesPerint32; i++ {
		testInt |= int32(testData[i]) << int32(bitsPerByte*i)
	}

	assert.Equal(t, bm.GetInt32(), testInt, "int32 value wasn't returned properly")
}

func TestBitmuncherGetUint32(t *testing.T) {
	bm := CreateBitMuncher(testData, 0)

	var testUint uint32

	for i := 0; i < bytesPerint32; i++ {
		testUint |= uint32(testData[i]) << uint32(bitsPerByte*i)
	}

	assert.Equal(t, bm.GetUInt32(), testUint, "uint32 value wasn't returned properly")
}


================================================
FILE: d2common/d2datautils/bitstream.go
================================================
package d2datautils

import (
	"log"
)

const (
	maxBits     = 16
	bitsPerByte = 8
)

// BitStream is a utility class for reading groups of bits from a stream
type BitStream struct {
	data         []byte
	dataPosition int
	current      int
	bitCount     int
}

// CreateBitStream creates a new BitStream
func CreateBitStream(newData []byte) *BitStream {
	result := &BitStream{
		data:         newData,
		dataPosition: 0,
		current:      0,
		bitCount:     0,
	}

	return result
}

// ReadBits reads the specified number of bits and returns the value
func (v *BitStream) ReadBits(bitCount int) int {
	if bitCount > maxBits {
		log.Panic("Maximum BitCount is 16")
	}

	if !v.EnsureBits(bitCount) {
		return -1
	}

	// nolint:gomnd // byte expresion
	result := v.current & (0xffff >> uint(maxBits-bitCount))
	v.WasteBits(bitCount)

	return result
}

// PeekByte returns the current byte without adjusting the position
func (v *BitStream) PeekByte() int {
	if !v.EnsureBits(bitsPerByte) {
		return -1
	}

	// nolint:gomnd // byte
	return v.current & 0xff
}

// EnsureBits ensures that the specified number of bits are available
func (v *BitStream) EnsureBits(bitCount int) bool {
	if bitCount <= v.bitCount {
		return true
	}

	if v.dataPosition >= len(v.data) {
		return false
	}

	nextValue := v.data[v.dataPosition]
	v.dataPosition++
	v.current |= int(nextValue) << uint(v.bitCount)
	v.bitCount += 8

	return true
}

// WasteBits dry-reads the specified number of bits
func (v *BitStream) WasteBits(bitCount int) {
	// noinspection GoRedundantConversion
	v.current >>= uint(bitCount)
	v.bitCount -= bitCount
}


================================================
FILE: d2common/d2datautils/bitstream_test.go
================================================
package d2datautils

import (
	"testing"
)

func TestBitStreamBits(t *testing.T) {
	data := []byte{0xAA}
	bitStream := CreateBitStream(data)
	shouldBeOne := 0

	for i := 0; i < 8; i++ {
		bit := bitStream.ReadBits(1)
		if bit != shouldBeOne {
			t.Fatalf("Expected %d but got %d on iteration %d", shouldBeOne, bit, i)
		}

		if shouldBeOne == 1 {
			shouldBeOne = 0
		} else {
			shouldBeOne = 1
		}
	}
}

func TestBitStreamBytes(t *testing.T) {
	data := []byte{0xAA, 0xBB, 0xCC, 0xDD, 0x12, 0x34, 0x56, 0x78}
	bitStream := CreateBitStream(data)

	for i := 0; i < 8; i++ {
		b := byte(bitStream.ReadBits(8))
		if b != data[i] {
			t.Fatalf("Expected %d but got %d on iteration %d", data[i], b, i)
		}
	}
}


================================================
FILE: d2common/d2datautils/doc.go
================================================
// Package d2datautils is a utility package that provides helper functions/classes
// for parsing the original diablo2 files. (eg. parsers for binary files that aren't byte-aligned)
package d2datautils


================================================
FILE: d2common/d2datautils/stream_reader.go
================================================
package d2datautils

import (
	"io"
)

const (
	bytesPerint16 = 2
	bytesPerint32 = 4
	bytesPerint64 = 8
)

// StreamReader allows you to read data from a byte array in various formats
type StreamReader struct {
	data     []byte
	position uint64
}

// CreateStreamReader creates an instance of the stream reader
func CreateStreamReader(source []byte) *StreamReader {
	result := &StreamReader{
		data:     source,
		position: 0,
	}

	return result
}

// ReadByte reads a byte from the stream
func (v *StreamReader) ReadByte() (byte, error) {
	if v.position >= v.Size() {
		return 0, io.EOF
	}

	result := v.data[v.position]
	v.position++

	return result, nil
}

// ReadInt16 returns a int16 word from the stream
func (v *StreamReader) ReadInt16() (int16, error) {
	b, err := v.ReadUInt16()
	return int16(b), err
}

// ReadUInt16 returns a uint16 word from the stream
func (v *StreamReader) ReadUInt16() (uint16, error) {
	b, err := v.ReadBytes(bytesPerint16)
	if err != nil {
		return 0, err
	}

	return uint16(b[0]) | uint16(b[1])<<8, err
}

// ReadInt32 returns an int32 dword from the stream
func (v *StreamReader) ReadInt32() (int32, error) {
	b, err := v.ReadUInt32()
	return int32(b), err
}

// ReadUInt32 returns a uint32 dword from the stream
//nolint
func (v *StreamReader) ReadUInt32() (uint32, error) {
	b, err := v.ReadBytes(bytesPerint32)
	if err != nil {
		return 0, err
	}

	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, err
}

// ReadInt64 returns a uint64 qword from the stream
func (v *StreamReader) ReadInt64() (int64, error) {
	b, err := v.ReadUInt64()
	return int64(b), err
}

// ReadUInt64 returns a uint64 qword from the stream
//nolint
func (v *StreamReader) ReadUInt64() (uint64, error) {
	b, err := v.ReadBytes(bytesPerint64)
	if err != nil {
		return 0, err
	}

	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
		uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, err
}

// Position returns the current stream position
func (v *StreamReader) Position() uint64 {
	return v.position
}

// SetPosition sets the stream position with the given position
func (v *StreamReader) SetPosition(newPosition uint64) {
	v.position = newPosition
}

// Size returns the total size of the stream in bytes
func (v *StreamReader) Size() uint64 {
	return uint64(len(v.data))
}

// ReadBytes reads multiple bytes
func (v *StreamReader) ReadBytes(count int) ([]byte, error) {
	if count <= 0 {
		return nil, nil
	}

	size := v.Size()
	if v.position >= size || v.position+uint64(count) > size {
		return nil, io.EOF
	}

	result := v.data[v.position : v.position+uint64(count)]
	v.position += uint64(count)

	return result, nil
}

// SkipBytes moves the stream position forward by the given amount
func (v *StreamReader) SkipBytes(count int) {
	v.position += uint64(count)
}

// Read implements io.Reader
func (v *StreamReader) Read(p []byte) (n int, err error) {
	streamLength := v.Size()

	for i := 0; ; i++ {
		if v.Position() >= streamLength {
			return i, io.EOF
		}

		if i >= len(p) {
			return i, nil
		}

		p[i], err = v.ReadByte()
		if err != nil {
			return i, err
		}
	}
}

// EOF returns if the stream position is reached to the end of the data, or not
func (v *StreamReader) EOF() bool {
	return v.position >= uint64(len(v.data))
}


================================================
FILE: d2common/d2datautils/stream_reader_test.go
================================================
package d2datautils

import (
	"testing"
)

func TestStreamReaderByte(t *testing.T) {
	data := []byte{0x78, 0x56, 0x34, 0x12}
	sr := CreateStreamReader(data)

	if sr.Position() != 0 {
		t.Fatal("StreamReader.Position() did not start at 0")
	}

	if ss := sr.Size(); ss != 4 {
		t.Fatalf("StreamREader.Size() was expected to return %d, but returned %d instead", 4, ss)
	}

	for i := 0; i < len(data); i++ {
		ret, err := sr.ReadByte()
		if err != nil {
			t.Error(err)
		}

		if ret != data[i] {
			t.Fatalf("StreamReader.GetDword() was expected to return %X, but returned %X instead", data[i], ret)
		}

		if pos := sr.Position(); pos != uint64(i+1) {
			t.Fatalf("StreamReader.Position() should be at %d, but was at %d instead", i, pos)
		}
	}
}

func TestStreamReaderWord(t *testing.T) {
	data := []byte{0x78, 0x56, 0x34, 0x12}
	sr := CreateStreamReader(data)

	ret, err := sr.ReadUInt16()
	if err != nil {
		t.Error(err)
	}

	if ret != 0x5678 {
		t.Fatalf("StreamReader.GetDword() was expected to return %X, but returned %X instead", 0x5678, ret)
	}

	if pos := sr.Position(); pos != 2 {
		t.Fatalf("StreamReader.Position() should be at %d, but was at %d instead", 2, pos)
	}

	ret, err = sr.ReadUInt16()
	if err != nil {
		t.Error(err)
	}

	if ret != 0x1234 {
		t.Fatalf("StreamReader.GetDword() was expected to return %X, but returned %X instead", 0x1234, ret)
	}

	if pos := sr.Position(); pos != 4 {
		t.Fatalf("StreamReader.Position() should be at %d, but was at %d instead", 4, pos)
	}
}

func TestStreamReaderDword(t *testing.T) {
	data := []byte{0x78, 0x56, 0x34, 0x12}
	sr := CreateStreamReader(data)

	ret, err := sr.ReadUInt32()
	if err != nil {
		t.Error(err)
	}

	if ret != 0x12345678 {
		t.Fatalf("StreamReader.GetDword() was expected to return %X, but returned %X instead", 0x12345678, ret)
	}

	if pos := sr.Position(); pos != 4 {
		t.Fatalf("StreamReader.Position() should be at %d, but was at %d instead", 4, pos)
	}
}


================================================
FILE: d2common/d2datautils/stream_writer.go
================================================
package d2datautils

import (
	"bytes"
	"log"
)

// StreamWriter allows you to create a byte array by streaming in writes of various sizes
type StreamWriter struct {
	data      *bytes.Buffer
	bitOffset int
	bitCache  byte
}

// CreateStreamWriter creates a new StreamWriter instance
func CreateStreamWriter() *StreamWriter {
	result := &StreamWriter{
		data: new(bytes.Buffer),
	}

	return result
}

// GetBytes returns the the byte slice of the underlying data
func (v *StreamWriter) GetBytes() []byte {
	return v.data.Bytes()
}

// PushBytes writes a bytes to the stream
func (v *StreamWriter) PushBytes(b ...byte) {
	for _, i := range b {
		v.data.WriteByte(i)
	}
}

// PushBit pushes single bit into stream
// WARNING: if you'll use PushBit, offset'll be less than 8, and if you'll
// use another Push... method, bits'll not be pushed
func (v *StreamWriter) PushBit(b bool) {
	if b {
		v.bitCache |= 1 << v.bitOffset
	}
	v.bitOffset++

	if v.bitOffset != bitsPerByte {
		return
	}

	v.PushBytes(v.bitCache)
	v.bitCache = 0
	v.bitOffset = 0
}

// PushBits pushes bits (with max range 8)
func (v *StreamWriter) PushBits(b byte, bits int) {
	if bits > bitsPerByte {
		log.Print("input bits number must be less (or equal) than 8")
	}

	val := b

	for i := 0; i < bits; i++ {
		v.PushBit(val&1 == 1)
		val >>= 1
	}
}

// PushBits16 pushes bits (with max range 16)
func (v *StreamWriter) PushBits16(b uint16, bits int) {
	if bits > bitsPerByte*bytesPerint16 {
		log.Print("input bits number must be less (or equal) than 16")
	}

	val := b

	for i := 0; i < bits; i++ {
		v.PushBit(val&1 == 1)
		val >>= 1
	}
}

// PushBits32 pushes bits (with max range 32)
func (v *StreamWriter) PushBits32(b uint32, bits int) {
	if bits > bitsPerByte*bytesPerint32 {
		log.Print("input bits number must be less (or equal) than 32")
	}

	val := b

	for i := 0; i < bits; i++ {
		v.PushBit(val&1 == 1)
		val >>= 1
	}
}

// PushInt16 writes a int16 word to the stream
func (v *StreamWriter) PushInt16(val int16) {
	v.PushUint16(uint16(val))
}

// PushUint16 writes an uint16 word to the stream
//nolint
func (v *StreamWriter) PushUint16(val uint16) {
	v.data.WriteByte(byte(val))
	v.data.WriteByte(byte(val >> 8))
}

// PushInt32 writes a int32 dword to the stream
func (v *StreamWriter) PushInt32(val int32) {
	v.PushUint32(uint32(val))
}

// PushUint32 writes a uint32 dword to the stream
//nolint
func (v *StreamWriter) PushUint32(val uint32) {
	v.data.WriteByte(byte(val))
	v.data.WriteByte(byte(val >> 8))
	v.data.WriteByte(byte(val >> 16))
	v.data.WriteByte(byte(val >> 24))
}

// PushInt64 writes a uint64 qword to the stream
func (v *StreamWriter) PushInt64(val int64) {
	v.PushUint64(uint64(val))
}

// PushUint64 writes a uint64 qword to the stream
//nolint
func (v *StreamWriter) PushUint64(val uint64) {
	v.data.WriteByte(byte(val))
	v.data.WriteByte(byte(val >> 8))
	v.data.WriteByte(byte(val >> 16))
	v.data.WriteByte(byte(val >> 24))
	v.data.WriteByte(byte(val >> 32))
	v.data.WriteByte(byte(val >> 40))
	v.data.WriteByte(byte(val >> 48))
	v.data.WriteByte(byte(val >> 56))
}


================================================
FILE: d2common/d2datautils/stream_writer_test.go
================================================
package d2datautils

import (
	"testing"
)

func TestStreamWriterBits(t *testing.T) {
	sr := CreateStreamWriter()
	data := []byte{221, 19}

	for _, i := range data {
		sr.PushBits(i, bitsPerByte)
	}

	output := sr.GetBytes()
	for i, d := range data {
		if output[i] != d {
			t.Fatalf("sr.PushBits() pushed %X, but wrote %X instead", d, output[i])
		}
	}
}

func TestStreamWriterBits16(t *testing.T) {
	sr := CreateStreamWriter()
	data := []uint16{1024, 19}

	for _, i := range data {
		sr.PushBits16(i, bitsPerByte*bytesPerint16)
	}

	output := sr.GetBytes()

	for i, d := range data {
		// nolint:gomnd // offset in byte slice; bit shifts for uint16
		outputInt := uint16(output[bytesPerint16*i]) |
			uint16(output[bytesPerint16*i+1])<<8
		if outputInt != d {
			t.Fatalf("sr.PushBits16() pushed %X, but wrote %X instead", d, output[i])
		}
	}
}

func TestStreamWriterBits32(t *testing.T) {
	sr := CreateStreamWriter()
	data := []uint32{19324, 87}

	for _, i := range data {
		sr.PushBits32(i, bitsPerByte*bytesPerint32)
	}

	output := sr.GetBytes()

	for i, d := range data {
		// nolint:gomnd // offset in byte slice; bit shifts for uint32
		outputInt := uint32(output[bytesPerint32*i]) |
			uint32(output[bytesPerint32*i+1])<<8 |
			uint32(output[bytesPerint32*i+2])<<16 |
			uint32(output[bytesPerint32*i+3])<<24

		if outputInt != d {
			t.Fatalf("sr.PushBits32() pushed %X, but wrote %X instead", d, output[i])
		}
	}
}

func TestStreamWriterByte(t *testing.T) {
	sr := CreateStreamWriter()
	data := []byte{0x12, 0x34, 0x56, 0x78}

	sr.PushBytes(data...)

	output := sr.GetBytes()
	for i, d := range data {
		if output[i] != d {
			t.Fatalf("sr.PushBytes() pushed %X, but wrote %X instead", d, output[i])
		}
	}
}

func TestStreamWriterWord(t *testing.T) {
	sr := CreateStreamWriter()
	data := []byte{0x12, 0x34, 0x56, 0x78}

	sr.PushUint16(0x3412)
	sr.PushUint16(0x7856)

	output := sr.GetBytes()
	for i, d := range data {
		if output[i] != d {
			t.Fatalf("sr.PushWord() pushed byte %X to %d, but %X was expected instead", output[i], i, d)
		}
	}
}

func TestStreamWriterDword(t *testing.T) {
	sr := CreateStreamWriter()
	data := []byte{0x12, 0x34, 0x56, 0x78}

	sr.PushUint32(0x78563412)

	output := sr.GetBytes()
	for i, d := range data {
		if output[i] != d {
			t.Fatalf("sr.PushDword() pushed byte %X to %d, but %X was expected instead", output[i], i, d)
		}
	}
}


================================================
FILE: d2common/d2enum/animation_frame.go
================================================
package d2enum

// AnimationFrame represents a single frame of animation.
type AnimationFrame int

// AnimationFrame types
const (
	AnimationFrameNoEvent AnimationFrame = iota
	AnimationFrameAttack
	AnimationFrameMissile
	AnimationFrameSound
	AnimationFrameSkill
)


================================================
FILE: d2common/d2enum/animation_frame_direction.go
================================================
package d2enum

// AnimationFrameDirection enumerates animation frame directions used in d2datadict.MonsterSequenceFrame
type AnimationFrameDirection int

// Animation frame directions
const (
	SouthWest AnimationFrameDirection = iota
	NorthWest
	NorthEast
	SouthEast
	South
	West
	North
	East
)


================================================
FILE: d2common/d2enum/animation_frame_event.go
================================================
package d2enum

// AnimationFrameEvent enumerates events used in d2datadict.MonsterSequenceFrame
type AnimationFrameEvent int

// Animation frame events
const (
	NoEvent AnimationFrameEvent = iota
	MeleeAttack
	MissileAttack
	PlaySound
	LaunchSpell
)


================================================
FILE: d2common/d2enum/composite_type.go
================================================
package d2enum

const (
	unknown = "Unknown"
)

//go:generate stringer -linecomment -type CompositeType -output composite_type_string.go

// CompositeType represents a composite type
type CompositeType int

// Composite types
const (
	CompositeTypeHead      CompositeType = iota // HD
	CompositeTypeTorso                          // TR
	CompositeTypeLegs                           // LG
	CompositeTypeRightArm                       // RA
	CompositeTypeLeftArm                        // LA
	CompositeTypeRightHand                      // RH
	CompositeTypeLeftHand                       // LH
	CompositeTypeShield                         // SH
	CompositeTypeSpecial1                       // S1
	CompositeTypeSpecial2                       // S2
	CompositeTypeSpecial3                       // S3
	CompositeTypeSpecial4                       // S4
	CompositeTypeSpecial5                       // S5
	CompositeTypeSpecial6                       // S6
	CompositeTypeSpecial7                       // S7
	CompositeTypeSpecial8                       // S8
	CompositeTypeMax
)

// Name returns a full name of layer
func (i CompositeType) Name() string {
	strings := map[CompositeType]string{
		CompositeTypeHead:      "Head",
		CompositeTypeTorso:     "Torso",
		CompositeTypeLegs:      "Legs",
		CompositeTypeRightArm:  "Right Arm",
		CompositeTypeLeftArm:   "Left Arm",
		CompositeTypeRightHand: "Right Hand",
		CompositeTypeLeftHand:  "Left Hand",
		CompositeTypeShield:    "Shield",
		CompositeTypeSpecial1:  "Special 1",
		CompositeTypeSpecial2:  "Special 2",
		CompositeTypeSpecial3:  "Special 3",
		CompositeTypeSpecial4:  "Special 4",
		CompositeTypeSpecial5:  "Special 5",
		CompositeTypeSpecial6:  "Special 6",
		CompositeTypeSpecial7:  "Special 7",
		CompositeTypeSpecial8:  "Special 8",
	}

	layerName, found := strings[i]
	if !found {
		return unknown
	}

	return layerName
}


================================================
FILE: d2common/d2enum/composite_type_string.go
================================================
// Code generated by "stringer -linecomment -type CompositeType -output composite_type_string.go"; DO NOT EDIT.

package d2enum

import "strconv"

func _() {
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{}
	_ = x[CompositeTypeHead-0]
	_ = x[CompositeTypeTorso-1]
	_ = x[CompositeTypeLegs-2]
	_ = x[CompositeTypeRightArm-3]
	_ = x[CompositeTypeLeftArm-4]
	_ = x[CompositeTypeRightHand-5]
	_ = x[CompositeTypeLeftHand-6]
	_ = x[CompositeTypeShield-7]
	_ = x[CompositeTypeSpecial1-8]
	_ = x[CompositeTypeSpecial2-9]
	_ = x[CompositeTypeSpecial3-10]
	_ = x[CompositeTypeSpecial4-11]
	_ = x[CompositeTypeSpecial5-12]
	_ = x[CompositeTypeSpecial6-13]
	_ = x[CompositeTypeSpecial7-14]
	_ = x[CompositeTypeSpecial8-15]
	_ = x[CompositeTypeMax-16]
}

const _CompositeType_name = "HDTRLGRALARHLHSHS1S2S3S4S5S6S7S8CompositeTypeMax"

var _CompositeType_index = [...]uint8{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 48}

func (i CompositeType) String() string {
	if i < 0 || i >= CompositeType(len(_CompositeType_index)-1) {
		return "CompositeType(" + strconv.FormatInt(int64(i), 10) + ")"
	}
	return _CompositeType_name[_CompositeType_index[i]:_CompositeType_index[i+1]]
}


================================================
FILE: d2common/d2enum/difficulty.go
================================================
package d2enum

// DifficultyType is an enum for the possible difficulties
type DifficultyType int

const (
	// DifficultyNormal is the normal difficulty
	DifficultyNormal DifficultyType = iota
	// DifficultyNightmare is the nightmare difficulty
	DifficultyNightmare
	// DifficultyHell is the hell difficulty
	DifficultyHell
)


================================================
FILE: d2common/d2enum/doc.go
================================================
// Package d2enum provides enumerations used throughout
// the OpenDiablo2 codebase.
package d2enum


================================================
FILE: d2common/d2enum/draw_effect.go
================================================
package d2enum

// DrawEffect is a draw effect
type DrawEffect int

// Names courtesy of Necrolis
const (
	// DrawEffectPctTransparency25 is a draw effect that implements the following function:
	// GL_MODULATE; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA 25 % transparency (colormaps 49-304 in a .pl2)
	DrawEffectPctTransparency25 DrawEffect = iota

	// DrawEffectPctTransparency50 is a draw effect that implements the following function:
	// GL_MODULATE; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA 50 % transparency (colormaps 305-560 in a .pl2)
	DrawEffectPctTransparency50

	// DrawEffectPctTransparency75 is a draw effect that implements the following function:
	// GL_MODULATE; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA 75 % transparency (colormaps 561-816 in a .pl2)
	DrawEffectPctTransparency75

	// DrawEffectModulate is a draw effect that implements the following function:
	// GL_MODULATE; GL_SRC_ALPHA, GL_DST_ALPHA (colormaps 817-1072 in a .pl2)
	DrawEffectModulate

	// DrawEffectBurn is a draw effect that implements the following function:
	// GL_MODULATE; GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA (colormaps 1073-1328 in a .pl2)
	DrawEffectBurn

	// DrawEffectNormal is a draw effect that implements the following function:
	// GL_MODULATE; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA (colormaps 1457-1712 in a .pl2)
	DrawEffectNormal

	// DrawEffectMod2XTrans is a draw effect that implements the following function:
	// GL_MODULATE; GL_SRC_COLOR, GL_DST_ALPHA (colormaps 1457-1712 in a .pl2)
	DrawEffectMod2XTrans

	// DrawEffectMod2X is a draw effect that implements the following function:
	// GL_COMBINE_ARB; GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA (colormaps 1457-1712 in a .pl2)
	DrawEffectMod2X

	// no effect
	DrawEffectNone
)

// Transparent returns true if there is no effect, false otherwise
func (d DrawEffect) Transparent() bool {
	return d != DrawEffectNone
}

func (d DrawEffect) String() string {
	strings := map[DrawEffect]string{
		DrawEffectPctTransparency25: "25% alpha",
		DrawEffectPctTransparency50: "50% alpha",
		DrawEffectPctTransparency75: "75% alpha",
		DrawEffectModulate:          "Modulate",
		DrawEffectBurn:              "Burn",
		DrawEffectNormal:            "Normal",
		DrawEffectMod2XTrans:        "Mod2XTrans",
		DrawEffectMod2X:             "Mod2X",
		DrawEffectNone:              "None",
	}

	drawEffect, found := strings[d]
	if !found {
		return unknown
	}

	return drawEffect
}


================================================
FILE: d2common/d2enum/encoding_type.go
================================================
package d2enum

// EncodingType represents a encoding type
type EncodingType int

// Encoding types
const (
	EncodeDefault EncodingType = iota
)


================================================
FILE: d2common/d2enum/equipped_slot.go
================================================
package d2enum

// EquippedSlot represents the type of equipment slot
type EquippedSlot int

// Equipped slot ID's
const (
	EquippedSlotNone EquippedSlot = iota
	EquippedSlotHead
	EquippedSlotTorso
	EquippedSlotLegs
	EquippedSlotRightArm
	EquippedSlotLeftArm
	EquippedSlotLeftHand
	EquippedSlotRightHand
	EquippedSlotNeck
	EquippedSlotBelt
	EquippedSlotGloves
)


================================================
FILE: d2common/d2enum/filter.go
================================================
package d2enum

// Filter represents the type of texture filter to be used when an image is magnified or minified.
type Filter int

const (
	// FilterDefault represents the default filter.
	FilterDefault Filter = iota

	// FilterNearest represents nearest (crisp-edged) filter
	FilterNearest

	// FilterLinear represents linear filter
	FilterLinear
)


================================================
FILE: d2common/d2enum/game_event.go
================================================
package d2enum

// GameEvent represents an envent in the game engine
type GameEvent int

// Game events
const (
	// ToggleGameMenu will display the game menu
	ToggleGameMenu GameEvent = iota + 1

	// panel toggles
	ToggleCharacterPanel
	ToggleInventoryPanel
	TogglePartyPanel
	ToggleSkillTreePanel
	ToggleHirelingPanel
	ToggleQuestLog
	ToggleHelpScreen
	ToggleChatOverlay
	ToggleMessageLog
	ToggleRightSkillSelector // these two are for left/right speed-skill panel toggles
	ToggleLeftSkillSelector

	ToggleAutomap
	CenterAutomap        // recenters the automap when opened
	FadeAutomap          // reduces the brightness of the map (not the players/npcs)
	TogglePartyOnAutomap // toggles the display of the party members on the automap
	ToggleNamesOnAutomap // toggles the display of party members names and npcs on the automap
	ToggleMiniMap

	// there can be 16 hotkeys, each hotkey can have a skill assigned
	UseSkill1
	UseSkill2
	UseSkill3
	UseSkill4
	UseSkill5
	UseSkill6
	UseSkill7
	UseSkill8
	UseSkill9
	UseSkill10
	UseSkill11
	UseSkill12
	UseSkill13
	UseSkill14
	UseSkill15
	UseSkill16

	// switching between prev/next skill
	SelectPreviousSkill
	SelectNextSkill

	// ToggleBelts toggles the display of the different level for
	// the currently equipped belt
	ToggleBelts
	UseBeltSlot1
	UseBeltSlot2
	UseBeltSlot3
	UseBeltSlot4

	SwapWeapons
	ToggleChatBox
	ToggleRunWalk

	SayHelp
	SayFollowMe
	SayThisIsForYou
	SayThanks
	SaySorry
	SayBye
	SayNowYouDie
	SayRetreat

	// these events are fired while a player holds the corresponding key
	HoldRun
	HoldStandStill
	HoldShowGroundItems
	HoldShowPortraits

	TakeScreenShot
	ClearScreen // closes all active menus/panels
	ClearMessages
)


================================================
FILE: d2common/d2enum/hero.go
================================================
package d2enum

import "log"

//go:generate stringer -linecomment -type Hero
//go:generate string2enum -samepkg -linecomment -type Hero

// Hero is used for different types of hero's
type Hero int

// Heroes
const (
	HeroNone        Hero = iota //
	HeroBarbarian               // Barbarian
	HeroNecromancer             // Necromancer
	HeroPaladin                 // Paladin
	HeroAssassin                // Assassin
	HeroSorceress               // Sorceress
	HeroAmazon                  // Amazon
	HeroDruid                   // Druid
)

// GetToken returns a 2 letter token
func (h Hero) GetToken() string {
	switch h {
	case HeroBarbarian:
		return "BA"
	case HeroNecromancer:
		return "NE"
	case HeroPaladin:
		return "PA"
	case HeroAssassin:
		return "AI"
	case HeroSorceress:
		return "SO"
	case HeroAmazon:
		return "AM"
	case HeroDruid:
		return "DZ"
	default:
		log.Fatalf("Unknown hero token: %d", h)
	}

	return ""
}

// GetToken3 returns a 3 letter token
func (h Hero) GetToken3() string {
	switch h {
	case HeroBarbarian:
		return "BAR"
	case HeroNecromancer:
		return "NEC"
	case HeroPaladin:
		return "PAL"
	case HeroAssassin:
		return "ASS"
	case HeroSorceress:
		return "SOR"
	case HeroAmazon:
		return "AMA"
	case HeroDruid:
		return "DRU"
	default:
		log.Fatalf("Unknown hero token: %d", h)
	}

	return ""
}


================================================
FILE: d2common/d2enum/hero_stance.go
================================================
package d2enum

// HeroStance used to render hero stance
type HeroStance int

// HeroStance types
const (
	HeroStanceIdle HeroStance = iota
	HeroStanceIdleSelected
	HeroStanceApproaching
	HeroStanceSelected
	HeroStanceRetreating
)


================================================
FILE: d2common/d2enum/hero_string.go
================================================
// Code generated by "stringer -linecomment -type Hero"; DO NOT EDIT.

package d2enum

import "strconv"

func _() {
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{}
	_ = x[HeroNone-0]
	_ = x[HeroBarbarian-1]
	_ = x[HeroNecromancer-2]
	_ = x[HeroPaladin-3]
	_ = x[HeroAssassin-4]
	_ = x[HeroSorceress-5]
	_ = x[HeroAmazon-6]
	_ = x[HeroDruid-7]
}

const _Hero_name = "BarbarianNecromancerPaladinAssassinSorceressAmazonDruid"

var _Hero_index = [...]uint8{0, 0, 9, 20, 27, 35, 44, 50, 55}

func (i Hero) String() string {
	if i < 0 || i >= Hero(len(_Hero_index)-1) {
		return "Hero(" + strconv.FormatInt(int64(i), 10) + ")"
	}
	return _Hero_name[_Hero_index[i]:_Hero_index[i+1]]
}


================================================
FILE: d2common/d2enum/hero_string2enum.go
================================================
// Code generated by "string2enum -samepkg -linecomment -type Hero"; DO NOT EDIT.

package d2enum

import "fmt"

// HeroFromString returns the Hero enum corresponding to s.
func HeroFromString(s string) Hero {
	if len(s) == 0 {
		return 0
	}
	for i := range _Hero_index[:len(_Hero_index)-1] {
		if s == _Hero_name[_Hero_index[i]:_Hero_index[i+1]] {
			return Hero(i)
		}
	}
	panic(fmt.Errorf("unable to locate Hero enum corresponding to %q", s))
}

func _(s string) {
	// Check for duplicate string values in type "Hero".
	switch s {
	// 0
	case "":
	// 1
	case "Barbarian":
	// 2
	case "Necromancer":
	// 3
	case "Paladin":
	// 4
	case "Assassin":
	// 5
	case "Sorceress":
	// 6
	case "Amazon":
	// 7
	case "Druid":
	}
}


================================================
FILE: d2common/d2enum/input_button.go
================================================
package d2enum

// MouseButton represents a traditional 3-button mouse
type MouseButton int

const (
	// MouseButtonLeft is the left mouse button
	MouseButtonLeft MouseButton = iota
	// MouseButtonMiddle is the middle mouse button
	MouseButtonMiddle
	// MouseButtonRight is the right mouse button
	MouseButtonRight
	// MouseButtonMin is the lowest MouseButton
	MouseButtonMin = MouseButtonLeft
	// MouseButtonMax is the highest MouseButton
	MouseButtonMax = MouseButtonRight
)

// MouseButtonMod represents a "modified" mouse button action. This could mean, for example, ctrl-mouse_left
type MouseButtonMod int

const (
	// MouseButtonModLeft is a modified left mouse button
	MouseButtonModLeft MouseButtonMod = 1 << iota
	// MouseButtonModMiddle is a modified middle mouse button
	MouseButtonModMiddle
	// MouseButtonModRight is a modified right mouse button
	MouseButtonModRight
)


================================================
FILE: d2common/d2enum/input_key.go
================================================
package d2enum

// Key represents button on a traditional keyboard.
type Key int

// Input keys
const (
	Key0 Key = iota
	Key1
	Key2
	Key3
	Key4
	Key5
	Key6
	Key7
	Key8
	Key9
	KeyA
	KeyB
	KeyC
	KeyD
	KeyE
	KeyF
	KeyG
	KeyH
	KeyI
	KeyJ
	KeyK
	KeyL
	KeyM
	KeyN
	KeyO
	KeyP
	KeyQ
	KeyR
	KeyS
	KeyT
	KeyU
	KeyV
	KeyW
	KeyX
	KeyY
	KeyZ
	KeyApostrophe
	KeyBackslash
	KeyBackspace
	KeyCapsLock
	KeyComma
	KeyDelete
	KeyDown
	KeyEnd
	KeyEnter
	KeyEqual
	KeyEscape
	KeyF1
	KeyF2
	KeyF3
	KeyF4
	KeyF5
	KeyF6
	KeyF7
	KeyF8
	KeyF9
	KeyF10
	KeyF11
	KeyF12
	KeyGraveAccent
	KeyHome
	KeyInsert
	KeyKP0
	KeyKP1
	KeyKP2
	KeyKP3
	KeyKP4
	KeyKP5
	KeyKP6
	KeyKP7
	KeyKP8
	KeyKP9
	KeyKPAdd
	KeyKPDecimal
	KeyKPDivide
	KeyKPEnter
	KeyKPEqual
	KeyKPMultiply
	KeyKPSubtract
	KeyLeft
	KeyLeftBracket
	KeyMenu
	KeyMinus
	KeyNumLock
	KeyPageDown
	KeyPageUp
	KeyPause
	KeyPeriod
	KeyPrintScreen
	KeyRight
	KeyRightBracket
	KeyScrollLock
	KeySemicolon
	KeySlash
	KeySpace
	KeyTab
	KeyUp
	KeyAlt
	KeyControl
	KeyShift
	KeyTilde
	KeyMouse3
	KeyMouse4
	KeyMouse5
	KeyMouseWheelUp
	KeyMouseWheelDown

	KeyMin = Key0
	KeyMax = KeyMouseWheelDown
)

// KeyMod represents a "modified" key action. This could mean, for example, ctrl-S
type KeyMod int

const (
	// KeyModAlt is the Alt key modifier
	KeyModAlt KeyMod = 1 << iota
	// KeyModControl is the Control key modifier
	KeyModControl
	// KeyModShift is the Shift key modifier
	KeyModShift
)


================================================
FILE: d2common/d2enum/input_priority.go
================================================
package d2enum

// Priority of the event handler
type Priority int

// Priorities
const (
	PriorityLow Priority = iota
	PriorityDefault
	PriorityHigh
)


================================================
FILE: d2common/d2enum/inventory_item_type.go
================================================
package d2enum

// InventoryItemType represents a inventory item type
type InventoryItemType int

// Inventry item types
const (
	InventoryItemTypeItem InventoryItemType = iota
	InventoryItemTypeWeapon
	InventoryItemTypeArmor
)


================================================
FILE: d2common/d2enum/item_affix_type.go
================================================
package d2enum

// ItemAffixSuperType represents a item affix super type
type ItemAffixSuperType int

// Super types
const (
	ItemAffixPrefix ItemAffixSuperType = iota
	ItemAffixSuffix
)

// ItemAffixSubType represents a item affix sub type
type ItemAffixSubType int

// Sub types
const (
	ItemAffixCommon ItemAffixSubType = iota
	ItemAffixMagic
)


================================================
FILE: d2common/d2enum/item_armor_class.go
================================================
package d2enum

// ArmorClass is a 3-character token for the armor. It's used for speed calculations.
type ArmorClass string

//  Armor classes
const (
	ArmorClassLite   = "lit"
	ArmorClassMedium = "med"
	ArmorClassHeavy  = "hvy"
)


================================================
FILE: d2common/d2enum/item_event_functions.go
================================================
package d2enum

// ItemEventFuncID represents a item event function
type ItemEventFuncID int

// Item event functions
const (
	// shoots a missile at the owner of a missile that has just hit you
	// (Chilling Armor uses this)
	ReflectMissile ItemEventFuncID = iota

	// freezes the attacker for a set duration the attacker
	// (Frozen Armor uses this)
	FreezeAttacker

	// does cold damage to and chills the attacker (Shiver Armor uses this)
	FreezeChillAttacker

	// % of damage taken is done to the attacker
	// (Iron Maiden, thorns uses a hardcoded stat)
	ReflectPercentDamage

	// % of damage done added to life, bypassing the targets resistance
	// (used by Life Tap)
	DamageDealtToHealth

	// attacker takes physical damage of #
	AttackerTakesPhysical

	// knocks the target back
	Knockback

	// induces fear in the target making it run away
	InduceFear

	// applies Dim Vision to the target (it casts the actual curse on the
	// monster)
	BlindTarget

	// attacker takes lightning damage of #
	AttackerTakesLightning

	// attacker takes fire damage of #
	AttackerTakesFire

	// attacker takes cold damage of #
	AttackerTakesCold

	// % damage taken is added to mana
	DamageTakenToMana

	// freezes the target
	FreezeTarget

	// causes the target to bleed and lose life (negative life regen)
	OpenWounds

	// crushing blow against the target
	CrushingBlow

	// mana after killing a monster
	ManaOnKillMonster

	// life after killing a demon
	LifeOnKillDemon

	// slows the target
	SlowTarget

	// casts a skill against the defender
	CastSkillAgainstDefender

	// casts a skill against the attacker
	CastSkillAgainstAttacker

	// absorbs physical damage taken (used by Bone Armor)
	AbsorbPhysical

	// transfers damage done from the summon to the owner (used by Blood Golem)
	TakeSummonDamage

	// used by Energy Shield to absorb damage and shift it from life to mana
	ManaAbsorbsDamage

	// absorbs elemental damage taken (used by Cyclone Armor)
	AbsorbElementalDamage

	// transfers damage taken from the summon to the owner (used by Blood Golem)
	TakeSummonDamage2

	// used to slow the attacker if he hits a unit that has the slow target stat
	// (used by Clay Golem)
	TargetSlowsTarget

	// life after killing a monster
	LifeOnKillMonster

	// destroys the corpse of a killed monster (rest in peace effect)
	RestInPeace

	// cast a skill when the event occurs, without a target
	CastSkillWithoutTarget

	// reanimate the target as the specified monster
	ReanimateTargetAsMonster
)


================================================
FILE: d2common/d2enum/item_events.go
================================================
package d2enum

// ItemEventType  used in ItemStatCost
type ItemEventType int

// Item event types
const (
	ItemEventNone             ItemEventType = iota
	ItemEventHitByMissile                   // hit By a Missile
	ItemEventDamagedInMelee                 // Damaged in Melee
	ItemEventDamagedByMissile               // Damaged By Missile
	ItemEventAttackedInMelee                // melee Attack atttempt
	ItemEventDoActive                       // do active state skill
	ItemEventDoMeleeDamage                  // do damage in melee
	ItemEventDoMissileDamage                // do missile damage
	ItemEventDoMeleeAttack                  // do melee attack
	ItemEventDoMissileAttack                // do missile attack
	ItemEventKill                           // killed something
	ItemEventKilled                         // killed By something
	ItemEventAbsorbDamage                   // dealt damage
	ItemEventLevelUp                        // gain a level
)

//nolint:gochecknoglobals // better for lookup
var itemEventsLookup = map[string]ItemEventType{
	"hitbymissile":     ItemEventHitByMissile,
	"damagedinmelee":   ItemEventDamagedInMelee,
	"damagedbymissile": ItemEventDamagedByMissile,
	"attackedinmelee":  ItemEventAttackedInMelee,
	"doactive":         ItemEventDoActive,
	"domeleedamage":    ItemEventDoMeleeDamage,
	"domissiledamage":  ItemEventDoMissileDamage,
	"domeleeattack":    ItemEventDoMeleeAttack,
	"domissileattack":  ItemEventDoMissileAttack,
	"kill":             ItemEventKill,
	"killed":           ItemEventKilled,
	"absorbdamage":     ItemEventAbsorbDamage,
	"levelup":          ItemEventLevelUp,
}

// GetItemEventType returns the ItemEventType from string, expects lowercase input
func GetItemEventType(s string) ItemEventType {
	if s == "" {
		return ItemEventNone
	}

	if v, ok := itemEventsLookup[s]; ok {
		return v
	}

	return ItemEventNone
}


================================================
FILE: d2common/d2enum/item_quality.go
================================================
package d2enum

// ItemQuality is used for enumerating item quality values
type ItemQuality int

// Item qualities
const (
	LowQuality ItemQuality = iota + 1
	Normal
	Superior
	Magic
	Set
	Rare
	Unique
	Crafted
	Tempered
)


================================================
FILE: d2common/d2enum/level_generation_types.go
================================================
package d2enum

// from levels.txt, field `DrlgType`
// https://d2mods.info/forum/kb/viewarticle?a=301

// LevelGenerationType Setting for Level Generation: You have 3 possibilities here:
// 1 Random Maze
// 2 Preset Area
// 3 Wilderness level
type LevelGenerationType int

// Level generation types
const (
	LevelTypeRandomMaze LevelGenerationType = iota
	LevelTypePreset
	LevelTypeWilderness
)


================================================
FILE: d2common/d2enum/level_teleport_flags.go
================================================
package d2enum

// from levels.txt, field `Teleport`
// https://d2mods.info/forum/kb/viewarticle?a=301

// TeleportFlag Controls if teleport is allowed in that level.
// 0 = Teleport not allowed
// 1 = Teleport allowed
// 2 = Teleport allowed, but not able to use teleport throu walls/objects
// (maybe for objects)
type TeleportFlag int

// Teleport flag types
const (
	TeleportDisabled TeleportFlag = iota
	TeleportEnabled
	TeleportEnabledLimited
)


================================================
FILE: d2common/d2enum/monster_alignment_type.go
================================================
package d2enum

// MonsterAlignmentType determines the hostility of the monster towards players
type MonsterAlignmentType int

const (
	// MonsterEnemy flag will make monsters hostile towards players
	MonsterEnemy MonsterAlignmentType = iota

	// MonsterFriend will make monsters friendly towards players
	// this is likely used by NPC's and summons
	MonsterFriend

	// MonsterNeutral will make monsters not care about players or monsters
	// this flag is used for `critter` type monsters
	MonsterNeutral
)


================================================
FILE: d2common/d2enum/monster_animation_mode.go
================================================
package d2enum

//go:generate stringer -linecomment -type MonsterAnimationMode -output monster_animation_mode_string.go

// MonsterAnimationMode represents monster animation modes
type MonsterAnimationMode int

// Monster animation modes
const (
	MonsterAnimationModeDeath     MonsterAnimationMode = iota // DT
	MonsterAnimationModeNeutral                               // NU
	MonsterAnimationModeWalk                                  // WL
	MonsterAnimationModeGetHit                                // GH
	MonsterAnimationModeAttack1                               // A1
	MonsterAnimationModeAttack2                               // A2
	MonsterAnimationModeBlock                                 // BL
	MonsterAnimationModeCast                                  // SC
	MonsterAnimationModeSkill1                                // S1
	MonsterAnimationModeSkill2                                // S2
	MonsterAnimationModeSkill3                                // S3
	MonsterAnimationModeSkill4                                // S4
	MonsterAnimationModeDead                                  // DD
	MonsterAnimationModeKnockback                             // GH
	MonsterAnimationModeSequence                              // xx
	MonsterAnimationModeRun                                   // RN
)


================================================
FILE: d2common/d2enum/monster_animation_mode_string.go
================================================
// Code generated by "stringer -linecomment -type MonsterAnimationMode -output monster_animation_mode_string.go"; DO NOT EDIT.

package d2enum

import "strconv"

func _() {
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{}
	_ = x[MonsterAnimationModeDeath-0]
	_ = x[MonsterAnimationModeNeutral-1]
	_ = x[MonsterAnimationModeWalk-2]
	_ = x[MonsterAnimationModeGetHit-3]
	_ = x[MonsterAnimationModeAttack1-4]
	_ = x[MonsterAnimationModeAttack2-5]
	_ = x[MonsterAnimationModeBlock-6]
	_ = x[MonsterAnimationModeCast-7]
	_ = x[MonsterAnimationModeSkill1-8]
	_ = x[MonsterAnimationModeSkill2-9]
	_ = x[MonsterAnimationModeSkill3-10]
	_ = x[MonsterAnimationModeSkill4-11]
	_ = x[MonsterAnimationModeDead-12]
	_ = x[MonsterAnimationModeKnockback-13]
	_ = x[MonsterAnimationModeSequence-14]
	_ = x[MonsterAnimationModeRun-15]
}

const _MonsterAnimationMode_name = "DTNUWLGHA1A2BLSCS1S2S3S4DDGHxxRN"

var _MonsterAnimationMode_index = [...]uint8{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32}

func (i MonsterAnimationMode) String() string {
	if i < 0 || i >= MonsterAnimationMode(len(_MonsterAnimationMode_index)-1) {
		return "MonsterAnimationMode(" + strconv.FormatInt(int64(i), 10) + ")"
	}
	return _MonsterAnimationMode_name[_MonsterAnimationMode_index[i]:_MonsterAnimationMode_index[i+1]]
}


================================================
FILE: d2common/d2enum/monster_combat_type.go
================================================
package d2enum

// MonsterCombatType is used for setting the monster as melee or ranged
type MonsterCombatType int

const (
	// MonsterMelee is a flag that sets the monster as melee-only
	MonsterMelee MonsterCombatType = iota

	// MonsterRanged is a flag that sets the monster as ranged-only
	MonsterRanged
)


================================================
FILE: d2common/d2enum/monumod_const_index.go
================================================
package d2enum

// MonUModConstIndex is used as an index into d2datadict.MonsterUniqueModifierConstants
type MonUModConstIndex int

// Unique monster modifier constants
const (
	ChampionChance MonUModConstIndex = iota
	MinionHPBonus
	MinionHPBonusNightmare
	MinionHPBonusHell
	ChampionHPBonus
	ChampionHPBonusNightmare
	ChampionHPBonusHell
	UniqueHPBonus
	UniqueHPBonusNightmare
	UniqueHPBonusHell
	ChampionAttackRatingBonus
	ChampionDamageBonus
	StrongMinionAttackRatingBonus
	StrongMinionDamageBonus
	MinionElementalDamageMinBonus
	MinionElementalDamageMinBonusNightmare
	MinionElementalDamageMinBonusHell
	MinionElementalDamageMaxBonus
	MinionElementalDamageMaxBonusNightmare
	MinionElementalDamageMaxBonusHell
	ChampionElementalDamageMinBonus
	ChampionElementalDamageMinBonusNightmare
	ChampionElementalDamageMinBonusHell
	ChampionElementalDamageMaxBonus
	ChampionElementalDamageMaxBonusNightmare
	ChampionElementalDamageMaxBonusHell
	UniqueElementalDamageMinBonus
	UniqueElementalDamageMinBonusNightmare
	UniqueElementalDamageMinBonusHell
	UniqueElementalDamageMaxBonus
	UniqueElementalDamageMaxBonusNightmare
	UniqueElementalDamageMaxBonusHell
)


================================================
FILE: d2common/d2enum/npc_action_type.go
================================================
package d2enum

// NPCActionType determines composite mode animations for NPC's as they move around
type NPCActionType int

// NPCAction types
// https://github.com/OpenDiablo2/OpenDiablo2/issues/811
const (
	NPCActionInvalid NPCActionType = iota
	NPCAction1
	NPCAction2
	NPCAction3
	NPCActionSkill1
)


================================================
FILE: d2common/d2enum/numeric_labels.go
================================================
package d2enum

// there are labels for "numeric labels (see AssetManager.TranslateString)
const (
	RepairAll = iota
	_
	CancelLabel
	CopyrightLabel
	AllRightsReservedLabel
	SinglePlayerLabel
	_
	OtherMultiplayerLabel
	ExitGameLabel
	CreditsLabel
	CinematicsLabel

	ViewAllCinematicsLabel
	EpilogueLabel
	SelectCinematicLabel

	_
	TCPIPGameLabel
	TCPIPOptionsLabel
	TCPIPHostGameLabel
	TCPIPJoinGameLabel
	TCPIPEnterHostIPLabel
	TCPIPYourIPLabel
	TipHostLabel
	TipJoinLabel
	IPNotFoundLabel

	CharNameLabel
	HardCoreLabel
	SelectHeroClassLabel
	AmazonDescr
	NecromancerDescr
	BarbarianDescr
	SorceressDescr
	PaladinDescr

	_

	HellLabel
	NightmareLabel
	NormalLabel
	SelectDifficultyLabel

	_

	DelCharConfLabel
	OpenLabel

	_

	YesLabel
	NoLabel

	_

	ExitLabel
	OKLabel
)

// BaseLabelNumbers returns base label value (#n in english string table table)
func BaseLabelNumbers(idx int) int {
	baseLabelNumbers := []int{
		128, // repairAll
		127,
		// main menu labels
		1612, // CANCEL
		1613, // (c) 2000 Blizzard Entertainment
		1614, // All Rights Reserved.
		1620, // SINGLE PLAYER
		1621, // BATTLE.NET
		1623, // OTHER MULTIPLAYER
		1625, // EXIT DIABLO II
		1627, // CREDITS
		1639, // CINEMATICS

		// cinematics menu labels
		1640, // View All Earned Cinematics
		1659, // Epilogue
		1660, // SELECT CINEMATICS

		// multiplayer labels
		1663, // OPEN BATTLE.NET
		1666, // TCP/IP GAME
		1667, // TCP/IP Options
		1675, // HOST GAME
		1676, // JOIN GAME
		1678, // Enter Host IP Address to Join Game
		1680, // Your IP Address is:
		1689, // Tip: host game
		1690, // Tip: join game
		1691, // Cannot detect a valid TCP/IP address.
		1694, // Character Name
		1696, // Hardcore
		1697, // Select Hero Class

		1698, // amazon description
		1704, // nec description
		1709, // barb description
		1710, // sorc description
		1711, // pal description
		/*in addition, as many elements as the value
		  of the highest modifier must be listed*/
		1712,

		/* here, should be labels used to battle.net multiplayer, but they are not used yet,
		   therefore I don't list them here.*/

		// difficulty levels:
		1800, // Hell
		1864, // Nightmare
		1865, // Normal
		1867, // Select Difficulty

		1869, // not used, for locales with +1 mod
		1878, // delete char confirm
		1881, // Open
		1889, // char name is currently taken (not used)
		1896, // YES
		1925, // NO

		1926, // not used, for locales with +1 mod

		970, // EXIT
		971, // OK
		1612,
	}

	return baseLabelNumbers[idx]
}


================================================
FILE: d2common/d2enum/object_animation_mode.go
================================================
package d2enum

//go:generate stringer -linecomment -type ObjectAnimationMode -output object_animation_mode_string.go
//go:generate string2enum -samepkg -linecomment -type ObjectAnimationMode -output object_animation_mode_string2enum.go

// ObjectAnimationMode represents object animation modes
type ObjectAnimationMode int

// Object animation modes
const (
	ObjectAnimationModeNeutral   ObjectAnimationMode = iota // NU
	ObjectAnimationModeOperating                            // OP
	ObjectAnimationModeOpened                               // ON
	ObjectAnimationModeSpecial1                             // S1
	ObjectAnimationModeSpecial2                             // S2
	ObjectAnimationModeSpecial3                             // S3
	ObjectAnimationModeSpecial4                             // S4
	ObjectAnimationModeSpecial5                             // S5
)


================================================
FILE: d2common/d2enum/object_animation_mode_string.go
================================================
// Code generated by "stringer -linecomment -type ObjectAnimationMode -output object_animation_mode_string.go"; DO NOT EDIT.

package d2enum

import "strconv"

func _() {
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{}
	_ = x[ObjectAnimationModeNeutral-0]
	_ = x[ObjectAnimationModeOperating-1]
	_ = x[ObjectAnimationModeOpened-2]
	_ = x[ObjectAnimationModeSpecial1-3]
	_ = x[ObjectAnimationModeSpecial2-4]
	_ = x[ObjectAnimationModeSpecial3-5]
	_ = x[ObjectAnimationModeSpecial4-6]
	_ = x[ObjectAnimationModeSpecial5-7]
}

const _ObjectAnimationMode_name = "NUOPONS1S2S3S4S5"

var _ObjectAnimationMode_index = [...]uint8{0, 2, 4, 6, 8, 10, 12, 14, 16}

func (i ObjectAnimationMode) String() string {
	if i < 0 || i >= ObjectAnimationMode(len(_ObjectAnimationMode_index)-1) {
		return "ObjectAnimationMode(" + strconv.FormatInt(int64(i), 10) + ")"
	}
	return _ObjectAnimationMode_name[_ObjectAnimationMode_index[i]:_ObjectAnimationMode_index[i+1]]
}


================================================
FILE: d2common/d2enum/object_animation_mode_string2enum.go
================================================
// Code generated by "string2enum -samepkg -linecomment -type ObjectAnimationMode -output object_animation_mode_string2enum.go"; DO NOT EDIT.

package d2enum

import "fmt"

// ObjectAnimationModeFromString returns the ObjectAnimationMode enum corresponding to s.
func ObjectAnimationModeFromString(s string) ObjectAnimationMode {
	if len(s) == 0 {
		return 0
	}
	for i := range _ObjectAnimationMode_index[:len(_ObjectAnimationMode_index)-1] {
		if s == _ObjectAnimationMode_name[_ObjectAnimationMode_index[i]:_ObjectAnimationMode_index[i+1]] {
			return ObjectAnimationMode(i)
		}
	}
	panic(fmt.Errorf("unable to locate ObjectAnimationMode enum corresponding to %q", s))
}

func _(s string) {
	// Check for duplicate string values in type "ObjectAnimationMode".
	switch s {
	// 0
	case "NU":
	// 1
	case "OP":
	// 2
	case "ON":
	// 3
	case "S1":
	// 4
	case "S2":
	// 5
	case "S3":
	// 6
	case "S4":
	// 7
	case "S5":
	}
}


================================================
FILE: d2common/d2enum/object_type.go
================================================
package d2enum

// ObjectType is the type of an object
type ObjectType int

// Object types
const (
	ObjectTypePlayer ObjectType = iota
	ObjectTypeCharacter
	ObjectTypeItem
)


================================================
FILE: d2common/d2enum/operator_type.go
================================================
package d2enum

// OperatorType is used for calculating dynamic property values
type OperatorType int // for dynamic properties

const (
	// OpDefault just adds the stat to the unit directly
	OpDefault = OperatorType(iota)

	// Op1 adds opstat.base * statvalue / 100 to the opstat.
	Op1

	// Op2 adds (statvalue * basevalue) / (2 ^ param) to the opstat
	// this does not work properly with any stat other then level because of the
	// way this is updated, it is only refreshed when you re-equip the item,
	// your character is saved or you level up, similar to passive skills, just
	// because it looks like it works in the item description
	// does not mean it does, the game just recalculates the information in the
	// description every frame, while the values remain unchanged serverside.
	Op2

	// Op3 is a percentage based version of op #2
	// look at op #2 for information about the formula behind it, just
	// remember the stat is increased by a percentage rather then by adding
	// an integer.
	Op3

	// Op4 works the same way op #2 works, however the stat bonus is
	// added to the item and not to the player (so that +defense per level
	// properly adds the defense to the armor and not to the character
	// directly!)
	Op4

	// Op5 works like op #4 but is percentage based, it is used for percentage
	// based increase of stats that are found on the item itself, and not stats
	// that are found on the character.
	Op5

	// Op6 works like for op #7, however this adds a plain bonus to the stat, and just
	// like #7 it also doesn't work so I won't bother to explain the arithmetic
	// behind it either.
	Op6

	// Op7 is used to increase a stat based on the current daytime of the game
	// world by a percentage, there is no need to explain the arithmetics
	// behind it because frankly enough it just doesn't work serverside, it
	// only updates clientside so this op is essentially useless.
	Op7

	// Op8 hardcoded to work only with maxmana, this will apply the proper amount
	// of mana to your character based on CharStats.txt for the amount of energy
	// the stat added (doesn't work for non characters)
	Op8

	// Op9 hardcoded to work only with maxhp and maxstamina, this will apply the
	// proper amount of maxhp and maxstamina to your character based on
	// CharStats.txt for the amount of vitality the stat added (doesn't work
	// for non characters)
	Op9

	// Op10 doesn't do anything, this has no switch case in the op function.
	Op10

	// Op11 adds opstat.base * statvalue / 100 similar to 1 and 13, the code just
	// does a few more checks
	Op11

	// Op12 doesn't do anything, this has no switch case in the op function.
	Op12

	// Op13 adds opstat.base * statvalue / 100 to the value of opstat, this is
	// useable only on items it will not apply the bonus to other unit types
	// (this is why it is used for +% durability, +% level requirement,
	// +% damage, +% defense ).
	Op13
)


================================================
FILE: d2common/d2enum/party_buttons.go
================================================
package d2enum

// Frames of party Buttons
const (
	PartyButtonListeningFrame = iota * 4
	PartyButtonRelationshipsFrame
	PartyButtonSeeingFrame
	PartyButtonCorpsLootingFrame

	PartyButtonNextButtonFrame = 2
)


================================================
FILE: d2common/d2enum/pet_icon_type.go
================================================
package d2enum

// PetIconType determines the pet icon type
type PetIconType int

// Pet icon types
// The information has been gathered from [https:// d2mods.info/forum/kb/viewarticle?a=355]
const (
	NoIcon PetIconType = iota
	ShowIconOnly
	ShowIconAndQuantity // Quantity, such as the number of skeletons
	ShowIconOnly2
)


================================================
FILE: d2common/d2enum/player_animation_mode.go
================================================
package d2enum

//go:generate stringer -linecomment -type PlayerAnimationMode -output player_animation_mode_string.go

// PlayerAnimationMode represents player animation modes
type PlayerAnimationMode int

// Player animation modes
const (
	PlayerAnimationModeDeath       PlayerAnimationMode = iota // DT
	PlayerAnimationModeNeutral                                // NU
	PlayerAnimationModeWalk                                   // WL
	PlayerAnimationModeRun                                    // RN
	PlayerAnimationModeGetHit                                 // GH
	PlayerAnimationModeTownNeutra
Download .txt
gitextract_unj84ffm/

├── .circleci/
│   └── config.yml
├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── dependabot.yml
│   └── workflows/
│       └── auto-author-assign.yml
├── .gitignore
├── .golangci.yml
├── .vscode/
│   └── extensions.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTORS
├── LICENSE
├── README.md
├── build.sh
├── d2app/
│   ├── app.go
│   ├── capture_state.go
│   ├── console_commands.go
│   └── initialization.go
├── d2common/
│   ├── d2cache/
│   │   ├── cache.go
│   │   ├── cache_test.go
│   │   └── doc.go
│   ├── d2calculation/
│   │   ├── calcstring.go
│   │   ├── calculation.go
│   │   ├── d2lexer/
│   │   │   ├── lexer.go
│   │   │   └── lexer_test.go
│   │   └── d2parser/
│   │       ├── d2parser.go
│   │       ├── operations.go
│   │       ├── parser.go
│   │       └── parser_test.go
│   ├── d2data/
│   │   ├── d2compression/
│   │   │   ├── huffman.go
│   │   │   └── wav.go
│   │   ├── d2video/
│   │   │   ├── binkdecoder.go
│   │   │   └── doc.go
│   │   └── doc.go
│   ├── d2datautils/
│   │   ├── bitmuncher.go
│   │   ├── bitmuncher_test.go
│   │   ├── bitstream.go
│   │   ├── bitstream_test.go
│   │   ├── doc.go
│   │   ├── stream_reader.go
│   │   ├── stream_reader_test.go
│   │   ├── stream_writer.go
│   │   └── stream_writer_test.go
│   ├── d2enum/
│   │   ├── animation_frame.go
│   │   ├── animation_frame_direction.go
│   │   ├── animation_frame_event.go
│   │   ├── composite_type.go
│   │   ├── composite_type_string.go
│   │   ├── difficulty.go
│   │   ├── doc.go
│   │   ├── draw_effect.go
│   │   ├── encoding_type.go
│   │   ├── equipped_slot.go
│   │   ├── filter.go
│   │   ├── game_event.go
│   │   ├── hero.go
│   │   ├── hero_stance.go
│   │   ├── hero_string.go
│   │   ├── hero_string2enum.go
│   │   ├── input_button.go
│   │   ├── input_key.go
│   │   ├── input_priority.go
│   │   ├── inventory_item_type.go
│   │   ├── item_affix_type.go
│   │   ├── item_armor_class.go
│   │   ├── item_event_functions.go
│   │   ├── item_events.go
│   │   ├── item_quality.go
│   │   ├── level_generation_types.go
│   │   ├── level_teleport_flags.go
│   │   ├── monster_alignment_type.go
│   │   ├── monster_animation_mode.go
│   │   ├── monster_animation_mode_string.go
│   │   ├── monster_combat_type.go
│   │   ├── monumod_const_index.go
│   │   ├── npc_action_type.go
│   │   ├── numeric_labels.go
│   │   ├── object_animation_mode.go
│   │   ├── object_animation_mode_string.go
│   │   ├── object_animation_mode_string2enum.go
│   │   ├── object_type.go
│   │   ├── operator_type.go
│   │   ├── party_buttons.go
│   │   ├── pet_icon_type.go
│   │   ├── player_animation_mode.go
│   │   ├── player_animation_mode_string.go
│   │   ├── players_relationships.go
│   │   ├── quests.go
│   │   ├── readme.md
│   │   ├── region_id.go
│   │   ├── region_layer.go
│   │   ├── render_type.go
│   │   ├── skill_class.go
│   │   ├── terminal_category.go
│   │   ├── tile.go
│   │   ├── weapon_class.go
│   │   ├── weapon_class_string.go
│   │   └── weapon_class_string2enum.go
│   ├── d2fileformats/
│   │   ├── d2animdata/
│   │   │   ├── animdata.go
│   │   │   ├── animdata_test.go
│   │   │   ├── block.go
│   │   │   ├── doc.go
│   │   │   ├── events.go
│   │   │   ├── hash.go
│   │   │   ├── record.go
│   │   │   └── testdata/
│   │   │       ├── AnimData.d2
│   │   │       └── BadData.d2
│   │   ├── d2cof/
│   │   │   ├── cof.go
│   │   │   ├── cof_dir_lookup.go
│   │   │   ├── cof_layer.go
│   │   │   ├── cof_test.go
│   │   │   ├── doc.go
│   │   │   └── helpers.go
│   │   ├── d2dat/
│   │   │   ├── dat.go
│   │   │   ├── dat_color.go
│   │   │   ├── dat_palette.go
│   │   │   └── doc.go
│   │   ├── d2dc6/
│   │   │   ├── dc6.go
│   │   │   ├── dc6.ksy
│   │   │   ├── dc6_frame.go
│   │   │   ├── dc6_frame_header.go
│   │   │   ├── dc6_header.go
│   │   │   ├── dc6_test.go
│   │   │   └── doc.go
│   │   ├── d2dcc/
│   │   │   ├── dcc.go
│   │   │   ├── dcc_cell.go
│   │   │   ├── dcc_dir_lookup.go
│   │   │   ├── dcc_direction.go
│   │   │   ├── dcc_direction_frame.go
│   │   │   ├── dcc_pixel_buffer_entry.go
│   │   │   └── doc.go
│   │   ├── d2ds1/
│   │   │   ├── doc.go
│   │   │   ├── ds1.go
│   │   │   ├── ds1_layers.go
│   │   │   ├── ds1_layers_test.go
│   │   │   ├── ds1_test.go
│   │   │   ├── ds1_version.go
│   │   │   ├── layer.go
│   │   │   ├── layer_test.go
│   │   │   ├── object.go
│   │   │   ├── substitution_group.go
│   │   │   └── tile.go
│   │   ├── d2dt1/
│   │   │   ├── block.go
│   │   │   ├── doc.go
│   │   │   ├── dt1.go
│   │   │   ├── gfx_decode.go
│   │   │   ├── material.go
│   │   │   ├── subtile.go
│   │   │   ├── subtile_test.go
│   │   │   └── tile.go
│   │   ├── d2font/
│   │   │   ├── d2fontglyph/
│   │   │   │   └── font_glyph.go
│   │   │   ├── doc.go
│   │   │   └── font.go
│   │   ├── d2mpq/
│   │   │   ├── crypto.go
│   │   │   ├── doc.go
│   │   │   ├── mpq.go
│   │   │   ├── mpq_block.go
│   │   │   ├── mpq_data_stream.go
│   │   │   ├── mpq_file_record.go
│   │   │   ├── mpq_hash.go
│   │   │   ├── mpq_header.go
│   │   │   └── mpq_stream.go
│   │   ├── d2pl2/
│   │   │   ├── doc.go
│   │   │   ├── pl2.go
│   │   │   ├── pl2_color.go
│   │   │   ├── pl2_color_24bits.go
│   │   │   ├── pl2_palette.go
│   │   │   ├── pl2_palette_transform.go
│   │   │   └── pl2_test.go
│   │   ├── d2tbl/
│   │   │   ├── doc.go
│   │   │   ├── text_dictionary.go
│   │   │   └── text_dictionary_test.go
│   │   └── d2txt/
│   │       ├── data_dictionary.go
│   │       └── doc.go
│   ├── d2geom/
│   │   ├── doc.go
│   │   ├── point.go
│   │   ├── rectangle.go
│   │   └── size.go
│   ├── d2interface/
│   │   ├── animation.go
│   │   ├── archive.go
│   │   ├── audio_provider.go
│   │   ├── cache.go
│   │   ├── data_stream.go
│   │   ├── doc.go
│   │   ├── input_events.go
│   │   ├── input_handlers.go
│   │   ├── input_manager.go
│   │   ├── input_service.go
│   │   ├── map_entity.go
│   │   ├── navigate.go
│   │   ├── palette.go
│   │   ├── renderer.go
│   │   ├── sound_effect.go
│   │   ├── surface.go
│   │   └── terminal.go
│   ├── d2loader/
│   │   ├── asset/
│   │   │   ├── asset.go
│   │   │   ├── doc.go
│   │   │   ├── source.go
│   │   │   └── types/
│   │   │       ├── asset_types.go
│   │   │       ├── doc.go
│   │   │       └── source_types.go
│   │   ├── doc.go
│   │   ├── filesystem/
│   │   │   ├── asset.go
│   │   │   ├── doc.go
│   │   │   ├── loader_provider.go
│   │   │   └── source.go
│   │   ├── loader.go
│   │   ├── loader_test.go
│   │   ├── mpq/
│   │   │   ├── asset.go
│   │   │   ├── doc.go
│   │   │   └── source.go
│   │   └── testdata/
│   │       ├── A/
│   │       │   ├── common.txt
│   │       │   └── exclusive_a.txt
│   │       ├── B/
│   │       │   ├── common.txt
│   │       │   └── exclusive_b.txt
│   │       ├── C/
│   │       │   ├── common.txt
│   │       │   └── exclusive_c.txt
│   │       └── D.mpq
│   ├── d2math/
│   │   ├── d2vector/
│   │   │   ├── doc.go
│   │   │   ├── position.go
│   │   │   ├── position_test.go
│   │   │   ├── vector.go
│   │   │   └── vector_test.go
│   │   ├── doc.go
│   │   ├── math.go
│   │   ├── math_test.go
│   │   ├── ranged_number.go
│   │   └── ranged_number_test.go
│   ├── d2path/
│   │   ├── doc.go
│   │   └── path.go
│   ├── d2resource/
│   │   ├── doc.go
│   │   ├── languages_map.go
│   │   ├── music_defs.go
│   │   └── resource_paths.go
│   ├── d2util/
│   │   ├── assets/
│   │   │   ├── assets.go
│   │   │   └── zipbmp.go
│   │   ├── debug_print.go
│   │   ├── doc.go
│   │   ├── logger.go
│   │   ├── logger_test.go
│   │   ├── palette.go
│   │   ├── rgba_color.go
│   │   ├── stringutils.go
│   │   └── timeutils.go
│   └── doc.go
├── d2core/
│   ├── d2asset/
│   │   ├── animation.go
│   │   ├── asset_manager.go
│   │   ├── composite.go
│   │   ├── d2asset.go
│   │   ├── dc6_animation.go
│   │   ├── dcc_animation.go
│   │   └── doc.go
│   ├── d2audio/
│   │   ├── doc.go
│   │   ├── ebiten/
│   │   │   ├── ebiten_audio_provider.go
│   │   │   └── ebiten_sound_effect.go
│   │   ├── sound_engine.go
│   │   └── sound_environment.go
│   ├── d2config/
│   │   ├── d2config.go
│   │   ├── default_directories.go
│   │   ├── defaults.go
│   │   └── doc.go
│   ├── d2gui/
│   │   ├── box.go
│   │   ├── button.go
│   │   ├── common.go
│   │   ├── doc.go
│   │   ├── gui_manager.go
│   │   ├── label.go
│   │   ├── label_button.go
│   │   ├── layout.go
│   │   ├── layout_entry.go
│   │   ├── layout_scrollbar.go
│   │   ├── spacer.go
│   │   ├── sprite.go
│   │   ├── style.go
│   │   └── widget.go
│   ├── d2hero/
│   │   ├── doc.go
│   │   ├── hero_skill.go
│   │   ├── hero_skill_util.go
│   │   ├── hero_state.go
│   │   ├── hero_state_factory.go
│   │   └── hero_stats_state.go
│   ├── d2input/
│   │   ├── d2input.go
│   │   ├── doc.go
│   │   ├── ebiten/
│   │   │   └── ebiten_input.go
│   │   ├── handler_event.go
│   │   ├── input_manager.go
│   │   ├── key_event.go
│   │   ├── keychars_event.go
│   │   ├── mouse_event.go
│   │   └── mousemove_event.go
│   ├── d2inventory/
│   │   ├── character_equipment.go
│   │   ├── doc.go
│   │   ├── hero_objects.go
│   │   ├── inventory_item.go
│   │   ├── inventory_item_armor.go
│   │   ├── inventory_item_factory.go
│   │   ├── inventory_item_misc.go
│   │   └── inventory_item_weapon.go
│   ├── d2item/
│   │   ├── context.go
│   │   ├── diablo2item/
│   │   │   ├── doc.go
│   │   │   ├── item.go
│   │   │   ├── item_factory.go
│   │   │   ├── item_property.go
│   │   │   └── item_property_test.go
│   │   ├── doc.go
│   │   ├── equipper.go
│   │   └── item.go
│   ├── d2map/
│   │   ├── d2mapengine/
│   │   │   ├── doc.go
│   │   │   ├── engine.go
│   │   │   ├── map_tile.go
│   │   │   └── pathfind.go
│   │   ├── d2mapentity/
│   │   │   ├── animated_entity.go
│   │   │   ├── cast_overlay.go
│   │   │   ├── doc.go
│   │   │   ├── factory.go
│   │   │   ├── item.go
│   │   │   ├── map_entity.go
│   │   │   ├── map_entity_test.go
│   │   │   ├── missile.go
│   │   │   ├── npc.go
│   │   │   ├── object.go
│   │   │   ├── object_init.go
│   │   │   └── player.go
│   │   ├── d2mapgen/
│   │   │   ├── act1_overworld.go
│   │   │   ├── d2wilderness/
│   │   │   │   └── wilderness_tile_types.go
│   │   │   ├── doc.go
│   │   │   └── map_generator.go
│   │   ├── d2maprenderer/
│   │   │   ├── camera.go
│   │   │   ├── doc.go
│   │   │   ├── renderer.go
│   │   │   ├── tile_cache.go
│   │   │   └── viewport.go
│   │   └── d2mapstamp/
│   │       ├── doc.go
│   │       ├── factory.go
│   │       └── stamp.go
│   ├── d2records/
│   │   ├── armor_type_loader.go
│   │   ├── armor_type_record.go
│   │   ├── automagic_loader.go
│   │   ├── automagic_record.go
│   │   ├── automap_loader.go
│   │   ├── automap_record.go
│   │   ├── belts_loader.go
│   │   ├── belts_record.go
│   │   ├── body_locations_loader.go
│   │   ├── body_locations_record.go
│   │   ├── books_loader.go
│   │   ├── books_record.go
│   │   ├── calculations_loader.go
│   │   ├── calculations_record.go
│   │   ├── charstats_loader.go
│   │   ├── charstats_record.go
│   │   ├── color_loader.go
│   │   ├── color_record.go
│   │   ├── component_codes_loader.go
│   │   ├── component_codes_record.go
│   │   ├── composite_type_loader.go
│   │   ├── composite_type_record.go
│   │   ├── constants.go
│   │   ├── cube_modifier_loader.go
│   │   ├── cube_modifier_record.go
│   │   ├── cube_type_loader.go
│   │   ├── cube_type_record.go
│   │   ├── cubemain_loader.go
│   │   ├── cubemain_record.go
│   │   ├── difficultylevels_loader.go
│   │   ├── difficultylevels_record.go
│   │   ├── doc.go
│   │   ├── elemtype_loader.go
│   │   ├── elemtype_record.go
│   │   ├── events_loader.go
│   │   ├── events_record.go
│   │   ├── experience_loader.go
│   │   ├── experience_record.go
│   │   ├── gamble_loader.go
│   │   ├── gamble_record.go
│   │   ├── gems_loader.go
│   │   ├── gems_record.go
│   │   ├── hireling_description_loader.go
│   │   ├── hireling_description_record.go
│   │   ├── hireling_loader.go
│   │   ├── hireling_record.go
│   │   ├── hit_class_loader.go
│   │   ├── hit_class_record.go
│   │   ├── inventory_loader.go
│   │   ├── inventory_record.go
│   │   ├── item_affix_loader.go
│   │   ├── item_affix_record.go
│   │   ├── item_armor_loader.go
│   │   ├── item_common_loader.go
│   │   ├── item_common_record.go
│   │   ├── item_low_quality_loader.go
│   │   ├── item_low_quality_record.go
│   │   ├── item_misc_loader.go
│   │   ├── item_quality_loader.go
│   │   ├── item_quality_record.go
│   │   ├── item_ratio_loader.go
│   │   ├── item_ratio_record.go
│   │   ├── item_types_loader.go
│   │   ├── item_types_record.go
│   │   ├── item_weapons_loader.go
│   │   ├── itemstatcost_loader.go
│   │   ├── itemstatcost_record.go
│   │   ├── level_details_loader.go
│   │   ├── level_details_record.go
│   │   ├── level_maze_loader.go
│   │   ├── level_maze_record.go
│   │   ├── level_presets_loader.go
│   │   ├── level_presets_record.go
│   │   ├── level_substitutions_loader.go
│   │   ├── level_substitutions_record.go
│   │   ├── level_types_loader.go
│   │   ├── level_types_record.go
│   │   ├── level_warp_loader.go
│   │   ├── level_warp_record.go
│   │   ├── missiles_loader.go
│   │   ├── missiles_record.go
│   │   ├── monster_ai_loader.go
│   │   ├── monster_ai_record.go
│   │   ├── monster_equipment_loader.go
│   │   ├── monster_equipment_record.go
│   │   ├── monster_levels_loader.go
│   │   ├── monster_levels_record.go
│   │   ├── monster_mode_loader.go
│   │   ├── monster_mode_record.go
│   │   ├── monster_placement_loader.go
│   │   ├── monster_placement_record.go
│   │   ├── monster_preset_loader.go
│   │   ├── monster_preset_record.go
│   │   ├── monster_property_loader.go
│   │   ├── monster_property_record.go
│   │   ├── monster_sequence_loader.go
│   │   ├── monster_sequence_record.go
│   │   ├── monster_sound_loader.go
│   │   ├── monster_sound_record.go
│   │   ├── monster_stats2_loader.go
│   │   ├── monster_stats2_record.go
│   │   ├── monster_stats_loader.go
│   │   ├── monster_stats_record.go
│   │   ├── monster_super_unique_loader.go
│   │   ├── monster_super_unique_record.go
│   │   ├── monster_type_loader.go
│   │   ├── monster_type_record.go
│   │   ├── monster_unique_affix_loader.go
│   │   ├── monster_unique_affix_record.go
│   │   ├── monster_unique_modifiers_loader.go
│   │   ├── monster_unique_modifiers_record.go
│   │   ├── npc_loader.go
│   │   ├── npc_record.go
│   │   ├── object_details_loader.go
│   │   ├── object_details_record.go
│   │   ├── object_groups_loader.go
│   │   ├── object_groups_record.go
│   │   ├── object_lookup_record.go
│   │   ├── object_lookup_record_data.go
│   │   ├── object_lookup_record_test.go
│   │   ├── object_mode_loader.go
│   │   ├── object_mode_record.go
│   │   ├── object_types_loader.go
│   │   ├── object_types_record.go
│   │   ├── overlays_loader.go
│   │   ├── overlays_record.go
│   │   ├── pet_type_loader.go
│   │   ├── pet_type_record.go
│   │   ├── player_class_loader.go
│   │   ├── player_class_record.go
│   │   ├── player_mode_loader.go
│   │   ├── player_mode_record.go
│   │   ├── player_type_loader.go
│   │   ├── player_type_record.go
│   │   ├── property_descriptor.go
│   │   ├── property_loader.go
│   │   ├── property_record.go
│   │   ├── rare_affix.go
│   │   ├── rare_affix_loader.go
│   │   ├── rare_prefix_loader.go
│   │   ├── rare_prefix_record.go
│   │   ├── rare_suffix_loader.go
│   │   ├── rare_suffix_record.go
│   │   ├── record_loader.go
│   │   ├── record_manager.go
│   │   ├── runeword_loader.go
│   │   ├── runeword_record.go
│   │   ├── set_item_loader.go
│   │   ├── set_item_record.go
│   │   ├── set_loader.go
│   │   ├── set_record.go
│   │   ├── shrine_loader.go
│   │   ├── shrine_record.go
│   │   ├── skill_description_loader.go
│   │   ├── skill_description_record.go
│   │   ├── skill_details_loader.go
│   │   ├── skill_details_record.go
│   │   ├── sound_details_loader.go
│   │   ├── sound_details_record.go
│   │   ├── sound_environment_loader.go
│   │   ├── sound_environment_record.go
│   │   ├── states_loader.go
│   │   ├── states_record.go
│   │   ├── storepage_loader.go
│   │   ├── storepage_record.go
│   │   ├── treasure_class_loader.go
│   │   ├── treasure_class_record.go
│   │   ├── unique_appellation_loader.go
│   │   ├── unique_appellations_record.go
│   │   ├── unique_items_loader.go
│   │   ├── unique_items_record.go
│   │   ├── weapon_class_loader.go
│   │   └── weapon_class_record.go
│   ├── d2render/
│   │   └── ebiten/
│   │       ├── doc.go
│   │       ├── ebiten_panic_screen.go
│   │       ├── ebiten_renderer.go
│   │       ├── ebiten_surface.go
│   │       ├── filter_helper.go
│   │       └── surface_state.go
│   ├── d2screen/
│   │   ├── d2screen.go
│   │   ├── doc.go
│   │   ├── loading_state.go
│   │   ├── loading_update.go
│   │   └── screen_manager.go
│   ├── d2stats/
│   │   ├── diablo2stats/
│   │   │   ├── doc.go
│   │   │   ├── stat.go
│   │   │   ├── stat_factory.go
│   │   │   ├── stat_test.go
│   │   │   ├── stat_value.go
│   │   │   ├── stat_value_stringers.go
│   │   │   ├── statlist.go
│   │   │   └── statlist_test.go
│   │   ├── doc.go
│   │   ├── stat.go
│   │   ├── stat_list.go
│   │   └── stat_value.go
│   ├── d2term/
│   │   ├── commmand.go
│   │   ├── d2term.go
│   │   ├── doc.go
│   │   ├── terminal.go
│   │   ├── terminal_logger.go
│   │   └── terminal_test.go
│   └── d2ui/
│       ├── button.go
│       ├── checkbox.go
│       ├── color_tokens.go
│       ├── custom_widget.go
│       ├── d2ui.go
│       ├── doc.go
│       ├── drawable.go
│       ├── frame.go
│       ├── label.go
│       ├── label_button.go
│       ├── scrollbar.go
│       ├── sprite.go
│       ├── switchable_button.go
│       ├── textbox.go
│       ├── tooltip.go
│       ├── ui_manager.go
│       ├── widget.go
│       └── widget_group.go
├── d2game/
│   ├── d2gamescreen/
│   │   ├── blizzard_intro.go
│   │   ├── character_select.go
│   │   ├── cinematics.go
│   │   ├── credits.go
│   │   ├── doc.go
│   │   ├── game.go
│   │   ├── gui_testing.go
│   │   ├── main_menu.go
│   │   ├── map_engine_testing.go
│   │   └── select_hero_class.go
│   └── d2player/
│       ├── binding_layout.go
│       ├── doc.go
│       ├── equipment_slot.go
│       ├── escape_menu.go
│       ├── game_controls.go
│       ├── globeWidget.go
│       ├── help_overlay.go
│       ├── hero_stats_panel.go
│       ├── hud.go
│       ├── input_callback_listener.go
│       ├── inventory.go
│       ├── inventory_grid.go
│       ├── key_binding_menu.go
│       ├── key_map.go
│       ├── mini_panel.go
│       ├── move_gold_panel.go
│       ├── party_panel.go
│       ├── quest_log.go
│       ├── skill_row.go
│       ├── skill_select_menu.go
│       ├── skill_select_panel.go
│       ├── skillicon.go
│       └── skilltree.go
├── d2networking/
│   ├── client_listener.go
│   ├── d2client/
│   │   ├── d2clientconnectiontype/
│   │   │   ├── connectiontype.go
│   │   │   └── doc.go
│   │   ├── d2localclient/
│   │   │   ├── doc.go
│   │   │   └── local_client_connection.go
│   │   ├── d2remoteclient/
│   │   │   ├── doc.go
│   │   │   └── remote_client_connection.go
│   │   ├── doc.go
│   │   ├── game_client.go
│   │   └── server_connection.go
│   ├── d2netpacket/
│   │   ├── d2netpackettype/
│   │   │   ├── doc.go
│   │   │   └── message_type.go
│   │   ├── doc.go
│   │   ├── net_packet.go
│   │   ├── packet_add_player.go
│   │   ├── packet_generate_map.go
│   │   ├── packet_item_spawn.go
│   │   ├── packet_move_player.go
│   │   ├── packet_ping.go
│   │   ├── packet_player_cast.go
│   │   ├── packet_player_connection_request.go
│   │   ├── packet_player_disconnect_request.go
│   │   ├── packet_pong.go
│   │   ├── packet_save_player.go
│   │   ├── packet_server_closed.go
│   │   ├── packet_server_full.go
│   │   └── packet_update_server_info.go
│   ├── d2server/
│   │   ├── client_connection.go
│   │   ├── d2tcpclientconnection/
│   │   │   └── tcp_client_connection.go
│   │   ├── d2udpclientconnection/
│   │   │   └── udp_client_connection.go
│   │   ├── doc.go
│   │   └── game_server.go
│   ├── dedicated_server.go
│   └── doc.go
├── d2script/
│   ├── doc.go
│   └── engine.go
├── d2thread/
│   └── mainthread.go
├── docs/
│   ├── CNAME
│   ├── CONTRIBUTING.md
│   ├── building.md
│   ├── debug.md
│   ├── development.md
│   ├── faq.md
│   ├── index.html
│   ├── install.md
│   ├── mpq.md
│   ├── play.md
│   ├── profiling.md
│   ├── purchase.md
│   ├── roadmap.md
│   ├── status.md
│   └── style.css
├── go.mod
├── go.sum
├── main.go
├── scripts/
│   ├── server/
│   │   └── server.js
│   └── test.js
├── tagdev.bat
└── utils/
    └── extract-mpq/
        ├── doc.go
        └── extract-mpq.go
Download .txt
Showing preview only (462K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (5639 symbols across 535 files)

FILE: d2app/app.go
  constant fpsX (line 49) | fpsX, fpsY         = 5, 565
  constant memInfoX (line 50) | memInfoX, memInfoY = 670, 5
  constant debugLineHeight (line 51) | debugLineHeight    = 16
  constant errMsgPadding (line 52) | errMsgPadding      = 20
  type App (line 56) | type App struct
    method startDedicatedServer (line 132) | func (a *App) startDedicatedServer() error {
    method loadEngine (line 159) | func (a *App) loadEngine() error {
    method parseArguments (line 195) | func (a *App) parseArguments() {
    method LoadConfig (line 237) | func (a *App) LoadConfig() (*d2config.Configuration, error) {
    method Run (line 270) | func (a *App) Run() (err error) {
    method renderDebug (line 324) | func (a *App) renderDebug(target d2interface.Surface) {
    method renderCapture (line 355) | func (a *App) renderCapture(target d2interface.Surface) error {
    method render (line 384) | func (a *App) render(target d2interface.Surface) {
    method advance (line 403) | func (a *App) advance() error {
    method update (line 434) | func (a *App) update(target d2interface.Surface) error {
    method allocRate (line 444) | func (a *App) allocRate(totalAlloc uint64, fps float64) float64 {
    method doCaptureFrame (line 452) | func (a *App) doCaptureFrame(target d2interface.Surface) error {
    method doCaptureGif (line 474) | func (a *App) doCaptureGif(target d2interface.Surface) {
    method convertFramesToGif (line 479) | func (a *App) convertFramesToGif() error {
    method updateInitError (line 587) | func (a *App) updateInitError(target d2interface.Surface) error {
    method ToMainMenu (line 596) | func (a *App) ToMainMenu(errorMessageOptional ...string) {
    method ToSelectHero (line 610) | func (a *App) ToSelectHero(connType d2clientconnectiontype.ClientConne...
    method ToCreateGame (line 621) | func (a *App) ToCreateGame(filePath string, connType d2clientconnectio...
    method ToCharacterSelect (line 649) | func (a *App) ToCharacterSelect(connType d2clientconnectiontype.Client...
    method ToMapEngineTest (line 660) | func (a *App) ToMapEngineTest(region, level int) {
    method ToCredits (line 672) | func (a *App) ToCredits() {
    method ToCinematics (line 677) | func (a *App) ToCinematics() {
  type Options (line 85) | type Options struct
  constant bytesToMegabyte (line 93) | bytesToMegabyte = 1024 * 1024
  constant nSamplesTAlloc (line 94) | nSamplesTAlloc  = 100
  constant debugPopN (line 95) | debugPopN       = 6
  constant appLoggerPrefix (line 99) | appLoggerPrefix = "App"
  function Create (line 103) | func Create(gitBranch, gitCommit string) *App {
  function updateNOOP (line 128) | func updateNOOP() error {
  function createZeroedRing (line 534) | func createZeroedRing(n int) *ring.Ring {
  function enableProfiler (line 544) | func enableProfiler(profileOption string, a *App) interface{ Stop() } {

FILE: d2app/capture_state.go
  type captureState (line 3) | type captureState
  constant captureStateNone (line 6) | captureStateNone captureState = iota
  constant captureStateFrame (line 7) | captureStateFrame
  constant captureStateGif (line 8) | captureStateGif

FILE: d2app/console_commands.go
  method initTerminalCommands (line 11) | func (a *App) initTerminalCommands() {
  method dumpHeap (line 38) | func (a *App) dumpHeap([]string) error {
  method evalJS (line 61) | func (a *App) evalJS(args []string) error {
  method toggleFullScreen (line 73) | func (a *App) toggleFullScreen([]string) error {
  method setupCaptureFrame (line 81) | func (a *App) setupCaptureFrame(args []string) error {
  method startAnimationCapture (line 89) | func (a *App) startAnimationCapture(args []string) error {
  method stopAnimationCapture (line 97) | func (a *App) stopAnimationCapture([]string) error {
  method toggleVsync (line 103) | func (a *App) toggleVsync([]string) error {
  method toggleFpsCounter (line 111) | func (a *App) toggleFpsCounter([]string) error {
  method setTimeScale (line 118) | func (a *App) setTimeScale(args []string) error {
  method quitGame (line 131) | func (a *App) quitGame([]string) error {
  method enterGuiPlayground (line 136) | func (a *App) enterGuiPlayground([]string) error {

FILE: d2app/initialization.go
  method initialize (line 17) | func (a *App) initialize() error {
  constant fmtErrSourceNotFound (line 57) | fmtErrSourceNotFound = `file not found: %q
  method initConfig (line 67) | func (a *App) initConfig(config *d2config.Configuration) error {
  method initLanguage (line 84) | func (a *App) initLanguage() {
  method initDataDictionaries (line 92) | func (a *App) initDataDictionaries() error {
  constant fmtLoadAnimData (line 142) | fmtLoadAnimData = "loading animation data from: %s"
  method initAnimationData (line 145) | func (a *App) initAnimationData(path string) error {
  method loadStrings (line 165) | func (a *App) loadStrings() error {

FILE: d2common/d2cache/cache.go
  type cacheNode (line 13) | type cacheNode struct
  type Cache (line 22) | type Cache struct
    method SetVerbose (line 38) | func (c *Cache) SetVerbose(verbose bool) {
    method GetWeight (line 43) | func (c *Cache) GetWeight() int {
    method GetBudget (line 48) | func (c *Cache) GetBudget() int {
    method Insert (line 53) | func (c *Cache) Insert(key string, value interface{}, weight int) error {
    method Retrieve (line 102) | func (c *Cache) Retrieve(key string) (interface{}, bool) {
    method Clear (line 138) | func (c *Cache) Clear() {
  function CreateCache (line 33) | func CreateCache(budget int) d2interface.Cache {

FILE: d2common/d2cache/cache_test.go
  function TestCacheInsert (line 7) | func TestCacheInsert(t *testing.T) {
  function TestCacheInsertWithinBudget (line 16) | func TestCacheInsertWithinBudget(t *testing.T) {
  function TestCacheInsertUpdatesWeight (line 25) | func TestCacheInsertUpdatesWeight(t *testing.T) {
  function TestCacheInsertDuplicateRejected (line 36) | func TestCacheInsertDuplicateRejected(t *testing.T) {
  function TestCacheInsertEvictsLeastRecentlyUsed (line 46) | func TestCacheInsertEvictsLeastRecentlyUsed(t *testing.T) {
  function TestCacheInsertEvictsLeastRecentlyRetrieved (line 67) | func TestCacheInsertEvictsLeastRecentlyRetrieved(t *testing.T) {
  function TestClear (line 84) | func TestClear(t *testing.T) {

FILE: d2common/d2calculation/calcstring.go
  type CalcString (line 6) | type CalcString

FILE: d2common/d2calculation/calculation.go
  type Calculation (line 10) | type Calculation interface
  type BinaryCalculation (line 16) | type BinaryCalculation struct
    method Eval (line 28) | func (node *BinaryCalculation) Eval() int {
    method String (line 32) | func (node *BinaryCalculation) String() string {
  type UnaryCalculation (line 37) | type UnaryCalculation struct
    method Eval (line 46) | func (node *UnaryCalculation) Eval() int {
    method String (line 50) | func (node *UnaryCalculation) String() string {
  type TernaryCalculation (line 55) | type TernaryCalculation struct
    method Eval (line 68) | func (node *TernaryCalculation) Eval() int {
    method String (line 72) | func (node *TernaryCalculation) String() string {
  type PropertyReferenceCalculation (line 77) | type PropertyReferenceCalculation struct
    method Eval (line 84) | func (node *PropertyReferenceCalculation) Eval() int {
    method String (line 88) | func (node *PropertyReferenceCalculation) String() string {
  type ConstantCalculation (line 93) | type ConstantCalculation struct
    method Eval (line 99) | func (node *ConstantCalculation) Eval() int {
    method String (line 103) | func (node *ConstantCalculation) String() string {

FILE: d2common/d2calculation/d2lexer/lexer.go
  type tokenType (line 11) | type tokenType
    method String (line 30) | func (t tokenType) String() string {
  constant Name (line 15) | Name tokenType = iota
  constant String (line 18) | String
  constant Symbol (line 21) | Symbol
  constant Number (line 24) | Number
  constant EOF (line 27) | EOF
  type Token (line 41) | type Token struct
    method String (line 46) | func (t *Token) String() string {
  type Lexer (line 51) | type Lexer struct
    method peekNext (line 66) | func (l *Lexer) peekNext() (byte, error) {
    method extractOpToken (line 74) | func (l *Lexer) extractOpToken() Token {
    method extractNumber (line 101) | func (l *Lexer) extractNumber() Token {
    method extractString (line 112) | func (l *Lexer) extractString() Token {
    method extractName (line 125) | func (l *Lexer) extractName() Token {
    method Peek (line 140) | func (l *Lexer) Peek() Token {
    method NextToken (line 178) | func (l *Lexer) NextToken() Token {
  function New (line 60) | func New(input []byte) *Lexer {

FILE: d2common/d2calculation/d2lexer/lexer_test.go
  function TestName (line 7) | func TestName(t *testing.T) {
  function TestNumber (line 32) | func TestNumber(t *testing.T) {
  function TestSymbol (line 56) | func TestSymbol(t *testing.T) {
  function TestString (line 101) | func TestString(t *testing.T) {
  function TestActualConstructions (line 125) | func TestActualConstructions(t *testing.T) {

FILE: d2common/d2calculation/d2parser/operations.go
  type binaryOperation (line 8) | type binaryOperation struct
  type unaryOperation (line 15) | type unaryOperation struct
  type ternaryOperation (line 21) | type ternaryOperation struct
  function getUnaryOperations (line 29) | func getUnaryOperations() map[string]unaryOperation {
  function getTernaryOperations (line 48) | func getTernaryOperations() map[string]ternaryOperation {
  function getBinaryOperations (line 65) | func getBinaryOperations() map[string]binaryOperation { //nolint:funlen ...
  function getFunctions (line 176) | func getFunctions() map[string]func(v1, v2 int) int {

FILE: d2common/d2calculation/d2parser/parser.go
  type Parser (line 13) | type Parser struct
    method SetCurrentReference (line 36) | func (parser *Parser) SetCurrentReference(propType, propName string) {
    method Parse (line 42) | func (parser *Parser) Parse(calc string) d2calculation.Calculation {
    method peek (line 59) | func (parser *Parser) peek() d2lexer.Token {
    method consume (line 63) | func (parser *Parser) consume() d2lexer.Token {
    method parseLevel (line 67) | func (parser *Parser) parseLevel(level int) d2calculation.Calculation {
    method parseProduction (line 146) | func (parser *Parser) parseProduction() d2calculation.Calculation {
    method parseLeafCalculation (line 190) | func (parser *Parser) parseLeafCalculation() d2calculation.Calculation {
    method parseFunction (line 227) | func (parser *Parser) parseFunction(name string) d2calculation.Calcula...
    method parseProperty (line 263) | func (parser *Parser) parseProperty() d2calculation.Calculation {
  function New (line 26) | func New() *Parser {

FILE: d2common/d2calculation/d2parser/parser_test.go
  function TestEmptyInput (line 9) | func TestEmptyInput(t *testing.T) {
  function TestConstantExpression (line 31) | func TestConstantExpression(t *testing.T) {
  function TestUnaryOperations (line 56) | func TestUnaryOperations(t *testing.T) {
  function TestArithmeticBinaryOperations (line 86) | func TestArithmeticBinaryOperations(t *testing.T) {
  function TestParentheses (line 116) | func TestParentheses(t *testing.T) {
  function TestLackFinalParethesis (line 141) | func TestLackFinalParethesis(t *testing.T) {
  function TestLogicalBinaryOperations (line 162) | func TestLogicalBinaryOperations(t *testing.T) {
  function TestLogicalAndArithmetic (line 194) | func TestLogicalAndArithmetic(t *testing.T) {
  function TestTernaryOperator (line 218) | func TestTernaryOperator(t *testing.T) {
  function TestBuiltinFunctions (line 244) | func TestBuiltinFunctions(t *testing.T) {
  function TestRandFunction (line 267) | func TestRandFunction(t *testing.T) {
  function BenchmarkSimpleExpression (line 288) | func BenchmarkSimpleExpression(b *testing.B) {

FILE: d2common/d2data/d2compression/huffman.go
  type linkedNode (line 40) | type linkedNode struct
    method getChild1 (line 59) | func (v *linkedNode) getChild1() *linkedNode {
    method insert (line 63) | func (v *linkedNode) insert(other *linkedNode) *linkedNode {
  function createLinkedNode (line 50) | func createLinkedNode(decompVal, weight int) *linkedNode {
  function getPrimes (line 92) | func getPrimes() [][]byte {
  function decode (line 202) | func decode(input *d2datautils.BitStream, head *linkedNode) *linkedNode {
  constant decompVal1 (line 223) | decompVal1 = 256
  constant decompVal2 (line 224) | decompVal2 = 257
  function buildList (line 227) | func buildList(primeData []byte) *linkedNode {
  function insertNode (line 240) | func insertNode(tail *linkedNode, decomp int) *linkedNode {
  function adjustTree (line 268) | func adjustTree(newNode *linkedNode) {
  function buildTree (line 353) | func buildTree(tail *linkedNode) *linkedNode {
  function HuffmanDecompress (line 378) | func HuffmanDecompress(data []byte) []byte {

FILE: d2common/d2data/d2compression/wav.go
  function WavDecompress (line 9) | func WavDecompress(data []byte, channelCount int) ([]byte, error) { //no...

FILE: d2common/d2data/d2video/binkdecoder.go
  type BinkVideoMode (line 11) | type BinkVideoMode
  constant BinkVideoModeNormal (line 15) | BinkVideoModeNormal BinkVideoMode = iota
  constant BinkVideoModeHeightDoubled (line 18) | BinkVideoModeHeightDoubled
  constant BinkVideoModeHeightInterlaced (line 21) | BinkVideoModeHeightInterlaced
  constant BinkVideoModeWidthDoubled (line 24) | BinkVideoModeWidthDoubled
  constant BinkVideoModeWidthAndHeightDoubled (line 27) | BinkVideoModeWidthAndHeightDoubled
  constant BinkVideoModeWidthAndHeightInterlaced (line 30) | BinkVideoModeWidthAndHeightInterlaced
  constant numHeaderBytes (line 34) | numHeaderBytes            = 3
  constant bikHeaderStr (line 35) | bikHeaderStr              = "BIK"
  constant numAudioTrackUnknownBytes (line 36) | numAudioTrackUnknownBytes = 2
  type BinkAudioAlgorithm (line 40) | type BinkAudioAlgorithm
  constant BinkAudioAlgorithmFFT (line 44) | BinkAudioAlgorithmFFT BinkAudioAlgorithm = iota
  constant BinkAudioAlgorithmDCT (line 47) | BinkAudioAlgorithmDCT
  type BinkAudioTrack (line 51) | type BinkAudioTrack struct
  type BinkDecoder (line 60) | type BinkDecoder struct
    method GetNextFrame (line 93) | func (v *BinkDecoder) GetNextFrame() error {
    method loadHeaderInformation (line 115) | func (v *BinkDecoder) loadHeaderInformation() error {
  function CreateBinkDecoder (line 82) | func CreateBinkDecoder(source []byte) (*BinkDecoder, error) {

FILE: d2common/d2datautils/bitmuncher.go
  type BitMuncher (line 4) | type BitMuncher struct
    method Init (line 28) | func (v *BitMuncher) Init(data []byte, offset int) *BitMuncher {
    method Copy (line 37) | func (v BitMuncher) Copy() *BitMuncher {
    method Offset (line 43) | func (v *BitMuncher) Offset() int {
    method SetOffset (line 48) | func (v *BitMuncher) SetOffset(n int) {
    method BitsRead (line 53) | func (v *BitMuncher) BitsRead() int {
    method SetBitsRead (line 58) | func (v *BitMuncher) SetBitsRead(n int) {
    method GetBit (line 63) | func (v *BitMuncher) GetBit() uint32 {
    method SkipBits (line 72) | func (v *BitMuncher) SkipBits(bits int) {
    method GetByte (line 78) | func (v *BitMuncher) GetByte() byte {
    method GetInt32 (line 83) | func (v *BitMuncher) GetInt32() int32 {
    method GetUInt32 (line 88) | func (v *BitMuncher) GetUInt32() uint32 {
    method GetBits (line 94) | func (v *BitMuncher) GetBits(bits int) uint32 {
    method GetSignedBits (line 108) | func (v *BitMuncher) GetSignedBits(bits int) int {
    method MakeSigned (line 113) | func (v *BitMuncher) MakeSigned(value uint32, bits int) int32 {
  constant twosComplimentNegativeOne (line 11) | twosComplimentNegativeOne = 4294967295
  constant byteLen (line 12) | byteLen                   = 8
  constant oneBit (line 13) | oneBit                    = 0x01
  constant fourBytes (line 14) | fourBytes                 = byteLen * 4
  function CreateBitMuncher (line 18) | func CreateBitMuncher(data []byte, offset int) *BitMuncher {
  function CopyBitMuncher (line 23) | func CopyBitMuncher(source *BitMuncher) *BitMuncher {

FILE: d2common/d2datautils/bitmuncher_test.go
  function TestBitmuncherCopy (line 11) | func TestBitmuncherCopy(t *testing.T) {
  function TestBitmuncherSetOffset (line 20) | func TestBitmuncherSetOffset(t *testing.T) {
  function TestBitmuncherSteBitsRead (line 27) | func TestBitmuncherSteBitsRead(t *testing.T) {
  function TestBitmuncherReadBit (line 34) | func TestBitmuncherReadBit(t *testing.T) {
  function TestBitmuncherGetBits (line 47) | func TestBitmuncherGetBits(t *testing.T) {
  function TestBitmuncherGetNoBits (line 53) | func TestBitmuncherGetNoBits(t *testing.T) {
  function TestBitmuncherGetSignedBits (line 59) | func TestBitmuncherGetSignedBits(t *testing.T) {
  function TestBitmuncherGetNoSignedBits (line 65) | func TestBitmuncherGetNoSignedBits(t *testing.T) {
  function TestBitmuncherGetOneSignedBit (line 71) | func TestBitmuncherGetOneSignedBit(t *testing.T) {
  function TestBitmuncherSkipBits (line 77) | func TestBitmuncherSkipBits(t *testing.T) {
  function TestBitmuncherGetInt32 (line 85) | func TestBitmuncherGetInt32(t *testing.T) {
  function TestBitmuncherGetUint32 (line 97) | func TestBitmuncherGetUint32(t *testing.T) {

FILE: d2common/d2datautils/bitstream.go
  constant maxBits (line 8) | maxBits     = 16
  constant bitsPerByte (line 9) | bitsPerByte = 8
  type BitStream (line 13) | type BitStream struct
    method ReadBits (line 33) | func (v *BitStream) ReadBits(bitCount int) int {
    method PeekByte (line 50) | func (v *BitStream) PeekByte() int {
    method EnsureBits (line 60) | func (v *BitStream) EnsureBits(bitCount int) bool {
    method WasteBits (line 78) | func (v *BitStream) WasteBits(bitCount int) {
  function CreateBitStream (line 21) | func CreateBitStream(newData []byte) *BitStream {

FILE: d2common/d2datautils/bitstream_test.go
  function TestBitStreamBits (line 7) | func TestBitStreamBits(t *testing.T) {
  function TestBitStreamBytes (line 26) | func TestBitStreamBytes(t *testing.T) {

FILE: d2common/d2datautils/stream_reader.go
  constant bytesPerint16 (line 8) | bytesPerint16 = 2
  constant bytesPerint32 (line 9) | bytesPerint32 = 4
  constant bytesPerint64 (line 10) | bytesPerint64 = 8
  type StreamReader (line 14) | type StreamReader struct
    method ReadByte (line 30) | func (v *StreamReader) ReadByte() (byte, error) {
    method ReadInt16 (line 42) | func (v *StreamReader) ReadInt16() (int16, error) {
    method ReadUInt16 (line 48) | func (v *StreamReader) ReadUInt16() (uint16, error) {
    method ReadInt32 (line 58) | func (v *StreamReader) ReadInt32() (int32, error) {
    method ReadUInt32 (line 65) | func (v *StreamReader) ReadUInt32() (uint32, error) {
    method ReadInt64 (line 75) | func (v *StreamReader) ReadInt64() (int64, error) {
    method ReadUInt64 (line 82) | func (v *StreamReader) ReadUInt64() (uint64, error) {
    method Position (line 93) | func (v *StreamReader) Position() uint64 {
    method SetPosition (line 98) | func (v *StreamReader) SetPosition(newPosition uint64) {
    method Size (line 103) | func (v *StreamReader) Size() uint64 {
    method ReadBytes (line 108) | func (v *StreamReader) ReadBytes(count int) ([]byte, error) {
    method SkipBytes (line 125) | func (v *StreamReader) SkipBytes(count int) {
    method Read (line 130) | func (v *StreamReader) Read(p []byte) (n int, err error) {
    method EOF (line 150) | func (v *StreamReader) EOF() bool {
  function CreateStreamReader (line 20) | func CreateStreamReader(source []byte) *StreamReader {

FILE: d2common/d2datautils/stream_reader_test.go
  function TestStreamReaderByte (line 7) | func TestStreamReaderByte(t *testing.T) {
  function TestStreamReaderWord (line 35) | func TestStreamReaderWord(t *testing.T) {
  function TestStreamReaderDword (line 66) | func TestStreamReaderDword(t *testing.T) {

FILE: d2common/d2datautils/stream_writer.go
  type StreamWriter (line 9) | type StreamWriter struct
    method GetBytes (line 25) | func (v *StreamWriter) GetBytes() []byte {
    method PushBytes (line 30) | func (v *StreamWriter) PushBytes(b ...byte) {
    method PushBit (line 39) | func (v *StreamWriter) PushBit(b bool) {
    method PushBits (line 55) | func (v *StreamWriter) PushBits(b byte, bits int) {
    method PushBits16 (line 69) | func (v *StreamWriter) PushBits16(b uint16, bits int) {
    method PushBits32 (line 83) | func (v *StreamWriter) PushBits32(b uint32, bits int) {
    method PushInt16 (line 97) | func (v *StreamWriter) PushInt16(val int16) {
    method PushUint16 (line 103) | func (v *StreamWriter) PushUint16(val uint16) {
    method PushInt32 (line 109) | func (v *StreamWriter) PushInt32(val int32) {
    method PushUint32 (line 115) | func (v *StreamWriter) PushUint32(val uint32) {
    method PushInt64 (line 123) | func (v *StreamWriter) PushInt64(val int64) {
    method PushUint64 (line 129) | func (v *StreamWriter) PushUint64(val uint64) {
  function CreateStreamWriter (line 16) | func CreateStreamWriter() *StreamWriter {

FILE: d2common/d2datautils/stream_writer_test.go
  function TestStreamWriterBits (line 7) | func TestStreamWriterBits(t *testing.T) {
  function TestStreamWriterBits16 (line 23) | func TestStreamWriterBits16(t *testing.T) {
  function TestStreamWriterBits32 (line 43) | func TestStreamWriterBits32(t *testing.T) {
  function TestStreamWriterByte (line 66) | func TestStreamWriterByte(t *testing.T) {
  function TestStreamWriterWord (line 80) | func TestStreamWriterWord(t *testing.T) {
  function TestStreamWriterDword (line 95) | func TestStreamWriterDword(t *testing.T) {

FILE: d2common/d2enum/animation_frame.go
  type AnimationFrame (line 4) | type AnimationFrame
  constant AnimationFrameNoEvent (line 8) | AnimationFrameNoEvent AnimationFrame = iota
  constant AnimationFrameAttack (line 9) | AnimationFrameAttack
  constant AnimationFrameMissile (line 10) | AnimationFrameMissile
  constant AnimationFrameSound (line 11) | AnimationFrameSound
  constant AnimationFrameSkill (line 12) | AnimationFrameSkill

FILE: d2common/d2enum/animation_frame_direction.go
  type AnimationFrameDirection (line 4) | type AnimationFrameDirection
  constant SouthWest (line 8) | SouthWest AnimationFrameDirection = iota
  constant NorthWest (line 9) | NorthWest
  constant NorthEast (line 10) | NorthEast
  constant SouthEast (line 11) | SouthEast
  constant South (line 12) | South
  constant West (line 13) | West
  constant North (line 14) | North
  constant East (line 15) | East

FILE: d2common/d2enum/animation_frame_event.go
  type AnimationFrameEvent (line 4) | type AnimationFrameEvent
  constant NoEvent (line 8) | NoEvent AnimationFrameEvent = iota
  constant MeleeAttack (line 9) | MeleeAttack
  constant MissileAttack (line 10) | MissileAttack
  constant PlaySound (line 11) | PlaySound
  constant LaunchSpell (line 12) | LaunchSpell

FILE: d2common/d2enum/composite_type.go
  constant unknown (line 4) | unknown = "Unknown"
  type CompositeType (line 10) | type CompositeType
    method Name (line 34) | func (i CompositeType) Name() string {
  constant CompositeTypeHead (line 14) | CompositeTypeHead      CompositeType = iota
  constant CompositeTypeTorso (line 15) | CompositeTypeTorso
  constant CompositeTypeLegs (line 16) | CompositeTypeLegs
  constant CompositeTypeRightArm (line 17) | CompositeTypeRightArm
  constant CompositeTypeLeftArm (line 18) | CompositeTypeLeftArm
  constant CompositeTypeRightHand (line 19) | CompositeTypeRightHand
  constant CompositeTypeLeftHand (line 20) | CompositeTypeLeftHand
  constant CompositeTypeShield (line 21) | CompositeTypeShield
  constant CompositeTypeSpecial1 (line 22) | CompositeTypeSpecial1
  constant CompositeTypeSpecial2 (line 23) | CompositeTypeSpecial2
  constant CompositeTypeSpecial3 (line 24) | CompositeTypeSpecial3
  constant CompositeTypeSpecial4 (line 25) | CompositeTypeSpecial4
  constant CompositeTypeSpecial5 (line 26) | CompositeTypeSpecial5
  constant CompositeTypeSpecial6 (line 27) | CompositeTypeSpecial6
  constant CompositeTypeSpecial7 (line 28) | CompositeTypeSpecial7
  constant CompositeTypeSpecial8 (line 29) | CompositeTypeSpecial8
  constant CompositeTypeMax (line 30) | CompositeTypeMax

FILE: d2common/d2enum/composite_type_string.go
  function _ (line 7) | func _() {
  constant _CompositeType_name (line 30) | _CompositeType_name = "HDTRLGRALARHLHSHS1S2S3S4S5S6S7S8CompositeTypeMax"
  method String (line 34) | func (i CompositeType) String() string {

FILE: d2common/d2enum/difficulty.go
  type DifficultyType (line 4) | type DifficultyType
  constant DifficultyNormal (line 8) | DifficultyNormal DifficultyType = iota
  constant DifficultyNightmare (line 10) | DifficultyNightmare
  constant DifficultyHell (line 12) | DifficultyHell

FILE: d2common/d2enum/draw_effect.go
  type DrawEffect (line 4) | type DrawEffect
    method Transparent (line 45) | func (d DrawEffect) Transparent() bool {
    method String (line 49) | func (d DrawEffect) String() string {
  constant DrawEffectPctTransparency25 (line 10) | DrawEffectPctTransparency25 DrawEffect = iota
  constant DrawEffectPctTransparency50 (line 14) | DrawEffectPctTransparency50
  constant DrawEffectPctTransparency75 (line 18) | DrawEffectPctTransparency75
  constant DrawEffectModulate (line 22) | DrawEffectModulate
  constant DrawEffectBurn (line 26) | DrawEffectBurn
  constant DrawEffectNormal (line 30) | DrawEffectNormal
  constant DrawEffectMod2XTrans (line 34) | DrawEffectMod2XTrans
  constant DrawEffectMod2X (line 38) | DrawEffectMod2X
  constant DrawEffectNone (line 41) | DrawEffectNone

FILE: d2common/d2enum/encoding_type.go
  type EncodingType (line 4) | type EncodingType
  constant EncodeDefault (line 8) | EncodeDefault EncodingType = iota

FILE: d2common/d2enum/equipped_slot.go
  type EquippedSlot (line 4) | type EquippedSlot
  constant EquippedSlotNone (line 8) | EquippedSlotNone EquippedSlot = iota
  constant EquippedSlotHead (line 9) | EquippedSlotHead
  constant EquippedSlotTorso (line 10) | EquippedSlotTorso
  constant EquippedSlotLegs (line 11) | EquippedSlotLegs
  constant EquippedSlotRightArm (line 12) | EquippedSlotRightArm
  constant EquippedSlotLeftArm (line 13) | EquippedSlotLeftArm
  constant EquippedSlotLeftHand (line 14) | EquippedSlotLeftHand
  constant EquippedSlotRightHand (line 15) | EquippedSlotRightHand
  constant EquippedSlotNeck (line 16) | EquippedSlotNeck
  constant EquippedSlotBelt (line 17) | EquippedSlotBelt
  constant EquippedSlotGloves (line 18) | EquippedSlotGloves

FILE: d2common/d2enum/filter.go
  type Filter (line 4) | type Filter
  constant FilterDefault (line 8) | FilterDefault Filter = iota
  constant FilterNearest (line 11) | FilterNearest
  constant FilterLinear (line 14) | FilterLinear

FILE: d2common/d2enum/game_event.go
  type GameEvent (line 4) | type GameEvent
  constant ToggleGameMenu (line 9) | ToggleGameMenu GameEvent = iota + 1
  constant ToggleCharacterPanel (line 12) | ToggleCharacterPanel
  constant ToggleInventoryPanel (line 13) | ToggleInventoryPanel
  constant TogglePartyPanel (line 14) | TogglePartyPanel
  constant ToggleSkillTreePanel (line 15) | ToggleSkillTreePanel
  constant ToggleHirelingPanel (line 16) | ToggleHirelingPanel
  constant ToggleQuestLog (line 17) | ToggleQuestLog
  constant ToggleHelpScreen (line 18) | ToggleHelpScreen
  constant ToggleChatOverlay (line 19) | ToggleChatOverlay
  constant ToggleMessageLog (line 20) | ToggleMessageLog
  constant ToggleRightSkillSelector (line 21) | ToggleRightSkillSelector
  constant ToggleLeftSkillSelector (line 22) | ToggleLeftSkillSelector
  constant ToggleAutomap (line 24) | ToggleAutomap
  constant CenterAutomap (line 25) | CenterAutomap
  constant FadeAutomap (line 26) | FadeAutomap
  constant TogglePartyOnAutomap (line 27) | TogglePartyOnAutomap
  constant ToggleNamesOnAutomap (line 28) | ToggleNamesOnAutomap
  constant ToggleMiniMap (line 29) | ToggleMiniMap
  constant UseSkill1 (line 32) | UseSkill1
  constant UseSkill2 (line 33) | UseSkill2
  constant UseSkill3 (line 34) | UseSkill3
  constant UseSkill4 (line 35) | UseSkill4
  constant UseSkill5 (line 36) | UseSkill5
  constant UseSkill6 (line 37) | UseSkill6
  constant UseSkill7 (line 38) | UseSkill7
  constant UseSkill8 (line 39) | UseSkill8
  constant UseSkill9 (line 40) | UseSkill9
  constant UseSkill10 (line 41) | UseSkill10
  constant UseSkill11 (line 42) | UseSkill11
  constant UseSkill12 (line 43) | UseSkill12
  constant UseSkill13 (line 44) | UseSkill13
  constant UseSkill14 (line 45) | UseSkill14
  constant UseSkill15 (line 46) | UseSkill15
  constant UseSkill16 (line 47) | UseSkill16
  constant SelectPreviousSkill (line 50) | SelectPreviousSkill
  constant SelectNextSkill (line 51) | SelectNextSkill
  constant ToggleBelts (line 55) | ToggleBelts
  constant UseBeltSlot1 (line 56) | UseBeltSlot1
  constant UseBeltSlot2 (line 57) | UseBeltSlot2
  constant UseBeltSlot3 (line 58) | UseBeltSlot3
  constant UseBeltSlot4 (line 59) | UseBeltSlot4
  constant SwapWeapons (line 61) | SwapWeapons
  constant ToggleChatBox (line 62) | ToggleChatBox
  constant ToggleRunWalk (line 63) | ToggleRunWalk
  constant SayHelp (line 65) | SayHelp
  constant SayFollowMe (line 66) | SayFollowMe
  constant SayThisIsForYou (line 67) | SayThisIsForYou
  constant SayThanks (line 68) | SayThanks
  constant SaySorry (line 69) | SaySorry
  constant SayBye (line 70) | SayBye
  constant SayNowYouDie (line 71) | SayNowYouDie
  constant SayRetreat (line 72) | SayRetreat
  constant HoldRun (line 75) | HoldRun
  constant HoldStandStill (line 76) | HoldStandStill
  constant HoldShowGroundItems (line 77) | HoldShowGroundItems
  constant HoldShowPortraits (line 78) | HoldShowPortraits
  constant TakeScreenShot (line 80) | TakeScreenShot
  constant ClearScreen (line 81) | ClearScreen
  constant ClearMessages (line 82) | ClearMessages

FILE: d2common/d2enum/hero.go
  type Hero (line 9) | type Hero
    method GetToken (line 24) | func (h Hero) GetToken() string {
    method GetToken3 (line 48) | func (h Hero) GetToken3() string {
  constant HeroNone (line 13) | HeroNone        Hero = iota
  constant HeroBarbarian (line 14) | HeroBarbarian
  constant HeroNecromancer (line 15) | HeroNecromancer
  constant HeroPaladin (line 16) | HeroPaladin
  constant HeroAssassin (line 17) | HeroAssassin
  constant HeroSorceress (line 18) | HeroSorceress
  constant HeroAmazon (line 19) | HeroAmazon
  constant HeroDruid (line 20) | HeroDruid

FILE: d2common/d2enum/hero_stance.go
  type HeroStance (line 4) | type HeroStance
  constant HeroStanceIdle (line 8) | HeroStanceIdle HeroStance = iota
  constant HeroStanceIdleSelected (line 9) | HeroStanceIdleSelected
  constant HeroStanceApproaching (line 10) | HeroStanceApproaching
  constant HeroStanceSelected (line 11) | HeroStanceSelected
  constant HeroStanceRetreating (line 12) | HeroStanceRetreating

FILE: d2common/d2enum/hero_string.go
  function _ (line 7) | func _() {
  constant _Hero_name (line 21) | _Hero_name = "BarbarianNecromancerPaladinAssassinSorceressAmazonDruid"
  method String (line 25) | func (i Hero) String() string {

FILE: d2common/d2enum/hero_string2enum.go
  function HeroFromString (line 8) | func HeroFromString(s string) Hero {
  function _ (line 20) | func _(s string) {

FILE: d2common/d2enum/input_button.go
  type MouseButton (line 4) | type MouseButton
  constant MouseButtonLeft (line 8) | MouseButtonLeft MouseButton = iota
  constant MouseButtonMiddle (line 10) | MouseButtonMiddle
  constant MouseButtonRight (line 12) | MouseButtonRight
  constant MouseButtonMin (line 14) | MouseButtonMin = MouseButtonLeft
  constant MouseButtonMax (line 16) | MouseButtonMax = MouseButtonRight
  type MouseButtonMod (line 20) | type MouseButtonMod
  constant MouseButtonModLeft (line 24) | MouseButtonModLeft MouseButtonMod = 1 << iota
  constant MouseButtonModMiddle (line 26) | MouseButtonModMiddle
  constant MouseButtonModRight (line 28) | MouseButtonModRight

FILE: d2common/d2enum/input_key.go
  type Key (line 4) | type Key
  constant Key0 (line 8) | Key0 Key = iota
  constant Key1 (line 9) | Key1
  constant Key2 (line 10) | Key2
  constant Key3 (line 11) | Key3
  constant Key4 (line 12) | Key4
  constant Key5 (line 13) | Key5
  constant Key6 (line 14) | Key6
  constant Key7 (line 15) | Key7
  constant Key8 (line 16) | Key8
  constant Key9 (line 17) | Key9
  constant KeyA (line 18) | KeyA
  constant KeyB (line 19) | KeyB
  constant KeyC (line 20) | KeyC
  constant KeyD (line 21) | KeyD
  constant KeyE (line 22) | KeyE
  constant KeyF (line 23) | KeyF
  constant KeyG (line 24) | KeyG
  constant KeyH (line 25) | KeyH
  constant KeyI (line 26) | KeyI
  constant KeyJ (line 27) | KeyJ
  constant KeyK (line 28) | KeyK
  constant KeyL (line 29) | KeyL
  constant KeyM (line 30) | KeyM
  constant KeyN (line 31) | KeyN
  constant KeyO (line 32) | KeyO
  constant KeyP (line 33) | KeyP
  constant KeyQ (line 34) | KeyQ
  constant KeyR (line 35) | KeyR
  constant KeyS (line 36) | KeyS
  constant KeyT (line 37) | KeyT
  constant KeyU (line 38) | KeyU
  constant KeyV (line 39) | KeyV
  constant KeyW (line 40) | KeyW
  constant KeyX (line 41) | KeyX
  constant KeyY (line 42) | KeyY
  constant KeyZ (line 43) | KeyZ
  constant KeyApostrophe (line 44) | KeyApostrophe
  constant KeyBackslash (line 45) | KeyBackslash
  constant KeyBackspace (line 46) | KeyBackspace
  constant KeyCapsLock (line 47) | KeyCapsLock
  constant KeyComma (line 48) | KeyComma
  constant KeyDelete (line 49) | KeyDelete
  constant KeyDown (line 50) | KeyDown
  constant KeyEnd (line 51) | KeyEnd
  constant KeyEnter (line 52) | KeyEnter
  constant KeyEqual (line 53) | KeyEqual
  constant KeyEscape (line 54) | KeyEscape
  constant KeyF1 (line 55) | KeyF1
  constant KeyF2 (line 56) | KeyF2
  constant KeyF3 (line 57) | KeyF3
  constant KeyF4 (line 58) | KeyF4
  constant KeyF5 (line 59) | KeyF5
  constant KeyF6 (line 60) | KeyF6
  constant KeyF7 (line 61) | KeyF7
  constant KeyF8 (line 62) | KeyF8
  constant KeyF9 (line 63) | KeyF9
  constant KeyF10 (line 64) | KeyF10
  constant KeyF11 (line 65) | KeyF11
  constant KeyF12 (line 66) | KeyF12
  constant KeyGraveAccent (line 67) | KeyGraveAccent
  constant KeyHome (line 68) | KeyHome
  constant KeyInsert (line 69) | KeyInsert
  constant KeyKP0 (line 70) | KeyKP0
  constant KeyKP1 (line 71) | KeyKP1
  constant KeyKP2 (line 72) | KeyKP2
  constant KeyKP3 (line 73) | KeyKP3
  constant KeyKP4 (line 74) | KeyKP4
  constant KeyKP5 (line 75) | KeyKP5
  constant KeyKP6 (line 76) | KeyKP6
  constant KeyKP7 (line 77) | KeyKP7
  constant KeyKP8 (line 78) | KeyKP8
  constant KeyKP9 (line 79) | KeyKP9
  constant KeyKPAdd (line 80) | KeyKPAdd
  constant KeyKPDecimal (line 81) | KeyKPDecimal
  constant KeyKPDivide (line 82) | KeyKPDivide
  constant KeyKPEnter (line 83) | KeyKPEnter
  constant KeyKPEqual (line 84) | KeyKPEqual
  constant KeyKPMultiply (line 85) | KeyKPMultiply
  constant KeyKPSubtract (line 86) | KeyKPSubtract
  constant KeyLeft (line 87) | KeyLeft
  constant KeyLeftBracket (line 88) | KeyLeftBracket
  constant KeyMenu (line 89) | KeyMenu
  constant KeyMinus (line 90) | KeyMinus
  constant KeyNumLock (line 91) | KeyNumLock
  constant KeyPageDown (line 92) | KeyPageDown
  constant KeyPageUp (line 93) | KeyPageUp
  constant KeyPause (line 94) | KeyPause
  constant KeyPeriod (line 95) | KeyPeriod
  constant KeyPrintScreen (line 96) | KeyPrintScreen
  constant KeyRight (line 97) | KeyRight
  constant KeyRightBracket (line 98) | KeyRightBracket
  constant KeyScrollLock (line 99) | KeyScrollLock
  constant KeySemicolon (line 100) | KeySemicolon
  constant KeySlash (line 101) | KeySlash
  constant KeySpace (line 102) | KeySpace
  constant KeyTab (line 103) | KeyTab
  constant KeyUp (line 104) | KeyUp
  constant KeyAlt (line 105) | KeyAlt
  constant KeyControl (line 106) | KeyControl
  constant KeyShift (line 107) | KeyShift
  constant KeyTilde (line 108) | KeyTilde
  constant KeyMouse3 (line 109) | KeyMouse3
  constant KeyMouse4 (line 110) | KeyMouse4
  constant KeyMouse5 (line 111) | KeyMouse5
  constant KeyMouseWheelUp (line 112) | KeyMouseWheelUp
  constant KeyMouseWheelDown (line 113) | KeyMouseWheelDown
  constant KeyMin (line 115) | KeyMin = Key0
  constant KeyMax (line 116) | KeyMax = KeyMouseWheelDown
  type KeyMod (line 120) | type KeyMod
  constant KeyModAlt (line 124) | KeyModAlt KeyMod = 1 << iota
  constant KeyModControl (line 126) | KeyModControl
  constant KeyModShift (line 128) | KeyModShift

FILE: d2common/d2enum/input_priority.go
  type Priority (line 4) | type Priority
  constant PriorityLow (line 8) | PriorityLow Priority = iota
  constant PriorityDefault (line 9) | PriorityDefault
  constant PriorityHigh (line 10) | PriorityHigh

FILE: d2common/d2enum/inventory_item_type.go
  type InventoryItemType (line 4) | type InventoryItemType
  constant InventoryItemTypeItem (line 8) | InventoryItemTypeItem InventoryItemType = iota
  constant InventoryItemTypeWeapon (line 9) | InventoryItemTypeWeapon
  constant InventoryItemTypeArmor (line 10) | InventoryItemTypeArmor

FILE: d2common/d2enum/item_affix_type.go
  type ItemAffixSuperType (line 4) | type ItemAffixSuperType
  constant ItemAffixPrefix (line 8) | ItemAffixPrefix ItemAffixSuperType = iota
  constant ItemAffixSuffix (line 9) | ItemAffixSuffix
  type ItemAffixSubType (line 13) | type ItemAffixSubType
  constant ItemAffixCommon (line 17) | ItemAffixCommon ItemAffixSubType = iota
  constant ItemAffixMagic (line 18) | ItemAffixMagic

FILE: d2common/d2enum/item_armor_class.go
  type ArmorClass (line 4) | type ArmorClass
  constant ArmorClassLite (line 8) | ArmorClassLite   = "lit"
  constant ArmorClassMedium (line 9) | ArmorClassMedium = "med"
  constant ArmorClassHeavy (line 10) | ArmorClassHeavy  = "hvy"

FILE: d2common/d2enum/item_event_functions.go
  type ItemEventFuncID (line 4) | type ItemEventFuncID
  constant ReflectMissile (line 10) | ReflectMissile ItemEventFuncID = iota
  constant FreezeAttacker (line 14) | FreezeAttacker
  constant FreezeChillAttacker (line 17) | FreezeChillAttacker
  constant ReflectPercentDamage (line 21) | ReflectPercentDamage
  constant DamageDealtToHealth (line 25) | DamageDealtToHealth
  constant AttackerTakesPhysical (line 28) | AttackerTakesPhysical
  constant Knockback (line 31) | Knockback
  constant InduceFear (line 34) | InduceFear
  constant BlindTarget (line 38) | BlindTarget
  constant AttackerTakesLightning (line 41) | AttackerTakesLightning
  constant AttackerTakesFire (line 44) | AttackerTakesFire
  constant AttackerTakesCold (line 47) | AttackerTakesCold
  constant DamageTakenToMana (line 50) | DamageTakenToMana
  constant FreezeTarget (line 53) | FreezeTarget
  constant OpenWounds (line 56) | OpenWounds
  constant CrushingBlow (line 59) | CrushingBlow
  constant ManaOnKillMonster (line 62) | ManaOnKillMonster
  constant LifeOnKillDemon (line 65) | LifeOnKillDemon
  constant SlowTarget (line 68) | SlowTarget
  constant CastSkillAgainstDefender (line 71) | CastSkillAgainstDefender
  constant CastSkillAgainstAttacker (line 74) | CastSkillAgainstAttacker
  constant AbsorbPhysical (line 77) | AbsorbPhysical
  constant TakeSummonDamage (line 80) | TakeSummonDamage
  constant ManaAbsorbsDamage (line 83) | ManaAbsorbsDamage
  constant AbsorbElementalDamage (line 86) | AbsorbElementalDamage
  constant TakeSummonDamage2 (line 89) | TakeSummonDamage2
  constant TargetSlowsTarget (line 93) | TargetSlowsTarget
  constant LifeOnKillMonster (line 96) | LifeOnKillMonster
  constant RestInPeace (line 99) | RestInPeace
  constant CastSkillWithoutTarget (line 102) | CastSkillWithoutTarget
  constant ReanimateTargetAsMonster (line 105) | ReanimateTargetAsMonster

FILE: d2common/d2enum/item_events.go
  type ItemEventType (line 4) | type ItemEventType
  constant ItemEventNone (line 8) | ItemEventNone             ItemEventType = iota
  constant ItemEventHitByMissile (line 9) | ItemEventHitByMissile
  constant ItemEventDamagedInMelee (line 10) | ItemEventDamagedInMelee
  constant ItemEventDamagedByMissile (line 11) | ItemEventDamagedByMissile
  constant ItemEventAttackedInMelee (line 12) | ItemEventAttackedInMelee
  constant ItemEventDoActive (line 13) | ItemEventDoActive
  constant ItemEventDoMeleeDamage (line 14) | ItemEventDoMeleeDamage
  constant ItemEventDoMissileDamage (line 15) | ItemEventDoMissileDamage
  constant ItemEventDoMeleeAttack (line 16) | ItemEventDoMeleeAttack
  constant ItemEventDoMissileAttack (line 17) | ItemEventDoMissileAttack
  constant ItemEventKill (line 18) | ItemEventKill
  constant ItemEventKilled (line 19) | ItemEventKilled
  constant ItemEventAbsorbDamage (line 20) | ItemEventAbsorbDamage
  constant ItemEventLevelUp (line 21) | ItemEventLevelUp
  function GetItemEventType (line 42) | func GetItemEventType(s string) ItemEventType {

FILE: d2common/d2enum/item_quality.go
  type ItemQuality (line 4) | type ItemQuality
  constant LowQuality (line 8) | LowQuality ItemQuality = iota + 1
  constant Normal (line 9) | Normal
  constant Superior (line 10) | Superior
  constant Magic (line 11) | Magic
  constant Set (line 12) | Set
  constant Rare (line 13) | Rare
  constant Unique (line 14) | Unique
  constant Crafted (line 15) | Crafted
  constant Tempered (line 16) | Tempered

FILE: d2common/d2enum/level_generation_types.go
  type LevelGenerationType (line 10) | type LevelGenerationType
  constant LevelTypeRandomMaze (line 14) | LevelTypeRandomMaze LevelGenerationType = iota
  constant LevelTypePreset (line 15) | LevelTypePreset
  constant LevelTypeWilderness (line 16) | LevelTypeWilderness

FILE: d2common/d2enum/level_teleport_flags.go
  type TeleportFlag (line 11) | type TeleportFlag
  constant TeleportDisabled (line 15) | TeleportDisabled TeleportFlag = iota
  constant TeleportEnabled (line 16) | TeleportEnabled
  constant TeleportEnabledLimited (line 17) | TeleportEnabledLimited

FILE: d2common/d2enum/monster_alignment_type.go
  type MonsterAlignmentType (line 4) | type MonsterAlignmentType
  constant MonsterEnemy (line 8) | MonsterEnemy MonsterAlignmentType = iota
  constant MonsterFriend (line 12) | MonsterFriend
  constant MonsterNeutral (line 16) | MonsterNeutral

FILE: d2common/d2enum/monster_animation_mode.go
  type MonsterAnimationMode (line 6) | type MonsterAnimationMode
  constant MonsterAnimationModeDeath (line 10) | MonsterAnimationModeDeath     MonsterAnimationMode = iota
  constant MonsterAnimationModeNeutral (line 11) | MonsterAnimationModeNeutral
  constant MonsterAnimationModeWalk (line 12) | MonsterAnimationModeWalk
  constant MonsterAnimationModeGetHit (line 13) | MonsterAnimationModeGetHit
  constant MonsterAnimationModeAttack1 (line 14) | MonsterAnimationModeAttack1
  constant MonsterAnimationModeAttack2 (line 15) | MonsterAnimationModeAttack2
  constant MonsterAnimationModeBlock (line 16) | MonsterAnimationModeBlock
  constant MonsterAnimationModeCast (line 17) | MonsterAnimationModeCast
  constant MonsterAnimationModeSkill1 (line 18) | MonsterAnimationModeSkill1
  constant MonsterAnimationModeSkill2 (line 19) | MonsterAnimationModeSkill2
  constant MonsterAnimationModeSkill3 (line 20) | MonsterAnimationModeSkill3
  constant MonsterAnimationModeSkill4 (line 21) | MonsterAnimationModeSkill4
  constant MonsterAnimationModeDead (line 22) | MonsterAnimationModeDead
  constant MonsterAnimationModeKnockback (line 23) | MonsterAnimationModeKnockback
  constant MonsterAnimationModeSequence (line 24) | MonsterAnimationModeSequence
  constant MonsterAnimationModeRun (line 25) | MonsterAnimationModeRun

FILE: d2common/d2enum/monster_animation_mode_string.go
  function _ (line 7) | func _() {
  constant _MonsterAnimationMode_name (line 29) | _MonsterAnimationMode_name = "DTNUWLGHA1A2BLSCS1S2S3S4DDGHxxRN"
  method String (line 33) | func (i MonsterAnimationMode) String() string {

FILE: d2common/d2enum/monster_combat_type.go
  type MonsterCombatType (line 4) | type MonsterCombatType
  constant MonsterMelee (line 8) | MonsterMelee MonsterCombatType = iota
  constant MonsterRanged (line 11) | MonsterRanged

FILE: d2common/d2enum/monumod_const_index.go
  type MonUModConstIndex (line 4) | type MonUModConstIndex
  constant ChampionChance (line 8) | ChampionChance MonUModConstIndex = iota
  constant MinionHPBonus (line 9) | MinionHPBonus
  constant MinionHPBonusNightmare (line 10) | MinionHPBonusNightmare
  constant MinionHPBonusHell (line 11) | MinionHPBonusHell
  constant ChampionHPBonus (line 12) | ChampionHPBonus
  constant ChampionHPBonusNightmare (line 13) | ChampionHPBonusNightmare
  constant ChampionHPBonusHell (line 14) | ChampionHPBonusHell
  constant UniqueHPBonus (line 15) | UniqueHPBonus
  constant UniqueHPBonusNightmare (line 16) | UniqueHPBonusNightmare
  constant UniqueHPBonusHell (line 17) | UniqueHPBonusHell
  constant ChampionAttackRatingBonus (line 18) | ChampionAttackRatingBonus
  constant ChampionDamageBonus (line 19) | ChampionDamageBonus
  constant StrongMinionAttackRatingBonus (line 20) | StrongMinionAttackRatingBonus
  constant StrongMinionDamageBonus (line 21) | StrongMinionDamageBonus
  constant MinionElementalDamageMinBonus (line 22) | MinionElementalDamageMinBonus
  constant MinionElementalDamageMinBonusNightmare (line 23) | MinionElementalDamageMinBonusNightmare
  constant MinionElementalDamageMinBonusHell (line 24) | MinionElementalDamageMinBonusHell
  constant MinionElementalDamageMaxBonus (line 25) | MinionElementalDamageMaxBonus
  constant MinionElementalDamageMaxBonusNightmare (line 26) | MinionElementalDamageMaxBonusNightmare
  constant MinionElementalDamageMaxBonusHell (line 27) | MinionElementalDamageMaxBonusHell
  constant ChampionElementalDamageMinBonus (line 28) | ChampionElementalDamageMinBonus
  constant ChampionElementalDamageMinBonusNightmare (line 29) | ChampionElementalDamageMinBonusNightmare
  constant ChampionElementalDamageMinBonusHell (line 30) | ChampionElementalDamageMinBonusHell
  constant ChampionElementalDamageMaxBonus (line 31) | ChampionElementalDamageMaxBonus
  constant ChampionElementalDamageMaxBonusNightmare (line 32) | ChampionElementalDamageMaxBonusNightmare
  constant ChampionElementalDamageMaxBonusHell (line 33) | ChampionElementalDamageMaxBonusHell
  constant UniqueElementalDamageMinBonus (line 34) | UniqueElementalDamageMinBonus
  constant UniqueElementalDamageMinBonusNightmare (line 35) | UniqueElementalDamageMinBonusNightmare
  constant UniqueElementalDamageMinBonusHell (line 36) | UniqueElementalDamageMinBonusHell
  constant UniqueElementalDamageMaxBonus (line 37) | UniqueElementalDamageMaxBonus
  constant UniqueElementalDamageMaxBonusNightmare (line 38) | UniqueElementalDamageMaxBonusNightmare
  constant UniqueElementalDamageMaxBonusHell (line 39) | UniqueElementalDamageMaxBonusHell

FILE: d2common/d2enum/npc_action_type.go
  type NPCActionType (line 4) | type NPCActionType
  constant NPCActionInvalid (line 9) | NPCActionInvalid NPCActionType = iota
  constant NPCAction1 (line 10) | NPCAction1
  constant NPCAction2 (line 11) | NPCAction2
  constant NPCAction3 (line 12) | NPCAction3
  constant NPCActionSkill1 (line 13) | NPCActionSkill1

FILE: d2common/d2enum/numeric_labels.go
  constant RepairAll (line 5) | RepairAll = iota
  constant _ (line 6) | _
  constant CancelLabel (line 7) | CancelLabel
  constant CopyrightLabel (line 8) | CopyrightLabel
  constant AllRightsReservedLabel (line 9) | AllRightsReservedLabel
  constant SinglePlayerLabel (line 10) | SinglePlayerLabel
  constant _ (line 11) | _
  constant OtherMultiplayerLabel (line 12) | OtherMultiplayerLabel
  constant ExitGameLabel (line 13) | ExitGameLabel
  constant CreditsLabel (line 14) | CreditsLabel
  constant CinematicsLabel (line 15) | CinematicsLabel
  constant ViewAllCinematicsLabel (line 17) | ViewAllCinematicsLabel
  constant EpilogueLabel (line 18) | EpilogueLabel
  constant SelectCinematicLabel (line 19) | SelectCinematicLabel
  constant _ (line 21) | _
  constant TCPIPGameLabel (line 22) | TCPIPGameLabel
  constant TCPIPOptionsLabel (line 23) | TCPIPOptionsLabel
  constant TCPIPHostGameLabel (line 24) | TCPIPHostGameLabel
  constant TCPIPJoinGameLabel (line 25) | TCPIPJoinGameLabel
  constant TCPIPEnterHostIPLabel (line 26) | TCPIPEnterHostIPLabel
  constant TCPIPYourIPLabel (line 27) | TCPIPYourIPLabel
  constant TipHostLabel (line 28) | TipHostLabel
  constant TipJoinLabel (line 29) | TipJoinLabel
  constant IPNotFoundLabel (line 30) | IPNotFoundLabel
  constant CharNameLabel (line 32) | CharNameLabel
  constant HardCoreLabel (line 33) | HardCoreLabel
  constant SelectHeroClassLabel (line 34) | SelectHeroClassLabel
  constant AmazonDescr (line 35) | AmazonDescr
  constant NecromancerDescr (line 36) | NecromancerDescr
  constant BarbarianDescr (line 37) | BarbarianDescr
  constant SorceressDescr (line 38) | SorceressDescr
  constant PaladinDescr (line 39) | PaladinDescr
  constant _ (line 41) | _
  constant HellLabel (line 43) | HellLabel
  constant NightmareLabel (line 44) | NightmareLabel
  constant NormalLabel (line 45) | NormalLabel
  constant SelectDifficultyLabel (line 46) | SelectDifficultyLabel
  constant _ (line 48) | _
  constant DelCharConfLabel (line 50) | DelCharConfLabel
  constant OpenLabel (line 51) | OpenLabel
  constant _ (line 53) | _
  constant YesLabel (line 55) | YesLabel
  constant NoLabel (line 56) | NoLabel
  constant _ (line 58) | _
  constant ExitLabel (line 60) | ExitLabel
  constant OKLabel (line 61) | OKLabel
  function BaseLabelNumbers (line 65) | func BaseLabelNumbers(idx int) int {

FILE: d2common/d2enum/object_animation_mode.go
  type ObjectAnimationMode (line 7) | type ObjectAnimationMode
  constant ObjectAnimationModeNeutral (line 11) | ObjectAnimationModeNeutral   ObjectAnimationMode = iota
  constant ObjectAnimationModeOperating (line 12) | ObjectAnimationModeOperating
  constant ObjectAnimationModeOpened (line 13) | ObjectAnimationModeOpened
  constant ObjectAnimationModeSpecial1 (line 14) | ObjectAnimationModeSpecial1
  constant ObjectAnimationModeSpecial2 (line 15) | ObjectAnimationModeSpecial2
  constant ObjectAnimationModeSpecial3 (line 16) | ObjectAnimationModeSpecial3
  constant ObjectAnimationModeSpecial4 (line 17) | ObjectAnimationModeSpecial4
  constant ObjectAnimationModeSpecial5 (line 18) | ObjectAnimationModeSpecial5

FILE: d2common/d2enum/object_animation_mode_string.go
  function _ (line 7) | func _() {
  constant _ObjectAnimationMode_name (line 21) | _ObjectAnimationMode_name = "NUOPONS1S2S3S4S5"
  method String (line 25) | func (i ObjectAnimationMode) String() string {

FILE: d2common/d2enum/object_animation_mode_string2enum.go
  function ObjectAnimationModeFromString (line 8) | func ObjectAnimationModeFromString(s string) ObjectAnimationMode {
  function _ (line 20) | func _(s string) {

FILE: d2common/d2enum/object_type.go
  type ObjectType (line 4) | type ObjectType
  constant ObjectTypePlayer (line 8) | ObjectTypePlayer ObjectType = iota
  constant ObjectTypeCharacter (line 9) | ObjectTypeCharacter
  constant ObjectTypeItem (line 10) | ObjectTypeItem

FILE: d2common/d2enum/operator_type.go
  type OperatorType (line 4) | type OperatorType
  constant OpDefault (line 8) | OpDefault = OperatorType(iota)
  constant Op1 (line 11) | Op1
  constant Op2 (line 20) | Op2
  constant Op3 (line 26) | Op3
  constant Op4 (line 32) | Op4
  constant Op5 (line 37) | Op5
  constant Op6 (line 42) | Op6
  constant Op7 (line 48) | Op7
  constant Op8 (line 53) | Op8
  constant Op9 (line 59) | Op9
  constant Op10 (line 62) | Op10
  constant Op11 (line 66) | Op11
  constant Op12 (line 69) | Op12
  constant Op13 (line 75) | Op13

FILE: d2common/d2enum/party_buttons.go
  constant PartyButtonListeningFrame (line 5) | PartyButtonListeningFrame = iota * 4
  constant PartyButtonRelationshipsFrame (line 6) | PartyButtonRelationshipsFrame
  constant PartyButtonSeeingFrame (line 7) | PartyButtonSeeingFrame
  constant PartyButtonCorpsLootingFrame (line 8) | PartyButtonCorpsLootingFrame
  constant PartyButtonNextButtonFrame (line 10) | PartyButtonNextButtonFrame = 2

FILE: d2common/d2enum/pet_icon_type.go
  type PetIconType (line 4) | type PetIconType
  constant NoIcon (line 9) | NoIcon PetIconType = iota
  constant ShowIconOnly (line 10) | ShowIconOnly
  constant ShowIconAndQuantity (line 11) | ShowIconAndQuantity
  constant ShowIconOnly2 (line 12) | ShowIconOnly2

FILE: d2common/d2enum/player_animation_mode.go
  type PlayerAnimationMode (line 6) | type PlayerAnimationMode
  constant PlayerAnimationModeDeath (line 10) | PlayerAnimationModeDeath       PlayerAnimationMode = iota
  constant PlayerAnimationModeNeutral (line 11) | PlayerAnimationModeNeutral
  constant PlayerAnimationModeWalk (line 12) | PlayerAnimationModeWalk
  constant PlayerAnimationModeRun (line 13) | PlayerAnimationModeRun
  constant PlayerAnimationModeGetHit (line 14) | PlayerAnimationModeGetHit
  constant PlayerAnimationModeTownNeutral (line 15) | PlayerAnimationModeTownNeutral
  constant PlayerAnimationModeTownWalk (line 16) | PlayerAnimationModeTownWalk
  constant PlayerAnimationModeAttack1 (line 17) | PlayerAnimationModeAttack1
  constant PlayerAnimationModeAttack2 (line 18) | PlayerAnimationModeAttack2
  constant PlayerAnimationModeBlock (line 19) | PlayerAnimationModeBlock
  constant PlayerAnimationModeCast (line 20) | PlayerAnimationModeCast
  constant PlayerAnimationModeThrow (line 21) | PlayerAnimationModeThrow
  constant PlayerAnimationModeKick (line 22) | PlayerAnimationModeKick
  constant PlayerAnimationModeSkill1 (line 23) | PlayerAnimationModeSkill1
  constant PlayerAnimationModeSkill2 (line 24) | PlayerAnimationModeSkill2
  constant PlayerAnimationModeSkill3 (line 25) | PlayerAnimationModeSkill3
  constant PlayerAnimationModeSkill4 (line 26) | PlayerAnimationModeSkill4
  constant PlayerAnimationModeDead (line 27) | PlayerAnimationModeDead
  constant PlayerAnimationModeSequence (line 28) | PlayerAnimationModeSequence
  constant PlayerAnimationModeKnockBack (line 29) | PlayerAnimationModeKnockBack
  constant PlayerAnimationModeNone (line 30) | PlayerAnimationModeNone

FILE: d2common/d2enum/player_animation_mode_string.go
  function _ (line 7) | func _() {
  constant _PlayerAnimationMode_name (line 33) | _PlayerAnimationMode_name = "DTNUWLRNGHTNTWA1A2BLSCTHKKS1S2S3S4DDGHGH"
  method String (line 37) | func (i PlayerAnimationMode) String() string {

FILE: d2common/d2enum/players_relationships.go
  type PlayersRelationships (line 4) | type PlayersRelationships
  constant PlayerRelationNeutral (line 8) | PlayerRelationNeutral PlayersRelationships = iota
  constant PlayerRelationFriend (line 9) | PlayerRelationFriend
  constant PlayerRelationEnemy (line 10) | PlayerRelationEnemy
  constant PlayersHostileLevel (line 15) | PlayersHostileLevel = 9
  constant MaxPlayersInGame (line 20) | MaxPlayersInGame = 8

FILE: d2common/d2enum/quests.go
  constant NormalActQuestsNumber (line 5) | NormalActQuestsNumber = 6
  constant HalfQuestsNumber (line 7) | HalfQuestsNumber = 3
  constant ActsNumber (line 11) | ActsNumber = 5
  constant Act1 (line 15) | Act1 = iota + 1
  constant Act2 (line 17) | Act2
  constant Act3 (line 19) | Act3
  constant Act4 (line 21) | Act4
  constant Act5 (line 23) | Act5
  constant QuestStatusCompleted (line 39) | QuestStatusCompleted  = iota - 2
  constant QuestStatusCompleting (line 40) | QuestStatusCompleting
  constant QuestStatusNotStarted (line 41) | QuestStatusNotStarted
  constant QuestStatusInProgress (line 42) | QuestStatusInProgress
  constant QuestNone (line 47) | QuestNone = iota
  constant Quest1 (line 49) | Quest1
  constant Quest2 (line 51) | Quest2
  constant Quest3 (line 53) | Quest3
  constant Quest4 (line 55) | Quest4
  constant Quest5 (line 57) | Quest5
  constant Quest6 (line 59) | Quest6

FILE: d2common/d2enum/region_id.go
  type RegionIdType (line 4) | type RegionIdType
  constant RegionNone (line 8) | RegionNone RegionIdType = iota
  constant RegionAct1Town (line 9) | RegionAct1Town
  constant RegionAct1Wilderness (line 10) | RegionAct1Wilderness
  constant RegionAct1Cave (line 11) | RegionAct1Cave
  constant RegionAct1Crypt (line 12) | RegionAct1Crypt
  constant RegionAct1Monestary (line 13) | RegionAct1Monestary
  constant RegionAct1Courtyard (line 14) | RegionAct1Courtyard
  constant RegionAct1Barracks (line 15) | RegionAct1Barracks
  constant RegionAct1Jail (line 16) | RegionAct1Jail
  constant RegionAct1Cathedral (line 17) | RegionAct1Cathedral
  constant RegionAct1Catacombs (line 18) | RegionAct1Catacombs
  constant RegionAct1Tristram (line 19) | RegionAct1Tristram
  constant RegionAct2Town (line 20) | RegionAct2Town
  constant RegionAct2Sewer (line 21) | RegionAct2Sewer
  constant RegionAct2Harem (line 22) | RegionAct2Harem
  constant RegionAct2Basement (line 23) | RegionAct2Basement
  constant RegionAct2Desert (line 24) | RegionAct2Desert
  constant RegionAct2Tomb (line 25) | RegionAct2Tomb
  constant RegionAct2Lair (line 26) | RegionAct2Lair
  constant RegionAct2Arcane (line 27) | RegionAct2Arcane
  constant RegionAct3Town (line 28) | RegionAct3Town
  constant RegionAct3Jungle (line 29) | RegionAct3Jungle
  constant RegionAct3Kurast (line 30) | RegionAct3Kurast
  constant RegionAct3Spider (line 31) | RegionAct3Spider
  constant RegionAct3Dungeon (line 32) | RegionAct3Dungeon
  constant RegionAct3Sewer (line 33) | RegionAct3Sewer
  constant RegionAct4Town (line 34) | RegionAct4Town
  constant RegionAct4Mesa (line 35) | RegionAct4Mesa
  constant RegionAct4Lava (line 36) | RegionAct4Lava
  constant RegonAct5Town (line 37) | RegonAct5Town
  constant RegionAct5Siege (line 38) | RegionAct5Siege
  constant RegionAct5Barricade (line 39) | RegionAct5Barricade
  constant RegionAct5Temple (line 40) | RegionAct5Temple
  constant RegionAct5IceCaves (line 41) | RegionAct5IceCaves
  constant RegionAct5Baal (line 42) | RegionAct5Baal
  constant RegionAct5Lava (line 43) | RegionAct5Lava

FILE: d2common/d2enum/region_layer.go
  type RegionLayerType (line 4) | type RegionLayerType
  constant RegionLayerTypeFloors (line 8) | RegionLayerTypeFloors RegionLayerType = iota
  constant RegionLayerTypeWalls (line 9) | RegionLayerTypeWalls
  constant RegionLayerTypeShadows (line 10) | RegionLayerTypeShadows

FILE: d2common/d2enum/render_type.go
  type RenderType (line 4) | type RenderType
  constant Ebiten (line 8) | Ebiten RenderType = iota + 1

FILE: d2common/d2enum/skill_class.go
  type SkillClass (line 6) | type SkillClass
    method FromToken (line 33) | func (sc *SkillClass) FromToken(classToken string) SkillClass {
    method GetToken (line 62) | func (sc SkillClass) GetToken() string {
  constant SkillClassGeneric (line 10) | SkillClassGeneric SkillClass = iota
  constant SkillClassBarbarian (line 11) | SkillClassBarbarian
  constant SkillClassNecromancer (line 12) | SkillClassNecromancer
  constant SkillClassPaladin (line 13) | SkillClassPaladin
  constant SkillClassAssassin (line 14) | SkillClassAssassin
  constant SkillClassSorceress (line 15) | SkillClassSorceress
  constant SkillClassAmazon (line 16) | SkillClassAmazon
  constant SkillClassDruid (line 17) | SkillClassDruid
  constant SkillClassTokenGeneric (line 22) | SkillClassTokenGeneric     = ""
  constant SkillClassTokenBarbarian (line 23) | SkillClassTokenBarbarian   = "bar"
  constant SkillClassTokenNecromancer (line 24) | SkillClassTokenNecromancer = "nec"
  constant SkillClassTokenPaladin (line 25) | SkillClassTokenPaladin     = "pal"
  constant SkillClassTokenAssassin (line 26) | SkillClassTokenAssassin    = "ass"
  constant SkillClassTokenSorceress (line 27) | SkillClassTokenSorceress   = "sor"
  constant SkillClassTokenAmazon (line 28) | SkillClassTokenAmazon      = "ama"
  constant SkillClassTokenDruid (line 29) | SkillClassTokenDruid       = "dru"

FILE: d2common/d2enum/terminal_category.go
  type TermCategory (line 4) | type TermCategory
  constant TermCategoryNone (line 8) | TermCategoryNone TermCategory = iota
  constant TermCategoryInfo (line 9) | TermCategoryInfo
  constant TermCategoryWarning (line 10) | TermCategoryWarning
  constant TermCategoryError (line 11) | TermCategoryError

FILE: d2common/d2enum/tile.go
  type TileType (line 4) | type TileType
    method LowerWall (line 31) | func (tile TileType) LowerWall() bool {
    method UpperWall (line 44) | func (tile TileType) UpperWall() bool {
    method Special (line 64) | func (tile TileType) Special() bool {
    method String (line 73) | func (tile TileType) String() string {
  constant TileFloor (line 8) | TileFloor TileType = iota
  constant TileLeftWall (line 9) | TileLeftWall
  constant TileRightWall (line 10) | TileRightWall
  constant TileRightPartOfNorthCornerWall (line 11) | TileRightPartOfNorthCornerWall
  constant TileLeftPartOfNorthCornerWall (line 12) | TileLeftPartOfNorthCornerWall
  constant TileLeftEndWall (line 13) | TileLeftEndWall
  constant TileRightEndWall (line 14) | TileRightEndWall
  constant TileSouthCornerWall (line 15) | TileSouthCornerWall
  constant TileLeftWallWithDoor (line 16) | TileLeftWallWithDoor
  constant TileRightWallWithDoor (line 17) | TileRightWallWithDoor
  constant TileSpecialTile1 (line 18) | TileSpecialTile1
  constant TileSpecialTile2 (line 19) | TileSpecialTile2
  constant TilePillarsColumnsAndStandaloneObjects (line 20) | TilePillarsColumnsAndStandaloneObjects
  constant TileShadow (line 21) | TileShadow
  constant TileTree (line 22) | TileTree
  constant TileRoof (line 23) | TileRoof
  constant TileLowerWallsEquivalentToLeftWall (line 24) | TileLowerWallsEquivalentToLeftWall
  constant TileLowerWallsEquivalentToRightWall (line 25) | TileLowerWallsEquivalentToRightWall
  constant TileLowerWallsEquivalentToRightLeftNorthCornerWall (line 26) | TileLowerWallsEquivalentToRightLeftNorthCornerWall
  constant TileLowerWallsEquivalentToSouthCornerwall (line 27) | TileLowerWallsEquivalentToSouthCornerwall

FILE: d2common/d2enum/weapon_class.go
  type WeaponClass (line 7) | type WeaponClass
    method Name (line 29) | func (w WeaponClass) Name() string {
  constant WeaponClassNone (line 11) | WeaponClassNone                 WeaponClass = iota
  constant WeaponClassHandToHand (line 12) | WeaponClassHandToHand
  constant WeaponClassBow (line 13) | WeaponClassBow
  constant WeaponClassOneHandSwing (line 14) | WeaponClassOneHandSwing
  constant WeaponClassOneHandThrust (line 15) | WeaponClassOneHandThrust
  constant WeaponClassStaff (line 16) | WeaponClassStaff
  constant WeaponClassTwoHandSwing (line 17) | WeaponClassTwoHandSwing
  constant WeaponClassTwoHandThrust (line 18) | WeaponClassTwoHandThrust
  constant WeaponClassCrossbow (line 19) | WeaponClassCrossbow
  constant WeaponClassLeftJabRightSwing (line 20) | WeaponClassLeftJabRightSwing
  constant WeaponClassLeftJabRightThrust (line 21) | WeaponClassLeftJabRightThrust
  constant WeaponClassLeftSwingRightSwing (line 22) | WeaponClassLeftSwingRightSwing
  constant WeaponClassLeftSwingRightThrust (line 23) | WeaponClassLeftSwingRightThrust
  constant WeaponClassOneHandToHand (line 24) | WeaponClassOneHandToHand
  constant WeaponClassTwoHandToHand (line 25) | WeaponClassTwoHandToHand

FILE: d2common/d2enum/weapon_class_string.go
  function _ (line 7) | func _() {
  constant _WeaponClass_name (line 28) | _WeaponClass_name = "hthbow1hs1htstf2hs2htxbw1js1jt1ss1stht1ht2"
  method String (line 32) | func (i WeaponClass) String() string {

FILE: d2common/d2enum/weapon_class_string2enum.go
  function WeaponClassFromString (line 8) | func WeaponClassFromString(s string) WeaponClass {
  function _ (line 20) | func _(s string) {

FILE: d2common/d2fileformats/d2animdata/animdata.go
  constant numBlocks (line 12) | numBlocks             = 256
  constant maxRecordsPerBlock (line 13) | maxRecordsPerBlock    = 67
  constant byteCountName (line 14) | byteCountName         = 8
  constant byteCountSpeedPadding (line 15) | byteCountSpeedPadding = 2
  constant numEvents (line 16) | numEvents             = 144
  constant speedDivisor (line 17) | speedDivisor          = 256
  constant speedBaseFPS (line 18) | speedBaseFPS          = 25
  constant milliseconds (line 19) | milliseconds          = 1000
  type AnimationData (line 23) | type AnimationData struct
    method GetRecordNames (line 30) | func (ad *AnimationData) GetRecordNames() []string {
    method GetRecord (line 42) | func (ad *AnimationData) GetRecord(name string) *AnimationDataRecord {
    method GetRecords (line 55) | func (ad *AnimationData) GetRecords(name string) []*AnimationDataRecord {
    method GetRecordsCount (line 60) | func (ad *AnimationData) GetRecordsCount() int {
    method PushRecord (line 65) | func (ad *AnimationData) PushRecord(name string) {
    method DeleteRecord (line 75) | func (ad *AnimationData) DeleteRecord(name string, recordIdx int) error {
    method AddEntry (line 96) | func (ad *AnimationData) AddEntry(name string) error {
    method DeleteEntry (line 108) | func (ad *AnimationData) DeleteEntry(name string) error {
    method Marshal (line 214) | func (ad *AnimationData) Marshal() []byte {
  function Load (line 121) | func Load(data []byte) (*AnimationData, error) {

FILE: d2common/d2fileformats/d2animdata/animdata_test.go
  function TestLoad (line 9) | func TestLoad(t *testing.T) {
  function TestLoad_BadData (line 41) | func TestLoad_BadData(t *testing.T) {
  function TestAnimationData_GetRecordNames (line 73) | func TestAnimationData_GetRecordNames(t *testing.T) {
  function TestAnimationData_GetRecords (line 90) | func TestAnimationData_GetRecords(t *testing.T) {
  function TestAnimationData_GetRecord (line 112) | func TestAnimationData_GetRecord(t *testing.T) {
  function TestAnimationDataRecord_FPS (line 131) | func TestAnimationDataRecord_FPS(t *testing.T) {
  function TestAnimationData_Marshal (line 158) | func TestAnimationData_Marshal(t *testing.T) {
  function TestAnimationData_DeleteRecord (line 213) | func TestAnimationData_DeleteRecord(t *testing.T) {
  function TestAnimationData_PushRecord (line 239) | func TestAnimationData_PushRecord(t *testing.T) {
  function TestAnimationData_AddEntry (line 260) | func TestAnimationData_AddEntry(t *testing.T) {
  function TestAnimationData_DeleteEntry (line 275) | func TestAnimationData_DeleteEntry(t *testing.T) {

FILE: d2common/d2fileformats/d2animdata/block.go
  type block (line 3) | type block struct

FILE: d2common/d2fileformats/d2animdata/events.go
  type AnimationEvent (line 4) | type AnimationEvent
  constant AnimationEventNone (line 8) | AnimationEventNone AnimationEvent = iota
  constant AnimationEventAttack (line 9) | AnimationEventAttack
  constant AnimationEventMissile (line 10) | AnimationEventMissile
  constant AnimationEventSound (line 11) | AnimationEventSound
  constant AnimationEventSkill (line 12) | AnimationEventSkill

FILE: d2common/d2fileformats/d2animdata/hash.go
  type hashTable (line 5) | type hashTable
  function hashName (line 7) | func hashName(name string) byte {

FILE: d2common/d2fileformats/d2animdata/record.go
  type AnimationDataRecord (line 4) | type AnimationDataRecord struct
    method FramesPerDirection (line 12) | func (r *AnimationDataRecord) FramesPerDirection() int {
    method SetFramesPerDirection (line 17) | func (r *AnimationDataRecord) SetFramesPerDirection(fpd uint32) {
    method Speed (line 22) | func (r *AnimationDataRecord) Speed() int {
    method SetSpeed (line 27) | func (r *AnimationDataRecord) SetSpeed(s uint16) {
    method FPS (line 32) | func (r *AnimationDataRecord) FPS() float64 {
    method FrameDurationMS (line 41) | func (r *AnimationDataRecord) FrameDurationMS() float64 {
    method Events (line 46) | func (r *AnimationDataRecord) Events() map[int]AnimationEvent {
    method Event (line 51) | func (r *AnimationDataRecord) Event(idx int) AnimationEvent {
    method SetEvent (line 61) | func (r *AnimationDataRecord) SetEvent(index int, event AnimationEvent) {

FILE: d2common/d2fileformats/d2cof/cof.go
  constant numUnknownHeaderBytes (line 11) | numUnknownHeaderBytes = 21
  constant numUnknownBodyBytes (line 12) | numUnknownBodyBytes   = 3
  constant numHeaderBytes (line 13) | numHeaderBytes        = 4 + numUnknownHeaderBytes
  constant numLayerBytes (line 14) | numLayerBytes         = 9
  constant headerNumLayers (line 18) | headerNumLayers = iota
  constant headerFramesPerDir (line 19) | headerFramesPerDir
  constant headerNumDirs (line 20) | headerNumDirs
  constant headerSpeed (line 21) | headerSpeed = numHeaderBytes - 1
  constant layerType (line 25) | layerType = iota
  constant layerShadow (line 26) | layerShadow
  constant layerSelectable (line 27) | layerSelectable
  constant layerTransparent (line 28) | layerTransparent
  constant layerDrawEffect (line 29) | layerDrawEffect
  constant layerWeaponClass (line 30) | layerWeaponClass
  constant badCharacter (line 34) | badCharacter = string(byte(0))
  function New (line 38) | func New() *COF {
  function Marshal (line 54) | func Marshal(c *COF) []byte {
  function Unmarshal (line 59) | func Unmarshal(data []byte) (*COF, error) {
  type COF (line 67) | type COF struct
    method Unmarshal (line 83) | func (c *COF) Unmarshal(fileData []byte) error {
    method loadHeader (line 128) | func (c *COF) loadHeader(b []byte) {
    method loadCOFLayers (line 136) | func (c *COF) loadCOFLayers(streamReader *d2datautils.StreamReader) er...
    method loadAnimationFrames (line 161) | func (c *COF) loadAnimationFrames(b []byte) {
    method loadPriority (line 169) | func (c *COF) loadPriority(priorityBytes []byte) {
    method Marshal (line 185) | func (c *COF) Marshal() []byte {

FILE: d2common/d2fileformats/d2cof/cof_dir_lookup.go
  type directionCount (line 3) | type directionCount
  constant four (line 6) | four directionCount = 4 << iota
  constant eight (line 7) | eight
  constant sixteen (line 8) | sixteen
  constant thirtyTwo (line 9) | thirtyTwo
  constant sixtyFour (line 10) | sixtyFour
  function Dir64ToCof (line 14) | func Dir64ToCof(direction, numDirections int) int {

FILE: d2common/d2fileformats/d2cof/cof_layer.go
  type CofLayer (line 6) | type CofLayer struct

FILE: d2common/d2fileformats/d2cof/cof_test.go
  function TestCOF_New (line 5) | func TestCOF_New(t *testing.T) {
  function TestCOF_Marshal_Unmarshal (line 13) | func TestCOF_Marshal_Unmarshal(t *testing.T) {

FILE: d2common/d2fileformats/d2cof/helpers.go
  method FPS (line 4) | func (c *COF) FPS() float64 {
  method Duration (line 19) | func (c *COF) Duration() float64 {

FILE: d2common/d2fileformats/d2dat/dat.go
  constant b (line 9) | b = iota
  constant g (line 10) | g
  constant r (line 11) | r
  constant o (line 12) | o
  function Load (line 16) | func Load(data []byte) (d2interface.Palette, error) {
  method Marshal (line 28) | func (p *DATPalette) Marshal() []byte {

FILE: d2common/d2fileformats/d2dat/dat_color.go
  type DATColor (line 4) | type DATColor struct
    method R (line 24) | func (c *DATColor) R() uint8 {
    method G (line 29) | func (c *DATColor) G() uint8 {
    method B (line 34) | func (c *DATColor) B() uint8 {
    method A (line 39) | func (c *DATColor) A() uint8 {
    method RGBA (line 44) | func (c *DATColor) RGBA() uint32 {
    method SetRGBA (line 49) | func (c *DATColor) SetRGBA(rgba uint32) {
    method BGRA (line 54) | func (c *DATColor) BGRA() uint32 {
    method SetBGRA (line 59) | func (c *DATColor) SetBGRA(bgra uint32) {
  constant colorBits (line 12) | colorBits = 8
  constant mask (line 13) | mask      = 0xff
  constant bitShift0 (line 17) | bitShift0 = iota * colorBits
  constant bitShift8 (line 18) | bitShift8
  constant bitShift16 (line 19) | bitShift16
  constant bitShift24 (line 20) | bitShift24
  function toComposite (line 63) | func toComposite(w, x, y, z uint8) uint32 {
  function toComponent (line 72) | func toComponent(wxyz uint32) (w, x, y, z uint8) {

FILE: d2common/d2fileformats/d2dat/dat_palette.go
  constant numColors (line 10) | numColors = 256
  type DATPalette (line 14) | type DATPalette struct
    method NumColors (line 29) | func (p *DATPalette) NumColors() int {
    method GetColors (line 34) | func (p *DATPalette) GetColors() [numColors]d2interface.Color {
    method GetColor (line 39) | func (p *DATPalette) GetColor(idx int) (d2interface.Color, error) {
  function New (line 19) | func New() *DATPalette {

FILE: d2common/d2fileformats/d2dc6/dc6.go
  constant endOfScanLine (line 8) | endOfScanLine = 0x80
  constant maxRunLength (line 9) | maxRunLength  = 0x7f
  constant terminationSize (line 11) | terminationSize = 4
  constant terminatorSize (line 12) | terminatorSize  = 3
  type scanlineState (line 15) | type scanlineState
  constant endOfLine (line 18) | endOfLine scanlineState = iota
  constant runOfTransparentPixels (line 19) | runOfTransparentPixels
  constant runOfOpaquePixels (line 20) | runOfOpaquePixels
  type DC6 (line 24) | type DC6 struct
    method Unmarshal (line 64) | func (d *DC6) Unmarshal(data []byte) error {
    method loadHeader (line 93) | func (d *DC6) loadHeader(r *d2datautils.StreamReader) error {
    method loadFrames (line 123) | func (d *DC6) loadFrames(r *d2datautils.StreamReader) error {
    method Marshal (line 176) | func (d *DC6) Marshal() []byte {
    method DecodeFrame (line 211) | func (d *DC6) DecodeFrame(frameIndex int) []byte {
    method Clone (line 262) | func (d *DC6) Clone() *DC6 {
  function New (line 36) | func New() *DC6 {
  function Load (line 52) | func Load(data []byte) (*DC6, error) {
  function scanlineType (line 249) | func scanlineType(b int) scanlineState {

FILE: d2common/d2fileformats/d2dc6/dc6_frame.go
  type DC6Frame (line 4) | type DC6Frame struct

FILE: d2common/d2fileformats/d2dc6/dc6_frame_header.go
  type DC6FrameHeader (line 4) | type DC6FrameHeader struct

FILE: d2common/d2fileformats/d2dc6/dc6_header.go
  type DC6Header (line 4) | type DC6Header struct

FILE: d2common/d2fileformats/d2dc6/dc6_test.go
  function TestDC6New (line 7) | func TestDC6New(t *testing.T) {
  function getExampleDC6 (line 15) | func getExampleDC6() *DC6 {
  function TestDC6Unmarshal (line 43) | func TestDC6Unmarshal(t *testing.T) {
  function TestDC6Clone (line 60) | func TestDC6Clone(t *testing.T) {

FILE: d2common/d2fileformats/d2dcc/dcc.go
  constant dccFileSignature (line 9) | dccFileSignature = 0x74
  constant directionOffsetMultiplier (line 10) | directionOffsetMultiplier = 8
  type DCC (line 13) | type DCC struct
    method decodeDirection (line 60) | func (d *DCC) decodeDirection(direction int) *DCCDirection {
    method Clone (line 66) | func (d *DCC) Clone() *DCC {
  function Load (line 24) | func Load(fileData []byte) (*DCC, error) {

FILE: d2common/d2fileformats/d2dcc/dcc_cell.go
  type DCCCell (line 4) | type DCCCell struct

FILE: d2common/d2fileformats/d2dcc/dcc_dir_lookup.go
  type directionCount (line 3) | type directionCount
  constant four (line 6) | four directionCount = 4 << iota
  constant eight (line 7) | eight
  constant sixteen (line 8) | sixteen
  constant thirtyTwo (line 9) | thirtyTwo
  constant sixtyFour (line 10) | sixtyFour
  function Dir64ToDcc (line 15) | func Dir64ToDcc(direction, numDirections int) int {

FILE: d2common/d2fileformats/d2dcc/dcc_direction.go
  constant baseMinx (line 13) | baseMinx = 100000
  constant baseMiny (line 14) | baseMiny = 100000
  constant baseMaxx (line 15) | baseMaxx = -100000
  constant baseMaxy (line 16) | baseMaxy = -100000
  constant cellsPerRow (line 19) | cellsPerRow = 4
  type DCCDirection (line 22) | type DCCDirection struct
    method verify (line 153) | func (v *DCCDirection) verify(
    method generateFrames (line 177) | func (v *DCCDirection) generateFrames(pcd *d2datautils.BitMuncher) {
    method fillPixelBuffer (line 280) | func (v *DCCDirection) fillPixelBuffer(pcd, ec, pm, et, rp *d2datautil...
    method calculateCells (line 414) | func (v *DCCDirection) calculateCells() {
  function CreateDCCDirection (line 48) | func CreateDCCDirection(bm *d2datautils.BitMuncher, file *DCC) *DCCDirec...

FILE: d2common/d2fileformats/d2dcc/dcc_direction_frame.go
  type DCCDirectionFrame (line 11) | type DCCDirectionFrame struct
    method recalculateCells (line 57) | func (v *DCCDirectionFrame) recalculateCells(direction *DCCDirection) {
  function CreateDCCDirectionFrame (line 28) | func CreateDCCDirectionFrame(bits *d2datautils.BitMuncher, direction *DC...

FILE: d2common/d2fileformats/d2dcc/dcc_pixel_buffer_entry.go
  type DCCPixelBufferEntry (line 4) | type DCCPixelBufferEntry struct

FILE: d2common/d2fileformats/d2ds1/ds1.go
  constant subType1 (line 14) | subType1 = 1
  constant subType2 (line 15) | subType2 = 2
  constant wallZeroBitmask (line 19) | wallZeroBitmask = 0xFFFFFF00
  constant wallZeroOffset (line 20) | wallZeroOffset  = 8
  constant wallTypeBitmask (line 21) | wallTypeBitmask = 0x000000FF
  constant unknown1BytesCount (line 25) | unknown1BytesCount = 8
  type DS1 (line 29) | type DS1 struct
    method Unmarshal (line 54) | func (ds1 *DS1) Unmarshal(fileData []byte) (*DS1, error) {
    method loadHeader (line 70) | func (ds1 *DS1) loadHeader(br *d2datautils.StreamReader) error {
    method loadBody (line 126) | func (ds1 *DS1) loadBody(stream *d2datautils.StreamReader) error {
    method loadFileList (line 197) | func (ds1 *DS1) loadFileList(br *d2datautils.StreamReader) error {
    method loadObjects (line 230) | func (ds1 *DS1) loadObjects(br *d2datautils.StreamReader) error {
    method loadSubstitutions (line 283) | func (ds1 *DS1) loadSubstitutions(br *d2datautils.StreamReader) error {
    method getLayerSchema (line 342) | func (ds1 *DS1) getLayerSchema() []layerStreamType {
    method loadNPCs (line 393) | func (ds1 *DS1) loadNPCs(br *d2datautils.StreamReader) error {
    method loadNpcPaths (line 448) | func (ds1 *DS1) loadNpcPaths(br *d2datautils.StreamReader, objIdx, num...
    method loadLayerStreams (line 483) | func (ds1 *DS1) loadLayerStreams(br *d2datautils.StreamReader) error {
    method SetSize (line 534) | func (ds1 *DS1) SetSize(w, h int) {
    method Marshal (line 539) | func (ds1 *DS1) Marshal() []byte {
    method encodeLayers (line 619) | func (ds1 *DS1) encodeLayers(sw *d2datautils.StreamWriter) {
    method encodeNPCs (line 651) | func (ds1 *DS1) encodeNPCs(sw *d2datautils.StreamWriter) {
    method Version (line 681) | func (ds1 *DS1) Version() int {
    method SetVersion (line 686) | func (ds1 *DS1) SetVersion(v int) {
  constant defaultNumFloors (line 43) | defaultNumFloors        = 1
  constant defaultNumShadows (line 44) | defaultNumShadows       = maxShadowLayers
  constant defaultNumSubstitutions (line 45) | defaultNumSubstitutions = 0
  function Unmarshal (line 49) | func Unmarshal(fileData []byte) (*DS1, error) {

FILE: d2common/d2fileformats/d2ds1/ds1_layers.go
  constant maxWallLayers (line 4) | maxWallLayers         = 4
  constant maxFloorLayers (line 5) | maxFloorLayers        = 2
  constant maxShadowLayers (line 6) | maxShadowLayers       = 1
  constant maxSubstitutionLayers (line 7) | maxSubstitutionLayers = 1
  type LayerGroupType (line 11) | type LayerGroupType
    method String (line 21) | func (l LayerGroupType) String() string {
  constant FloorLayerGroup (line 15) | FloorLayerGroup LayerGroupType = iota
  constant WallLayerGroup (line 16) | WallLayerGroup
  constant ShadowLayerGroup (line 17) | ShadowLayerGroup
  constant SubstitutionLayerGroup (line 18) | SubstitutionLayerGroup
  type layerGroup (line 37) | type layerGroup
  type ds1Layers (line 39) | type ds1Layers struct
    method ensureInit (line 47) | func (l *ds1Layers) ensureInit() {
    method cull (line 66) | func (l *ds1Layers) cull() {
    method cullNilLayers (line 74) | func (l *ds1Layers) cullNilLayers(t LayerGroupType) {
    method Size (line 95) | func (l *ds1Layers) Size() (w, h int) {
    method SetSize (line 102) | func (l *ds1Layers) SetSize(w, h int) {
    method enforceSize (line 111) | func (l *ds1Layers) enforceSize(t LayerGroupType) {
    method Width (line 125) | func (l *ds1Layers) Width() int {
    method SetWidth (line 130) | func (l *ds1Layers) SetWidth(w int) {
    method Height (line 134) | func (l *ds1Layers) Height() int {
    method SetHeight (line 139) | func (l *ds1Layers) SetHeight(h int) {
    method push (line 144) | func (l *ds1Layers) push(t LayerGroupType, layer *Layer) {
    method pop (line 159) | func (l *ds1Layers) pop(t LayerGroupType) *Layer {
    method get (line 182) | func (l *ds1Layers) get(t LayerGroupType, idx int) *Layer {
    method insert (line 198) | func (l *ds1Layers) insert(t LayerGroupType, idx int, newLayer *Layer) {
    method delete (line 234) | func (l *ds1Layers) delete(t LayerGroupType, idx int) {
    method GetFloor (line 252) | func (l *ds1Layers) GetFloor(idx int) *Layer {
    method PushFloor (line 256) | func (l *ds1Layers) PushFloor(floor *Layer) *ds1Layers {
    method PopFloor (line 261) | func (l *ds1Layers) PopFloor() *Layer {
    method InsertFloor (line 265) | func (l *ds1Layers) InsertFloor(idx int, newFloor *Layer) {
    method DeleteFloor (line 269) | func (l *ds1Layers) DeleteFloor(idx int) {
    method GetWall (line 273) | func (l *ds1Layers) GetWall(idx int) *Layer {
    method PushWall (line 277) | func (l *ds1Layers) PushWall(wall *Layer) *ds1Layers {
    method PopWall (line 282) | func (l *ds1Layers) PopWall() *Layer {
    method InsertWall (line 286) | func (l *ds1Layers) InsertWall(idx int, newWall *Layer) {
    method DeleteWall (line 290) | func (l *ds1Layers) DeleteWall(idx int) {
    method GetShadow (line 294) | func (l *ds1Layers) GetShadow(idx int) *Layer {
    method PushShadow (line 298) | func (l *ds1Layers) PushShadow(shadow *Layer) *ds1Layers {
    method PopShadow (line 303) | func (l *ds1Layers) PopShadow() *Layer {
    method InsertShadow (line 307) | func (l *ds1Layers) InsertShadow(idx int, newShadow *Layer) {
    method DeleteShadow (line 311) | func (l *ds1Layers) DeleteShadow(idx int) {
    method GetSubstitution (line 315) | func (l *ds1Layers) GetSubstitution(idx int) *Layer {
    method PushSubstitution (line 319) | func (l *ds1Layers) PushSubstitution(sub *Layer) *ds1Layers {
    method PopSubstitution (line 324) | func (l *ds1Layers) PopSubstitution() *Layer {
    method InsertSubstitution (line 328) | func (l *ds1Layers) InsertSubstitution(idx int, newSubstitution *Layer) {
    method DeleteSubstitution (line 332) | func (l *ds1Layers) DeleteSubstitution(idx int) {
    method GetLayersGroup (line 337) | func (l *ds1Layers) GetLayersGroup(t LayerGroupType) (group *layerGrou...
  function GetMaxGroupLen (line 355) | func GetMaxGroupLen(t LayerGroupType) (max int) {

FILE: d2common/d2fileformats/d2ds1/ds1_layers_test.go
  function Test_ds1Layers_Delete (line 7) | func Test_ds1Layers_Delete(t *testing.T) {
  function ds1LayersDelete (line 22) | func ds1LayersDelete(t *testing.T, lt LayerGroupType) {
  function Test_ds1Layers_Get (line 59) | func Test_ds1Layers_Get(t *testing.T) {
  function ds1LayersGet (line 74) | func ds1LayersGet(t *testing.T, lt LayerGroupType) {
  function Test_ds1Layers_Insert (line 101) | func Test_ds1Layers_Insert(t *testing.T) {
  function ds1LayersInsert (line 116) | func ds1LayersInsert(t *testing.T, lt LayerGroupType) {
  function Test_ds1Layers_Pop (line 166) | func Test_ds1Layers_Pop(t *testing.T) {
  function ds1layerPop (line 184) | func ds1layerPop(lt LayerGroupType, t *testing.T) {
  function Test_ds1Layers_Push (line 246) | func Test_ds1Layers_Push(t *testing.T) {
  function ds1layerPush (line 268) | func ds1layerPush(lt LayerGroupType, t *testing.T) { //nolint:funlen // ...

FILE: d2common/d2fileformats/d2ds1/ds1_test.go
  function exampleData (line 10) | func exampleData() *DS1 { //nolint:funlen // not a big deal if this is l...
  function TestDS1_MarshalUnmarshal (line 187) | func TestDS1_MarshalUnmarshal(t *testing.T) {
  function TestDS1_Version (line 198) | func TestDS1_Version(t *testing.T) {
  function TestDS1_SetSize (line 210) | func TestDS1_SetSize(t *testing.T) {
  function Test_getLayerSchema (line 224) | func Test_getLayerSchema(t *testing.T) {

FILE: d2common/d2fileformats/d2ds1/ds1_version.go
  type ds1version (line 3) | type ds1version
    method hasUnknown1Bytes (line 20) | func (v ds1version) hasUnknown1Bytes() bool {
    method hasUnknown2Bytes (line 25) | func (v ds1version) hasUnknown2Bytes() bool {
    method specifiesAct (line 29) | func (v ds1version) specifiesAct() bool {
    method specifiesSubstitutionType (line 34) | func (v ds1version) specifiesSubstitutionType() bool {
    method hasStandardLayers (line 39) | func (v ds1version) hasStandardLayers() bool {
    method specifiesWalls (line 44) | func (v ds1version) specifiesWalls() bool {
    method specifiesFloors (line 49) | func (v ds1version) specifiesFloors() bool {
    method hasFileList (line 54) | func (v ds1version) hasFileList() bool {
    method hasObjects (line 58) | func (v ds1version) hasObjects() bool {
    method hasSubstitutions (line 62) | func (v ds1version) hasSubstitutions() bool {
    method specifiesNPCs (line 66) | func (v ds1version) specifiesNPCs() bool {
    method specifiesNPCActions (line 70) | func (v ds1version) specifiesNPCActions() bool {
  constant v3 (line 6) | v3  ds1version = 3
  constant v4 (line 7) | v4  ds1version = 4
  constant v7 (line 8) | v7  ds1version = 7
  constant v8 (line 9) | v8  ds1version = 8
  constant v9 (line 10) | v9  ds1version = 9
  constant v10 (line 11) | v10 ds1version = 10
  constant v12 (line 12) | v12 ds1version = 12
  constant v13 (line 13) | v13 ds1version = 13
  constant v14 (line 14) | v14 ds1version = 14
  constant v15 (line 15) | v15 ds1version = 15
  constant v16 (line 16) | v16 ds1version = 16
  constant v18 (line 17) | v18 ds1version = 18

FILE: d2common/d2fileformats/d2ds1/layer.go
  type layerStreamType (line 4) | type layerStreamType
  constant layerStreamWall1 (line 8) | layerStreamWall1 layerStreamType = iota
  constant layerStreamWall2 (line 9) | layerStreamWall2
  constant layerStreamWall3 (line 10) | layerStreamWall3
  constant layerStreamWall4 (line 11) | layerStreamWall4
  constant layerStreamOrientation1 (line 12) | layerStreamOrientation1
  constant layerStreamOrientation2 (line 13) | layerStreamOrientation2
  constant layerStreamOrientation3 (line 14) | layerStreamOrientation3
  constant layerStreamOrientation4 (line 15) | layerStreamOrientation4
  constant layerStreamFloor1 (line 16) | layerStreamFloor1
  constant layerStreamFloor2 (line 17) | layerStreamFloor2
  constant layerStreamShadow1 (line 18) | layerStreamShadow1
  constant layerStreamSubstitute1 (line 19) | layerStreamSubstitute1
  type tileRow (line 23) | type tileRow
  type tileGrid (line 24) | type tileGrid
  type Layer (line 28) | type Layer struct
    method Tile (line 33) | func (l *Layer) Tile(x, y int) *Tile {
    method SetTile (line 42) | func (l *Layer) SetTile(x, y int, t *Tile) {
    method Width (line 51) | func (l *Layer) Width() int {
    method SetWidth (line 60) | func (l *Layer) SetWidth(w int) *Layer {
    method Height (line 91) | func (l *Layer) Height() int {
    method SetHeight (line 100) | func (l *Layer) SetHeight(h int) *Layer {
    method Size (line 133) | func (l *Layer) Size() (w, h int) {
    method SetSize (line 138) | func (l *Layer) SetSize(w, h int) *Layer {

FILE: d2common/d2fileformats/d2ds1/layer_test.go
  function Test_layers (line 5) | func Test_layers(t *testing.T) {

FILE: d2common/d2fileformats/d2ds1/object.go
  type Object (line 8) | type Object struct
    method Equals (line 18) | func (o *Object) Equals(other *Object) bool {

FILE: d2common/d2fileformats/d2ds1/substitution_group.go
  type SubstitutionGroup (line 4) | type SubstitutionGroup struct

FILE: d2common/d2fileformats/d2ds1/tile.go
  constant prop1Bitmask (line 9) | prop1Bitmask = 0x000000FF
  constant prop1Offset (line 10) | prop1Offset  = 0
  constant prop1Length (line 11) | prop1Length  = 8
  constant sequenceBitmask (line 13) | sequenceBitmask = 0x00003F00
  constant sequenceOffset (line 14) | sequenceOffset  = 8
  constant sequenceLength (line 15) | sequenceLength  = 6
  constant unknown1Bitmask (line 17) | unknown1Bitmask = 0x000FC000
  constant unknown1Offset (line 18) | unknown1Offset  = 14
  constant unknown1Length (line 19) | unknown1Length  = 6
  constant styleBitmask (line 21) | styleBitmask = 0x03F00000
  constant styleOffset (line 22) | styleOffset  = 20
  constant styleLength (line 23) | styleLength  = 6
  constant unknown2Bitmask (line 25) | unknown2Bitmask = 0x7C000000
  constant unknown2Offset (line 26) | unknown2Offset  = 26
  constant unknown2Length (line 27) | unknown2Length  = 5
  constant hiddenBitmask (line 29) | hiddenBitmask = 0x80000000
  constant hiddenOffset (line 30) | hiddenOffset  = 31
  constant hiddenLength (line 31) | hiddenLength  = 1
  type tileCommonFields (line 34) | type tileCommonFields struct
  type tileFloorShadowFields (line 45) | type tileFloorShadowFields struct
  type tileSubstitutionFields (line 49) | type tileSubstitutionFields struct
  type tileWallFields (line 53) | type tileWallFields struct
  type Tile (line 59) | type Tile struct
    method Hidden (line 67) | func (t *Tile) Hidden() bool {
    method DecodeWall (line 72) | func (t *Tile) DecodeWall(dw uint32) {
    method EncodeWall (line 82) | func (t *Tile) EncodeWall(sw *d2datautils.StreamWriter) {
    method decodeFloorShadow (line 91) | func (t *Tile) decodeFloorShadow(dw uint32) {
    method encodeFloorShadow (line 100) | func (t *Tile) encodeFloorShadow(sw *d2datautils.StreamWriter) {
    method DecodeFloor (line 110) | func (t *Tile) DecodeFloor(dw uint32) {
    method EncodeFloor (line 115) | func (t *Tile) EncodeFloor(sw *d2datautils.StreamWriter) {
    method DecodeShadow (line 120) | func (t *Tile) DecodeShadow(dw uint32) {
    method EncodeShadow (line 125) | func (t *Tile) EncodeShadow(sw *d2datautils.StreamWriter) {

FILE: d2common/d2fileformats/d2dt1/block.go
  type Block (line 4) | type Block struct
    method Format (line 16) | func (b *Block) Format() BlockDataFormat {
    method unknown1 (line 24) | func (b *Block) unknown1() []byte {
    method unknown2 (line 28) | func (b *Block) unknown2() []byte {

FILE: d2common/d2fileformats/d2dt1/dt1.go
  type BlockDataFormat (line 11) | type BlockDataFormat
  constant BlockFormatRLE (line 15) | BlockFormatRLE BlockDataFormat = 0
  constant BlockFormatIsometric (line 18) | BlockFormatIsometric BlockDataFormat = 1
  constant numUnknownHeaderBytes (line 22) | numUnknownHeaderBytes = 260
  constant knownMajorVersion (line 23) | knownMajorVersion     = 7
  constant knownMinorVersion (line 24) | knownMinorVersion     = 6
  constant numUnknownTileBytes1 (line 25) | numUnknownTileBytes1  = 4
  constant numUnknownTileBytes2 (line 26) | numUnknownTileBytes2  = 4
  constant numUnknownTileBytes3 (line 27) | numUnknownTileBytes3  = 7
  constant numUnknownTileBytes4 (line 28) | numUnknownTileBytes4  = 12
  constant numUnknownBlockBytes (line 29) | numUnknownBlockBytes  = 2
  type DT1 (line 33) | type DT1 struct
    method Marshal (line 247) | func (d *DT1) Marshal() []byte {
    method unknownHeaderBytes (line 319) | func (d *DT1) unknownHeaderBytes() []byte {
  function New (line 42) | func New() *DT1 {
  function LoadDT1 (line 53) | func LoadDT1(fileData []byte) (*DT1, error) {

FILE: d2common/d2fileformats/d2dt1/gfx_decode.go
  constant blockDataLength (line 4) | blockDataLength = 256
  function DecodeTileGfxData (line 8) | func DecodeTileGfxData(blocks []Block, pixels *[]byte, tileYOffset, tile...

FILE: d2common/d2fileformats/d2dt1/material.go
  type MaterialFlags (line 4) | type MaterialFlags struct
    method Encode (line 35) | func (m *MaterialFlags) Encode() uint16 {
  function NewMaterialFlags (line 19) | func NewMaterialFlags(data uint16) MaterialFlags {

FILE: d2common/d2fileformats/d2dt1/subtile.go
  type SubTileFlags (line 4) | type SubTileFlags struct
    method Combine (line 16) | func (s *SubTileFlags) Combine(f SubTileFlags) {
    method DebugString (line 28) | func (s *SubTileFlags) DebugString() string {
    method Encode (line 82) | func (s *SubTileFlags) Encode() byte {
  function NewSubTileFlags (line 68) | func NewSubTileFlags(data byte) SubTileFlags {

FILE: d2common/d2fileformats/d2dt1/subtile_test.go
  function TestNewSubTile (line 9) | func TestNewSubTile(t *testing.T) {

FILE: d2common/d2fileformats/d2dt1/tile.go
  type Tile (line 4) | type Tile struct
    method unknown1 (line 21) | func (t *Tile) unknown1() []byte {
    method unknown3 (line 25) | func (t *Tile) unknown3() []byte {
    method unknown4 (line 29) | func (t *Tile) unknown4() []byte {

FILE: d2common/d2fileformats/d2font/d2fontglyph/font_glyph.go
  function Create (line 5) | func Create(frame, width, height int) *FontGlyph {
  type FontGlyph (line 18) | type FontGlyph struct
    method SetSize (line 25) | func (fg *FontGlyph) SetSize(w, h int) {
    method Size (line 30) | func (fg *FontGlyph) Size() (w, h int) {
    method Width (line 35) | func (fg *FontGlyph) Width() int {
    method Height (line 40) | func (fg *FontGlyph) Height() int {
    method SetFrameIndex (line 45) | func (fg *FontGlyph) SetFrameIndex(idx int) {
    method FrameIndex (line 50) | func (fg *FontGlyph) FrameIndex() int {
    method Unknown1 (line 55) | func (fg *FontGlyph) Unknown1() []byte {
    method Unknown2 (line 60) | func (fg *FontGlyph) Unknown2() []byte {
    method Unknown3 (line 65) | func (fg *FontGlyph) Unknown3() []byte {

FILE: d2common/d2fileformats/d2font/font.go
  constant knownSignature (line 15) | knownSignature = "Woo!\x01"
  constant numHeaderBytes (line 19) | numHeaderBytes          = 12
  constant bytesPerGlyph (line 20) | bytesPerGlyph           = 14
  constant signatureBytesCount (line 21) | signatureBytesCount     = 5
  constant unknownHeaderBytesCount (line 22) | unknownHeaderBytesCount = 7
  constant unknown1BytesCount (line 23) | unknown1BytesCount      = 1
  constant unknown2BytesCount (line 24) | unknown2BytesCount      = 3
  constant unknown3BytesCount (line 25) | unknown3BytesCount      = 4
  type Font (line 29) | type Font struct
    method SetBackground (line 65) | func (f *Font) SetBackground(sheet d2interface.Animation) {
    method SetColor (line 77) | func (f *Font) SetColor(c color.Color) {
    method GetTextMetrics (line 82) | func (f *Font) GetTextMetrics(text string) (width, height int) {
    method RenderText (line 107) | func (f *Font) RenderText(text string, target d2interface.Surface) err...
    method initGlyphs (line 145) | func (f *Font) initGlyphs(sr *d2datautils.StreamReader) error {
    method Marshal (line 190) | func (f *Font) Marshal() []byte {
  function Load (line 37) | func Load(data []byte) (*Font, error) {

FILE: d2common/d2fileformats/d2mpq/crypto.go
  function cryptoLookup (line 12) | func cryptoLookup(index uint32) uint32 {
  function cryptoInitialize (line 23) | func cryptoInitialize() {
  function decrypt (line 41) | func decrypt(data []uint32, seed uint32) {
  function decryptBytes (line 56) | func decryptBytes(data []byte, seed uint32) {
  function decryptTable (line 73) | func decryptTable(r io.Reader, size uint32, name string) ([]uint32, erro...
  function hashFilename (line 99) | func hashFilename(key string) uint64 {
  function hashString (line 105) | func hashString(key string, hashType uint32) uint32 {
  function encrypt (line 119) | func encrypt(data []uint32, seed uint32) {

FILE: d2common/d2fileformats/d2mpq/mpq.go
  type MPQ (line 20) | type MPQ struct
    method getFileBlockData (line 77) | func (mpq *MPQ) getFileBlockData(fileName string) (*Block, error) {
    method Close (line 91) | func (mpq *MPQ) Close() error {
    method ReadFile (line 96) | func (mpq *MPQ) ReadFile(fileName string) ([]byte, error) {
    method ReadFileStream (line 118) | func (mpq *MPQ) ReadFileStream(fileName string) (d2interface.DataStrea...
    method ReadTextFile (line 135) | func (mpq *MPQ) ReadTextFile(fileName string) (string, error) {
    method Listfile (line 146) | func (mpq *MPQ) Listfile() ([]string, error) {
    method Path (line 167) | func (mpq *MPQ) Path() string {
    method Contains (line 172) | func (mpq *MPQ) Contains(filename string) bool {
    method Size (line 178) | func (mpq *MPQ) Size() uint32 {
  type PatchInfo (line 29) | type PatchInfo struct
  function New (line 37) | func New(fileName string) (*MPQ, error) {
  function FromFile (line 59) | func FromFile(fileName string) (*MPQ, error) {
  function openIgnoreCase (line 182) | func openIgnoreCase(mpqPath string) (*os.File, error) {

FILE: d2common/d2fileformats/d2mpq/mpq_block.go
  type FileFlag (line 9) | type FileFlag
  constant FileImplode (line 13) | FileImplode FileFlag = 0x00000100
  constant FileCompress (line 15) | FileCompress FileFlag = 0x00000200
  constant FileEncrypted (line 17) | FileEncrypted FileFlag = 0x00010000
  constant FileFixKey (line 19) | FileFixKey FileFlag = 0x00020000
  constant FilePatchFile (line 21) | FilePatchFile FileFlag = 0x00100000
  constant FileSingleUnit (line 23) | FileSingleUnit FileFlag = 0x01000000
  constant FileDeleteMarker (line 27) | FileDeleteMarker FileFlag = 0x02000000
  constant FileSectorCrc (line 29) | FileSectorCrc FileFlag = 0x04000000
  constant FileExists (line 31) | FileExists FileFlag = 0x80000000
  type Block (line 35) | type Block struct
    method HasFlag (line 46) | func (b *Block) HasFlag(flag FileFlag) bool {
    method calculateEncryptionSeed (line 50) | func (b *Block) calculateEncryptionSeed(fileName string) {
  method readBlockTable (line 57) | func (mpq *MPQ) readBlockTable() error {

FILE: d2common/d2fileformats/d2mpq/mpq_data_stream.go
  type MpqDataStream (line 8) | type MpqDataStream struct
    method Read (line 13) | func (m *MpqDataStream) Read(p []byte) (n int, err error) {
    method Seek (line 19) | func (m *MpqDataStream) Seek(offset int64, whence int) (int64, error) {
    method Close (line 25) | func (m *MpqDataStream) Close() error {

FILE: d2common/d2fileformats/d2mpq/mpq_file_record.go
  type MpqFileRecord (line 4) | type MpqFileRecord struct

FILE: d2common/d2fileformats/d2mpq/mpq_hash.go
  type Hash (line 6) | type Hash struct
    method Name64 (line 15) | func (h *Hash) Name64() uint64 {
  method readHashTable (line 20) | func (mpq *MPQ) readHashTable() error {

FILE: d2common/d2fileformats/d2mpq/mpq_header.go
  type Header (line 10) | type Header struct
  method readHeader (line 22) | func (mpq *MPQ) readHeader() error {

FILE: d2common/d2fileformats/d2mpq/mpq_stream.go
  type Stream (line 18) | type Stream struct
    method loadBlockOffsets (line 55) | func (v *Stream) loadBlockOffsets() error {
    method Read (line 83) | func (v *Stream) Read(buffer []byte, offset, count uint32) (readTotal ...
    method readInternalSingleUnit (line 108) | func (v *Stream) readInternalSingleUnit(buffer []byte, offset, count u...
    method readInternal (line 118) | func (v *Stream) readInternal(buffer []byte, offset, count uint32) (ui...
    method copy (line 128) | func (v *Stream) copy(buffer []byte, offset, pos, count uint32) (uint3...
    method bufferData (line 140) | func (v *Stream) bufferData() (err error) {
    method loadSingleUnit (line 157) | func (v *Stream) loadSingleUnit() (err error) {
    method loadBlock (line 178) | func (v *Stream) loadBlock(blockIndex, expectedLength uint32) ([]byte,...
  function CreateStream (line 29) | func CreateStream(mpq *MPQ, block *Block, fileName string) (*Stream, err...
  function decompressMulti (line 227) | func decompressMulti(data []byte /*expectedLength*/, _ uint32) ([]byte, ...
  function deflate (line 286) | func deflate(data []byte) ([]byte, error) {
  function pkDecompress (line 309) | func pkDecompress(data []byte) ([]byte, error) {

FILE: d2common/d2fileformats/d2pl2/pl2.go
  type PL2 (line 10) | type PL2 struct
    method Marshal (line 46) | func (p *PL2) Marshal() []byte {
  function Load (line 32) | func Load(data []byte) (*PL2, error) {

FILE: d2common/d2fileformats/d2pl2/pl2_color.go
  constant bitShift0 (line 4) | bitShift0 = 8 * iota
  constant bitShift8 (line 5) | bitShift8
  constant bitShift16 (line 6) | bitShift16
  constant bitShift24 (line 7) | bitShift24
  constant mask (line 9) | mask = 0xff
  type PL2Color (line 13) | type PL2Color struct
    method RGBA (line 21) | func (p *PL2Color) RGBA() uint32 {
    method SetRGBA (line 26) | func (p *PL2Color) SetRGBA(rgba uint32) {
  function toComposite (line 30) | func toComposite(w, x, y, z uint8) uint32 {
  function toComponent (line 39) | func toComponent(wxyz uint32) (w, x, y uint8) {

FILE: d2common/d2fileformats/d2pl2/pl2_color_24bits.go
  type PL2Color24Bits (line 4) | type PL2Color24Bits struct
    method RGBA (line 11) | func (p *PL2Color24Bits) RGBA() uint32 {
    method SetRGBA (line 16) | func (p *PL2Color24Bits) SetRGBA(rgba uint32) {

FILE: d2common/d2fileformats/d2pl2/pl2_palette.go
  type PL2Palette (line 4) | type PL2Palette struct

FILE: d2common/d2fileformats/d2pl2/pl2_palette_transform.go
  type PL2PaletteTransform (line 4) | type PL2PaletteTransform struct

FILE: d2common/d2fileformats/d2pl2/pl2_test.go
  function exampleData (line 7) | func exampleData() *PL2 {
  function TestPL2_MarshalUnmarshal (line 23) | func TestPL2_MarshalUnmarshal(t *testing.T) {

FILE: d2common/d2fileformats/d2tbl/text_dictionary.go
  type TextDictionary (line 11) | type TextDictionary
    method loadHashEntries (line 13) | func (td TextDictionary) loadHashEntries(hashEntries []*textDictionary...
    method loadHashEntry (line 65) | func (td TextDictionary) loadHashEntry(idx int, hashEntry *textDiction...
    method Marshal (line 179) | func (td *TextDictionary) Marshal() []byte {
  type textDictionaryHashEntry (line 104) | type textDictionaryHashEntry struct
  constant crcByteCount (line 114) | crcByteCount = 2
  function LoadTextDictionary (line 118) | func LoadTextDictionary(dictionaryData []byte) (TextDictionary, error) {

FILE: d2common/d2fileformats/d2tbl/text_dictionary_test.go
  function exampleData (line 7) | func exampleData() *TextDictionary {
  function TestTBL_Marshal (line 17) | func TestTBL_Marshal(t *testing.T) {
  function TestTBL_MarshalNoNameString (line 39) | func TestTBL_MarshalNoNameString(t *testing.T) {

FILE: d2common/d2fileformats/d2txt/data_dictionary.go
  type DataDictionary (line 13) | type DataDictionary struct
    method Next (line 45) | func (d *DataDictionary) Next() bool {
    method String (line 64) | func (d *DataDictionary) String(field string) string {
    method Number (line 69) | func (d *DataDictionary) Number(field string) int {
    method List (line 79) | func (d *DataDictionary) List(field string) []string {
    method Bool (line 85) | func (d *DataDictionary) Bool(field string) bool {
  function LoadDataDictionary (line 21) | func LoadDataDictionary(buf []byte) *DataDictionary {

FILE: d2common/d2geom/point.go
  type Point (line 4) | type Point struct
  type Pointf (line 10) | type Pointf struct

FILE: d2common/d2geom/rectangle.go
  type Rectangle (line 4) | type Rectangle struct
    method Bottom (line 12) | func (v *Rectangle) Bottom() int {
    method Right (line 17) | func (v *Rectangle) Right() int {
    method IsInRect (line 22) | func (v *Rectangle) IsInRect(x, y int) bool {

FILE: d2common/d2geom/size.go
  type Size (line 4) | type Size struct

FILE: d2common/d2interface/animation.go
  type Animation (line 11) | type Animation interface

FILE: d2common/d2interface/archive.go
  type Archive (line 7) | type Archive interface

FILE: d2common/d2interface/audio_provider.go
  type AudioProvider (line 5) | type AudioProvider interface

FILE: d2common/d2interface/cache.go
  type Cache (line 4) | type Cache interface
  type Cacher (line 14) | type Cacher interface

FILE: d2common/d2interface/data_stream.go
  type DataStream (line 4) | type DataStream interface

FILE: d2common/d2interface/input_events.go
  type HandlerEvent (line 6) | type HandlerEvent interface
  type KeyEvent (line 14) | type KeyEvent interface
  type KeyCharsEvent (line 22) | type KeyCharsEvent interface
  type MouseEvent (line 28) | type MouseEvent interface
  type MouseMoveEvent (line 34) | type MouseMoveEvent interface

FILE: d2common/d2interface/input_handlers.go
  type InputEventHandler (line 4) | type InputEventHandler interface
  type KeyDownHandler (line 12) | type KeyDownHandler interface
  type KeyRepeatHandler (line 17) | type KeyRepeatHandler interface
  type KeyUpHandler (line 22) | type KeyUpHandler interface
  type KeyCharsHandler (line 27) | type KeyCharsHandler interface
  type MouseButtonDownHandler (line 32) | type MouseButtonDownHandler interface
  type MouseButtonRepeatHandler (line 37) | type MouseButtonRepeatHandler interface
  type MouseButtonUpHandler (line 42) | type MouseButtonUpHandler interface
  type MouseMoveHandler (line 47) | type MouseMoveHandler interface

FILE: d2common/d2interface/input_manager.go
  type InputManager (line 6) | type InputManager interface

FILE: d2common/d2interface/input_service.go
  type InputService (line 6) | type InputService interface

FILE: d2common/d2interface/map_entity.go
  type MapEntity (line 6) | type MapEntity interface

FILE: d2common/d2interface/navigate.go
  type Navigator (line 8) | type Navigator interface

FILE: d2common/d2interface/palette.go
  constant numColors (line 3) | numColors = 256
  type Color (line 6) | type Color interface
  type Palette (line 18) | type Palette interface

FILE: d2common/d2interface/renderer.go
  type Renderer (line 8) | type Renderer interface

FILE: d2common/d2interface/sound_effect.go
  type SoundEffect (line 4) | type SoundEffect interface

FILE: d2common/d2interface/surface.go
  type Surface (line 11) | type Surface interface

FILE: d2common/d2interface/terminal.go
  type Terminal (line 8) | type Terminal interface
  type TerminalLogger (line 31) | type TerminalLogger interface

FILE: d2common/d2loader/asset/asset.go
  type Asset (line 12) | type Asset interface

FILE: d2common/d2loader/asset/source.go
  type Source (line 9) | type Source interface

FILE: d2common/d2loader/asset/types/asset_types.go
  type AssetType (line 6) | type AssetType
  constant AssetTypeUnknown (line 10) | AssetTypeUnknown AssetType = iota
  constant AssetTypeJSON (line 11) | AssetTypeJSON
  constant AssetTypeStringTable (line 12) | AssetTypeStringTable
  constant AssetTypeDataDictionary (line 13) | AssetTypeDataDictionary
  constant AssetTypePalette (line 14) | AssetTypePalette
  constant AssetTypePaletteTransform (line 15) | AssetTypePaletteTransform
  constant AssetTypeCOF (line 16) | AssetTypeCOF
  constant AssetTypeDC6 (line 17) | AssetTypeDC6
  constant AssetTypeDCC (line 18) | AssetTypeDCC
  constant AssetTypeDS1 (line 19) | AssetTypeDS1
  constant AssetTypeDT1 (line 20) | AssetTypeDT1
  constant AssetTypeWAV (line 21) | AssetTypeWAV
  constant AssetTypeD2 (line 22) | AssetTypeD2
  function Ext2AssetType (line 26) | func Ext2AssetType(ext string) AssetType {

FILE: d2common/d2loader/asset/types/source_types.go
  type SourceType (line 11) | type SourceType
  constant AssetSourceUnknown (line 15) | AssetSourceUnknown SourceType = iota
  constant AssetSourceFileSystem (line 16) | AssetSourceFileSystem
  constant AssetSourceMPQ (line 17) | AssetSourceMPQ
  function Ext2SourceType (line 21) | func Ext2SourceType(ext string) SourceType {
  function CheckSourceType (line 37) | func CheckSourceType(path string) SourceType {

FILE: d2common/d2loader/filesystem/asset.go
  constant bufLength (line 12) | bufLength = 32
  type Asset (line 19) | type Asset struct
    method Type (line 28) | func (fsa *Asset) Type() types.AssetType {
    method Source (line 33) | func (fsa *Asset) Source() asset.Source {
    method Path (line 38) | func (fsa *Asset) Path() string {
    method Read (line 43) | func (fsa *Asset) Read(p []byte) (n int, err error) {
    method Seek (line 48) | func (fsa *Asset) Seek(offset int64, whence int) (int64, error) {
    method Close (line 53) | func (fsa *Asset) Close() error {
    method Data (line 58) | func (fsa *Asset) Data() ([]byte, error) {
    method String (line 91) | func (fsa *Asset) String() string {

FILE: d2common/d2loader/filesystem/loader_provider.go
  function OnAddSource (line 8) | func OnAddSource(path string) (asset.Source, error) {

FILE: d2common/d2loader/filesystem/source.go
  type Source (line 16) | type Source struct
    method Type (line 21) | func (s *Source) Type() types.SourceType {
    method Open (line 26) | func (s *Source) Open(subPath string) (io.ReadSeeker, error) {
    method Exists (line 31) | func (s *Source) Exists(subPath string) bool {
    method fullPath (line 36) | func (s *Source) fullPath(subPath string) string {
    method Path (line 41) | func (s *Source) Path() string {
    method String (line 46) | func (s *Source) String() string {

FILE: d2common/d2loader/loader.go
  constant defaultCacheBudget (line 22) | defaultCacheBudget = 1024 * 1024 * 512
  constant errFmtFileNotFound (line 23) | errFmtFileNotFound = "file not found: %s"
  constant logPrefix (line 27) | logPrefix = "File Loader"
  constant fontToken (line 31) | fontToken  = d2resource.LanguageFontToken
  constant tableToken (line 32) | tableToken = d2resource.LanguageTableToken
  function NewLoader (line 36) | func NewLoader(l d2util.LogLevel) (*Loader, error) {
  type Loader (line 55) | type Loader struct
    method SetLanguage (line 65) | func (l *Loader) SetLanguage(language *string) {
    method SetCharset (line 70) | func (l *Loader) SetCharset(charset *string) {
    method Load (line 76) | func (l *Loader) Load(subPath string) (io.ReadSeeker, error) {
    method AddSource (line 111) | func (l *Loader) AddSource(path string, sourceType types.SourceType) e...
    method Exists (line 131) | func (l *Loader) Exists(subPath string) bool {

FILE: d2common/d2loader/loader_test.go
  constant sourcePathA (line 15) | sourcePathA   = "testdata/A"
  constant sourcePathB (line 16) | sourcePathB   = "testdata/B"
  constant sourcePathC (line 17) | sourcePathC   = "testdata/C"
  constant sourcePathD (line 18) | sourcePathD   = "testdata/D.mpq"
  constant commonFile (line 19) | commonFile    = "common.txt"
  constant exclusiveA (line 20) | exclusiveA    = "exclusive_a.txt"
  constant exclusiveB (line 21) | exclusiveB    = "exclusive_b.txt"
  constant exclusiveC (line 22) | exclusiveC    = "exclusive_c.txt"
  constant exclusiveD (line 23) | exclusiveD    = "exclusive_d.txt"
  constant subdirCommonD (line 24) | subdirCommonD = "dir\\common.txt"
  constant badSourcePath (line 25) | badSourcePath = "/x/y/z.mpq"
  constant badFilePath (line 26) | badFilePath   = "a/bad/file/path.txt"
  function TestLoader_NewLoader (line 29) | func TestLoader_NewLoader(t *testing.T) {
  function TestLoader_AddSource (line 37) | func TestLoader_AddSource(t *testing.T) {
  function TestLoader_Load (line 68) | func TestLoader_Load(t *testing.T) {

FILE: d2common/d2loader/mpq/asset.go
  constant bufLength (line 13) | bufLength = 32
  type Asset (line 20) | type Asset struct
    method Type (line 28) | func (a *Asset) Type() types.AssetType {
    method Source (line 33) | func (a *Asset) Source() asset.Source {
    method Path (line 38) | func (a *Asset) Path() string {
    method Read (line 43) | func (a *Asset) Read(buf []byte) (n int, err error) {
    method Seek (line 48) | func (a *Asset) Seek(offset int64, whence int) (n int64, err error) {
    method Close (line 53) | func (a *Asset) Close() (err error) {
    method Data (line 63) | func (a *Asset) Data() ([]byte, error) {
    method String (line 96) | func (a *Asset) String() string {

FILE: d2common/d2loader/mpq/source.go
  function NewSource (line 16) | func NewSource(sourcePath string) (asset.Source, error) {
  type Source (line 26) | type Source struct
    method Open (line 31) | func (v *Source) Open(name string) (a io.ReadSeeker, err error) {
    method Exists (line 37) | func (v *Source) Exists(subPath string) bool {
    method Path (line 43) | func (v *Source) Path() string {
    method String (line 48) | func (v *Source) String() string {
  function cleanName (line 52) | func cleanName(name string) string {

FILE: d2common/d2math/d2vector/position.go
  constant subTilesPerTile (line 11) | subTilesPerTile          float64 = 5
  constant entityDirectionCount (line 12) | entityDirectionCount     float64 = 64
  constant entityDirectionIncrement (line 13) | entityDirectionIncrement float64 = 8
  type Position (line 18) | type Position struct
    method Set (line 40) | func (p *Position) Set(x, y float64) {
    method checkValues (line 45) | func (p *Position) checkValues() {
    method World (line 56) | func (p *Position) World() *Vector {
    method Tile (line 62) | func (p *Position) Tile() *Vector {
    method RenderOffset (line 70) | func (p *Position) RenderOffset() *Vector {
    method SubTileOffset (line 75) | func (p *Position) SubTileOffset() *Vector {
  function NewPosition (line 24) | func NewPosition(x, y float64) Position {
  function NewPositionTile (line 32) | func NewPositionTile(x, y float64) Position {
  method DirectionTo (line 83) | func (v *Vector) DirectionTo(target Vector) int {

FILE: d2common/d2math/d2vector/position_test.go
  function TestNewPosition (line 9) | func TestNewPosition(t *testing.T) {
  function validate (line 46) | func validate(description string, t *testing.T, original, got, want, unc...
  function TestPosition_World (line 56) | func TestPosition_World(t *testing.T) {
  function TestPosition_Tile (line 65) | func TestPosition_Tile(t *testing.T) {
  function TestPosition_RenderOffset (line 74) | func TestPosition_RenderOffset(t *testing.T) {

FILE: d2common/d2math/d2vector/vector.go
  type Vector (line 11) | type Vector struct
    method X (line 23) | func (v *Vector) X() float64 {
    method Y (line 28) | func (v *Vector) Y() float64 {
    method Equals (line 33) | func (v *Vector) Equals(o *Vector) bool {
    method EqualsApprox (line 39) | func (v *Vector) EqualsApprox(o *Vector) bool {
    method CompareApprox (line 45) | func (v *Vector) CompareApprox(o *Vector) (x, y int) {
    method IsZero (line 51) | func (v *Vector) IsZero() bool {
    method Set (line 56) | func (v *Vector) Set(x, y float64) *Vector {
    method Clone (line 64) | func (v *Vector) Clone() *Vector {
    method Copy (line 69) | func (v *Vector) Copy(o *Vector) *Vector {
    method Floor (line 77) | func (v *Vector) Floor() *Vector {
    method Clamp (line 86) | func (v *Vector) Clamp(a, b *Vector) *Vector {
    method Add (line 94) | func (v *Vector) Add(o *Vector) *Vector {
    method AddScalar (line 102) | func (v *Vector) AddScalar(s float64) *Vector {
    method Subtract (line 110) | func (v *Vector) Subtract(o *Vector) *Vector {
    method Multiply (line 118) | func (v *Vector) Multiply(o *Vector) *Vector {
    method Scale (line 126) | func (v *Vector) Scale(s float64) *Vector {
    method Divide (line 134) | func (v *Vector) Divide(o *Vector) *Vector {
    method DivideScalar (line 142) | func (v *Vector) DivideScalar(s float64) *Vector {
    method Abs (line 150) | func (v *Vector) Abs() *Vector {
    method Negate (line 163) | func (v *Vector) Negate() *Vector {
    method Distance (line 168) | func (v *Vector) Distance(o *Vector) float64 {
    method Length (line 176) | func (v *Vector) Length() float64 {
    method SetLength (line 182) | func (v *Vector) SetLength(length float64) *Vector {
    method Lerp (line 191) | func (v *Vector) Lerp(o *Vector, interp float64) *Vector {
    method Dot (line 199) | func (v *Vector) Dot(o *Vector) float64 {
    method Cross (line 215) | func (v *Vector) Cross(o *Vector) float64 {
    method Normalize (line 221) | func (v *Vector) Normalize() *Vector {
    method Angle (line 233) | func (v *Vector) Angle(o *Vector) float64 {
    method SignedAngle (line 251) | func (v *Vector) SignedAngle(o *Vector) float64 {
    method Reflect (line 264) | func (v *Vector) Reflect(normal *Vector) *Vector {
    method ReflectSurface (line 277) | func (v *Vector) ReflectSurface(surface *Vector) *Vector {
    method Rotate (line 285) | func (v *Vector) Rotate(angle float64) *Vector {
    method NinetyAnti (line 296) | func (v *Vector) NinetyAnti() *Vector {
    method NinetyClock (line 305) | func (v *Vector) NinetyClock() *Vector {
    method String (line 313) | func (v Vector) String() string {
  constant two (line 15) | two float64 = 2
  function NewVector (line 18) | func NewVector(x, y float64) *Vector {
  function VectorUp (line 318) | func VectorUp() *Vector {
  function VectorDown (line 323) | func VectorDown() *Vector {
  function VectorRight (line 328) | func VectorRight() *Vector {
  function VectorLeft (line 333) | func VectorLeft() *Vector {
  function VectorOne (line 338) | func VectorOne() *Vector {
  function VectorZero (line 343) | func VectorZero() *Vector {

FILE: d2common/d2math/d2vector/vector_test.go
  function TestVector_Equals (line 20) | func TestVector_Equals(t *testing.T) {
  function BenchmarkVector_Equals (line 39) | func BenchmarkVector_Equals(b *testing.B) {
  function TestVector_EqualsApprox (line 48) | func TestVector_EqualsApprox(t *testing.T) {
  function BenchmarkVector_EqualsApprox (line 69) | func BenchmarkVector_EqualsApprox(b *testing.B) {
  function TestVector_CompareApprox (line 78) | func TestVector_CompareApprox(t *testing.T) {
  function BenchmarkVector_CompareApprox (line 109) | func BenchmarkVector_CompareApprox(b *testing.B) {
  function TestVector_IsZero (line 118) | func TestVector_IsZero(t *testing.T) {
  function testIsZero (line 125) | func testIsZero(v Vector, want bool, t *testing.T) {
  function BenchmarkVector_IsZero (line 132) | func BenchmarkVector_IsZero(b *testing.B) {
  function TestVector_Set (line 140) | func TestVector_Set(t *testing.T) {
  function BenchmarkVector_Set (line 151) | func BenchmarkVector_Set(b *testing.B) {
  function TestVector_Clone (line 159) | func TestVector_Clone(t *testing.T) {
  function BenchmarkVector_Clone (line 168) | func BenchmarkVector_Clone(b *testing.B) {
  function TestVector_Copy (line 176) | func TestVector_Copy(t *testing.T) {
  function BenchmarkVector_Copy (line 186) | func BenchmarkVector_Copy(b *testing.B) {
  function TestVector_Floor (line 195) | func TestVector_Floor(t *testing.T) {
  function BenchmarkVector_Floor (line 206) | func BenchmarkVector_Floor(b *testing.B) {
  function TestVector_Clamp (line 214) | func TestVector_Clamp(t *testing.T) {
  function BenchmarkVector_Clamp (line 228) | func BenchmarkVector_Clamp(b *testing.B) {
  function TestVector_Add (line 238) | func TestVector_Add(t *testing.T) {
  function BenchmarkVector_Add (line 250) | func BenchmarkVector_Add(b *testing.B) {
  function TestVector_AddScalar (line 259) | func TestVector_AddScalar(t *testing.T) {
  function BenchmarkVector_AddScalar (line 271) | func BenchmarkVector_AddScalar(b *testing.B) {
  function TestVector_Subtract (line 279) | func TestVector_Subtract(t *testing.T) {
  function BenchmarkVector_Subtract (line 291) | func BenchmarkVector_Subtract(b *testing.B) {
  function TestVector_Multiply (line 300) | func TestVector_Multiply(t *testing.T) {
  function BenchmarkVector_Multiply (line 312) | func BenchmarkVector_Multiply(b *testing.B) {
  function TestVector_Divide (line 321) | func TestVector_Divide(t *testing.T) {
  function BenchmarkVector_Divide (line 333) | func BenchmarkVector_Divide(b *testing.B) {
  function TestVector_DivideScalar (line 342) | func TestVector_DivideScalar(t *testing.T) {
  function BenchmarkVector_DivideScalar (line 354) | func BenchmarkVector_DivideScalar(b *testing.B) {
  function TestVector_Scale (line 362) | func TestVector_Scale(t *testing.T) {
  function BenchmarkVector_Scale (line 373) | func BenchmarkVector_Scale(b *testing.B) {
  function TestVector_Abs (line 381) | func TestVector_Abs(t *testing.T) {
  function BenchmarkVector_Abs (line 392) | func BenchmarkVector_Abs(b *testing.B) {
  function TestVector_Negate (line 400) | func TestVector_Negate(t *testing.T) {
  function BenchmarkVector_Negate (line 411) | func BenchmarkVector_Negate(b *testing.B) {
  function TestVector_Distance (line 419) | func TestVector_Distance(t *testing.T) {
  function BenchmarkVector_Distance (line 431) | func BenchmarkVector_Distance(b *testing.B) {
  function TestVector_Length (line 440) | func TestVector_Length(t *testing.T) {
  function BenchmarkVector_Length (line 457) | func BenchmarkVector_Length(b *testing.B) {
  function TestVector_SetLength (line 465) | func TestVector_SetLength(t *testing.T) {
  function BenchmarkVector_SetLength (line 476) | func BenchmarkVector_SetLength(b *testing.B) {
  function TestVector_Lerp (line 484) | func TestVector_Lerp(t *testing.T) {
  function BenchmarkVector_Lerp (line 498) | func BenchmarkVector_Lerp(b *testing.B) {
  function TestVector_Dot (line 507) | func TestVector_Dot(t *testing.T) {
  function BenchmarkVector_Dot (line 524) | func BenchmarkVector_Dot(b *testing.B) {
  function TestVector_Cross (line 532) | func TestVector_Cross(t *testing.T) {
  function BenchmarkVector_Cross (line 553) | func BenchmarkVector_Cross(b *testing.B) {
  function TestVector_Normalize (line 562) | func TestVector_Normalize(t *testing.T) {
  function BenchmarkVector_Normalize (line 594) | func BenchmarkVector_Normalize(b *testing.B) {
  function TestVector_Angle (line 602) | func TestVector_Angle(t *testing.T) {
  function BenchmarkVector_Angle (line 635) | func BenchmarkVector_Angle(b *testing.B) {
  function TestVector_SignedAngle (line 644) | func TestVector_SignedAngle(t *testing.T) {
  function BenchmarkVector_SignedAngle (line 677) | func BenchmarkVector_SignedAngle(b *testing.B) {
  function TestVector_Reflect (line 686) | func TestVector_Reflect(t *testing.T) {
  function BenchmarkVector_Reflect (line 701) | func BenchmarkVector_Reflect(b *testing.B) {
  function TestVector_ReflectSurface (line 710) | func TestVector_ReflectSurface(t *testing.T) {
  function BenchmarkVector_ReflectSurface (line 725) | func BenchmarkVector_ReflectSurface(b *testing.B) {
  function TestVector_Rotate (line 734) | func TestVector_Rotate(t *testing.T) {
  function BenchmarkVector_Rotate (line 757) | func BenchmarkVector_Rotate(b *testing.B) {
  function TestVector_NinetyAnti (line 766) | func TestVector_NinetyAnti(t *testing.T) {
  function BenchmarkVector_NinetyAnti (line 778) | func BenchmarkVector_NinetyAnti(b *testing.B) {
  function TestVector_NinetyClock (line 786) | func TestVector_NinetyClock(t *testing.T) {
  function BenchmarkVector_NinetyClock (line 799) | func BenchmarkVector_NinetyClock(b *testing.B) {
  function TestVectorUp (line 807) | func TestVectorUp(t *testing.T) {
  function TestVectorDown (line 816) | func TestVectorDown(t *testing.T) {
  function TestVectorRight (line 825) | func TestVectorRight(t *testing.T) {
  function TestVectorLeft (line 834) | func TestVectorLeft(t *testing.T) {
  function TestVectorOne (line 843) | func TestVectorOne(t *testing.T) {
  function TestVectorZero (line 852) | func TestVectorZero(t *testing.T) {

FILE: d2common/d2math/math.go
  constant Epsilon (line 7) | Epsilon float64 = 0.0001
  constant RadToDeg (line 11) | RadToDeg float64 = 57.29578
  constant RadFull (line 14) | RadFull float64 = 6.283185253783088
  function EqualsApprox (line 18) | func EqualsApprox(a, b float64) bool {
  function CompareApprox (line 24) | func CompareApprox(a, b float64) int {
  function Abs (line 39) | func Abs(a float64) float64 {
  function Clamp (line 48) | func Clamp(a, min, max float64) float64 {
  function Sign (line 59) | func Sign(a float64) int {
  function Lerp (line 71) | func Lerp(a, b, x float64) float64 {
  function Unlerp (line 79) | func Unlerp(a, b, x float64) float64 {
  function WrapInt (line 84) | func WrapInt(x, max int) int {
  function MinInt (line 95) | func MinInt(a, b int) int {
  function MaxInt (line 104) | func MaxInt(a, b int) int {
  function Min (line 113) | func Min(a, b uint32) uint32 {
  function Max (line 122) | func Max(a, b uint32) uint32 {
  function MaxInt32 (line 131) | func MaxInt32(a, b int32) int32 {
  function AbsInt32 (line 140) | func AbsInt32(a int32) int32 {
  function MinInt32 (line 149) | func MinInt32(a, b int32) int32 {
  function GetRadiansBetween (line 164) | func GetRadiansBetween(p1X, p1Y, p2X, p2Y float64) float64 {
  function ClampInt (line 172) | func ClampInt(value, min, max int) int {

FILE: d2common/d2math/math_test.go
  function TestEqualsApprox (line 16) | func TestEqualsApprox(t *testing.T) {
  function BenchmarkEqualsApprox (line 34) | func BenchmarkEqualsApprox(b *testing.B) {
  function TestCompareApprox (line 43) | func TestCompareApprox(t *testing.T) {
  function BenchmarkCompareApprox (line 71) | func BenchmarkCompareApprox(b *testing.B) {
  function TestAbs (line 80) | func TestAbs(t *testing.T) {
  function BenchmarkAbs (line 98) | func BenchmarkAbs(b *testing.B) {
  function TestClamp (line 106) | func TestClamp(t *testing.T) {
  function BenchmarkClamp (line 132) | func BenchmarkClamp(b *testing.B) {
  function TestSign (line 140) | func TestSign(t *testing.T) {
  function BenchmarkSign (line 166) | func BenchmarkSign(b *testing.B) {
  function TestLerp (line 174) | func TestLerp(t *testing.T) {
  function BenchmarkLerp (line 188) | func BenchmarkLerp(b *testing.B) {
  function TestUnlerp (line 198) | func TestUnlerp(t *testing.T) {
  function BenchmarkUnlerp (line 212) | func BenchmarkUnlerp(b *testing.B) {
  function TestWrapInt (line 222) | func TestWrapInt(t *testing.T) {
  function BenchmarkWrapInt (line 258) | func BenchmarkWrapInt(b *testing.B) {

FILE: d2common/d2math/ranged_number.go
  type RangedNumber (line 6) | type RangedNumber struct
    method Min (line 12) | func (rn *RangedNumber) Min() int {
    method Max (line 21) | func (rn *RangedNumber) Max() int {
    method Set (line 30) | func (rn *RangedNumber) Set(min, max int) *RangedNumber {
    method SetMin (line 38) | func (rn *RangedNumber) SetMin(min int) *RangedNumber {
    method SetMax (line 49) | func (rn *RangedNumber) SetMax(max int) *RangedNumber {
    method Clone (line 60) | func (rn RangedNumber) Clone() *RangedNumber {
    method Copy (line 65) | func (rn *RangedNumber) Copy(other *RangedNumber) *RangedNumber {
    method Equals (line 70) | func (rn *RangedNumber) Equals(other *RangedNumber) bool {
    method Add (line 75) | func (rn *RangedNumber) Add(other *RangedNumber) *RangedNumber {
    method Sub (line 80) | func (rn *RangedNumber) Sub(other *RangedNumber) *RangedNumber {
    method Mul (line 85) | func (rn *RangedNumber) Mul(other *RangedNumber) *RangedNumber {
    method Div (line 90) | func (rn *RangedNumber) Div(other *RangedNumber) *RangedNumber {
    method String (line 94) | func (rn *RangedNumber) String() string {

FILE: d2common/d2math/ranged_number_test.go
  function TestRangedNumber_Clone (line 5) | func TestRangedNumber_Clone(t *testing.T) {
  function TestRangedNumber_Copy (line 14) | func TestRangedNumber_Copy(t *testing.T) {
  function TestRangedNumber_Set (line 24) | func TestRangedNumber_Set(t *testing.T) {
  function TestRangedNumber_Equals (line 39) | func TestRangedNumber_Equals(t *testing.T) {
  function TestRangedNumber_Add (line 55) | func TestRangedNumber_Add(t *testing.T) {
  function TestRangedNumber_Sub (line 67) | func TestRangedNumber_Sub(t *testing.T) {
  function TestRangedNumber_Mul (line 79) | func TestRangedNumber_Mul(t *testing.T) {
  function TestRangedNumber_Div (line 91) | func TestRangedNumber_Div(t *testing.T) {
  function TestRangedNumber_String (line 103) | func TestRangedNumber_String(t *testing.T) {

FILE: d2common/d2path/path.go
  type Path (line 6) | type Path struct

FILE: d2common/d2resource/languages_map.go
  function getLanguages (line 3) | func getLanguages() map[byte]string {
  function GetLanguageLiteral (line 22) | func GetLanguageLiteral(code byte) string {
  function getCharsets (line 29) | func getCharsets() map[string]string {
  function GetFontCharset (line 47) | func GetFontCharset(language string) string {
  function GetLabelModifier (line 66) | func GetLabelModifier(language string) int {

FILE: d2common/d2resource/music_defs.go
  type MusicDef (line 8) | type MusicDef struct
  function getMusicDefs (line 14) | func getMusicDefs() []MusicDef {
  function GetMusicDef (line 55) | func GetMusicDef(regionType d2enum.RegionIdType) *MusicDef {

FILE: d2common/d2resource/resource_paths.go
  constant LocalLanguage (line 7) | LocalLanguage      = "/data/local/use"
  constant LanguageFontToken (line 8) | LanguageFontToken  = "{LANG_FONT}"
  constant LanguageTableToken (line 9) | LanguageTableToken = "{LANG}"
  constant LoadingScreen (line 13) | LoadingScreen = "/data/global/ui/Loading/loadingscreen.dc6"
  constant TrademarkScreen (line 17) | TrademarkScreen       = "/data/global/ui/FrontEnd/trademarkscreenEXP.dc6"
  constant GameSelectScreen (line 18) | GameSelectScreen      = "/data/global/ui/FrontEnd/gameselectscreenEXP.dc6"
  constant TCPIPBackground (line 19) | TCPIPBackground       = "/data/global/ui/FrontEnd/TCPIPscreen.dc6"
  constant Diablo2LogoFireLeft (line 20) | Diablo2LogoFireLeft   = "/data/global/ui/FrontEnd/D2logoFireLeft.DC6"
  constant Diablo2LogoFireRight (line 21) | Diablo2LogoFireRight  = "/data/global/ui/FrontEnd/D2logoFireRight.DC6"
  constant Diablo2LogoBlackLeft (line 22) | Diablo2LogoBlackLeft  = "/data/global/ui/FrontEnd/D2logoBlackLeft.DC6"
  constant Diablo2LogoBlackRight (line 23) | Diablo2LogoBlackRight = "/data/global/ui/FrontEnd/D2logoBlackRight.DC6"
  constant CreditsBackground (line 27) | CreditsBackground = "/data/global/ui/CharSelect/creditsbckgexpand.dc6"
  constant CreditsText (line 28) | CreditsText       = "/data/local/ui/" + LanguageTableToken + "/Expansion...
  constant CinematicsBackground (line 32) | CinematicsBackground = "/data/global/ui/FrontEnd/CinematicsSelectionEXP....
  constant Act1Intro (line 36) | Act1Intro = "/data/local/video/" + LanguageTableToken + "/d2intro640x292...
  constant Act2Intro (line 37) | Act2Intro = "/data/local/video/" + LanguageTableToken + "/act02start640x...
  constant Act3Intro (line 38) | Act3Intro = "/data/local/video/" + LanguageTableToken + "/act03start640x...
  constant Act4Intro (line 39) | Act4Intro = "/data/local/video/" + LanguageTableToken + "/act04start640x...
  constant Act4Outro (line 40) | Act4Outro = "/data/local/video/" + LanguageTableToken + "/act04end640x29...
  constant Act5Intro (line 41) | Act5Intro = "/data/local/video/" + LanguageTableToken + "/d2x_intro_640x...
  constant Act5Outro (line 42) | Act5Outro = "/data/local/video/" + LanguageTableToken + "/d2x_out_640x29...
  constant CharacterSelectBackground (line 46) | CharacterSelectBackground = "/data/global/ui/FrontEnd/charactercreations...
  constant CharacterSelectCampfire (line 47) | CharacterSelectCampfire   = "/data/global/ui/FrontEnd/fire.DC6"
  constant CharacterSelectBarbarianUnselected (line 49) | CharacterSelectBarbarianUnselected         = "/data/global/ui/FrontEnd/b...
  constant CharacterSelectBarbarianUnselectedH (line 50) | CharacterSelectBarbarianUnselectedH        = "/data/global/ui/FrontEnd/b...
  constant CharacterSelectBarbarianSelected (line 51) | CharacterSelectBarbarianSelected           = "/data/global/ui/FrontEnd/b...
  constant CharacterSelectBarbarianForwardWalk (line 52) | CharacterSelectBarbarianForwardWalk        = "/data/global/ui/FrontEnd/b...
  constant CharacterSelectBarbarianForwardWalkOverlay (line 53) | CharacterSelectBarbarianForwardWalkOverlay = "/data/global/ui/FrontEnd/b...
  constant CharacterSelectBarbarianBackWalk (line 54) | CharacterSelectBarbarianBackWalk           = "/data/global/ui/FrontEnd/b...
  constant CharacterSelectSorceressUnselected (line 56) | CharacterSelectSorceressUnselected         = "/data/global/ui/FrontEnd/s...
  constant CharacterSelectSorceressUnselectedH (line 57) | CharacterSelectSorceressUnselectedH        = "/data/global/ui/FrontEnd/s...
  constant CharacterSelectSorceressSelected (line 58) | CharacterSelectSorceressSelected           = "/data/global/ui/FrontEnd/s...
  constant CharacterSelectSorceressSelectedOverlay (line 59) | CharacterSelectSorceressSelectedOverlay    = "/data/global/ui/FrontEnd/s...
  constant CharacterSelectSorceressForwardWalk (line 60) | CharacterSelectSorceressForwardWalk        = "/data/global/ui/FrontEnd/s...
  constant CharacterSelectSorceressForwardWalkOverlay (line 61) | CharacterSelectSorceressForwardWalkOverlay = "/data/global/ui/FrontEnd/s...
  constant CharacterSelectSorceressBackWalk (line 62) | CharacterSelectSorceressBackWalk           = "/data/global/ui/FrontEnd/s...
  constant CharacterSelectSorceressBackWalkOverlay (line 63) | CharacterSelectSorceressBackWalkOverlay    = "/data/global/ui/FrontEnd/s...
  constant CharacterSelectNecromancerUnselected (line 65) | CharacterSelectNecromancerUnselected         = "/data/global/ui/FrontEnd...
  constant CharacterSelectNecromancerUnselectedH (line 66) | CharacterSelectNecromancerUnselectedH        = "/data/global/ui/FrontEnd...
  constant CharacterSelectNecromancerSelected (line 67) | CharacterSelectNecromancerSelected           = "/data/global/ui/FrontEnd...
  constant CharacterSelectNecromancerSelectedOverlay (line 68) | CharacterSelectNecromancerSelectedOverlay    = "/data/global/ui/FrontEnd...
  constant CharacterSelectNecromancerForwardWalk (line 69) | CharacterSelectNecromancerForwardWalk        = "/data/global/ui/FrontEnd...
  constant CharacterSelectNecromancerForwardWalkOverlay (line 70) | CharacterSelectNecromancerForwardWalkOverlay = "/data/global/ui/FrontEnd...
  constant CharacterSelectNecromancerBackWalk (line 71) | CharacterSelectNecromancerBackWalk           = "/data/global/ui/FrontEnd...
  constant CharacterSelectNecromancerBackWalkOverlay (line 72) | CharacterSelectNecromancerBackWalkOverlay    = "/data/global/ui/FrontEnd...
  constant CharacterSelectPaladinUnselected (line 74) | CharacterSelectPaladinUnselected         = "/data/global/ui/FrontEnd/pal...
  constant CharacterSelectPaladinUnselectedH (line 75) | CharacterSelectPaladinUnselectedH        = "/data/global/ui/FrontEnd/pal...
  constant CharacterSelectPaladinSelected (line 76) | CharacterSelectPaladinSelected           = "/data/global/ui/FrontEnd/pal...
  constant CharacterSelectPaladinForwardWalk (line 77) | CharacterSelectPaladinForwardWalk        = "/data/global/ui/FrontEnd/pal...
  constant CharacterSelectPaladinForwardWalkOverlay (line 78) | CharacterSelectPaladinForwardWalkOverlay = "/data/global/ui/FrontEnd/pal...
  constant CharacterSelectPaladinBackWalk (line 79) | CharacterSelectPaladinBackWalk           = "/data/global/ui/FrontEnd/pal...
  constant CharacterSelectAmazonUnselected (line 81) | CharacterSelectAmazonUnselected         = "/data/global/ui/FrontEnd/amaz...
  constant CharacterSelectAmazonUnselectedH (line 82) | CharacterSelectAmazonUnselectedH        = "/data/global/ui/FrontEnd/amaz...
  constant CharacterSelectAmazonSelected (line 83) | CharacterSelectAmazonSelected           = "/data/global/ui/FrontEnd/amaz...
  constant CharacterSelectAmazonForwardWalk (line 84) | CharacterSelectAmazonForwardWalk        = "/data/global/ui/FrontEnd/amaz...
  constant CharacterSelectAmazonForwardWalkOverlay (line 85) | CharacterSelectAmazonForwardWalkOverlay = "/data/global/ui/FrontEnd/amaz...
  constant CharacterSelectAmazonBackWalk (line 86) | CharacterSelectAmazonBackWalk           = "/data/global/ui/FrontEnd/amaz...
  constant CharacterSelectAssassinUnselected (line 88) | CharacterSelectAssassinUnselected  = "/data/global/ui/FrontEnd/assassin/...
  constant CharacterSelectAssassinUnselectedH (line 89) | CharacterSelectAssassinUnselectedH = "/data/global/ui/FrontEnd/assassin/...
  constant CharacterSelectAssassinSelected (line 90) | CharacterSelectAssassinSelected    = "/data/global/ui/FrontEnd/assassin/...
  constant CharacterSelectAssassinForwardWalk (line 91) | CharacterSelectAssassinForwardWalk = "/data/global/ui/FrontEnd/assassin/...
  constant CharacterSelectAssassinBackWalk (line 92) | CharacterSelectAssassinBackWalk    = "/data/global/ui/FrontEnd/assassin/...
  constant CharacterSelectDruidUnselected (line 94) | CharacterSelectDruidUnselected  = "/data/global/ui/FrontEnd/druid/DZNU1....
  constant CharacterSelectDruidUnselectedH (line 95) | CharacterSelectDruidUnselectedH = "/data/global/ui/FrontEnd/druid/DZNU2....
  constant CharacterSelectDruidSelected (line 96) | CharacterSelectDruidSelected    = "/data/global/ui/FrontEnd/druid/DZNU3....
  constant CharacterSelectDruidForwardWalk (line 97) | CharacterSelectDruidForwardWalk = "/data/global/ui/FrontEnd/druid/DZFW.DC6"
  constant CharacterSelectDruidBackWalk (line 98) | CharacterSelectDruidBackWalk    = "/data/global/ui/FrontEnd/druid/DZBW.DC6"
  constant CharacterSelectionBackground (line 102) | CharacterSelectionBackground = "/data/global/ui/CharSelect/charactersele...
  constant CharacterSelectionSelectBox (line 103) | CharacterSelectionSelectBox  = "/data/global/ui/CharSelect/charselectbox...
  constant PopUpOkCancel (line 104) | PopUpOkCancel                = "/data/global/ui/FrontEnd/PopUpOKCancel.dc6"
  constant GamePanels (line 108) | GamePanels          = "/data/global/ui/PANEL/800ctrlpnl7.dc6"
  constant GameGlobeOverlap (line 109) | GameGlobeOverlap    = "/data/global/ui/PANEL/overlap.DC6"
  constant HealthManaIndicator (line 110) | HealthManaIndicator = "/data/global/ui/PANEL/hlthmana.DC6"
  constant AddSkillButton (line 111) | AddSkillButton      = "/data/global/ui/PANEL/level.DC6"
  constant MoveGoldDialog (line 112) | MoveGoldDialog      = "/data/global/ui/menu/dialogbackground.DC6"
  constant WPTabs (line 113) | WPTabs              = "/data/global/ui/menu/expwaygatetabs.dc6"
  constant WPBg (line 114) | WPBg                = "/data/global/ui/menu/waygatebackground.dc6"
  constant WPIcons (line 115) | WPIcons             = "/data/global/ui/menu/waygateicons.dc6"
  constant UpDownArrows (line 116) | UpDownArrows        = "/data/global/ui/BIGMENU/numberarrows.dc6"
  constant EscapeOptions (line 120) | EscapeOptions      = "/data/local/ui/" + LanguageTableToken + "/options....
  constant EscapeExit (line 121) | EscapeExit         = "/data/local/ui/" + LanguageTableToken + "/exit.dc6"
  constant EscapeReturnToGame (line 122) | EscapeReturnToGame = "/data/local/ui/" + LanguageTableToken + "/returnto...
  constant EscapeOptSoundOptions (line 124) | EscapeOptSoundOptions   = "/data/local/ui/" + LanguageTableToken + "/sou...
  constant EscapeOptVideoOptions (line 125) | EscapeOptVideoOptions   = "/data/local/ui/" + LanguageTableToken + "/vid...
  constant EscapeOptAutoMapOptions (line 126) | EscapeOptAutoMapOptions = "/data/local/ui/" + LanguageTableToken + "/aut...
  constant EscapeOptCfgOptions (line 127) | EscapeOptCfgOptions     = "/data/local/ui/" + LanguageTableToken + "/cfg...
  constant EscapeOptPrevious (line 128) | EscapeOptPrevious       = "/data/local/ui/" + LanguageTableToken + "/pre...
  constant EscapeSndOptSoundVolume (line 131) | EscapeSndOptSoundVolume = "/data/local/ui/" + LanguageTableToken + "/sou...
  constant EscapeSndOptMusicVolume (line 132) | EscapeSndOptMusicVolume = "/data/local/ui/" + LanguageTableToken + "/mus...
  constant EscapeSndOpt3DBias (line 133) | EscapeSndOpt3DBias      = "/data/local/ui/" + LanguageTableToken + "/3db...
  constant EscapeSndOptNPCSpeech (line 136) | EscapeSndOptNPCSpeech             = "/data/local/ui/" + LanguageTableTok...
  constant EscapeSndOptNPCSpeechAudioAndText (line 137) | EscapeSndOptNPCSpeechAudioAndText = "/data/local/ui/" + LanguageTableTok...
  constant EscapeSndOptNPCSpeechAudioOnly (line 138) | EscapeSndOptNPCSpeechAudioOnly    = "/data/local/ui/" + LanguageTableTok...
  constant EscapeSndOptNPCSpeechTextOnly (line 139) | EscapeSndOptNPCSpeechTextOnly     = "/data/local/ui/" + LanguageTableTok...
  constant EscapeVidOptRes (line 142) | EscapeVidOptRes          = "/data/local/ui/" + LanguageTableToken + "/re...
  constant EscapeVidOptLightQuality (line 143) | EscapeVidOptLightQuality = "/data/local/ui/" + LanguageTableToken + "/li...
  constant EscapeVidOptBlendShadow (line 144) | EscapeVidOptBlendShadow  = "/data/local/ui/" + LanguageTableToken + "/bl...
  constant EscapeVidOptPerspective (line 145) | EscapeVidOptPerspective  = "/data/local/ui/" + LanguageTableToken + "/pr...
  constant EscapeVidOptGamma (line 146) | EscapeVidOptGamma        = "/data/local/ui/" + LanguageTableToken + "/ga...
  constant EscapeVidOptContrast (line 147) | EscapeVidOptContrast     = "/data/local/ui/" + LanguageTableToken + "/co...
  constant EscapeAutoMapOptSize (line 150) | EscapeAutoMapOptSize   = "/data/local/ui/" + LanguageTableToken + "/auto...
  constant EscapeAutoMapOptFade (line 151) | EscapeAutoMapOptFade   = "/data/local/ui/" + LanguageTableToken + "/auto...
  constant EscapeAutoMapOptCenter (line 152) | EscapeAutoMapOptCenter = "/data/local/ui/" + LanguageTableToken + "/auto...
  constant EscapeAutoMapOptNames (line 153) | EscapeAutoMapOptNames  = "/data/local/ui/" + LanguageTableToken + "/auto...
  constant EscapeAutoMapOptFullScreen (line 156) | EscapeAutoMapOptFullScreen = "/data/local/ui/" + LanguageTableToken + "/...
  constant EscapeAutoMapOptMiniMap (line 157) | EscapeAutoMapOptMiniMap    = "/data/local/ui/" + LanguageTableToken + "/...
  constant EscapeVideoOptRes640x480 (line 160) | EscapeVideoOptRes640x480 = "/data/local/ui/" + LanguageTableToken + "/64...
  constant EscapeVideoOptRes800x600 (line 161) | EscapeVideoOptRes800x600 = "/data/local/ui/" + LanguageTableToken + "/80...
  constant EscapeOn (line 163) | EscapeOn            = "/data/local/ui/" + LanguageTableToken + "/smallon...
  constant EscapeOff (line 164) | EscapeOff           = "/data/local/ui/" + LanguageTableToken + "/smallof...
  constant EscapeYes (line 165) | EscapeYes           = "/data/local/ui/" + LanguageTableToken + "/smallye...
  constant EscapeNo (line 166) | EscapeNo            = "/data/local/ui/" + LanguageTableToken + "/smallno...
  constant EscapeSlideBar (line 167) | EscapeSlideBar      = "/data/global/ui/widgets/optbarc.dc6"
  constant EscapeSlideBarSkull (line 168) | EscapeSlideBarSkull = "/data/global/ui/widgets/optskull.dc6"
  constant HelpBorder (line 173) | HelpBorder       = "/data/global/ui/MENU/800helpborder.DC6"
  constant HelpYellowBullet (line 174) | HelpYellowBullet = "/data/global/ui/MENU/helpyellowbullet.DC6"
  constant HelpWhiteBullet (line 175) | HelpWhiteBullet  = "/data/global/ui/MENU/helpwhitebullet.DC6"
  constant BoxPieces (line 179) | BoxPieces = "/data/global/ui/MENU/boxpieces.DC6"
  constant TextSlider (line 183) | TextSlider = "/data/global/ui/MENU/textslid.DC6"
  constant GameSmallMenuButton (line 186) | GameSmallMenuButton = "/data/global/ui/PANEL/menubutton.DC6"
  constant SkillIcon (line 187) | SkillIcon           = "/data/global/ui/PANEL/Skillicon.DC6"
  constant QuestLogBg (line 190) | QuestLogBg              = "/data/global/ui/MENU/questbackground.dc6"
  constant QuestLogDone (line 191) | QuestLogDone            = "/data/global/ui/MENU/questdone.dc6"
  constant QuestLogTabs (line 192) | QuestLogTabs            = "/data/global/ui/MENU/expquesttabs.dc6"
  constant QuestLogQDescrBtn (line 193) | QuestLogQDescrBtn       = "/data/global/ui/MENU/questlast.dc6"
  constant QuestLogSocket (line 194) | QuestLogSocket          = "/data/global/ui/MENU/questsockets.dc6"
  constant QuestLogAQuestAnimation (line 195) | QuestLogAQuestAnimation = "/data/global/ui/MENU/a%dq%d.dc6"
  constant QuestLogDoneSfx (line 196) | QuestLogDoneSfx         = "cursor/questdone.wav"
  constant CursorDefault (line 200) | CursorDefault = "/data/global/ui/CURSOR/ohand.DC6"
  constant Font6 (line 203) | Font6                = "/data/local/FONT/" + LanguageFontToken + "/font6"
  constant Font8 (line 204) | Font8                = "/data/local/FONT/" + LanguageFontToken + "/font8"
  constant Font16 (line 205) | Font16               = "/data/local/FONT/" + LanguageFontToken + "/font16"
  constant Font24 (line 206) | Font24               = "/data/local/FONT/" + LanguageFontToken + "/font24"
  constant Font30 (line 207) | Font30               = "/data/local/FONT/" + LanguageFontToken + "/font30"
  constant Font42 (line 208) | Font42               = "/data/local/FONT/" + LanguageFontToken + "/font42"
  constant FontFormal12 (line 209) | FontFormal12         = "/data/local/FONT/" + LanguageFontToken + "/fontf...
  constant FontFormal11 (line 210) | FontFormal11         = "/data/local/FONT/" + LanguageFontToken + "/fontf...
  constant FontFormal10 (line 211) | FontFormal10         = "/data/local/FONT/" + LanguageFontToken + "/fontf...
  constant FontExocet10 (line 212) | FontExocet10         = "/data/local/FONT/" + LanguageFontToken + "/fonte...
  constant FontExocet8 (line 213) | FontExocet8          = "/data/local/FONT/" + LanguageFontToken + "/fonte...
  constant FontSucker (line 214) | FontSucker           = "/data/local/FONT/" + LanguageFontToken + "/Reall...
  constant FontRediculous (line 215) | FontRediculous       = "/data/local/FONT/" + LanguageFontToken + "/fontr...
  constant ExpansionStringTable (line 216) | ExpansionStringTable = "/data/local/lng/" + LanguageTableToken + "/expan...
  constant StringTable (line 217) | StringTable          = "/data/local/lng/" + LanguageTableToken + "/strin...
  constant PatchStringTable (line 218) | PatchStringTable     = "/data/local/lng/" + LanguageTableToken + "/patch...
  constant WideButtonBlank (line 222) | WideButtonBlank   = "/data/global/ui/FrontEnd/WideButtonBlank.dc6"
  constant MediumButtonBlank (line 223) | MediumButtonBlank = "/data/global/ui/FrontEnd/MediumButtonBlank.dc6"
  constant CancelButton (line 224) | CancelButton      = "/data/global/ui/FrontEnd/CancelButtonBlank.dc6"
  constant NarrowButtonBlank (line 225) | NarrowButtonBlank = "/data/global/ui/FrontEnd/NarrowButtonBlank.dc6"
  constant ShortButtonBlank (line 226) | ShortButtonBlank  = "/data/global/ui/CharSelect/ShortButtonBlank.dc6"
  constant TextBox2 (line 227) | TextBox2          = "/data/global/ui/FrontEnd/textbox2.dc6"
  constant TallButtonBlank (line 228) | TallButtonBlank   = "/data/global/ui/CharSelect/TallButtonBlank.dc6"
  constant Checkbox (line 229) | Checkbox          = "/data/global/ui/FrontEnd/clickbox.dc6"
  constant Scrollbar (line 230) | Scrollbar         = "/data/global/ui/PANEL/scrollbar.dc6"
  constant PopUpLarge (line 232) | PopUpLarge     = "/data/global/ui/FrontEnd/PopUpLarge.dc6"
  constant PopUpLargest (line 233) | PopUpLargest   = "/data/global/ui/FrontEnd/PopUpLargest.dc6"
  constant PopUpWide (line 234) | PopUpWide      = "/data/global/ui/FrontEnd/PopUpWide.dc6"
  constant PopUpOk (line 235) | PopUpOk        = "/data/global/ui/FrontEnd/PopUpOk.dc6"
  constant PopUpOk2 (line 236) | PopUpOk2       = "/data/global/ui/FrontEnd/PopUpOk.dc6"
  constant PopUpOkCancel2 (line 237) | PopUpOkCancel2 = "/data/global/ui/FrontEnd/PopUpOkCancel2.dc6"
  constant PopUp340x224 (line 238) | PopUp340x224   = "/data/global/ui/FrontEnd/PopUp_340x224.dc6"
  constant PentSpin (line 242) | PentSpin        = "/data/global/ui/CURSOR/pentspin.DC6"
  constant Minipanel (line 243) | Minipanel       = "/data/global/ui/PANEL/minipanel.DC6"
  constant MinipanelSmall (line 244) | MinipanelSmall  = "/data/global/ui/PANEL/minipanel_s.dc6"
  constant MinipanelButton (line 245) | MinipanelButton = "/data/global/ui/PANEL/minipanelbtn.DC6"
  constant Frame (line 247) | Frame                     = "/data/global/ui/PANEL/800borderframe.dc6"
  constant InventoryCharacterPanel (line 248) | InventoryCharacterPanel   = "/data/global/ui/PANEL/invchar6.DC6"
  constant PartyPanel (line 249) | PartyPanel                = "/data/global/ui/MENU/party.dc6"
  constant PartyButton (line 250) | PartyButton               = "/data/global/ui/MENU/partybuttons.dc6"
  constant PartyBoxes (line 251) | PartyBoxes                = "/data/global/ui/MENU/partyboxes.dc6"
  constant PartyBar (line 252) | PartyBar                  = "/data/global/ui/MENU/partybar.dc6"
  constant HeroStatsPanelStatsPoints (line 253) | HeroStatsPanelStatsPoints = "/data/global/ui/PANEL/skillpoints.dc6"
  constant HeroStatsPanelSocket (line 254) | HeroStatsPanelSocket      = "/data/global/ui/PANEL/levelsocket.dc6"
  constant InventoryWeaponsTab (line 255) | InventoryWeaponsTab       = "/data/global/ui/PANEL/invchar6Tab.DC6"
  constant SkillsPanelAmazon (line 256) | SkillsPanelAmazon         = "/data/global/ui/SPELLS/skltree_a_back.DC6"
  constant SkillsPanelBarbarian (line 257) | SkillsPanelBarbarian      = "/data/global/ui/SPELLS/skltree_b_back.DC6"
  constant SkillsPanelDruid (line 258) | SkillsPanelDruid          = "/data/global/ui/SPELLS/skltree_d_back.DC6"
  constant SkillsPanelAssassin (line 259) | SkillsPanelAssassin       = "/data/global/ui/SPELLS/skltree_i_back.DC6"
  constant SkillsPanelNecromancer (line 260) | SkillsPanelNecromancer    = "/data/global/ui/SPELLS/skltree_n_back.DC6"
  constant SkillsPanelPaladin (line 261) | SkillsPanelPaladin        = "/data/global/ui/SPELLS/skltree_p_back.DC6"
  constant SkillsPanelSorcerer (line 262) | SkillsPanelSorcerer       = "/data/global/ui/SPELLS/skltree_s_back.DC6"
  constant GenericSkills (line 264) | GenericSkills     = "/data/global/ui/SPELLS/Skillicon.DC6"
  constant AmazonSkills (line 265) | AmazonSkills      = "/data/global/ui/SPELLS/AmSkillicon.DC6"
  constant BarbarianSkills (line 266) | BarbarianSkills   = "/data/global/ui/SPELLS/BaSkillicon.DC6"
  constant DruidSkills (line 267) | DruidSkills       = "/data/global/ui/SPELLS/DrSkillicon.DC6"
  constant AssassinSkills (line 268) | AssassinSkills    = "/data/global/ui/SPELLS/AsSkillicon.DC6"
  constant NecromancerSkills (line 269) | NecromancerSkills = "/data/global/ui/SPELLS/NeSkillicon.DC6"
  constant PaladinSkills (line 270) | PaladinSkills     = "/data/global/ui/SPELLS/PaSkillicon.DC6"
  constant SorcererSkills (line 271) | SorcererSkills    = "/data/global/ui/SPELLS/SoSkillicon.DC6"
  constant RunButton (line 273) | RunButton      = "/data/global/ui/PANEL/runbutton.dc6"
  constant MenuButton (line 274) | MenuButton     = "/data/global/ui/PANEL/menubutton.DC6"
  constant GoldCoinButton (line 275) | GoldCoinButton = "/data/global/ui/panel/goldcoinbtn.dc6"
  constant BuySellButton (line 276) | BuySellButton  = "/data/global/ui/panel/buysellbtn.dc6"
  constant ArmorPlaceholder (line 278) | ArmorPlaceholder      = "/data/global/ui/PANEL/inv_armor.DC6"
  constant BeltPlaceholder (line 279) | BeltPlaceholder       = "/data/global/ui/PANEL/inv_belt.DC6"
  constant BootsPlaceholder (line 280) | BootsPlaceholder      = "/data/global/ui/PANEL/inv_boots.DC6"
  constant HelmGlovePlaceholder (line 281) | HelmGlovePlaceholder  = "/data/global/ui/PANEL/inv_helm_glove.DC6"
  constant RingAmuletPlaceholder (line 282) | RingAmuletPlaceholder = "/data/global/ui/PANEL/inv_ring_amulet.DC6"
  constant WeaponsPlaceholder (line 283) | WeaponsPlaceholder    = "/data/global/ui/PANEL/inv_weapons.DC6"
  constant LevelPreset (line 287) | LevelPreset        = "/data/global/excel/LvlPrest.txt"
  constant LevelType (line 288) | LevelType          = "/data/global/excel/LvlTypes.txt"
  constant ObjectType (line 289) | ObjectType         = "/data/global/excel/objtype.txt"
  constant LevelWarp (line 290) | LevelWarp          = "/data/global/excel/LvlWarp.txt"
  constant LevelDetails (line 291) | LevelDetails       = "/data/global/excel/Levels.txt"
  constant LevelMaze (line 292) | LevelMaze          = "/data/global/excel/LvlMaze.txt"
  constant LevelSubstitutions (line 293) | LevelSubstitutions = "/data/global/excel/LvlSub.txt"
  constant ObjectDetails (line 295) | ObjectDetails         = "/data/global/excel/Objects.txt"
  constant ObjectMode (line 296) | ObjectMode            = "/data/global/excel/ObjMode.txt"
  constant SoundSettings (line 297) | SoundSettings         = "/data/global/excel/Sounds.txt"
  constant ItemStatCost (line 298) | ItemStatCost          = "/data/global/excel/ItemStatCost.txt"
  constant ItemRatio (line 299) | ItemRatio             = "/data/global/excel/itemratio.txt"
  constant ItemTypes (line 300) | ItemTypes             = "/data/global/excel/ItemTypes.txt"
  constant QualityItems (line 301) | QualityItems          = "/data/global/excel/qualityitems.txt"
  constant LowQualityItems (line 302) | LowQualityItems       = "/data/global/excel/lowqualityitems.txt"
  constant Overlays (line 303) | Overlays              = "/data/global/excel/Overlay.txt"
  constant Runes (line 304) | Runes                 = "/data/global/excel/runes.txt"
  constant Sets (line 305) | Sets                  = "/data/global/excel/Sets.txt"
  constant SetItems (line 306) | SetItems              = "/data/global/excel/SetItems.txt"
  constant AutoMagic (line 307) | AutoMagic             = "/data/global/excel/automagic.txt"
  constant BodyLocations (line 308) | BodyLocations         = "/data/global/excel/bodylocs.txt"
  constant Events (line 309) | Events                = "/data/global/excel/events.txt"
  constant Properties (line 310) | Properties            = "/data/global/excel/Properties.txt"
  constant Hireling (line 311) | Hireling              = "/data/global/excel/hireling.txt"
  constant HirelingDescription (line 312) | HirelingDescription   = "/data/global/excel/HireDesc.txt"
  constant DifficultyLevels (line 313) | DifficultyLevels      = "/data/global/excel/difficultylevels.txt"
  constant AutoMap (line 314) | AutoMap               = "/data/global/excel/AutoMap.txt"
  constant CubeRecipes (line 315) | CubeRecipes           = "/data/global/excel/cubemain.txt"
  constant CubeModifier (line 316) | CubeModifier          = "/data/global/excel/CubeMod.txt"
  constant CubeType (line 317) | CubeType              = "/data/global/excel/CubeType.txt"
  constant Skills (line 318) | Skills                = "/data/global/excel/skills.txt"
  constant SkillDesc (line 319) | SkillDesc             = "/data/global/excel/skilldesc.txt"
  constant SkillCalc (line 320) | SkillCalc             = "/data/global/excel/skillcalc.txt"
  constant MissileCalc (line 321) | MissileCalc           = "/data/global/excel/misscalc.txt"
  constant TreasureClass (line 322) | TreasureClass         = "/data/global/excel/TreasureClass.txt"
  constant TreasureClassEx (line 323) | TreasureClassEx       = "/data/global/excel/TreasureClassEx.txt"
  constant States (line 324) | States                = "/data/global/excel/states.txt"
  constant SoundEnvirons (line 325) | SoundEnvirons         = "/data/global/excel/soundenviron.txt"
  constant Shrines (line 326) | Shrines               = "/data/global/excel/shrines.txt"
  constant MonProp (line 327) | MonProp               = "/data/global/excel/Monprop.txt"
  constant ElemType (line 328) | ElemType              = "/data/global/excel/ElemTypes.txt"
  constant PlrMode (line 329) | PlrMode               = "/data/global/excel/PlrMode.txt"
  constant PetType (line 330) | PetType               = "/data/global/excel/pettype.txt"
  constant NPC (line 331) | NPC                   = "/data/global/excel/npc.txt"
  constant MonsterUniqueModifier (line 332) | MonsterUniqueModifier = "/data/global/excel/monumod.txt"
  constant MonsterEquipment (line 333) | MonsterEquipment      = "/data/global/excel/monequip.txt"
  constant UniqueAppellation (line 334) | UniqueAppellation     = "/data/global/excel/UniqueAppellation.txt"
  constant MonsterLevel (line 335) | MonsterLevel          = "/data/global/excel/monlvl.txt"
  constant MonsterSound (line 336) | MonsterSound          = "/data/global/excel/monsounds.txt"
  constant MonsterSequence (line 337) | MonsterSequence       = "/data/global/excel/monseq.txt"
  constant PlayerClass (line 338) | PlayerClass           = "/data/global/excel/PlayerClass.txt"
  constant PlayerType (line 339) | PlayerType            = "/data/global/excel/PlrType.txt"
  constant Composite (line 340) | Composite             = "/data/global/excel/Composit.txt"
  constant HitClass (line 341) | HitClass              = "/data/global/excel/HitClass.txt"
  constant ObjectGroup (line 342) | ObjectGroup           = "/data/global/excel/objgroup.txt"
  constant CompCode (line 343) | CompCode              = "/data/global/excel/compcode.txt"
  constant Belts (line 344) | Belts                 = "/data/global/excel/belts.txt"
  constant Gamble (line 345) | Gamble                = "/data/global/excel/gamble.txt"
  constant Colors (line 346) | Colors                = "/data/global/excel/colors.txt"
  constant StorePage (line 347) | StorePage             = "/data/global/excel/StorePage.txt"
  constant ObjectData (line 351) | ObjectData          = "/data/global/objects"
  constant AnimationData (line 352) | AnimationData       = "/data/global/animdata.d2"
  constant PlayerAnimationBase (line 353) | PlayerAnimationBase = "/data/global/CHARS"
  constant MissileData (line 354) | MissileData         = "/data/global/missiles"
  constant ItemGraphics (line 355) | ItemGraphics        = "/data/global/items"
  constant Inventory (line 359) | Inventory   = "/data/global/excel/inventory.txt"
  constant Weapons (line 360) | Weapons     = "/data/global/excel/weapons.txt"
  constant Armor (line 361) | Armor       = "/data/global/excel/armor.txt"
  constant ArmorType (line 362) | ArmorType   = "/data/global/excel/ArmType.txt"
  constant WeaponClass (line 363) | WeaponClass = "/data/global/excel/WeaponClass.txt"
  constant Books (line 364) | Books       = "/data/global/excel/books.txt"
  constant Misc (line 365) | Misc        = "/data/global/excel/misc.txt"
  constant UniqueItems (line 366) | UniqueItems = "/data/global/excel/UniqueItems.txt"
  constant Gems (line 367) | Gems        = "/data/global/excel/gems.txt"
  constant MagicPrefix (line 371) | MagicPrefix = "/data/global/excel/MagicPrefix.txt"
  constant MagicSuffix (line 372) | MagicSuffix = "/data/global/excel/MagicSuffix.txt"
  constant RarePrefix (line 373) | RarePrefix  = "/data/global/excel/RarePrefix.txt"
  constant RareSuffix (line 374) | RareSuffix  = "/data/global/excel/RareSuffix.txt"
  constant UniquePrefix (line 377) | UniquePrefix = "/data/global/excel/UniquePrefix.txt"
  constant UniqueSuffix (line 378) | UniqueSuffix = "/data/global/excel/UniqueSuffix.txt"
  constant Experience (line 382) | Experience = "/data/global/excel/experience.txt"
  constant CharStats (line 383) | CharStats  = "/data/global/excel/charstats.txt"
  constant BGMTitle (line 387) | BGMTitle                    = "/data/global/music/introedit.wav"
  constant BGMOptions (line 388) | BGMOptions                  = "/data/global/music/Common/options.wav"
  constant BGMAct1AndarielAction (line 389) | BGMAct1AndarielAction       = "/data/global/music/Act1/andarielaction.wav"
  constant BGMAct1BloodRavenResolution (line 390) | BGMAct1BloodRavenResolution = "/data/global/music/Act1/bloodravenresolut...
  constant BGMAct1Caves (line 391) | BGMAct1Caves                = "/data/global/music/Act1/caves.wav"
  constant BGMAct1Crypt (line 392) | BGMAct1Crypt                = "/data/global/music/Act1/crypt.wav"
  constant BGMAct1DenOfEvilAction (line 393) | BGMAct1DenOfEvilAction      = "/data/global/music/Act1/denofevilaction.wav"
  constant BGMAct1Monastery (line 394) | BGMAct1Monastery            = "/data/global/music/Act1/monastery.wav"
  constant BGMAct1Town1 (line 395) | BGMAct1Town1                = "/data/global/music/Act1/town1.wav"
  constant BGMAct1Tristram (line 396) | BGMAct1Tristram             = "/data/global/music/Act1/tristram.wav"
  constant BGMAct1Wild (line 397) | BGMAct1Wild                 = "/data/global/music/Act1/wild.wav"
  constant BGMAct2Desert (line 398) | BGMAct2Desert               = "/data/global/music/Act2/desert.wav"
  constant BGMAct2Harem (line 399) | BGMAct2Harem                = "/data/global/music/Act2/harem.wav"
  constant BGMAct2HoradricAction (line 400) | BGMAct2HoradricAction       = "/data/global/music/Act2/horadricaction.wav"
  constant BGMAct2Lair (line 401) | BGMAct2Lair                 = "/data/global/music/Act2/lair.wav"
  constant BGMAct2RadamentResolution (line 402) | BGMAct2RadamentResolution   = "/data/global/music/Act2/radamentresolutio...
  constant BGMAct2Sanctuary (line 403) | BGMAct2Sanctuary            = "/data/global/music/Act2/sanctuary.wav"
  constant BGMAct2Sewer (line 404) | BGMAct2Sewer                = "/data/global/music/Act2/sewer.wav"
  constant BGMAct2TaintedSunAction (line 405) | BGMAct2TaintedSunAction     = "/data/global/music/Act2/taintedsunaction....
  constant BGMAct2Tombs (line 406) | BGMAct2Tombs                = "/data/global/music/Act2/tombs.wav"
  constant BGMAct2Town2 (line 407) | BGMAct2Town2                = "/data/global/music/Act2/town2.wav"
  constant BGMAct2Valley (line 408) | BGMAct2Valley               = "/data/global/music/Act2/valley.wav"
  constant BGMAct3Jungle (line 409) | BGMAct3Jungle               = "/data/global/music/Act3/jungle.wav"
  constant BGMAct3Kurast (line 410) | BGMAct3Kurast               = "/data/global/music/Act3/kurast.wav"
  constant BGMAct3KurastSewer (line 411) | BGMAct3KurastSewer          = "/data/global/music/Act3/kurastsewer.wav"
  constant BGMAct3MefDeathAction (line 412) | BGMAct3MefDeathAction       = "/data/global/music/Act3/mefdeathaction.wav"
  constant BGMAct3OrbAction (line 413) | BGMAct3OrbAction            = "/data/global/music/Act3/orbaction.wav"
  constant BGMAct3Spider (line 414) | BGMAct3Spider               = "/data/global/music/Act3/spider.wav"
  constant BGMAct3Town3 (line 415) | BGMAct3Town3                = "/data/global/music/Act3/town3.wav"
  constant BGMAct4Diablo (line 416) | BGMAct4Diablo               = "/data/global/music/Act4/diablo.wav"
  constant BGMAct4DiabloAction (line 417) | BGMAct4DiabloAction         = "/data/global/music/Act4/diabloaction.wav"
  constant BGMAct4ForgeAction (line 418) | BGMAct4ForgeAction          = "/data/global/music/Act4/forgeaction.wav"
  constant BGMAct4IzualAction (line 419) | BGMAct4IzualAction          = "/data/global/music/Act4/izualaction.wav"
  constant BGMAct4Mesa (line 420) | BGMAct4Mesa                 = "/data/global/music/Act4/mesa.wav"
  constant BGMAct4Town4 (line 421) | BGMAct4Town4                = "/data/global/music/Act4/town4.wav"
  constant BGMAct5Baal (line 422) | BGMAct5Baal                 = "/data/global/music/Act5/baal.wav"
  constant BGMAct5Siege (line 423) | BGMAct5Siege                = "/data/global/music/Act5/siege.wav"
  constant BGMAct5Shenk (line 424) | BGMAct5Shenk                = "/data/global/music/Act5/shenkmusic.wav"
  constant BGMAct5XTown (line 425) | BGMAct5XTown                = "/data/global/music/Act5/xtown.wav"
  constant BGMAct5XTemple (line 426) | BGMAct5XTemple              = "/data/global/music/Act5/xtemple.wav"
  constant BGMAct5IceCaves (line 427) | BGMAct5IceCaves             = "/data/global/music/Act5/icecaves.wav"
  constant BGMAct5Nihlathak (line 428) | BGMAct5Nihlathak            = "/data/global/music/Act5/nihlathakmusic.wav"
  constant SFXCursorSelect (line 432) | SFXCursorSelect        = "cursor_select"
  constant SFXButtonClick (line 433) | SFXButtonClick         = "cursor_button_click"
  constant SFXAmazonDeselect (line 434) | SFXAmazonDeselect      = "cursor_amazon_deselect"
  constant SFXAmazonSelect (line 435) | SFXAmazonSelect        = "cursor_amazon_select"
  constant SFXAssassinDeselect (line 436) | SFXAssassinDeselect    = "Cursor/intro/assassin deselect.wav"
  constant SFXAssassinSelect (line 437) | SFXAssassinSelect      = "Cursor/intro/assassin select.wav"
  constant SFXBarbarianDeselect (line 438) | SFXBarbarianDeselect   = "cursor_barbarian_deselect"
  constant SFXBarbarianSelect (line 439) | SFXBarbarianSelect     = "cursor_barbarian_select"
  constant SFXDruidDeselect (line 440) | SFXDruidDeselect       = "Cursor/intro/druid deselect.wav"
  constant SFXDruidSelect (line 441) | SFXDruidSelect         = "Cursor/intro/druid select.wav"
  constant SFXNecromancerDeselect (line 442) | SFXNecromancerDeselect = "cursor_necromancer_deselect"
  constant SFXNecromancerSelect (line 443) | SFXNecromancerSelect   = "cursor_necromancer_select"
  constant SFXPaladinDeselect (line 444) | SFXPaladinDeselect     = "cursor_paladin_deselect"
  constant SFXPaladinSelect (line 445) | SFXPaladinSelect       = "cursor_paladin_select"
  constant SFXSorceressDeselect (line 446) | SFXSorceressDeselect   = "cursor_sorceress_deselect"
  constant SFXSorceressSelect (line 447) | SFXSorceressSelect     = "cursor_sorceress_select"
  constant MonStats (line 451) | MonStats         = "/data/global/excel/monstats.txt"
  constant MonStats2 (line 452) | MonStats2        = "/data/global/excel/monstats2.txt"
  constant MonPreset (line 453) | MonPreset        = "/data/global/excel/monpreset.txt"
  constant MonType (line 454) | MonType          = "/data/global/excel/Montype.txt"
  constant SuperUniques (line 455) | SuperUniques     = "/data/global/excel/SuperUniques.txt"
  constant MonMode (line 456) | MonMode          = "/data/global/excel/monmode.txt"
  constant MonsterPlacement (line 457) | MonsterPlacement = "/data/global/excel/MonPlace.txt"
  constant MonsterAI (line 458) | MonsterAI        = "/data/global/excel/monai.txt"
  constant Missiles (line 462) | Missiles = "/data/global/excel/Missiles.txt"
  constant PaletteAct1 (line 466) | PaletteAct1      = "/data/global/palette/act1/pal.dat"
  constant PaletteAct2 (line 467) | PaletteAct2      = "/data/global/palette/act2/pal.dat"
  constant PaletteAct3 (line 468) | PaletteAct3      = "/data/global/palette/act3/pal.dat"
  constant PaletteAct4 (line 469) | PaletteAct4      = "/data/global/palette/act4/pal.dat"
  constant PaletteAct5 (line 470) | PaletteAct5      = "/data/global/palette/act5/pal.dat"
  constant PaletteEndGame (line 471) | PaletteEndGame   = "/data/global/palette/endgame/pal.dat"
  constant PaletteEndGame2 (line 472) | PaletteEndGame2  = "/data/global/palette/endgame2/pal.dat"
  constant PaletteFechar (line 473) | PaletteFechar    = "/data/global/palette/fechar/pal.dat"
  constant PaletteLoading (line 474) | PaletteLoading   = "/data/global/palette/loading/pal.dat"
  constant PaletteMenu0 (line 475) | PaletteMenu0     = "/data/global/palette/menu0/pal.dat"
  constant PaletteMenu1 (line 476) | PaletteMenu1     = "/data/global/palette/menu1/pal.dat"
  constant PaletteMenu2 (line 477) | PaletteMenu2     = "/data/global/palette/menu2/pal.dat"
  constant PaletteMenu3 (line 478) | PaletteMenu3     = "/data/global/palette/menu3/pal.dat"
  constant PaletteMenu4 (line 479) | PaletteMenu4     = "/data/global/palette/menu4/pal.dat"
  constant PaletteSky (line 480) | PaletteSky       = "/data/global/palette/sky/pal.dat"
  constant PaletteStatic (line 481) | PaletteStatic    = "/data/global/palette/static/pal.dat"
  constant PaletteTrademark (line 482) | PaletteTrademark = "/data/global/palette/trademark/pal.dat"
  constant PaletteUnits (line 483) | PaletteUnits     = "/data/global/palette/units/pal.dat"
  constant PaletteTransformAct1 (line 487) | PaletteTransformAct1      = "/data/global/palette/act1/Pal.pl2"
  constant PaletteTransformAct2 (line 488) | PaletteTransformAct2      = "/data/global/palette/act2/Pal.pl2"
  constant PaletteTransformAct3 (line 489) | PaletteTransformAct3      = "/data/global/palette/act3/Pal.pl2"
  constant PaletteTransformAct4 (line 490) | PaletteTransformAct4      = "/data/global/palette/act4/Pal.pl2"
  constant PaletteTransformAct5 (line 491) | PaletteTransformAct5      = "/data/global/palette/act5/Pal.pl2"
  constant PaletteTransformEndGame (line 492) | PaletteTransformEndGame   = "/data/global/palette/endgame/Pal.pl2"
  constant PaletteTransformEndGame2 (line 493) | PaletteTransformEndGame2  = "/data/global/palette/endgame2/Pal.pl2"
  constant PaletteTransformFechar (line 494) | PaletteTransformFechar    = "/data/global/palette/fechar/Pal.pl2"
  constant PaletteTransformLoading (line 495) | PaletteTransformLoading   = "/data/global/palette/loading/Pal.pl2"
  constant PaletteTransformMenu0 (line 496) | PaletteTransformMenu0     = "/data/global/palette/menu0/Pal.pl2"
  constant PaletteTransformMenu1 (line 497) | PaletteTransformMenu1     = "/data/global/palette/menu1/Pal.pl2"
  constant PaletteTransformMenu2 (line 498) | PaletteTransformMenu2     = "/data/global/palette/menu2/Pal.pl2"
  constant PaletteTransformMenu3 (line 499) | PaletteTransformMenu3     = "/data/global/palette/menu3/Pal.pl2"
  constant PaletteTransformMenu4 (line 500) | PaletteTransformMenu4     = "/data/global/palette/menu4/Pal.pl2"
  constant PaletteTransformSky (line 501) | PaletteTransformSky       = "/data/global/palette/sky/Pal.pl2"
  constant PaletteTransformTrademark (line 502) | PaletteTransformTrademark = "/data/global/palette/trademark/Pal.pl2"

FILE: d2common/d2util/assets/assets.go
  constant CharWidth (line 34) | CharWidth = 8
  constant CharHeight (line 37) | CharHeight = 16
  function CreateTextImage (line 41) | func CreateTextImage() image.Image {

FILE: d2common/d2util/debug_print.go
  constant cw (line 12) | cw = assets.CharWidth
  constant ch (line 13) | ch = assets.CharHeight
  function NewDebugPrinter (line 17) | func NewDebugPrinter() *GlyphPrinter {
  type GlyphPrinter (line 29) | type GlyphPrinter struct
    method Print (line 40) | func (p *GlyphPrinter) Print(target interface{}, str string) error {
    method PrintAt (line 48) | func (p *GlyphPrinter) PrintAt(target interface{}, str string, x, y in...
    method drawDebugText (line 52) | func (p *GlyphPrinter) drawDebugText(target *ebiten.Image, str string,...

FILE: d2common/d2util/logger.go
  constant LogLevelNone (line 16) | LogLevelNone LogLevel = iota
  constant LogLevelFatal (line 17) | LogLevelFatal
  constant LogLevelError (line 18) | LogLevelError
  constant LogLevelWarning (line 19) | LogLevelWarning
  constant LogLevelInfo (line 20) | LogLevelInfo
  constant LogLevelDebug (line 21) | LogLevelDebug
  constant LogLevelUnspecified (line 22) | LogLevelUnspecified
  constant LogLevelDefault (line 26) | LogLevelDefault = LogLevelInfo
  constant red (line 29) | red     = 1
  constant green (line 30) | green   = 2
  constant yellow (line 31) | yellow  = 3
  constant magenta (line 32) | magenta = 5
  constant cyan (line 33) | cyan    = 6
  constant fmtColorEscape (line 36) | fmtColorEscape = "\033[3%dm"
  constant colorEscapeReset (line 37) | colorEscapeReset = "\033[0m"
  constant fmtPrefix (line 41) | fmtPrefix     = "[%s]"
  constant LogFmtDebug (line 42) | LogFmtDebug   = "[DEBUG]" + colorEscapeReset + " %s\r\n"
  constant LogFmtInfo (line 43) | LogFmtInfo    = "[INFO]" + colorEscapeReset + " %s\r\n"
  constant LogFmtWarning (line 44) | LogFmtWarning = "[WARNING]" + colorEscapeReset + " %s\r\n"
  constant LogFmtError (line 45) | LogFmtError   = "[ERROR]" + colorEscapeReset + " %s\r\n"
  constant LogFmtFatal (line 46) | LogFmtFatal   = "[FATAL]" + colorEscapeReset + " %s\r\n"
  function NewLogger (line 50) | func NewLogger() *Logger {
  type Logger (line 62) | type Logger struct
    method SetPrefix (line 73) | func (l *Logger) SetPrefix(s string) {
    method SetLevel (line 78) | func (l *Logger) SetLevel(level LogLevel) {
    method SetColorEnabled (line 87) | func (l *Logger) SetColorEnabled(b bool) {
    method Info (line 96) | func (l *Logger) Info(msg string) {
    method Infof (line 105) | func (l *Logger) Infof(fmtMsg string, args ...interface{}) {
    method Warning (line 110) | func (l *Logger) Warning(msg string) {
    method Warningf (line 119) | func (l *Logger) Warningf(fmtMsg string, args ...interface{}) {
    method Error (line 124) | func (l *Logger) Error(msg string) {
    method Errorf (line 133) | func (l *Logger) Errorf(fmtMsg string, args ...interface{}) {
    method Fatal (line 138) | func (l *Logger) Fatal(msg string) {
    method Fatalf (line 149) | func (l *Logger) Fatalf(fmtMsg string, args ...interface{}) {
    method Debug (line 154) | func (l *Logger) Debug(msg string) {
    method Debugf (line 163) | func (l *Logger) Debugf(fmtMsg string, args ...interface{}) {
    method print (line 167) | func (l *Logger) print(level LogLevel, msg string) {
    method Write (line 220) | func (l *Logger) Write(p []byte) (n int, err error) {
  function format (line 216) | func format(fmtStr string, fmtInput []byte) []byte {

FILE: d2common/d2util/logger_test.go
  type testWriter (line 8) | type testWriter struct
    method Write (line 12) | func (tw *testWriter) Write(msg []byte) (int, error) {
  function Test_logger_SetLevel (line 18) | func Test_logger_SetLevel(t *testing.T) {
  function Test_logger_LogLevels (line 42) | func Test_logger_LogLevels(t *testing.T) {

FILE: d2common/d2util/palette.go
  function ImgIndexToRGBA (line 11) | func ImgIndexToRGBA(indexData []byte, palette d2interface.Palette) []byte {

FILE: d2common/d2util/rgba_color.go
  function Color (line 6) | func Color(rgba uint32) color.RGBA {

FILE: d2common/d2util/stringutils.go
  function AsterToEmpty (line 14) | func AsterToEmpty(text string) string {
  function EmptyToZero (line 24) | func EmptyToZero(text string) string {
  function StringToInt (line 33) | func StringToInt(text string) int {
  function StringToUint (line 45) | func StringToUint(text string) uint {
  function StringToUint8 (line 55) | func StringToUint8(text string) uint8 {
  function StringToInt8 (line 69) | func StringToInt8(text string) int8 {
  function Utf16BytesToString (line 83) | func Utf16BytesToString(b []byte) (string, error) {
  function SplitIntoLinesWithMaxWidth (line 107) | func SplitIntoLinesWithMaxWidth(fullSentence string, maxChars int) []str...
  function splitCjkIntoChunks (line 139) | func splitCjkIntoChunks(str string, chars int) []string {

FILE: d2common/d2util/timeutils.go
  constant nanoseconds (line 6) | nanoseconds = 1000000000.0
  function Now (line 10) | func Now() float64 {

FILE: d2core/d2asset/animation.go
  type playMode (line 16) | type playMode
  constant playModePause (line 19) | playModePause playMode = iota
  constant playModeForward (line 20) | playModeForward
  constant playModeBackward (line 21) | playModeBackward
  constant defaultPlayLength (line 24) | defaultPlayLength = 1.0
  type animationFrame (line 26) | type animationFrame struct
  type animationDirection (line 37) | type animationDirection struct
  type Animation (line 46) | type Animation struct
    method SetSubLoop (line 67) | func (a *Animation) SetSubLoop(startFrame, endFrame int) {
    method Advance (line 74) | func (a *Animation) Advance(elapsed float64) error {
    method renderShadow (line 129) | func (a *Animation) renderShadow(target d2interface.Surface) {
    method GetCurrentFrameSurface (line 156) | func (a *Animation) GetCurrentFrameSurface() d2interface.Surface {
    method Render (line 161) | func (a *Animation) Render(target d2interface.Surface) {
    method BindRenderer (line 183) | func (a *Animation) BindRenderer(r d2interface.Renderer) {
    method RenderFromOrigin (line 194) | func (a *Animation) RenderFromOrigin(target d2interface.Surface, shado...
    method RenderSection (line 224) | func (a *Animation) RenderSection(target d2interface.Surface, bound im...
    method GetFrameSize (line 245) | func (a *Animation) GetFrameSize(frameIndex int) (width, height int, e...
    method GetCurrentFrameSize (line 257) | func (a *Animation) GetCurrentFrameSize() (width, height int) {
    method GetFrameBounds (line 267) | func (a *Animation) GetFrameBounds() (maxWidth, maxHeight int) {
    method GetCurrentFrame (line 281) | func (a *Animation) GetCurrentFrame() int {
    method GetFrameCount (line 286) | func (a *Animation) GetFrameCount() int {
    method IsOnFirstFrame (line 292) | func (a *Animation) IsOnFirstFrame() bool {
    method IsOnLastFrame (line 297) | func (a *Animation) IsOnLastFrame() bool {
    method GetDirectionCount (line 302) | func (a *Animation) GetDirectionCount() int {
    method SetDirection (line 307) | func (a *Animation) SetDirection(directionIndex int) error {
    method GetDirection (line 320) | func (a *Animation) GetDirection() int {
    method SetCurrentFrame (line 325) | func (a *Animation) SetCurrentFrame(frameIndex int) error {
    method Rewind (line 337) | func (a *Animation) Rewind() {
    method PlayForward (line 345) | func (a *Animation) PlayForward() {
    method PlayBackward (line 351) | func (a *Animation) PlayBackward() {
    method Pause (line 357) | func (a *Animation) Pause() {
    method SetPlayLoop (line 363) | func (a *Animation) SetPlayLoop(loop bool) {
    method SetPlaySpeed (line 368) | func (a *Animation) SetPlaySpeed(playSpeed float64) {
    method SetPlayLength (line 373) | func (a *Animation) SetPlayLength(playLength float64) {
    method SetColorMod (line 380) | func (a *Animation) SetColorMod(colorMod color.Color) {
    method GetPlayedCount (line 385) | func (a *Animation) GetPlayedCount() int {
    method ResetPlayedCount (line 390) | func (a *Animation) ResetPlayedCount() {
    method SetEffect (line 395) | func (a *Animation) SetEffect(e d2enum.DrawEffect) {
    method SetShadow (line 400) | func (a *Animation) SetShadow(shadow bool) {
    method Clone (line 405) | func (a *Animation) Clone() d2interface.Animation {
  constant full (line 124) | full = 1.0
  constant half (line 125) | half = 0.5
  constant zero (line 126) | zero = 0.0

FILE: d2core/d2asset/asset_manager.go
  constant defaultCacheEntryWeight (line 36) | defaultCacheEntryWeight = 1
  constant animationBudget (line 40) | animationBudget        = 1024 * 1024 * 128
  constant fontBudget (line 41) | fontBudget             = 128
  constant paletteBudget (line 42) | paletteBudget          = 64
  constant paletteTransformBudget (line 43) | paletteTransformBudget = 64
  constant dt1Budget (line 44) | dt1Budget              = 4096 * 2048 * 128
  constant ds1Budget (line 45) | ds1Budget              = 4096 * 2048 * 128
  constant cofBudget (line 46) | cofBudget              = 4096 * 2048 * 128
  constant dccBudget (line 47) | dccBudget              = 4096 * 2048 * 128
  constant defaultLanguage (line 51) | defaultLanguage    = "ENG"
  constant logPrefix (line 52) | logPrefix          = "Asset Manager"
  constant fmtLoadAsset (line 53) | fmtLoadAsset       = "could not load file stream %s (%v)"
  constant fmtLoadAnimation (line 54) | fmtLoadAnimation   = "loading animation %s with palette %s, draw effect %d"
  constant fmtLoadComposite (line 55) | fmtLoadComposite   = "loading composite: type %d, token %s, palette %s"
  constant fmtLoadFont (line 56) | fmtLoadFont        = "loading font: table %s, sprite %s, palette %s"
  constant fmtLoadPalette (line 57) | fmtLoadPalette     = "loading palette %s"
  constant fmtLoadStringTable (line 58) | fmtLoadStringTable = "loading string table: %s"
  constant fmtLoadTransform (line 59) | fmtLoadTransform   = "loading palette transform: %s"
  constant fmtLoadDict (line 60) | fmtLoadDict        = "loading data dictionary: %s"
  type AssetManager (line 64) | type AssetManager struct
    method SetLogLevel (line 83) | func (am *AssetManager) SetLogLevel(level d2util.LogLevel) {
    method LoadAsset (line 90) | func (am *AssetManager) LoadAsset(filePath string) (io.ReadSeeker, err...
    method LoadFileStream (line 102) | func (am *AssetManager) LoadFileStream(filePath string) (io.ReadSeeker...
    method LoadFile (line 108) | func (am *AssetManager) LoadFile(filePath string) ([]byte, error) { //...
    method FileExists (line 123) | func (am *AssetManager) FileExists(filePath string) (bool, error) {
    method LoadLanguage (line 132) | func (am *AssetManager) LoadLanguage(languagePath string) string {
    method LoadAnimation (line 152) | func (am *AssetManager) LoadAnimation(animationPath, palettePath strin...
    method LoadAnimationWithEffect (line 157) | func (am *AssetManager) LoadAnimationWithEffect(animationPath, palette...
    method LoadComposite (line 195) | func (am *AssetManager) LoadComposite(baseType d2enum.ObjectType, toke...
    method LoadFont (line 212) | func (am *AssetManager) LoadFont(tablePath, spritePath, palettePath st...
    method LoadPalette (line 244) | func (am *AssetManager) LoadPalette(palettePath string) (d2interface.P...
    method LoadStringTable (line 271) | func (am *AssetManager) LoadStringTable(tablePath string) (d2tbl.TextD...
    method TranslateString (line 292) | func (am *AssetManager) TranslateString(input interface{}) string {
    method LoadPaletteTransform (line 316) | func (am *AssetManager) LoadPaletteTransform(path string) (*d2pl2.PL2,...
    method LoadDataDictionary (line 341) | func (am *AssetManager) LoadDataDictionary(path string) (*d2txt.DataDi...
    method LoadRecords (line 360) | func (am *AssetManager) LoadRecords(path string) error {
    method loadDC6 (line 375) | func (am *AssetManager) loadDC6(path string,
    method loadDCC (line 393) | func (am *AssetManager) loadDCC(path string,
    method BindTerminalCommands (line 409) | func (am *AssetManager) BindTerminalCommands(term d2interface.Terminal...
    method UnbindTerminalCommands (line 426) | func (am *AssetManager) UnbindTerminalCommands(term d2interface.Termin...
    method commandAssetSpam (line 430) | func (am *AssetManager) commandAssetSpam(term d2interface.Terminal) fu...
    method commandAssetStat (line 457) | func (am *AssetManager) commandAssetStat(term d2interface.Terminal) fu...
    method commandAssetClear (line 473) | func (am *AssetManager) commandAssetClear([]string) error {
    method LoadDT1 (line 487) | func (am *AssetManager) LoadDT1(dt1Path string) (*d2dt1.DT1, error) {
    method LoadDS1 (line 510) | func (am *AssetManager) LoadDS1(ds1Path string) (*d2ds1.DS1, error) {
    method LoadCOF (line 533) | func (am *AssetManager) LoadCOF(cofPath string) (*d2cof.COF, error) {
    method LoadDCC (line 556) | func (am *AssetManager) LoadDCC(dccPath string) (*d2dcc.DCC, error) {

FILE: d2core/d2asset/composite.go
  constant hardcodedFPS (line 15) | hardcodedFPS     = 25.0
  constant hardcodedDivisor (line 16) | hardcodedDivisor = 1.0 / 256.0
  constant speedUnit (line 17) | speedUnit        = hardcodedFPS * hardcodedDivisor
  type Composite (line 21) | type Composite struct
    method Advance (line 39) | func (c *Composite) Advance(elapsed float64) error {
    method Render (line 63) | func (c *Composite) Render(target d2interface.Surface) error {
    method ObjectAnimationMode (line 89) | func (c *Composite) ObjectAnimationMode() d2enum.ObjectAnimationMode {
    method GetAnimationMode (line 94) | func (c *Composite) GetAnimationMode() string {
    method GetCurrentFrame (line 99) | func (c *Composite) GetCurrentFrame() int {
    method GetFrameCount (line 104) | func (c *Composite) GetFrameCount() int {
    method GetWeaponClass (line 109) | func (c *Composite) GetWeaponClass() string {
    method SetMode (line 114) | func (c *Composite) SetMode(animationMode animationMode, weaponClass s...
    method Equip (line 131) | func (c *Composite) Equip(equipment *[d2enum.CompositeTypeMax]string) ...
    method SetAnimSpeed (line 149) | func (c *Composite) SetAnimSpeed(speed int) {
    method SetDirection (line 160) | func (c *Composite) SetDirection(direction int) {
    method GetDirection (line 188) | func (c *Composite) GetDirection() int {
    method GetPlayedCount (line 193) | func (c *Composite) GetPlayedCount() int {
    method SetPlayLoop (line 202) | func (c *Composite) SetPlayLoop(loop bool) {
    method SetSubLoop (line 212) | func (c *Composite) SetSubLoop(startFrame, endFrame int) {
    method SetCurrentFrame (line 222) | func (c *Composite) SetCurrentFrame(frame int) {
    method resetPlayedCount (line 233) | func (c *Composite) resetPlayedCount() {
    method createMode (line 257) | func (c *Composite) createMode(animationMode animationMode, weaponClas...
    method loadCompositeLayer (line 314) | func (c *Composite) loadCompositeLayer(layerKey, layerValue, animation...
    method GetSize (line 337) | func (c *Composite) GetSize() (w, h int) {
    method updateSize (line 342) | func (c *Composite) updateSize() {
  type size (line 33) | type size struct
  type animationMode (line 239) | type animationMode interface
  type compositeMode (line 243) | type compositeMode struct
  function baseString (line 374) | func baseString(baseType d2enum.ObjectType) string {

FILE: d2core/d2asset/d2asset.go
  function NewAssetManager (line 12) | func NewAssetManager(logLevel d2util.LogLevel) (*AssetManager, error) {

FILE: d2core/d2asset/dc6_animation.go
  function newDC6Animation (line 17) | func newDC6Animation(
  type DC6Animation (line 53) | type DC6Animation struct
    method init (line 59) | func (a *DC6Animation) init() error {
    method SetDirection (line 72) | func (a *DC6Animation) SetDirection(directionIndex int) error {
    method decode (line 92) | func (a *DC6Animation) decode() error {
    method decodeDirection (line 103) | func (a *DC6Animation) decodeDirection(directionIndex int) error {
    method decodeFrame (line 114) | func (a *DC6Animation) decodeFrame(directionIndex, frameIndex int) ani...
    method createSurfaces (line 131) | func (a *DC6Animation) createSurfaces() error {
    method createDirectionSurfaces (line 142) | func (a *DC6Animation) createDirectionSurfaces(directionIndex int) err...
    method createFrameSurface (line 162) | func (a *DC6Animation) createFrameSurface(directionIndex, frameIndex i...
    method Clone (line 185) | func (a *DC6Animation) Clone() d2interface.Animation {

FILE: d2core/d2asset/dcc_animation.go
  function newDCCAnimation (line 17) | func newDCCAnimation(
  type DCCAnimation (line 52) | type DCCAnimation struct
    method init (line 58) | func (a *DCCAnimation) init() error {
    method Clone (line 71) | func (a *DCCAnimation) Clone() d2interface.Animation {
    method SetDirection (line 81) | func (a *DCCAnimation) SetDirection(directionIndex int) error {
    method decode (line 101) | func (a *DCCAnimation) decode() error {
    method decodeDirection (line 112) | func (a *DCCAnimation) decodeDirection(directionIndex int) error {
    method decodeFrame (line 129) | func (a *DCCAnimation) decodeFrame(directionIndex int) animationFrame {
    method createSurfaces (line 143) | func (a *DCCAnimation) createSurfaces() error {
    method createDirectionSurfaces (line 154) | func (a *DCCAnimation) createDirectionSurfaces(directionIndex int) err...
    method createFrameSurface (line 174) | func (a *DCCAnimation) createFrameSurface(directionIndex, frameIndex i...

FILE: d2core/d2audio/ebiten/ebiten_audio_provider.go
  constant sampleRate (line 15) | sampleRate = 44100
  constant logPrefix (line 17) | logPrefix = "Ebiten Audio Provider"
  function CreateAudio (line 22) | func CreateAudio(l d2util.LogLevel, am *d2asset.AssetManager) *AudioProv...
  type AudioProvider (line 37) | type AudioProvider struct
    method PlayBGM (line 50) | func (eap *AudioProvider) PlayBGM(song string) {
    method LoadSound (line 106) | func (eap *AudioProvider) LoadSound(sfx string, loop, bgm bool) (d2int...
    method SetVolumes (line 121) | func (eap *AudioProvider) SetVolumes(bgmVolume, sfxVolume float64) {
    method createSoundEffect (line 127) | func (eap *AudioProvider) createSoundEffect(sfx string, context *audio...

FILE: d2core/d2audio/ebiten/ebiten_sound_effect.go
  type panStream (line 11) | type panStream struct
    method Read (line 28) | func (s *panStream) Read(p []byte) (n int, err error) {
  constant bitsPerByte (line 18) | bitsPerByte = 8
  function newPanStreamFromReader (line 21) | func newPanStreamFromReader(src io.ReadSeeker) *panStream {
  type SoundEffect (line 54) | type SoundEffect struct
    method SetPan (line 61) | func (v *SoundEffect) SetPan(pan float64) {
    method SetVolume (line 68) | func (v *SoundEffect) SetVolume(volume float64) {
    method IsPlaying (line 73) | func (v *SoundEffect) IsPlaying() bool {
    method Play (line 78) | func (v *SoundEffect) Play() {
    method Stop (line 89) | func (v *SoundEffect) Stop() {

FILE: d2core/d2audio/sound_engine.go
  type envState (line 16) | type envState
  constant logPrefix (line 19) | logPrefix = "Sound Engine"
  constant envAttack (line 23) | envAttack  = 0
  constant envSustain (line 24) | envSustain = 1
  constant envRelease (line 25) | envRelease = 2
  constant envStopped (line 26) | envStopped = 3
  constant volMax (line 29) | volMax float64 = 255
  constant originalFPS (line 30) | originalFPS float64 = 25
  type Sound (line 33) | type Sound struct
    method update (line 45) | func (s *Sound) update(elapsed float64) {
    method SetPan (line 71) | func (s *Sound) SetPan(pan float64) {
    method Play (line 76) | func (s *Sound) Play() {
    method Stop (line 94) | func (s *Sound) Stop() {
    method String (line 108) | func (s *Sound) String() string {
  type SoundEngine (line 113) | type SoundEngine struct
    method Advance (line 161) | func (s *SoundEngine) Advance(elapsed float64) {
    method UnbindTerminalCommands (line 186) | func (s *SoundEngine) UnbindTerminalCommands(term d2interface.Terminal...
    method Reset (line 191) | func (s *SoundEngine) Reset() {
    method PlaySoundID (line 201) | func (s *SoundEngine) PlaySoundID(id int) *Sound {
    method PlaySoundHandle (line 234) | func (s *SoundEngine) PlaySoundHandle(handle string) *Sound {
    method commandPlaySoundID (line 239) | func (s *SoundEngine) commandPlaySoundID(args []string) error {
    method commandPlaySound (line 250) | func (s *SoundEngine) commandPlaySound(args []string) error {
    method commandActiveSounds (line 256) | func (s *SoundEngine) commandActiveSounds([]string) error {
    method commandKillSounds (line 263) | func (s *SoundEngine) commandKillSounds([]string) error {
  function NewSoundEngine (line 124) | func NewSoundEngine(provider d2interface.AudioProvider,

FILE: d2core/d2audio/sound_environment.go
  constant assumedFPS (line 9) | assumedFPS = 25
  type SoundEnvironment (line 12) | type SoundEnvironment struct
    method SetEnv (line 32) | func (s *SoundEnvironment) SetEnv(environmentIdx int) {
    method Advance (line 57) | func (s *SoundEnvironment) Advance(elapsed float64) {
  function NewSoundEnvironment (line 21) | func NewSoundEnvironment(soundEngine *SoundEngine) SoundEnvironment {

FILE: d2core/d2config/d2config.go
  type Configuration (line 10) | type Configuration struct
    method Save (line 25) | func (c *Configuration) Save() error {
    method Dir (line 49) | func (c *Configuration) Dir() string {
    method Base (line 54) | func (c *Configuration) Base() string {
    method Path (line 59) | func (c *Configuration) Path() string {
    method SetPath (line 64) | func (c *Configuration) SetPath(p string) {

FILE: d2core/d2config/default_directories.go
  constant od2ConfigDirName (line 9) | od2ConfigDirName  = "OpenDiablo2"
  constant od2ConfigFileName (line 10) | od2ConfigFileName = "config.json"
  function DefaultConfigPath (line 14) | func DefaultConfigPath() string {
  function LocalConfigPath (line 23) | func LocalConfigPath() string {

FILE: d2core/d2config/defaults.go
  function DefaultConfig (line 10) | func DefaultConfig() *Configuration {

FILE: d2core/d2gui/box.go
  constant boxSpriteHeight (line 12) | boxSpriteHeight = 15 - 5
  constant boxSpriteWidth (line 13) | boxSpriteWidth  = 14 - 2
  constant boxBorderSpriteLeftBorderOffset (line 15) | boxBorderSpriteLeftBorderOffset       = 4
  constant boxBorderSpriteRightBorderOffset (line 16) | boxBorderSpriteRightBorderOffset      = 7
  constant boxBorderSpriteTopBorderSectionOffset (line 17) | boxBorderSpriteTopBorderSectionOffset = 5
  constant minimumAllowedSectionSize (line 19) | minimumAllowedSectionSize    = 14
  constant sectionHeightPercentageOfBox (line 20) | sectionHeightPercentageOfBox = 0.12
  constant boxBackgroundColor (line 21) | boxBackgroundColor           = 0x000000d0
  constant boxCornerTopLeft (line 25) | boxCornerTopLeft = iota
  constant boxCornerTopRight (line 26) | boxCornerTopRight
  constant boxTopHorizontalEdge1 (line 27) | boxTopHorizontalEdge1
  constant boxTopHorizontalEdge2 (line 28) | boxTopHorizontalEdge2
  constant boxTopHorizontalEdge3 (line 29) | boxTopHorizontalEdge3
  constant boxTopHorizontalEdge4 (line 30) | boxTopHorizontalEdge4
  constant boxTopHorizontalEdge5 (line 31) | boxTopHorizontalEdge5
  constant boxTopHorizontalEdge6 (line 32) | boxTopHorizontalEdge6
  constant boxCornerBottomLeft (line 33) | boxCornerBottomLeft
  constant boxCornerBottomRight (line 34) | boxCornerBottomRight
  constant boxSideEdge1 (line 35) | boxSideEdge1
  constant boxSideEdge2 (line 36) | boxSideEdge2
  constant boxSideEdge3 (line 37) | boxSideEdge3
  constant boxSideEdge4 (line 38) | boxSideEdge4
  constant boxSideEdge5 (line 39) | boxSideEdge5
  constant boxSideEdge6 (line 40) | boxSideEdge6
  constant boxBottomHorizontalEdge1 (line 41) | boxBottomHorizontalEdge1
  constant boxBottomHorizontalEdge2 (line 42) | boxBottomHorizontalEdge2
  constant boxBottomHorizontalEdge3 (line 43) | boxBottomHorizontalEdge3
  constant boxBottomHorizontalEdge4 (line 44) | boxBottomHorizontalEdge4
  constant boxBottomHorizontalEdge5 (line 45) | boxBottomHorizontalEdge5
  constant boxBottomHorizontalEdge6 (line 46) | boxBottomHorizontalEdge6
  type Box (line 51) | type Box struct
    method GetLayout (line 102) | func (box *Box) GetLayout() *Layout {
    method Toggle (line 107) | func (box *Box) Toggle() {
    method SetPadding (line 116) | func (box *Box) SetPadding(paddingX, paddingY int) {
    method Open (line 122) | func (box *Box) Open() {
    method Close (line 127) | func (box *Box) Close() {
    method IsOpen (line 132) | func (box *Box) IsOpen() bool {
    method setupTopBorder (line 136) | func (box *Box) setupTopBorder(offsetY int) {
    method setupBottomBorder (line 178) | func (box *Box) setupBottomBorder(offsetY int) {
    method setupLeftBorder (line 221) | func (box *Box) setupLeftBorder() {
    method setupRightBorder (line 260) | func (box *Box) setupRightBorder() {
    method setupCorners (line 300) | func (box *Box) setupCorners() {
    method SetOptions (line 335) | func (box *Box) SetOptions(options []*LabelButton) {
    method setupTitle (line 339) | func (box *Box) setupTitle(sectionHeight int) error {
    method setupOptions (line 390) | func (box *Box) setupOptions(sectionHeight int) error {
    method Load (line 441) | func (box *Box) Load() error {
    method OnMouseButtonDown (line 484) | func (box *Box) OnMouseButtonDown(event d2interface.MouseEvent) bool {
    method Render (line 496) | func (box *Box) Render(target d2interface.Surface) error {
    method IsInRect (line 513) | func (box *Box) IsInRect(px, py int) bool {
  function NewBox (line 72) | func NewBox(

FILE: d2core/d2gui/button.go
  type buttonState (line 7) | type buttonState
  constant buttonStateDefault (line 10) | buttonStateDefault buttonState = iota
  constant buttonStatePressed (line 11) | buttonStatePressed
  constant buttonStatePressedToggled (line 12) | buttonStatePressedToggled
  constant grey (line 16) | grey = 0x404040ff
  type Button (line 20) | type Button struct
    method onMouseButtonDown (line 29) | func (b *Button) onMouseButtonDown(_ d2interface.MouseEvent) bool {
    method onMouseButtonUp (line 35) | func (b *Button) onMouseButtonUp(_ d2interface.MouseEvent) bool {
    method onMouseLeave (line 41) | func (b *Button) onMouseLeave(_ d2interface.MouseMoveEvent) bool {
    method render (line 47) | func (b *Button) render(target d2interface.Surface) {
    method getSize (line 51) | func (b *Button) getSize() (width, height int) {

FILE: d2core/d2gui/common.go
  function renderSegmented (line 8) | func renderSegmented(animation d2interface.Animation, segmentsX, segment...
  function half (line 35) | func half(n int) int {

FILE: d2core/d2gui/gui_manager.go
  constant logPrefix (line 14) | logPrefix = "GUI Manager"
  type GuiManager (line 18) | type GuiManager struct
    method SetLayout (line 64) | func (m *GuiManager) SetLayout(layout *Layout) {
    method OnMouseButtonDown (line 72) | func (m *GuiManager) OnMouseButtonDown(event d2interface.MouseEvent) b...
    method OnMouseButtonUp (line 81) | func (m *GuiManager) OnMouseButtonUp(event d2interface.MouseEvent) bool {
    method OnMouseMove (line 90) | func (m *GuiManager) OnMouseMove(event d2interface.MouseMoveEvent) bool {
    method Render (line 102) | func (m *GuiManager) Render(target d2interface.Surface) error {
    method renderLoadScreen (line 117) | func (m *GuiManager) renderLoadScreen(target d2interface.Surface) {
    method renderCursor (line 136) | func (m *GuiManager) renderCursor(target d2interface.Surface) {
    method Advance (line 152) | func (m *GuiManager) Advance(elapsed float64) error {
    method ShowLoadScreen (line 163) | func (m *GuiManager) ShowLoadScreen(progress float64) {
    method HideLoadScreen (line 179) | func (m *GuiManager) HideLoadScreen() {
    method ShowCursor (line 184) | func (m *GuiManager) ShowCursor() {
    method HideCursor (line 189) | func (m *GuiManager) HideCursor() {
    method clear (line 193) | func (m *GuiManager) clear() {
  function CreateGuiManager (line 32) | func CreateGuiManager(asset *d2asset.AssetManager, l d2util.LogLevel, in...

FILE: d2core/d2gui/label.go
  constant ColorWhite (line 14) | ColorWhite = 0xffffffff
  constant ColorRed (line 15) | ColorRed   = 0xdb3f3dff
  constant ColorGreen (line 16) | ColorGreen = 0x00d000ff
  constant ColorBlue (line 17) | ColorBlue  = 0x5450d1ff
  constant ColorBrown (line 18) | ColorBrown = 0xa1925dff
  constant ColorGrey (line 19) | ColorGrey  = 0x555555ff
  type Label (line 23) | type Label struct
    method SetHoverColor (line 57) | func (l *Label) SetHoverColor(col color.RGBA) {
    method SetIsBlinking (line 62) | func (l *Label) SetIsBlinking(isBlinking bool) {
    method SetIsHovered (line 67) | func (l *Label) SetIsHovered(isHovered bool) error {
    method render (line 73) | func (l *Label) render(target d2interface.Surface) {
    method getSize (line 86) | func (l *Label) getSize() (width, height int) {
    method GetText (line 91) | func (l *Label) GetText() string {
    method SetColor (line 96) | func (l *Label) SetColor(col color.RGBA) error {
    method SetText (line 102) | func (l *Label) SetText(text string) error {
    method setText (line 110) | func (l *Label) setText(text string) error {
  function createLabel (line 38) | func createLabel(renderer d2interface.Renderer, text string, font *d2fon...

FILE: d2core/d2gui/label_button.go
  type LabelButton (line 13) | type LabelButton struct
    method IsInRect (line 44) | func (lb *LabelButton) IsInRect(px, py int) bool {
    method Load (line 60) | func (lb *LabelButton) Load(renderer d2interface.Renderer, asset *d2as...
    method SetLabel (line 84) | func (lb *LabelButton) SetLabel(val string) {
    method SetHoverColor (line 89) | func (lb *LabelButton) SetHoverColor(col color.RGBA) {
    method SetCanHover (line 94) | func (lb *LabelButton) SetCanHover(val bool) {
    method IsHovered (line 99) | func (lb *LabelButton) IsHovered() bool {
    method GetLayout (line 104) | func (lb *LabelButton) GetLayout() *Layout {
  function NewLabelButton (line 26) | func NewLabelButton(x, y int, text string, col color.RGBA, l d2util.LogL...

FILE: d2core/d2gui/layout.go
  constant layoutDebug (line 14) | layoutDebug = false
  constant white (line 17) | white   = 0xffffff_ff
  constant magenta (line 18) | magenta = 0xff00ff_ff
  constant grey2 (line 19) | grey2   = 0x808080_ff
  constant green (line 20) | green   = 0x0000ff_ff
  constant yellow (line 21) | yellow  = 0xffff00_ff
  type VerticalAlign (line 25) | type VerticalAlign
  constant VerticalAlignTop (line 29) | VerticalAlignTop VerticalAlign = iota
  constant VerticalAlignMiddle (line 30) | VerticalAlignMiddle
Condensed preview — 649 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,067K chars).
[
  {
    "path": ".circleci/config.yml",
    "chars": 846,
    "preview": "# Golang CircleCI 2.0 configuration file\n#\n# Check https://circleci.com/docs/2.0/language-go/ for more details\nversion: "
  },
  {
    "path": ".editorconfig",
    "chars": 112,
    "preview": "root = true\n[*]\nend_of_line = lf\ninsert_final_newline = true\ncharset = utf-8\nindent_style = tab\nindent_size = 4\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 63,
    "preview": "# These are supported funding model platforms\n\npatreon: essial\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 597,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n**Describe the bug**\nA clear and concise descriptio"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 560,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem? "
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 118,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/auto-author-assign.yml",
    "chars": 299,
    "preview": "name: 'Auto Author Assign'\n\non:\n    pull_request_target:\n        types: [opened, reopened]\n\njobs:\n    assign-author:\n   "
  },
  {
    "path": ".gitignore",
    "chars": 185,
    "preview": "**/*__debug_bin\n.vscode/**/*\n!.vscode/extensions.json\n**/Client.exe\n**/Client\n.idea/**/*\n.vs/**/*\n/OpenDiablo2.exe\n/Open"
  },
  {
    "path": ".golangci.yml",
    "chars": 1916,
    "preview": "---\nlinters-settings:\n  dupl:\n    threshold: 100\n  funlen:\n    lines: 100\n    statements: 50\n  goconst:\n    min-len: 2\n "
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 97,
    "preview": "{\r\n    \"recommendations\": [\r\n        \"golang.go\",\r\n        \"soren.go-coverage-viewer\"\r\n    ]\r\n}\r\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3352,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CONTRIBUTORS",
    "chars": 475,
    "preview": "* OPEN DIABLO 2\nTim \"essial\" Sarbin\nndechiara\nmewmew\ngrazz\nErexo\nZiemas\nliberodark\ncardoso\nMirey\nLectem\nwtfblub\nq3cpma\na"
  },
  {
    "path": "LICENSE",
    "chars": 35149,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "README.md",
    "chars": 4113,
    "preview": "# NOTE \n<image align=\"left\" src=\"https://user-images.githubusercontent.com/242652/138285004-b27d55b3-163b-4fe3-a8ff-6c34"
  },
  {
    "path": "build.sh",
    "chars": 4540,
    "preview": "#!/bin/bash\n#\n# About: Build OpenDiablo 2 automatically\n# Author: liberodark\n# License: GNU GPLv3\n\nversion=\"0.0.8\"\ngo_ve"
  },
  {
    "path": "d2app/app.go",
    "chars": 17682,
    "preview": "// Package d2app contains the OpenDiablo2 application shell\npackage d2app\n\nimport (\n\t\"bytes\"\n\t\"container/ring\"\n\t\"encodin"
  },
  {
    "path": "d2app/capture_state.go",
    "chars": 122,
    "preview": "package d2app\n\ntype captureState int\n\nconst (\n\tcaptureStateNone captureState = iota\n\tcaptureStateFrame\n\tcaptureStateGif\n"
  },
  {
    "path": "d2app/console_commands.go",
    "chars": 3383,
    "preview": "package d2app\n\nimport (\n\t\"os\"\n\t\"runtime/pprof\"\n\t\"strconv\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2game/d2gamescreen\"\n)\n\n"
  },
  {
    "path": "d2app/initialization.go",
    "chars": 5124,
    "preview": "package d2app\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2loader/asset/types\"\n\n\t\""
  },
  {
    "path": "d2common/d2cache/cache.go",
    "chars": 2623,
    "preview": "package d2cache\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"sync\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface\"\n)\n\nvar _ "
  },
  {
    "path": "d2common/d2cache/cache_test.go",
    "chars": 2403,
    "preview": "package d2cache\n\nimport (\n\t\"testing\"\n)\n\nfunc TestCacheInsert(t *testing.T) {\n\tcache := CreateCache(1)\n\tinsertError := ca"
  },
  {
    "path": "d2common/d2cache/doc.go",
    "chars": 77,
    "preview": "// Package d2cache provides a generic caching implementation\npackage d2cache\n"
  },
  {
    "path": "d2common/d2calculation/calcstring.go",
    "chars": 370,
    "preview": "package d2calculation\n\n// CalcString is a type of string often used in datafiles to specify\n// a value that is calculate"
  },
  {
    "path": "d2common/d2calculation/calculation.go",
    "chars": 2521,
    "preview": "// Package d2calculation contains code for calculation nodes.\npackage d2calculation\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\n// Ca"
  },
  {
    "path": "d2common/d2calculation/d2lexer/lexer.go",
    "chars": 3701,
    "preview": "// Package d2lexer contains the code for tokenizing calculation strings.\npackage d2lexer\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n"
  },
  {
    "path": "d2common/d2calculation/d2lexer/lexer_test.go",
    "chars": 3191,
    "preview": "package d2lexer\n\nimport (\n\t\"testing\"\n)\n\nfunc TestName(t *testing.T) {\n\tlexer := New([]byte(\"correct horse battery staple"
  },
  {
    "path": "d2common/d2calculation/d2parser/d2parser.go",
    "chars": 88,
    "preview": "// Package d2parser contains the code for parsing calculation strings.\npackage d2parser\n"
  },
  {
    "path": "d2common/d2calculation/d2parser/operations.go",
    "chars": 2731,
    "preview": "package d2parser\n\nimport (\n\t\"math\"\n\t\"math/rand\"\n)\n\ntype binaryOperation struct {\n\tOperator          string\n\tPrecedence  "
  },
  {
    "path": "d2common/d2calculation/d2parser/parser.go",
    "chars": 6326,
    "preview": "package d2parser\n\nimport (\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation\"\n\t\""
  },
  {
    "path": "d2common/d2calculation/d2parser/parser_test.go",
    "chars": 5565,
    "preview": "package d2parser\n\nimport (\n\t\"math\"\n\t\"math/rand\"\n\t\"testing\"\n)\n\nfunc TestEmptyInput(t *testing.T) {\n\tparser := New()\n\n\ttab"
  },
  {
    "path": "d2common/d2data/d2compression/huffman.go",
    "chars": 15846,
    "preview": "// Package d2compression is used for decompressing WAV files.\npackage d2compression\n\n// MpqHuffman.go based on the origi"
  },
  {
    "path": "d2common/d2data/d2compression/wav.go",
    "chars": 3250,
    "preview": "package d2compression\n\nimport (\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n)\n\n// WavDecompress decompres"
  },
  {
    "path": "d2common/d2data/d2video/binkdecoder.go",
    "chars": 5419,
    "preview": "package d2video\n\nimport (\n\t\"errors\"\n\t\"log\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n)\n\n// BinkVideoMo"
  },
  {
    "path": "d2common/d2data/d2video/doc.go",
    "chars": 65,
    "preview": "// Package d2video provides a bink video decoder\npackage d2video\n"
  },
  {
    "path": "d2common/d2data/doc.go",
    "chars": 153,
    "preview": "// Package d2data provides file compression utilities, video decoders, and file loaders\n// for the txt files inside of d"
  },
  {
    "path": "d2common/d2datautils/bitmuncher.go",
    "chars": 3278,
    "preview": "package d2datautils\n\n// BitMuncher is used for parsing files that are not byte-aligned such as the DCC files.\ntype BitMu"
  },
  {
    "path": "d2common/d2datautils/bitmuncher_test.go",
    "chars": 2800,
    "preview": "package d2datautils\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar testData = []byte{33, 23, 4, 33, "
  },
  {
    "path": "d2common/d2datautils/bitstream.go",
    "chars": 1609,
    "preview": "package d2datautils\n\nimport (\n\t\"log\"\n)\n\nconst (\n\tmaxBits     = 16\n\tbitsPerByte = 8\n)\n\n// BitStream is a utility class fo"
  },
  {
    "path": "d2common/d2datautils/bitstream_test.go",
    "chars": 706,
    "preview": "package d2datautils\n\nimport (\n\t\"testing\"\n)\n\nfunc TestBitStreamBits(t *testing.T) {\n\tdata := []byte{0xAA}\n\tbitStream := C"
  },
  {
    "path": "d2common/d2datautils/doc.go",
    "chars": 202,
    "preview": "// Package d2datautils is a utility package that provides helper functions/classes\n// for parsing the original diablo2 f"
  },
  {
    "path": "d2common/d2datautils/stream_reader.go",
    "chars": 3331,
    "preview": "package d2datautils\n\nimport (\n\t\"io\"\n)\n\nconst (\n\tbytesPerint16 = 2\n\tbytesPerint32 = 4\n\tbytesPerint64 = 8\n)\n\n// StreamRead"
  },
  {
    "path": "d2common/d2datautils/stream_reader_test.go",
    "chars": 1939,
    "preview": "package d2datautils\n\nimport (\n\t\"testing\"\n)\n\nfunc TestStreamReaderByte(t *testing.T) {\n\tdata := []byte{0x78, 0x56, 0x34, "
  },
  {
    "path": "d2common/d2datautils/stream_writer.go",
    "chars": 3071,
    "preview": "package d2datautils\n\nimport (\n\t\"bytes\"\n\t\"log\"\n)\n\n// StreamWriter allows you to create a byte array by streaming in write"
  },
  {
    "path": "d2common/d2datautils/stream_writer_test.go",
    "chars": 2380,
    "preview": "package d2datautils\n\nimport (\n\t\"testing\"\n)\n\nfunc TestStreamWriterBits(t *testing.T) {\n\tsr := CreateStreamWriter()\n\tdata "
  },
  {
    "path": "d2common/d2enum/animation_frame.go",
    "chars": 265,
    "preview": "package d2enum\n\n// AnimationFrame represents a single frame of animation.\ntype AnimationFrame int\n\n// AnimationFrame typ"
  },
  {
    "path": "d2common/d2enum/animation_frame_direction.go",
    "chars": 296,
    "preview": "package d2enum\n\n// AnimationFrameDirection enumerates animation frame directions used in d2datadict.MonsterSequenceFrame"
  },
  {
    "path": "d2common/d2enum/animation_frame_event.go",
    "chars": 251,
    "preview": "package d2enum\n\n// AnimationFrameEvent enumerates events used in d2datadict.MonsterSequenceFrame\ntype AnimationFrameEven"
  },
  {
    "path": "d2common/d2enum/composite_type.go",
    "chars": 1882,
    "preview": "package d2enum\n\nconst (\n\tunknown = \"Unknown\"\n)\n\n//go:generate stringer -linecomment -type CompositeType -output composit"
  },
  {
    "path": "d2common/d2enum/composite_type_string.go",
    "chars": 1302,
    "preview": "// Code generated by \"stringer -linecomment -type CompositeType -output composite_type_string.go\"; DO NOT EDIT.\n\npackage"
  },
  {
    "path": "d2common/d2enum/difficulty.go",
    "chars": 327,
    "preview": "package d2enum\n\n// DifficultyType is an enum for the possible difficulties\ntype DifficultyType int\n\nconst (\n\t// Difficul"
  },
  {
    "path": "d2common/d2enum/doc.go",
    "chars": 100,
    "preview": "// Package d2enum provides enumerations used throughout\n// the OpenDiablo2 codebase.\npackage d2enum\n"
  },
  {
    "path": "d2common/d2enum/draw_effect.go",
    "chars": 2405,
    "preview": "package d2enum\n\n// DrawEffect is a draw effect\ntype DrawEffect int\n\n// Names courtesy of Necrolis\nconst (\n\t// DrawEffect"
  },
  {
    "path": "d2common/d2enum/encoding_type.go",
    "chars": 145,
    "preview": "package d2enum\n\n// EncodingType represents a encoding type\ntype EncodingType int\n\n// Encoding types\nconst (\n\tEncodeDefau"
  },
  {
    "path": "d2common/d2enum/equipped_slot.go",
    "chars": 362,
    "preview": "package d2enum\n\n// EquippedSlot represents the type of equipment slot\ntype EquippedSlot int\n\n// Equipped slot ID's\nconst"
  },
  {
    "path": "d2common/d2enum/filter.go",
    "chars": 351,
    "preview": "package d2enum\n\n// Filter represents the type of texture filter to be used when an image is magnified or minified.\ntype "
  },
  {
    "path": "d2common/d2enum/game_event.go",
    "chars": 1693,
    "preview": "package d2enum\n\n// GameEvent represents an envent in the game engine\ntype GameEvent int\n\n// Game events\nconst (\n\t// Togg"
  },
  {
    "path": "d2common/d2enum/hero.go",
    "chars": 1325,
    "preview": "package d2enum\n\nimport \"log\"\n\n//go:generate stringer -linecomment -type Hero\n//go:generate string2enum -samepkg -linecom"
  },
  {
    "path": "d2common/d2enum/hero_stance.go",
    "chars": 231,
    "preview": "package d2enum\n\n// HeroStance used to render hero stance\ntype HeroStance int\n\n// HeroStance types\nconst (\n\tHeroStanceIdl"
  },
  {
    "path": "d2common/d2enum/hero_string.go",
    "chars": 798,
    "preview": "// Code generated by \"stringer -linecomment -type Hero\"; DO NOT EDIT.\n\npackage d2enum\n\nimport \"strconv\"\n\nfunc _() {\n\t// "
  },
  {
    "path": "d2common/d2enum/hero_string2enum.go",
    "chars": 722,
    "preview": "// Code generated by \"string2enum -samepkg -linecomment -type Hero\"; DO NOT EDIT.\n\npackage d2enum\n\nimport \"fmt\"\n\n// Hero"
  },
  {
    "path": "d2common/d2enum/input_button.go",
    "chars": 883,
    "preview": "package d2enum\n\n// MouseButton represents a traditional 3-button mouse\ntype MouseButton int\n\nconst (\n\t// MouseButtonLeft"
  },
  {
    "path": "d2common/d2enum/input_key.go",
    "chars": 1408,
    "preview": "package d2enum\n\n// Key represents button on a traditional keyboard.\ntype Key int\n\n// Input keys\nconst (\n\tKey0 Key = iota"
  },
  {
    "path": "d2common/d2enum/input_priority.go",
    "chars": 152,
    "preview": "package d2enum\n\n// Priority of the event handler\ntype Priority int\n\n// Priorities\nconst (\n\tPriorityLow Priority = iota\n\t"
  },
  {
    "path": "d2common/d2enum/inventory_item_type.go",
    "chars": 228,
    "preview": "package d2enum\n\n// InventoryItemType represents a inventory item type\ntype InventoryItemType int\n\n// Inventry item types"
  },
  {
    "path": "d2common/d2enum/item_affix_type.go",
    "chars": 348,
    "preview": "package d2enum\n\n// ItemAffixSuperType represents a item affix super type\ntype ItemAffixSuperType int\n\n// Super types\ncon"
  },
  {
    "path": "d2common/d2enum/item_armor_class.go",
    "chars": 232,
    "preview": "package d2enum\n\n// ArmorClass is a 3-character token for the armor. It's used for speed calculations.\ntype ArmorClass st"
  },
  {
    "path": "d2common/d2enum/item_event_functions.go",
    "chars": 2491,
    "preview": "package d2enum\n\n// ItemEventFuncID represents a item event function\ntype ItemEventFuncID int\n\n// Item event functions\nco"
  },
  {
    "path": "d2common/d2enum/item_events.go",
    "chars": 1876,
    "preview": "package d2enum\n\n// ItemEventType  used in ItemStatCost\ntype ItemEventType int\n\n// Item event types\nconst (\n\tItemEventNon"
  },
  {
    "path": "d2common/d2enum/item_quality.go",
    "chars": 223,
    "preview": "package d2enum\n\n// ItemQuality is used for enumerating item quality values\ntype ItemQuality int\n\n// Item qualities\nconst"
  },
  {
    "path": "d2common/d2enum/level_generation_types.go",
    "chars": 396,
    "preview": "package d2enum\n\n// from levels.txt, field `DrlgType`\n// https://d2mods.info/forum/kb/viewarticle?a=301\n\n// LevelGenerati"
  },
  {
    "path": "d2common/d2enum/level_teleport_flags.go",
    "chars": 451,
    "preview": "package d2enum\n\n// from levels.txt, field `Teleport`\n// https://d2mods.info/forum/kb/viewarticle?a=301\n\n// TeleportFlag "
  },
  {
    "path": "d2common/d2enum/monster_alignment_type.go",
    "chars": 507,
    "preview": "package d2enum\n\n// MonsterAlignmentType determines the hostility of the monster towards players\ntype MonsterAlignmentTyp"
  },
  {
    "path": "d2common/d2enum/monster_animation_mode.go",
    "chars": 1288,
    "preview": "package d2enum\n\n//go:generate stringer -linecomment -type MonsterAnimationMode -output monster_animation_mode_string.go\n"
  },
  {
    "path": "d2common/d2enum/monster_animation_mode_string.go",
    "chars": 1422,
    "preview": "// Code generated by \"stringer -linecomment -type MonsterAnimationMode -output monster_animation_mode_string.go\"; DO NOT"
  },
  {
    "path": "d2common/d2enum/monster_combat_type.go",
    "chars": 309,
    "preview": "package d2enum\n\n// MonsterCombatType is used for setting the monster as melee or ranged\ntype MonsterCombatType int\n\ncons"
  },
  {
    "path": "d2common/d2enum/monumod_const_index.go",
    "chars": 1152,
    "preview": "package d2enum\n\n// MonUModConstIndex is used as an index into d2datadict.MonsterUniqueModifierConstants\ntype MonUModCons"
  },
  {
    "path": "d2common/d2enum/npc_action_type.go",
    "chars": 302,
    "preview": "package d2enum\n\n// NPCActionType determines composite mode animations for NPC's as they move around\ntype NPCActionType i"
  },
  {
    "path": "d2common/d2enum/numeric_labels.go",
    "chars": 2488,
    "preview": "package d2enum\n\n// there are labels for \"numeric labels (see AssetManager.TranslateString)\nconst (\n\tRepairAll = iota\n\t_\n"
  },
  {
    "path": "d2common/d2enum/object_animation_mode.go",
    "chars": 865,
    "preview": "package d2enum\n\n//go:generate stringer -linecomment -type ObjectAnimationMode -output object_animation_mode_string.go\n//"
  },
  {
    "path": "d2common/d2enum/object_animation_mode_string.go",
    "chars": 1070,
    "preview": "// Code generated by \"stringer -linecomment -type ObjectAnimationMode -output object_animation_mode_string.go\"; DO NOT E"
  },
  {
    "path": "d2common/d2enum/object_animation_mode_string2enum.go",
    "chars": 923,
    "preview": "// Code generated by \"string2enum -samepkg -linecomment -type ObjectAnimationMode -output object_animation_mode_string2e"
  },
  {
    "path": "d2common/d2enum/object_type.go",
    "chars": 175,
    "preview": "package d2enum\n\n// ObjectType is the type of an object\ntype ObjectType int\n\n// Object types\nconst (\n\tObjectTypePlayer Ob"
  },
  {
    "path": "d2common/d2enum/operator_type.go",
    "chars": 2908,
    "preview": "package d2enum\n\n// OperatorType is used for calculating dynamic property values\ntype OperatorType int // for dynamic pro"
  },
  {
    "path": "d2common/d2enum/party_buttons.go",
    "chars": 209,
    "preview": "package d2enum\n\n// Frames of party Buttons\nconst (\n\tPartyButtonListeningFrame = iota * 4\n\tPartyButtonRelationshipsFrame\n"
  },
  {
    "path": "d2common/d2enum/pet_icon_type.go",
    "chars": 324,
    "preview": "package d2enum\n\n// PetIconType determines the pet icon type\ntype PetIconType int\n\n// Pet icon types\n// The information h"
  },
  {
    "path": "d2common/d2enum/player_animation_mode.go",
    "chars": 1656,
    "preview": "package d2enum\n\n//go:generate stringer -linecomment -type PlayerAnimationMode -output player_animation_mode_string.go\n\n/"
  },
  {
    "path": "d2common/d2enum/player_animation_mode_string.go",
    "chars": 1571,
    "preview": "// Code generated by \"stringer -linecomment -type PlayerAnimationMode -output player_animation_mode_string.go\"; DO NOT E"
  },
  {
    "path": "d2common/d2enum/players_relationships.go",
    "chars": 421,
    "preview": "package d2enum\n\n// PlayersRelationships represents players relationships\ntype PlayersRelationships int\n\n// Players relat"
  },
  {
    "path": "d2common/d2enum/quests.go",
    "chars": 1488,
    "preview": "package d2enum\n\nconst (\n\t// NormalActQuestsNumber is number of quests in standard act\n\tNormalActQuestsNumber = 6\n\t// Hal"
  },
  {
    "path": "d2common/d2enum/readme.md",
    "chars": 518,
    "preview": "# OpenDiablo2 Enums\nItems in this folder are compiled with two programs. You can obtain them\nby running the following:\n`"
  },
  {
    "path": "d2common/d2enum/region_id.go",
    "chars": 827,
    "preview": "package d2enum\n\n// RegionIdType represents a region ID\ntype RegionIdType int //nolint:golint,stylecheck // many changed "
  },
  {
    "path": "d2common/d2enum/region_layer.go",
    "chars": 211,
    "preview": "package d2enum\n\n// RegionLayerType represents a region layer\ntype RegionLayerType int\n\n// Region layer types\nconst (\n\tRe"
  },
  {
    "path": "d2common/d2enum/render_type.go",
    "chars": 151,
    "preview": "package d2enum\n\n// RenderType defines the type of rendering engine to use\ntype RenderType int\n\n// Render types\nconst (\n\t"
  },
  {
    "path": "d2common/d2enum/skill_class.go",
    "chars": 1937,
    "preview": "package d2enum\n\nimport \"log\"\n\n// SkillClass represents the skills for a character class\ntype SkillClass int\n\n// Skill cl"
  },
  {
    "path": "d2common/d2enum/terminal_category.go",
    "chars": 233,
    "preview": "package d2enum\n\n// TermCategory applies styles to the lines in the  Terminal\ntype TermCategory int\n\n// Terminal Category"
  },
  {
    "path": "d2common/d2enum/tile.go",
    "chars": 2975,
    "preview": "package d2enum\n\n// TileType represents a tile type\ntype TileType byte\n\n// Tile types\nconst (\n\tTileFloor TileType = iota\n"
  },
  {
    "path": "d2common/d2enum/weapon_class.go",
    "chars": 2181,
    "preview": "package d2enum\n\n//go:generate stringer -linecomment -type WeaponClass -output weapon_class_string.go\n//go:generate strin"
  },
  {
    "path": "d2common/d2enum/weapon_class_string.go",
    "chars": 1248,
    "preview": "// Code generated by \"stringer -linecomment -type WeaponClass -output weapon_class_string.go\"; DO NOT EDIT.\n\npackage d2e"
  },
  {
    "path": "d2common/d2enum/weapon_class_string2enum.go",
    "chars": 953,
    "preview": "// Code generated by \"string2enum -samepkg -linecomment -type WeaponClass -output weapon_class_string2enum.go\"; DO NOT E"
  },
  {
    "path": "d2common/d2fileformats/d2animdata/animdata.go",
    "chars": 6832,
    "preview": "package d2animdata\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n)\n\n"
  },
  {
    "path": "d2common/d2fileformats/d2animdata/animdata_test.go",
    "chars": 5280,
    "preview": "package d2animdata\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestLoad(t *testing.T) {\n\ttestFile, fileErr := os.Open(\"tes"
  },
  {
    "path": "d2common/d2fileformats/d2animdata/block.go",
    "chars": 98,
    "preview": "package d2animdata\n\ntype block struct {\n\trecordCount uint32\n\trecords     []*AnimationDataRecord\n}\n"
  },
  {
    "path": "d2common/d2fileformats/d2animdata/doc.go",
    "chars": 1049,
    "preview": "// Package d2animdata provides a file parser for AnimData files. AnimData files have the '.d2'\n// file extension, but we"
  },
  {
    "path": "d2common/d2fileformats/d2animdata/events.go",
    "chars": 283,
    "preview": "package d2animdata\n\n// AnimationEvent represents an event that can happen on a frame of animation\ntype AnimationEvent by"
  },
  {
    "path": "d2common/d2fileformats/d2animdata/hash.go",
    "chars": 290,
    "preview": "package d2animdata\n\nimport \"strings\"\n\ntype hashTable [numBlocks]byte\n\nfunc hashName(name string) byte {\n\thashBytes := []"
  },
  {
    "path": "d2common/d2fileformats/d2animdata/record.go",
    "chars": 1630,
    "preview": "package d2animdata\n\n// AnimationDataRecord represents a single record from the AnimData.d2 file\ntype AnimationDataRecord"
  },
  {
    "path": "d2common/d2fileformats/d2cof/cof.go",
    "chars": 5766,
    "preview": "package d2cof\n\nimport (\n\t\"strings\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n\t\"github.com/OpenDiablo2/"
  },
  {
    "path": "d2common/d2fileformats/d2cof/cof_dir_lookup.go",
    "chars": 1747,
    "preview": "package d2cof\n\ntype directionCount int\n\nconst (\n\tfour directionCount = 4 << iota\n\teight\n\tsixteen\n\tthirtyTwo\n\tsixtyFour\n)"
  },
  {
    "path": "d2common/d2fileformats/d2cof/cof_layer.go",
    "chars": 325,
    "preview": "package d2cof\n\nimport \"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum\"\n\n// CofLayer is a structure that represents a"
  },
  {
    "path": "d2common/d2fileformats/d2cof/cof_test.go",
    "chars": 522,
    "preview": "package d2cof\n\nimport \"testing\"\n\nfunc TestCOF_New(t *testing.T) {\n\tc := New()\n\n\tif c == nil {\n\t\tt.Error(\"method New crea"
  },
  {
    "path": "d2common/d2fileformats/d2cof/doc.go",
    "chars": 88,
    "preview": "// Package d2cof contains the logic for loading and processing COF files.\npackage d2cof\n"
  },
  {
    "path": "d2common/d2fileformats/d2cof/helpers.go",
    "chars": 451,
    "preview": "package d2cof\n\n// FPS returns FPS value basing on cof's speed\nfunc (c *COF) FPS() float64 {\n\tconst (\n\t\tbaseFPS      = 25"
  },
  {
    "path": "d2common/d2fileformats/d2dat/dat.go",
    "chars": 651,
    "preview": "package d2dat\n\nimport (\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface\"\n)\n\nconst (\n\t// index offset helpers\n\t"
  },
  {
    "path": "d2common/d2fileformats/d2dat/dat_color.go",
    "chars": 1575,
    "preview": "package d2dat\n\n// DATColor represents a single color in a DAT file.\ntype DATColor struct {\n\tr uint8\n\tg uint8\n\tb uint8\n\ta"
  },
  {
    "path": "d2common/d2fileformats/d2dat/dat_palette.go",
    "chars": 910,
    "preview": "package d2dat\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface\"\n)\n\nconst (\n\tnumColors = 256\n)"
  },
  {
    "path": "d2common/d2fileformats/d2dat/doc.go",
    "chars": 88,
    "preview": "// Package d2dat contains the logic for loading and processing DAT files.\npackage d2dat\n"
  },
  {
    "path": "d2common/d2fileformats/d2dc6/dc6.go",
    "chars": 5307,
    "preview": "package d2dc6\n\nimport (\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n)\n\nconst (\n\tendOfScanLine = 0x80\n\tmax"
  },
  {
    "path": "d2common/d2fileformats/d2dc6/dc6.ksy",
    "chars": 1457,
    "preview": "meta:\n  id: dc6\n  title: Diablo CEL 6\n  application: Diablo II\n  file-extension: dc6\n  license: MIT\n  ks-version: 0.7\n  "
  },
  {
    "path": "d2common/d2fileformats/d2dc6/dc6_frame.go",
    "chars": 318,
    "preview": "package d2dc6\n\n// DC6Frame represents a single frame in a DC6.\ntype DC6Frame struct {\n\tFlipped    uint32\n\tWidth      uin"
  },
  {
    "path": "d2common/d2fileformats/d2dc6/dc6_frame_header.go",
    "chars": 390,
    "preview": "package d2dc6\n\n// DC6FrameHeader represents the header of a frame in a DC6.\ntype DC6FrameHeader struct {\n\tFlipped   int3"
  },
  {
    "path": "d2common/d2fileformats/d2dc6/dc6_header.go",
    "chars": 364,
    "preview": "package d2dc6\n\n// DC6Header represents the file header of a DC6 file.\ntype DC6Header struct {\n\tVersion            int32 "
  },
  {
    "path": "d2common/d2fileformats/d2dc6/dc6_test.go",
    "chars": 1473,
    "preview": "package d2dc6\n\nimport (\n\t\"testing\"\n)\n\nfunc TestDC6New(t *testing.T) {\n\tdc6 := New()\n\n\tif dc6 == nil {\n\t\tt.Error(\"d2dc6.N"
  },
  {
    "path": "d2common/d2fileformats/d2dc6/doc.go",
    "chars": 88,
    "preview": "// Package d2dc6 contains the logic for loading and processing DC6 files.\npackage d2dc6\n"
  },
  {
    "path": "d2common/d2fileformats/d2dcc/dcc.go",
    "chars": 1926,
    "preview": "package d2dcc\n\nimport (\n\t\"errors\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n)\n\nconst dccFileSignature "
  },
  {
    "path": "d2common/d2fileformats/d2dcc/dcc_cell.go",
    "chars": 226,
    "preview": "package d2dcc\n\n// DCCCell represents a single cell in a DCC file.\ntype DCCCell struct {\n\tWidth       int\n\tHeight      in"
  },
  {
    "path": "d2common/d2fileformats/d2dcc/dcc_dir_lookup.go",
    "chars": 1797,
    "preview": "package d2dcc\n\ntype directionCount int\n\nconst (\n\tfour directionCount = 4 << iota\n\teight\n\tsixteen\n\tthirtyTwo\n\tsixtyFour\n)"
  },
  {
    "path": "d2common/d2fileformats/d2dcc/dcc_direction.go",
    "chars": 13870,
    "preview": "package d2dcc\n\nimport (\n\t\"log\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n\t\"github.com/OpenDiablo2/Open"
  },
  {
    "path": "d2common/d2fileformats/d2dcc/dcc_direction_frame.go",
    "chars": 3602,
    "preview": "package d2dcc\n\nimport (\n\t\"log\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n\t\"github.com/OpenDiablo2/Open"
  },
  {
    "path": "d2common/d2fileformats/d2dcc/dcc_pixel_buffer_entry.go",
    "chars": 185,
    "preview": "package d2dcc\n\n// DCCPixelBufferEntry represents a single entry in the pixel buffer.\ntype DCCPixelBufferEntry struct {\n\t"
  },
  {
    "path": "d2common/d2fileformats/d2dcc/doc.go",
    "chars": 88,
    "preview": "// Package d2dcc contains the logic for loading and processing DCC files.\npackage d2dcc\n"
  },
  {
    "path": "d2common/d2fileformats/d2ds1/doc.go",
    "chars": 87,
    "preview": "// Package d2ds1 provides functionality for loading/processing DS1 Files\npackage d2ds1\n"
  },
  {
    "path": "d2common/d2fileformats/d2ds1/ds1.go",
    "chars": 16599,
    "preview": "package d2ds1\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n\t\"github.com/OpenDiablo2/Open"
  },
  {
    "path": "d2common/d2fileformats/d2ds1/ds1_layers.go",
    "chars": 7037,
    "preview": "package d2ds1\n\nconst (\n\tmaxWallLayers         = 4\n\tmaxFloorLayers        = 2\n\tmaxShadowLayers       = 1\n\tmaxSubstitution"
  },
  {
    "path": "d2common/d2fileformats/d2ds1/ds1_layers_test.go",
    "chars": 7195,
    "preview": "package d2ds1\n\nimport (\n\t\"testing\"\n)\n\nfunc Test_ds1Layers_Delete(t *testing.T) {\n\tt.Run(\"Floors\", func(t *testing.T) {\n\t"
  },
  {
    "path": "d2common/d2fileformats/d2ds1/ds1_test.go",
    "chars": 4449,
    "preview": "package d2ds1\n\nimport (\n\t\"testing\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum\"\n\t\"github.com/OpenDiablo2/OpenD"
  },
  {
    "path": "d2common/d2fileformats/d2ds1/ds1_version.go",
    "chars": 1313,
    "preview": "package d2ds1\n\ntype ds1version int\n\nconst (\n\tv3  ds1version = 3\n\tv4  ds1version = 4\n\tv7  ds1version = 7\n\tv8  ds1version "
  },
  {
    "path": "d2common/d2fileformats/d2ds1/layer.go",
    "chars": 2637,
    "preview": "package d2ds1\n\n// layerStreamType represents a layer stream type\ntype layerStreamType int\n\n// Layer stream types\nconst ("
  },
  {
    "path": "d2common/d2fileformats/d2ds1/layer_test.go",
    "chars": 515,
    "preview": "package d2ds1\n\nimport \"testing\"\n\nfunc Test_layers(t *testing.T) {\n\tconst (\n\t\tfmtWidthHeightError = \"unexpected wall laye"
  },
  {
    "path": "d2common/d2fileformats/d2ds1/object.go",
    "chars": 485,
    "preview": "package d2ds1\n\nimport (\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2path\"\n)\n\n// Object is a game world object\ntype O"
  },
  {
    "path": "d2common/d2fileformats/d2ds1/substitution_group.go",
    "chars": 222,
    "preview": "package d2ds1\n\n// SubstitutionGroup represents a substitution group in a DS1 file.\ntype SubstitutionGroup struct {\n\tTile"
  },
  {
    "path": "d2common/d2fileformats/d2ds1/tile.go",
    "chars": 3301,
    "preview": "package d2ds1\n\nimport (\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n\t\"github.com/OpenDiablo2/OpenDiablo2/"
  },
  {
    "path": "d2common/d2fileformats/d2dt1/block.go",
    "chars": 538,
    "preview": "package d2dt1\n\n// Block represents a DT1 block\ntype Block struct {\n\tX           int16\n\tY           int16\n\tGridX       by"
  },
  {
    "path": "d2common/d2fileformats/d2dt1/doc.go",
    "chars": 139,
    "preview": "// Package d2dt1 provides functionality for loading/processing DT1 files.\n// https://d2mods.info/forum/viewtopic.php?t=6"
  },
  {
    "path": "d2common/d2fileformats/d2dt1/dt1.go",
    "chars": 7013,
    "preview": "package d2dt1\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n)\n\n// BlockDataFormat"
  },
  {
    "path": "d2common/d2fileformats/d2dt1/gfx_decode.go",
    "chars": 1405,
    "preview": "package d2dt1\n\nconst (\n\tblockDataLength = 256\n)\n\n// DecodeTileGfxData decodes tile graphics data for a slice of dt1 bloc"
  },
  {
    "path": "d2common/d2fileformats/d2dt1/material.go",
    "chars": 1323,
    "preview": "package d2dt1\n\n// MaterialFlags represents the material flags. Lots of unknowns for now...\ntype MaterialFlags struct {\n\t"
  },
  {
    "path": "d2common/d2fileformats/d2dt1/subtile.go",
    "chars": 2028,
    "preview": "package d2dt1\n\n// SubTileFlags represent the sub-tile flags for a DT1\ntype SubTileFlags struct {\n\tBlockWalk       bool\n\t"
  },
  {
    "path": "d2common/d2fileformats/d2dt1/subtile_test.go",
    "chars": 568,
    "preview": "package d2dt1\n\nimport (\n\t\"testing\"\n\n\ttestify \"github.com/stretchr/testify/assert\"\n)\n\nfunc TestNewSubTile(t *testing.T) {"
  },
  {
    "path": "d2common/d2fileformats/d2dt1/tile.go",
    "chars": 707,
    "preview": "package d2dt1\n\n// Tile is a representation of a map tile\ntype Tile struct {\n\tunknown2           []byte\n\tDirection       "
  },
  {
    "path": "d2common/d2fileformats/d2font/d2fontglyph/font_glyph.go",
    "chars": 1362,
    "preview": "// Package d2fontglyph represents a single font glyph\npackage d2fontglyph\n\n// Create creates a new font glyph\nfunc Creat"
  },
  {
    "path": "d2common/d2fileformats/d2font/doc.go",
    "chars": 87,
    "preview": "// Package d2font contains logic for loading and processing\n// d2 fonts\npackage d2font\n"
  },
  {
    "path": "d2common/d2fileformats/d2font/font.go",
    "chars": 4405,
    "preview": "package d2font\n\nimport (\n\t\"fmt\"\n\t\"image/color\"\n\t\"strings\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n\t\""
  },
  {
    "path": "d2common/d2fileformats/d2mpq/crypto.go",
    "chars": 3130,
    "preview": "package d2mpq\n\nimport (\n\t\"encoding/binary\"\n\t\"io\"\n\t\"strings\"\n)\n\nvar cryptoBuffer [0x500]uint32 //nolint:gochecknoglobals "
  },
  {
    "path": "d2common/d2fileformats/d2mpq/doc.go",
    "chars": 78,
    "preview": "// Package d2mpq contains the functions for handling MPQ files.\npackage d2mpq\n"
  },
  {
    "path": "d2common/d2fileformats/d2mpq/mpq.go",
    "chars": 4717,
    "preview": "package d2mpq\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\""
  },
  {
    "path": "d2common/d2fileformats/d2mpq/mpq_block.go",
    "chars": 2667,
    "preview": "package d2mpq\n\nimport (\n\t\"io\"\n\t\"strings\"\n)\n\n// FileFlag represents flags for a file record in the MPQ archive\ntype FileF"
  },
  {
    "path": "d2common/d2fileformats/d2mpq/mpq_data_stream.go",
    "chars": 782,
    "preview": "package d2mpq\n\nimport \"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface\"\n\nvar _ d2interface.DataStream = &MpqData"
  },
  {
    "path": "d2common/d2fileformats/d2mpq/mpq_file_record.go",
    "chars": 170,
    "preview": "package d2mpq\n\n// MpqFileRecord represents a file record in an MPQ\ntype MpqFileRecord struct {\n\tMpqFile          string\n"
  },
  {
    "path": "d2common/d2fileformats/d2mpq/mpq_hash.go",
    "chars": 1099,
    "preview": "package d2mpq\n\nimport \"io\"\n\n// Hash represents a hashed file entry in the MPQ file\ntype Hash struct { // 16 bytes\n\tA    "
  },
  {
    "path": "d2common/d2fileformats/d2mpq/mpq_header.go",
    "chars": 671,
    "preview": "package d2mpq\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"io\"\n)\n\n// Header Represents a MPQ file\ntype Header struct {\n\tMagi"
  },
  {
    "path": "d2common/d2fileformats/d2mpq/mpq_stream.go",
    "chars": 7693,
    "preview": "package d2mpq\n\nimport (\n\t\"bytes\"\n\t\"compress/zlib\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/JoshVarga/blas"
  },
  {
    "path": "d2common/d2fileformats/d2pl2/doc.go",
    "chars": 72,
    "preview": "// Package d2pl2 handles processing of PL2 palette files.\npackage d2pl2\n"
  },
  {
    "path": "d2common/d2fileformats/d2pl2/pl2.go",
    "chars": 1303,
    "preview": "package d2pl2\n\nimport (\n\t\"encoding/binary\"\n\n\t\"github.com/go-restruct/restruct\"\n)\n\n// PL2 represents a palette file.\ntype"
  },
  {
    "path": "d2common/d2fileformats/d2pl2/pl2_color.go",
    "chars": 838,
    "preview": "package d2pl2\n\nconst (\n\tbitShift0 = 8 * iota\n\tbitShift8\n\tbitShift16\n\tbitShift24\n\n\tmask = 0xff\n)\n\n// PL2Color represents "
  },
  {
    "path": "d2common/d2fileformats/d2pl2/pl2_color_24bits.go",
    "chars": 373,
    "preview": "package d2pl2\n\n// PL2Color24Bits represents an RGB color\ntype PL2Color24Bits struct {\n\tR uint8\n\tG uint8\n\tB uint8\n}\n\n// R"
  },
  {
    "path": "d2common/d2fileformats/d2pl2/pl2_palette.go",
    "chars": 104,
    "preview": "package d2pl2\n\n// PL2Palette represents a PL2 palette.\ntype PL2Palette struct {\n\tColors [256]PL2Color\n}\n"
  },
  {
    "path": "d2common/d2fileformats/d2pl2/pl2_palette_transform.go",
    "chars": 130,
    "preview": "package d2pl2\n\n// PL2PaletteTransform represents a PL2 palette transform.\ntype PL2PaletteTransform struct {\n\tIndices [25"
  },
  {
    "path": "d2common/d2fileformats/d2pl2/pl2_test.go",
    "chars": 810,
    "preview": "package d2pl2\n\nimport (\n\t\"testing\"\n)\n\nfunc exampleData() *PL2 {\n\tresult := &PL2{\n\t\tBasePalette:       PL2Palette{},\n\t\tSe"
  },
  {
    "path": "d2common/d2fileformats/d2tbl/doc.go",
    "chars": 81,
    "preview": "// Package d2tbl provides a file parser for tbl string table files\npackage d2tbl\n"
  },
  {
    "path": "d2common/d2fileformats/d2tbl/text_dictionary.go",
    "chars": 5539,
    "preview": "package d2tbl\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils\"\n)\n\n// TextDictiona"
  },
  {
    "path": "d2common/d2fileformats/d2tbl/text_dictionary_test.go",
    "chars": 995,
    "preview": "package d2tbl\n\nimport (\n\t\"testing\"\n)\n\nfunc exampleData() *TextDictionary {\n\tresult := &TextDictionary{\n\t\t\"abc\":        \""
  },
  {
    "path": "d2common/d2fileformats/d2txt/data_dictionary.go",
    "chars": 1748,
    "preview": "package d2txt\n\nimport (\n\t\"bytes\"\n\t\"encoding/csv\"\n\t\"io\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// DataDictionary represents a da"
  },
  {
    "path": "d2common/d2fileformats/d2txt/doc.go",
    "chars": 90,
    "preview": "// Package d2txt provides a parser implementation for diablo TSV data files\npackage d2txt\n"
  },
  {
    "path": "d2common/d2geom/doc.go",
    "chars": 87,
    "preview": "// Package d2geom is a utility package for anything related to geometry\npackage d2geom\n"
  },
  {
    "path": "d2common/d2geom/point.go",
    "chars": 178,
    "preview": "package d2geom\n\n// Point represents a point\ntype Point struct {\n\tX int\n\tY int\n}\n\n// Pointf represents a point with float"
  },
  {
    "path": "d2common/d2geom/rectangle.go",
    "chars": 559,
    "preview": "package d2geom\n\n// Rectangle represents a rectangle\ntype Rectangle struct {\n\tLeft   int\n\tTop    int\n\tWidth  int\n\tHeight "
  },
  {
    "path": "d2common/d2geom/size.go",
    "chars": 82,
    "preview": "package d2geom\n\n// Size represents a size\ntype Size struct {\n\tWidth, Height int\n}\n"
  },
  {
    "path": "d2common/d2interface/animation.go",
    "chars": 1043,
    "preview": "package d2interface\n\nimport (\n\t\"image\"\n\t\"image/color\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum\"\n)\n\n// Anima"
  },
  {
    "path": "d2common/d2interface/archive.go",
    "chars": 510,
    "preview": "package d2interface\n\n// Archive is an abstract representation of a game archive file\n// For the original Diablo II, arch"
  },
  {
    "path": "d2common/d2interface/audio_provider.go",
    "chars": 324,
    "preview": "package d2interface\n\n// AudioProvider is something that can play music, load audio files managed\n// by the asset manager"
  },
  {
    "path": "d2common/d2interface/cache.go",
    "chars": 363,
    "preview": "package d2interface\n\n// Cache stores arbitrary data for fast retrieval\ntype Cache interface {\n\tSetVerbose(verbose bool)\n"
  },
  {
    "path": "d2common/d2interface/data_stream.go",
    "chars": 179,
    "preview": "package d2interface\n\n// DataStream is a data stream\ntype DataStream interface {\n\tRead(p []byte) (n int, err error)\n\tSeek"
  },
  {
    "path": "d2common/d2interface/doc.go",
    "chars": 89,
    "preview": "// Package d2interface defines interfaces for the OpenDiablo2 engine\npackage d2interface\n"
  },
  {
    "path": "d2common/d2interface/input_events.go",
    "chars": 834,
    "preview": "package d2interface\n\nimport \"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum\"\n\n// HandlerEvent holds the qualifiers f"
  },
  {
    "path": "d2common/d2interface/input_handlers.go",
    "chars": 1717,
    "preview": "package d2interface\n\n// InputEventHandler is an event handler\ntype InputEventHandler interface{}\n\n/*\n\tNOTE: The return v"
  },
  {
    "path": "d2common/d2interface/input_manager.go",
    "chars": 358,
    "preview": "package d2interface\n\nimport \"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum\"\n\n// InputManager manages an InputServic"
  },
  {
    "path": "d2common/d2interface/input_service.go",
    "chars": 1331,
    "preview": "package d2interface\n\nimport \"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum\"\n\n// InputService represents an interfac"
  },
  {
    "path": "d2common/d2interface/map_entity.go",
    "chars": 459,
    "preview": "package d2interface\n\nimport \"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector\"\n\n// MapEntity is something tha"
  },
  {
    "path": "d2common/d2interface/navigate.go",
    "chars": 595,
    "preview": "package d2interface\n\nimport (\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype\"\n)\n\n// N"
  },
  {
    "path": "d2common/d2interface/palette.go",
    "chars": 344,
    "preview": "package d2interface\n\nconst numColors = 256\n\n// Color represents a color\ntype Color interface {\n\tR() uint8\n\tG() uint8\n\tB("
  },
  {
    "path": "d2common/d2interface/renderer.go",
    "chars": 725,
    "preview": "package d2interface\n\ntype renderCallback = func(Surface) error\n\ntype updateCallback = func() error\n\n// Renderer interfac"
  },
  {
    "path": "d2common/d2interface/sound_effect.go",
    "chars": 207,
    "preview": "package d2interface\n\n// SoundEffect is something that that the AudioProvider can Play or Stop\ntype SoundEffect interface"
  },
  {
    "path": "d2common/d2interface/surface.go",
    "chars": 875,
    "preview": "package d2interface\n\nimport (\n\t\"image\"\n\t\"image/color\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum\"\n)\n\n// Surfa"
  },
  {
    "path": "d2common/d2interface/terminal.go",
    "chars": 1046,
    "preview": "package d2interface\n\nimport \"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum\"\n\n// Terminal is a drop-down terminal an"
  },
  {
    "path": "d2common/d2loader/asset/asset.go",
    "chars": 414,
    "preview": "package asset\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2loader/asset/types\"\n)\n\n// Asset re"
  },
  {
    "path": "d2common/d2loader/asset/doc.go",
    "chars": 72,
    "preview": "// Package asset provides interfaces for Asset and Source\npackage asset\n"
  },
  {
    "path": "d2common/d2loader/asset/source.go",
    "chars": 238,
    "preview": "package asset\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\n// Source is an abstraction for something that can load and list assets\ntype Sou"
  },
  {
    "path": "d2common/d2loader/asset/types/asset_types.go",
    "chars": 1003,
    "preview": "package types\n\nimport \"strings\"\n\n// AssetType represents the type of an asset\ntype AssetType int\n\n// Asset types\nconst ("
  },
  {
    "path": "d2common/d2loader/asset/types/doc.go",
    "chars": 119,
    "preview": "// Package types provides an enumeration of Asset and Source types, as well as some utility\n// functions\npackage types\n"
  },
  {
    "path": "d2common/d2loader/asset/types/source_types.go",
    "chars": 1032,
    "preview": "package types\n\nimport (\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2mpq\"\n"
  }
]

// ... and 449 more files (download for full content)

About this extraction

This page contains the full source code of the OpenDiablo2/OpenDiablo2 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 649 files (3.6 MB), approximately 969.4k tokens, and a symbol index with 5639 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.

Copied to clipboard!