# Copyright 2022-2026 Bartek thindil Jasicki
#
# This file is part of Steam Sky.
#
# Steam Sky is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Steam Sky is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Steam Sky.  If not, see <http://www.gnu.org/licenses/>.

## Provides various types for the game, like ships' data structure, etc.

import std/tables
import contracts, nimalyzer

type
  CrewNoSpaceError* = object of CatchableError
    ## Raised when there is no space for new item in crew member inventory

  CrewOrderError* = object of CatchableError
    ## Used to mark problems during giving orders to the crew members

  NoTraderError* = object of CatchableError
    ## Raised when there is no crew member assigned to talk

  NoFreeCargoError* = object of CatchableError
    ## Raised when there is no free space in the player's ship cargo

  NoMoneyInBaseError* = object of CatchableError
    ## Raised when there is not enough money in the base for trade

  NoMoneyError* = object of CatchableError
    ## Raised when the player doesn't have money to buy an item

  NotEnoughMoneyError* = object of CatchableError
    ## Raised when the player doesn't have enough money to buy an item

  CantBuyError* = object of CatchableError
    ## Raised when the item is not available for sale

  ReputationError* = object of CatchableError
    ## Raised when there is some problems with reputations

  NoFreeSpaceError* = object of CatchableError
    ## Raised when there is no space in a trader's cargo to sell an item

  ShipUpgrade* = enum
    ## Available types of the player's ship's upgrades
    none, durability, maxValue, value

  ModuleType2* {.pure.} = enum
    ## Available types of the ships' modules
    workshop, any, medicalRoom, trainingRoom, engine, cabin, cockpit, turret,
        gun, cargoRoom, hull, armor, batteringRam, harpoonGun

  ShipSpeed* = enum
    ## Ships's state of speed, how much engines are used
    docked, fullStop = "full_Stop", quarterSpeed = "quarter_Speed",
        halfSpeed = "half_Speed", fullSpeed = "full_Speed"

  CrewOrders* = enum
    ## Possible orders for ships' crew members
    pilot, engineer, gunner, repair, craft, upgrading, talk, heal, clean, rest,
        defend, boarding, train

  EquipmentLocations* = enum
    ## Possible equipment location for mobiles
    weapon, shield, helmet, torso, arms, legs, tool

  NamesTypes* = enum
    ## The type of the faction names, normal, based on syllables or robotic,
    ## based on random letters and numbers
    normal, robotic

  BasesSize* = enum
    ## Size of sky bases
    small, medium, big, unknown

  MissionsTypes* = enum
    ## Types of missions
    deliver, destroy, patrol, explore, passenger

  ModuleType* {.pure.} = enum
    ## Types of available prototypes of ships modules
    any, engine, cabin, cockpit, turret, gun, cargo, hull, armor, batteringRam,
    alchemyLab, furnace, waterCollector, workshop, greenhouse, medicalRoom,
    harpoonGun, trainingRoom

  GoalTypes* {.pure.} = enum
    ## Types of in-game goals
    random, reputation, destroy, discover, visit, craft, mission, kill

  MessageType* = enum
    ## Type of an in-game message
    default, combatMessage, tradeMessage, orderMessage, craftMessage,
        otherMessage, missionMessage

  MessageColor* = enum
    ## The color used to show a message
    white, yellow, green, red, blue, cyan

  EventsTypes* {.pure.} = enum
    ## Possible types of events on map
    none, enemyShip, attackOnBase, disease, doublePrice, baseRecovery,
        fullDocks, enemyPatrol, trader, friendlyShip

  ShipCombatAi* {.pure.} = enum
    ## Possible types of NPC's ships combat behaviour
    none, berserker, attacker, coward, disarmer

  BasePopulation* = enum
    ## The size of a base's population
    empty, small, medium, large

  ObjectQuality* = enum
    ## The quality of an item
    poor, low, normal, good, excellent, any

  CraftBonuses* = enum
    ## Special bonuses set during crafting items
    any,
    none = "None",
    lighter = "Lighter",
    moreDurable = "More durable",
    lessBreakable = "Less breakable",
    moreEffective = "More effective"

  CraftMaluses* = enum
    ## Special maluses set during crafting items
    any,
    none = "None",
    heavier = "Heavier",
    lessDurable = "Less durable",
    moreBreakable = "More breakable",
    lessEffective = "Less effective"

  MapXRange* = range[1..1_024] ## The size of the game map in X axis
  MapYRange* = range[1..1_024] ## The size of the game map in Y axis
  ItemsDurability* = range[0..121] ## The range of the items durability
  SkillRange* = range[0..100] ## The range of skills levels
  BasesRange* = range[1..1_024] ## The amount of bases in the game
  ExtendedBasesRange* = range[0..1_024] ## The amount of bases in the game with zero value
  ReputationRange* = range[-100..100] ## The range of possible reputation levels
  RewardMultiplier* = range[0.0..2.0] ## The range of multiplier for missions reward
  ExtendedNatural* = range[-1..Natural.high] ## Extended Natural range, with -1
  ExtendedNegative* = range[int.low..0] ## Extended negative numbers range, with 0

  AttributesArray* = array[1..2, Natural] ## 1 - Attribute level, 2 - Attribute experience
  EquipmentArray* = array[EquipmentLocations, ExtendedNatural] ## The equipment of mobs

  XmlAttribute* = string
    ## Used to read the game data from XML files
  FactionIndex* = string
    ## Used to store in-game factions indexes
  RecipeIndex* = string
    ## Used to store in-game crafting recipes indexes
  BaseType* = string
    ## Used to store types of bases
  ObjectName* = string
    ## Used to store names of objects (items)
  MessageText* = string
    ## Used to store the text of a message
  CareerName* = string
    ## The name of a career
  ErrorMessage* = string
    ## Used to store errors info
  SettingString* = string
    ## Used to store in-game settings, like money, tools names, etc
  MobName* = string
    ## Used to store a mob's name
  ModuleName* = string
    ## Used to store a module name
  ShipName* = string
    ## Used to store a ship's name
  Description* = string
    ## Used to store an object's description
  MobIndex* = string
    ## Used to store prototypes of mobiles indexes
  ShipIndex* = Positive
    ## Used to store prototypes of ships indexes
  FactionName* = string
    ## Used to store a faction's name
  FactionMemberName* = string
    ## Used to store a faction's members' names
  ItemType* = string
    ## Used to store names of objects (items) types

template typeGetterSetter(baseType: typedesc; varName, name: untyped;
    typ: typedesc) =
  ## Set the getter for a field of ModuleData type
  ##
  ## * baseType - the type which getters and setters will be set
  ## * varName  - the name of variable used in getter and setter
  ## * name     - the name of the field for which the getter will be set
  ## * typ      - the type of the value of the field
  proc `name`*(`varName`: `baseType`): `typ` {.sideEffect, raises: [], tags: [],
      contractual.} =
    ## The getter of a field of `baseType` type
    ##
    ## * `varName` - the data of the selected type
    ##
    ## Returns the value of the selected field
    `varName`.`name`

  proc `name=`*(`varName`: var `baseType`; value: `typ`) {.sideEffect, raises: [
      ], tags: [], contractual.} =
    ## The setter of a field of `baseType` type
    ##
    ## * `varName` - the data of the selected `baseType`
    ## * value     - the new value for the selected field
    ##
    ## Returns modified options of the selected `baseType`
    `varName`.`name` = value

{.push ruleOff: "objects".}
type
  ModuleData* = object
    ## Used to store information about ships' modules
    ##
    ## * mType            - The type of the module
    ## * name             - The name of the module
    ## * protoIndex       - The index of the prototype module
    ## * weight           - The weight of the module
    ## * durability       - The current durability of the module
    ## * maxDurability    - The max durability of the module
    ## * owner            - The list of owners of the module
    ## * upgradeProgress  - The upgrade progess of the module
    ## * upgradeAction    - The current upgrade type for the module
    ## * fuelUsage        - The fuel usage for engines modules
    ## * power            - The power of the engines modules
    ## * disabled         - If true, the engine is disabled
    ## * cleanliness      - The cleanliness level of the cabin
    ## * quality          - The quality level of the cabin
    ## * gunIndex         - The index of the module used as gun in the turret
    ## * damage           - The damage of the gun
    ## * ammoIndex        - The index of item from ship's cargo used as ammunition
    ## * installedModules - The amount of installed modules in the hull
    ## * maxModules       - The max amount of modules which the hull can hold
    ## * craftingIndex    - The index of currently crafted recipe
    ## * craftingTime     - The amount of time needed to finish the order
    ## * craftingAmount   - How many times repeat the crafting order
    ## * craftingQuality  - The desired quality of crafted item
    ## * craftingBonus    - The special bonus for crafted item
    ## * craftingMalus    - The special malus for crafted item
    ## * trainedSkill     - The index of trained skill
    ## * damage2          - The damage of the battering ram
    ## * coolingDown      - If true, the battering ram can't attack now
    ## * duration         - The duration bonus of the harpoon gun
    ## * harpoonIndex     - The index of item from ship's cargo used as harpoon
    ## * data             - Various data for module, depends on module
    name: ModuleName
    protoIndex: Natural
    weight: Natural
    durability: Natural
    maxDurability: Natural
    owner*: seq[int]
    upgradeProgress: ExtendedNatural
    upgradeAction: ShipUpgrade
    case mType: ModuleType2
    of engine:
      fuelUsage: Positive = 1
      power: Positive = 1
      disabled: bool
    of cabin:
      cleanliness: Natural
      quality: Natural
    of turret:
      gunIndex: ExtendedNatural
    of gun:
      damage: Positive = 1
      ammoIndex: ExtendedNatural
    of hull:
      installedModules: Natural
      maxModules: Positive = 1
    of workshop:
      craftingIndex: RecipeIndex
      craftingTime: Natural
      craftingAmount: Natural
      craftingQuality: ObjectQuality = normal
      craftingBonus: CraftBonuses
      craftingMalus: CraftMaluses
    of trainingRoom:
      trainedSkill: Natural
    of batteringRam:
      damage2: Positive = 1
      coolingDown: bool
    of harpoonGun:
      duration: Positive = 1
      harpoonIndex: ExtendedNatural
    of ModuleType2.any:
      data: array[1..3, int]
    else:
      discard
{.pop ruleOn: "objects".}

proc initModuleData*(mType: ModuleType2; name: ModuleName; protoIndex, weight,
    durability, maxDurability: Natural; owner: seq[int] = @[];
    upgradeProgress: ExtendedNatural = -1; upgradeAction: ShipUpgrade = none;
    fuelUsage: Positive = 1; power: Positive = 1; disabled: bool = false;
    cleanliness: Natural = 0; quality: Natural = 0;
    gunIndex: ExtendedNatural = -1; damage: Positive = 1;
    ammoIndex: ExtendedNatural = -1; installedModules: Natural = 0;
    maxModules: Positive = 1; craftingIndex: RecipeIndex = "";
    craftingTime: Natural = 0; craftingAmount: Natural = 0;
    craftingQuality: ObjectQuality = normal;
    craftingBonus: CraftBonuses = CraftBonuses.none;
    craftingMalus: CraftMaluses = CraftMaluses.none; trainedSkill: Natural = 0;
    damage2: Positive = 1; coolingDown: bool = false; duration: Positive = 1;
    harpoonIndex: ExtendedNatural = -1; data: array[1..3,
    int] = [0, 0, 0]): ModuleData {.raises: [], tags: [], contractual.} =
  ## Create a new data structure for the player's ship's module data
  ##
  ## * mType            - The type of the module
  ## * name             - The name of the module
  ## * protoIndex       - The index of the prototype module
  ## * weight           - The weight of the module
  ## * durability       - The current durability of the module
  ## * maxDurability    - The max durability of the module
  ## * owner            - The list of owners of the module
  ## * upgradeProgress  - The upgrade progess of the module
  ## * upgradeAction    - The current upgrade type for the module
  ## * fuelUsage        - The fuel usage for engines modules
  ## * power            - The power of the engines modules
  ## * disabled         - If true, the engine is disabled
  ## * cleanliness      - The cleanliness level of the cabin
  ## * quality          - The quality level of the cabin
  ## * gunIndex         - The index of the module used as gun in the turret
  ## * damage           - The damage of the gun
  ## * ammoIndex        - The index of item from ship's cargo used as ammunition
  ## * installedModules - The amount of installed modules in the hull
  ## * maxModules       - The max amount of modules which the hull can hold
  ## * craftingIndex    - The index of currently crafted recipe
  ## * craftingTime     - The amount of time needed to finish the order
  ## * craftingAmount   - How many times repeat the crafting order
  ## * craftingQuality  - The desired quality of crafted item
  ## * craftingBonus    - The special bonus for crafted item
  ## * craftingMalus    - The special malus for crafted item
  ## * trainedSkill     - The index of trained skill
  ## * damage2          - The damage of the battering ram
  ## * coolingDown      - If true, the battering ram can't attack now
  ## * duration         - The duration bonus of the harpoon gun
  ## * harpoonIndex     - The index of item from ship's cargo used as harpoon
  ## * data             - Various data for module, depends on module
  ##
  ## Returns the new structure with information about the selected module
  case mType
  of engine:
    result = ModuleData(mType: ModuleType2.engine)
  of cabin:
    result = ModuleData(mType: ModuleType2.cabin)
  of turret:
    result = ModuleData(mType: ModuleType2.turret)
  of gun:
    result = ModuleData(mType: ModuleType2.gun)
  of hull:
    result = ModuleData(mType: ModuleType2.hull)
  of workshop:
    result = ModuleData(mType: ModuleType2.workshop)
  of trainingRoom:
    result = ModuleData(mType: ModuleType2.trainingRoom)
  of batteringRam:
    result = ModuleData(mType: ModuleType2.batteringRam)
  of harpoonGun:
    result = ModuleData(mType: ModuleType2.harpoonGun)
  of medicalRoom:
    result = ModuleData(mType: ModuleType2.medicalRoom)
  of cockpit:
    result = ModuleData(mType: ModuleType2.cockpit)
  of cargoRoom:
    result = ModuleData(mType: ModuleType2.cargoRoom)
  of armor:
    result = ModuleData(mType: ModuleType2.armor)
  of ModuleType2.any:
    result = ModuleData(mType: ModuleType2.any)
  result.name = name
  result.protoIndex = protoIndex
  result.weight = weight
  result.durability = durability
  result.maxDurability = maxDurability
  result.owner = owner
  result.upgradeProgress = upgradeProgress
  result.upgradeAction = upgradeAction
  case mType
  of engine:
    result.fuelUsage = fuelUsage
    result.power = power
    result.disabled = disabled
  of cabin:
    result.cleanliness = cleanliness
    result.quality = quality
  of turret:
    result.gunIndex = gunIndex
  of gun:
    result.damage = damage
    result.ammoIndex = ammoIndex
  of hull:
    result.installedModules = installedModules
    result.maxModules = maxModules
  of workshop:
    result.craftingIndex = craftingIndex
    result.craftingTime = craftingTime
    result.craftingAmount = craftingAmount
    result.craftingQuality = craftingQuality
    result.craftingBonus = craftingBonus
    result.craftingMalus = craftingMalus
  of trainingRoom:
    result.trainedSkill = trainedSkill
  of batteringRam:
    result.damage2 = damage2
    result.coolingDown = coolingDown
  of harpoonGun:
    result.duration = duration
    result.harpoonIndex = harpoonIndex
  of ModuleType2.any:
    result.data = data
  else:
    discard

typeGetterSetter(baseType = ModuleData, varName = module, name = name,
    typ = ModuleName)
typeGetterSetter(baseType = ModuleData, varName = module, name = protoIndex, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module, name = weight, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module, name = durability, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module, name = maxDurability, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module,
    name = upgradeProgress, typ = ExtendedNatural)
typeGetterSetter(baseType = ModuleData, varName = module, name = upgradeAction,
    typ = ShipUpgrade)
typeGetterSetter(baseType = ModuleData, varName = module, name = mType,
    typ = ModuleType2)
typeGetterSetter(baseType = ModuleData, varName = module, name = fuelUsage,
    typ = Positive)
typeGetterSetter(baseType = ModuleData, varName = module, name = power,
    typ = Positive)
typeGetterSetter(baseType = ModuleData, varName = module, name = disabled, typ = bool)
typeGetterSetter(baseType = ModuleData, varName = module, name = cleanliness, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module, name = quality, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module, name = gunIndex,
    typ = ExtendedNatural)
typeGetterSetter(baseType = ModuleData, varName = module, name = damage,
    typ = Positive)
typeGetterSetter(baseType = ModuleData, varName = module, name = ammoIndex,
    typ = ExtendedNatural)
typeGetterSetter(baseType = ModuleData, varName = module,
    name = installedModules, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module, name = maxModules,
    typ = Positive)
typeGetterSetter(baseType = ModuleData, varName = module, name = craftingIndex,
    typ = RecipeIndex)
typeGetterSetter(baseType = ModuleData, varName = module, name = craftingTime, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module, name = craftingAmount, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module,
    name = craftingQuality, typ = ObjectQuality)
typeGetterSetter(baseType = ModuleData, varName = module, name = craftingBonus,
    typ = CraftBonuses)
typeGetterSetter(baseType = ModuleData, varName = module, name = craftingMalus,
    typ = CraftMaluses)
typeGetterSetter(baseType = ModuleData, varName = module, name = trainedSkill, typ = Natural)
typeGetterSetter(baseType = ModuleData, varName = module, name = damage2,
    typ = Positive)
typeGetterSetter(baseType = ModuleData, varName = module, name = coolingDown, typ = bool)
typeGetterSetter(baseType = ModuleData, varName = module, name = duration,
    typ = Positive)
typeGetterSetter(baseType = ModuleData, varName = module, name = harpoonIndex,
    typ = ExtendedNatural)
typeGetterSetter(baseType = ModuleData, varName = module, name = data,
    typ = array[1..3, int])

type
  InventoryData* = object
    ## Used to store information about items in various inventories (cargo, crew
    ## inventory, ect)
    ##
    ## * protoIndex    - The index of the item's prototype
    ## * amount        - The amount of the item in the inventory
    ## * name          - The name of the item, if different than the default one
    ## * durability    - The current durability of the item
    ## * price         - The price for which the item was bought
    ## * quality       - The quality of the item
    ## * craftBonus    - The special crafting bonus for the item
    ## * craftMalus    - The special crafting malus for the item
    protoIndex: Natural = 0
    amount: Positive = 1
    name: ObjectName
    durability: ItemsDurability = 100
    price: Natural = 0
    quality: ObjectQuality = normal
    craftBonus: CraftBonuses = CraftBonuses.none
    craftMalus: CraftMaluses = CraftMaluses.none

proc initInventoryData*(protoIndex: Natural; amount: Positive;
    name: ObjectName = ""; durability: ItemsDurability = 100;
        price: Natural = 0;
    quality: ObjectQuality = normal;
    craftBonus: CraftBonuses = none;
    craftMalus: CraftMaluses = CraftMaluses.none): InventoryData {.raises: [],
    tags: [], contractual.} =
  ## Create a new data structure for the item in an inventory
  ##
  ## * protoIndex    - The index of the prototype item
  ## * amount        - The amount of the item in the inventory
  ## * name          - The name of the item, if different than the default one
  ## * durability    - The current durability of the item
  ## * price         - The price for which the item was bought
  ## * quality       - The quality of the item
  ## * craftBonus    - The special crafting bonus for the item
  ## * craftMalus    - The special crafting malus for the item
  ##
  ## Returns the new structure with information about the selected item
  return InventoryData(protoIndex: protoIndex, amount: amount, name: name,
      durability: durability, price: price,
      quality: quality, craftBonus: craftBonus,
      craftMalus: craftMalus)

typeGetterSetter(baseType = InventoryData, varName = item, name = protoIndex, typ = Natural)
typeGetterSetter(baseType = InventoryData, varName = item, name = amount,
    typ = Positive)
typeGetterSetter(baseType = InventoryData, varName = item, name = name,
    typ = ObjectName)
typeGetterSetter(baseType = InventoryData, varName = item, name = durability,
    typ = ItemsDurability)
typeGetterSetter(baseType = InventoryData, varName = item, name = price, typ = Natural)
typeGetterSetter(baseType = InventoryData, varName = item, name = quality,
    typ = ObjectQuality)
typeGetterSetter(baseType = InventoryData, varName = item, name = craftBonus,
    typ = CraftBonuses)
typeGetterSetter(baseType = InventoryData, varName = item, name = craftMalus,
    typ = CraftMaluses)

type
  MobAttributeRecord* = object
    ## Used to store information about the crew member's attributes
    ##
    ## * level      - The level of the attribute
    ## * experience - The amount of experience in the attribute
    level: range[1..50] = 1
    experience: Natural = 0

proc initMobAttributeRecord*(level: range[1..50] = 1;
    experience: Natural = 0): MobAttributeRecord {.raises: [], tags: [],
    contractual.} =
  ## Create a new data structure for the mob attribute
  ##
  ## * level      - the level of the attribute
  ## * experience - the experience in the selected attribuge
  ##
  ## Returns the new structure with information about the selected attribute
  return MobAttributeRecord(level: level, experience: experience)

typeGetterSetter(baseType = MobAttributeRecord, varName = attribute,
    name = level, typ = range[1..50])
typeGetterSetter(baseType = MobAttributeRecord, varName = attribute,
    name = experience, typ = Natural)

type
  SkillInfo* = object
    ## Used to store information about the crew member's skills
    ##
    ## * index      - The index of the skill
    ## * level      - The level of the skill
    ## * experience - The amount of the experience in the skill
    index: Natural = 0
    level: SkillRange = 0
    experience: Natural = 0

proc initSkillInfo*(index: Natural = 0; level: SkillRange = 0;
    experience: Natural = 0): SkillInfo {.raises: [], tags: [], contractual.} =
  ## Create a new data structure for the mob skills list
  ##
  ## * index      - the index of skill in the skills list
  ## * level      - the level of the skill
  ## * experience - The amount of the experience in the skill
  ##
  ## Returns the new structure with information about the selected skill
  return SkillInfo(index: index, level: level, experience: experience)

typeGetterSetter(baseType = SkillInfo, varName = skill, name = index, typ = Natural)
typeGetterSetter(baseType = SkillInfo, varName = skill, name = level,
    typ = SkillRange)
typeGetterSetter(baseType = SkillInfo, varName = skill, name = experience, typ = Natural)

{.push ruleOff: "objects".}
type
  MemberData* = object
    ## Used to store information about the crew member
    ##
    ## * attributes     - The member's attributes
    ## * skills         - The member's skills
    ## * name           - The member's name
    ## * gender         - The member's gender
    ## * health         - The member's health points
    ## * tired          - The member's tiredness level
    ## * hunger         - The member's hunger level
    ## * thirst         - The member's thirst level
    ## * order          - The current order of the member
    ## * previousOrder  - The previous order of the member
    ## * orderTime      - The amount of minutes to next check in the order
    ## * orders         - The orders priorities for the member
    ## * inventory      - The inventory of the member
    ## * equipment      - The equipment of the member
    ## * payment        - The payment information for the member
    ## * contractLength - The length of the contract with the member
    ## * morale         - The morale information for the member
    ## * loyalty        - The loyalty level of the member
    ## * homeBase       - The index of the home base
    ## * faction        - The faction index to which the member belongs
    attributes*: seq[MobAttributeRecord] = @[]
    skills*: seq[SkillInfo] = @[]
    name: MobName = ""
    gender: char = 'M'
    health: SkillRange = 100
    tired: range[0..150] = 0
    hunger: SkillRange = 0
    thirst: SkillRange = 0
    order: CrewOrders = rest
    previousOrder: CrewOrders = rest
    orderTime: range[-1_000..1_000] = 15
    orders*: array[1..12, Natural]
    inventory*: seq[InventoryData] = @[]
    equipment*: EquipmentArray
    payment*: AttributesArray
    contractLength*: range[-1_000..100_000] = -1
    morale*: AttributesArray
    loyalty: SkillRange = 100
    homeBase: BasesRange = 1
    faction: FactionIndex = ""
{.pop ruleOn: "objects".}

proc initMemberData*(attributes: seq[MobAttributeRecord] = @[]; skills: seq[
    SkillInfo] = @[]; name: MobName = ""; gender: char = 'M';
    health: SkillRange = 100; tired: range[0..150] = 0; hunger: SkillRange = 0;
    thirst: SkillRange = 0; order: CrewOrders = rest;
    previousOrder: CrewOrders = rest; orderTime: range[-1_000..1000] = 15;
        orders: array[1..12,
    Natural] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; inventory: seq[
    InventoryData] = @[]; equipment: EquipmentArray = [-1, -1, -1, -1, -1, -1,
    -1]; payment: AttributesArray = [0, 0]; contractLength: range[
        -1_000..100_000] = -1;
    morale: AttributesArray = [0, 0]; loyalty: SkillRange = 100;
    homeBase: BasesRange = 1;
    faction: FactionIndex = ""): MemberData {.raises: [], tags: [],
    contractual.} =
  ## Create a new data structure for the crew member of the player's ship
  ##
  ## * attributes     - The member's attributes
  ## * skills         - The member's skills
  ## * name           - The member's name
  ## * gender         - The member's gender
  ## * health         - The member's health points
  ## * tired          - The member's tiredness level
  ## * hunger         - The member's hunger level
  ## * thirst         - The member's thirst level
  ## * order          - The current order of the member
  ## * previousOrder  - The previous order of the member
  ## * orderTime      - The amount of minutes to next check in the order
  ## * orders         - The orders priorities for the member
  ## * inventory      - The inventory of the member
  ## * equipment      - The equipment of the member
  ## * payment        - The payment information for the member
  ## * contractLength - The length of the contract with the member
  ## * morale         - The morale information for the member
  ## * loyalty        - The loyalty level of the member
  ## * homeBase       - The index of the home base
  ## * faction        - The faction index to which the member belongs
  ##
  ## Returns the new structure with information about the selected crew member
  return MemberData(attributes: attributes, skills: skills, name: name,
      gender: gender, health: health, tired: tired, hunger: hunger,
      thirst: thirst, order: order, previousOrder: previousOrder,
      orderTime: orderTime, orders: orders, inventory: inventory,
      equipment: equipment, payment: payment, contractLength: contractLength,
      morale: morale, loyalty: loyalty, homeBase: homeBase, faction: faction)

typeGetterSetter(baseType = MemberData, varName = member, name = name, typ = MobName)
typeGetterSetter(baseType = MemberData, varName = member, name = gender, typ = char)
typeGetterSetter(baseType = MemberData, varName = member, name = health,
    typ = SkillRange)
typeGetterSetter(baseType = MemberData, varName = member, name = tired,
    typ = range[0..150])
typeGetterSetter(baseType = MemberData, varName = member, name = hunger,
    typ = SkillRange)
typeGetterSetter(baseType = MemberData, varName = member, name = thirst,
    typ = SkillRange)
typeGetterSetter(baseType = MemberData, varName = member, name = order,
    typ = CrewOrders)
typeGetterSetter(baseType = MemberData, varName = member, name = previousOrder,
    typ = CrewOrders)
typeGetterSetter(baseType = MemberData, varName = member, name = orderTime,
    typ = range[-1_000..1_000])
typeGetterSetter(baseType = MemberData, varName = member, name = contractLength,
    typ = range[-1_000..100_000])
typeGetterSetter(baseType = MemberData, varName = member, name = loyalty,
    typ = SkillRange)
typeGetterSetter(baseType = MemberData, varName = member, name = homeBase,
    typ = BasesRange)
typeGetterSetter(baseType = MemberData, varName = member, name = faction,
    typ = FactionIndex)

{.push ruleOff: "objects".}
type
  ShipRecord* = object
    ## Used to store information about ships
    ##
    ## * name          - The name of the ship
    ## * skyX          - The X position of the ship on the map
    ## * skyY          - The Y position of the ship on the map
    ## * speed         - The current setting for the ship's speed
    ## * modules       - The list of modules installed on the ship
    ## * cargo         - The list of items in the ship's cargo
    ## * crew          - The list of the crew members of the ship
    ## * upgradeModule - The index of the currently upgraded module
    ## * destinationX  - The X position to which the ship goes
    ## * destinationY  - The Y position to which the ship goes
    ## * repairModule  - The index of module which will be repaired as first
    ## * description   - The description of the ship
    ## * homeBase      - The index of the home base of the ship
    name: ShipName = ""
    skyX: MapXRange = 1
    skyY: MapYRange = 1
    speed: ShipSpeed = fullSpeed
    modules*: seq[ModuleData] = @[]
    cargo*: seq[InventoryData] = @[]
    crew*: seq[MemberData] = @[]
    upgradeModule: ExtendedNatural = -1
    destinationX: range[0..MapXRange.high] = 0
    destinationY: range[0..MapYRange.high] = 0
    repairModule: ExtendedNatural = -1
    description: Description = ""
    homeBase: Natural = 0
{.pop ruleOn: "objects".}

proc initShipRecord*(name: ShipName = ""; skyX: MapXRange = 1;
    skyY: MapYRange = 1; speed: ShipSpeed = fullSpeed; modules: seq[
    ModuleData] = @[]; cargo: seq[InventoryData] = @[]; crew: seq[
    MemberData] = @[]; upgradeModule: ExtendedNatural = -1; destinationX: range[
    0..MapXRange.high] = 0; destinationY: range[0..MapYRange.high] = 0;
    repairModule: ExtendedNatural = -1; description: Description = "";
    homeBase: Natural = 0): ShipRecord {.raises: [], tags: [], contractual.} =
  ## Create a new data structure for the selected ship
  ##
  ## * name          - The name of the ship
  ## * skyX          - The X position of the ship on the map
  ## * skyY          - The Y position of the ship on the map
  ## * speed         - The current setting for the ship's speed
  ## * modules       - The list of modules installed on the ship
  ## * cargo         - The list of items in the ship's cargo
  ## * crew          - The list of the crew members of the ship
  ## * upgradeModule - The index of the currently upgraded module
  ## * destinationX  - The X position to which the ship goes
  ## * destinationY  - The Y position to which the ship goes
  ## * repairModule  - The index of module which will be repaired as first
  ## * description   - The description of the ship
  ## * homeBase      - The index of the home base of the ship
  ##
  ## Returns the new structure with information about the selected crew member
  return ShipRecord(name: name, skyX: skyX, skyY: skyY, speed: speed,
      modules: modules, cargo: cargo, crew: crew, upgradeModule: upgradeModule,
      destinationX: destinationX, destinationY: destinationY,
      repairModule: repairModule, description: description, homeBase: homeBase)

typeGetterSetter(baseType = ShipRecord, varName = ship, name = name,
    typ = ShipName)
typeGetterSetter(baseType = ShipRecord, varName = ship, name = skyX,
    typ = MapXRange)
typeGetterSetter(baseType = ShipRecord, varName = ship, name = skyY,
    typ = MapYRange)
typeGetterSetter(baseType = ShipRecord, varName = ship, name = speed,
    typ = ShipSpeed)
typeGetterSetter(baseType = ShipRecord, varName = ship, name = upgradeModule,
    typ = ExtendedNatural)
typeGetterSetter(baseType = ShipRecord, varName = ship, name = destinationX,
    typ = range[0..MapXRange.high])
typeGetterSetter(baseType = ShipRecord, varName = ship, name = destinationY,
    typ = range[0..MapYRange.high])
typeGetterSetter(baseType = ShipRecord, varName = ship, name = repairModule,
    typ = ExtendedNatural)
typeGetterSetter(baseType = ShipRecord, varName = ship, name = description,
    typ = Description)
typeGetterSetter(baseType = ShipRecord, varName = ship, name = homeBase, typ = Natural)

type
  ReputationRanges* = object
    ## Used to store reputation ranges for relation with other factions
    ##
    ## * min - Minimal reputation with the selected faction
    ## * max - Maximal reputation with the selected faction
    min: ReputationRange
    max: ReputationRange

proc initReputationRanges*(min: ReputationRange = 0;
    max: ReputationRange = 0): ReputationRanges {.raises: [], tags: [],
    contractual.} =
  ## Create a new data structure for a reputation
  ##
  ## * min - Minimal reputation with the selected faction
  ## * max - Maximal reputation with the selected faction
  ##
  ## Returns the new structure with information about the reputation
  return ReputationRanges(min: min, max: max)

typeGetterSetter(baseType = ReputationRanges, varName = reputation, name = min,
    typ = ReputationRange)
typeGetterSetter(baseType = ReputationRanges, varName = reputation, name = max,
    typ = ReputationRange)

type
  RelationsData* = object
    ## Used to store data about relation with other faction
    ##
    ## * reputation - Values of min and max reputation with the faction
    ## * friendly   - If true, the selected faction is friendly towards the faction
    reputation: ReputationRanges
    friendly: bool

proc initRelationsData*(reputation: ReputationRanges = initReputationRanges();
    friendly: bool = true): RelationsData {.raises: [], tags: [],
    contractual.} =
  ## Create a new data structure for a factions relations
  ##
  ## * reputation - Values of min and max reputation with the faction
  ## * friendly   - If true, the selected faction is friendly towards the faction
  ##
  ## Returns the new structure with information about the relations between factions
  return RelationsData(reputation: reputation, friendly: friendly)

typeGetterSetter(baseType = RelationsData, varName = relation,
    name = reputation, typ = ReputationRanges)
typeGetterSetter(baseType = RelationsData, varName = relation, name = friendly, typ = bool)

type
  CareerData* = object
    ## Used to store data about careers available for the faction
    ##
    ## * shipIndex   - The index of the starting ship prototype for the career
    ## * playerIndex - The index of the starting mob prototype as the player character
    ## * description - The description of the career
    ## * name        - The name of the career
    shipIndex: ShipIndex
    playerIndex: MobIndex
    description: Description
    name: CareerName

proc initCareerData*(shipIndex: ShipIndex = 1; playerIndex: MobIndex = "";
    description: Description = "";
    name: CareerName = ""): CareerData {.raises: [], tags: [], contractual.} =
  ## Create a new data structure for the player's career
  ##
  ## * shipIndex   - The index of the starting ship prototype for the career
  ## * playerIndex - The index of the starting mob prototype as the player character
  ## * description - The description of the career
  ## * name        - The name of the career
  ##
  ## Returns the new structure with information about the selected career
  return CareerData(shipIndex: shipIndex, playerIndex: playerIndex,
      description: description, name: name)

typeGetterSetter(baseType = CareerData, varName = career, name = shipIndex,
    typ = ShipIndex)
typeGetterSetter(baseType = CareerData, varName = career, name = playerIndex,
    typ = MobIndex)
typeGetterSetter(baseType = CareerData, varName = career, name = description,
    typ = Description)
typeGetterSetter(baseType = CareerData, varName = career, name = name,
    typ = CareerName)

{.push ruleOff: "objects".}
type
  FactionData* = object
    ## Used to store data about the selected faction
    ##
    ## * name             - The name of the faction
    ## * memberName       - The name of members of the faction
    ## * pluralMemberName - The name for plural amount of members of the faction
    ## * spawnChance      - The chance of the spawn for a base of the selected faction
    ## * population       - The min and max population for new bases of the faction
    ## * namesType        - The type of names for the mobs, bases and ships of the faction
    ## * relations        - The faction's relations with other factions
    ## * description      - The description of the faction
    ## * foodTypes        - The types of items used as food for the faction's members
    ## * drinksTypes      - The types of items used as drinks for the faction's members
    ## * healingTools     - The type of items used as healing tools for the faction's members
    ## * healingSkill     - The skill used as healing skill for the faction's members
    ## * flags            - Various flags set for the faction
    ## * careers          - The list of available careers for the faction
    ## * baseIcon         - The icon used as icon for the faction's bases on the map
    ## * basesTypes       - The list of available bases types for the faction
    ## * weaponSkill      - The skill used as prefered weapon skill for the faction
    name: FactionName
    memberName: FactionMemberName
    pluralMemberName: FactionMemberName
    spawnChance: Natural
    population*: AttributesArray
    namesType: NamesTypes
    relations*: Table[string, RelationsData]
    description: Description
    foodTypes*: seq[string]
    drinksTypes*: seq[string]
    healingTools: SettingString
    healingSkill: Natural
    flags*: seq[string]
    careers*: Table[string, CareerData]
    baseIcon: Natural
    basesTypes*: Table[string, Positive]
    weaponSkill: Natural
{.pop ruleOn: "objects".}

proc initFactionData*(name: FactionName = "";
    memberName: FactionMemberName = "";
    pluralMemberName: FactionMemberName = ""; spawnChance: Natural = 0;
    population: AttributesArray = [0, 0]; namesType: NamesTypes = normal;
    relations: Table[string, RelationsData] = initTable[string, RelationsData]();
    description: Description = ""; foodTypes: seq[string] = @[];
    drinksTypes: seq[string] = @[]; healingTools: SettingString = "";
    healingSkill: Natural = 0; flags: seq[string] = @[]; careers: Table[string,
    CareerData] = initTable[string, CareerData](); baseIcon: Natural = 0;
    basesTypes: Table[string, Positive] = initTable[string, Positive]();
    weaponSkill: Natural = 0): FactionData {.raises: [], tags: [],
    contractual.} =
  ## Create a new data structure for the in-game faction
  ##
  ## * name             - The name of the faction
  ## * memberName       - The name of members of the faction
  ## * pluralMemberName - The name for plural amount of members of the faction
  ## * spawnChance      - The chance of the spawn for a base of the selected faction
  ## * population       - The min and max population for new bases of the faction
  ## * namesType        - The type of names for the mobs, bases and ships of the faction
  ## * relations        - The faction's relations with other factions
  ## * description      - The description of the faction
  ## * foodTypes        - The types of items used as food for the faction's members
  ## * drinksTypes      - The types of items used as drinks for the faction's members
  ## * healingTools     - The type of items used as healing tools for the faction's members
  ## * healingSkill     - The skill used as healing skill for the faction's members
  ## * flags            - Various flags set for the faction
  ## * careers          - The list of available careers for the faction
  ## * baseIcon         - The icon used as icon for the faction's bases on the map
  ## * basesTypes       - The list of available bases types for the faction
  ##
  ## Returns the new structure with information about the selected faction
  return FactionData(name: name, memberName: memberName,
      pluralMemberName: pluralMemberName, spawnChance: spawnChance,
      population: population, namesType: namesType, relations: relations,
      description: description, foodTypes: foodTypes, drinksTypes: drinksTypes,
      healingTools: healingTools, healingSkill: healingSkill, flags: flags,
      careers: careers, baseIcon: baseIcon, basesTypes: basesTypes,
      weaponSkill: weaponSkill)

typeGetterSetter(baseType = FactionData, varName = faction, name = name,
    typ = FactionName)
typeGetterSetter(baseType = FactionData, varName = faction, name = memberName,
    typ = FactionMemberName)
typeGetterSetter(baseType = FactionData, varName = faction,
    name = pluralMemberName, typ = FactionMemberName)
typeGetterSetter(baseType = FactionData, varName = faction, name = spawnChance, typ = Natural)
typeGetterSetter(baseType = FactionData, varName = faction, name = namesType,
    typ = NamesTypes)
typeGetterSetter(baseType = FactionData, varName = faction, name = description,
    typ = Description)
typeGetterSetter(baseType = FactionData, varName = faction, name = healingTools,
    typ = SettingString)
typeGetterSetter(baseType = FactionData, varName = faction, name = healingSkill, typ = Natural)
typeGetterSetter(baseType = FactionData, varName = faction, name = baseIcon, typ = Natural)
typeGetterSetter(baseType = FactionData, varName = faction, name = weaponSkill, typ = Natural)

{.push ruleOff: "objects".}
type
  ObjectData* = object
    ## Used to store information about items
    ##
    ## * name        - The name of the item
    ## * weight      - The weight of the item
    ## * itemType    - The type of the item
    ## * price       - The base price of the item in bases
    ## * value       - Various data related to the item (damage for ammo, etc.)
    ## * showType    - The item's type to show to the player instead of the itemType
    ## * description - The description of the item
    ## * reputation  - The minumal reputation which is needed to buy that item
    name: ObjectName
    weight: Positive
    itemType: ItemType
    price: Natural
    value*: array[1..5, int]
    showType: ItemType
    description: Description
    reputation: ReputationRange
{.pop ruleOn: "objects".}

proc initObjectData*(name: ObjectName = ""; weight: Positive = 1;
    itemType: ItemType = ""; price: Natural = 0; value: array[1..5, int] = [0,
    0, 0, 0, 0]; showType: ItemType = ""; description: Description = "";
    reputation: ReputationRange = 0): ObjectData {.raises: [], tags: [],
    contractual.} =
  ## Create a new data structure for an item
  ##
  ## * name        - The name of the item
  ## * weight      - The weight of the item
  ## * itemType    - The type of the item
  ## * price       - The base price of the item in bases
  ## * value       - Various data related to the item (damage for ammo, etc.)
  ## * showType    - The item's type to show to the player instead of the itemType
  ## * description - The description of the item
  ## * reputation  - The minumal reputation which is needed to buy that item
  ##
  ## Returns the new structure with information about the selected item
  return ObjectData(name: name, weight: weight, itemType: itemType,
      price: price, value: value, showType: showType, description: description,
      reputation: reputation)

typeGetterSetter(baseType = ObjectData, varName = obj, name = name,
    typ = ObjectName)
typeGetterSetter(baseType = ObjectData, varName = obj, name = weight,
    typ = Positive)
typeGetterSetter(baseType = ObjectData, varName = obj, name = itemType,
    typ = ItemType)
typeGetterSetter(baseType = ObjectData, varName = obj, name = price,
    typ = Natural)
typeGetterSetter(baseType = ObjectData, varName = obj, name = showType,
    typ = ItemType)
typeGetterSetter(baseType = ObjectData, varName = obj, name = description,
    typ = Description)
typeGetterSetter(baseType = ObjectData, varName = obj, name = reputation,
    typ = ReputationRange)

type
  RecruitItem* = object
    ## Used to store information about a recruit's inventory
    ##
    ## * index   - the index of the item's prototype
    ## * quality - the quality of the item
    index: Positive = 1
    quality: ObjectQuality = normal

proc initRecruitItem*(index: Positive = 1;
    quality: ObjectQuality = normal): RecruitItem {.raises: [], tags: [],
    contractual.} =
  ## Create a new data structure for a recruit's item
  ##
  ## * index   - the index of the item's prototype
  ## * quality - the quality of the item
  ##
  ## Returns the new structure with information about the selected item
  return RecruitItem(index: index, quality: quality)

typeGetterSetter(baseType = RecruitItem, varName = item, name = index,
    typ = Positive)
typeGetterSetter(baseType = RecruitItem, varName = item, name = quality,
    typ = ObjectQuality)

type
  RecruitData* = object
    ## Used to store information about the recruit in bases
    ##
    ## * attributes - The recruit's attributes
    ## * skills     - The recruit's skills
    ## * name       - The recruit's name
    ## * gender     - The recruit's gender
    ## * price      - The cost of hire of the recruit
    ## * inventory  - The inventory of the recruit
    ## * equipment  - The equipment of the recruit
    ## * payment    - The payment information for the recruit
    ## * homeBase   - The index of the home base
    ## * faction    - The faction index to which the recruit belongs
    attributes*: seq[MobAttributeRecord]
    skills*: seq[SkillInfo]
    name*: MobName
    gender*: char
    price*: Positive = 1
    inventory*: seq[RecruitItem]
    equipment*: EquipmentArray
    payment*: Positive = 1
    homeBase*: BasesRange = 1
    faction*: FactionName

proc initRecruitData*(attributes: seq[MobAttributeRecord] = @[]; skills: seq[
    SkillInfo] = @[]; name: MobName = ""; gender: char = 'M';
    price: Positive = 1; inventory: seq[RecruitItem] = @[];
    equipment: EquipmentArray = [-1, -1, -1, -1, -1, -1, -1];
    payment: Positive = 1): RecruitData {.raises: [], tags: [], contractual.} =
  ## Create a new data structure for a recruit
  ##
  ## * attributes - The recruit's attributes
  ## * skills     - The recruit's skills
  ## * name       - The recruit's name
  ## * gender     - The recruit's gender
  ## * price      - The cost of hire of the recruit
  ## * inventory  - The inventory of the recruit
  ## * equipment  - The equipment of the recruit
  ## * payment    - The payment information for the recruit
  ##
  ## Returns the new structure with information about the selected recruit
  return RecruitData(attributes: attributes, skills: skills, name: name,
      gender: gender, price: price, inventory: inventory, equipment: equipment,
      payment: payment)

type
  BaseCargo* = object
    ## Used to store information about items in bases cargo
    ##
    ## * protoIndex    - The index of the item's prototype
    ## * amount        - The amount of the item in the inventory
    ## * durability    - The current durability of the item
    ## * price         - The price for which the item was bought
    ## * quality       - The quality of the item
    ## * craftFeature  - The special feature of the item set during crafting it
    protoIndex*: Natural
    amount*: Natural
    durability*: ItemsDurability = 100
    price*: Natural
    quality*: ObjectQuality = normal
    craftBonus*: CraftBonuses = CraftBonuses.none
    craftMalus*: CraftMaluses = CraftMaluses.none

  DateRecord* = object
    ## Used to store the game's time
    ##
    ## * year    - The game's year
    ## * month   - The game's month
    ## * day     - The game's day
    ## * hour    - The game's hour
    ## * minutes - The game's minutes
    year*: range[0..4_000_000] = 0
    month*: range[0..24] = 0
    day*: range[0..62] = 0
    hour*: range[0..48] = 0
    minutes*: range[0..120] = 0

  ReputationData* = object
    ## Used to store information about the level of the player's reputation
    ##
    ## * level      - The level of the reputation
    ## * experience - The current experience gained in the reputation
    level*: ReputationRange
    experience*: Natural

  MissionData* = object
    ## Used to store information about missions
    ##
    ## * mType      - The type of the mission
    ## * time       - The amount of minutes to finish the mission
    ## * targetX    - The X position of the target on the map
    ## * targetY    - The Y position of the target on the map
    ## * reward     - The amount of money as the reward for the mission
    ## * startBase  - The index of the starting base for the mission
    ## * finished   - If true, the mission is ready to return, otherwise false
    ## * multiplier - The multiplier for the mission reward money and reputation
    ## * itemIndex  - The index of the proto item to deliver
    ## * data       - The minumum quality of the cabin (in bases) or passenger index (in accepted)
    ## * shipIndex  - The index of the prototype ship to destroy
    ## * target     - The target for the mission (ship, item)
    time*: Positive = 1
    targetX*: range[0..MapXRange.high]
    targetY*: range[0..MapYRange.high]
    reward*: Positive = 1
    startBase*: BasesRange = 1
    finished*: bool
    multiplier*: RewardMultiplier
    case mType*: MissionsTypes
    of deliver:
      itemIndex*: Natural
    of passenger:
      data*: Natural
    of destroy:
      shipIndex*: Natural
    else:
      target*: Natural

  BaseRecord* = object
    ## Used to store information about bases
    ##
    ## * name           - The name of the base
    ## * visited        - The date when the base was last visited
    ## * skyX           - The X position of the base on the map
    ## * skyY           - The Y position of the base on the map
    ## * baseType       - The type of the base
    ## * population     - The amount of people living in the base
    ## * recruitDate    - The date when recruits were last checked
    ## * recruits       - The list of recruits available in the base
    ## * known          - If true, the base is known to the player, otherwise false
    ## * askedForBases  - If true, the player asked for other bases in the base
    ## * askedForEvents - The date when the player asked for event last time
    ## * reputation     - The player's reputation in the base
    ## * missionsDate   - The date when the player last checked missions in the base
    ## * missions       - The list of available missions in the base
    ## * owner          - The index of faction which owe the base
    ## * cargo          - The base's cargo
    ## * size           - The size of the base
    name*: string
    visited*: DateRecord
    skyX*: MapXRange
    skyY*: MapYRange
    baseType*: BaseType
    population*: Natural
    recruitDate*: DateRecord
    recruits*: seq[RecruitData]
    known*: bool
    askedForBases*: bool
    askedForEvents*: DateRecord
    reputation*: ReputationData
    missionsDate*: DateRecord
    missions*: seq[MissionData]
    owner*: FactionIndex
    cargo*: seq[BaseCargo]
    size*: BasesSize

  BaseModuleData* = object
    ## Used to store information about prototypes of ships' modules
    ##
    ## * name           - The name of the module
    ## * mType          - The type of the module
    ## * weight         - The weight of the module
    ## * value          - Additional data for the module, for engines it is power
    ## * maxValue       - Additional data for the mode, for guns it is damage
    ## * durability     - The base durability of the module
    ## * repairMaterial - The index of the material used to repair the module
    ## * repairSkill    - The index of the skill used to repair the module
    ## * price          - The base price of the module in shipyards
    ## * installTime    - The amount of time needed to install the module
    ## * unique         - If true, only one that module can be installed on the ship
    ## * size           - The size of the module
    ## * description    - The description of the module
    ## * maxOwners      - The amount of users of the module
    ## * speed          - How fast the gun shoots in the combat
    ## * reputation     - The minumum amount of reputation needed for buy the module
    name*: string
    mType*: ModuleType
    weight*: Natural
    value*: int
    maxValue*: int
    durability*: int
    repairMaterial*: string
    repairSkill*: Positive
    price*: Natural
    installTime*: Positive
    unique*: bool
    size*: range[1..10]
    description*: string
    maxOwners*: range[0..10]
    speed*: int
    reputation*: ReputationRange

  CraftData* = object
    ## Used to store information about crafting recipes
    ##
    ## * materialTypes   - The list of materials types used in crafting
    ## * materialAmounts - The list of materials amount used in crafting
    ## * resultIndex     - The index of proto item which is the result of the recipe
    ## * resultAmount    - The amount of items produced by one recipe
    ## * workplace       - The type of ship's module used as a workshop for the recipe
    ## * skill           - The index of the skill used in crafting
    ## * time            - The amount of minutes needed to finish the recipe
    ## * difficulty      - The difficulty level of the recipe
    ## * tool            - The type of item used as a tool in crafting
    ## * reputation      - The minimal amount of reputation needed to buy the recipe in bases
    ## * toolQuality     - The minimal quality of tool used in crafting
    materialTypes*: seq[string] = @[]
    materialAmounts*: seq[Positive] = @[]
    resultIndex*: Natural = 0
    resultAmount*: Natural = 0
    workplace*: ModuleType = alchemyLab
    skill*: Natural = 0
    time*: Positive = 1
    difficulty*: Positive = 1
    tool*: SettingString = ""
    reputation*: ReputationRange = 0
    toolQuality*: Positive = 1

  GoalData* = object
    ## Used to store information about the in-game goals
    ##
    ## * index       - The index of the goal prototype
    ## * goalType    - The type of the goal
    ## * amount      - The amount of targets needed for finishe the goal
    ## * targetIndex - The index of the target needed for finish the goal. If empty
    ##                 means all targets of the selected type (bases, ships, etc.)
    ## * multiplier  - The muliplier for points awarded for finishing the goal
    index*: string
    goalType*: GoalTypes
    amount*: Natural
    targetIndex*: string
    multiplier*: Positive

  MessageData* = object
    ## Used to store data about the game's messages
    ##
    ## * message - The message itself
    ## * kind    - The type of message
    ## * color   - The color used to show the message
    message*: MessageText
    kind*: MessageType
    color*: MessageColor

  EventData* = object
    ## Used to store data about an event
    ##
    ## * eType     - The type of the event
    ## * skyX      - The X coordinate of the event on the map
    ## * skyY      - The Y coordinate of the event on the map
    ## * time      - The time in minutes by how long the event will be available
    ## * itemIndex - The index of the prototype item used by the event
    ## * shipIndex - The index of the prototype ship used by the event
    ## * data      - General data of the event
    skyX*: MapXRange = 1
    skyY*: MapYRange = 1
    time*: Positive = 1
    case eType*: EventsTypes
    of doublePrice:
      itemIndex*: int
    of attackOnBase, enemyShip, enemyPatrol, trader, friendlyShip:
      shipIndex*: int
    else:
      data*: int

  MobInventoryRecord* = object
    ## Used to store data about the inventory of the mob's prototype
    ##
    ## * protoIndex - The index of the item's prototype
    ## * minAmount  - The minimal amount of the item
    ## * maxAmount  - The maximum amount of the item
    protoIndex*: Natural
    minAmount*: Natural
    maxAmount*: Natural

  ShipBonusData* = object
    ## Used to store data for proto ships bonuses, like accuracy, evasion, etc
    ##
    ## * minValue - The minimum value of the bonus
    ## * maxValue - The maximum value of the bonus
    minValue*: Natural
    maxValue*: Natural

  ProtoMemberData* = object
    ## Used to store data about the crew member in prototypes of ships
    ##
    ## * protoIndex - The index of mob's prototype which will be used to create the crew member
    ## * minAmount  - The minimum amount of the mob as crew members on the ship
    ## * maxAmount  - The maximum amount of the mob as crew members on the ship
    protoIndex*: Positive = 1
    minAmount*: Positive = 1
    maxAmount*: Natural = 0

  ProtoShipData* = object
    ## Used to store data about the prototype of the ship
    ##
    ## * name         - The name of the prototype
    ## * modules      - The list of installed modules
    ## * accuracy     - The accuracy bonus for the ship
    ## * combatAi     - The combat behaviour of the ship
    ## * evasion      - The evasion bonus for the ship
    ## * loot         - The amount of money looted from the ship
    ## * perception   - The perception bonus for the ship
    ## * cargo        - The cargo of the ship
    ## * combatValue  - The combat strength of the ship (used to generate enemies)
    ## * crew         - The crew of the ship
    ## * description  - The ship's description
    ## * owner        - The faction to which the ship belongs
    ## * knownRecipes - The list of known recipes (used only by the player's ship)
    ## * reputation   - The level of reputation at which the ship will appear.
    ##                  an enemy, it is negative value, for friendly positive
    name*: string
    modules*: seq[Positive]
    accuracy*: ShipBonusData
    combatAi*: ShipCombatAi
    evasion*: ShipBonusData
    loot*: ShipBonusData
    perception*: ShipBonusData
    cargo*: seq[MobInventoryRecord]
    combatValue*: Positive
    crew*: seq[ProtoMemberData]
    description*: string
    owner*: FactionIndex
    knownRecipes*: seq[string]
    reputation*: Natural

  ProtoMobRecord* = object
    ## Used to store data about mobs prototypes
    ##
    ## * attributes - The mob's attributes
    ## * skills     - The mob's skills
    ## * order      - The current order of the mob
    ## * priorities - The orders priorities of the mob
    ## * inventory  - The inventory of the mob
    ## * equipment  - The equipment of the mob
    attributes*: seq[MobAttributeRecord]
    skills*: seq[SkillInfo]
    order*: CrewOrders
    priorities*: array[1..12, Natural]
    inventory*: seq[MobInventoryRecord]
    equipment*: EquipmentArray

  EnemyRecord* = object
    ## Used to store information about the enemy
    ##
    ## * ship            - The enemy's ship
    ## * accuracy        - The enemy's bonus to accuracy
    ## * distance        - The distance to the enemy's ship in combat
    ## * combatAi        - The type of enemy's AI
    ## * evasion         - The enemy's bonus to evasion
    ## * loot            - The amount of money looted from the enemy after win
    ##                     the fight with it
    ## * perception      - The enemy's bonus to perception
    ## * harpoonDuration - How long in combat rounds the enemy's ship will be
    ##                     stopped by the player's harpoon
    ## * guns            - The list of guns on the enemy's ship, 0 - gun index
    ##                     in ship modules list, 1 - gunner order, 2 - amount
    ##                     of shoots from the gun, value below zero means that
    ##                     gun shoot once per that amount of rounds
    ship*: ShipRecord
    accuracy*: Natural
    distance*: int
    combatAi*: ShipCombatAi
    evasion*: Natural
    loot*: Natural
    perception*: Natural
    harpoonDuration*: Natural
    guns*: seq[array[1..3, int]]
