// ################################
// ##   Tridy na hracske ucty    ##
// ##  obsahuji vedu a podobne   ##
// ################################

#include "players_realms.h"

#include "error_handling.h"

#include "fortress_skelet.h"

// ################################
// ################################

#ifdef _DEBUG
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif
#endif

// ###############################
// ###############################

playerAddingResult realmClass::createNewPlayer(string name, string login, string password, unsigned long basesCount, double basesQualityRating, unsigned long shipsCount, double shipsQualityRating, double scienceQualityRating)
{
	if (!(actx->startingPlanet))
	{
		errExceptionError("NULL startingPlanet.");
		return PAR_INTERNAL_ERROR;
	}
	spaceSunObject * startingStar = actx->cacheSpaceObjectList.getItem<spaceSunObject>(actx->startingPlanet->getStarSystem());
	if (!startingStar)
	{
		errLogicalError("Starting planet in freespace (not in star system).");
		return PAR_INTERNAL_ERROR;
	}
	if (0 == basesCount)
	{
		errLogicalError("Canceled attempt to register new player without any bases.");
		return PAR_INTERNAL_ERROR;
	}
    if (actx->cacheRealmsList.loginExists(login))
    {
        return PAR_LOGIN_ALREADY_EXISTS;
    }
    if (actx->cacheRealmsList.nameExists(name))
    {
        return PAR_NAME_ALREADY_EXISTS;
    }

	basesQualityRating   = max(0, min(1, basesQualityRating  ));
	shipsQualityRating   = max(0, min(1, shipsQualityRating  ));
	scienceQualityRating = max(0, min(1, scienceQualityRating));

	fortressClassClass * newBaseClass = NULL;
	for (dtIdentifier loop1 = 1; loop1 < actx->cacheFortressClassesList.getSize(); loop1++)
	{
		fortressClassClass * actualFortressClass = actx->cacheFortressClassesList.getItem<fortressClassClass>(loop1);
		if ((FT_BASE == actualFortressClass->getClassType()               ) &&
			(basesQualityRating >= actualFortressClass->getQualityRating()))
		{
			if ((!newBaseClass                                                             ) ||
				(newBaseClass->getQualityRating() < actualFortressClass->getQualityRating()))
			{
				newBaseClass = actualFortressClass;
			}
		}
	}
	if (!newBaseClass)
	{
		return PAR_INTERNAL_ERROR;
	}

	fortressClassClass * newShipClass = NULL;
	for (dtIdentifier loop1 = 1; loop1 < actx->cacheFortressClassesList.getSize(); loop1++)
	{
		fortressClassClass * actualFortressClass = actx->cacheFortressClassesList.getItem<fortressClassClass>(loop1);
		if ((FT_SHIP == actualFortressClass->getClassType()               ) &&
			(shipsQualityRating >= actualFortressClass->getQualityRating()))
		{
			if ((!newShipClass                                                             ) ||
				(newShipClass->getQualityRating() < actualFortressClass->getQualityRating()))
			{
				newShipClass = actualFortressClass;
			}
		}
	}
	if (!newShipClass)
	{
		return PAR_INTERNAL_ERROR;
	}

	realmClass * newPlayer = new realmClass();
	newPlayer->setPlayersNewName(name    );
	newPlayer->setNewLogin      (login   );
	newPlayer->setNewPassword   (password);

	newPlayer->discoverNewStar(actx->startingPlanet->getParentSpaceObject());

	newPlayer->science_.setWholeTreeLevelForNewPlayer(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL);

	dtIdentifier newPlayerID = actx->cacheRealmsList.insertItem(newPlayer);


	// tvorba bazi
	baseClass     * dockingBase           = NULL;
	unsigned long   dockingHangarPosition = 0   ;
	for (unsigned long loop1 = 0; loop1 < basesCount; loop1++)
	{
		unsigned long long buildingTitanium = newBaseClass->getMinWeight() + ullRound((double)(newBaseClass->getMaxWeight() - newBaseClass->getMinWeight()) * basesQualityRating);
		unsigned long      weaponsCount     = newBaseClass->getMaxWeapons();
		unsigned long      launchersCount   = newBaseClass->getMaxDroneMissileLaunchers();
		unsigned long      gunsCount        = newBaseClass->getMaxLaserGuns();
		unsigned long      hangarsCount     = shipsCount + 1;
		while ((weaponsCount) < (launchersCount + gunsCount))
		{
			if (flipACoin())
			{
				if (0 < launchersCount)
				{
					launchersCount--;
				}
			}
			else
			{
				if (0 < gunsCount)
				{
					gunsCount--;
				}
			}
		}

		baseClass * newBase = (baseClass *)(newBaseClass->deriveNewFortress(NULL, buildingTitanium, 1));
		if (!newBase)
		{
			errExceptionError("Starting base wasn't created because of nonsense NULL derived from baseClass.");
			return PAR_INTERNAL_ERROR;
		}
		actx->cacheFortressesList.insertItem(newBase);
		newBase->addIDBehindName();
		if (0 == spaceFortressObject::createWithFortress(actx->startingPlanet->getID(), newBase))
		{
			errLogicalError("Can't link base (ID %u) with planet (ID %u).", (unsigned long long)newBase->getID(), (unsigned long long)actx->startingPlanet->getID());
			return PAR_INTERNAL_ERROR;
		};
		newPlayer->addUncontrollableFortress(newBase);

		// mainframe
		itemsPatternClass * mainframePattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_MAINFRAME);
		newBase->mainframeSystem.changeMainframe(actx->cacheItemsList.insertItem(new mainframeClass(
			mainframePattern->getMaxWeight(),
			BIONODES_FOR_ONE_FORTRESS * (basesCount + shipsCount),
			ulNumberFromScale(RANGE_MAINFRAME_PREDICTION_MIN, RANGE_MAINFRAME_PREDICTION_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_MAINFRAME_TIME_REUSABILITY_MIN, RANGE_MAINFRAME_TIME_REUSABILITY_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_MAINFRAME_CONSUMPTION_MIN, RANGE_MAINFRAME_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newBase->mainframeSystem.mainframeEnergyDivision.maxPowerDrain = newBase->mainframeSystem.mainframe()->maxPossibleConsumption();

		// energeticky akumulator
		itemsPatternClass * energeticAccumulatorPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_ENERGETIC_ACCUMULATOR);
		newBase->energeticSystem.changeEnergeticAccumulator(actx->cacheItemsList.insertItem(new energeticAccumulatorClass(
			ulNumberFromScale(energeticAccumulatorPattern->getMinWeight(), energeticAccumulatorPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ullNumberFromScale(RANGE_ENERGETIC_ACCUMULATOR_ACCUMULATOR_MIN, RANGE_ENERGETIC_ACCUMULATOR_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_ENERGETIC_ACCUMULATOR_CHARGING_MIN, RANGE_ENERGETIC_ACCUMULATOR_CHARGING_MAX, (double)1, scienceQualityRating))));
		newBase->energeticSystem.energeticAccumulatorEnergyState.energy = newBase->energeticSystem.energeticAccumulator()->actualAccumulator();

		// stity
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_SHIELDS <= scienceQualityRating)
		{
			itemsPatternClass * deflectorShieldsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_DEFLECTOR_SHIELDS);
			newBase->deflectorShields.mountDeflectorShieldsGenerator(actx->cacheItemsList.insertItem(new deflectorShieldsGeneratorClass(
				ulNumberFromScale(deflectorShieldsPattern->getMinWeight(), deflectorShieldsPattern->getMaxWeight(), (double)1, scienceQualityRating),
				ulRound((double)MAX_TOTAL_SCIENCE_LEVEL * scienceQualityRating),
				ulNumberFromScale(RANGE_DEFLECTOR_SHIELDS_ACCUMULATOR_MIN, RANGE_DEFLECTOR_SHIELDS_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_DEFLECTOR_SHIELDS_CHARGING_MIN, RANGE_DEFLECTOR_SHIELDS_CHARGING_MAX, (double)1, scienceQualityRating),
				(double)ulNumberFromScale(RANGE_DEFLECTOR_SHIELDS_ACCUMULATOR_MIN, RANGE_DEFLECTOR_SHIELDS_ACCUMULATOR_MAX, (double)1, scienceQualityRating) * DEFLECTOR_SHIELDS_LEAK_TO_ACCUMULATOR))); 
			newBase->deflectorShields.deflectorsEnergyDivision.maxPowerDrain   = newBase->deflectorShields.deflectorShieldsGenerator()->maxPossibleConsumption();
		}

		// zbranovy energeticky okruh
		itemsPatternClass * weaponEnergyCircuitPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_WEAPON_ENERGY_CIRCUIT);
		newBase->weapons.mountWeaponEnergyCircuit(actx->cacheItemsList.insertItem(new weaponEnergyCircuitClass(
			ulNumberFromScale(weaponEnergyCircuitPattern->getMinWeight(), weaponEnergyCircuitPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_WEAPON_ENERGY_CIRCUIT_CHARGING_MIN, RANGE_WEAPON_ENERGY_CIRCUIT_CHARGING_MAX, (double)1, scienceQualityRating))));
		newBase->weapons.weaponsEnergyDivision.maxPowerDrain = newBase->weapons.weaponEnergyCircuit()->maxPossibleConsumption();

		// droni strely
		itemsPatternClass * droneMissilesPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_DRONE_MISSILES);
		if (droneMissilesPattern->getMinWeight() != droneMissilesPattern->getMaxWeight())
		{
			errLogicalError("Drone missiles: positive weight range.");
		}
		droneMissilesClass * droneMissiles = new droneMissilesClass(droneMissilesPattern->getMinWeight(), 0, 0);
		newBase->weapons.mountDroneMissiles(
			droneMissiles,
			ullNumberFromScale(NPR_DRONE_MISSILES_MIN_COUNT, NPR_DRONE_MISSILES_MAX_COUNT, (double)1, scienceQualityRating));
		delete droneMissiles;

		// torpedomety
		itemsPatternClass * droneMissileLauncherPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_DRONE_MISSILE_LAUNCHER);
		for (unsigned long loop2 = 0; loop2 < launchersCount; loop2++)
		{
			newBase->weapons.mountDroneMissileLauncher(newBase, actx->cacheItemsList.insertItem(new droneMissileLauncherClass(
				ulNumberFromScale(droneMissileLauncherPattern->getMinWeight(), droneMissileLauncherPattern->getMaxWeight(), (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_DRONE_MISSILE_LAUNCHER_ACCUMULATOR_MIN, RANGE_DRONE_MISSILE_LAUNCHER_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_DRONE_MISSILE_LAUNCHER_CHARGING_MIN, RANGE_DRONE_MISSILE_LAUNCHER_CHARGING_MAX, (double)1, scienceQualityRating))));
		}
		
		// laserova dela
		itemsPatternClass * laserGunPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_LASER_GUN);
		for (unsigned long loop2 = 0; loop2 < gunsCount; loop2++)
		{
			newBase->weapons.mountLaserGun(newBase, actx->cacheItemsList.insertItem(new laserGunClass(
				ulNumberFromScale(laserGunPattern->getMinWeight(), laserGunPattern->getMaxWeight(), (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_LASER_GUN_ACCUMULATOR_MIN, RANGE_LASER_GUN_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_LASER_GUN_CHARGING_MIN, RANGE_LASER_GUN_CHARGING_MAX, (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_LASER_GUN_RANGE_MIN, RANGE_LASER_GUN_RANGE_MAX, (double)1, scienceQualityRating),
				ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
				ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL))));
		}
		
		// transporter
		itemsPatternClass * transportBeamGeneratorPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_TRANSPORT_BEAM_GENERATOR);
		newBase->transportBeam.mountTransportBeamGenerator(actx->cacheItemsList.insertItem(new transportBeamGeneratorClass(
			ulNumberFromScale(transportBeamGeneratorPattern->getMinWeight(), transportBeamGeneratorPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_TRANSPORT_BEAM_GENERATOR_ACCUMULATOR_MIN, RANGE_TRANSPORT_BEAM_GENERATOR_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_TRANSPORT_BEAM_GENERATOR_CHARGING_MIN, RANGE_TRANSPORT_BEAM_GENERATOR_CHARGING_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_TRANSPORT_BEAM_GENERATOR_RANGE_MIN, RANGE_TRANSPORT_BEAM_GENERATOR_RANGE_MAX, (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL))));
		newBase->transportBeam.tBeamEnergyDivision.maxPowerDrain = newBase->transportBeam.transportBeamGenerator()->maxPossibleConsumption();
		newBase->transportBeam.tBeamEnergyState.targetEnergy     = 0;

		// magneticke kolektory plasmy
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_MCP <= scienceQualityRating)
		{
			itemsPatternClass * magneticalCollectorsOfPlasmaPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA);
			if (magneticalCollectorsOfPlasmaPattern->getMinWeight() != magneticalCollectorsOfPlasmaPattern->getMaxWeight())
			{
				errLogicalError("Magnetical collectors of plasma: positive weight range.");
			}
			magneticalCollectorsOfPlasmaClass * magneticalCollectorsOfPlasma = new magneticalCollectorsOfPlasmaClass(magneticalCollectorsOfPlasmaPattern->getMinWeight(), 0, 0);
			newBase->miningDevices.mountMagneticalCollectorsOfPlasma(
				magneticalCollectorsOfPlasma,
				ullNumberFromScale(NPR_MCP_MIN_COUNT, NPR_MCP_MAX_COUNT, (double)1, scienceQualityRating));
			delete magneticalCollectorsOfPlasma;
		}

		// ponorne filtracni nadrze
		itemsPatternClass * submersibleFiltrationTanksPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK);
		if (submersibleFiltrationTanksPattern->getMinWeight() != submersibleFiltrationTanksPattern->getMaxWeight())
		{
			errLogicalError("Submersible filtration tanks: positive weight range.");
		}
		submersibleFiltrationTankClass * submersibleFiltrationTanks = new submersibleFiltrationTankClass(submersibleFiltrationTanksPattern->getMinWeight(), 0, 0);
		newBase->miningDevices.mountSubmersibleFiltrationTanks(
			submersibleFiltrationTanks,
			ullNumberFromScale(NPR_BASE_SUBMERSIBLE_FT_MIN_COUNT, NPR_BASE_SUBMERSIBLE_FT_MAX_COUNT, (double)1, scienceQualityRating));
		delete submersibleFiltrationTanks;

		// podmorske tezebni stroje
		itemsPatternClass * submarineMiningMachinesPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_SUBMARINE_MINING_MACHINE);
		if (submarineMiningMachinesPattern->getMinWeight() != submarineMiningMachinesPattern->getMaxWeight())
		{
			errLogicalError("Submarine mining machines: positive weight range.");
		}
		submarineMiningMachineClass * submarineMiningMachines = new submarineMiningMachineClass(submarineMiningMachinesPattern->getMinWeight(), 0, 0);
		newBase->miningDevices.mountSubmarineMiningMachines(
			submarineMiningMachines,
			ullNumberFromScale(NPR_BASE_SUBMARINE_MM_MIN_COUNT, NPR_BASE_SUBMARINE_MM_MAX_COUNT, (double)1, scienceQualityRating));
		delete submarineMiningMachines;

		// dulni vrtaci stroje
		itemsPatternClass * undergroundDrillingMachinesPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE);
		if (undergroundDrillingMachinesPattern->getMinWeight() != undergroundDrillingMachinesPattern->getMaxWeight())
		{
			errLogicalError("Underground drilling machines: positive weight range.");
		}
		undergroundDrillingMachineClass * undergroundMiningMachines = new undergroundDrillingMachineClass(undergroundDrillingMachinesPattern->getMinWeight(), 0, 0);
		newBase->miningDevices.mountUndergroundDrillingMachines(
			undergroundMiningMachines,
			ullNumberFromScale(NPR_BASE_UNDERGROUND_DM_MIN_COUNT, NPR_BASE_UNDERGROUND_DM_MAX_COUNT, (double)1, scienceQualityRating));
		delete undergroundMiningMachines;

		// citlive senzory
		itemsPatternClass * highResolutionSensorsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_HIGH_RESOLUTION_SENSORS);
		newBase->sensors.mountHighResolutionSensors(actx->cacheItemsList.insertItem(new highResolutionSensorsClass(
			ulNumberFromScale(highResolutionSensorsPattern->getMinWeight(), highResolutionSensorsPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_HIGH_RESOLUTION_SENSORS_RANGE_MIN, RANGE_HIGH_RESOLUTION_SENSORS_RANGE_MAX, (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulNumberFromScale(RANGE_HIGH_RESOLUTION_SENSORS_CONSUMPTION_MIN, RANGE_HIGH_RESOLUTION_SENSORS_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newBase->sensors.sensorsHREnergyDivision.maxPowerDrain = newBase->sensors.highResolutionSensors()->maxPossibleConsumption();

		// dalkove senzory
		itemsPatternClass * longRangeSensorsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_LONG_RANGE_SENSORS);
		newBase->sensors.mountLongRangeSensors(actx->cacheItemsList.insertItem(new longRangeSensorsClass(
			ulNumberFromScale(longRangeSensorsPattern->getMinWeight(), longRangeSensorsPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_LONG_RANGE_SENSORS_RANGE_MIN, RANGE_LONG_RANGE_SENSORS_RANGE_MAX, (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulNumberFromScale(RANGE_LONG_RANGE_SENSORS_CONSUMPTION_MIN, RANGE_LONG_RANGE_SENSORS_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newBase->sensors.sensorsLREnergyDivision.maxPowerDrain = newBase->sensors.longRangeSensors()->maxPossibleConsumption();

		// maskovani
		itemsPatternClass * cloakingDevicePattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_CLOAKING_DEVICE);
		newBase->cloaking.mountCloakingDevice(actx->cacheItemsList.insertItem(new cloakingDeviceClass(
			ulNumberFromScale(cloakingDevicePattern->getMinWeight(), cloakingDevicePattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulNumberFromScale(RANGE_CLOAKING_DEVICE_CONSUMPTION_MIN, RANGE_CLOAKING_DEVICE_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newBase->cloaking.cloakingEnergyDivision.maxPowerDrain = 0;

		// androidi
		itemsPatternClass * androidsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_ANDROIDS);
		if (androidsPattern->getMinWeight() != androidsPattern->getMaxWeight())
		{
			errLogicalError("Androids: positive weight range.");
		}
		androidsClass * androids = new androidsClass(androidsPattern->getMinWeight(), 0, 0);
		newBase->mechanics.mountAndroids(
			androids,
			ullNumberFromScale(NPR_BASE_ANDROIDS_MIN_COUNT, NPR_BASE_ANDROIDS_MAX_COUNT, (double)1, scienceQualityRating));
		delete androids;
		newBase->mechanics.androidsEnergyDivision.maxPowerDrain = newBase->mechanics.androids()->maxPossibleConsumption();
		newBase->mechanics.setMaxWorkingAndroids  (              newBase->mechanics.androids()->getCount()    );
		newBase->mechanics.setMaxRepairingAndroids(ullUpRoundDiv(newBase->mechanics.androids()->getCount(), 2));

		// magneticke mrizky
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_QGP <= scienceQualityRating)
		{
			itemsPatternClass * magneticalGridsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_MAGNETICAL_GRID);
			if (magneticalGridsPattern->getMinWeight() != magneticalGridsPattern->getMaxWeight())
			{
				errLogicalError("Magnetical grids: positive weight range.");
			}
			magneticalGridClass * magneticalGrids = new magneticalGridClass(magneticalGridsPattern->getMinWeight(), 0, 0);
			newBase->warehouse.addItem(
				magneticalGrids,
				ullNumberFromScale(NPR_BASE_MAGNETICAL_GRIDS_MIN_COUNT, NPR_BASE_MAGNETICAL_GRIDS_MAX_COUNT, (double)1, scienceQualityRating),
				0,
				0);
			delete magneticalGrids;
		}

		// transportni kontejnery
		itemsPatternClass * transportContainersPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_TRANSPORT_CONTAINER);
		if (transportContainersPattern->getMinWeight() != transportContainersPattern->getMaxWeight())
		{
			errLogicalError("Transport containers: positive weight range.");
		}
		transportContainerClass * transportContainers = new transportContainerClass(transportContainersPattern->getMinWeight(), 0, 0);
		newBase->warehouse.addItem(
			transportContainers,
			ullNumberFromScale(NPR_BASE_TRANSPORT_CONTAINERS_MIN_COUNT, NPR_BASE_TRANSPORT_CONTAINRES_MAX_COUNT, (double)1, scienceQualityRating),
			0,
			0);
		delete transportContainers;

		// energeticke mrizky
		itemsPatternClass * energeticCellsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_ENERGETIC_CELL);
		if (energeticCellsPattern->getMinWeight() != energeticCellsPattern->getMaxWeight())
		{
			errLogicalError("Energetic cells: positive weight range.");
		}
		energeticCellClass * energeticCells = new energeticCellClass(energeticCellsPattern->getMinWeight(), 0, 0);
		newBase->warehouse.addItem(
			energeticCells,
			ullNumberFromScale(NPR_BASE_ENERGETIC_CELLS_MIN_COUNT, NPR_BASE_ENERGETIC_CELLS_MAX_COUNT, (double)1, scienceQualityRating),
			0,
			0);
		delete energeticCells;

		// plazmove filtry
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_QGP <= scienceQualityRating)
		{
			itemsPatternClass * plasmaFilterPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_PLASMA_FILTER);
			newBase->otherEquipment.mountPlasmaFilter(actx->cacheItemsList.insertItem(new plasmaFilterClass(
				ulNumberFromScale(plasmaFilterPattern->getMinWeight(), plasmaFilterPattern->getMaxWeight(), (double)1, scienceQualityRating))));
		}

		// vedecka laborator
		itemsPatternClass * scientificLabPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_SCIENTIFIC_LAB);
		newBase->otherEquipment.mountScientificLab(actx->cacheItemsList.insertItem(new scientificLabClass(
			ulNumberFromScale(scientificLabPattern->getMinWeight(), scientificLabPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulNumberFromScale(scientificLabPattern->getMinWeight(), scientificLabPattern->getMaxWeight(), (double)1, scienceQualityRating) / SCIENTIFIC_LAB_WEIGHT_FOR_ONE_CAPACITY)));

		// podpora zivota
		itemsPatternClass * lifeSupportPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_LIFE_SUPPORT);
		newBase->otherEquipment.mountLifeSupport(actx->cacheItemsList.insertItem(new lifeSupportClass(
			ulNumberFromScale(lifeSupportPattern->getMinWeight(), lifeSupportPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_LIFE_SUPPORT_CAPACITY_MIN, RANGE_LIFE_SUPPORT_CAPACITY_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_LIFE_SUPPORT_CONSUMPTION_MIN, RANGE_LIFE_SUPPORT_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newBase->otherEquipment.lifeSupportEnergyDivision.maxPowerDrain = newBase->otherEquipment.lifeSupport()->maxPossibleConsumption();

		// podprostorovy vysilac
		itemsPatternClass * subspaceTransmitterPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_SUBSPACE_TRANSMITTER);
		newBase->otherEquipment.mountSubspaceTransmitter(actx->cacheItemsList.insertItem(new subspaceTransmitterClass(
			ulNumberFromScale(subspaceTransmitterPattern->getMinWeight(), subspaceTransmitterPattern->getMaxWeight(), (double)1, scienceQualityRating),
			SUBSPACE_MESSAGE_COST)));

		// hangary
		itemsPatternClass   * hangarPattern    = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_HANGAR);
		itemDimensionsClass   hangarDimensions(newShipClass->getMaxLength(), newShipClass->getMaxWidth(), newShipClass->getMaxHeight());
		hangarDimensions.weight_ = ullUpRound(hangarDimensions.getSize()) * (unsigned long long)hangarPattern->getDensity();
		for (unsigned long loop2 = 0; loop2 < hangarsCount; loop2++)
		{
			if ((newBase->hangarsPort.mountHangar(actx->cacheItemsList.insertItem(new hangarClass(
				(unsigned long)hangarDimensions.weight_,
				ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
				ulUpRound(hangarDimensions.length_),
				ulUpRound(hangarDimensions.width_),
				ulUpRound(hangarDimensions.height_)))))
				&&
				(!dockingBase))
			{
				dockingBase = newBase;
			};
		}

		// magneticke filtry
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_QGP <= scienceQualityRating)
		{
			itemsPatternClass * magneticalFiltersPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_MAGNETICAL_FILTER);
			if (magneticalFiltersPattern->getMinWeight() != magneticalFiltersPattern->getMaxWeight())
			{
				errLogicalError("Magnetical filters: positive weight range.");
			}
			magneticalFilterClass * magneticalFilters = new magneticalFilterClass(magneticalFiltersPattern->getMinWeight(), 0, 0);
			newBase->factories.mountMagneticalFilters(
				magneticalFilters,
				ulNumberFromScale(NPR_MAGNETICAL_FILTERS_MIN_COUNT, NPR_MAGNETICAL_FILTERS_MAX_COUNT, (double)1, scienceQualityRating));
			delete magneticalFilters;
		}

		// deuteriove rozkladace
		itemsPatternClass * deuteriumDecomposersPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_DEUTERIUM_DECOMPOSER);
		if (deuteriumDecomposersPattern->getMinWeight() != deuteriumDecomposersPattern->getMaxWeight())
		{
			errLogicalError("Deuterium decomposers: positive weight range.");
		}
		deuteriumDecomposerClass * deuteriumDecomposers = new deuteriumDecomposerClass(deuteriumDecomposersPattern->getMinWeight(), 0, 0);
		newBase->factories.mountDeuteriumDecomposers(
			deuteriumDecomposers,
			ulNumberFromScale(NPR_DEUTERIUM_DECOMPOSERS_MIN_COUNT, NPR_DEUTERIUM_DECOMPOSERS_MAX_COUNT, (double)1, scienceQualityRating));
		delete deuteriumDecomposers;

		// zirkoniove reaktory
		itemsPatternClass * zirconiumReactorsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_ZIRCONIUM_REACTOR);
		if (zirconiumReactorsPattern->getMinWeight() != zirconiumReactorsPattern->getMaxWeight())
		{
			errLogicalError("Zirconium reactors: positive weight range.");
		}
		zirconiumReactorClass * zirconiumReactors = new zirconiumReactorClass(zirconiumReactorsPattern->getMinWeight(), 0, 0);
		newBase->factories.mountZirconiumReactors(
			zirconiumReactors,
			ulNumberFromScale(NPR_ZIRCONIUM_REACTORS_MIN_COUNT, NPR_ZIRCONIUM_REACTORS_MAX_COUNT, (double)1, scienceQualityRating));
		delete zirconiumReactors;

		// ilmenitove pece
		itemsPatternClass * ilmeniteFurnacesPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_ILMENITE_FURNACE);
		if (ilmeniteFurnacesPattern->getMinWeight() != ilmeniteFurnacesPattern->getMaxWeight())
		{
			errLogicalError("Ilmenite furnaces: positive weight range.");
		}
		ilmeniteFurnaceClass * ilmeniteFurnaces = new ilmeniteFurnaceClass(ilmeniteFurnacesPattern->getMinWeight(), 0, 0);
		newBase->factories.mountIlmeniteFurnaces(
			ilmeniteFurnaces,
			ulNumberFromScale(NPR_ILMENITE_FURNACES_MIN_COUNT, NPR_ILMENITE_FURNACES_MAX_COUNT, (double)1, scienceQualityRating));
		delete ilmeniteFurnaces;
		
		unsigned long long QGP = (unsigned long long)(NPR_RESOURCES_PART * newBase->freeSpaceForQuarkGluonPlasmaInMiligrams(1, 0));
		unsigned long long Ulr = ullNumberFromScale(NPR_MIN_ULREI, NPR_MAX_ULREI, (double)1, scienceQualityRating);
		unsigned long long HeW = (unsigned long long)(NPR_RESOURCES_PART * newBase->freeSpaceForHeavyWaterInKilograms       (1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		unsigned long long Deu = (unsigned long long)(NPR_RESOURCES_PART * newBase->freeSpaceForDeuteriumInKilograms        (1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		unsigned long long ZrC = (unsigned long long)(NPR_RESOURCES_PART * newBase->freeSpaceForZirconiumCrystalsInKilograms(1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		unsigned long long Eng = (unsigned long long)(NPR_RESOURCES_PART * newBase->freeSpaceForEnergyInTeraJoules(1, 0));
		unsigned long long Ilm = (unsigned long long)(NPR_RESOURCES_PART * newBase->freeSpaceForIlmeniteInKilograms         (1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		unsigned long long Tit = (unsigned long long)(NPR_RESOURCES_PART * newBase->freeSpaceForTitaniumInKilograms         (1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_QGP <= scienceQualityRating)
		{
			newBase->addAllResources(QGP, Ulr, HeW, Deu, ZrC, Eng, Ilm, Tit);
		}
		else
		{
			newBase->addAllResources(0, Ulr, HeW, Deu, ZrC, Eng, Ilm, Tit);
		}
		
		newPlayer->addNewFortress(newBase);
		newBase->globalUpdate();
	}


	// tvorba lodi
	if (!dockingBase)
	{
		return PAR_INTERNAL_ERROR;
	}
	for (unsigned long loop1 = 0; loop1 < shipsCount; loop1++)
	{
		unsigned long long buildingTitanium = newShipClass->getMinWeight() + ullRound((double)(newShipClass->getMaxWeight() - newShipClass->getMinWeight()) * shipsQualityRating);
		unsigned long      weaponsCount     = newShipClass->getMaxWeapons();
		unsigned long      launchersCount   = newShipClass->getMaxDroneMissileLaunchers();
		unsigned long      gunsCount        = newShipClass->getMaxLaserGuns();
		double             massRating       = newShipClass->getMassRating();
		while ((weaponsCount) < (launchersCount + gunsCount))
		{
			if (flipACoin())
			{
				if (0 < launchersCount)
				{
					launchersCount--;
				}
			}
			else
			{
				if (0 < gunsCount)
				{
					gunsCount--;
				}
			}
		}

		shipClass * newShip = (shipClass *)(newShipClass->deriveNewFortress(NULL, buildingTitanium, 1));
		if (!newShip)
		{
			errExceptionError("Starting ship wasn't created because of nonsense NULL derived from shipClass.");
			return PAR_INTERNAL_ERROR;
		}
		actx->cacheFortressesList.insertItem(newShip);
		newShip->addIDBehindName();
		hangarClass * dockingHangar;
		if (NULL != (dockingHangar = dockingBase->hangarsPort.hangars(dockingHangarPosition)))
		{
			dockingHangar->dockAShip(newShip);
			newShip->MovementLand(dockingBase->getID());
			actx->spaceObjectIndex.addShip(newShip->getID(), startingStar->getID());
		}
		else
		{
			errLogicalError("New ship (ID %u) can't dock down; now it is unreachable but still in list!!");
			return PAR_INTERNAL_ERROR;
		}
		newPlayer->addUncontrollableFortress(newShip);
		

		// mainframe
		itemsPatternClass * mainframePattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_MAINFRAME);
		newShip->mainframeSystem.changeMainframe(actx->cacheItemsList.insertItem(new mainframeClass(
			mainframePattern->getMaxWeight(),
			BIONODES_FOR_ONE_FORTRESS * (basesCount + shipsCount),
			ulNumberFromScale(RANGE_MAINFRAME_PREDICTION_MIN, RANGE_MAINFRAME_PREDICTION_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_MAINFRAME_TIME_REUSABILITY_MIN, RANGE_MAINFRAME_TIME_REUSABILITY_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_MAINFRAME_CONSUMPTION_MIN, RANGE_MAINFRAME_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newShip->mainframeSystem.mainframeEnergyDivision.maxPowerDrain = newShip->mainframeSystem.mainframe()->maxPossibleConsumption();

		// energeticky akumulator
		itemsPatternClass * energeticAccumulatorPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_ENERGETIC_ACCUMULATOR);
		newShip->energeticSystem.changeEnergeticAccumulator(actx->cacheItemsList.insertItem(new energeticAccumulatorClass(
			ulNumberFromScale(energeticAccumulatorPattern->getMinWeight(), energeticAccumulatorPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ullNumberFromScale(RANGE_ENERGETIC_ACCUMULATOR_ACCUMULATOR_MIN, RANGE_ENERGETIC_ACCUMULATOR_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_ENERGETIC_ACCUMULATOR_CHARGING_MIN, RANGE_ENERGETIC_ACCUMULATOR_CHARGING_MAX, (double)1, scienceQualityRating))));
		newShip->energeticSystem.energeticAccumulatorEnergyState.energy = newShip->energeticSystem.energeticAccumulator()->actualAccumulator();
		
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_QGP <= scienceQualityRating)
		{
			// quark-gluonove jadro
			itemsPatternClass * quarkGluonPlasmaPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_QUARK_GLUON_CORE);
			newShip->subspaceDrive.mountQuarkGluonCore(actx->cacheItemsList.insertItem(new quarkGluonCoreClass(
				ulNumberFromScale(quarkGluonPlasmaPattern->getMinWeight(), quarkGluonPlasmaPattern->getMaxWeight(), (double)1, scienceQualityRating),
				dNumberFromScale(RANGE_QUARK_GLUON_CORE_SPEED_MIN, RANGE_QUARK_GLUON_CORE_SPEED_MAX, (double)1, scienceQualityRating),
				(unsigned short)ulNumberFromScale(RANGE_QUARK_GLUON_CORE_CONSUMPTION_MIN, RANGE_QUARK_GLUON_CORE_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));

			// navigacni pocitac
			itemsPatternClass * navigationComputerPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_NAVIGATION_COMPUTER);
			newShip->subspaceDrive.mountNavigationComputer(actx->cacheItemsList.insertItem(new navigationComputerClass(
				ulNumberFromScale(navigationComputerPattern->getMinWeight(), navigationComputerPattern->getMaxWeight(), (double)1, scienceQualityRating),
				dNumberFromScale(RANGE_NAVIGATION_COMPUTER_SPEED_MIN, RANGE_NAVIGATION_COMPUTER_SPEED_MAX, (double)1, scienceQualityRating))));

			// podprostorovy majak
			itemsPatternClass * subspaceBeaconPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_SUBSPACE_BEACON);
			newShip->subspaceDrive.mountSubspaceBeacon(actx->cacheItemsList.insertItem(new subspaceBeaconClass(
				ulNumberFromScale(subspaceBeaconPattern->getMinWeight(), subspaceBeaconPattern->getMaxWeight(), (double)1, scienceQualityRating),
				dNumberFromScale(RANGE_SUBSPACE_BEACON_SPEED_MIN, RANGE_SUBSPACE_BEACON_SPEED_MAX, (double)1, scienceQualityRating))));

			// inercialni tlumice
			itemsPatternClass * inertialDampersPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_INERTIAL_DAMPERS);
			newShip->subspaceDrive.mountInertialDampers(actx->cacheItemsList.insertItem(new inertialDampersClass(
				ulNumberFromScale(inertialDampersPattern->getMinWeight(), inertialDampersPattern->getMaxWeight(), (double)1, scienceQualityRating),
				dNumberFromScale(RANGE_INERTIAL_DAMPERS_SPEED_MIN, RANGE_INERTIAL_DAMPERS_SPEED_MAX, (double)1, scienceQualityRating))));
		}

		// impulzni tryskovy motor
		itemsPatternClass * impulsJetEnginePattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_IMPULS_JET_ENGINE);
		newShip->impulsDrive.mountImpulsJetEngine(actx->cacheItemsList.insertItem(new impulsJetEngineClass(
			ulNumberFromScale(impulsJetEnginePattern->getMinWeight(), impulsJetEnginePattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_IMPULS_ENGINE_CONSUMPTION_MIN, RANGE_IMPULS_ENGINE_FORCE_MAX, (double)1, (double)1 - scienceQualityRating),
			ulNumberFromScale(RANGE_IMPULS_ENGINE_FORCE_MIN, RANGE_IMPULS_ENGINE_FORCE_MAX, (double)1, scienceQualityRating))));

		// mechanicke tlumice
		itemsPatternClass * mechanicalDampersPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_MECHANICAL_DAMPERS);
		newShip->impulsDrive.mountMechanicalDampers(actx->cacheItemsList.insertItem(new mechanicalDampersClass(
			ulNumberFromScale(mechanicalDampersPattern->getMinWeight(), mechanicalDampersPattern->getMaxWeight(), (double)1, scienceQualityRating),
			(unsigned short)ulNumberFromScale(RANGE_MECHANICAL_DAMPERS_ACCELERATION_MIN, RANGE_MECHANICAL_DAMPERS_ACCELERATION_MAX, (double)1, scienceQualityRating))));

		// stity
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_SHIELDS <= scienceQualityRating)
		{
			itemsPatternClass * deflectorShieldsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_DEFLECTOR_SHIELDS);
			newShip->deflectorShields.mountDeflectorShieldsGenerator(actx->cacheItemsList.insertItem(new deflectorShieldsGeneratorClass(
				ulNumberFromScale(deflectorShieldsPattern->getMinWeight(), deflectorShieldsPattern->getMaxWeight(), (double)1, scienceQualityRating),
				ulRound((double)MAX_TOTAL_SCIENCE_LEVEL * scienceQualityRating),
				ulNumberFromScale(RANGE_DEFLECTOR_SHIELDS_ACCUMULATOR_MIN, RANGE_DEFLECTOR_SHIELDS_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_DEFLECTOR_SHIELDS_CHARGING_MIN, RANGE_DEFLECTOR_SHIELDS_CHARGING_MAX, (double)1, scienceQualityRating),
				(double)ulNumberFromScale(RANGE_DEFLECTOR_SHIELDS_ACCUMULATOR_MIN, RANGE_DEFLECTOR_SHIELDS_ACCUMULATOR_MAX, (double)1, scienceQualityRating) * DEFLECTOR_SHIELDS_LEAK_TO_ACCUMULATOR))); 
			newShip->deflectorShields.deflectorsEnergyDivision.maxPowerDrain   = newShip->deflectorShields.deflectorShieldsGenerator()->maxPossibleConsumption();
		}

		// zbranovy energeticky okruh
		itemsPatternClass * weaponEnergyCircuitPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_WEAPON_ENERGY_CIRCUIT);
		newShip->weapons.mountWeaponEnergyCircuit(actx->cacheItemsList.insertItem(new weaponEnergyCircuitClass(
			ulNumberFromScale(weaponEnergyCircuitPattern->getMinWeight(), weaponEnergyCircuitPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_WEAPON_ENERGY_CIRCUIT_CHARGING_MIN, RANGE_WEAPON_ENERGY_CIRCUIT_CHARGING_MAX, (double)1, scienceQualityRating))));
		newShip->weapons.weaponsEnergyDivision.maxPowerDrain = newShip->weapons.weaponEnergyCircuit()->maxPossibleConsumption();

		// droni strely
		itemsPatternClass * droneMissilesPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_DRONE_MISSILES);
		if (droneMissilesPattern->getMinWeight() != droneMissilesPattern->getMaxWeight())
		{
			errLogicalError("Drone missiles: positive weight range.");
		}
		droneMissilesClass * droneMissiles = new droneMissilesClass(droneMissilesPattern->getMinWeight(), 0, 0);
		newShip->weapons.mountDroneMissiles(
			droneMissiles,
			ullNumberFromScale(NPR_DRONE_MISSILES_MIN_COUNT, NPR_DRONE_MISSILES_MAX_COUNT, (double)1, scienceQualityRating));
		delete droneMissiles;

		// torpedomety
		itemsPatternClass * droneMissileLauncherPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_DRONE_MISSILE_LAUNCHER);
		for (unsigned long loop2 = 0; loop2 < launchersCount; loop2++)
		{
			newShip->weapons.mountDroneMissileLauncher(newShip, actx->cacheItemsList.insertItem(new droneMissileLauncherClass(
				ulNumberFromScale(droneMissileLauncherPattern->getMinWeight(), droneMissileLauncherPattern->getMaxWeight(), (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_DRONE_MISSILE_LAUNCHER_ACCUMULATOR_MIN, RANGE_DRONE_MISSILE_LAUNCHER_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_DRONE_MISSILE_LAUNCHER_CHARGING_MIN, RANGE_DRONE_MISSILE_LAUNCHER_CHARGING_MAX, (double)1, scienceQualityRating))));
		}
		
		// laserova dela
		itemsPatternClass * laserGunPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_LASER_GUN);
		for (unsigned long loop2 = 0; loop2 < gunsCount; loop2++)
		{
			newShip->weapons.mountLaserGun(newShip, actx->cacheItemsList.insertItem(new laserGunClass(
				ulNumberFromScale(laserGunPattern->getMinWeight(), laserGunPattern->getMaxWeight(), (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_LASER_GUN_ACCUMULATOR_MIN, RANGE_LASER_GUN_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_LASER_GUN_CHARGING_MIN, RANGE_LASER_GUN_CHARGING_MAX, (double)1, scienceQualityRating),
				ulNumberFromScale(RANGE_LASER_GUN_RANGE_MIN, RANGE_LASER_GUN_RANGE_MAX, (double)1, scienceQualityRating),
				ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
				ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL))));
		}
		
		// transporter
		itemsPatternClass * transportBeamGeneratorPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_TRANSPORT_BEAM_GENERATOR);
		newShip->transportBeam.mountTransportBeamGenerator(actx->cacheItemsList.insertItem(new transportBeamGeneratorClass(
			ulNumberFromScale(transportBeamGeneratorPattern->getMinWeight(), transportBeamGeneratorPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_TRANSPORT_BEAM_GENERATOR_ACCUMULATOR_MIN, RANGE_TRANSPORT_BEAM_GENERATOR_ACCUMULATOR_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_TRANSPORT_BEAM_GENERATOR_CHARGING_MIN, RANGE_TRANSPORT_BEAM_GENERATOR_CHARGING_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_TRANSPORT_BEAM_GENERATOR_RANGE_MIN, RANGE_TRANSPORT_BEAM_GENERATOR_RANGE_MAX, (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL))));
		newShip->transportBeam.tBeamEnergyDivision.maxPowerDrain = newShip->transportBeam.transportBeamGenerator()->maxPossibleConsumption();
		newShip->transportBeam.tBeamEnergyState.targetEnergy     = 0;

		// magneticke kolektory plasmy
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_MCP <= scienceQualityRating)
		{
			itemsPatternClass * magneticalCollectorsOfPlasmaPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA);
			if (magneticalCollectorsOfPlasmaPattern->getMinWeight() != magneticalCollectorsOfPlasmaPattern->getMaxWeight())
			{
				errLogicalError("Magnetical collectors of plasma: positive weight range.");
			}
			magneticalCollectorsOfPlasmaClass * magneticalCollectorsOfPlasma = new magneticalCollectorsOfPlasmaClass(magneticalCollectorsOfPlasmaPattern->getMinWeight(), 0, 0);
			newShip->miningDevices.mountMagneticalCollectorsOfPlasma(
				magneticalCollectorsOfPlasma,
				ullNumberFromScale(NPR_MCP_MIN_COUNT, NPR_MCP_MAX_COUNT, (double)1, massRating));
			delete magneticalCollectorsOfPlasma;
		}

		// ponorne filtracni nadrze
		itemsPatternClass * submersibleFiltrationTanksPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK);
		if (submersibleFiltrationTanksPattern->getMinWeight() != submersibleFiltrationTanksPattern->getMaxWeight())
		{
			errLogicalError("Submersible filtration tanks: positive weight range.");
		}
		submersibleFiltrationTankClass * submersibleFiltrationTanks = new submersibleFiltrationTankClass(submersibleFiltrationTanksPattern->getMinWeight(), 0, 0);
		newShip->miningDevices.mountSubmersibleFiltrationTanks(
			submersibleFiltrationTanks,
			ullNumberFromScale(NPR_SHIP_SUBMERSIBLE_FT_MIN_COUNT, NPR_SHIP_SUBMERSIBLE_FT_MAX_COUNT, (double)1, massRating));
		delete submersibleFiltrationTanks;

		// podmorske tezebni stroje
		itemsPatternClass * submarineMiningMachinesPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_SUBMARINE_MINING_MACHINE);
		if (submarineMiningMachinesPattern->getMinWeight() != submarineMiningMachinesPattern->getMaxWeight())
		{
			errLogicalError("Submarine mining machines: positive weight range.");
		}
		submarineMiningMachineClass * submarineMiningMachines = new submarineMiningMachineClass(submarineMiningMachinesPattern->getMinWeight(), 0, 0);
		newShip->miningDevices.mountSubmarineMiningMachines(
			submarineMiningMachines,
			ullNumberFromScale(NPR_SHIP_SUBMARINE_MM_MIN_COUNT, NPR_SHIP_SUBMARINE_MM_MAX_COUNT, (double)1, massRating));
		delete submarineMiningMachines;

		// dulni vrtaci stroje
		itemsPatternClass * undergroundDrillingMachinesPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE);
		if (undergroundDrillingMachinesPattern->getMinWeight() != undergroundDrillingMachinesPattern->getMaxWeight())
		{
			errLogicalError("Underground drilling machines: positive weight range.");
		}
		undergroundDrillingMachineClass * undergroundMiningMachines = new undergroundDrillingMachineClass(undergroundDrillingMachinesPattern->getMinWeight(), 0, 0);
		newShip->miningDevices.mountUndergroundDrillingMachines(
			undergroundMiningMachines,
			ullNumberFromScale(NPR_SHIP_UNDERGROUND_DM_MIN_COUNT, NPR_SHIP_UNDERGROUND_DM_MAX_COUNT, (double)1, massRating));
		delete undergroundMiningMachines;

		// citlive senzory
		itemsPatternClass * highResolutionSensorsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_HIGH_RESOLUTION_SENSORS);
		newShip->sensors.mountHighResolutionSensors(actx->cacheItemsList.insertItem(new highResolutionSensorsClass(
			ulNumberFromScale(highResolutionSensorsPattern->getMinWeight(), highResolutionSensorsPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_HIGH_RESOLUTION_SENSORS_RANGE_MIN, RANGE_HIGH_RESOLUTION_SENSORS_RANGE_MAX, (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulNumberFromScale(RANGE_HIGH_RESOLUTION_SENSORS_CONSUMPTION_MIN, RANGE_HIGH_RESOLUTION_SENSORS_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newShip->sensors.sensorsHREnergyDivision.maxPowerDrain = newShip->sensors.highResolutionSensors()->maxPossibleConsumption();

		// dalkove senzory
		itemsPatternClass * longRangeSensorsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_LONG_RANGE_SENSORS);
		newShip->sensors.mountLongRangeSensors(actx->cacheItemsList.insertItem(new longRangeSensorsClass(
			ulNumberFromScale(longRangeSensorsPattern->getMinWeight(), longRangeSensorsPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_LONG_RANGE_SENSORS_RANGE_MIN, RANGE_LONG_RANGE_SENSORS_RANGE_MAX, (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulNumberFromScale(RANGE_LONG_RANGE_SENSORS_CONSUMPTION_MIN, RANGE_LONG_RANGE_SENSORS_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newShip->sensors.sensorsLREnergyDivision.maxPowerDrain = newShip->sensors.longRangeSensors()->maxPossibleConsumption();

		// maskovani
		itemsPatternClass * cloakingDevicePattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_CLOAKING_DEVICE);
		newShip->cloaking.mountCloakingDevice(actx->cacheItemsList.insertItem(new cloakingDeviceClass(
			ulNumberFromScale(cloakingDevicePattern->getMinWeight(), cloakingDevicePattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulNumberFromScale(RANGE_CLOAKING_DEVICE_CONSUMPTION_MIN, RANGE_CLOAKING_DEVICE_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newShip->cloaking.cloakingEnergyDivision.maxPowerDrain = 0;

		// androidi
		itemsPatternClass * androidsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_ANDROIDS);
		if (androidsPattern->getMinWeight() != androidsPattern->getMaxWeight())
		{
			errLogicalError("Androids: positive weight range.");
		}
		androidsClass * androids = new androidsClass(androidsPattern->getMinWeight(), 0, 0);
		newShip->mechanics.mountAndroids(
			androids,
			ullNumberFromScale(NPR_SHIP_ANDROIDS_MIN_COUNT, NPR_SHIP_ANDROIDS_MAX_COUNT, (double)1, massRating));
		delete androids;
		newShip->mechanics.androidsEnergyDivision.maxPowerDrain = newShip->mechanics.androids()->maxPossibleConsumption();
		newShip->mechanics.setMaxWorkingAndroids  (              newShip->mechanics.androids()->getCount()    );
		newShip->mechanics.setMaxRepairingAndroids(ullUpRoundDiv(newShip->mechanics.androids()->getCount(), 2));

		// magneticke mrizky
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_QGP <= scienceQualityRating)
		{
			itemsPatternClass * magneticalGridsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_MAGNETICAL_GRID);
			if (magneticalGridsPattern->getMinWeight() != magneticalGridsPattern->getMaxWeight())
			{
				errLogicalError("Magnetical grids: positive weight range.");
			}
			magneticalGridClass * magneticalGrids = new magneticalGridClass(magneticalGridsPattern->getMinWeight(), 0, 0);
			newShip->warehouse.addItem(
				magneticalGrids,
				ullNumberFromScale(NPR_SHIP_MAGNETICAL_GRIDS_MIN_COUNT, NPR_SHIP_MAGNETICAL_GRIDS_MAX_COUNT, (double)1, (scienceQualityRating + massRating) / 2),
				0,
				0);
			delete magneticalGrids;
		}

		// transportni kontejnery
		itemsPatternClass * transportContainersPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_TRANSPORT_CONTAINER);
		if (transportContainersPattern->getMinWeight() != transportContainersPattern->getMaxWeight())
		{
			errLogicalError("Transport containers: positive weight range.");
		}
		transportContainerClass * transportContainers = new transportContainerClass(transportContainersPattern->getMinWeight(), 0, 0);
		newShip->warehouse.addItem(
			transportContainers,
			ullNumberFromScale(NPR_SHIP_TRANSPORT_CONTAINERS_MIN_COUNT, NPR_SHIP_TRANSPORT_CONTAINERS_MAX_COUNT, (double)1, scienceQualityRating),
			0,
			0);
		delete transportContainers;

		// energeticke mrizky
		itemsPatternClass * energeticCellsPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_ENERGETIC_CELL);
		if (energeticCellsPattern->getMinWeight() != energeticCellsPattern->getMaxWeight())
		{
			errLogicalError("Energetic cells: positive weight range.");
		}
		energeticCellClass * energeticCells = new energeticCellClass(energeticCellsPattern->getMinWeight(), 0, 0);
		newShip->warehouse.addItem(
			energeticCells,
			ullNumberFromScale(NPR_SHIP_ENERGETIC_CELLS_MIN_COUNT, NPR_SHIP_ENERGETIC_CELLS_MAX_COUNT, (double)1, (scienceQualityRating + massRating) / 2),
			0,
			0);
		delete energeticCells;

		// plazmove filtry
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_QGP <= scienceQualityRating)
		{
			itemsPatternClass * plasmaFilterPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_PLASMA_FILTER);
			newShip->otherEquipment.mountPlasmaFilter(actx->cacheItemsList.insertItem(new plasmaFilterClass(
				ulNumberFromScale(plasmaFilterPattern->getMinWeight(), plasmaFilterPattern->getMaxWeight(), (double)1, scienceQualityRating))));
		}

		// vedecka laborator
		itemsPatternClass * scientificLabPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_SCIENTIFIC_LAB);
		newShip->otherEquipment.mountScientificLab(actx->cacheItemsList.insertItem(new scientificLabClass(
			ulNumberFromScale(scientificLabPattern->getMinWeight(), scientificLabPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulRound(scienceQualityRating * (double)MAX_TOTAL_SCIENCE_LEVEL),
			ulNumberFromScale(scientificLabPattern->getMinWeight(), scientificLabPattern->getMaxWeight(), (double)1, scienceQualityRating) / SCIENTIFIC_LAB_WEIGHT_FOR_ONE_CAPACITY)));

		// podpora zivota
		itemsPatternClass * lifeSupportPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_LIFE_SUPPORT);
		newShip->otherEquipment.mountLifeSupport(actx->cacheItemsList.insertItem(new lifeSupportClass(
			ulNumberFromScale(lifeSupportPattern->getMinWeight(), lifeSupportPattern->getMaxWeight(), (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_LIFE_SUPPORT_CAPACITY_MIN, RANGE_LIFE_SUPPORT_CAPACITY_MAX, (double)1, scienceQualityRating),
			ulNumberFromScale(RANGE_LIFE_SUPPORT_CONSUMPTION_MIN, RANGE_LIFE_SUPPORT_CONSUMPTION_MAX, (double)1, (double)1 - scienceQualityRating))));
		newShip->otherEquipment.lifeSupportEnergyDivision.maxPowerDrain = newShip->otherEquipment.lifeSupport()->maxPossibleConsumption();

		// podprostorovy vysilac
		itemsPatternClass * subspaceTransmitterPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(PATTERN_ID_SUBSPACE_TRANSMITTER);
		newShip->otherEquipment.mountSubspaceTransmitter(actx->cacheItemsList.insertItem(new subspaceTransmitterClass(
			ulNumberFromScale(subspaceTransmitterPattern->getMinWeight(), subspaceTransmitterPattern->getMaxWeight(), (double)1, scienceQualityRating),
			SUBSPACE_MESSAGE_COST)));

		unsigned long long QGP = (unsigned long long)(NPR_RESOURCES_PART * newShip->freeSpaceForQuarkGluonPlasmaInMiligrams(1, 0));
		unsigned long long Ulr = ullNumberFromScale(NPR_MIN_ULREI, NPR_MAX_ULREI, (double)1, scienceQualityRating);
		unsigned long long HeW = (unsigned long long)(NPR_RESOURCES_PART * newShip->freeSpaceForHeavyWaterInKilograms       (1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		unsigned long long Deu = (unsigned long long)(NPR_RESOURCES_PART * newShip->freeSpaceForDeuteriumInKilograms        (1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		unsigned long long ZrC = (unsigned long long)(NPR_RESOURCES_PART * newShip->freeSpaceForZirconiumCrystalsInKilograms(1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		unsigned long long Eng = (unsigned long long)(NPR_RESOURCES_PART * newShip->freeSpaceForEnergyInTeraJoules(1, 0));
		unsigned long long Ilm = (unsigned long long)(NPR_RESOURCES_PART * newShip->freeSpaceForIlmeniteInKilograms         (1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		unsigned long long Tit = (unsigned long long)(NPR_RESOURCES_PART * newShip->freeSpaceForTitaniumInKilograms         (1, 1, 0) / CONTAINERED_RESOURCES_COUNT);
		if (NPR_SCIENCE_QUALITY_REQUIRED_FOR_QGP <= scienceQualityRating)
		{
			newShip->addAllResources(QGP, Ulr, HeW, Deu, ZrC, Eng, Ilm, Tit);
		}
		else
		{
			newShip->addAllResources(0, Ulr, HeW, Deu, ZrC, Eng, Ilm, Tit);
		}

        newShip->MovementUpdateNearestStar();

		newPlayer->addNewFortress(newShip);
		newShip->globalUpdate();
	}

    return PAR_OK;
};

// --------------------------------

void realmClass::removeFortress(fortressClass * oldFortress)
{
	if (NULL == oldFortress)
	{
		return;
	}

	if (oldFortress->getFortressRealmID() != this->getID())
	{
		errLogicalError("attempt to remove from realm %u not owned fortress with id %u", (unsigned long long)(this->getID()), (unsigned long long)(oldFortress->getFortressRealmID()));
		return;
	}

	dtIdentifierVector::iterator baseFound = bases_.end();
	for (dtIdentifierVector::iterator litp1 = bases_.begin(); litp1 != bases_.end(); litp1++)
	{
		if (oldFortress->getID() == (*litp1))
		{
			baseFound = litp1;
			break;
		}
	}

	dtIdentifierVector::iterator shipFound = ships_.end();
	if (bases_.end() == baseFound)
	{
		for (dtIdentifierVector::iterator litp1 = ships_.begin(); litp1 != ships_.end(); litp1++)
		{
			if (oldFortress->getID() == (*litp1))
			{
				shipFound = litp1;
				break;
			}
		}
	}

	dtIdentifierVector::iterator uncontrollableFound = uncontrollableFortresses_.end();
	if ((bases_.end() == baseFound) && (ships_.end() == shipFound))
	{
		for (dtIdentifierVector::iterator litp1 = uncontrollableFortresses_.begin(); litp1 != uncontrollableFortresses_.end(); litp1++)
		{
			if (oldFortress->getID() == (*litp1))
			{
				uncontrollableFound = litp1;
				break;
			}
		}
	}

	bool fortressFound = (bases_.end() != baseFound) || (ships_.end() != shipFound) || (uncontrollableFortresses_.end() != uncontrollableFound);

	if (!(fortressFound))
	{
        errLogicalError("Realm %u: owned fortress %u not found in vectors", (unsigned long long)this->getID(), (unsigned long long)oldFortress->getFortressRealmID());
		return;
	}

	if (bases_.end() != baseFound)
	{
		bases_.erase(baseFound);
	}
	if (ships_.end() != shipFound)
	{
		ships_.erase(shipFound);
	}
	if (uncontrollableFortresses_.end() != uncontrollableFound)
	{
		uncontrollableFortresses_.erase(uncontrollableFound);
	}

	oldFortress->setFortressRealm(NOT_VALID_ID);
	oldFortress->loseControl();
};

// --------------------------------

void realmClass::mainframeFailure(fortressClass * oldFortress)
{
	return; 

	if (NULL == oldFortress)
	{
		return;
	}

	if (oldFortress->getFortressRealmID() != this->getID())
	{
		errLogicalError("attempt to remove from realm %u not owned fortress with id %u", (unsigned long long)(this->getID()), (unsigned long long)(oldFortress->getFortressRealmID()));
		return;
	}

	oldFortress->loseControl();

	dtIdentifierVector::iterator baseFound = bases_.end();
	for (dtIdentifierVector::iterator litp1 = bases_.begin(); litp1 != bases_.end(); litp1++)
	{
		if (oldFortress->getID() == (*litp1))
		{
			baseFound = litp1;
			break;
		}
	}

	dtIdentifierVector::iterator shipFound = ships_.end();
	if (bases_.end() == baseFound)
	{
		for (dtIdentifierVector::iterator litp1 = ships_.begin(); litp1 != ships_.end(); litp1++)
		{
			if (oldFortress->getID() == (*litp1))
			{
				shipFound = litp1;
				break;
			}
		}
	}

	//bool fortressFound = (bases_.end() != baseFound) || (ships_.end() != shipFound);

	//if (!(fortressFound))
	//{
        //errLogicalError("Realm %u: owned fortress %u not found in vectors", (unsigned long long)this->getID(), (unsigned long long)oldFortress->getFortressRealmID());
		//return;
	//}

	// tohle uz neplati, pevnost muze byt uncontrollable

	if (bases_.end() != baseFound)
	{
		uncontrollableFortresses_.push_back(*baseFound);
		bases_.erase(baseFound);
	}
	if (ships_.end() != shipFound)
	{
		uncontrollableFortresses_.push_back(*shipFound);
		ships_.erase(shipFound);
	}
};

// --------------------------------

void realmClass::addNewFortressWithoutAnyControll(fortressClass * newFortress, bool controllable)
{
	if (!(newFortress))
	{
		return;
	}

	if (NOT_VALID_ID != newFortress->getFortressRealmID())
	{
		newFortress->getFortressRealm()->removeFortress(newFortress);
	}

	newFortress->setFortressRealm(this->getID());
	if (controllable)
	{
		if (FT_BASE == newFortress->getFortressType())
		{
			bases_.push_back(newFortress->getID());
			newFortress->gainControl();
		}
		if (FT_SHIP == newFortress->getFortressType())
		{
			ships_.push_back(newFortress->getID());
			newFortress->gainControl();
		}
	}
	else
	{
		uncontrollableFortresses_.push_back(newFortress->getID());
		newFortress->loseControl();
	}
};

// --------------------------------

fortressAddingResult realmClass::addNewFortress(fortressClass * newFortress)
{
	fortressAddingResult result = this->canNewFortressBeAdded(newFortress, 1);

	if (FAR_DONE == result)
	{
		this->addNewFortressWithoutAnyControll(newFortress, 1);
	}

	return result;
};

// --------------------------------

fortressAddingResult realmClass::addUncontrollableFortress(fortressClass * newFortress)
{
	fortressAddingResult result = this->canNewFortressBeAdded(newFortress, 0);

	if (FAR_DONE == result)
	{
		this->addNewFortressWithoutAnyControll(newFortress, 0);
	}

	return result;
};

// --------------------------------

baseClass * realmClass :: controllableBases(unsigned long position)
{ 
    if (position < bases_.size())
	{
		return actx->cacheFortressesList.getItem<baseClass>(bases_[position]); 
	}
    else 
	{
        return NULL;
	}
};

// --------------------------------

shipClass* realmClass :: controllableShips(unsigned long position) 
{ 
    if (position < ships_.size())
	{
		return actx->cacheFortressesList.getItem<shipClass>(ships_[position]);
	}
    else
	{
        return NULL;
	}
};

// --------------------------------

fortressClass* realmClass :: uncontrollableFortresses(unsigned long position) 
{ 
    if (position < uncontrollableFortresses_.size())
	{
		return actx->cacheFortressesList.getItem<fortressClass>(uncontrollableFortresses_[position]);
	}
    else
	{
        return NULL;
	}
};

// --------------------------------

fortressAddingResult realmClass::canNewFortressBeAdded(fortressClass * newFortress, bool controllable)
{
	if (!newFortress)
	{
		return FAR_NULL_FORTRESS;
	}

	dtIdentifier newFortressID = newFortress->getID();

	unsigned long minBioNodes = RANGE_MAINFRAME_BIO_NODES_MAX;
	for (dtIdentifierVector::iterator litp1 = bases_.begin(); litp1 != bases_.end(); litp1++)
	{
		if (newFortressID == (*litp1))
		// pokud uz pevnost ma, nelze ji znovu pridat
		{
			return FAR_FORTRESS_ALREADY_OWNED;
		}
		minBioNodes = min(minBioNodes, actx->cacheFortressesList.getItem<fortressClass>(*litp1)->getBioNodesCount());
	}
	for (dtIdentifierVector::iterator litp1 = ships_.begin(); litp1 != ships_.end(); litp1++)
	{
		if (newFortressID == (*litp1))
		// pokud uz pevnost ma, nelze ji znovu pridat
		{
			return FAR_FORTRESS_ALREADY_OWNED;
		}
		minBioNodes = min(minBioNodes, actx->cacheFortressesList.getItem<fortressClass>(*litp1)->getBioNodesCount());
	}
	if (!(controllable))
	{
		for (dtIdentifierVector::iterator litp1 = uncontrollableFortresses_.begin(); litp1 != uncontrollableFortresses_.end(); litp1++)
		{
			if (newFortressID == (*litp1))
			{
				return FAR_FORTRESS_ALREADY_OWNED;
			}
		}
	}
	
	minBioNodes = min(minBioNodes, newFortress->getBioNodesCount());

	if (controllable)
	{
		unsigned long fortressesCount = (unsigned long)bases_.size() + (unsigned long)ships_.size();
		if (newFortress->mainframeSystem.nullMainframe())
		{
			return FAR_MAINFRAME_NOT_MOUNTED;
		}
		newFortress->energyDistributionPhaseAndWeaponsFire();
		if (newFortress->mainframeSystem.isMainframeLackingEnergy())
		{
			return FAR_MAINFRAME_ENERGY_LACK;
		}
		if (minBioNodes < ((fortressesCount + 1) * BIONODES_FOR_ONE_FORTRESS))
		// pokud ma nejaka pevnost malo bionodu, nelze pridat zadna dalsi
		{
			return FAR_NOT_ENOUGH_BIONODES;
		}
	}

	return FAR_DONE;
};

// --------------------------------

void realmClass::scientificUpdate()
{
	unsigned long long totalSciencePoints = 0;
	for (unsigned long loop1 = 0; loop1 < this->bases_.size(); loop1++)
	{
		baseClass * actualBase  = this->controllableBases(loop1);
		totalSciencePoints     += actualBase->getFortressScientistsEffectivity();
	}
	for (unsigned long loop1 = 0; loop1 < this->ships_.size(); loop1++)
	{
		shipClass * actualShip  = this->controllableShips(loop1);
		totalSciencePoints     += actualShip->getFortressScientistsEffectivity();
	}
	if (!(0 < totalSciencePoints))
	{
		return;
	}
	this->science_.distributeScientificPointsToLeafs(totalSciencePoints);
};

// --------------------------------

void realmClass::medicalUpdate()
{
	for (unsigned long loop1 = 0; loop1 < this->bases_.size(); loop1++)
	{
		baseClass * actualBase  = this->controllableBases(loop1);
		actualBase->crew.healingPhase();
	}
	for (unsigned long loop1 = 0; loop1 < this->ships_.size(); loop1++)
	{
		shipClass * actualShip  = this->controllableShips(loop1);
		actualShip->crew.healingPhase();
	}
};

// ================================

int banClass::getLevel() const 
{
	return this->level_;
}

// --------------------------------

int banClass::getDurationInDays() const  
{
	return this->durationInDays_;
}

// --------------------------------
std::string banClass::getReason() const
{
	return this->reason_;
}

// --------------------------------

dv_time::datetime banClass::getTimePlaced() const
{
	return this->timePlaced_;
}

// --------------------------------

banClass::banClass(int level, int durationInDays, const std::string & reason, dv_time::datetime timePlaced)
{
	this->level_ = level;
	this->durationInDays_ = durationInDays;
	this->reason_ = reason;
	this->timePlaced_ = timePlaced;
}

// --------------------------------

bool realmClass::hasBan()
{
	return this->ban_ != NULL;
}

// --------------------------------

const banClass* realmClass::getBan() 
{
	return this->ban_;
}

// --------------------------------

void realmClass::makeBan(int level, int days, std::string reason) 
{
	if (ban_ != NULL) 
	{
		delete ban_;
		ban_ = NULL;
	}

	ban_ = new banClass(level, days, reason, dv_time::now());
}

// --------------------------------

void realmClass::cancelBan() 
{
	if (ban_ != NULL) 
	{
		delete ban_;
		ban_ = NULL;
	}
}

// -------------------------------

void tradeStateClass::createTradeBundle()
{
	if (tradeBundle_ != NULL) 
	{
		delete tradeBundle_;
		tradeBundle_ = NULL;
	}

	tradeBundle_ = new tradeBundleClass();
}

// -------------------------------

void tradeStateClass::createPartnerTradeBundle()
{
	if (partnerTradeBundle_ != NULL) 
	{
		delete partnerTradeBundle_;
		partnerTradeBundle_ = NULL;
	}

	partnerTradeBundle_ = new tradeBundleClass();
}

// -------------------------------

tradeBundleClass* tradeStateClass::getTradeBundle() const
{
	return this->tradeBundle_; 
}

// -------------------------------

tradeBundleClass* tradeStateClass::getPartnerTradeBundle() const
{
	return this->partnerTradeBundle_; 
}

void tradeStateClass::deleteTradeBundles()
{
	if (tradeBundle_ != NULL) 
	{
		delete tradeBundle_;
		tradeBundle_ = NULL; 
	}	

	if (partnerTradeBundle_ != NULL) 
	{
		delete partnerTradeBundle_;
		partnerTradeBundle_ = NULL; 
	}
}

// -------------------------------

void tradeStateClass::becomeCanceled() { 
	tradeRole_ = TRADE_ROLE_CANCELED;	
	commitRole_ = TRADE_COMMIT_ROLE_NONE;
	deleteTradeBundles();
}

// -------------------------------

void tradeStateClass::cancelTrade() { 
	tradeRole_ = TRADE_ROLE_NONE;
	commitRole_ = TRADE_COMMIT_ROLE_NONE;
	deleteTradeBundles();
}

// -------------------------------

void tradeStateClass::cancelCommit() { 
	// Na rozdil od commit trade je porad ve stejnem obchodnim stavu. Navic nerusi bundly.
	commitRole_ = TRADE_COMMIT_ROLE_NONE;
}

// -------------------------------

void tradeStateClass::commitTrade() { 
	// Na rozdil od cancel commit uz dokonce ani neni obchodnikem, protoze
	// obchod uspesne skoncil
	tradeRole_ = TRADE_ROLE_NONE;
	commitRole_ = TRADE_COMMIT_ROLE_NONE;
	deleteTradeBundles();
}

// -------------------------------

void tradeStateClass::becomeHost(dtIdentifier enemyId, dtIdentifier enemyFortressId, dtIdentifier ownedFortressId)
{
	this->tradeRole_ = TRADE_ROLE_HOST;
	this->enemyFortressId_ = enemyFortressId;
	this->ownedFortressId_ = ownedFortressId;
	this->enemyId_ = enemyId;
}

// -------------------------------
void tradeStateClass::becomePartnerTrader(dtIdentifier enemyId, dtIdentifier enemyFortressId, dtIdentifier ownedFortressId)
{
	this->tradeRole_ = TRADE_ROLE_PARTNER_TRADER;
	this->enemyFortressId_ = enemyFortressId;
	this->ownedFortressId_ = ownedFortressId;
	this->enemyId_ = enemyId;
	createTradeBundle();
}

// -------------------------------
void tradeStateClass::becomeSelfTrader(dtIdentifier enemyId, dtIdentifier enemyFortressId, dtIdentifier ownedFortressId)
{
	this->tradeRole_ = TRADE_ROLE_SELF_TRADER;
	this->enemyFortressId_ = enemyFortressId;
	this->ownedFortressId_ = ownedFortressId;
	this->enemyId_ = enemyId;
	createTradeBundle();
	createPartnerTradeBundle();
}

// -------------------------------
void tradeStateClass::becomeLootTrader(dtIdentifier enemyId, dtIdentifier enemyFortressId, dtIdentifier ownedFortressId)
{
	this->tradeRole_ = TRADE_ROLE_LOOT_TRADER;
	this->enemyFortressId_ = enemyFortressId;
	this->ownedFortressId_ = ownedFortressId;
	this->enemyId_ = enemyId;
	createTradeBundle();
}

// -------------------------------
void tradeStateClass::becomeSpaceTrader(dtIdentifier ownedFortressId)
{
	this->tradeRole_ = TRADE_ROLE_SPACE_TRADER;
	this->enemyFortressId_ = 0;
	this->ownedFortressId_ = ownedFortressId;
	this->enemyId_ = 0;
	createTradeBundle();
}
// -------------------------------
void tradeStateClass::becomeCommiterHost() 
{
	this->commitRole_ = TRADE_COMMIT_ROLE_HOST;

	createTradeBundle();
	createPartnerTradeBundle();
}
// -------------------------------
void tradeStateClass::becomeCommiterInvited() 
{
	this->commitRole_ = TRADE_COMMIT_ROLE_INVITED;
}
// -------------------------------
void tradeStateClass::becomeCommiterAcknowledged() 
{
	this->commitRole_ = TRADE_COMMIT_ROLE_INVITED;

	createTradeBundle();
	createPartnerTradeBundle();
}

// ################################

void banClass :: setBanParameters(int level, int durationInDays, const std::string & reason, dv_time::datetime timePlaced)
{
    level_          = level;
    durationInDays_ = durationInDays;
    reason_         = reason;
    timePlaced_     = timePlaced;
}

// ################################
// ################################