// Copyright 2013-2021 the openage authors. See copying.md for legal info.

// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter;
// its purpose is to keep the deprecated gamestate compilable and intact;
// these files keep only the minimum functionality and should not be changed;
// For details, see buildsystem/codegen.cmake and openage/codegen.


#include <cstdio>
#include <vector>
#include "error/error.h"
#include "unit_dummy.h"
#include "util/strings.h"


namespace openage {
namespace gamedata {

constexpr size_t action_unit::member_count;
constexpr size_t animated_unit::member_count;
constexpr size_t building_annex::member_count;
constexpr size_t building_unit::member_count;
constexpr size_t damage_graphic::member_count;
constexpr size_t doppelganger_unit::member_count;
constexpr size_t hit_type::member_count;
constexpr size_t living_unit::member_count;
constexpr size_t missile_unit::member_count;
constexpr size_t moving_unit::member_count;
constexpr size_t projectile_unit::member_count;
constexpr size_t resource_cost::member_count;
constexpr size_t resource_storage::member_count;
constexpr size_t tree_unit::member_count;
constexpr size_t unit_command::member_count;
constexpr size_t unit_header::member_count;
constexpr size_t unit_object::member_count;
int action_unit::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', action_unit::member_count
    );

    if (buf.size() != action_unit::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing action_unit led to "
            << buf.size()
            << " columns (expected "
            << action_unit::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }
    if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; }
    if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; }
    if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; }
    if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; }
    if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; }
    if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; }
    if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; }
    if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; }
    if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; }
    if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; }
    if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; }
    if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; }
    if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; }
    if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; }
    if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; }
    if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; }
    if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; }
    if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; }
    if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; }
    if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; }
    if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; }

    return -1;
}

bool action_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);

    return true;
}

int animated_unit::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', animated_unit::member_count
    );

    if (buf.size() != animated_unit::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing animated_unit led to "
            << buf.size()
            << " columns (expected "
            << animated_unit::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; }
    if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; }
    if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; }
    this->resource_storage.filename = buf[60];
    this->damage_graphics.filename = buf[61];
    if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; }
    if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; }
    // parse enum attack_modes
    if (buf[64] == "DUMMY") {
        this->old_attack_mode = attack_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[64]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }
    if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; }

    return -1;
}

bool animated_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);

    return true;
}

int building_annex::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', building_annex::member_count
    );

    if (buf.size() != building_annex::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing building_annex led to "
            << buf.size()
            << " columns (expected "
            << building_annex::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->unit_id) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%f", &this->misplaced0) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%f", &this->misplaced1) != 1) { return 2; }

    return -1;
}

bool building_annex::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) {
    return true;
}

int building_unit::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', building_unit::member_count
    );

    if (buf.size() != building_unit::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing building_unit led to "
            << buf.size()
            << " columns (expected "
            << building_unit::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; }
    if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; }
    if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; }
    this->resource_storage.filename = buf[60];
    this->damage_graphics.filename = buf[61];
    if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; }
    if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; }
    // parse enum attack_modes
    if (buf[64] == "DUMMY") {
        this->old_attack_mode = attack_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[64]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }
    if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; }
    if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; }
    if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; }
    if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; }
    if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; }
    if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; }
    if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; }
    if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; }
    if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; }
    if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; }
    if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; }
    if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; }
    if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; }
    if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; }
    if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; }
    if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; }
    if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; }
    if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; }
    if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; }
    if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; }
    if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; }
    if (sscanf(buf[91].c_str(), "%hd", &this->default_armor) != 1) { return 91; }
    this->attacks.filename = buf[92];
    this->armors.filename = buf[93];
    // parse enum boundary_ids
    if (buf[94] == "DUMMY") {
        this->boundary_id = boundary_ids::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[94]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[95].c_str(), "%f", &this->weapon_range_max) != 1) { return 95; }
    if (sscanf(buf[96].c_str(), "%f", &this->blast_range) != 1) { return 96; }
    if (sscanf(buf[97].c_str(), "%f", &this->attack_speed) != 1) { return 97; }
    if (sscanf(buf[98].c_str(), "%hd", &this->attack_projectile_primary_unit_id) != 1) { return 98; }
    if (sscanf(buf[99].c_str(), "%hd", &this->accuracy) != 1) { return 99; }
    if (sscanf(buf[100].c_str(), "%hhd", &this->break_off_combat) != 1) { return 100; }
    if (sscanf(buf[101].c_str(), "%hd", &this->frame_delay) != 1) { return 101; }
    // parse enum range_damage_type
    if (buf[103] == "DUMMY") {
        this->blast_level_offence = range_damage_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[103]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[104].c_str(), "%f", &this->weapon_range_min) != 1) { return 104; }
    if (sscanf(buf[105].c_str(), "%f", &this->accuracy_dispersion) != 1) { return 105; }
    if (sscanf(buf[106].c_str(), "%hd", &this->attack_sprite_id) != 1) { return 106; }
    if (sscanf(buf[107].c_str(), "%hd", &this->melee_armor_displayed) != 1) { return 107; }
    if (sscanf(buf[108].c_str(), "%hd", &this->attack_displayed) != 1) { return 108; }
    if (sscanf(buf[109].c_str(), "%f", &this->range_displayed) != 1) { return 109; }
    if (sscanf(buf[110].c_str(), "%f", &this->reload_time_displayed) != 1) { return 110; }
    this->resource_cost.filename = buf[111];
    if (sscanf(buf[112].c_str(), "%hd", &this->creation_time) != 1) { return 112; }
    if (sscanf(buf[113].c_str(), "%hd", &this->train_location_id) != 1) { return 113; }
    if (sscanf(buf[114].c_str(), "%f", &this->rear_attack_modifier) != 1) { return 114; }
    if (sscanf(buf[115].c_str(), "%f", &this->flank_attack_modifier) != 1) { return 115; }
    // parse enum creatable_types
    if (buf[116] == "DUMMY") {
        this->creatable_type = creatable_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[116]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[117].c_str(), "%hhd", &this->hero_mode) != 1) { return 117; }
    if (sscanf(buf[118].c_str(), "%d", &this->garrison_graphic) != 1) { return 118; }
    if (sscanf(buf[119].c_str(), "%f", &this->attack_projectile_count) != 1) { return 119; }
    if (sscanf(buf[120].c_str(), "%hhd", &this->attack_projectile_max_count) != 1) { return 120; }
    if (sscanf(buf[121].c_str(), "%f", &this->attack_projectile_spawning_area_width) != 1) { return 121; }
    if (sscanf(buf[122].c_str(), "%f", &this->attack_projectile_spawning_area_length) != 1) { return 122; }
    if (sscanf(buf[123].c_str(), "%f", &this->attack_projectile_spawning_area_randomness) != 1) { return 123; }
    if (sscanf(buf[124].c_str(), "%d", &this->attack_projectile_secondary_unit_id) != 1) { return 124; }
    if (sscanf(buf[125].c_str(), "%d", &this->special_graphic_id) != 1) { return 125; }
    if (sscanf(buf[126].c_str(), "%hhd", &this->special_activation) != 1) { return 126; }
    if (sscanf(buf[127].c_str(), "%hd", &this->pierce_armor_displayed) != 1) { return 127; }
    if (sscanf(buf[128].c_str(), "%hd", &this->construction_graphic_id) != 1) { return 128; }
    if (sscanf(buf[129].c_str(), "%hd", &this->snow_graphic_id) != 1) { return 129; }
    if (sscanf(buf[130].c_str(), "%hhd", &this->adjacent_mode) != 1) { return 130; }
    if (sscanf(buf[131].c_str(), "%hd", &this->graphics_angle) != 1) { return 131; }
    if (sscanf(buf[132].c_str(), "%hhd", &this->disappears_when_built) != 1) { return 132; }
    if (sscanf(buf[133].c_str(), "%hd", &this->stack_unit_id) != 1) { return 133; }
    if (sscanf(buf[134].c_str(), "%hd", &this->foundation_terrain_id) != 1) { return 134; }
    if (sscanf(buf[135].c_str(), "%hd", &this->old_overlay_id) != 1) { return 135; }
    if (sscanf(buf[136].c_str(), "%hd", &this->research_id) != 1) { return 136; }
    if (sscanf(buf[137].c_str(), "%hhd", &this->can_burn) != 1) { return 137; }
    this->building_annex.filename = buf[138];
    if (sscanf(buf[139].c_str(), "%hd", &this->head_unit_id) != 1) { return 139; }
    if (sscanf(buf[140].c_str(), "%hd", &this->transform_unit_id) != 1) { return 140; }
    if (sscanf(buf[141].c_str(), "%hd", &this->transform_sound_id) != 1) { return 141; }
    if (sscanf(buf[142].c_str(), "%hd", &this->construction_sound_id) != 1) { return 142; }
    // parse enum garrison_types
    if (buf[143] == "DUMMY") {
        this->garrison_type = garrison_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[143]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[144].c_str(), "%f", &this->garrison_heal_rate) != 1) { return 144; }
    if (sscanf(buf[145].c_str(), "%f", &this->garrison_repair_rate) != 1) { return 145; }
    if (sscanf(buf[146].c_str(), "%hd", &this->salvage_unit_id) != 1) { return 146; }

    return -1;
}

bool building_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);
    this->attacks.read(storage, basedir);
    this->armors.read(storage, basedir);
    this->resource_cost.read(storage, basedir);
    this->building_annex.read(storage, basedir);

    return true;
}

int damage_graphic::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', damage_graphic::member_count
    );

    if (buf.size() != damage_graphic::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing damage_graphic led to "
            << buf.size()
            << " columns (expected "
            << damage_graphic::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->graphic_id) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hhd", &this->damage_percent) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hhd", &this->old_apply_mode) != 1) { return 2; }
    // parse enum damage_draw_type
    if (buf[3] == "DUMMY") {
        this->apply_mode = damage_draw_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}

    return -1;
}

bool damage_graphic::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) {
    return true;
}

int doppelganger_unit::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', doppelganger_unit::member_count
    );

    if (buf.size() != doppelganger_unit::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing doppelganger_unit led to "
            << buf.size()
            << " columns (expected "
            << doppelganger_unit::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; }
    if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; }
    if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; }
    this->resource_storage.filename = buf[60];
    this->damage_graphics.filename = buf[61];
    if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; }
    if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; }
    // parse enum attack_modes
    if (buf[64] == "DUMMY") {
        this->old_attack_mode = attack_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[64]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }
    if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; }

    return -1;
}

bool doppelganger_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);

    return true;
}

int hit_type::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', hit_type::member_count
    );

    if (buf.size() != hit_type::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing hit_type led to "
            << buf.size()
            << " columns (expected "
            << hit_type::member_count
            << ")!"
        );
    }

    // parse enum hit_class
    if (buf[0] == "DUMMY") {
        this->type_id = hit_class::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[0]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[1].c_str(), "%hd", &this->amount) != 1) { return 1; }

    return -1;
}

bool hit_type::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) {
    return true;
}

int living_unit::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', living_unit::member_count
    );

    if (buf.size() != living_unit::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing living_unit led to "
            << buf.size()
            << " columns (expected "
            << living_unit::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; }
    if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; }
    if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; }
    this->resource_storage.filename = buf[60];
    this->damage_graphics.filename = buf[61];
    if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; }
    if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; }
    // parse enum attack_modes
    if (buf[64] == "DUMMY") {
        this->old_attack_mode = attack_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[64]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }
    if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; }
    if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; }
    if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; }
    if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; }
    if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; }
    if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; }
    if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; }
    if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; }
    if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; }
    if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; }
    if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; }
    if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; }
    if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; }
    if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; }
    if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; }
    if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; }
    if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; }
    if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; }
    if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; }
    if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; }
    if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; }
    if (sscanf(buf[91].c_str(), "%hd", &this->default_armor) != 1) { return 91; }
    this->attacks.filename = buf[92];
    this->armors.filename = buf[93];
    // parse enum boundary_ids
    if (buf[94] == "DUMMY") {
        this->boundary_id = boundary_ids::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[94]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[95].c_str(), "%f", &this->weapon_range_max) != 1) { return 95; }
    if (sscanf(buf[96].c_str(), "%f", &this->blast_range) != 1) { return 96; }
    if (sscanf(buf[97].c_str(), "%f", &this->attack_speed) != 1) { return 97; }
    if (sscanf(buf[98].c_str(), "%hd", &this->attack_projectile_primary_unit_id) != 1) { return 98; }
    if (sscanf(buf[99].c_str(), "%hd", &this->accuracy) != 1) { return 99; }
    if (sscanf(buf[100].c_str(), "%hhd", &this->break_off_combat) != 1) { return 100; }
    if (sscanf(buf[101].c_str(), "%hd", &this->frame_delay) != 1) { return 101; }
    // parse enum range_damage_type
    if (buf[103] == "DUMMY") {
        this->blast_level_offence = range_damage_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[103]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[104].c_str(), "%f", &this->weapon_range_min) != 1) { return 104; }
    if (sscanf(buf[105].c_str(), "%f", &this->accuracy_dispersion) != 1) { return 105; }
    if (sscanf(buf[106].c_str(), "%hd", &this->attack_sprite_id) != 1) { return 106; }
    if (sscanf(buf[107].c_str(), "%hd", &this->melee_armor_displayed) != 1) { return 107; }
    if (sscanf(buf[108].c_str(), "%hd", &this->attack_displayed) != 1) { return 108; }
    if (sscanf(buf[109].c_str(), "%f", &this->range_displayed) != 1) { return 109; }
    if (sscanf(buf[110].c_str(), "%f", &this->reload_time_displayed) != 1) { return 110; }
    this->resource_cost.filename = buf[111];
    if (sscanf(buf[112].c_str(), "%hd", &this->creation_time) != 1) { return 112; }
    if (sscanf(buf[113].c_str(), "%hd", &this->train_location_id) != 1) { return 113; }
    if (sscanf(buf[114].c_str(), "%f", &this->rear_attack_modifier) != 1) { return 114; }
    if (sscanf(buf[115].c_str(), "%f", &this->flank_attack_modifier) != 1) { return 115; }
    // parse enum creatable_types
    if (buf[116] == "DUMMY") {
        this->creatable_type = creatable_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[116]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[117].c_str(), "%hhd", &this->hero_mode) != 1) { return 117; }
    if (sscanf(buf[118].c_str(), "%d", &this->garrison_graphic) != 1) { return 118; }
    if (sscanf(buf[119].c_str(), "%f", &this->attack_projectile_count) != 1) { return 119; }
    if (sscanf(buf[120].c_str(), "%hhd", &this->attack_projectile_max_count) != 1) { return 120; }
    if (sscanf(buf[121].c_str(), "%f", &this->attack_projectile_spawning_area_width) != 1) { return 121; }
    if (sscanf(buf[122].c_str(), "%f", &this->attack_projectile_spawning_area_length) != 1) { return 122; }
    if (sscanf(buf[123].c_str(), "%f", &this->attack_projectile_spawning_area_randomness) != 1) { return 123; }
    if (sscanf(buf[124].c_str(), "%d", &this->attack_projectile_secondary_unit_id) != 1) { return 124; }
    if (sscanf(buf[125].c_str(), "%d", &this->special_graphic_id) != 1) { return 125; }
    if (sscanf(buf[126].c_str(), "%hhd", &this->special_activation) != 1) { return 126; }
    if (sscanf(buf[127].c_str(), "%hd", &this->pierce_armor_displayed) != 1) { return 127; }

    return -1;
}

bool living_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);
    this->attacks.read(storage, basedir);
    this->armors.read(storage, basedir);
    this->resource_cost.read(storage, basedir);

    return true;
}

int missile_unit::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', missile_unit::member_count
    );

    if (buf.size() != missile_unit::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing missile_unit led to "
            << buf.size()
            << " columns (expected "
            << missile_unit::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; }
    if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; }
    if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; }
    this->resource_storage.filename = buf[60];
    this->damage_graphics.filename = buf[61];
    if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; }
    if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; }
    // parse enum attack_modes
    if (buf[64] == "DUMMY") {
        this->old_attack_mode = attack_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[64]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }
    if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; }
    if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; }
    if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; }
    if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; }
    if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; }
    if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; }
    if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; }
    if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; }
    if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; }
    if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; }
    if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; }
    if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; }
    if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; }
    if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; }
    if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; }
    if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; }
    if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; }
    if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; }
    if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; }
    if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; }
    if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; }
    if (sscanf(buf[91].c_str(), "%hd", &this->default_armor) != 1) { return 91; }
    this->attacks.filename = buf[92];
    this->armors.filename = buf[93];
    // parse enum boundary_ids
    if (buf[94] == "DUMMY") {
        this->boundary_id = boundary_ids::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[94]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[95].c_str(), "%f", &this->weapon_range_max) != 1) { return 95; }
    if (sscanf(buf[96].c_str(), "%f", &this->blast_range) != 1) { return 96; }
    if (sscanf(buf[97].c_str(), "%f", &this->attack_speed) != 1) { return 97; }
    if (sscanf(buf[98].c_str(), "%hd", &this->attack_projectile_primary_unit_id) != 1) { return 98; }
    if (sscanf(buf[99].c_str(), "%hd", &this->accuracy) != 1) { return 99; }
    if (sscanf(buf[100].c_str(), "%hhd", &this->break_off_combat) != 1) { return 100; }
    if (sscanf(buf[101].c_str(), "%hd", &this->frame_delay) != 1) { return 101; }
    // parse enum range_damage_type
    if (buf[103] == "DUMMY") {
        this->blast_level_offence = range_damage_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[103]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[104].c_str(), "%f", &this->weapon_range_min) != 1) { return 104; }
    if (sscanf(buf[105].c_str(), "%f", &this->accuracy_dispersion) != 1) { return 105; }
    if (sscanf(buf[106].c_str(), "%hd", &this->attack_sprite_id) != 1) { return 106; }
    if (sscanf(buf[107].c_str(), "%hd", &this->melee_armor_displayed) != 1) { return 107; }
    if (sscanf(buf[108].c_str(), "%hd", &this->attack_displayed) != 1) { return 108; }
    if (sscanf(buf[109].c_str(), "%f", &this->range_displayed) != 1) { return 109; }
    if (sscanf(buf[110].c_str(), "%f", &this->reload_time_displayed) != 1) { return 110; }
    if (sscanf(buf[111].c_str(), "%hhd", &this->projectile_type) != 1) { return 111; }
    if (sscanf(buf[112].c_str(), "%hhd", &this->smart_mode) != 1) { return 112; }
    if (sscanf(buf[113].c_str(), "%hhd", &this->drop_animation_mode) != 1) { return 113; }
    if (sscanf(buf[114].c_str(), "%hhd", &this->penetration_mode) != 1) { return 114; }
    if (sscanf(buf[115].c_str(), "%hhd", &this->area_of_effect_special) != 1) { return 115; }
    if (sscanf(buf[116].c_str(), "%f", &this->projectile_arc) != 1) { return 116; }

    return -1;
}

bool missile_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);
    this->attacks.read(storage, basedir);
    this->armors.read(storage, basedir);

    return true;
}

int moving_unit::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', moving_unit::member_count
    );

    if (buf.size() != moving_unit::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing moving_unit led to "
            << buf.size()
            << " columns (expected "
            << moving_unit::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; }
    if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; }
    if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; }
    this->resource_storage.filename = buf[60];
    this->damage_graphics.filename = buf[61];
    if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; }
    if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; }
    // parse enum attack_modes
    if (buf[64] == "DUMMY") {
        this->old_attack_mode = attack_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[64]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }
    if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; }
    if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; }
    if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; }
    if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; }
    if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; }
    if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; }
    if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; }
    if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; }
    if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; }
    if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; }
    if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; }
    if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; }
    if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; }
    if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; }

    return -1;
}

bool moving_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);

    return true;
}

int projectile_unit::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', projectile_unit::member_count
    );

    if (buf.size() != projectile_unit::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing projectile_unit led to "
            << buf.size()
            << " columns (expected "
            << projectile_unit::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; }
    if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; }
    if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; }
    this->resource_storage.filename = buf[60];
    this->damage_graphics.filename = buf[61];
    if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; }
    if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; }
    // parse enum attack_modes
    if (buf[64] == "DUMMY") {
        this->old_attack_mode = attack_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[64]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }
    if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; }
    if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; }
    if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; }
    if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; }
    if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; }
    if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; }
    if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; }
    if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; }
    if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; }
    if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; }
    if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; }
    if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; }
    if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; }
    if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; }
    if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; }
    if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; }
    if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; }
    if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; }
    if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; }
    if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; }
    if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; }
    if (sscanf(buf[91].c_str(), "%hd", &this->default_armor) != 1) { return 91; }
    this->attacks.filename = buf[92];
    this->armors.filename = buf[93];
    // parse enum boundary_ids
    if (buf[94] == "DUMMY") {
        this->boundary_id = boundary_ids::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[94]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[95].c_str(), "%f", &this->weapon_range_max) != 1) { return 95; }
    if (sscanf(buf[96].c_str(), "%f", &this->blast_range) != 1) { return 96; }
    if (sscanf(buf[97].c_str(), "%f", &this->attack_speed) != 1) { return 97; }
    if (sscanf(buf[98].c_str(), "%hd", &this->attack_projectile_primary_unit_id) != 1) { return 98; }
    if (sscanf(buf[99].c_str(), "%hd", &this->accuracy) != 1) { return 99; }
    if (sscanf(buf[100].c_str(), "%hhd", &this->break_off_combat) != 1) { return 100; }
    if (sscanf(buf[101].c_str(), "%hd", &this->frame_delay) != 1) { return 101; }
    // parse enum range_damage_type
    if (buf[103] == "DUMMY") {
        this->blast_level_offence = range_damage_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[103]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[104].c_str(), "%f", &this->weapon_range_min) != 1) { return 104; }
    if (sscanf(buf[105].c_str(), "%f", &this->accuracy_dispersion) != 1) { return 105; }
    if (sscanf(buf[106].c_str(), "%hd", &this->attack_sprite_id) != 1) { return 106; }
    if (sscanf(buf[107].c_str(), "%hd", &this->melee_armor_displayed) != 1) { return 107; }
    if (sscanf(buf[108].c_str(), "%hd", &this->attack_displayed) != 1) { return 108; }
    if (sscanf(buf[109].c_str(), "%f", &this->range_displayed) != 1) { return 109; }
    if (sscanf(buf[110].c_str(), "%f", &this->reload_time_displayed) != 1) { return 110; }

    return -1;
}

bool projectile_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);
    this->attacks.read(storage, basedir);
    this->armors.read(storage, basedir);

    return true;
}

int resource_cost::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', resource_cost::member_count
    );

    if (buf.size() != resource_cost::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing resource_cost led to "
            << buf.size()
            << " columns (expected "
            << resource_cost::member_count
            << ")!"
        );
    }

    // parse enum resource_types
    if (buf[0] == "DUMMY") {
        this->type_id = resource_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[0]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[1].c_str(), "%hd", &this->amount) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hd", &this->enabled) != 1) { return 2; }

    return -1;
}

bool resource_cost::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) {
    return true;
}

int resource_storage::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', resource_storage::member_count
    );

    if (buf.size() != resource_storage::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing resource_storage led to "
            << buf.size()
            << " columns (expected "
            << resource_storage::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->type) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%f", &this->amount) != 1) { return 1; }
    // parse enum resource_handling
    if (buf[2] == "DUMMY") {
        this->used_mode = resource_handling::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[2]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}

    return -1;
}

bool resource_storage::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) {
    return true;
}

int tree_unit::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', tree_unit::member_count
    );

    if (buf.size() != tree_unit::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing tree_unit led to "
            << buf.size()
            << " columns (expected "
            << tree_unit::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; }
    if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; }
    if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; }
    this->resource_storage.filename = buf[60];
    this->damage_graphics.filename = buf[61];
    if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; }
    if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; }
    // parse enum attack_modes
    if (buf[64] == "DUMMY") {
        this->old_attack_mode = attack_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[64]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }

    return -1;
}

bool tree_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);

    return true;
}

int unit_command::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', unit_command::member_count
    );

    if (buf.size() != unit_command::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing unit_command led to "
            << buf.size()
            << " columns (expected "
            << unit_command::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->command_used) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hd", &this->command_id) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hhd", &this->is_default) != 1) { return 2; }
    // parse enum command_ability
    if (buf[3] == "DUMMY") {
        this->type = command_ability::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->class_id) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->unit_id) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->terrain_id) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->resource_in) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hd", &this->resource_multiplier) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->resource_out) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%hd", &this->unused_resource) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%f", &this->work_value1) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->work_value2) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->work_range) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%hhd", &this->search_mode) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%f", &this->search_time) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hhd", &this->enable_targeting) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hhd", &this->combat_level_flag) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hd", &this->gather_type) != 1) { return 18; }
    // parse enum selection_type
    if (buf[19] == "DUMMY") {
        this->owner_type = selection_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[19]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[20].c_str(), "%hhd", &this->carry_check) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->state_build) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->move_sprite_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hd", &this->proceed_sprite_id) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->work_sprite_id) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->carry_sprite_id) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->resource_gather_sound_id) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->resource_deposit_sound_id) != 1) { return 27; }

    return -1;
}

bool unit_command::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) {
    return true;
}

int unit_header::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', unit_header::member_count
    );

    if (buf.size() != unit_header::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing unit_header led to "
            << buf.size()
            << " columns (expected "
            << unit_header::member_count
            << ")!"
        );
    }

    // remember if the following members are undefined
    if (buf[0] == "data_absent") {
        this->exists = 0;
    } else if (buf[0] == "data_exists") {
        this->exists = 1;
    } else {
        throw openage::error::Error(ERR << "unexpected value '"<< buf[0] << "' for ContinueReadMember");
    }
    this->unit_commands.filename = buf[1];

    return -1;
}

bool unit_header::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->unit_commands.read(storage, basedir);

    return true;
}

int unit_object::fill(const std::string &line) {
    std::vector<std::string> buf = openage::util::split_escape(
        line, ',', unit_object::member_count
    );

    if (buf.size() != unit_object::member_count) {
        throw openage::error::Error(
            ERR
            << "Tokenizing unit_object led to "
            << buf.size()
            << " columns (expected "
            << unit_object::member_count
            << ")!"
        );
    }

    if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; }
    if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; }
    if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; }
    // parse enum unit_classes
    if (buf[3] == "DUMMY") {
        this->unit_class = unit_classes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[3]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; }
    if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; }
    if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; }
    if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; }
    if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; }
    if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; }
    if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; }
    if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; }
    if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; }
    if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; }
    if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; }
    if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; }
    if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; }
    if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; }
    if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; }
    if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; }
    if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; }
    if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; }
    if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; }
    if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; }
    if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; }
    if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; }
    if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; }
    if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; }
    if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; }
    if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; }
    // parse enum elevation_modes
    if (buf[30] == "DUMMY") {
        this->elevation_mode = elevation_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[30]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum fog_visibility
    if (buf[31] == "DUMMY") {
        this->visible_in_fog = fog_visibility::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[31]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum ground_type
    if (buf[32] == "DUMMY") {
        this->terrain_restriction = ground_type::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[32]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; }
    if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; }
    if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; }
    // parse enum blast_types
    if (buf[36] == "DUMMY") {
        this->blast_defense_level = blast_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[36]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum combat_levels
    if (buf[37] == "DUMMY") {
        this->combat_level = combat_levels::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[37]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum interaction_modes
    if (buf[38] == "DUMMY") {
        this->interaction_mode = interaction_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[38]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum minimap_modes
    if (buf[39] == "DUMMY") {
        this->map_draw_level = minimap_modes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[39]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    // parse enum command_attributes
    if (buf[40] == "DUMMY") {
        this->unit_level = command_attributes::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[40]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; }
    if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; }
    if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; }
    if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; }
    if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; }
    if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; }
    if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; }
    if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; }
    if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; }
    if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; }
    // parse enum obstruction_types
    if (buf[51] == "DUMMY") {
        this->obstruction_type = obstruction_types::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[51]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; }
    if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; }
    if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; }
    if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; }
    // parse enum selection_effects
    if (buf[56] == "DUMMY") {
        this->selection_effect = selection_effects::DUMMY;
    }
    else {
    throw openage::error::Error(
        MSG(err)
        << "unknown enum value '" << buf[56]
        << "' encountered. valid are: "
           "DUMMY\n---\n"
    );}
    if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; }
    this->name = buf[66];
    if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; }
    if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; }

    return -1;
}

bool unit_object::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) {
    this->resource_storage.read(storage, basedir);
    this->damage_graphics.read(storage, basedir);

    return true;
}

} // gamedata
} // openage
